From 70f5c8efa9f0a1d563d9b5645bb70e651c5e73ad Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 27 Mar 2024 12:05:28 +0000 Subject: [PATCH 1/3] feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5475) Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE chore: delete `R1CSTransformer` (https://github.com/noir-lang/noir/pull/4649) fix: Slice coercions (https://github.com/noir-lang/noir/pull/4640) chore(ci): add warning sticky comment (https://github.com/noir-lang/noir/pull/4647) fix(ssa): Fix slice intrinsic handling in the capacity tracker (https://github.com/noir-lang/noir/pull/4643) chore: fix versioning of `bn254_blackbox_solver` crate (https://github.com/noir-lang/noir/pull/4638) chore: fix acvm crates reporting errors as JS packages (https://github.com/noir-lang/noir/pull/4637) chore: Release Noir(0.26.0) (https://github.com/noir-lang/noir/pull/4526) chore: convert `BlockExpression` into a standard struct (https://github.com/noir-lang/noir/pull/4623) chore(github): Improve PR template "document later" checkbox description (https://github.com/noir-lang/noir/pull/4625) chore: Update integers.md to note support for Fields using `from_integer` (https://github.com/noir-lang/noir/pull/4536) chore: update docs with function names to match version 0.25.0 specifications (https://github.com/noir-lang/noir/pull/4466) feat: add specific error for attempting `string[x] = ".."` (https://github.com/noir-lang/noir/pull/4611) fix(ssa): Use accurate type during SSA AsSlice simplficiation (https://github.com/noir-lang/noir/pull/4610) END_COMMIT_OVERRIDE --------- Co-authored-by: sirasistant --- .aztec-sync-commit | 2 +- .github/ACVM_PUBLISH_FAILED.md | 10 + .github/pull_request_template.md | 2 +- .github/workflows/publish-acvm.yml | 2 +- .github/workflows/release.yml | 30 + .release-please-manifest.json | 4 +- CHANGELOG.md | 62 + Cargo.lock | 53 +- Cargo.toml | 16 +- acvm-repo/CHANGELOG.md | 81 ++ acvm-repo/acir/Cargo.toml | 2 +- acvm-repo/acir/codegen/acir.cpp | 1245 ++++++++--------- .../acir/tests/test_program_serialization.rs | 46 +- acvm-repo/acir_field/Cargo.toml | 2 +- acvm-repo/acvm/Cargo.toml | 2 +- .../acvm/src/compiler/transformers/mod.rs | 5 +- .../acvm/src/compiler/transformers/r1cs.rs | 16 - acvm-repo/acvm/src/pwg/brillig.rs | 20 +- acvm-repo/acvm/tests/solver.rs | 41 +- acvm-repo/acvm_js/Cargo.toml | 2 +- acvm-repo/acvm_js/package.json | 2 +- acvm-repo/acvm_js/src/foreign_call/inputs.rs | 4 +- acvm-repo/acvm_js/src/foreign_call/outputs.rs | 8 +- .../test/shared/complex_foreign_call.ts | 14 +- acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/blackbox_solver/Cargo.toml | 2 +- acvm-repo/bn254_blackbox_solver/Cargo.toml | 2 +- acvm-repo/brillig/Cargo.toml | 2 +- acvm-repo/brillig/src/foreign_call.rs | 26 +- acvm-repo/brillig/src/lib.rs | 3 - acvm-repo/brillig/src/opcodes.rs | 15 +- acvm-repo/brillig/src/value.rs | 103 -- acvm-repo/brillig_vm/Cargo.toml | 3 +- acvm-repo/brillig_vm/src/arithmetic.rs | 136 +- acvm-repo/brillig_vm/src/black_box.rs | 67 +- acvm-repo/brillig_vm/src/lib.rs | 754 +++++----- acvm-repo/brillig_vm/src/memory.rs | 176 ++- aztec_macros/src/transforms/events.rs | 12 +- aztec_macros/src/transforms/functions.rs | 156 ++- aztec_macros/src/transforms/storage.rs | 2 +- .../brillig/brillig_gen/brillig_black_box.rs | 12 +- .../src/brillig/brillig_gen/brillig_block.rs | 10 +- .../brillig_gen/brillig_block_variables.rs | 7 +- .../brillig/brillig_gen/brillig_directive.rs | 37 +- .../src/brillig/brillig_gen/brillig_fn.rs | 16 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 238 ++-- .../noirc_evaluator/src/brillig/brillig_ir.rs | 17 +- .../brillig/brillig_ir/brillig_variable.rs | 15 +- .../src/brillig/brillig_ir/codegen_binary.rs | 4 +- .../brillig/brillig_ir/codegen_intrinsic.rs | 14 +- .../src/brillig/brillig_ir/debug_show.rs | 11 +- .../src/brillig/brillig_ir/entry_point.rs | 34 +- .../src/brillig/brillig_ir/instructions.rs | 42 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 16 +- .../src/ssa/ir/instruction/call.rs | 9 +- compiler/noirc_evaluator/src/ssa/ir/types.rs | 7 + .../ssa/opt/flatten_cfg/capacity_tracker.rs | 14 +- compiler/noirc_frontend/src/ast/expression.rs | 32 +- compiler/noirc_frontend/src/ast/function.rs | 2 +- compiler/noirc_frontend/src/ast/statement.rs | 14 +- compiler/noirc_frontend/src/debug/mod.rs | 38 +- .../src/hir/resolution/resolver.rs | 6 +- .../src/hir/type_check/errors.rs | 5 +- .../noirc_frontend/src/hir/type_check/mod.rs | 3 +- .../noirc_frontend/src/hir/type_check/stmt.rs | 5 + compiler/noirc_frontend/src/hir_def/expr.rs | 8 +- compiler/noirc_frontend/src/hir_def/types.rs | 15 +- .../src/monomorphization/mod.rs | 2 +- compiler/noirc_frontend/src/parser/parser.rs | 20 +- compiler/noirc_printable_type/src/lib.rs | 16 +- compiler/wasm/package.json | 2 +- docs/docs/how_to/how-to-oracles.md | 2 +- .../docs/noir/concepts/data_types/integers.md | 2 +- docs/docs/tutorials/noirjs_app.md | 4 +- .../version-v0.24.0/how_to/how-to-oracles.md | 2 +- .../version-v0.24.0/tutorials/noirjs_app.md | 4 +- .../version-v0.25.0/how_to/how-to-oracles.md | 2 +- .../version-v0.25.0/tutorials/noirjs_app.md | 4 +- flake.nix | 2 +- noir_stdlib/src/collections/bounded_vec.nr | 9 + noir_stdlib/src/field.nr | 2 +- release-please-config.json | 2 +- .../array_to_slice/src/main.nr | 23 + .../regression_capacity_tracker/Nargo.toml | 7 + .../regression_capacity_tracker/Prover.toml | 3 + .../regression_capacity_tracker/src/main.nr | 19 + .../slice_coercion/Nargo.toml | 7 + .../slice_coercion/Prover.toml | 2 + .../slice_coercion/src/main.nr | 19 + tooling/debugger/src/context.rs | 12 +- tooling/debugger/src/foreign_calls.rs | 17 +- tooling/debugger/src/repl.rs | 12 +- tooling/nargo/src/artifacts/debug_vars.rs | 12 +- tooling/nargo/src/ops/foreign_calls.rs | 43 +- tooling/nargo_fmt/src/visitor/expr.rs | 4 +- tooling/noir_codegen/package.json | 2 +- tooling/noir_js/package.json | 2 +- .../noir_js_backend_barretenberg/package.json | 4 +- tooling/noir_js_types/package.json | 2 +- tooling/noirc_abi_wasm/package.json | 2 +- yarn.lock | 13 +- 101 files changed, 2315 insertions(+), 1734 deletions(-) create mode 100644 .github/ACVM_PUBLISH_FAILED.md delete mode 100644 acvm-repo/acvm/src/compiler/transformers/r1cs.rs delete mode 100644 acvm-repo/brillig/src/value.rs create mode 100644 test_programs/execution_success/regression_capacity_tracker/Nargo.toml create mode 100644 test_programs/execution_success/regression_capacity_tracker/Prover.toml create mode 100644 test_programs/execution_success/regression_capacity_tracker/src/main.nr create mode 100644 test_programs/execution_success/slice_coercion/Nargo.toml create mode 100644 test_programs/execution_success/slice_coercion/Prover.toml create mode 100644 test_programs/execution_success/slice_coercion/src/main.nr diff --git a/.aztec-sync-commit b/.aztec-sync-commit index ead8f3147c0..e38b482f955 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -208abbb63af4c9a3f25d723fe1c49e82aa461061 +27bd8d318df486f6d30a01212f9d7894cafcec74 diff --git a/.github/ACVM_PUBLISH_FAILED.md b/.github/ACVM_PUBLISH_FAILED.md new file mode 100644 index 00000000000..00e692a64d8 --- /dev/null +++ b/.github/ACVM_PUBLISH_FAILED.md @@ -0,0 +1,10 @@ +--- +title: "ACVM crates failed to publish" +assignees: TomAFrench, Savio-Sou +--- + +The {{env.CRATE_VERSION}} release of the ACVM crates failed. + +Check the [Publish ACVM crates]({{env.WORKFLOW_URL}}) workflow for details. + +This issue was raised by the workflow `{{env.WORKFLOW_NAME}}` diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e81ede7199d..dfb141e29f7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,7 +17,7 @@ Resolves Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. -- [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. +- [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* diff --git a/.github/workflows/publish-acvm.yml b/.github/workflows/publish-acvm.yml index 959cd8e4bca..d17d8f294fb 100644 --- a/.github/workflows/publish-acvm.yml +++ b/.github/workflows/publish-acvm.yml @@ -74,4 +74,4 @@ jobs: WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} with: update_existing: true - filename: .github/JS_PUBLISH_FAILED.md \ No newline at end of file + filename: .github/ACVM_PUBLISH_FAILED.md \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 83e8e479181..249d83afecc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -100,6 +100,36 @@ jobs: git commit -m "chore(docs): cut new docs version for tag ${{ steps.noir-version.outputs.semver }}" git push + release-end: + name: Release End + runs-on: ubuntu-latest + # We want this job to always run (even if the dependant jobs fail) as we need apply changes to the sticky comment. + if: ${{ always() }} + + needs: + - update-acvm-workspace-package-versions + - update-docs + + env: + # We treat any skipped or failing jobs as a failure for the workflow as a whole. + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') } + + steps: + - name: Add warning to sticky comment + uses: marocchino/sticky-pull-request-comment@v2 + with: + # delete the comment in case failures have been fixed + delete: ${{ !env.FAIL }} + message: "The release workflow has not completed successfully. Releasing now will result in a broken release" + + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + build-binaries: name: Build binaries needs: [release-please] diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b38234ca0b9..d4cc095c484 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,4 @@ { - ".": "0.25.0", - "acvm-repo": "0.41.0" + ".": "0.26.0", + "acvm-repo": "0.42.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cdbccf768ca..7c4bcad5840 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,67 @@ # Changelog +## [0.26.0](https://github.com/noir-lang/noir/compare/v0.25.0...v0.26.0) (2024-03-25) + + +### ⚠ BREAKING CHANGES + +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) +* automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) +* separating out array and slice types in the AST ([#4504](https://github.com/noir-lang/noir/issues/4504)) +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) +* Remove open keyword from Noir (https://github.com/AztecProtocol/aztec-packages/pull/4967) + +### Features + +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add `break` and `continue` in unconstrained code ([#4569](https://github.com/noir-lang/noir/issues/4569)) ([f2f827d](https://github.com/noir-lang/noir/commit/f2f827d51e6fe99fa3d17f125b22743da25e25be)) +* Add `nargo compile --watch` command ([#4464](https://github.com/noir-lang/noir/issues/4464)) ([44e60b6](https://github.com/noir-lang/noir/commit/44e60b67469de88f20842c4eead64d736f7bd4a0)) +* Add as_slice builtin function, add execution test ([#4523](https://github.com/noir-lang/noir/issues/4523)) ([6a9ea35](https://github.com/noir-lang/noir/commit/6a9ea35c4f1578058179aa08eedf44eb18bad4a1)) +* Add checks for bit size consistency on brillig gen ([#4542](https://github.com/noir-lang/noir/issues/4542)) ([f3243b7](https://github.com/noir-lang/noir/commit/f3243b763c0b15ae90beb8e35630df27f3d314c0)) +* Add CMOV instruction to brillig and brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5308) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add experimental `quote` expression to parser ([#4595](https://github.com/noir-lang/noir/issues/4595)) ([4c3a30b](https://github.com/noir-lang/noir/commit/4c3a30b4991a329d3c52e1dfa59d854d7e6910db)) +* Add more impls on Option ([#4549](https://github.com/noir-lang/noir/issues/4549)) ([4cf700b](https://github.com/noir-lang/noir/commit/4cf700bcfe157ebc82cdf7321a16959b7a4add57)) +* Add specific error for attempting `string[x] = ".."` ([#4611](https://github.com/noir-lang/noir/issues/4611)) ([ff95fd9](https://github.com/noir-lang/noir/commit/ff95fd93451b2053360a16b7d3204ca251199296)) +* Allow usage of noir `#[test]` syntax in stdlib ([#4553](https://github.com/noir-lang/noir/issues/4553)) ([a8b7cdb](https://github.com/noir-lang/noir/commit/a8b7cdb8a3698bc8923b6fa8714deebb8bf3923f)) +* Automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **avm:** Brillig CONST of size > u128 (https://github.com/AztecProtocol/aztec-packages/pull/5217) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Brillig IR refactor (https://github.com/AztecProtocol/aztec-packages/pull/5233) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Check initialization arguments in constructors (https://github.com/AztecProtocol/aztec-packages/pull/5144) ([d4213a0](https://github.com/noir-lang/noir/commit/d4213a03c9f77ee8e7663fc965a825258d90a368)) +* Check initializer msg.sender matches deployer from address preimage (https://github.com/AztecProtocol/aztec-packages/pull/5222) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Initial Earthly CI (https://github.com/AztecProtocol/aztec-packages/pull/5069) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Integrated native ACVM (https://github.com/AztecProtocol/aztec-packages/pull/4903) ([a6016b4](https://github.com/noir-lang/noir/commit/a6016b46abf6da6de4566cf6d35a675d805dd9b5)) +* Make brillig-gen more AVM-friendly (https://github.com/AztecProtocol/aztec-packages/pull/5091) ([a6016b4](https://github.com/noir-lang/noir/commit/a6016b46abf6da6de4566cf6d35a675d805dd9b5)) +* New brillig field operations and refactor of binary operations (https://github.com/AztecProtocol/aztec-packages/pull/5208) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Optimize sha2 implementation ([#4441](https://github.com/noir-lang/noir/issues/4441)) ([80373d6](https://github.com/noir-lang/noir/commit/80373d612c023e3e165b49b6d1729486b0ba3b4b)) +* RC optimization pass ([#4560](https://github.com/noir-lang/noir/issues/4560)) ([dfa5126](https://github.com/noir-lang/noir/commit/dfa5126f2c65843c34701cacddf2cbcfb0d7ff11)) +* Remove curly braces with fmt ([#4529](https://github.com/noir-lang/noir/issues/4529)) ([fe9a437](https://github.com/noir-lang/noir/commit/fe9a437b6d7ddc3f78665df1a576236555880c51)) +* Separating out array and slice types in the AST ([#4504](https://github.com/noir-lang/noir/issues/4504)) ([9a241f9](https://github.com/noir-lang/noir/commit/9a241f9622b342cd9d56bf8481219cfc374c0510)) +* Signed integer division and modulus in brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5279) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5234) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5286) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Visible aliases for nargo commands ([#4453](https://github.com/noir-lang/noir/issues/4453)) ([773cf19](https://github.com/noir-lang/noir/commit/773cf190ee21381d826ba80391a5d7d5efae9174)) + + +### Bug Fixes + +* **acir_gen:** More granular element sizes array check ([#4528](https://github.com/noir-lang/noir/issues/4528)) ([f93d16e](https://github.com/noir-lang/noir/commit/f93d16e3e89c5df358c982deae4f3c2d4c82b77f)) +* Added error messages for passing oracles and references from unconstrained to constrained functions ([#4570](https://github.com/noir-lang/noir/issues/4570)) ([265bd8b](https://github.com/noir-lang/noir/commit/265bd8b284e5acd572a3812a94a99fc102227ff2)) +* Allow non-integer globals to reference struct methods ([#4490](https://github.com/noir-lang/noir/issues/4490)) ([00d6494](https://github.com/noir-lang/noir/commit/00d6494ae70b10e1872d96fb4e57ecb0b5f01787)) +* Dynamic assert messages in brillig ([#4531](https://github.com/noir-lang/noir/issues/4531)) ([e24d3fc](https://github.com/noir-lang/noir/commit/e24d3fc5a084610d9511e3c5421275cb9c84a548)) +* Evaluate operators in globals in types ([#4537](https://github.com/noir-lang/noir/issues/4537)) ([c8aa16b](https://github.com/noir-lang/noir/commit/c8aa16bc7e78456cce1736fac82496996a8761f4)) +* Make `nargo` the default binary for cargo run ([#4554](https://github.com/noir-lang/noir/issues/4554)) ([de4986e](https://github.com/noir-lang/noir/commit/de4986eb74b28b2e1065fa6b413d02457ddf61b0)) +* Signed integer comparisons in brillig ([#4579](https://github.com/noir-lang/noir/issues/4579)) ([938d5e8](https://github.com/noir-lang/noir/commit/938d5e85eda00a05de5014e64d3dc9fc7c24936d)) +* **ssa:** Use accurate type during SSA AsSlice simplficiation ([#4610](https://github.com/noir-lang/noir/issues/4610)) ([0473497](https://github.com/noir-lang/noir/commit/04734976e92475b1ab94257e30bc3438c7358681)) +* Substitute generics when checking the field count of a type ([#4547](https://github.com/noir-lang/noir/issues/4547)) ([eeeebac](https://github.com/noir-lang/noir/commit/eeeebacd10698e847f773e26dac8a4a5eb8e84ed)) + + +### Miscellaneous Chores + +* Remove open keyword from Noir (https://github.com/AztecProtocol/aztec-packages/pull/4967) ([a6016b4](https://github.com/noir-lang/noir/commit/a6016b46abf6da6de4566cf6d35a675d805dd9b5)) + ## [0.25.0](https://github.com/noir-lang/noir/compare/v0.24.0...v0.25.0) (2024-03-11) diff --git a/Cargo.lock b/Cargo.lock index 99c19417267..8c47f03b267 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acir" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir_field", "base64 0.21.2", @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.41.0" +version = "0.42.0" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -37,7 +37,7 @@ dependencies = [ [[package]] name = "acvm" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -53,7 +53,7 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir", "blake2", @@ -88,7 +88,7 @@ dependencies = [ [[package]] name = "acvm_js" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acvm", "bn254_blackbox_solver", @@ -232,7 +232,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arena" -version = "0.25.0" +version = "0.26.0" [[package]] name = "ark-bls12-381" @@ -433,7 +433,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aztec_macros" -version = "0.25.0" +version = "0.26.0" dependencies = [ "convert_case 0.6.0", "iter-extended", @@ -600,7 +600,7 @@ dependencies = [ [[package]] name = "bn254_blackbox_solver" -version = "0.39.0" +version = "0.42.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -623,7 +623,7 @@ dependencies = [ [[package]] name = "brillig" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir_field", "serde", @@ -631,12 +631,13 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir", "acvm_blackbox_solver", "num-bigint", "num-traits", + "thiserror", ] [[package]] @@ -1736,7 +1737,7 @@ dependencies = [ [[package]] name = "fm" -version = "0.25.0" +version = "0.26.0" dependencies = [ "codespan-reporting", "iter-extended", @@ -2357,7 +2358,7 @@ dependencies = [ [[package]] name = "iter-extended" -version = "0.25.0" +version = "0.26.0" [[package]] name = "itertools" @@ -2742,7 +2743,7 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "nargo" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "codespan-reporting", @@ -2769,7 +2770,7 @@ dependencies = [ [[package]] name = "nargo_cli" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "assert_cmd", @@ -2824,7 +2825,7 @@ dependencies = [ [[package]] name = "nargo_fmt" -version = "0.25.0" +version = "0.26.0" dependencies = [ "bytecount", "noirc_frontend", @@ -2836,7 +2837,7 @@ dependencies = [ [[package]] name = "nargo_toml" -version = "0.25.0" +version = "0.26.0" dependencies = [ "dirs", "fm", @@ -2909,7 +2910,7 @@ dependencies = [ [[package]] name = "noir_debugger" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "assert_cmd", @@ -2944,7 +2945,7 @@ dependencies = [ [[package]] name = "noir_lsp" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "async-lsp", @@ -2970,7 +2971,7 @@ dependencies = [ [[package]] name = "noir_wasm" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "build-data", @@ -2993,7 +2994,7 @@ dependencies = [ [[package]] name = "noirc_abi" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "iter-extended", @@ -3010,7 +3011,7 @@ dependencies = [ [[package]] name = "noirc_abi_wasm" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "build-data", @@ -3027,7 +3028,7 @@ dependencies = [ [[package]] name = "noirc_driver" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "aztec_macros", @@ -3048,7 +3049,7 @@ dependencies = [ [[package]] name = "noirc_errors" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "base64 0.21.2", @@ -3066,7 +3067,7 @@ dependencies = [ [[package]] name = "noirc_evaluator" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "fxhash", @@ -3082,7 +3083,7 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "arena", @@ -3107,7 +3108,7 @@ dependencies = [ [[package]] name = "noirc_printable_type" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "iter-extended", diff --git a/Cargo.toml b/Cargo.toml index b8f9b9ceacc..46ccb401fbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ resolver = "2" [workspace.package] # x-release-please-start-version -version = "0.25.0" +version = "0.26.0" # x-release-please-end authors = ["The Noir Team "] edition = "2021" @@ -52,13 +52,13 @@ repository = "https://github.com/noir-lang/noir/" [workspace.dependencies] # ACVM workspace dependencies -acir_field = { version = "0.41.0", path = "acvm-repo/acir_field", default-features = false } -acir = { version = "0.41.0", path = "acvm-repo/acir", default-features = false } -acvm = { version = "0.41.0", path = "acvm-repo/acvm" } -brillig = { version = "0.41.0", path = "acvm-repo/brillig", default-features = false } -brillig_vm = { version = "0.41.0", path = "acvm-repo/brillig_vm", default-features = false } -acvm_blackbox_solver = { version = "0.41.0", path = "acvm-repo/blackbox_solver", default-features = false } -bn254_blackbox_solver = { version = "0.39.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } +acir_field = { version = "0.42.0", path = "acvm-repo/acir_field", default-features = false } +acir = { version = "0.42.0", path = "acvm-repo/acir", default-features = false } +acvm = { version = "0.42.0", path = "acvm-repo/acvm" } +brillig = { version = "0.42.0", path = "acvm-repo/brillig", default-features = false } +brillig_vm = { version = "0.42.0", path = "acvm-repo/brillig_vm", default-features = false } +acvm_blackbox_solver = { version = "0.42.0", path = "acvm-repo/blackbox_solver", default-features = false } +bn254_blackbox_solver = { version = "0.42.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } # Noir compiler workspace dependencies arena = { path = "compiler/utils/arena" } diff --git a/acvm-repo/CHANGELOG.md b/acvm-repo/CHANGELOG.md index 4f220d6eeba..33cc83d7dd9 100644 --- a/acvm-repo/CHANGELOG.md +++ b/acvm-repo/CHANGELOG.md @@ -5,6 +5,87 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.42.0](https://github.com/noir-lang/noir/compare/v0.41.0...v0.42.0) (2024-03-25) + + +### ⚠ BREAKING CHANGES + +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) +* automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) +* move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) +* note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) +* rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) +* init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) +* Rename Arithmetic opcode to AssertZero ([#3840](https://github.com/noir-lang/noir/issues/3840)) +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) + +### Features + +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add bit size to const opcode (https://github.com/AztecProtocol/aztec-packages/pull/4385) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add CMOV instruction to brillig and brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5308) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add instrumentation for tracking variables in debugging ([#4122](https://github.com/noir-lang/noir/issues/4122)) ([c58d691](https://github.com/noir-lang/noir/commit/c58d69141b54a918cd1675400c00bfd48720f896)) +* Add poseidon2 opcode implementation for acvm/brillig, and Noir ([#4398](https://github.com/noir-lang/noir/issues/4398)) ([10e8292](https://github.com/noir-lang/noir/commit/10e82920798380f50046e52db4a20ca205191ab7)) +* Add support for overriding expression width ([#4117](https://github.com/noir-lang/noir/issues/4117)) ([c8026d5](https://github.com/noir-lang/noir/commit/c8026d557d535b10fe455165d6445076df7a03de)) +* Added cast opcode and cast calldata (https://github.com/AztecProtocol/aztec-packages/pull/4423) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Allow brillig to read arrays directly from memory (https://github.com/AztecProtocol/aztec-packages/pull/4460) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow nested arrays and vectors in Brillig foreign calls (https://github.com/AztecProtocol/aztec-packages/pull/4478) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow variables and stack trace inspection in the debugger ([#4184](https://github.com/noir-lang/noir/issues/4184)) ([bf263fc](https://github.com/noir-lang/noir/commit/bf263fc8d843940f328a90f6366edd2671fb2682)) +* Automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **avm:** Back in avm context with macro - refactor context (https://github.com/AztecProtocol/aztec-packages/pull/4438) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* **avm:** Brillig CONST of size > u128 (https://github.com/AztecProtocol/aztec-packages/pull/5217) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **aztec-nr:** Initial work for aztec public vm macro (https://github.com/AztecProtocol/aztec-packages/pull/4400) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Aztec-packages ([#3754](https://github.com/noir-lang/noir/issues/3754)) ([c043265](https://github.com/noir-lang/noir/commit/c043265e550b59bd4296504826fe15d3ce3e9ad2)) +* Backpropagate constants in ACIR during optimization ([#3926](https://github.com/noir-lang/noir/issues/3926)) ([aad0da0](https://github.com/noir-lang/noir/commit/aad0da024c69663f42e6913e674682d5864b26ae)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) ([5be049e](https://github.com/noir-lang/noir/commit/5be049eee6c342649462282ee04f6411e6ea392c)) +* Brillig IR refactor (https://github.com/AztecProtocol/aztec-packages/pull/5233) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Check initializer msg.sender matches deployer from address preimage (https://github.com/AztecProtocol/aztec-packages/pull/5222) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Evaluation of dynamic assert messages ([#4101](https://github.com/noir-lang/noir/issues/4101)) ([c284e01](https://github.com/noir-lang/noir/commit/c284e01bfe20ceae4414dc123624b5cbb8b66d09)) +* Init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Initial Earthly CI (https://github.com/AztecProtocol/aztec-packages/pull/5069) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* New brillig field operations and refactor of binary operations (https://github.com/AztecProtocol/aztec-packages/pull/5208) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove range constraints from witnesses which are constrained to be constants ([#3928](https://github.com/noir-lang/noir/issues/3928)) ([afe9c7a](https://github.com/noir-lang/noir/commit/afe9c7a38bb9d4245205d3aa46d4ce23d70a5671)) +* Remove replacement of boolean range opcodes with `AssertZero` opcodes ([#4107](https://github.com/noir-lang/noir/issues/4107)) ([dac0e87](https://github.com/noir-lang/noir/commit/dac0e87ee3be3446b92bbb12ef4832fd493fcee3)) +* Signed integer division and modulus in brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5279) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Speed up transformation of debug messages ([#3815](https://github.com/noir-lang/noir/issues/3815)) ([2a8af1e](https://github.com/noir-lang/noir/commit/2a8af1e4141ffff61547ee1c2837a6392bd5db48)) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync `aztec-packages` ([#4011](https://github.com/noir-lang/noir/issues/4011)) ([fee2452](https://github.com/noir-lang/noir/commit/fee24523c427c27f0bdaf98ea09a852a2da3e94c)) +* Sync commits from `aztec-packages` ([#4068](https://github.com/noir-lang/noir/issues/4068)) ([7a8f3a3](https://github.com/noir-lang/noir/commit/7a8f3a33b57875e681e3d81e667e3570a1cdbdcc)) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) ([0205d3b](https://github.com/noir-lang/noir/commit/0205d3b4ad0cf5ffd775a43eb5af273a772cf138)) +* Sync from aztec-packages ([#4483](https://github.com/noir-lang/noir/issues/4483)) ([fe8f277](https://github.com/noir-lang/noir/commit/fe8f2776ccfde29209a2c3fc162311c99e4f59be)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5234) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5286) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) + + +### Bug Fixes + +* Deserialize odd length hex literals ([#3747](https://github.com/noir-lang/noir/issues/3747)) ([4000fb2](https://github.com/noir-lang/noir/commit/4000fb279221eb07187d657bfaa7f1c7b311abf2)) +* Noir test incorrect reporting (https://github.com/AztecProtocol/aztec-packages/pull/4925) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* Remove panic from `init_log_level` in `acvm_js` ([#4195](https://github.com/noir-lang/noir/issues/4195)) ([2e26530](https://github.com/noir-lang/noir/commit/2e26530bf53006c1ed4fee310bcaa905c95dd95b)) +* Return error rather instead of panicking on invalid circuit ([#3976](https://github.com/noir-lang/noir/issues/3976)) ([67201bf](https://github.com/noir-lang/noir/commit/67201bfc21a9c8858aa86be9cd47d463fb78d925)) + + +### Miscellaneous Chores + +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) ([0383100](https://github.com/noir-lang/noir/commit/0383100853a80a5b28b797cdfeae0d271f1b7805)) +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) ([9e5d0e8](https://github.com/noir-lang/noir/commit/9e5d0e813d61a0bfb5ee68174ed287c5a20f1579)) +* Rename Arithmetic opcode to AssertZero ([#3840](https://github.com/noir-lang/noir/issues/3840)) ([836f171](https://github.com/noir-lang/noir/commit/836f17145c2901060706294461c2d282dd121b3e)) +* Rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) + ## [0.41.0](https://github.com/noir-lang/noir/compare/v0.40.0...v0.41.0) (2024-03-11) diff --git a/acvm-repo/acir/Cargo.toml b/acvm-repo/acir/Cargo.toml index be859d7d054..368f49258f9 100644 --- a/acvm-repo/acir/Cargo.toml +++ b/acvm-repo/acir/Cargo.toml @@ -2,7 +2,7 @@ name = "acir" description = "ACIR is the IR that the VM processes, it is analogous to LLVM IR" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index ca281d89637..d7ef849ab75 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,957 +5,951 @@ namespace Program { - struct BinaryFieldOp { + struct Witness { + uint32_t value; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const Witness&, const Witness&); + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); + }; + + struct FunctionInput { + Program::Witness witness; + uint32_t num_bits; + + friend bool operator==(const FunctionInput&, const FunctionInput&); + std::vector bincodeSerialize() const; + static FunctionInput bincodeDeserialize(std::vector); + }; + + struct BlackBoxFuncCall { + + struct AND { + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; + + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct XOR { + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; + + friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static XOR bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct RANGE { + Program::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static RANGE bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct SHA256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static SHA256 bincodeDeserialize(std::vector); }; - struct IntegerDiv { - friend bool operator==(const IntegerDiv&, const IntegerDiv&); + struct Blake2s { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static IntegerDiv bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct Blake3 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct SchnorrVerify { + Program::FunctionInput public_key_x; + Program::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Program::Witness output; + + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; + + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - std::variant value; + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Program::Witness output; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); - std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); + }; - struct BinaryIntOp { + struct EcdsaSecp256k1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct EcdsaSecp256r1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; + + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct FixedBaseScalarMul { + Program::FunctionInput low; + Program::FunctionInput high; + std::array outputs; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct EmbeddedCurveAdd { + Program::FunctionInput input1_x; + Program::FunctionInput input1_y; + Program::FunctionInput input2_x; + Program::FunctionInput input2_y; + std::array outputs; + + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct Keccak256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct Keccak256VariableLength { + std::vector inputs; + Program::FunctionInput var_message_size; + std::vector outputs; + + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static Keccak256VariableLength bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Program::FunctionInput key_hash; + + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); + static RecursiveAggregation bincodeDeserialize(std::vector); }; - struct Or { - friend bool operator==(const Or&, const Or&); + struct BigIntAdd { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); + static BigIntAdd bincodeDeserialize(std::vector); }; - struct Xor { - friend bool operator==(const Xor&, const Xor&); + struct BigIntSub { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; - struct Shl { - friend bool operator==(const Shl&, const Shl&); + struct BigIntMul { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + struct BigIntDiv { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - std::variant value; + struct BigIntFromLeBytes { + std::vector inputs; + std::vector modulus; + uint32_t output; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + std::vector bincodeSerialize() const; + static BigIntFromLeBytes bincodeDeserialize(std::vector); + }; - struct MemoryAddress { - uint64_t value; + struct BigIntToLeBytes { + uint32_t input; + std::vector outputs; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + std::vector bincodeSerialize() const; + static BigIntToLeBytes bincodeDeserialize(std::vector); + }; - struct HeapArray { - Program::MemoryAddress pointer; - uint64_t size; + struct Poseidon2Permutation { + std::vector inputs; + std::vector outputs; + uint32_t len; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + std::vector bincodeSerialize() const; + static Poseidon2Permutation bincodeDeserialize(std::vector); + }; + + struct Sha256Compression { + std::vector inputs; + std::vector hash_values; + std::vector outputs; + + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static BlackBoxFuncCall bincodeDeserialize(std::vector); }; - struct HeapVector { - Program::MemoryAddress pointer; - Program::MemoryAddress size; + struct BlockId { + uint32_t value; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const BlockId&, const BlockId&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static BlockId bincodeDeserialize(std::vector); }; - struct BlackBoxOp { + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; - struct Sha256 { - Program::HeapVector message; - Program::HeapArray output; + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); + }; - friend bool operator==(const Sha256&, const Sha256&); - std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); - }; + struct BrilligInputs { - struct Blake2s { - Program::HeapVector message; - Program::HeapArray output; + struct Single { + Program::Expression value; - friend bool operator==(const Blake2s&, const Blake2s&); + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct Blake3 { - Program::HeapVector message; - Program::HeapArray output; + struct Array { + std::vector value; - friend bool operator==(const Blake3&, const Blake3&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Keccak256 { - Program::HeapVector message; - Program::HeapArray output; + struct MemoryArray { + Program::BlockId value; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Program::HeapVector message; - Program::HeapArray output; + std::variant value; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); - std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); - }; + friend bool operator==(const BrilligInputs&, const BrilligInputs&); + std::vector bincodeSerialize() const; + static BrilligInputs bincodeDeserialize(std::vector); + }; - struct EcdsaSecp256k1 { - Program::HeapVector hashed_msg; - Program::HeapArray public_key_x; - Program::HeapArray public_key_y; - Program::HeapArray signature; - Program::MemoryAddress result; + struct BinaryFieldOp { - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - Program::HeapVector hashed_msg; - Program::HeapArray public_key_x; - Program::HeapArray public_key_y; - Program::HeapArray signature; - Program::MemoryAddress result; - - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Program::MemoryAddress public_key_x; - Program::MemoryAddress public_key_y; - Program::HeapVector message; - Program::HeapVector signature; - Program::MemoryAddress result; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::HeapArray output; - - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; - struct PedersenHash { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::MemoryAddress output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); + struct IntegerDiv { + friend bool operator==(const IntegerDiv&, const IntegerDiv&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static IntegerDiv bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Program::MemoryAddress low; - Program::MemoryAddress high; - Program::HeapArray result; - - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Program::MemoryAddress input1_x; - Program::MemoryAddress input1_y; - Program::MemoryAddress input2_x; - Program::MemoryAddress input2_y; - Program::HeapArray result; - - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - struct BigIntAdd { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; - - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static LessThanEquals bincodeDeserialize(std::vector); }; - struct BigIntSub { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + std::variant value; - friend bool operator==(const BigIntSub&, const BigIntSub&); - std::vector bincodeSerialize() const; - static BigIntSub bincodeDeserialize(std::vector); - }; + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + std::vector bincodeSerialize() const; + static BinaryFieldOp bincodeDeserialize(std::vector); + }; - struct BigIntMul { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + struct BinaryIntOp { - friend bool operator==(const BigIntMul&, const BigIntMul&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct BigIntDiv { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; - - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - Program::HeapVector inputs; - Program::HeapVector modulus; - Program::MemoryAddress output; - - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - Program::MemoryAddress input; - Program::HeapVector output; - - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - Program::HeapVector message; - Program::HeapArray output; - Program::MemoryAddress len; - - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct Sha256Compression { - Program::HeapVector input; - Program::HeapVector hash_values; - Program::HeapArray output; - - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); - std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); - }; - - struct HeapValueType; - - struct HeapValueType { + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; - struct Simple { - friend bool operator==(const Simple&, const Simple&); + struct And { + friend bool operator==(const And&, const And&); std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); + static And bincodeDeserialize(std::vector); }; - struct Array { - std::vector value_types; - uint64_t size; + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; - friend bool operator==(const Array&, const Array&); + struct Xor { + friend bool operator==(const Xor&, const Xor&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static Xor bincodeDeserialize(std::vector); }; - struct Vector { - std::vector value_types; + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; - friend bool operator==(const Vector&, const Vector&); + struct Shr { + friend bool operator==(const Shr&, const Shr&); std::vector bincodeSerialize() const; - static Vector bincodeDeserialize(std::vector); + static Shr bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const HeapValueType&, const HeapValueType&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static HeapValueType bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct Value { - std::string inner; + struct MemoryAddress { + uint64_t value; - friend bool operator==(const Value&, const Value&); + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct ValueOrArray { + struct HeapArray { + Program::MemoryAddress pointer; + uint64_t size; - struct MemoryAddress { - Program::MemoryAddress value; + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; + struct HeapVector { + Program::MemoryAddress pointer; + Program::MemoryAddress size; - struct HeapArray { - Program::HeapArray value; + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; - friend bool operator==(const HeapArray&, const HeapArray&); - std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); - }; + struct BlackBoxOp { - struct HeapVector { - Program::HeapVector value; + struct Sha256 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static Sha256 bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const ValueOrArray&, const ValueOrArray&); - std::vector bincodeSerialize() const; - static ValueOrArray bincodeDeserialize(std::vector); - }; - - struct BrilligOpcode { - - struct BinaryFieldOp { - Program::MemoryAddress destination; - Program::BinaryFieldOp op; - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; + struct Blake2s { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct BinaryIntOp { - Program::MemoryAddress destination; - Program::BinaryIntOp op; - uint32_t bit_size; - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; + struct Blake3 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - struct Cast { - Program::MemoryAddress destination; - Program::MemoryAddress source; - uint32_t bit_size; + struct Keccak256 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const Cast&, const Cast&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static Cast bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct JumpIfNot { - Program::MemoryAddress condition; - uint64_t location; + struct Keccakf1600 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const JumpIfNot&, const JumpIfNot&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct JumpIf { - Program::MemoryAddress condition; - uint64_t location; + struct EcdsaSecp256k1 { + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; - friend bool operator==(const JumpIf&, const JumpIf&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - struct Jump { - uint64_t location; + struct EcdsaSecp256r1 { + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; - friend bool operator==(const Jump&, const Jump&); + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); + static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct CalldataCopy { - Program::MemoryAddress destination_address; - uint64_t size; - uint64_t offset; + struct SchnorrVerify { + Program::MemoryAddress public_key_x; + Program::MemoryAddress public_key_y; + Program::HeapVector message; + Program::HeapVector signature; + Program::MemoryAddress result; - friend bool operator==(const CalldataCopy&, const CalldataCopy&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static CalldataCopy bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Call { - uint64_t location; + struct PedersenCommitment { + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::HeapArray output; - friend bool operator==(const Call&, const Call&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct Const { - Program::MemoryAddress destination; - uint32_t bit_size; - Program::Value value; + struct PedersenHash { + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::MemoryAddress output; - friend bool operator==(const Const&, const Const&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct Return { - friend bool operator==(const Return&, const Return&); + struct FixedBaseScalarMul { + Program::MemoryAddress low; + Program::MemoryAddress high; + Program::HeapArray result; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector destination_value_types; - std::vector inputs; - std::vector input_value_types; + struct EmbeddedCurveAdd { + Program::MemoryAddress input1_x; + Program::MemoryAddress input1_y; + Program::MemoryAddress input2_x; + Program::MemoryAddress input2_y; + Program::HeapArray result; - friend bool operator==(const ForeignCall&, const ForeignCall&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct Mov { - Program::MemoryAddress destination; - Program::MemoryAddress source; + struct BigIntAdd { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Mov&, const Mov&); + friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); + static BigIntAdd bincodeDeserialize(std::vector); }; - struct ConditionalMov { - Program::MemoryAddress destination; - Program::MemoryAddress source_a; - Program::MemoryAddress source_b; - Program::MemoryAddress condition; + struct BigIntSub { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const ConditionalMov&, const ConditionalMov&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static ConditionalMov bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; - struct Load { - Program::MemoryAddress destination; - Program::MemoryAddress source_pointer; + struct BigIntMul { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Load&, const Load&); + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct Store { - Program::MemoryAddress destination_pointer; - Program::MemoryAddress source; + struct BigIntDiv { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Store&, const Store&); + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - struct BlackBox { - Program::BlackBoxOp value; + struct BigIntFromLeBytes { + Program::HeapVector inputs; + Program::HeapVector modulus; + Program::MemoryAddress output; - friend bool operator==(const BlackBox&, const BlackBox&); + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); + static BigIntFromLeBytes bincodeDeserialize(std::vector); }; - struct Trap { - friend bool operator==(const Trap&, const Trap&); + struct BigIntToLeBytes { + Program::MemoryAddress input; + Program::HeapVector output; + + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); + static BigIntToLeBytes bincodeDeserialize(std::vector); }; - struct Stop { - uint64_t return_data_offset; - uint64_t return_data_size; + struct Poseidon2Permutation { + Program::HeapVector message; + Program::HeapArray output; + Program::MemoryAddress len; - friend bool operator==(const Stop&, const Stop&); + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static Poseidon2Permutation bincodeDeserialize(std::vector); }; - std::variant value; + struct Sha256Compression { + Program::HeapVector input; + Program::HeapVector hash_values; + Program::HeapArray output; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); - std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); - }; + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; - struct Witness { - uint32_t value; + std::variant value; - friend bool operator==(const Witness&, const Witness&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct FunctionInput { - Program::Witness witness; - uint32_t num_bits; - - friend bool operator==(const FunctionInput&, const FunctionInput&); - std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); - }; + struct HeapValueType; - struct BlackBoxFuncCall { + struct HeapValueType { - struct AND { - Program::FunctionInput lhs; - Program::FunctionInput rhs; - Program::Witness output; + struct Simple { + uint32_t value; - friend bool operator==(const AND&, const AND&); + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; - struct XOR { - Program::FunctionInput lhs; - Program::FunctionInput rhs; - Program::Witness output; + struct Array { + std::vector value_types; + uint64_t size; - friend bool operator==(const XOR&, const XOR&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct RANGE { - Program::FunctionInput input; + struct Vector { + std::vector value_types; - friend bool operator==(const RANGE&, const RANGE&); + friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Vector bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const SHA256&, const SHA256&); - std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); - }; + std::variant value; - struct Blake2s { - std::vector inputs; - std::vector outputs; + friend bool operator==(const HeapValueType&, const HeapValueType&); + std::vector bincodeSerialize() const; + static HeapValueType bincodeDeserialize(std::vector); + }; - friend bool operator==(const Blake2s&, const Blake2s&); - std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); - }; + struct ValueOrArray { - struct Blake3 { - std::vector inputs; - std::vector outputs; + struct MemoryAddress { + Program::MemoryAddress value; - friend bool operator==(const Blake3&, const Blake3&); + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Program::FunctionInput public_key_x; - Program::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Program::Witness output; + struct HeapArray { + Program::HeapArray value; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct HeapVector { + Program::HeapVector value; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Program::Witness output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); - std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); - }; + std::variant value; - struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Program::Witness output; + friend bool operator==(const ValueOrArray&, const ValueOrArray&); + std::vector bincodeSerialize() const; + static ValueOrArray bincodeDeserialize(std::vector); + }; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); - std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); - }; + struct BrilligOpcode { - struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Program::Witness output; + struct BinaryFieldOp { + Program::MemoryAddress destination; + Program::BinaryFieldOp op; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Program::FunctionInput low; - Program::FunctionInput high; - std::array outputs; + struct BinaryIntOp { + Program::MemoryAddress destination; + Program::BinaryIntOp op; + uint32_t bit_size; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Program::FunctionInput input1_x; - Program::FunctionInput input1_y; - Program::FunctionInput input2_x; - Program::FunctionInput input2_y; - std::array outputs; + struct Cast { + Program::MemoryAddress destination; + Program::MemoryAddress source; + uint32_t bit_size; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Cast&, const Cast&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Cast bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - std::vector outputs; + struct JumpIfNot { + Program::MemoryAddress condition; + uint64_t location; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Program::FunctionInput var_message_size; - std::vector outputs; + struct JumpIf { + Program::MemoryAddress condition; + uint64_t location; - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + struct Jump { + uint64_t location; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Program::FunctionInput key_hash; + struct CalldataCopy { + Program::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Call { + uint64_t location; - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct BigIntSub { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Const { + Program::MemoryAddress destination; + uint32_t bit_size; + std::string value; - friend bool operator==(const BigIntSub&, const BigIntSub&); + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static BigIntSub bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; - - friend bool operator==(const BigIntMul&, const BigIntMul&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct ForeignCall { + std::string function; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + struct Mov { + Program::MemoryAddress destination; + Program::MemoryAddress source; - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + struct ConditionalMov { + Program::MemoryAddress destination; + Program::MemoryAddress source_a; + Program::MemoryAddress source_b; + Program::MemoryAddress condition; - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + friend bool operator==(const ConditionalMov&, const ConditionalMov&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static ConditionalMov bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + struct Load { + Program::MemoryAddress destination; + Program::MemoryAddress source_pointer; - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + struct Store { + Program::MemoryAddress destination_pointer; + Program::MemoryAddress source; - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static Store bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; - - friend bool operator==(const Expression&, const Expression&); - std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); - }; - - struct BrilligInputs { - - struct Single { - Program::Expression value; + struct BlackBox { + Program::BlackBoxOp value; - friend bool operator==(const Single&, const Single&); + friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static BlackBox bincodeDeserialize(std::vector); }; - struct Array { - std::vector value; - - friend bool operator==(const Array&, const Array&); + struct Trap { + friend bool operator==(const Trap&, const Trap&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static Trap bincodeDeserialize(std::vector); }; - struct MemoryArray { - Program::BlockId value; + struct Stop { + uint64_t return_data_offset; + uint64_t return_data_size; - friend bool operator==(const MemoryArray&, const MemoryArray&); + friend bool operator==(const Stop&, const Stop&); std::vector bincodeSerialize() const; - static MemoryArray bincodeDeserialize(std::vector); + static Stop bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligInputs&, const BrilligInputs&); + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); + static BrilligOpcode bincodeDeserialize(std::vector); }; struct BrilligOutputs { @@ -5645,6 +5639,7 @@ Program::HeapValueType serde::Deserializable::deserializ namespace Program { inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } @@ -5668,12 +5663,14 @@ namespace Program { template <> template void serde::Serializable::serialize(const Program::HeapValueType::Simple &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template Program::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { Program::HeapValueType::Simple obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } @@ -6419,48 +6416,6 @@ Program::PublicInputs serde::Deserializable::deserialize( return obj; } -namespace Program { - - inline bool operator==(const Value &lhs, const Value &rhs) { - if (!(lhs.inner == rhs.inner)) { return false; } - return true; - } - - inline std::vector Value::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline Value Value::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::Value &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.inner, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -Program::Value serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Program::Value obj; - obj.inner = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} - namespace Program { inline bool operator==(const ValueOrArray &lhs, const ValueOrArray &rhs) { diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 64385a37582..8b04292dfaa 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -190,9 +190,9 @@ fn simple_brillig_foreign_call() { brillig::Opcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], @@ -211,11 +211,11 @@ fn simple_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 214, - 159, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, - 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, 251, 164, 235, 53, 94, 218, 247, 75, - 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, 251, 208, - 106, 207, 232, 150, 65, 100, 53, 33, 2, 22, 232, 178, 27, 144, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 61, 10, 192, 48, 8, 133, 53, 133, 82, 186, + 245, 38, 233, 13, 122, 153, 14, 93, 58, 132, 144, 227, 135, 252, 41, 56, 36, 46, 201, 7, + 162, 168, 200, 123, 34, 52, 142, 28, 72, 245, 38, 106, 9, 247, 30, 202, 118, 142, 27, 215, + 221, 178, 82, 175, 33, 15, 133, 189, 163, 159, 57, 197, 252, 251, 195, 235, 188, 230, 186, + 16, 65, 255, 12, 239, 92, 131, 89, 149, 198, 77, 3, 10, 9, 119, 8, 198, 242, 152, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -264,8 +264,8 @@ fn complex_brillig_foreign_call() { }, brillig::Opcode::Const { destination: MemoryAddress(0), - value: brillig::Value::from(32_usize), - bit_size: 32, + value: FieldElement::from(32_usize), + bit_size: 64, }, brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(1), @@ -280,8 +280,8 @@ fn complex_brillig_foreign_call() { ValueOrArray::MemoryAddress(MemoryAddress::from(1)), ], input_value_types: vec![ - HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, - HeapValueType::Simple, + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::field()] }, + HeapValueType::field(), ], destinations: vec![ ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), @@ -289,9 +289,9 @@ fn complex_brillig_foreign_call() { ValueOrArray::MemoryAddress(MemoryAddress::from(36)), ], destination_value_types: vec![ - HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, - HeapValueType::Simple, - HeapValueType::Simple, + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::field()] }, + HeapValueType::field(), + HeapValueType::field(), ], }, brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 }, @@ -311,15 +311,15 @@ fn complex_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 222, - 246, 7, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, - 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, 205, 200, 157, 49, 124, 227, 44, 129, 207, - 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, 160, 209, 156, - 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, - 254, 196, 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, - 47, 178, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, - 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, 164, 50, 165, 0, 137, 17, - 72, 139, 88, 97, 4, 173, 98, 132, 157, 33, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 93, 10, 131, 48, 12, 78, 218, 233, 100, 111, + 187, 193, 96, 59, 64, 231, 9, 188, 139, 248, 166, 232, 163, 167, 23, 11, 126, 197, 24, 250, + 34, 86, 208, 64, 72, 218, 252, 125, 36, 105, 153, 22, 42, 60, 51, 116, 235, 217, 64, 103, + 156, 37, 5, 191, 10, 210, 29, 163, 63, 167, 203, 229, 206, 194, 104, 110, 128, 209, 158, + 128, 49, 236, 195, 69, 231, 157, 114, 46, 73, 251, 103, 35, 239, 231, 225, 57, 243, 156, + 227, 252, 132, 44, 112, 79, 176, 125, 84, 223, 73, 248, 145, 152, 69, 149, 4, 107, 233, + 114, 90, 119, 145, 85, 237, 151, 192, 89, 247, 221, 208, 54, 163, 85, 174, 26, 234, 87, + 232, 63, 101, 103, 21, 55, 169, 216, 73, 72, 249, 5, 197, 234, 132, 123, 179, 35, 247, 155, + 214, 246, 102, 20, 73, 204, 72, 168, 123, 191, 161, 25, 66, 136, 159, 187, 53, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acir_field/Cargo.toml b/acvm-repo/acir_field/Cargo.toml index c2056b73277..d63a885bfd8 100644 --- a/acvm-repo/acir_field/Cargo.toml +++ b/acvm-repo/acir_field/Cargo.toml @@ -2,7 +2,7 @@ name = "acir_field" description = "The field implementation being used by ACIR." # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index d585850170a..d0ea52e859d 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm" description = "The virtual machine that processes ACIR given a backend/proof system." # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index 2e549854521..18f49c154f1 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -6,10 +6,8 @@ use acir::{ use indexmap::IndexMap; mod csat; -mod r1cs; pub(crate) use csat::CSatTransformer; -pub(crate) use r1cs::R1CSTransformer; use super::{transform_assert_messages, AcirTransformationMap}; @@ -43,8 +41,7 @@ pub(super) fn transform_internal( ) -> (Circuit, Vec) { let mut transformer = match &expression_width { ExpressionWidth::Unbounded => { - let transformer = R1CSTransformer::new(acir); - return (transformer.transform(), acir_opcode_positions); + return (acir, acir_opcode_positions); } ExpressionWidth::Bounded { width } => { let mut csat = CSatTransformer::new(*width); diff --git a/acvm-repo/acvm/src/compiler/transformers/r1cs.rs b/acvm-repo/acvm/src/compiler/transformers/r1cs.rs deleted file mode 100644 index 3bdd29c9c53..00000000000 --- a/acvm-repo/acvm/src/compiler/transformers/r1cs.rs +++ /dev/null @@ -1,16 +0,0 @@ -use acir::circuit::Circuit; - -/// Currently a "noop" transformer. -pub(crate) struct R1CSTransformer { - acir: Circuit, -} - -impl R1CSTransformer { - pub(crate) fn new(acir: Circuit) -> Self { - Self { acir } - } - // TODO: We could possibly make sure that all polynomials are at most degree-2 - pub(crate) fn transform(self) -> Circuit { - self.acir - } -} diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 51c7f4c6203..bcf736cd926 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use acir::{ - brillig::{ForeignCallParam, ForeignCallResult, Value}, + brillig::{ForeignCallParam, ForeignCallResult}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, opcodes::BlockId, @@ -11,7 +11,7 @@ use acir::{ FieldElement, }; use acvm_blackbox_solver::BlackBoxFunctionSolver; -use brillig_vm::{VMStatus, VM}; +use brillig_vm::{MemoryValue, VMStatus, VM}; use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; @@ -73,7 +73,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { acir_index: usize, ) -> Result { // Set input values - let mut calldata: Vec = Vec::new(); + let mut calldata: Vec = Vec::new(); // Each input represents an expression or array of expressions to evaluate. // Iterate over each input and evaluate the expression(s) associated with it. // Push the results into memory. @@ -81,7 +81,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { for input in &brillig.inputs { match input { BrilligInputs::Single(expr) => match get_value(expr, initial_witness) { - Ok(value) => calldata.push(value.into()), + Ok(value) => calldata.push(value), Err(_) => { return Err(OpcodeResolutionError::OpcodeNotSolvable( OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), @@ -92,7 +92,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { // Attempt to fetch all array input values for expr in expr_arr.iter() { match get_value(expr, initial_witness) { - Ok(value) => calldata.push(value.into()), + Ok(value) => calldata.push(value), Err(_) => { return Err(OpcodeResolutionError::OpcodeNotSolvable( OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), @@ -110,7 +110,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { .block_value .get(&memory_index) .expect("All memory is initialized on creation"); - calldata.push((*memory_value).into()); + calldata.push(*memory_value); } } } @@ -122,11 +122,11 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { Ok(Self { vm, acir_index }) } - pub fn get_memory(&self) -> &[Value] { + pub fn get_memory(&self) -> &[MemoryValue] { self.vm.get_memory() } - pub fn write_memory_at(&mut self, ptr: usize, value: Value) { + pub fn write_memory_at(&mut self, ptr: usize, value: MemoryValue) { self.vm.write_memory_at(ptr, value); } @@ -206,13 +206,13 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { for output in brillig.outputs.iter() { match output { BrilligOutputs::Simple(witness) => { - insert_value(witness, memory[current_ret_data_idx].to_field(), witness_map)?; + insert_value(witness, memory[current_ret_data_idx].value, witness_map)?; current_ret_data_idx += 1; } BrilligOutputs::Array(witness_arr) => { for witness in witness_arr.iter() { let value = memory[current_ret_data_idx]; - insert_value(witness, value.to_field(), witness_map)?; + insert_value(witness, value.value, witness_map)?; current_ret_data_idx += 1; } } diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index b267c3005a8..a708db5b030 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use acir::{ - brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, Value, ValueOrArray}, + brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, opcodes::{BlockId, MemOp}, @@ -70,9 +70,9 @@ fn inversion_brillig_oracle_equivalence() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, ], @@ -120,8 +120,7 @@ fn inversion_brillig_oracle_equivalence() { assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); // As caller of VM, need to resolve foreign calls - let foreign_call_result = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let foreign_call_result = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); // Alter Brillig oracle opcode with foreign call resolution acvm.resolve_pending_foreign_call(foreign_call_result.into()); @@ -199,16 +198,16 @@ fn double_inversion_brillig_oracle() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, ], @@ -257,8 +256,7 @@ fn double_inversion_brillig_oracle() { acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); - let x_plus_y_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let x_plus_y_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); // Resolve Brillig foreign call acvm.resolve_pending_foreign_call(x_plus_y_inverse.into()); @@ -275,8 +273,7 @@ fn double_inversion_brillig_oracle() { acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); - let i_plus_j_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let i_plus_j_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); assert_ne!(x_plus_y_inverse, i_plus_j_inverse); // Alter Brillig oracle opcode @@ -334,16 +331,16 @@ fn oracle_dependent_execution() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, ], @@ -389,8 +386,7 @@ fn oracle_dependent_execution() { assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); // Resolve Brillig foreign call - let x_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let x_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); acvm.resolve_pending_foreign_call(x_inverse.into()); // After filling data request, continue solving @@ -406,8 +402,7 @@ fn oracle_dependent_execution() { assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); // Resolve Brillig foreign call - let y_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let y_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); acvm.resolve_pending_foreign_call(y_inverse.into()); // We've resolved all the brillig foreign calls so we should be able to complete execution now. @@ -464,9 +459,9 @@ fn brillig_oracle_predicate() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, ], predicate: Some(Expression::default()), diff --git a/acvm-repo/acvm_js/Cargo.toml b/acvm-repo/acvm_js/Cargo.toml index 63fca2bd32a..65c072b1d96 100644 --- a/acvm-repo/acvm_js/Cargo.toml +++ b/acvm-repo/acvm_js/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_js" description = "Typescript wrapper around the ACVM allowing execution of ACIR code" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm_js/package.json b/acvm-repo/acvm_js/package.json index 2f444ba565a..55345a2ddf6 100644 --- a/acvm-repo/acvm_js/package.json +++ b/acvm-repo/acvm_js/package.json @@ -1,6 +1,6 @@ { "name": "@noir-lang/acvm_js", - "version": "0.41.0", + "version": "0.42.0", "publishConfig": { "access": "public" }, diff --git a/acvm-repo/acvm_js/src/foreign_call/inputs.rs b/acvm-repo/acvm_js/src/foreign_call/inputs.rs index 728fc2d3d2f..ebd29fb7d58 100644 --- a/acvm-repo/acvm_js/src/foreign_call/inputs.rs +++ b/acvm-repo/acvm_js/src/foreign_call/inputs.rs @@ -8,8 +8,8 @@ pub(super) fn encode_foreign_call_inputs( let inputs = js_sys::Array::default(); for input in foreign_call_inputs { let input_array = js_sys::Array::default(); - for value in input.values() { - let hex_js_string = field_element_to_js_string(&value.to_field()); + for value in input.fields() { + let hex_js_string = field_element_to_js_string(&value); input_array.push(&hex_js_string); } inputs.push(&input_array); diff --git a/acvm-repo/acvm_js/src/foreign_call/outputs.rs b/acvm-repo/acvm_js/src/foreign_call/outputs.rs index 630b1afb6fd..78fa520aa15 100644 --- a/acvm-repo/acvm_js/src/foreign_call/outputs.rs +++ b/acvm-repo/acvm_js/src/foreign_call/outputs.rs @@ -1,18 +1,18 @@ -use acvm::brillig_vm::brillig::{ForeignCallParam, ForeignCallResult, Value}; +use acvm::brillig_vm::brillig::{ForeignCallParam, ForeignCallResult}; use wasm_bindgen::JsValue; use crate::js_witness_map::js_value_to_field_element; fn decode_foreign_call_output(output: JsValue) -> Result { if output.is_string() { - let value = Value::from(js_value_to_field_element(output)?); + let value = js_value_to_field_element(output)?; Ok(ForeignCallParam::Single(value)) } else if output.is_array() { let output = js_sys::Array::from(&output); - let mut values: Vec = Vec::with_capacity(output.length() as usize); + let mut values: Vec<_> = Vec::with_capacity(output.length() as usize); for elem in output.iter() { - values.push(Value::from(js_value_to_field_element(elem)?)); + values.push(js_value_to_field_element(elem)?); } Ok(ForeignCallParam::Array(values)) } else { diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index fba8470585f..e074cf1ad38 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 222, 246, 7, 38, 187, 15, 96, - 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, - 205, 200, 157, 49, 124, 227, 44, 129, 207, 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, - 160, 209, 156, 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, 254, 196, - 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, 47, 178, 186, 251, 37, 116, 86, 93, - 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, - 164, 50, 165, 0, 137, 17, 72, 139, 88, 97, 4, 173, 98, 132, 157, 33, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 93, 10, 131, 48, 12, 78, 218, 233, 100, 111, 187, 193, 96, 59, 64, 231, 9, + 188, 139, 248, 166, 232, 163, 167, 23, 11, 126, 197, 24, 250, 34, 86, 208, 64, 72, 218, 252, 125, 36, 105, 153, 22, + 42, 60, 51, 116, 235, 217, 64, 103, 156, 37, 5, 191, 10, 210, 29, 163, 63, 167, 203, 229, 206, 194, 104, 110, 128, + 209, 158, 128, 49, 236, 195, 69, 231, 157, 114, 46, 73, 251, 103, 35, 239, 231, 225, 57, 243, 156, 227, 252, 132, 44, + 112, 79, 176, 125, 84, 223, 73, 248, 145, 152, 69, 149, 4, 107, 233, 114, 90, 119, 145, 85, 237, 151, 192, 89, 247, + 221, 208, 54, 163, 85, 174, 26, 234, 87, 232, 63, 101, 103, 21, 55, 169, 216, 73, 72, 249, 5, 197, 234, 132, 123, 179, + 35, 247, 155, 214, 246, 102, 20, 73, 204, 72, 168, 123, 191, 161, 25, 66, 136, 159, 187, 53, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index dd010f0c5e5..eb14cb2e9f1 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 214, 159, 216, 31, 244, 51, 61, - 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, - 251, 164, 235, 53, 94, 218, 247, 75, 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, - 251, 208, 106, 207, 232, 150, 65, 100, 53, 33, 2, 22, 232, 178, 27, 144, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 61, 10, 192, 48, 8, 133, 53, 133, 82, 186, 245, 38, 233, 13, 122, 153, + 14, 93, 58, 132, 144, 227, 135, 252, 41, 56, 36, 46, 201, 7, 162, 168, 200, 123, 34, 52, 142, 28, 72, 245, 38, 106, 9, + 247, 30, 202, 118, 142, 27, 215, 221, 178, 82, 175, 33, 15, 133, 189, 163, 159, 57, 197, 252, 251, 195, 235, 188, 230, + 186, 16, 65, 255, 12, 239, 92, 131, 89, 149, 198, 77, 3, 10, 9, 119, 8, 198, 242, 152, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/blackbox_solver/Cargo.toml b/acvm-repo/blackbox_solver/Cargo.toml index a783193edba..8f5ff862360 100644 --- a/acvm-repo/blackbox_solver/Cargo.toml +++ b/acvm-repo/blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_blackbox_solver" description = "A solver for the blackbox functions found in ACIR and Brillig" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/bn254_blackbox_solver/Cargo.toml b/acvm-repo/bn254_blackbox_solver/Cargo.toml index a0a15409604..396e4aa0146 100644 --- a/acvm-repo/bn254_blackbox_solver/Cargo.toml +++ b/acvm-repo/bn254_blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "bn254_blackbox_solver" description = "Solvers for black box functions which are specific for the bn254 curve" # x-release-please-start-version -version = "0.39.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig/Cargo.toml b/acvm-repo/brillig/Cargo.toml index 57f89e091b4..d3f082fda86 100644 --- a/acvm-repo/brillig/Cargo.toml +++ b/acvm-repo/brillig/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig" description = "Brillig is the bytecode ACIR uses for non-determinism." # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig/src/foreign_call.rs b/acvm-repo/brillig/src/foreign_call.rs index 3f124a9a0a7..e547b99f0eb 100644 --- a/acvm-repo/brillig/src/foreign_call.rs +++ b/acvm-repo/brillig/src/foreign_call.rs @@ -1,34 +1,34 @@ -use crate::value::Value; +use acir_field::FieldElement; use serde::{Deserialize, Serialize}; /// Single output of a [foreign call][crate::Opcode::ForeignCall]. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] pub enum ForeignCallParam { - Single(Value), - Array(Vec), + Single(FieldElement), + Array(Vec), } -impl From for ForeignCallParam { - fn from(value: Value) -> Self { +impl From for ForeignCallParam { + fn from(value: FieldElement) -> Self { ForeignCallParam::Single(value) } } -impl From> for ForeignCallParam { - fn from(values: Vec) -> Self { +impl From> for ForeignCallParam { + fn from(values: Vec) -> Self { ForeignCallParam::Array(values) } } impl ForeignCallParam { - pub fn values(&self) -> Vec { + pub fn fields(&self) -> Vec { match self { ForeignCallParam::Single(value) => vec![*value], ForeignCallParam::Array(values) => values.clone(), } } - pub fn unwrap_value(&self) -> Value { + pub fn unwrap_field(&self) -> FieldElement { match self { ForeignCallParam::Single(value) => *value, ForeignCallParam::Array(_) => panic!("Expected single value, found array"), @@ -43,14 +43,14 @@ pub struct ForeignCallResult { pub values: Vec, } -impl From for ForeignCallResult { - fn from(value: Value) -> Self { +impl From for ForeignCallResult { + fn from(value: FieldElement) -> Self { ForeignCallResult { values: vec![value.into()] } } } -impl From> for ForeignCallResult { - fn from(values: Vec) -> Self { +impl From> for ForeignCallResult { + fn from(values: Vec) -> Self { ForeignCallResult { values: vec![values.into()] } } } diff --git a/acvm-repo/brillig/src/lib.rs b/acvm-repo/brillig/src/lib.rs index 0661e794360..40f2e15acfe 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -13,7 +13,6 @@ mod black_box; mod foreign_call; mod opcodes; -mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; @@ -21,5 +20,3 @@ pub use opcodes::{ BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, }; pub use opcodes::{BrilligOpcode as Opcode, Label}; -pub use value::Typ; -pub use value::Value; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 22a0ebe1170..d1345351986 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -1,4 +1,5 @@ -use crate::{black_box::BlackBoxOp, Value}; +use crate::black_box::BlackBoxOp; +use acir_field::FieldElement; use serde::{Deserialize, Serialize}; pub type Label = usize; @@ -22,8 +23,8 @@ impl From for MemoryAddress { /// Describes the memory layout for an array/vector element #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum HeapValueType { - // A single field element is enough to represent the value - Simple, + // A single field element is enough to represent the value with a given bit size + Simple(u32), // The value read should be interpreted as a pointer to a heap array, which // consists of a pointer to a slice of memory of size elements, and a // reference count @@ -36,7 +37,11 @@ pub enum HeapValueType { impl HeapValueType { pub fn all_simple(types: &[HeapValueType]) -> bool { - types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + types.iter().all(|typ| matches!(typ, HeapValueType::Simple(_))) + } + + pub fn field() -> HeapValueType { + HeapValueType::Simple(FieldElement::max_num_bits()) } } @@ -131,7 +136,7 @@ pub enum BrilligOpcode { Const { destination: MemoryAddress, bit_size: u32, - value: Value, + value: FieldElement, }, Return, /// Used to get data from an outside source. diff --git a/acvm-repo/brillig/src/value.rs b/acvm-repo/brillig/src/value.rs deleted file mode 100644 index 5a532cbc1a7..00000000000 --- a/acvm-repo/brillig/src/value.rs +++ /dev/null @@ -1,103 +0,0 @@ -use acir_field::FieldElement; -use serde::{Deserialize, Serialize}; -use std::ops::{Add, Div, Mul, Neg, Sub}; - -/// Types of values allowed in the VM -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] -pub enum Typ { - Field, - Unsigned { bit_size: u32 }, - Signed { bit_size: u32 }, -} - -/// `Value` represents the base descriptor for a value in the VM. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Value { - inner: FieldElement, -} - -impl Value { - /// Returns `true` if the `Value` represents `zero` - pub fn is_zero(&self) -> bool { - self.inner.is_zero() - } - - /// Converts `Value` into a `FieldElement`. - pub fn to_field(&self) -> FieldElement { - self.inner - } - - /// Converts `Value` into a `u128`. - // TODO: Check what happens if `Value` cannot fit into a u128 - pub fn to_u128(&self) -> u128 { - self.to_field().to_u128() - } - - /// Converts `Value` into a u64 and then casts it into a usize. - /// Panics: If `Value` cannot fit into a u64 or `Value` does - //// not fit into a usize. - pub fn to_usize(&self) -> usize { - usize::try_from(self.inner.try_to_u64().expect("value does not fit into u64")) - .expect("value does not fit into usize") - } -} - -impl From for Value { - fn from(value: usize) -> Self { - Value { inner: FieldElement::from(value as u128) } - } -} - -impl From for Value { - fn from(value: u128) -> Self { - Value { inner: FieldElement::from(value) } - } -} - -impl From for Value { - fn from(value: FieldElement) -> Self { - Value { inner: value } - } -} - -impl From for Value { - fn from(value: bool) -> Self { - Value { inner: FieldElement::from(value) } - } -} - -impl Add for Value { - type Output = Value; - - fn add(self, rhs: Self) -> Self::Output { - Value { inner: self.inner + rhs.inner } - } -} -impl Sub for Value { - type Output = Value; - - fn sub(self, rhs: Self) -> Self::Output { - Value { inner: self.inner - rhs.inner } - } -} -impl Mul for Value { - type Output = Value; - - fn mul(self, rhs: Self) -> Self::Output { - Value { inner: self.inner * rhs.inner } - } -} -impl Div for Value { - type Output = Value; - - fn div(self, rhs: Self) -> Self::Output { - Value { inner: self.inner / rhs.inner } - } -} -impl Neg for Value { - type Output = Value; - - fn neg(self) -> Self::Output { - Value { inner: -self.inner } - } -} diff --git a/acvm-repo/brillig_vm/Cargo.toml b/acvm-repo/brillig_vm/Cargo.toml index 1c7add5cb40..95675469479 100644 --- a/acvm-repo/brillig_vm/Cargo.toml +++ b/acvm-repo/brillig_vm/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig_vm" description = "The virtual machine that processes Brillig bytecode, used to introduce non-determinism to the ACVM" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true @@ -17,6 +17,7 @@ acir.workspace = true acvm_blackbox_solver.workspace = true num-bigint.workspace = true num-traits.workspace = true +thiserror.workspace = true [features] default = ["bn254"] diff --git a/acvm-repo/brillig_vm/src/arithmetic.rs b/acvm-repo/brillig_vm/src/arithmetic.rs index 81103be582d..3d77982ffb1 100644 --- a/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/acvm-repo/brillig_vm/src/arithmetic.rs @@ -3,56 +3,98 @@ use acir::FieldElement; use num_bigint::BigUint; use num_traits::{One, ToPrimitive, Zero}; -/// Evaluate a binary operation on two FieldElements and return the result as a FieldElement. +use crate::memory::MemoryValue; + +#[derive(Debug, thiserror::Error)] +pub(crate) enum BrilligArithmeticError { + #[error("Bit size for lhs {lhs_bit_size} does not match op bit size {op_bit_size}")] + MismatchedLhsBitSize { lhs_bit_size: u32, op_bit_size: u32 }, + #[error("Bit size for rhs {rhs_bit_size} does not match op bit size {op_bit_size}")] + MismatchedRhsBitSize { rhs_bit_size: u32, op_bit_size: u32 }, + #[error("Shift with bit size {op_bit_size} is invalid")] + InvalidShift { op_bit_size: u32 }, +} + +/// Evaluate a binary operation on two FieldElement memory values. pub(crate) fn evaluate_binary_field_op( op: &BinaryFieldOp, - a: FieldElement, - b: FieldElement, -) -> FieldElement { - match op { + lhs: MemoryValue, + rhs: MemoryValue, +) -> Result { + if lhs.bit_size != FieldElement::max_num_bits() { + return Err(BrilligArithmeticError::MismatchedLhsBitSize { + lhs_bit_size: lhs.bit_size, + op_bit_size: FieldElement::max_num_bits(), + }); + } + if rhs.bit_size != FieldElement::max_num_bits() { + return Err(BrilligArithmeticError::MismatchedRhsBitSize { + rhs_bit_size: rhs.bit_size, + op_bit_size: FieldElement::max_num_bits(), + }); + } + + let a = lhs.value; + let b = rhs.value; + Ok(match op { // Perform addition, subtraction, multiplication, and division based on the BinaryOp variant. - BinaryFieldOp::Add => a + b, - BinaryFieldOp::Sub => a - b, - BinaryFieldOp::Mul => a * b, - BinaryFieldOp::Div => a / b, + BinaryFieldOp::Add => (a + b).into(), + BinaryFieldOp::Sub => (a - b).into(), + BinaryFieldOp::Mul => (a * b).into(), + BinaryFieldOp::Div => (a / b).into(), BinaryFieldOp::IntegerDiv => { let a_big = BigUint::from_bytes_be(&a.to_be_bytes()); let b_big = BigUint::from_bytes_be(&b.to_be_bytes()); let result = a_big / b_big; - FieldElement::from_be_bytes_reduce(&result.to_bytes_be()) + FieldElement::from_be_bytes_reduce(&result.to_bytes_be()).into() } BinaryFieldOp::Equals => (a == b).into(), BinaryFieldOp::LessThan => (a < b).into(), BinaryFieldOp::LessThanEquals => (a <= b).into(), - } + }) } -/// Evaluate a binary operation on two unsigned big integers with a given bit size and return the result as a big integer. -pub(crate) fn evaluate_binary_bigint_op( +/// Evaluate a binary operation on two unsigned big integers with a given bit size. +pub(crate) fn evaluate_binary_int_op( op: &BinaryIntOp, - a: BigUint, - b: BigUint, + lhs: MemoryValue, + rhs: MemoryValue, bit_size: u32, -) -> Result { +) -> Result { + if lhs.bit_size != bit_size { + return Err(BrilligArithmeticError::MismatchedLhsBitSize { + lhs_bit_size: lhs.bit_size, + op_bit_size: bit_size, + }); + } + if rhs.bit_size != bit_size { + return Err(BrilligArithmeticError::MismatchedRhsBitSize { + rhs_bit_size: rhs.bit_size, + op_bit_size: bit_size, + }); + } + + let lhs = BigUint::from_bytes_be(&lhs.value.to_be_bytes()); + let rhs = BigUint::from_bytes_be(&rhs.value.to_be_bytes()); + let bit_modulo = &(BigUint::one() << bit_size); let result = match op { // Perform addition, subtraction, and multiplication, applying a modulo operation to keep the result within the bit size. - BinaryIntOp::Add => (a + b) % bit_modulo, - BinaryIntOp::Sub => (bit_modulo + a - b) % bit_modulo, - BinaryIntOp::Mul => (a * b) % bit_modulo, + BinaryIntOp::Add => (lhs + rhs) % bit_modulo, + BinaryIntOp::Sub => (bit_modulo + lhs - rhs) % bit_modulo, + BinaryIntOp::Mul => (lhs * rhs) % bit_modulo, // Perform unsigned division using the modulo operation on a and b. BinaryIntOp::Div => { - let b_mod = b % bit_modulo; - if b_mod.is_zero() { + if rhs.is_zero() { BigUint::zero() } else { - (a % bit_modulo) / b_mod + lhs / rhs } } // Perform a == operation, returning 0 or 1 BinaryIntOp::Equals => { - if (a % bit_modulo) == (b % bit_modulo) { + if lhs == rhs { BigUint::one() } else { BigUint::zero() @@ -60,7 +102,7 @@ pub(crate) fn evaluate_binary_bigint_op( } // Perform a < operation, returning 0 or 1 BinaryIntOp::LessThan => { - if (a % bit_modulo) < (b % bit_modulo) { + if lhs < rhs { BigUint::one() } else { BigUint::zero() @@ -68,29 +110,40 @@ pub(crate) fn evaluate_binary_bigint_op( } // Perform a <= operation, returning 0 or 1 BinaryIntOp::LessThanEquals => { - if (a % bit_modulo) <= (b % bit_modulo) { + if lhs <= rhs { BigUint::one() } else { BigUint::zero() } } // Perform bitwise AND, OR, XOR, left shift, and right shift operations, applying a modulo operation to keep the result within the bit size. - BinaryIntOp::And => (a & b) % bit_modulo, - BinaryIntOp::Or => (a | b) % bit_modulo, - BinaryIntOp::Xor => (a ^ b) % bit_modulo, + BinaryIntOp::And => lhs & rhs, + BinaryIntOp::Or => lhs | rhs, + BinaryIntOp::Xor => lhs ^ rhs, BinaryIntOp::Shl => { - assert!(bit_size <= 128, "unsupported bit size for right shift"); - let b = b.to_u128().unwrap(); - (a << b) % bit_modulo + if bit_size > 128 { + return Err(BrilligArithmeticError::InvalidShift { op_bit_size: bit_size }); + } + let rhs = rhs.to_u128().unwrap(); + (lhs << rhs) % bit_modulo } BinaryIntOp::Shr => { - assert!(bit_size <= 128, "unsupported bit size for right shift"); - let b = b.to_u128().unwrap(); - (a >> b) % bit_modulo + if bit_size > 128 { + return Err(BrilligArithmeticError::InvalidShift { op_bit_size: bit_size }); + } + let rhs = rhs.to_u128().unwrap(); + lhs >> rhs } }; - Ok(result) + let result_as_field = FieldElement::from_be_bytes_reduce(&result.to_bytes_be()); + + Ok(match op { + BinaryIntOp::Equals | BinaryIntOp::LessThan | BinaryIntOp::LessThanEquals => { + MemoryValue::new(result_as_field, 1) + } + _ => MemoryValue::new(result_as_field, bit_size), + }) } #[cfg(test)] @@ -104,12 +157,15 @@ mod tests { } fn evaluate_u128(op: &BinaryIntOp, a: u128, b: u128, bit_size: u32) -> u128 { - // Convert to big integers - let lhs_big = BigUint::from(a); - let rhs_big = BigUint::from(b); - let result_value = evaluate_binary_bigint_op(op, lhs_big, rhs_big, bit_size).unwrap(); + let result_value = evaluate_binary_int_op( + op, + MemoryValue::new(a.into(), bit_size), + MemoryValue::new(b.into(), bit_size), + bit_size, + ) + .unwrap(); // Convert back to u128 - result_value.to_u128().unwrap() + result_value.value.to_u128() } fn to_negative(a: u128, bit_size: u32) -> u128 { diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index 73b57b907f3..ab4358739e9 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -1,33 +1,33 @@ -use acir::brillig::{BlackBoxOp, HeapArray, HeapVector, Value}; +use acir::brillig::{BlackBoxOp, HeapArray, HeapVector}; use acir::{BlackBoxFunc, FieldElement}; use acvm_blackbox_solver::{ blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, keccakf1600, sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; +use crate::memory::MemoryValue; use crate::Memory; -fn read_heap_vector<'a>(memory: &'a Memory, vector: &HeapVector) -> &'a [Value] { - memory.read_slice(memory.read_ref(vector.pointer), memory.read(vector.size).to_usize()) +fn read_heap_vector<'a>(memory: &'a Memory, vector: &HeapVector) -> &'a [MemoryValue] { + let size = memory.read(vector.size); + memory.read_slice(memory.read_ref(vector.pointer), size.to_usize()) } -fn read_heap_array<'a>(memory: &'a Memory, array: &HeapArray) -> &'a [Value] { +fn read_heap_array<'a>(memory: &'a Memory, array: &HeapArray) -> &'a [MemoryValue] { memory.read_slice(memory.read_ref(array.pointer), array.size) } /// Extracts the last byte of every value -fn to_u8_vec(inputs: &[Value]) -> Vec { +fn to_u8_vec(inputs: &[MemoryValue]) -> Vec { let mut result = Vec::with_capacity(inputs.len()); - for input in inputs { - let field_bytes = input.to_field().to_be_bytes(); - let byte = field_bytes.last().unwrap(); - result.push(*byte); + for &input in inputs { + result.push(input.try_into().unwrap()); } result } -fn to_value_vec(input: &[u8]) -> Vec { - input.iter().map(|x| Value::from(*x as usize)).collect() +fn to_value_vec(input: &[u8]) -> Vec { + input.iter().map(|&x| x.into()).collect() } pub(crate) fn evaluate_black_box( @@ -63,14 +63,13 @@ pub(crate) fn evaluate_black_box( BlackBoxOp::Keccakf1600 { message, output } => { let state_vec: Vec = read_heap_vector(memory, message) .iter() - .map(|value| value.to_field().try_to_u64().unwrap()) + .map(|&memory_value| memory_value.try_into().unwrap()) .collect(); let state: [u64; 25] = state_vec.try_into().unwrap(); let new_state = keccakf1600(state)?; - let new_state: Vec = - new_state.into_iter().map(|x| Value::from(x as usize)).collect(); + let new_state: Vec = new_state.into_iter().map(|x| x.into()).collect(); memory.write_slice(memory.read_ref(output.pointer), &new_state); Ok(()) } @@ -125,8 +124,8 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::SchnorrVerify { public_key_x, public_key_y, message, signature, result } => { - let public_key_x = memory.read(*public_key_x).to_field(); - let public_key_y = memory.read(*public_key_y).to_field(); + let public_key_x = memory.read(*public_key_x).try_into().unwrap(); + let public_key_y = memory.read(*public_key_y).try_into().unwrap(); let message: Vec = to_u8_vec(read_heap_vector(memory, message)); let signature: Vec = to_u8_vec(read_heap_vector(memory, signature)); let verified = @@ -135,26 +134,26 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::FixedBaseScalarMul { low, high, result } => { - let low = memory.read(*low).to_field(); - let high = memory.read(*high).to_field(); + let low = memory.read(*low).try_into().unwrap(); + let high = memory.read(*high).try_into().unwrap(); let (x, y) = solver.fixed_base_scalar_mul(&low, &high)?; memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, result } => { - let input1_x = memory.read(*input1_x).to_field(); - let input1_y = memory.read(*input1_y).to_field(); - let input2_x = memory.read(*input2_x).to_field(); - let input2_y = memory.read(*input2_y).to_field(); + let input1_x = memory.read(*input1_x).try_into().unwrap(); + let input1_y = memory.read(*input1_y).try_into().unwrap(); + let input2_x = memory.read(*input2_x).try_into().unwrap(); + let input2_y = memory.read(*input2_y).try_into().unwrap(); let (x, y) = solver.ec_add(&input1_x, &input1_y, &input2_x, &input2_y)?; memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { let inputs: Vec = - read_heap_vector(memory, inputs).iter().map(|x| x.to_field()).collect(); + read_heap_vector(memory, inputs).iter().map(|&x| x.try_into().unwrap()).collect(); let domain_separator: u32 = - memory.read(*domain_separator).to_u128().try_into().map_err(|_| { + memory.read(*domain_separator).try_into().map_err(|_| { BlackBoxResolutionError::Failed( BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), @@ -166,9 +165,9 @@ pub(crate) fn evaluate_black_box( } BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { let inputs: Vec = - read_heap_vector(memory, inputs).iter().map(|x| x.to_field()).collect(); + read_heap_vector(memory, inputs).iter().map(|&x| x.try_into().unwrap()).collect(); let domain_separator: u32 = - memory.read(*domain_separator).to_u128().try_into().map_err(|_| { + memory.read(*domain_separator).try_into().map_err(|_| { BlackBoxResolutionError::Failed( BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), @@ -186,12 +185,12 @@ pub(crate) fn evaluate_black_box( BlackBoxOp::BigIntToLeBytes { .. } => todo!(), BlackBoxOp::Poseidon2Permutation { message, output, len } => { let input = read_heap_vector(memory, message); - let input: Vec = input.iter().map(|x| x.to_field()).collect(); - let len = memory.read(*len).to_u128() as u32; + let input: Vec = input.iter().map(|&x| x.try_into().unwrap()).collect(); + let len = memory.read(*len).try_into().unwrap(); let result = solver.poseidon2_permutation(&input, len)?; let mut values = Vec::new(); for i in result { - values.push(Value::from(i)); + values.push(i.into()); } memory.write_slice(memory.read_ref(output.pointer), &values); Ok(()) @@ -205,8 +204,8 @@ pub(crate) fn evaluate_black_box( format!("Expected 16 inputs but encountered {}", &inputs.len()), )); } - for (i, input) in inputs.iter().enumerate() { - message[i] = input.to_u128() as u32; + for (i, &input) in inputs.iter().enumerate() { + message[i] = input.try_into().unwrap(); } let mut state = [0; 8]; let values = read_heap_vector(memory, hash_values); @@ -216,12 +215,12 @@ pub(crate) fn evaluate_black_box( format!("Expected 8 values but encountered {}", &values.len()), )); } - for (i, value) in values.iter().enumerate() { - state[i] = value.to_u128() as u32; + for (i, &value) in values.iter().enumerate() { + state[i] = value.try_into().unwrap(); } sha256compression(&mut state, &message); - let state = state.map(|x| Value::from(x as u128)); + let state = state.map(|x| x.into()); memory.write_slice(memory.read_ref(output.pointer), &state); Ok(()) diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index e2a037618a4..0f430b0d5b2 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -13,23 +13,22 @@ use acir::brillig::{ BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, - HeapVector, MemoryAddress, Opcode, Value, ValueOrArray, + HeapVector, MemoryAddress, Opcode, ValueOrArray, }; use acir::FieldElement; +use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; +use arithmetic::{evaluate_binary_field_op, evaluate_binary_int_op, BrilligArithmeticError}; +use black_box::evaluate_black_box; +use num_bigint::BigUint; + // Re-export `brillig`. pub use acir::brillig; +pub use memory::{Memory, MemoryValue, MEMORY_ADDRESSING_BIT_SIZE}; mod arithmetic; mod black_box; mod memory; -use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; -use arithmetic::{evaluate_binary_bigint_op, evaluate_binary_field_op}; -use black_box::evaluate_black_box; - -pub use memory::Memory; -use num_bigint::BigUint; - /// The error call stack contains the opcode indexes of the call stack at the time of failure, plus the index of the opcode that failed. pub type ErrorCallStack = Vec; @@ -63,7 +62,7 @@ pub enum VMStatus { /// VM encapsulates the state of the Brillig VM during execution. pub struct VM<'a, B: BlackBoxFunctionSolver> { /// Calldata to the brillig function - calldata: Vec, + calldata: Vec, /// Instruction pointer program_counter: usize, /// A counter maintained throughout a Brillig process that determines @@ -79,7 +78,7 @@ pub struct VM<'a, B: BlackBoxFunctionSolver> { /// Memory of the VM memory: Memory, /// Call stack - call_stack: Vec, + call_stack: Vec, /// The solver for blackbox functions black_box_solver: &'a B, } @@ -87,7 +86,7 @@ pub struct VM<'a, B: BlackBoxFunctionSolver> { impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { /// Constructs a new VM instance pub fn new( - calldata: Vec, + calldata: Vec, bytecode: &'a [Opcode], foreign_call_results: Vec, black_box_solver: &'a B, @@ -143,8 +142,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { /// Indicating that the VM encountered a `Trap` Opcode /// or an invalid state. fn fail(&mut self, message: String) -> VMStatus { - let mut error_stack: Vec<_> = - self.call_stack.iter().map(|value| value.to_usize()).collect(); + let mut error_stack: Vec<_> = self.call_stack.clone(); error_stack.push(self.program_counter); self.status(VMStatus::Failure { call_stack: error_stack, message }); self.status.clone() @@ -159,22 +157,18 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.status.clone() } - pub fn get_memory(&self) -> &[Value] { + pub fn get_memory(&self) -> &[MemoryValue] { self.memory.values() } - pub fn write_memory_at(&mut self, ptr: usize, value: Value) { + pub fn write_memory_at(&mut self, ptr: usize, value: MemoryValue) { self.memory.write(MemoryAddress(ptr), value); } /// Returns the VM's current call stack, including the actual program /// counter in the last position of the returned vector. pub fn get_call_stack(&self) -> Vec { - self.call_stack - .iter() - .map(|program_counter| program_counter.to_usize()) - .chain(std::iter::once(self.program_counter)) - .collect() + self.call_stack.iter().copied().chain(std::iter::once(self.program_counter)).collect() } /// Process a single opcode and modify the program counter. @@ -182,13 +176,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let opcode = &self.bytecode[self.program_counter]; match opcode { Opcode::BinaryFieldOp { op, lhs, rhs, destination: result } => { - self.process_binary_field_op(*op, *lhs, *rhs, *result); - self.increment_program_counter() + if let Err(error) = self.process_binary_field_op(*op, *lhs, *rhs, *result) { + self.fail(error.to_string()) + } else { + self.increment_program_counter() + } } Opcode::BinaryIntOp { op, bit_size, lhs, rhs, destination: result } => { if let Err(error) = self.process_binary_int_op(*op, *bit_size, *lhs, *rhs, *result) { - self.fail(error) + self.fail(error.to_string()) } else { self.increment_program_counter() } @@ -204,26 +201,29 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // Check if condition is true // We use 0 to mean false and any other value to mean true let condition_value = self.memory.read(*condition); - if !condition_value.is_zero() { + if condition_value.try_into().expect("condition value is not a boolean") { return self.set_program_counter(*destination); } self.increment_program_counter() } Opcode::JumpIfNot { condition, location: destination } => { let condition_value = self.memory.read(*condition); - if condition_value.is_zero() { - return self.set_program_counter(*destination); + if condition_value.try_into().expect("condition value is not a boolean") { + return self.increment_program_counter(); } - self.increment_program_counter() + self.set_program_counter(*destination) } Opcode::CalldataCopy { destination_address, size, offset } => { - let values = &self.calldata[*offset..(*offset + size)]; - self.memory.write_slice(*destination_address, values); + let values: Vec<_> = self.calldata[*offset..(*offset + size)] + .iter() + .map(|value| MemoryValue::new_field(*value)) + .collect(); + self.memory.write_slice(*destination_address, &values); self.increment_program_counter() } Opcode::Return => { if let Some(return_location) = self.call_stack.pop() { - self.set_program_counter(return_location.to_usize() + 1) + self.set_program_counter(return_location + 1) } else { self.fail("return opcode hit, but callstack already empty".to_string()) } @@ -254,81 +254,14 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { return self.wait_for_foreign_call(function.clone(), resolved_inputs); } - let values = &self.foreign_call_results[self.foreign_call_counter].values; + let write_result = self.write_foreign_call_result( + destinations, + destination_value_types, + self.foreign_call_counter, + ); - let mut invalid_foreign_call_result = false; - for ((destination, value_type), output) in - destinations.iter().zip(destination_value_types).zip(values) - { - match (destination, value_type) { - (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { - match output { - ForeignCallParam::Single(value) => { - self.memory.write(*value_index, *value); - } - _ => unreachable!( - "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" - ), - } - } - ( - ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), - HeapValueType::Array { value_types, size: type_size }, - ) if size == type_size => { - if HeapValueType::all_simple(value_types) { - match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; - } - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") - } - } - } else { - unimplemented!("deflattening heap arrays from foreign calls"); - } - } - ( - ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), - HeapValueType::Vector { value_types }, - ) => { - if HeapValueType::all_simple(value_types) { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size address - self.memory.write(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") - } - } - } else { - unimplemented!("deflattening heap vectors from foreign calls"); - } - } - _ => { - unreachable!("Unexpected value type {value_type:?} for destination {destination:?}"); - } - } - } - - // These checks must come after resolving the foreign call outputs as `fail` uses a mutable reference - if destinations.len() != values.len() { - self.fail(format!("{} output values were provided as a foreign call result for {} destination slots", values.len(), destinations.len())); - } - if invalid_foreign_call_result { - self.fail("Function result size does not match brillig bytecode".to_owned()); + if let Err(e) = write_result { + return self.fail(e); } self.foreign_call_counter += 1; @@ -341,10 +274,10 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } Opcode::ConditionalMov { destination, source_a, source_b, condition } => { let condition_value = self.memory.read(*condition); - if condition_value.is_zero() { - self.memory.write(*destination, self.memory.read(*source_b)); - } else { + if condition_value.try_into().expect("condition value is not a boolean") { self.memory.write(*destination, self.memory.read(*source_a)); + } else { + self.memory.write(*destination, self.memory.read(*source_b)); } self.increment_program_counter() } @@ -369,11 +302,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } Opcode::Call { location } => { // Push a return location - self.call_stack.push(Value::from(self.program_counter)); + self.call_stack.push(self.program_counter); self.set_program_counter(*location) } - Opcode::Const { destination, value, bit_size: _ } => { - self.memory.write(*destination, *value); + Opcode::Const { destination, value, bit_size } => { + // Consts are not checked in runtime to fit in the bit size, since they can safely be checked statically. + self.memory.write(*destination, MemoryValue::new(*value, *bit_size)); self.increment_program_counter() } Opcode::BlackBox(black_box_op) => { @@ -413,15 +347,19 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { value_type: &HeapValueType, ) -> ForeignCallParam { match (input, value_type) { - (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { - self.memory.read(value_index).into() + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple(_)) => { + self.memory.read(value_index).value.into() } ( ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), HeapValueType::Array { value_types, size: type_size }, ) if *type_size == size => { let start = self.memory.read_ref(pointer_index); - self.read_slice_of_values_from_memory(start, size, value_types).into() + self.read_slice_of_values_from_memory(start, size, value_types) + .into_iter() + .map(|mem_value| mem_value.value) + .collect::>() + .into() } ( ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }), @@ -429,7 +367,11 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { ) => { let start = self.memory.read_ref(pointer_index); let size = self.memory.read(size_index).to_usize(); - self.read_slice_of_values_from_memory(start, size, value_types).into() + self.read_slice_of_values_from_memory(start, size, value_types) + .into_iter() + .map(|mem_value| mem_value.value) + .collect::>() + .into() } _ => { unreachable!("Unexpected value type {value_type:?} for input {input:?}"); @@ -444,7 +386,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { start: MemoryAddress, size: usize, value_types: &[HeapValueType], - ) -> Vec { + ) -> Vec { if HeapValueType::all_simple(value_types) { self.memory.read_slice(start, size).to_vec() } else { @@ -459,9 +401,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { .flat_map(|(i, value_type)| { let value_address: MemoryAddress = (start.to_usize() + i).into(); match value_type { - HeapValueType::Simple => { - let value = self.memory.read(value_address); - vec![value] + HeapValueType::Simple(_) => { + vec![self.memory.read(value_address)] } HeapValueType::Array { value_types, size } => { let array_address = self.memory.read_ref(value_address); @@ -486,6 +427,124 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } } + fn write_foreign_call_result( + &mut self, + destinations: &[ValueOrArray], + destination_value_types: &[HeapValueType], + foreign_call_index: usize, + ) -> Result<(), String> { + let values = &self.foreign_call_results[foreign_call_index].values; + + if destinations.len() != values.len() { + return Err(format!( + "{} output values were provided as a foreign call result for {} destination slots", + values.len(), + destinations.len() + )); + } + + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { + match (destination, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple(bit_size)) => { + match output { + ForeignCallParam::Single(value) => { + let memory_value = MemoryValue::new_checked(*value, *bit_size); + if let Some(memory_value) = memory_value { + self.memory.write(*value_index, memory_value); + } else { + return Err(format!( + "Foreign call result value {} does not fit in bit size {}", + value, + bit_size + )); + } + } + _ => return Err(format!( + "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}") + ), + } + } + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if size == type_size => { + if HeapValueType::all_simple(value_types) { + let bit_sizes_iterator = value_types.iter().map(|typ| match typ { + HeapValueType::Simple(bit_size) => *bit_size, + _ => unreachable!("Expected simple value type"), + }).cycle(); + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + return Err("Foreign call result array doesn't match expected size".to_string()); + } + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + let memory_values: Option> = values.iter().zip(bit_sizes_iterator).map( + |(value, bit_size)| MemoryValue::new_checked(*value, bit_size)).collect(); + if let Some(memory_values) = memory_values { + self.memory.write_slice(destination, &memory_values); + } else { + return Err(format!( + "Foreign call result values {:?} do not match expected bit sizes", + values, + )); + } + } + _ => { + return Err("Function result size does not match brillig bytecode size".to_string()); + } + } + } else { + unimplemented!("deflattening heap arrays from foreign calls"); + } + } + ( + ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { + if HeapValueType::all_simple(value_types) { + let bit_sizes_iterator = value_types.iter().map(|typ| match typ { + HeapValueType::Simple(bit_size) => *bit_size, + _ => unreachable!("Expected simple value type"), + }).cycle(); + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size address + self.memory.write(*size_index, values.len().into()); + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + let memory_values: Option> = values.iter().zip(bit_sizes_iterator).map(|(value, bit_size)| MemoryValue::new_checked(*value, bit_size)).collect(); + if let Some(memory_values) = memory_values { + self.memory.write_slice(destination, &memory_values); + }else{ + return Err(format!( + "Foreign call result values {:?} do not match expected bit sizes", + values, + )); + } + } + _ => { + return Err("Function result size does not match brillig bytecode size".to_string()); + } + } + } else { + unimplemented!("deflattening heap vectors from foreign calls"); + } + } + _ => { + return Err(format!("Unexpected value type {value_type:?} for destination {destination:?}")); + } + } + } + + Ok(()) + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( @@ -494,14 +553,15 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { lhs: MemoryAddress, rhs: MemoryAddress, result: MemoryAddress, - ) { + ) -> Result<(), BrilligArithmeticError> { let lhs_value = self.memory.read(lhs); let rhs_value = self.memory.read(rhs); - let result_value = - evaluate_binary_field_op(&op, lhs_value.to_field(), rhs_value.to_field()); + let result_value = evaluate_binary_field_op(&op, lhs_value, rhs_value)?; + + self.memory.write(result, result_value); - self.memory.write(result, result_value.into()); + Ok(()) } /// Process a binary operation. @@ -513,25 +573,23 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { lhs: MemoryAddress, rhs: MemoryAddress, result: MemoryAddress, - ) -> Result<(), String> { + ) -> Result<(), BrilligArithmeticError> { let lhs_value = self.memory.read(lhs); let rhs_value = self.memory.read(rhs); - // Convert to big integers - let lhs_big = BigUint::from_bytes_be(&lhs_value.to_field().to_be_bytes()); - let rhs_big = BigUint::from_bytes_be(&rhs_value.to_field().to_be_bytes()); - let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size)?; - // Convert back to field element - self.memory - .write(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into()); + let result_value = evaluate_binary_int_op(&op, lhs_value, rhs_value, bit_size)?; + self.memory.write(result, result_value); Ok(()) } /// Casts a value to a different bit size. - fn cast(&self, bit_size: u32, value: Value) -> Value { - let lhs_big = BigUint::from_bytes_be(&value.to_field().to_be_bytes()); + fn cast(&self, bit_size: u32, source_value: MemoryValue) -> MemoryValue { + let lhs_big = BigUint::from_bytes_be(&source_value.value.to_be_bytes()); let mask = BigUint::from(2_u32).pow(bit_size) - 1_u32; - FieldElement::from_be_bytes_reduce(&(lhs_big & mask).to_bytes_be()).into() + MemoryValue { + value: FieldElement::from_be_bytes_reduce(&(lhs_big & mask).to_bytes_be()), + bit_size, + } } } @@ -592,7 +650,7 @@ mod tests { #[test] fn add_single_step_smoke() { - let calldata = vec![Value::from(27u128)]; + let calldata = vec![FieldElement::from(27u128)]; // Add opcode to add the value in address `0` and `1` // and place the output in address `2` @@ -618,7 +676,7 @@ mod tests { let VM { memory, .. } = vm; let output_value = memory.read(MemoryAddress::from(0)); - assert_eq!(output_value, Value::from(27u128)); + assert_eq!(output_value.value, FieldElement::from(27u128)); } #[test] @@ -627,12 +685,12 @@ mod tests { let mut opcodes = vec![]; let lhs = { - calldata.push(Value::from(2u128)); + calldata.push(2u128.into()); MemoryAddress::from(calldata.len() - 1) }; let rhs = { - calldata.push(Value::from(2u128)); + calldata.push(2u128.into()); MemoryAddress::from(calldata.len() - 1) }; @@ -643,11 +701,10 @@ mod tests { size: 2, offset: 0, }); - let equal_cmp_opcode = - Opcode::BinaryIntOp { op: BinaryIntOp::Equals, bit_size: 1, lhs, rhs, destination }; - opcodes.push(equal_cmp_opcode); + + opcodes.push(Opcode::BinaryFieldOp { destination, op: BinaryFieldOp::Equals, lhs, rhs }); opcodes.push(Opcode::Jump { location: 3 }); - opcodes.push(Opcode::JumpIf { condition: MemoryAddress::from(2), location: 4 }); + opcodes.push(Opcode::JumpIf { condition: destination, location: 4 }); let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); @@ -657,8 +714,8 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_cmp_value, Value::from(true)); + let output_cmp_value = vm.memory.read(destination); + assert_eq!(output_cmp_value.value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -669,7 +726,7 @@ mod tests { #[test] fn jmpifnot_opcode() { - let calldata = vec![Value::from(1u128), Value::from(2u128)]; + let calldata = vec![1u128.into(), 2u128.into()]; let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -717,7 +774,7 @@ mod tests { assert_eq!(status, VMStatus::InProgress); let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_cmp_value, Value::from(false)); + assert_eq!(output_cmp_value.value, false.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -734,12 +791,12 @@ mod tests { // The address at index `2` should have not changed as we jumped over the add opcode let VM { memory, .. } = vm; let output_value = memory.read(MemoryAddress::from(2)); - assert_eq!(output_value, Value::from(false)); + assert_eq!(output_value.value, false.into()); } #[test] fn cast_opcode() { - let calldata = vec![Value::from((2_u128.pow(32)) - 1)]; + let calldata = vec![((2_u128.pow(32)) - 1).into()]; let opcodes = &[ Opcode::CalldataCopy { @@ -768,12 +825,12 @@ mod tests { let VM { memory, .. } = vm; let casted_value = memory.read(MemoryAddress::from(1)); - assert_eq!(casted_value, Value::from(2_u128.pow(8) - 1)); + assert_eq!(casted_value.value, (2_u128.pow(8) - 1).into()); } #[test] fn mov_opcode() { - let calldata = vec![Value::from(1u128), Value::from(2u128), Value::from(3u128)]; + let calldata = vec![(1u128).into(), (2u128).into(), (3u128).into()]; let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -796,16 +853,15 @@ mod tests { let VM { memory, .. } = vm; let destination_value = memory.read(MemoryAddress::from(2)); - assert_eq!(destination_value, Value::from(1u128)); + assert_eq!(destination_value.value, (1u128).into()); let source_value = memory.read(MemoryAddress::from(0)); - assert_eq!(source_value, Value::from(1u128)); + assert_eq!(source_value.value, (1u128).into()); } #[test] fn cmov_opcode() { - let calldata = - vec![Value::from(0u128), Value::from(1u128), Value::from(2u128), Value::from(3u128)]; + let calldata = vec![(0u128).into(), (1u128).into(), (2u128).into(), (3u128).into()]; let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -813,8 +869,22 @@ mod tests { offset: 0, }; + let cast_zero = Opcode::Cast { + destination: MemoryAddress::from(0), + source: MemoryAddress::from(0), + bit_size: 1, + }; + + let cast_one = Opcode::Cast { + destination: MemoryAddress::from(1), + source: MemoryAddress::from(1), + bit_size: 1, + }; + let opcodes = &[ calldata_copy, + cast_zero, + cast_one, Opcode::ConditionalMov { destination: MemoryAddress(4), // Sets 3_u128 to memory address 4 source_a: MemoryAddress(2), @@ -836,28 +906,30 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + let status = vm.process_opcode(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); let VM { memory, .. } = vm; let destination_value = memory.read(MemoryAddress::from(4)); - assert_eq!(destination_value, Value::from(3_u128)); + assert_eq!(destination_value.value, (3_u128).into()); let source_value = memory.read(MemoryAddress::from(5)); - assert_eq!(source_value, Value::from(2_u128)); + assert_eq!(source_value.value, (2_u128).into()); } #[test] fn cmp_binary_ops() { let bit_size = 32; - let calldata = vec![ - Value::from(2u128), - Value::from(2u128), - Value::from(0u128), - Value::from(5u128), - Value::from(6u128), - ]; + let calldata = + vec![(2u128).into(), (2u128).into(), (0u128).into(), (5u128).into(), (6u128).into()]; + let calldata_size = calldata.len(); let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -865,6 +937,14 @@ mod tests { offset: 0, }; + let cast_opcodes: Vec<_> = (0..calldata_size) + .map(|index| Opcode::Cast { + destination: MemoryAddress::from(index), + source: MemoryAddress::from(index), + bit_size, + }) + .collect(); + let equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::Equals, @@ -897,42 +977,47 @@ mod tests { destination: MemoryAddress::from(2), }; - let opcodes = [ - calldata_copy, - equal_opcode, - not_equal_opcode, - less_than_opcode, - less_than_equal_opcode, - ]; + let opcodes: Vec<_> = std::iter::once(calldata_copy) + .chain(cast_opcodes) + .chain([equal_opcode, not_equal_opcode, less_than_opcode, less_than_equal_opcode]) + .collect(); let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); + // Calldata copy let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); + for _ in 0..calldata_size { + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + } + + // Equals let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let output_eq_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_eq_value, Value::from(true)); + assert_eq!(output_eq_value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let output_neq_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_neq_value, Value::from(false)); + assert_eq!(output_neq_value, false.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let lt_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(lt_value, Value::from(true)); + assert_eq!(lt_value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); let lte_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(lte_value, Value::from(true)); + assert_eq!(lte_value, true.into()); } + #[test] fn store_opcode() { /// Brillig code for the following: @@ -942,8 +1027,8 @@ mod tests { /// memory[i] = i as Value; /// i += 1; /// } - fn brillig_write_memory(item_count: usize) -> Vec { - let bit_size = 32; + fn brillig_write_memory(item_count: usize) -> Vec { + let bit_size = 64; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_tmp = MemoryAddress::from(2); @@ -951,21 +1036,17 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, // len = memory.len() (approximation) - Opcode::Const { - destination: r_len, - value: Value::from(item_count as u128), - bit_size: 32, - }, + Opcode::Const { destination: r_len, value: item_count.into(), bit_size }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size }, ]; let loop_body = [ // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1000,17 +1081,12 @@ mod tests { } let memory = brillig_write_memory(5); - let expected = vec![ - Value::from(0u128), - Value::from(1u128), - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - ]; + let expected = + vec![(0u64).into(), (1u64).into(), (2u64).into(), (3u64).into(), (4u64).into()]; assert_eq!(memory, expected); let memory = brillig_write_memory(1024); - let expected: Vec = (0..1024).map(|i| Value::from(i as u128)).collect(); + let expected: Vec<_> = (0..1024).map(|i: u64| i.into()).collect(); assert_eq!(memory, expected); } @@ -1024,8 +1100,8 @@ mod tests { /// sum += memory[i]; /// i += 1; /// } - fn brillig_sum_memory(memory: Vec) -> Value { - let bit_size = 32; + fn brillig_sum_memory(memory: Vec) -> FieldElement { + let bit_size = 64; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_sum = MemoryAddress::from(2); @@ -1034,17 +1110,17 @@ mod tests { let start = [ // sum = 0 - Opcode::Const { destination: r_sum, value: 0u128.into(), bit_size: 32 }, - // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, - // len = array.len() (approximation) Opcode::Const { - destination: r_len, - value: Value::from(memory.len() as u128), - bit_size: 32, + destination: r_sum, + value: 0u128.into(), + bit_size: FieldElement::max_num_bits(), }, + // i = 0 + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, + // len = array.len() (approximation) + Opcode::Const { destination: r_len, value: memory.len().into(), bit_size }, // pointer = array_ptr - Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size }, Opcode::CalldataCopy { destination_address: MemoryAddress(5), size: memory.len(), @@ -1055,15 +1131,14 @@ mod tests { // tmp = *i Opcode::Load { destination: r_tmp, source_pointer: r_pointer }, // sum = sum + tmp - Opcode::BinaryIntOp { + Opcode::BinaryFieldOp { destination: r_sum, lhs: r_sum, - op: BinaryIntOp::Add, + op: BinaryFieldOp::Add, rhs: r_tmp, - bit_size, }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1094,20 +1169,20 @@ mod tests { let opcodes = [&start[..], &loop_body[..]].concat(); let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.memory.read(r_sum) + vm.memory.read(r_sum).value } assert_eq!( brillig_sum_memory(vec![ - Value::from(1u128), - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - Value::from(5u128), + (1u128).into(), + (2u128).into(), + (3u128).into(), + (4u128).into(), + (5u128).into(), ]), - Value::from(15u128) + (15u128).into() ); - assert_eq!(brillig_sum_memory(vec![Value::from(1u128); 1024]), Value::from(1024u128)); + assert_eq!(brillig_sum_memory(vec![(1u128).into(); 1024]), (1024u128).into()); } #[test] @@ -1121,8 +1196,8 @@ mod tests { /// recursive_write(memory, i + 1, len); /// } /// Note we represent a 100% in-stack optimized form in brillig - fn brillig_recursive_write_memory(size: usize) -> Vec { - let bit_size = 32; + fn brillig_recursive_write_memory(size: usize) -> Vec { + let bit_size = 64; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_tmp = MemoryAddress::from(2); @@ -1130,15 +1205,15 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, // len = size - Opcode::Const { destination: r_len, value: size.into(), bit_size: 32 }, + Opcode::Const { destination: r_len, value: size.into(), bit_size }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size }, // call recursive_fn Opcode::Call { - location: 5, // Call after 'start' - }, + location: 5, // Call after 'start' + }, // end program by jumping to end Opcode::Jump { location: 100 }, ]; @@ -1160,7 +1235,7 @@ mod tests { // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1188,23 +1263,18 @@ mod tests { } let memory = brillig_recursive_write_memory(5); - let expected = vec![ - Value::from(0u128), - Value::from(1u128), - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - ]; + let expected = + vec![(0u64).into(), (1u64).into(), (2u64).into(), (3u64).into(), (4u64).into()]; assert_eq!(memory, expected); let memory = brillig_recursive_write_memory(1024); - let expected: Vec = (0..1024).map(|i| Value::from(i as u128)).collect(); + let expected: Vec<_> = (0..1024).map(|i: u64| i.into()).collect(); assert_eq!(memory, expected); } /// Helper to execute brillig code fn brillig_execute_and_get_vm( - calldata: Vec, + calldata: Vec, opcodes: &[Opcode], ) -> VM<'_, DummyBlackBoxSolver> { let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver); @@ -1230,14 +1300,14 @@ mod tests { let double_program = vec![ // Load input address with value 5 - Opcode::Const { destination: r_input, value: Value::from(5u128), bit_size: 32 }, + Opcode::Const { destination: r_input, value: (5u128).into(), bit_size: 32 }, // Call foreign function "double" with the input address Opcode::ForeignCall { function: "double".into(), destinations: vec![ValueOrArray::MemoryAddress(r_result)], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::Simple(32)], inputs: vec![ValueOrArray::MemoryAddress(r_input)], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::Simple(32)], }, ]; @@ -1248,13 +1318,13 @@ mod tests { vm.status, VMStatus::ForeignCallWait { function: "double".into(), - inputs: vec![Value::from(5u128).into()] + inputs: vec![FieldElement::from(5usize).into()] } ); // Push result we're waiting for vm.resolve_foreign_call( - Value::from(10u128).into(), // Result of doubling 5u128 + FieldElement::from(10u128).into(), // Result of doubling 5u128 ); // Resume VM @@ -1265,7 +1335,7 @@ mod tests { // Check result address let result_value = vm.memory.read(r_result); - assert_eq!(result_value, Value::from(10u128)); + assert_eq!(result_value, (10u32).into()); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); @@ -1277,12 +1347,11 @@ mod tests { let r_output = MemoryAddress::from(1); // Define a simple 2x2 matrix in memory - let initial_matrix = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; + let initial_matrix = vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; // Transpose of the matrix (but arbitrary for this test, the 'correct value') - let expected_result = - vec![Value::from(1u128), Value::from(3u128), Value::from(2u128), Value::from(4u128)]; + let expected_result: Vec = + vec![(1u128).into(), (3u128).into(), (2u128).into(), (4u128).into()]; let invert_program = vec![ Opcode::CalldataCopy { @@ -1291,9 +1360,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 32 }, + Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 64 }, // output = 0 - Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 32 }, + Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 64 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1303,14 +1372,14 @@ mod tests { })], destination_value_types: vec![HeapValueType::Array { size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], input_value_types: vec![HeapValueType::Array { - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], size: initial_matrix.len(), }], }, @@ -1338,7 +1407,10 @@ mod tests { // Check result in memory let result_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); - assert_eq!(result_values, expected_result); + assert_eq!( + result_values.into_iter().map(|mem_value| mem_value.value).collect::>(), + expected_result + ); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); @@ -1354,10 +1426,10 @@ mod tests { let r_output_size = MemoryAddress::from(3); // Our first string to use the identity function with - let input_string = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; + let input_string: Vec = + vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; // Double the string (concatenate it with itself) - let mut output_string: Vec = + let mut output_string: Vec<_> = input_string.iter().cloned().chain(input_string.clone()).collect(); // Reverse the concatenated string output_string.reverse(); @@ -1370,24 +1442,24 @@ mod tests { offset: 0, }, // input_pointer = 4 - Opcode::Const { destination: r_input_pointer, value: Value::from(4u128), bit_size: 32 }, + Opcode::Const { destination: r_input_pointer, value: (4u128).into(), bit_size: 64 }, // input_size = input_string.len() (constant here) Opcode::Const { destination: r_input_size, - value: Value::from(input_string.len()), - bit_size: 32, + value: input_string.len().into(), + bit_size: 64, }, // output_pointer = 4 + input_size Opcode::Const { destination: r_output_pointer, - value: Value::from(4 + input_string.len()), - bit_size: 32, + value: (4 + input_string.len()).into(), + bit_size: 64, }, // output_size = input_size * 2 Opcode::Const { destination: r_output_size, - value: Value::from(input_string.len() * 2), - bit_size: 32, + value: (input_string.len() * 2).into(), + bit_size: 64, }, // output_pointer[0..output_size] = string_double(input_pointer[0...input_size]) Opcode::ForeignCall { @@ -1397,14 +1469,14 @@ mod tests { size: r_output_size, })], destination_value_types: vec![HeapValueType::Vector { - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ValueOrArray::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, })], input_value_types: vec![HeapValueType::Vector { - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], }, ]; @@ -1432,10 +1504,12 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm + let result_values: Vec<_> = vm .memory .read_slice(MemoryAddress(4 + input_string.len()), output_string.len()) - .to_vec(); + .iter() + .map(|mem_val| mem_val.value) + .collect(); assert_eq!(result_values, output_string); // Ensure the foreign call counter has been incremented @@ -1448,12 +1522,11 @@ mod tests { let r_output = MemoryAddress::from(1); // Define a simple 2x2 matrix in memory - let initial_matrix = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; + let initial_matrix = vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; // Transpose of the matrix (but arbitrary for this test, the 'correct value') - let expected_result = - vec![Value::from(1u128), Value::from(3u128), Value::from(2u128), Value::from(4u128)]; + let expected_result: Vec = + vec![(1u128).into(), (3u128).into(), (2u128).into(), (4u128).into()]; let invert_program = vec![ Opcode::CalldataCopy { @@ -1462,9 +1535,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: Value::from(2u128), bit_size: 32 }, + Opcode::Const { destination: r_input, value: (2u128).into(), bit_size: 64 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(6u128), bit_size: 32 }, + Opcode::Const { destination: r_output, value: (6u128).into(), bit_size: 64 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1474,7 +1547,7 @@ mod tests { })], destination_value_types: vec![HeapValueType::Array { size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, @@ -1482,7 +1555,7 @@ mod tests { })], input_value_types: vec![HeapValueType::Array { size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], }, ]; @@ -1508,11 +1581,13 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check initial memory still in place - let initial_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); + let initial_values: Vec<_> = + vm.memory.read_slice(MemoryAddress(2), 4).iter().map(|mem_val| mem_val.value).collect(); assert_eq!(initial_values, initial_matrix); // Check result in memory - let result_values = vm.memory.read_slice(MemoryAddress(6), 4).to_vec(); + let result_values: Vec<_> = + vm.memory.read_slice(MemoryAddress(6), 4).iter().map(|mem_val| mem_val.value).collect(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented @@ -1526,23 +1601,13 @@ mod tests { let r_output = MemoryAddress::from(2); // Define a simple 2x2 matrix in memory - let matrix_a = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; - - let matrix_b = vec![ - Value::from(10u128), - Value::from(11u128), - Value::from(12u128), - Value::from(13u128), - ]; + let matrix_a = vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; + + let matrix_b = vec![(10u128).into(), (11u128).into(), (12u128).into(), (13u128).into()]; // Transpose of the matrix (but arbitrary for this test, the 'correct value') - let expected_result = vec![ - Value::from(34u128), - Value::from(37u128), - Value::from(78u128), - Value::from(85u128), - ]; + let expected_result: Vec = + vec![(34u128).into(), (37u128).into(), (78u128).into(), (85u128).into()]; let matrix_mul_program = vec![ Opcode::CalldataCopy { @@ -1551,11 +1616,11 @@ mod tests { offset: 0, }, // input = 3 - Opcode::Const { destination: r_input_a, value: Value::from(3u128), bit_size: 32 }, + Opcode::Const { destination: r_input_a, value: (3u128).into(), bit_size: 64 }, // input = 7 - Opcode::Const { destination: r_input_b, value: Value::from(7u128), bit_size: 32 }, + Opcode::Const { destination: r_input_b, value: (7u128).into(), bit_size: 64 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(0u128), bit_size: 32 }, + Opcode::Const { destination: r_output, value: (0u128).into(), bit_size: 64 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1565,7 +1630,7 @@ mod tests { })], destination_value_types: vec![HeapValueType::Array { size: matrix_a.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ ValueOrArray::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len() }), @@ -1574,11 +1639,11 @@ mod tests { input_value_types: vec![ HeapValueType::Array { size: matrix_a.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }, HeapValueType::Array { size: matrix_b.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }, ], }, @@ -1606,7 +1671,8 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm.memory.read_slice(MemoryAddress(0), 4).to_vec(); + let result_values: Vec<_> = + vm.memory.read_slice(MemoryAddress(0), 4).iter().map(|mem_val| mem_val.value).collect(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented @@ -1617,47 +1683,54 @@ mod tests { fn foreign_call_opcode_nested_arrays_and_slices_input() { // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] - let v2 = vec![Value::from(2u128), Value::from(3u128)]; - let a4 = vec![Value::from(4u128)]; - let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; - let a9 = vec![Value::from(9u128)]; + let v2: Vec = vec![ + MemoryValue::from(FieldElement::from(2u128)), + MemoryValue::from(FieldElement::from(3u128)), + ]; + let a4: Vec = vec![FieldElement::from(4u128).into()]; + let v6: Vec = vec![ + MemoryValue::from(FieldElement::from(6u128)), + MemoryValue::from(FieldElement::from(7u128)), + MemoryValue::from(FieldElement::from(8u128)), + ]; + let a9: Vec = vec![FieldElement::from(9u128).into()]; // construct memory by declaring all inner arrays/vectors first - let v2_ptr = 0u128; + let v2_ptr: usize = 0usize; let mut memory = v2.clone(); let v2_start = memory.len(); - memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(v2_ptr), v2.len().into(), MemoryValue::from(1_usize)]); let a4_ptr = memory.len(); memory.extend(a4.clone()); let a4_start = memory.len(); - memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(a4_ptr), MemoryValue::from(1_usize)]); let v6_ptr = memory.len(); memory.extend(v6.clone()); let v6_start = memory.len(); - memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(v6_ptr), v6.len().into(), MemoryValue::from(1_usize)]); let a9_ptr = memory.len(); memory.extend(a9.clone()); let a9_start = memory.len(); - memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(a9_ptr), MemoryValue::from(1_usize)]); // finally we add the contents of the outer array let outer_ptr = memory.len(); let outer_array = vec![ - Value::from(1u128), - Value::from(v2.len()), - Value::from(v2_start), - Value::from(a4_start), - Value::from(5u128), - Value::from(v6.len()), - Value::from(v6_start), - Value::from(a9_start), + MemoryValue::from(FieldElement::from(1u128)), + MemoryValue::from(v2.len()), + MemoryValue::from(v2_start), + MemoryValue::from(a4_start), + MemoryValue::from(FieldElement::from(5u128)), + MemoryValue::from(v6.len()), + MemoryValue::from(v6_start), + MemoryValue::from(a9_start), ]; memory.extend(outer_array.clone()); - let input_array_value_types = vec![ - HeapValueType::Simple, - HeapValueType::Simple, // size of following vector - HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, - HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + let input_array_value_types: Vec = vec![ + HeapValueType::field(), + HeapValueType::Simple(64), // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::field()] }, + HeapValueType::Array { value_types: vec![HeapValueType::field()], size: 1 }, ]; // memory address of the end of the above data structures @@ -1666,19 +1739,24 @@ mod tests { let r_input = MemoryAddress::from(r_ptr); let r_output = MemoryAddress::from(r_ptr + 1); - let program = vec![ - Opcode::CalldataCopy { - destination_address: MemoryAddress::from(0), - size: memory.len(), - offset: 0, - }, + let program: Vec<_> = std::iter::once(Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: memory.len(), + offset: 0, + }) + .chain(memory.iter().enumerate().map(|(index, mem_value)| Opcode::Cast { + destination: MemoryAddress(index), + source: MemoryAddress(index), + bit_size: mem_value.bit_size, + })) + .chain(vec![ // input = 0 - Opcode::Const { destination: r_input, value: Value::from(outer_ptr), bit_size: 32 }, + Opcode::Const { destination: r_input, value: (outer_ptr).into(), bit_size: 64 }, // some_function(input) Opcode::ForeignCall { function: "flat_sum".into(), destinations: vec![ValueOrArray::MemoryAddress(r_output)], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: outer_array.len(), @@ -1688,9 +1766,13 @@ mod tests { size: outer_array.len(), }], }, - ]; + ]) + .collect(); - let mut vm = brillig_execute_and_get_vm(memory, &program); + let mut vm = brillig_execute_and_get_vm( + memory.into_iter().map(|mem_value| mem_value.value).collect(), + &program, + ); // Check that VM is waiting assert_eq!( @@ -1698,23 +1780,23 @@ mod tests { VMStatus::ForeignCallWait { function: "flat_sum".into(), inputs: vec![ForeignCallParam::Array(vec![ - Value::from(1u128), - Value::from(2u128), // size of following vector - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - Value::from(5u128), - Value::from(3u128), // size of following vector - Value::from(6u128), - Value::from(7u128), - Value::from(8u128), - Value::from(9u128), + (1u128).into(), + (2u128).into(), // size of following vector + (2u128).into(), + (3u128).into(), + (4u128).into(), + (5u128).into(), + (3u128).into(), // size of following vector + (6u128).into(), + (7u128).into(), + (8u128).into(), + (9u128).into(), ])], } ); // Push result we're waiting for - vm.resolve_foreign_call(Value::from(45u128).into()); + vm.resolve_foreign_call(FieldElement::from(45u128).into()); // Resume VM brillig_execute(&mut vm); @@ -1724,7 +1806,7 @@ mod tests { // Check result let result_value = vm.memory.read(r_output); - assert_eq!(result_value, Value::from(45u128)); + assert_eq!(result_value, MemoryValue::from(FieldElement::from(45u128))); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); diff --git a/acvm-repo/brillig_vm/src/memory.rs b/acvm-repo/brillig_vm/src/memory.rs index d1c81447170..ae442ac2628 100644 --- a/acvm-repo/brillig_vm/src/memory.rs +++ b/acvm-repo/brillig_vm/src/memory.rs @@ -1,30 +1,188 @@ use acir::{brillig::MemoryAddress, FieldElement}; -use crate::Value; +pub const MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MemoryValue { + pub value: FieldElement, + pub bit_size: u32, +} + +#[derive(Debug, thiserror::Error)] +pub enum MemoryTypeError { + #[error("Bit size for value {value_bit_size} does not match the expected bit size {expected_bit_size}")] + MismatchedBitSize { value_bit_size: u32, expected_bit_size: u32 }, +} + +impl MemoryValue { + pub fn new(value: FieldElement, bit_size: u32) -> Self { + MemoryValue { value, bit_size } + } + + pub fn new_checked(value: FieldElement, bit_size: u32) -> Option { + if value.num_bits() > bit_size { + return None; + } + + Some(MemoryValue::new(value, bit_size)) + } + + pub fn new_field(value: FieldElement) -> Self { + MemoryValue { value, bit_size: FieldElement::max_num_bits() } + } + + pub fn to_usize(&self) -> usize { + assert!(self.bit_size == MEMORY_ADDRESSING_BIT_SIZE, "value is not typed as brillig usize"); + usize::try_from(self.value.try_to_u64().expect("value does not fit into u64")) + .expect("value does not fit into usize") + } + + pub fn expect_bit_size(&self, expected_bit_size: u32) -> Result<(), MemoryTypeError> { + if self.bit_size != expected_bit_size { + return Err(MemoryTypeError::MismatchedBitSize { + value_bit_size: self.bit_size, + expected_bit_size, + }); + } + Ok(()) + } +} + +impl std::fmt::Display for MemoryValue { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let typ = match self.bit_size { + 0 => "null".to_string(), + 1 => "bool".to_string(), + _ if self.bit_size == FieldElement::max_num_bits() => "field".to_string(), + _ => format!("u{}", self.bit_size), + }; + f.write_str(format!("{}: {}", self.value, typ).as_str()) + } +} + +impl Default for MemoryValue { + fn default() -> Self { + MemoryValue::new(FieldElement::zero(), 0) + } +} + +impl From for MemoryValue { + fn from(field: FieldElement) -> Self { + MemoryValue::new_field(field) + } +} + +impl From for MemoryValue { + fn from(value: usize) -> Self { + MemoryValue::new(value.into(), MEMORY_ADDRESSING_BIT_SIZE) + } +} + +impl From for MemoryValue { + fn from(value: u64) -> Self { + MemoryValue::new((value as u128).into(), 64) + } +} + +impl From for MemoryValue { + fn from(value: u32) -> Self { + MemoryValue::new((value as u128).into(), 32) + } +} + +impl From for MemoryValue { + fn from(value: u8) -> Self { + MemoryValue::new((value as u128).into(), 8) + } +} + +impl From for MemoryValue { + fn from(value: bool) -> Self { + MemoryValue::new(value.into(), 1) + } +} + +impl TryFrom for FieldElement { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(FieldElement::max_num_bits())?; + Ok(memory_value.value) + } +} + +impl TryFrom for u64 { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(64)?; + Ok(memory_value.value.try_to_u64().expect("value typed as u64 does not fit into u64")) + } +} + +impl TryFrom for u32 { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(32)?; + let as_u64 = + memory_value.value.try_to_u64().expect("value typed as u32 does not fit into u64"); + Ok(u32::try_from(as_u64).expect("value typed as u32 does not fit into u32")) + } +} + +impl TryFrom for u8 { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(8)?; + + Ok(u8::try_from( + memory_value.value.try_to_u64().expect("value typed as u8 does not fit into u64"), + ) + .expect("value typed as u8 does not fit into u8")) + } +} + +impl TryFrom for bool { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(1)?; + + if memory_value.value == FieldElement::zero() { + Ok(false) + } else if memory_value.value == FieldElement::one() { + Ok(true) + } else { + unreachable!("value typed as bool is greater than one") + } + } +} #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct Memory { // Memory is a vector of values. // We grow the memory when values past the end are set, extending with 0s. - inner: Vec, + inner: Vec, } impl Memory { /// Gets the value at pointer - pub fn read(&self, ptr: MemoryAddress) -> Value { - self.inner.get(ptr.to_usize()).copied().unwrap_or(0_u128.into()) + pub fn read(&self, ptr: MemoryAddress) -> MemoryValue { + self.inner.get(ptr.to_usize()).copied().unwrap_or_default() } pub fn read_ref(&self, ptr: MemoryAddress) -> MemoryAddress { MemoryAddress(self.read(ptr).to_usize()) } - pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[Value] { + pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[MemoryValue] { &self.inner[addr.to_usize()..(addr.to_usize() + len)] } /// Sets the value at pointer `ptr` to `value` - pub fn write(&mut self, ptr: MemoryAddress, value: Value) { + pub fn write(&mut self, ptr: MemoryAddress, value: MemoryValue) { self.resize_to_fit(ptr.to_usize() + 1); self.inner[ptr.to_usize()] = value; } @@ -33,17 +191,17 @@ impl Memory { // Calculate new memory size let new_size = std::cmp::max(self.inner.len(), size); // Expand memory to new size with default values if needed - self.inner.resize(new_size, Value::from(FieldElement::zero())); + self.inner.resize(new_size, MemoryValue::default()); } /// Sets the values after pointer `ptr` to `values` - pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[Value]) { + pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[MemoryValue]) { self.resize_to_fit(ptr.to_usize() + values.len()); self.inner[ptr.to_usize()..(ptr.to_usize() + values.len())].copy_from_slice(values); } /// Returns the values of the memory - pub fn values(&self) -> &[Value] { + pub fn values(&self) -> &[MemoryValue] { &self.inner } } diff --git a/aztec_macros/src/transforms/events.rs b/aztec_macros/src/transforms/events.rs index b02709efacb..e7e39ed29ba 100644 --- a/aztec_macros/src/transforms/events.rs +++ b/aztec_macros/src/transforms/events.rs @@ -47,10 +47,14 @@ pub fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { let mut from_signature_path = selector_path.clone(); from_signature_path.segments.push(ident("from_signature")); - let selector_fun_body = BlockExpression(vec![make_statement(StatementKind::Expression(call( - variable_path(from_signature_path), - vec![expression(ExpressionKind::Literal(Literal::Str(SIGNATURE_PLACEHOLDER.to_string())))], - )))]); + let selector_fun_body = BlockExpression { + statements: vec![make_statement(StatementKind::Expression(call( + variable_path(from_signature_path), + vec![expression(ExpressionKind::Literal(Literal::Str( + SIGNATURE_PLACEHOLDER.to_string(), + )))], + )))], + }; // Define `FunctionSelector` return type let return_type = diff --git a/aztec_macros/src/transforms/functions.rs b/aztec_macros/src/transforms/functions.rs index c719651e10e..2d84c2c8c44 100644 --- a/aztec_macros/src/transforms/functions.rs +++ b/aztec_macros/src/transforms/functions.rs @@ -39,29 +39,29 @@ pub fn transform_function( // Add check that msg sender equals this address and flag function as internal if is_internal { let is_internal_check = create_internal_check(func.name()); - func.def.body.0.insert(0, is_internal_check); + func.def.body.statements.insert(0, is_internal_check); } // Add initialization check if insert_init_check { let init_check = create_init_check(); - func.def.body.0.insert(0, init_check); + func.def.body.statements.insert(0, init_check); } // Add assertion for initialization arguments and sender if is_initializer { - func.def.body.0.insert(0, create_assert_initializer()); + func.def.body.statements.insert(0, create_assert_initializer()); } // Add access to the storage struct if storage_defined { let storage_def = abstract_storage(&ty.to_lowercase(), false); - func.def.body.0.insert(0, storage_def); + func.def.body.statements.insert(0, storage_def); } // Insert the context creation as the first action let create_context = create_context(&context_name, &func.def.parameters)?; - func.def.body.0.splice(0..0, (create_context).iter().cloned()); + func.def.body.statements.splice(0..0, (create_context).iter().cloned()); // Add the inputs to the params let input = create_inputs(&inputs_name); @@ -71,20 +71,20 @@ pub fn transform_function( if let Some(return_values) = abstract_return_values(func) { // In case we are pushing return values to the context, we remove the statement that originated it // This avoids running duplicate code, since blocks like if/else can be value returning statements - func.def.body.0.pop(); + func.def.body.statements.pop(); // Add the new return statement - func.def.body.0.push(return_values); + func.def.body.statements.push(return_values); } // Before returning mark the contract as initialized if is_initializer { let mark_initialized = create_mark_as_initialized(); - func.def.body.0.push(mark_initialized); + func.def.body.statements.push(mark_initialized); } // Push the finish method call to the end of the function let finish_def = create_context_finish(); - func.def.body.0.push(finish_def); + func.def.body.statements.push(finish_def); let return_type = create_return_type(&return_type_name); func.def.return_type = return_type; @@ -109,12 +109,16 @@ pub fn transform_vm_function( // Create access to storage if storage_defined { let storage = abstract_storage("public_vm", true); - func.def.body.0.insert(0, storage); + func.def.body.statements.insert(0, storage); } // Push Avm context creation to the beginning of the function let create_context = create_avm_context()?; - func.def.body.0.insert(0, create_context); + func.def.body.statements.insert(0, create_context); + + // Add the inputs to the params (first!) + let input = create_inputs("AvmContextInputs"); + func.def.parameters.insert(0, input); // We want the function to be seen as a public function func.def.is_unconstrained = true; @@ -131,7 +135,7 @@ pub fn transform_vm_function( /// /// This will allow developers to access their contract' storage struct in unconstrained functions pub fn transform_unconstrained(func: &mut NoirFunction) { - func.def.body.0.insert(0, abstract_storage("Unconstrained", true)); + func.def.body.statements.insert(0, abstract_storage("Unconstrained", true)); } /// Helper function that returns what the private context would look like in the ast @@ -232,62 +236,62 @@ fn create_assert_initializer() -> Statement { /// ```noir /// #[aztec(private)] /// fn foo(structInput: SomeStruct, arrayInput: [u8; 10], fieldInput: Field) -> Field { -/// // Create the hasher object -/// let mut hasher = Hasher::new(); +/// // Create the bounded vec object +/// let mut serialized_args = BoundedVec::new(); /// /// // struct inputs call serialize on them to add an array of fields -/// hasher.add_multiple(structInput.serialize()); +/// serialized_args.extend_from_array(structInput.serialize()); /// -/// // Array inputs are iterated over and each element is added to the hasher (as a field) +/// // Array inputs are iterated over and each element is added to the bounded vec (as a field) /// for i in 0..arrayInput.len() { -/// hasher.add(arrayInput[i] as Field); +/// serialized_args.push(arrayInput[i] as Field); /// } -/// // Field inputs are added to the hasher -/// hasher.add({ident}); +/// // Field inputs are added to the bounded vec +/// serialized_args.push({ident}); /// /// // Create the context /// // The inputs (injected by this `create_inputs`) and completed hash object are passed to the context -/// let mut context = PrivateContext::new(inputs, hasher.hash()); +/// let mut context = PrivateContext::new(inputs, hash_args(serialized_args)); /// } /// ``` fn create_context(ty: &str, params: &[Param]) -> Result, AztecMacroError> { let mut injected_expressions: Vec = vec![]; - // `let mut hasher = Hasher::new();` - let let_hasher = mutable_assignment( - "hasher", // Assigned to + // `let mut serialized_args = BoundedVec::new();` + let let_serialized_args = mutable_assignment( + "serialized_args", // Assigned to call( - variable_path(chained_dep!("aztec", "hasher", "Hasher", "new")), // Path - vec![], // args + variable_path(chained_dep!("std", "collections", "bounded_vec", "BoundedVec", "new")), // Path + vec![], // args ), ); - // Completes: `let mut hasher = Hasher::new();` - injected_expressions.push(let_hasher); + // Completes: `let mut serialized_args = BoundedVec::new();` + injected_expressions.push(let_serialized_args); - // Iterate over each of the function parameters, adding to them to the hasher + // Iterate over each of the function parameters, adding to them to the bounded vec for Param { pattern, typ, span, .. } in params { match pattern { Pattern::Identifier(identifier) => { // Match the type to determine the padding to do let unresolved_type = &typ.typ; let expression = match unresolved_type { - // `hasher.add_multiple({ident}.serialize())` - UnresolvedTypeData::Named(..) => add_struct_to_hasher(identifier), + // `serialized_args.extend_from_array({ident}.serialize())` + UnresolvedTypeData::Named(..) => add_struct_to_serialized_args(identifier), UnresolvedTypeData::Array(_, arr_type) => { - add_array_to_hasher(identifier, arr_type) + add_array_to_serialized_args(identifier, arr_type) } - // `hasher.add({ident})` - UnresolvedTypeData::FieldElement => add_field_to_hasher(identifier), - // Add the integer to the hasher, casted to a field - // `hasher.add({ident} as Field)` + // `serialized_args.push({ident})` + UnresolvedTypeData::FieldElement => add_field_to_serialized_args(identifier), + // Add the integer to the serialized args, casted to a field + // `serialized_args.push({ident} as Field)` UnresolvedTypeData::Integer(..) | UnresolvedTypeData::Bool => { - add_cast_to_hasher(identifier) + add_cast_to_serialized_args(identifier) } UnresolvedTypeData::String(..) => { let (var_bytes, id) = str_to_bytes(identifier); injected_expressions.push(var_bytes); - add_array_to_hasher( + add_array_to_serialized_args( &id, &UnresolvedType { typ: UnresolvedTypeData::Integer( @@ -313,11 +317,10 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac // Create the inputs to the context let inputs_expression = variable("inputs"); - // `hasher.hash()` - let hash_call = method_call( - variable("hasher"), // variable - "hash", // method name - vec![], // args + // `hash_args(serialized_args)` + let hash_call = call( + variable_path(chained_dep!("aztec", "hash", "hash_args")), // variable + vec![variable("serialized_args")], // args ); let path_snippet = ty.to_case(Case::Snake); // e.g. private_context @@ -354,11 +357,14 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac /// // ... /// } fn create_avm_context() -> Result { + // Create the inputs to the context + let inputs_expression = variable("inputs"); + let let_context = mutable_assignment( "context", // Assigned to call( variable_path(chained_dep!("aztec", "context", "AVMContext", "new")), // Path - vec![], // args + vec![inputs_expression], // args ), ); @@ -393,7 +399,7 @@ fn create_avm_context() -> Result { /// Any primitive type that can be cast will be casted to a field and pushed to the context. fn abstract_return_values(func: &NoirFunction) -> Option { let current_return_type = func.return_type().typ; - let last_statement = func.def.body.0.last()?; + let last_statement = func.def.body.statements.last()?; // TODO: (length, type) => We can limit the size of the array returned to be limited by kernel size // Doesn't need done until we have settled on a kernel size @@ -598,11 +604,11 @@ fn create_context_finish() -> Statement { } // -// Methods to create hasher inputs +// Methods to create hash_args inputs // -fn add_struct_to_hasher(identifier: &Ident) -> Statement { - // If this is a struct, we call serialize and add the array to the hasher +fn add_struct_to_serialized_args(identifier: &Ident) -> Statement { + // If this is a struct, we call serialize and add the array to the serialized args let serialized_call = method_call( variable_path(path(identifier.clone())), // variable "serialize", // method name @@ -610,9 +616,9 @@ fn add_struct_to_hasher(identifier: &Ident) -> Statement { ); make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add_multiple", // method name - vec![serialized_call], // args + variable("serialized_args"), // variable + "extend_from_array", // method name + vec![serialized_call], // args ))) } @@ -632,7 +638,7 @@ fn str_to_bytes(identifier: &Ident) -> (Statement, Ident) { } fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the hasher + // If this is an array of primitive types (integers / fields) we can add them each to the serialized args // casted to a field let span = var.span; @@ -644,8 +650,10 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { ); // What will be looped over - // - `hasher.add({ident}[i] as Field)` - let for_loop_block = expression(ExpressionKind::Block(BlockExpression(loop_body))); + + // - `serialized_args.push({ident}[i] as Field)` + let for_loop_block = + expression(ExpressionKind::Block(BlockExpression { statements: loop_body })); // `for i in 0..{ident}.len()` make_statement(StatementKind::For(ForLoopStatement { @@ -662,66 +670,66 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { })) } -fn add_array_to_hasher(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the hasher +fn add_array_to_serialized_args(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { + // If this is an array of primitive types (integers / fields) we can add them each to the serialized_args // casted to a field // Wrap in the semi thing - does that mean ended with semi colon? - // `hasher.add({ident}[i] as Field)` + // `serialized_args.push({ident}[i] as Field)` let arr_index = index_array(identifier.clone(), "i"); - let (add_expression, hasher_method_name) = match arr_type.typ { + let (add_expression, vec_method_name) = match arr_type.typ { UnresolvedTypeData::Named(..) => { - let hasher_method_name = "add_multiple".to_owned(); + let vec_method_name = "extend_from_array".to_owned(); let call = method_call( // All serialize on each element arr_index, // variable "serialize", // method name vec![], // args ); - (call, hasher_method_name) + (call, vec_method_name) } _ => { - let hasher_method_name = "add".to_owned(); + let vec_method_name = "push".to_owned(); let call = cast( arr_index, // lhs - `ident[i]` UnresolvedTypeData::FieldElement, // cast to - `as Field` ); - (call, hasher_method_name) + (call, vec_method_name) } }; let block_statement = make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - &hasher_method_name, // method name + variable("serialized_args"), // variable + &vec_method_name, // method name vec![add_expression], ))); create_loop_over(variable_ident(identifier.clone()), vec![block_statement]) } -fn add_field_to_hasher(identifier: &Ident) -> Statement { - // `hasher.add({ident})` +fn add_field_to_serialized_args(identifier: &Ident) -> Statement { + // `serialized_args.push({ident})` let ident = variable_path(path(identifier.clone())); make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add", // method name - vec![ident], // args + variable("serialized_args"), // variable + "push", // method name + vec![ident], // args ))) } -fn add_cast_to_hasher(identifier: &Ident) -> Statement { - // `hasher.add({ident} as Field)` +fn add_cast_to_serialized_args(identifier: &Ident) -> Statement { + // `serialized_args.push({ident} as Field)` // `{ident} as Field` let cast_operation = cast( variable_path(path(identifier.clone())), // lhs UnresolvedTypeData::FieldElement, // rhs ); - // `hasher.add({ident} as Field)` + // `serialized_args.push({ident} as Field)` make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add", // method name - vec![cast_operation], // args + variable("serialized_args"), // variable + "push", // method name + vec![cast_operation], // args ))) } diff --git a/aztec_macros/src/transforms/storage.rs b/aztec_macros/src/transforms/storage.rs index 40a094f78e3..10f44d01bb4 100644 --- a/aztec_macros/src/transforms/storage.rs +++ b/aztec_macros/src/transforms/storage.rs @@ -150,7 +150,7 @@ pub fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), true, )), )], - &BlockExpression(vec![storage_constructor_statement]), + &BlockExpression { statements: vec![storage_constructor_statement] }, &[], &return_type(chained_path!("Self")), )); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 36e5c99a2ca..874be06b86c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,7 +1,7 @@ use acvm::acir::{brillig::BlackBoxOp, BlackBoxFunc}; use crate::brillig::brillig_ir::{ - brillig_variable::{BrilligVariable, BrilligVector}, + brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, BrilligContext, }; @@ -56,17 +56,23 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::Keccak256 => { if let ( - [message, BrilligVariable::SingleAddr(array_size)], + [message, BrilligVariable::SingleAddr(message_size)], [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { let mut message_vector = convert_array_or_vector(brillig_context, message, bb_func); - message_vector.size = array_size.address; + let message_size_as_usize = + SingleAddrVariable::new_usize(brillig_context.allocate_register()); + // Message_size is not usize + brillig_context.cast_instruction(message_size_as_usize, *message_size); + + message_vector.size = message_size_as_usize.address; brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { message: message_vector.to_heap_vector(), output: result_array.to_heap_array(), }); + brillig_context.deallocate_single_addr(message_size_as_usize); } else { unreachable!("ICE: Keccak256 expects message, message size and result array") } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 94e81d02053..cf2501ab1c0 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -514,7 +514,7 @@ impl<'block> BrilligBlock<'block> { .extract_vector(); // Update the user-facing slice length - self.brillig_context.mov_instruction(target_len.address, limb_count.address); + self.brillig_context.cast_instruction(target_len, limb_count); self.brillig_context.codegen_to_radix( source, @@ -522,6 +522,7 @@ impl<'block> BrilligBlock<'block> { radix, limb_count, matches!(endianness, Endian::Big), + 8, ); } Value::Intrinsic(Intrinsic::ToBits(endianness)) => { @@ -554,7 +555,7 @@ impl<'block> BrilligBlock<'block> { let radix = self.brillig_context.make_constant_instruction(2_usize.into(), 32); // Update the user-facing slice length - self.brillig_context.mov_instruction(target_len.address, limb_count.address); + self.brillig_context.cast_instruction(target_len, limb_count); self.brillig_context.codegen_to_radix( source, @@ -562,6 +563,7 @@ impl<'block> BrilligBlock<'block> { radix, limb_count, matches!(endianness, Endian::Big), + 1, ); self.brillig_context.deallocate_single_addr(radix); @@ -654,7 +656,7 @@ impl<'block> BrilligBlock<'block> { // Create a field constant with the max let max = BigUint::from(2_u128).pow(*max_bit_size) - BigUint::from(1_u128); let right = self.brillig_context.make_constant_instruction( - FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), + FieldElement::from_be_bytes_reduce(&max.to_bytes_be()), FieldElement::max_num_bits(), ); @@ -1584,7 +1586,7 @@ impl<'block> BrilligBlock<'block> { self.variables.allocate_constant(self.brillig_context, value_id, dfg); self.brillig_context - .const_instruction(new_variable.extract_single_addr(), (*constant).into()); + .const_instruction(new_variable.extract_single_addr(), *constant); new_variable } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index dc9900daee3..892e82d771a 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -2,7 +2,10 @@ use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ brillig::brillig_ir::{ - brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, + brillig_variable::{ + get_bit_size_from_ssa_type, BrilligArray, BrilligVariable, BrilligVector, + SingleAddrVariable, + }, BrilligContext, }, ssa::ir::{ @@ -13,7 +16,7 @@ use crate::{ }, }; -use super::brillig_fn::{get_bit_size_from_ssa_type, FunctionContext}; +use super::brillig_fn::FunctionContext; #[derive(Debug, Default)] pub(crate) struct BlockVariables { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 26b21e918ff..15a2a531e78 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,5 +1,5 @@ use acvm::{ - acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value}, + acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode}, FieldElement, }; @@ -16,18 +16,32 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // We store the result in this register too. let input = MemoryAddress::from(0); let one_const = MemoryAddress::from(1); + let zero_const = MemoryAddress::from(2); + let input_is_zero = MemoryAddress::from(3); // Location of the stop opcode - let stop_location = 3; + let stop_location = 6; GeneratedBrillig { byte_code: vec![ BrilligOpcode::CalldataCopy { destination_address: input, size: 1, offset: 0 }, + // Put value zero in register (2) + BrilligOpcode::Const { + destination: zero_const, + value: FieldElement::from(0_usize), + bit_size: FieldElement::max_num_bits(), + }, + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + lhs: input, + rhs: zero_const, + destination: input_is_zero, + }, // If the input is zero, then we jump to the stop opcode - BrilligOpcode::JumpIfNot { condition: input, location: stop_location }, + BrilligOpcode::JumpIf { condition: input_is_zero, location: stop_location }, // Put value one in register (1) BrilligOpcode::Const { destination: one_const, - value: Value::from(1_usize), + value: FieldElement::from(1_usize), bit_size: FieldElement::max_num_bits(), }, // Divide 1 by the input, and set the result of the division into register (0) @@ -53,9 +67,12 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { /// (a/b, a-a/b*b) /// } /// ``` -pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { +pub(crate) fn directive_quotient(mut bit_size: u32) -> GeneratedBrillig { // `a` is (0) (i.e register index 0) // `b` is (1) + if bit_size > FieldElement::max_num_bits() { + bit_size = FieldElement::max_num_bits(); + } GeneratedBrillig { byte_code: vec![ BrilligOpcode::CalldataCopy { @@ -63,6 +80,16 @@ pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { size: 2, offset: 0, }, + BrilligOpcode::Cast { + destination: MemoryAddress(0), + source: MemoryAddress(0), + bit_size, + }, + BrilligOpcode::Cast { + destination: MemoryAddress(1), + source: MemoryAddress(1), + bit_size, + }, //q = a/b is set into register (2) BrilligOpcode::BinaryIntOp { op: BinaryIntOp::Div, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index 42765d10ce2..92027026ce8 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -3,8 +3,8 @@ use iter_extended::vecmap; use crate::{ brillig::brillig_ir::{ artifact::{BrilligParameter, Label}, - brillig_variable::BrilligVariable, - BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + brillig_variable::{get_bit_size_from_ssa_type, BrilligVariable}, + BrilligContext, }, ssa::ir::{ basic_block::BasicBlockId, @@ -112,15 +112,3 @@ impl FunctionContext { .collect() } } - -pub(crate) fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { - match typ { - Type::Numeric(num_type) => num_type.bit_size(), - Type::Reference(_) => BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - // NB. function references are converted to a constant when - // translating from SSA to Brillig (to allow for debugger - // instrumentation to work properly) - Type::Function => 32, - _ => unreachable!("ICE bit size not on a non numeric type"), - } -} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 98dd17ce080..e42b2787f73 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -354,7 +354,7 @@ impl<'block> BrilligBlock<'block> { mod tests { use std::vec; - use acvm::acir::brillig::Value; + use acvm::FieldElement; use crate::brillig::brillig_gen::brillig_block::BrilligBlock; use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; @@ -400,9 +400,9 @@ mod tests { fn test_slice_push_operation() { fn test_case_push( push_back: bool, - array: Vec, - item_to_push: Value, - expected_return: Vec, + array: Vec, + item_to_push: FieldElement, + expected_return: Vec, ) { let arguments = vec![ BrilligParameter::Array( @@ -462,44 +462,65 @@ mod tests { create_and_run_vm(array.into_iter().chain(vec![item_to_push]).collect(), &bytecode); assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_push( true, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], + FieldElement::from(27_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(27_usize), + ], + ); + test_case_push( + true, + vec![], + FieldElement::from(27_usize), + vec![FieldElement::from(27_usize)], ); - test_case_push(true, vec![], Value::from(27_usize), vec![Value::from(27_usize)]); test_case_push( false, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), vec![ - Value::from(27_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + vec![ + FieldElement::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], ); - test_case_push(false, vec![], Value::from(27_usize), vec![Value::from(27_usize)]); + test_case_push( + false, + vec![], + FieldElement::from(27_usize), + vec![FieldElement::from(27_usize)], + ); } #[test] fn test_slice_pop_back_operation() { fn test_case_pop( pop_back: bool, - array: Vec, - expected_return_array: Vec, - expected_return_item: Value, + array: Vec, + expected_return_array: Vec, + expected_return_item: FieldElement, ) { let arguments = vec![BrilligParameter::Array( vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], @@ -566,33 +587,44 @@ mod tests { assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_pop( true, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![Value::from(1_usize), Value::from(2_usize)], - Value::from(3_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + vec![FieldElement::from(1_usize), FieldElement::from(2_usize)], + FieldElement::from(3_usize), ); - test_case_pop(true, vec![Value::from(1_usize)], vec![], Value::from(1_usize)); + test_case_pop(true, vec![FieldElement::from(1_usize)], vec![], FieldElement::from(1_usize)); test_case_pop( false, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![Value::from(2_usize), Value::from(3_usize)], - Value::from(1_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + vec![FieldElement::from(2_usize), FieldElement::from(3_usize)], + FieldElement::from(1_usize), ); } #[test] fn test_slice_insert_operation() { fn test_case_insert( - array: Vec, - item: Value, - index: Value, - expected_return: Vec, + array: Vec, + item: FieldElement, + index: FieldElement, + expected_return: Vec, ) { let arguments = vec![ BrilligParameter::Array( @@ -651,71 +683,90 @@ mod tests { assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(1_usize), vec![ - Value::from(1_usize), - Value::from(27_usize), - Value::from(2_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(1_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(27_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], ); test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(0_usize), vec![ - Value::from(27_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(0_usize), + vec![ + FieldElement::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], ); test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(2_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(27_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(2_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(27_usize), + FieldElement::from(3_usize), ], ); test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(3_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(3_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(27_usize), ], ); test_case_insert( vec![], - Value::from(27_usize), - Value::from(0_usize), - vec![Value::from(27_usize)], + FieldElement::from(27_usize), + FieldElement::from(0_usize), + vec![FieldElement::from(27_usize)], ); } #[test] fn test_slice_remove_operation() { fn test_case_remove( - array: Vec, - index: Value, - expected_array: Vec, - expected_removed_item: Value, + array: Vec, + index: FieldElement, + expected_array: Vec, + expected_removed_item: FieldElement, ) { let arguments = vec![ BrilligParameter::Array( @@ -784,36 +835,51 @@ mod tests { assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(0_usize), - vec![Value::from(2_usize), Value::from(3_usize)], - Value::from(1_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(0_usize), + vec![FieldElement::from(2_usize), FieldElement::from(3_usize)], + FieldElement::from(1_usize), ); test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(1_usize), - vec![Value::from(1_usize), Value::from(3_usize)], - Value::from(2_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(1_usize), + vec![FieldElement::from(1_usize), FieldElement::from(3_usize)], + FieldElement::from(2_usize), ); test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(2_usize), - vec![Value::from(1_usize), Value::from(2_usize)], - Value::from(3_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(2_usize), + vec![FieldElement::from(1_usize), FieldElement::from(2_usize)], + FieldElement::from(3_usize), ); test_case_remove( - vec![Value::from(1_usize)], - Value::from(0_usize), + vec![FieldElement::from(1_usize)], + FieldElement::from(0_usize), vec![], - Value::from(1_usize), + FieldElement::from(1_usize), ); } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 9138f57083a..e5c731be679 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -122,7 +122,7 @@ pub(crate) mod tests { use std::vec; use acvm::acir::brillig::{ - ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, ValueOrArray, + ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, ValueOrArray, }; use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; @@ -205,7 +205,7 @@ pub(crate) mod tests { } pub(crate) fn create_and_run_vm( - calldata: Vec, + calldata: Vec, bytecode: &[BrilligOpcode], ) -> (VM<'_, DummyBlackBoxSolver>, usize, usize) { let mut vm = VM::new(calldata, bytecode, vec![], &DummyBlackBoxSolver); @@ -234,20 +234,20 @@ pub(crate) mod tests { let mut context = BrilligContext::new(true); let r_stack = ReservedRegisters::free_memory_pointer(); // Start stack pointer at 0 - context.usize_const_instruction(r_stack, Value::from(ReservedRegisters::len() + 3)); + context.usize_const_instruction(r_stack, FieldElement::from(ReservedRegisters::len() + 3)); let r_input_size = MemoryAddress::from(ReservedRegisters::len()); let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); - context.usize_const_instruction(r_input_size, Value::from(12_usize)); + context.usize_const_instruction(r_input_size, FieldElement::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); context.foreign_call_instruction( "make_number_sequence".into(), &[ValueOrArray::MemoryAddress(r_input_size)], - &[HeapValueType::Simple], + &[HeapValueType::Simple(32)], &[ValueOrArray::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], - &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple(32)] }], ); // push stack frame by r_returned_size context.memory_op_instruction(r_stack, r_output_size, r_stack, BrilligBinaryOp::Add); @@ -266,8 +266,9 @@ pub(crate) mod tests { context.stop_instruction(); - let bytecode = context.artifact().finish().byte_code; - let number_sequence: Vec = (0_usize..12_usize).map(Value::from).collect(); + let bytecode: Vec = context.artifact().finish().byte_code; + let number_sequence: Vec = + (0_usize..12_usize).map(FieldElement::from).collect(); let mut vm = VM::new( vec![], &bytecode, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index b415421dd92..bbfdbb69f7c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -125,7 +125,9 @@ impl BrilligVariable { pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { match typ { - Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Numeric(_) | Type::Reference(_) | Type::Function => { + HeapValueType::Simple(get_bit_size_from_ssa_type(typ)) + } Type::Array(elem_type, size) => HeapValueType::Array { value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), size: typ.element_size() * size, @@ -135,3 +137,14 @@ pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { }, } } + +pub(crate) fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { + match typ { + Type::Reference(_) => BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + // NB. function references are converted to a constant when + // translating from SSA to Brillig (to allow for debugger + // instrumentation to work properly) + Type::Function => 32, + typ => typ.bit_size(), + } +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs index 248a304d820..4ef279bd532 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs @@ -1,4 +1,4 @@ -use acvm::acir::brillig::{MemoryAddress, Value}; +use acvm::{acir::brillig::MemoryAddress, FieldElement}; use super::{instructions::BrilligBinaryOp, BrilligContext}; @@ -21,7 +21,7 @@ impl BrilligContext { op: BrilligBinaryOp, constant: usize, ) { - let const_register = self.make_usize_constant_instruction(Value::from(constant)); + let const_register = self.make_usize_constant_instruction(FieldElement::from(constant)); self.memory_op_instruction(operand, const_register.address, destination, op); // Mark as no longer used for this purpose, frees for reuse self.deallocate_single_addr(const_register); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index be262d9dee7..ab756217bcd 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -39,6 +39,7 @@ impl BrilligContext { radix: SingleAddrVariable, limb_count: SingleAddrVariable, big_endian: bool, + limb_bit_size: u32, ) { assert!(source_field.bit_size == FieldElement::max_num_bits()); assert!(radix.bit_size == 32); @@ -55,19 +56,23 @@ impl BrilligContext { SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); self.mov_instruction(shifted_field.address, source_field.address); - let modulus_field = + let limb_field = SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + let limb_casted = SingleAddrVariable::new(self.allocate_register(), limb_bit_size); + self.codegen_loop(target_vector.size, |ctx, iterator_register| { // Compute the modulus ctx.binary_instruction( shifted_field, radix_as_field, - modulus_field, + limb_field, BrilligBinaryOp::Modulo, ); + // Cast it + ctx.cast_instruction(limb_casted, limb_field); // Write it - ctx.codegen_array_set(target_vector.pointer, iterator_register, modulus_field.address); + ctx.codegen_array_set(target_vector.pointer, iterator_register, limb_casted.address); // Integer div the field ctx.binary_instruction( shifted_field, @@ -79,7 +84,8 @@ impl BrilligContext { // Deallocate our temporary registers self.deallocate_single_addr(shifted_field); - self.deallocate_single_addr(modulus_field); + self.deallocate_single_addr(limb_field); + self.deallocate_single_addr(limb_casted); self.deallocate_single_addr(radix_as_field); if big_endian { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 5611905697c..4ca1144b6a4 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -2,7 +2,10 @@ use super::BrilligBinaryOp; use crate::brillig::brillig_ir::ReservedRegisters; -use acvm::acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, Value, ValueOrArray}; +use acvm::{ + acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, ValueOrArray}, + FieldElement, +}; /// Trait for converting values into debug-friendly strings. trait DebugToString { @@ -66,9 +69,9 @@ impl DebugToString for BrilligBinaryOp { } } -impl DebugToString for Value { +impl DebugToString for FieldElement { fn debug_to_string(&self) -> String { - self.to_usize().to_string() + self.to_string() } } @@ -167,7 +170,7 @@ impl DebugShow { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: Value) { + pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: FieldElement) { debug_println!(self.enable_debug_trace, " CONST {} = {}", result, constant); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 14c4ada8606..1d823ded718 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -453,7 +453,8 @@ impl BrilligContext { #[cfg(test)] mod tests { - use acvm::brillig_vm::brillig::Value; + + use acvm::FieldElement; use crate::brillig::brillig_ir::{ artifact::BrilligParameter, @@ -464,12 +465,12 @@ mod tests { #[test] fn entry_point_with_nested_array_parameter() { let calldata = vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(4_usize), + FieldElement::from(5_usize), + FieldElement::from(6_usize), ]; let arguments = vec![BrilligParameter::Array( vec![ @@ -496,18 +497,18 @@ mod tests { let (vm, return_data_offset, return_data_size) = create_and_run_vm(calldata.clone(), &bytecode); assert_eq!(return_data_size, 1, "Return data size is incorrect"); - assert_eq!(vm.get_memory()[return_data_offset], Value::from(1_usize)); + assert_eq!(vm.get_memory()[return_data_offset].value, FieldElement::from(1_usize)); } #[test] fn entry_point_with_nested_array_return() { let flattened_array = vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(4_usize), + FieldElement::from(5_usize), + FieldElement::from(6_usize), ]; let array_param = BrilligParameter::Array( vec![ @@ -536,7 +537,10 @@ mod tests { let memory = vm.get_memory(); assert_eq!( - memory[return_data_pointer..(return_data_pointer + flattened_array.len())], + memory[return_data_pointer..(return_data_pointer + flattened_array.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), flattened_array ); assert_eq!(return_data_size, flattened_array.len()); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index 99fb4c89f64..f305eb81b01 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -1,7 +1,7 @@ use acvm::{ acir::brillig::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, MemoryAddress, - Opcode as BrilligOpcode, Value, ValueOrArray, + Opcode as BrilligOpcode, ValueOrArray, }, FieldElement, }; @@ -43,7 +43,7 @@ impl BrilligContext { // Compile !x as ((-1) - x) let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(input.bit_size as i128)) - FieldElement::one(); - let max = self.make_constant(Value::from(u_max), input.bit_size); + let max = self.make_constant(u_max, input.bit_size); self.binary(max, input, result, BrilligBinaryOp::Sub); self.deallocate_single_addr(max); @@ -397,21 +397,23 @@ impl BrilligContext { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: Value) { + pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: FieldElement) { self.debug_show.const_instruction(result.address, constant); self.constant(result, constant); } - fn constant(&mut self, result: SingleAddrVariable, constant: Value) { - if result.bit_size > 128 && !constant.to_field().fits_in_u128() { - let high = Value::from(FieldElement::from_be_bytes_reduce( - constant - .to_field() - .to_be_bytes() - .get(0..16) - .expect("FieldElement::to_be_bytes() too short!"), - )); - let low = Value::from(constant.to_u128()); + fn constant(&mut self, result: SingleAddrVariable, constant: FieldElement) { + assert!( + result.bit_size >= constant.num_bits(), + "Constant {} does not fit in bit size {}", + constant, + result.bit_size + ); + if result.bit_size > 128 && !constant.fits_in_u128() { + let high = FieldElement::from_be_bytes_reduce( + constant.to_be_bytes().get(0..16).expect("FieldElement::to_be_bytes() too short!"), + ); + let low = FieldElement::from(constant.to_u128()); let high_register = SingleAddrVariable::new(self.allocate_register(), 254); let low_register = SingleAddrVariable::new(self.allocate_register(), 254); let intermediate_register = SingleAddrVariable::new(self.allocate_register(), 254); @@ -419,7 +421,7 @@ impl BrilligContext { self.constant(low_register, low); // I want to multiply high by 2^128, but I can't get that big constant in. // So I'll multiply by 2^64 twice. - self.constant(intermediate_register, Value::from(1_u128 << 64)); + self.constant(intermediate_register, FieldElement::from(1_u128 << 64)); self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); // Now we can add. @@ -437,14 +439,18 @@ impl BrilligContext { } } - pub(crate) fn usize_const_instruction(&mut self, result: MemoryAddress, constant: Value) { + pub(crate) fn usize_const_instruction( + &mut self, + result: MemoryAddress, + constant: FieldElement, + ) { self.const_instruction(SingleAddrVariable::new_usize(result), constant); } /// Returns a register which holds the value of a constant pub(crate) fn make_constant_instruction( &mut self, - constant: Value, + constant: FieldElement, bit_size: u32, ) -> SingleAddrVariable { let var = SingleAddrVariable::new(self.allocate_register(), bit_size); @@ -452,7 +458,7 @@ impl BrilligContext { var } - fn make_constant(&mut self, constant: Value, bit_size: u32) -> SingleAddrVariable { + fn make_constant(&mut self, constant: FieldElement, bit_size: u32) -> SingleAddrVariable { let var = SingleAddrVariable::new(self.allocate_register(), bit_size); self.constant(var, constant); var @@ -461,7 +467,7 @@ impl BrilligContext { /// Returns a register which holds the value of an usize constant pub(crate) fn make_usize_constant_instruction( &mut self, - constant: Value, + constant: FieldElement, ) -> SingleAddrVariable { let register = self.allocate_register(); self.usize_const_instruction(register, constant); diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index fb11bae556c..7e951cf4e00 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -11,7 +11,7 @@ use acvm::acir::circuit::brillig::{BrilligInputs, BrilligOutputs}; use acvm::acir::circuit::opcodes::{BlockId, MemOp}; use acvm::acir::circuit::Opcode; use acvm::blackbox_solver; -use acvm::brillig_vm::{brillig::Value, VMStatus, VM}; +use acvm::brillig_vm::{MemoryValue, VMStatus, VM}; use acvm::{ acir::{ brillig::Opcode as BrilligOpcode, @@ -1623,7 +1623,7 @@ impl AcirContext { let outputs_var = vecmap(outputs_types.iter(), |output| match output { AcirType::NumericType(_) => { let var = self.add_data(AcirVarData::Const( - memory.next().expect("Missing return data").to_field(), + memory.next().expect("Missing return data").value, )); AcirValue::Var(var, output.clone()) } @@ -1640,7 +1640,7 @@ impl AcirContext { &mut self, element_types: &[AcirType], size: usize, - memory_iter: &mut impl Iterator, + memory_iter: &mut impl Iterator, ) -> AcirValue { let mut array_values = im::Vector::new(); for _ in 0..size { @@ -1657,7 +1657,7 @@ impl AcirContext { AcirType::NumericType(_) => { let memory_value = memory_iter.next().expect("ICE: Unexpected end of memory"); - let var = self.add_data(AcirVarData::Const(memory_value.to_field())); + let var = self.add_data(AcirVarData::Const(memory_value.value)); array_values.push_back(AcirValue::Var(var, element_type.clone())); } } @@ -1839,21 +1839,21 @@ pub(crate) struct AcirVar(usize); /// Returns the finished state of the Brillig VM if execution can complete. /// /// Returns `None` if complete execution of the Brillig bytecode is not possible. -fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option> { +fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option> { // Set input values - let mut calldata: Vec = Vec::new(); + let mut calldata: Vec = Vec::new(); // Each input represents a constant or array of constants. // Iterate over each input and push it into registers and/or memory. for input in inputs { match input { BrilligInputs::Single(expr) => { - calldata.push(expr.to_const()?.into()); + calldata.push(expr.to_const()?); } BrilligInputs::Array(expr_arr) => { // Attempt to fetch all array input values for expr in expr_arr.iter() { - calldata.push(expr.to_const()?.into()); + calldata.push(expr.to_const()?); } } BrilligInputs::MemoryArray(_) => { diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 8b800e0db54..5b268de239d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -85,10 +85,11 @@ pub(super) fn simplify_call( } } Intrinsic::AsSlice => { - let slice = dfg.get_array_constant(arguments[0]); - if let Some((slice, element_type)) = slice { - let slice_length = dfg.make_constant(slice.len().into(), Type::length_type()); - let new_slice = dfg.make_array(slice, element_type); + let array = dfg.get_array_constant(arguments[0]); + if let Some((array, array_type)) = array { + let slice_length = dfg.make_constant(array.len().into(), Type::length_type()); + let inner_element_types = array_type.element_types(); + let new_slice = dfg.make_array(array, Type::Slice(inner_element_types)); SimplifyResult::SimplifiedToMultiple(vec![slice_length, new_slice]) } else { SimplifyResult::None diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index ea3f5393245..48036580d29 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -159,6 +159,13 @@ impl Type { Type::Reference(element) => element.contains_an_array(), } } + + pub(crate) fn element_types(self) -> Rc> { + match self { + Type::Array(element_types, _) | Type::Slice(element_types) => element_types, + other => panic!("element_types: Expected array or slice, found {other}"), + } + } } /// Composite Types are essentially flattened struct or tuple types. diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index bdfc04f0bbe..93e52542278 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -73,6 +73,7 @@ impl<'a> SliceCapacityTracker<'a> { Intrinsic::SlicePopFront => (Some(1), results.len() - 1), // The slice capacity of these intrinsics is not determined by the arguments of the function. Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => (None, 1), + Intrinsic::AsSlice => (Some(0), 1), _ => return, }; let result_slice = results[result_index]; @@ -90,6 +91,7 @@ impl<'a> SliceCapacityTracker<'a> { self.compute_slice_capacity(*arg, slice_sizes); } } + if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { let new_capacity = *contents_capacity + 1; slice_sizes.insert(result_slice, new_capacity); @@ -102,9 +104,6 @@ impl<'a> SliceCapacityTracker<'a> { .expect("ICE: Should have an argument index for slice intrinsics"); let slice_contents = arguments[argument_index]; - // We do not decrement the size on intrinsics that could remove values from a slice. - // This is because we could potentially go back to the smaller slice and not fill in dummies. - // This pass should be tracking the potential max that a slice ***could be*** if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { let new_capacity = *contents_capacity - 1; slice_sizes.insert(result_slice, new_capacity); @@ -121,6 +120,15 @@ impl<'a> SliceCapacityTracker<'a> { slice_sizes .insert(result_slice, FieldElement::max_num_bytes() as usize); } + Intrinsic::AsSlice => { + let argument_index = argument_index + .expect("ICE: Should have an argument index for AsSlice builtin"); + let array_size = self + .dfg + .try_get_array_length(arguments[argument_index]) + .expect("ICE: Should be have an array length for AsSlice input"); + slice_sizes.insert(result_slice, array_size); + } _ => {} } } diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index d646a6ca98a..0e5919bf7db 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -192,16 +192,18 @@ impl Expression { // with tuples without calling them. E.g. `if c { t } else { e }(a, b)` is interpreted // as a sequence of { if, tuple } rather than a function call. This behavior matches rust. let kind = if matches!(&lhs.kind, ExpressionKind::If(..)) { - ExpressionKind::Block(BlockExpression(vec![ - Statement { kind: StatementKind::Expression(lhs), span }, - Statement { - kind: StatementKind::Expression(Expression::new( - ExpressionKind::Tuple(arguments), + ExpressionKind::Block(BlockExpression { + statements: vec![ + Statement { kind: StatementKind::Expression(lhs), span }, + Statement { + kind: StatementKind::Expression(Expression::new( + ExpressionKind::Tuple(arguments), + span, + )), span, - )), - span, - }, - ])) + }, + ], + }) } else { ExpressionKind::Call(Box::new(CallExpression { func: Box::new(lhs), arguments })) }; @@ -452,19 +454,21 @@ pub struct IndexExpression { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct BlockExpression(pub Vec); +pub struct BlockExpression { + pub statements: Vec, +} impl BlockExpression { pub fn pop(&mut self) -> Option { - self.0.pop().map(|stmt| stmt.kind) + self.statements.pop().map(|stmt| stmt.kind) } pub fn len(&self) -> usize { - self.0.len() + self.statements.len() } pub fn is_empty(&self) -> bool { - self.0.is_empty() + self.statements.is_empty() } } @@ -542,7 +546,7 @@ impl Display for Literal { impl Display for BlockExpression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "{{")?; - for statement in &self.0 { + for statement in &self.statements { let statement = statement.kind.to_string(); for line in statement.lines() { writeln!(f, " {line}")?; diff --git a/compiler/noirc_frontend/src/ast/function.rs b/compiler/noirc_frontend/src/ast/function.rs index 46f0ac0fa0f..3e8b78c1312 100644 --- a/compiler/noirc_frontend/src/ast/function.rs +++ b/compiler/noirc_frontend/src/ast/function.rs @@ -83,7 +83,7 @@ impl NoirFunction { &mut self.def } pub fn number_of_statements(&self) -> usize { - self.def.body.0.len() + self.def.body.statements.len() } pub fn span(&self) -> Span { self.def.span diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index fb7f520ee71..b14ead8ad42 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -603,10 +603,12 @@ impl ForRange { }; let block_span = block.span; - let new_block = BlockExpression(vec![ - let_elem, - Statement { kind: StatementKind::Expression(block), span: block_span }, - ]); + let new_block = BlockExpression { + statements: vec![ + let_elem, + Statement { kind: StatementKind::Expression(block), span: block_span }, + ], + }; let new_block = Expression::new(ExpressionKind::Block(new_block), block_span); let for_loop = Statement { kind: StatementKind::For(ForLoopStatement { @@ -618,7 +620,9 @@ impl ForRange { span: for_loop_span, }; - let block = ExpressionKind::Block(BlockExpression(vec![let_array, for_loop])); + let block = ExpressionKind::Block(BlockExpression { + statements: vec![let_array, for_loop], + }); StatementKind::Expression(Expression::new(block, for_loop_span)) } } diff --git a/compiler/noirc_frontend/src/debug/mod.rs b/compiler/noirc_frontend/src/debug/mod.rs index 05916502d73..8e5c174d270 100644 --- a/compiler/noirc_frontend/src/debug/mod.rs +++ b/compiler/noirc_frontend/src/debug/mod.rs @@ -113,7 +113,7 @@ impl DebugInstrumenter { }) .collect(); - let func_body = &mut func.body.0; + let func_body = &mut func.body.statements; let mut statements = take(func_body); self.walk_scope(&mut statements, func.span); @@ -243,7 +243,9 @@ impl DebugInstrumenter { pattern: ast::Pattern::Tuple(vars_pattern, let_stmt.pattern.span()), r#type: ast::UnresolvedType::unspecified(), expression: ast::Expression { - kind: ast::ExpressionKind::Block(ast::BlockExpression(block_stmts)), + kind: ast::ExpressionKind::Block(ast::BlockExpression { + statements: block_stmts, + }), span: let_stmt.expression.span, }, }), @@ -330,11 +332,13 @@ impl DebugInstrumenter { kind: ast::StatementKind::Assign(ast::AssignStatement { lvalue: assign_stmt.lvalue.clone(), expression: ast::Expression { - kind: ast::ExpressionKind::Block(ast::BlockExpression(vec![ - ast::Statement { kind: let_kind, span: expression_span }, - new_assign_stmt, - ast::Statement { kind: ret_kind, span: expression_span }, - ])), + kind: ast::ExpressionKind::Block(ast::BlockExpression { + statements: vec![ + ast::Statement { kind: let_kind, span: expression_span }, + new_assign_stmt, + ast::Statement { kind: ret_kind, span: expression_span }, + ], + }), span: expression_span, }, }), @@ -344,7 +348,7 @@ impl DebugInstrumenter { fn walk_expr(&mut self, expr: &mut ast::Expression) { match &mut expr.kind { - ast::ExpressionKind::Block(ast::BlockExpression(ref mut statements)) => { + ast::ExpressionKind::Block(ast::BlockExpression { ref mut statements, .. }) => { self.scope.push(HashMap::default()); self.walk_scope(statements, expr.span); } @@ -415,14 +419,16 @@ impl DebugInstrumenter { self.walk_expr(&mut for_stmt.block); for_stmt.block = ast::Expression { - kind: ast::ExpressionKind::Block(ast::BlockExpression(vec![ - set_stmt, - ast::Statement { - kind: ast::StatementKind::Semi(for_stmt.block.clone()), - span: for_stmt.block.span, - }, - drop_stmt, - ])), + kind: ast::ExpressionKind::Block(ast::BlockExpression { + statements: vec![ + set_stmt, + ast::Statement { + kind: ast::StatementKind::Semi(for_stmt.block.clone()), + span: for_stmt.block.span, + }, + drop_stmt, + ], + }), span: for_stmt.span, }; } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 3fbde8a890b..f8e3c4cab60 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -252,7 +252,7 @@ impl<'a> Resolver<'a> { typ: typ.clone(), span: name.span(), }), - body: BlockExpression(Vec::new()), + body: BlockExpression { statements: Vec::new() }, span: name.span(), where_clause: where_clause.to_vec(), return_type: return_type.clone(), @@ -1952,8 +1952,8 @@ impl<'a> Resolver<'a> { fn resolve_block(&mut self, block_expr: BlockExpression) -> HirExpression { let statements = - self.in_new_scope(|this| vecmap(block_expr.0, |stmt| this.intern_stmt(stmt))); - HirExpression::Block(HirBlockExpression(statements)) + self.in_new_scope(|this| vecmap(block_expr.statements, |stmt| this.intern_stmt(stmt))); + HirExpression::Block(HirBlockExpression { statements }) } pub fn intern_block(&mut self, block: BlockExpression) -> ExprId { diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 642cebc83b0..6beb6929ce1 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -140,6 +140,8 @@ pub enum TypeCheckError { method_name: String, span: Span, }, + #[error("Strings do not support indexed assignment")] + StringIndexAssign { span: Span }, } impl TypeCheckError { @@ -237,7 +239,8 @@ impl From for Diagnostic { | TypeCheckError::ConstrainedReferenceToUnconstrained { span } | TypeCheckError::UnconstrainedReferenceToConstrained { span } | TypeCheckError::UnconstrainedSliceReturnToConstrained { span } - | TypeCheckError::NonConstantSliceLength { span } => { + | TypeCheckError::NonConstantSliceLength { span } + | TypeCheckError::StringIndexAssign { span } => { Diagnostic::simple_error(error.to_string(), String::new(), span) } TypeCheckError::PublicReturnType { typ, span } => Diagnostic::simple_error( diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index ab759f454e5..137608f8037 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -468,7 +468,8 @@ mod test { expression: expr_id, }; let stmt_id = interner.push_stmt(HirStatement::Let(let_stmt)); - let expr_id = interner.push_expr(HirExpression::Block(HirBlockExpression(vec![stmt_id]))); + let expr_id = interner + .push_expr(HirExpression::Block(HirBlockExpression { statements: vec![stmt_id] })); interner.push_expr_location(expr_id, Span::single_char(0), file); // Create function to enclose the let statement diff --git a/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/compiler/noirc_frontend/src/hir/type_check/stmt.rs index 49ba3244dc9..69363d5f00a 100644 --- a/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -258,6 +258,11 @@ impl<'interner> TypeChecker<'interner> { Type::Array(_, elem_type) => *elem_type, Type::Slice(elem_type) => *elem_type, Type::Error => Type::Error, + Type::String(_) => { + let (_lvalue_name, lvalue_span) = self.get_lvalue_name_and_span(&lvalue); + self.errors.push(TypeCheckError::StringIndexAssign { span: lvalue_span }); + Type::Error + } other => { // TODO: Need a better span here self.errors.push(TypeCheckError::TypeMismatch { diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index 61743d2cdc7..c2f6031bf6d 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -37,7 +37,7 @@ pub enum HirExpression { impl HirExpression { /// Returns an empty block expression pub const fn empty_block() -> HirExpression { - HirExpression::Block(HirBlockExpression(vec![])) + HirExpression::Block(HirBlockExpression { statements: vec![] }) } } @@ -249,11 +249,13 @@ pub struct HirIndexExpression { } #[derive(Debug, Clone)] -pub struct HirBlockExpression(pub Vec); +pub struct HirBlockExpression { + pub statements: Vec, +} impl HirBlockExpression { pub fn statements(&self) -> &[StmtId] { - &self.0 + &self.statements } } diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 3c5627f739b..65592407d7d 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -1662,14 +1662,19 @@ fn convert_array_expression_to_slice( let as_slice = HirExpression::Ident(HirIdent::non_trait_method(as_slice_id, location)); let func = interner.push_expr(as_slice); - let arguments = vec![expression]; + // Copy the expression and give it a new ExprId. The old one + // will be mutated in place into a Call expression. + let argument = interner.expression(&expression); + let argument = interner.push_expr(argument); + interner.push_expr_type(argument, array_type.clone()); + interner.push_expr_location(argument, location.span, location.file); + + let arguments = vec![argument]; let call = HirExpression::Call(HirCallExpression { func, arguments, location }); - let call = interner.push_expr(call); + interner.replace_expr(&expression, call); - interner.push_expr_location(call, location.span, location.file); interner.push_expr_location(func, location.span, location.file); - - interner.push_expr_type(call, target_type.clone()); + interner.push_expr_type(expression, target_type.clone()); let func_type = Type::Function(vec![array_type], Box::new(target_type), Box::new(Type::Unit)); interner.push_expr_type(func, func_type); diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 9b0f57a7d39..618eba8f190 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -430,7 +430,7 @@ impl<'interner> Monomorphizer<'interner> { } }, HirExpression::Literal(HirLiteral::Unit) => ast::Expression::Block(vec![]), - HirExpression::Block(block) => self.block(block.0)?, + HirExpression::Block(block) => self.block(block.statements)?, HirExpression::Prefix(prefix) => { let location = self.interner.expr_location(&expr); diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index dec1c7aa9ce..a40355be8aa 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -347,7 +347,7 @@ fn block<'a>( [(LeftParen, RightParen), (LeftBracket, RightBracket)], |span| vec![Statement { kind: StatementKind::Error, span }], )) - .map(BlockExpression) + .map(|statements| BlockExpression { statements }) } fn check_statements_require_semicolon( @@ -1015,10 +1015,12 @@ where // Wrap the inner `if` expression in a block expression. // i.e. rewrite the sugared form `if cond1 {} else if cond2 {}` as `if cond1 {} else { if cond2 {} }`. let if_expression = Expression::new(kind, span); - let desugared_else = BlockExpression(vec![Statement { - kind: StatementKind::Expression(if_expression), - span, - }]); + let desugared_else = BlockExpression { + statements: vec![Statement { + kind: StatementKind::Expression(if_expression), + span, + }], + }; Expression::new(ExpressionKind::Block(desugared_else), span) })); @@ -1399,13 +1401,13 @@ mod test { // Regression for #1310: this should be parsed as a block and not a function call let res = parse_with(block(fresh_statement()), "{ if true { 1 } else { 2 } (3, 4) }").unwrap(); - match unwrap_expr(&res.0.last().unwrap().kind) { + match unwrap_expr(&res.statements.last().unwrap().kind) { // The `if` followed by a tuple is currently creates a block around both in case // there was none to start with, so there is an extra block here. ExpressionKind::Block(block) => { - assert_eq!(block.0.len(), 2); - assert!(matches!(unwrap_expr(&block.0[0].kind), ExpressionKind::If(_))); - assert!(matches!(unwrap_expr(&block.0[1].kind), ExpressionKind::Tuple(_))); + assert_eq!(block.statements.len(), 2); + assert!(matches!(unwrap_expr(&block.statements[0].kind), ExpressionKind::If(_))); + assert!(matches!(unwrap_expr(&block.statements[1].kind), ExpressionKind::Tuple(_))); } _ => unreachable!(), } diff --git a/compiler/noirc_printable_type/src/lib.rs b/compiler/noirc_printable_type/src/lib.rs index d3d20654adc..b9240203a5e 100644 --- a/compiler/noirc_printable_type/src/lib.rs +++ b/compiler/noirc_printable_type/src/lib.rs @@ -88,7 +88,7 @@ impl TryFrom<&[ForeignCallParam]> for PrintableValueDisplay { let (is_fmt_str, foreign_call_inputs) = foreign_call_inputs.split_last().ok_or(ForeignCallError::MissingForeignCallInputs)?; - if is_fmt_str.unwrap_value().to_field().is_one() { + if is_fmt_str.unwrap_field().is_one() { convert_fmt_string_inputs(foreign_call_inputs) } else { convert_string_inputs(foreign_call_inputs) @@ -106,8 +106,7 @@ fn convert_string_inputs( let printable_type = fetch_printable_type(printable_type_as_values)?; // We must use a flat map here as each value in a struct will be in a separate input value - let mut input_values_as_fields = - input_values.iter().flat_map(|param| vecmap(param.values(), |value| value.to_field())); + let mut input_values_as_fields = input_values.iter().flat_map(|param| param.fields()); let value = decode_value(&mut input_values_as_fields, &printable_type); @@ -120,7 +119,7 @@ fn convert_fmt_string_inputs( let (message, input_and_printable_types) = foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?; - let message_as_fields = vecmap(message.values(), |value| value.to_field()); + let message_as_fields = message.fields(); let message_as_string = decode_string_value(&message_as_fields); let (num_values, input_and_printable_types) = input_and_printable_types @@ -128,12 +127,11 @@ fn convert_fmt_string_inputs( .ok_or(ForeignCallError::MissingForeignCallInputs)?; let mut output = Vec::new(); - let num_values = num_values.unwrap_value().to_field().to_u128() as usize; + let num_values = num_values.unwrap_field().to_u128() as usize; let types_start_at = input_and_printable_types.len() - num_values; - let mut input_iter = input_and_printable_types[0..types_start_at] - .iter() - .flat_map(|param| vecmap(param.values(), |value| value.to_field())); + let mut input_iter = + input_and_printable_types[0..types_start_at].iter().flat_map(|param| param.fields()); for printable_type in input_and_printable_types.iter().skip(types_start_at) { let printable_type = fetch_printable_type(printable_type)?; let value = decode_value(&mut input_iter, &printable_type); @@ -147,7 +145,7 @@ fn convert_fmt_string_inputs( fn fetch_printable_type( printable_type: &ForeignCallParam, ) -> Result { - let printable_type_as_fields = vecmap(printable_type.values(), |value| value.to_field()); + let printable_type_as_fields = printable_type.fields(); let printable_type_as_string = decode_string_value(&printable_type_as_fields); let printable_type: PrintableType = serde_json::from_str(&printable_type_as_string)?; diff --git a/compiler/wasm/package.json b/compiler/wasm/package.json index 8db3876a753..6d11a5ba5c8 100644 --- a/compiler/wasm/package.json +++ b/compiler/wasm/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "license": "(MIT OR Apache-2.0)", "main": "dist/main.js", "types": "./dist/types/src/index.d.cts", diff --git a/docs/docs/how_to/how-to-oracles.md b/docs/docs/how_to/how-to-oracles.md index 0d84d992320..ab225b9421f 100644 --- a/docs/docs/how_to/how-to-oracles.md +++ b/docs/docs/how_to/how-to-oracles.md @@ -198,7 +198,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo ```js const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc -await noir.generateFinalProof(inputs, foreignCallHandler) +await noir.generateProof(inputs, foreignCallHandler) ``` As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. diff --git a/docs/docs/noir/concepts/data_types/integers.md b/docs/docs/noir/concepts/data_types/integers.md index 4d58d96fed5..1c6b375db49 100644 --- a/docs/docs/noir/concepts/data_types/integers.md +++ b/docs/docs/noir/concepts/data_types/integers.md @@ -51,7 +51,7 @@ The built-in structure `U128` allows you to use 128-bit unsigned integers almost - You cannot cast between a native integer and `U128` - There is a higher performance cost when using `U128`, compared to a native type. -Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. `from_integer` also accepts the `Field` type as input. ```rust fn main() { diff --git a/docs/docs/tutorials/noirjs_app.md b/docs/docs/tutorials/noirjs_app.md index ad76dd255cc..12beb476994 100644 --- a/docs/docs/tutorials/noirjs_app.md +++ b/docs/docs/tutorials/noirjs_app.md @@ -243,7 +243,7 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul await setup(); // let's squeeze our wasm inits here display('logs', 'Generating proof... ⌛'); -const proof = await noir.generateFinalProof(input); +const proof = await noir.generateProof(input); display('logs', 'Generating proof... ✅'); display('results', proof.proof); ``` @@ -264,7 +264,7 @@ Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add th ```js display('logs', 'Verifying proof... ⌛'); -const verification = await noir.verifyFinalProof(proof); +const verification = await noir.verifyProof(proof); if (verification) display('logs', 'Verifying proof... ✅'); ``` diff --git a/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md b/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md index 0d84d992320..ab225b9421f 100644 --- a/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md +++ b/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md @@ -198,7 +198,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo ```js const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc -await noir.generateFinalProof(inputs, foreignCallHandler) +await noir.generateProof(inputs, foreignCallHandler) ``` As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. diff --git a/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md index ad76dd255cc..12beb476994 100644 --- a/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md @@ -243,7 +243,7 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul await setup(); // let's squeeze our wasm inits here display('logs', 'Generating proof... ⌛'); -const proof = await noir.generateFinalProof(input); +const proof = await noir.generateProof(input); display('logs', 'Generating proof... ✅'); display('results', proof.proof); ``` @@ -264,7 +264,7 @@ Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add th ```js display('logs', 'Verifying proof... ⌛'); -const verification = await noir.verifyFinalProof(proof); +const verification = await noir.verifyProof(proof); if (verification) display('logs', 'Verifying proof... ✅'); ``` diff --git a/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md b/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md index 0d84d992320..ab225b9421f 100644 --- a/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md +++ b/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md @@ -198,7 +198,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo ```js const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc -await noir.generateFinalProof(inputs, foreignCallHandler) +await noir.generateProof(inputs, foreignCallHandler) ``` As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. diff --git a/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md index ad76dd255cc..12beb476994 100644 --- a/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md @@ -243,7 +243,7 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul await setup(); // let's squeeze our wasm inits here display('logs', 'Generating proof... ⌛'); -const proof = await noir.generateFinalProof(input); +const proof = await noir.generateProof(input); display('logs', 'Generating proof... ✅'); display('results', proof.proof); ``` @@ -264,7 +264,7 @@ Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add th ```js display('logs', 'Verifying proof... ⌛'); -const verification = await noir.verifyFinalProof(proof); +const verification = await noir.verifyProof(proof); if (verification) display('logs', 'Verifying proof... ✅'); ``` diff --git a/flake.nix b/flake.nix index 785d5aead56..1cb421a49ef 100644 --- a/flake.nix +++ b/flake.nix @@ -73,7 +73,7 @@ # Configuration shared between builds config = { # x-release-please-start-version - version = "0.25.0"; + version = "0.26.0"; # x-release-please-end src = pkgs.lib.cleanSourceWith { diff --git a/noir_stdlib/src/collections/bounded_vec.nr b/noir_stdlib/src/collections/bounded_vec.nr index 752b96d6591..6d5fbd44247 100644 --- a/noir_stdlib/src/collections/bounded_vec.nr +++ b/noir_stdlib/src/collections/bounded_vec.nr @@ -48,6 +48,15 @@ impl BoundedVec { self.len = new_len; } + pub fn extend_from_slice(&mut self, slice: [T]) { + let new_len = self.len + slice.len(); + assert(new_len as u64 <= MaxLen as u64, "extend_from_slice out of bounds"); + for i in 0..slice.len() { + self.storage[self.len + i] = slice[i]; + } + self.len = new_len; + } + pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) { let append_len = vec.len(); let new_len = self.len + append_len; diff --git a/noir_stdlib/src/field.nr b/noir_stdlib/src/field.nr index 0f4c2caffdf..b876bcc967b 100644 --- a/noir_stdlib/src/field.nr +++ b/noir_stdlib/src/field.nr @@ -97,7 +97,7 @@ pub fn modulus_be_bytes() -> [u8] {} #[builtin(modulus_le_bytes)] pub fn modulus_le_bytes() -> [u8] {} -// Convert a 32 byte array to a field element +// Convert a 32 byte array to a field element by modding pub fn bytes32_to_field(bytes32: [u8; 32]) -> Field { // Convert it to a field element let mut v = 1; diff --git a/release-please-config.json b/release-please-config.json index e73993ca974..217a86303a1 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -61,8 +61,8 @@ "acir_field/Cargo.toml", "acvm/Cargo.toml", "acvm_js/Cargo.toml", - "barretenberg_blackbox_solver/Cargo.toml", "blackbox_solver/Cargo.toml", + "bn254_blackbox_solver/Cargo.toml", "brillig/Cargo.toml", "brillig_vm/Cargo.toml", { diff --git a/test_programs/execution_success/array_to_slice/src/main.nr b/test_programs/execution_success/array_to_slice/src/main.nr index b97f68fc280..0d0f9562d7b 100644 --- a/test_programs/execution_success/array_to_slice/src/main.nr +++ b/test_programs/execution_success/array_to_slice/src/main.nr @@ -7,6 +7,7 @@ fn as_slice_push(xs: [T; N]) -> [T] { slice } +// Expected that x == 0 and y == 1 fn main(x: Field, y: pub Field) { let xs: [Field; 0] = []; let ys: [Field; 1] = [1]; @@ -30,4 +31,26 @@ fn main(x: Field, y: pub Field) { assert(dynamic.as_slice()[2] == dynamic_expected[2]); assert(dynamic.as_slice()[3] == dynamic_expected[3]); assert(dynamic.as_slice().len() == 4); + + regression_4609_append_slices(x, y); + regression_4609_append_dynamic_slices(x, y); +} + +fn regression_4609_append_slices(x: Field, y: Field) { + let sl = [x, 1, 2, 3].as_slice(); + let sl2 = [y, 5, 6].as_slice(); + let sl3 = sl.append(sl2); + assert(sl3[0] == x); + assert(sl3[4] == y); +} + +fn regression_4609_append_dynamic_slices(x: Field, y: Field) { + let mut sl = [x, 1, 2, 3].as_slice(); + sl[x] = x + 10; + let mut sl2 = [y, 5, 6].as_slice(); + sl2[y] = y + 5; + let sl3 = sl.append(sl2); + assert(sl3[0] == 10); + assert(sl3[4] == y); + assert(sl3[5] == 6); } diff --git a/test_programs/execution_success/regression_capacity_tracker/Nargo.toml b/test_programs/execution_success/regression_capacity_tracker/Nargo.toml new file mode 100644 index 00000000000..d5a3839626f --- /dev/null +++ b/test_programs/execution_success/regression_capacity_tracker/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_capacity_tracker" +type = "bin" +authors = [""] +compiler_version = ">=0.26.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/regression_capacity_tracker/Prover.toml b/test_programs/execution_success/regression_capacity_tracker/Prover.toml new file mode 100644 index 00000000000..bbf35b23a0f --- /dev/null +++ b/test_programs/execution_success/regression_capacity_tracker/Prover.toml @@ -0,0 +1,3 @@ +expected = "10" +first = "10" +input = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] \ No newline at end of file diff --git a/test_programs/execution_success/regression_capacity_tracker/src/main.nr b/test_programs/execution_success/regression_capacity_tracker/src/main.nr new file mode 100644 index 00000000000..be645c811d2 --- /dev/null +++ b/test_programs/execution_success/regression_capacity_tracker/src/main.nr @@ -0,0 +1,19 @@ +// Reference https://github.com/noir-lang/noir/issues/4395#issuecomment-2018948631 +// for context. +// We were not accurately accounting for situations where the slice capacity tracker +// was expecting a capacity from slice intrinsic results. +fn main(expected: pub Field, first: Field, input: [Field; 20]) { + let mut hasher_slice = input.as_slice(); + hasher_slice = hasher_slice.push_front(first); + assert(hasher_slice[0] == expected); + // We need a conditional based upon witnesses + // to force a store of the slice. + // If this successfully compiles it means we have stored + // the results of the slice intrinsics used above. + if expected as u32 > 10 { + hasher_slice[expected - 10] = 100; + } else { + hasher_slice[expected] = 100; + } + assert(hasher_slice[0] == expected); +} diff --git a/test_programs/execution_success/slice_coercion/Nargo.toml b/test_programs/execution_success/slice_coercion/Nargo.toml new file mode 100644 index 00000000000..659677cc560 --- /dev/null +++ b/test_programs/execution_success/slice_coercion/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "slice_coercion" +type = "bin" +authors = [""] +compiler_version = ">=0.25.0" + +[dependencies] diff --git a/test_programs/execution_success/slice_coercion/Prover.toml b/test_programs/execution_success/slice_coercion/Prover.toml new file mode 100644 index 00000000000..09c44a855b0 --- /dev/null +++ b/test_programs/execution_success/slice_coercion/Prover.toml @@ -0,0 +1,2 @@ +first = 3 +expected = 3 diff --git a/test_programs/execution_success/slice_coercion/src/main.nr b/test_programs/execution_success/slice_coercion/src/main.nr new file mode 100644 index 00000000000..a3785e79afa --- /dev/null +++ b/test_programs/execution_success/slice_coercion/src/main.nr @@ -0,0 +1,19 @@ +struct Hasher { + fields: [Field], +} + +impl Hasher { + pub fn new() -> Self { + Self { fields: [] } + } + + pub fn add(&mut self, field: Field) { + self.fields = self.fields.push_back(field); + } +} + +fn main(expected: pub Field, first: Field) { + let mut hasher = Hasher::new(); + hasher.add(first); + assert(hasher.fields[0] == expected); +} diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index a3ee89263a4..f0de8d5d1c8 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -2,7 +2,7 @@ use crate::foreign_calls::DebugForeignCallExecutor; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; use acvm::brillig_vm::brillig::ForeignCallResult; -use acvm::brillig_vm::brillig::Value; +use acvm::brillig_vm::MemoryValue; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, }; @@ -506,13 +506,13 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { acir_index < opcodes.len() && matches!(opcodes[acir_index], Opcode::Brillig(..)) } - pub(super) fn get_brillig_memory(&self) -> Option<&[Value]> { + pub(super) fn get_brillig_memory(&self) -> Option<&[MemoryValue]> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) } - pub(super) fn write_brillig_memory(&mut self, ptr: usize, value: FieldElement) { + pub(super) fn write_brillig_memory(&mut self, ptr: usize, value: FieldElement, bit_size: u32) { if let Some(solver) = self.brillig_solver.as_mut() { - solver.write_memory_at(ptr, value.into()); + solver.write_memory_at(ptr, MemoryValue::new(value, bit_size)); } } @@ -667,7 +667,7 @@ mod tests { }, BrilligOpcode::Const { destination: MemoryAddress::from(1), - value: Value::from(fe_0), + value: fe_0, bit_size: 32, }, BrilligOpcode::ForeignCall { @@ -675,7 +675,7 @@ mod tests { destinations: vec![], destination_value_types: vec![], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, ], diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 25f126ff490..aae2212fd54 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -1,6 +1,7 @@ use acvm::{ - acir::brillig::{ForeignCallParam, ForeignCallResult, Value}, + acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, + FieldElement, }; use nargo::{ artifacts::debug::{DebugArtifact, DebugVars, StackFrame}, @@ -81,11 +82,11 @@ impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor { } } -fn debug_var_id(value: &Value) -> DebugVarId { +fn debug_var_id(value: &FieldElement) -> DebugVarId { DebugVarId(value.to_u128() as u32) } -fn debug_fn_id(value: &Value) -> DebugFnId { +fn debug_fn_id(value: &FieldElement) -> DebugFnId { DebugFnId(value.to_u128() as u32) } @@ -100,8 +101,8 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { let fcp_var_id = &foreign_call.inputs[0]; if let ForeignCallParam::Single(var_id_value) = fcp_var_id { let var_id = debug_var_id(var_id_value); - let values: Vec = - foreign_call.inputs[1..].iter().flat_map(|x| x.values()).collect(); + let values: Vec = + foreign_call.inputs[1..].iter().flat_map(|x| x.fields()).collect(); self.debug_vars.assign_var(var_id, &values); } Ok(ForeignCallResult::default().into()) @@ -129,12 +130,12 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { } }) .collect(); - let values: Vec = (0..n - 1 - arity) + let values: Vec = (0..n - 1 - arity) .flat_map(|i| { foreign_call .inputs .get(1 + i) - .map(|fci| fci.values()) + .map(|fci| fci.fields()) .unwrap_or_default() }) .collect(); @@ -147,7 +148,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { let fcp_value = &foreign_call.inputs[1]; if let ForeignCallParam::Single(var_id_value) = fcp_var_id { let var_id = debug_var_id(var_id_value); - self.debug_vars.assign_deref(var_id, &fcp_value.values()); + self.debug_vars.assign_deref(var_id, &fcp_value.fields()); } Ok(ForeignCallResult::default().into()) } diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 41dbf604f99..1c077c6ee9b 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -319,12 +319,12 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { return; }; - for (index, value) in memory.iter().enumerate() { - println!("{index} = {}", value.to_field()); + for (index, value) in memory.iter().enumerate().filter(|(_, value)| value.bit_size > 0) { + println!("{index} = {}", value); } } - pub fn write_brillig_memory(&mut self, index: usize, value: String) { + pub fn write_brillig_memory(&mut self, index: usize, value: String, bit_size: u32) { let Some(field_value) = FieldElement::try_from_str(&value) else { println!("Invalid value: {value}"); return; @@ -333,7 +333,7 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { println!("Not executing a Brillig block"); return; } - self.context.write_brillig_memory(index, field_value); + self.context.write_brillig_memory(index, field_value, bit_size); } pub fn show_vars(&self) { @@ -513,8 +513,8 @@ pub fn run( "memset", command! { "update a Brillig memory cell with the given value", - (index: usize, value: String) => |index, value| { - ref_context.borrow_mut().write_brillig_memory(index, value); + (index: usize, value: String, bit_size: u32) => |index, value, bit_size| { + ref_context.borrow_mut().write_brillig_memory(index, value, bit_size); Ok(CommandStatus::Done) } }, diff --git a/tooling/nargo/src/artifacts/debug_vars.rs b/tooling/nargo/src/artifacts/debug_vars.rs index 0e9e177e023..8e5c2bc46a4 100644 --- a/tooling/nargo/src/artifacts/debug_vars.rs +++ b/tooling/nargo/src/artifacts/debug_vars.rs @@ -1,4 +1,4 @@ -use acvm::brillig_vm::brillig::Value; +use acvm::FieldElement; use noirc_errors::debug_info::{ DebugFnId, DebugFunction, DebugInfo, DebugTypeId, DebugVarId, DebugVariable, }; @@ -66,7 +66,7 @@ impl DebugVars { } } - pub fn assign_var(&mut self, var_id: DebugVarId, values: &[Value]) { + pub fn assign_var(&mut self, var_id: DebugVarId, values: &[FieldElement]) { let type_id = &self.variables.get(&var_id).unwrap().debug_type_id; let ptype = self.types.get(type_id).unwrap(); @@ -74,10 +74,10 @@ impl DebugVars { .last_mut() .expect("unexpected empty stack frames") .1 - .insert(var_id, decode_value(&mut values.iter().map(|v| v.to_field()), ptype)); + .insert(var_id, decode_value(&mut values.iter().copied(), ptype)); } - pub fn assign_field(&mut self, var_id: DebugVarId, indexes: Vec, values: &[Value]) { + pub fn assign_field(&mut self, var_id: DebugVarId, indexes: Vec, values: &[FieldElement]) { let current_frame = &mut self.frames.last_mut().expect("unexpected empty stack frames").1; let mut cursor: &mut PrintableValue = current_frame .get_mut(&var_id) @@ -147,10 +147,10 @@ impl DebugVars { } }; } - *cursor = decode_value(&mut values.iter().map(|v| v.to_field()), cursor_type); + *cursor = decode_value(&mut values.iter().copied(), cursor_type); } - pub fn assign_deref(&mut self, _var_id: DebugVarId, _values: &[Value]) { + pub fn assign_deref(&mut self, _var_id: DebugVarId, _values: &[FieldElement]) { unimplemented![] } diff --git a/tooling/nargo/src/ops/foreign_calls.rs b/tooling/nargo/src/ops/foreign_calls.rs index f7f36c65c90..ea67f17af2a 100644 --- a/tooling/nargo/src/ops/foreign_calls.rs +++ b/tooling/nargo/src/ops/foreign_calls.rs @@ -1,6 +1,7 @@ use acvm::{ - acir::brillig::{ForeignCallParam, ForeignCallResult, Value}, + acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, + FieldElement, }; use jsonrpc::{arg as build_json_rpc_arg, minreq_http::Builder, Client}; use noirc_printable_type::{decode_string_value, ForeignCallError, PrintableValueDisplay}; @@ -46,15 +47,15 @@ impl From for NargoForeignCallResult { } } -impl From for NargoForeignCallResult { - fn from(value: Value) -> Self { +impl From for NargoForeignCallResult { + fn from(value: FieldElement) -> Self { let foreign_call_result: ForeignCallResult = value.into(); foreign_call_result.into() } } -impl From> for NargoForeignCallResult { - fn from(values: Vec) -> Self { +impl From> for NargoForeignCallResult { + fn from(values: Vec) -> Self { let foreign_call_result: ForeignCallResult = values.into(); foreign_call_result.into() } @@ -178,7 +179,10 @@ impl DefaultForeignCallExecutor { ) -> Result<(usize, &[ForeignCallParam]), ForeignCallError> { let (id, params) = foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?; - Ok((id.unwrap_value().to_usize(), params)) + let id = + usize::try_from(id.unwrap_field().try_to_u64().expect("value does not fit into u64")) + .expect("value does not fit into usize"); + Ok((id, params)) } fn find_mock_by_id(&mut self, id: usize) -> Option<&mut MockedCall> { @@ -186,12 +190,12 @@ impl DefaultForeignCallExecutor { } fn parse_string(param: &ForeignCallParam) -> String { - let fields: Vec<_> = param.values().into_iter().map(|value| value.to_field()).collect(); + let fields: Vec<_> = param.fields().to_vec(); decode_string_value(&fields) } fn execute_print(foreign_call_inputs: &[ForeignCallParam]) -> Result<(), ForeignCallError> { - let skip_newline = foreign_call_inputs[0].unwrap_value().is_zero(); + let skip_newline = foreign_call_inputs[0].unwrap_field().is_zero(); let foreign_call_inputs = foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?.1; @@ -242,7 +246,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { self.mocked_responses.push(MockedCall::new(id, mock_oracle_name)); self.last_mock_id += 1; - Ok(Value::from(id).into()) + Ok(FieldElement::from(id).into()) } Some(ForeignCall::SetMockParams) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -262,11 +266,8 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { } Some(ForeignCall::SetMockTimes) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; - let times = params[0] - .unwrap_value() - .to_field() - .try_to_u64() - .expect("Invalid bit size of times"); + let times = + params[0].unwrap_field().try_to_u64().expect("Invalid bit size of times"); self.find_mock_by_id(id) .unwrap_or_else(|| panic!("Unknown mock id {}", id)) @@ -325,10 +326,8 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { #[cfg(test)] mod tests { use acvm::{ - acir::brillig::ForeignCallParam, - brillig_vm::brillig::{ForeignCallResult, Value}, - pwg::ForeignCallWaitInfo, - FieldElement, + acir::brillig::ForeignCallParam, brillig_vm::brillig::ForeignCallResult, + pwg::ForeignCallWaitInfo, FieldElement, }; use jsonrpc_core::Result as RpcResult; use jsonrpc_derive::rpc; @@ -356,11 +355,11 @@ mod tests { fn sum(&self, array: ForeignCallParam) -> RpcResult { let mut res: FieldElement = 0_usize.into(); - for value in array.values() { - res += value.to_field(); + for value in array.fields() { + res += value; } - Ok(Value::from(res).into()) + Ok(res.into()) } } @@ -406,7 +405,7 @@ mod tests { }; let result = executor.execute(&foreign_call); - assert_eq!(result.unwrap(), Value::from(3_usize).into()); + assert_eq!(result.unwrap(), FieldElement::from(3_usize).into()); server.close(); } diff --git a/tooling/nargo_fmt/src/visitor/expr.rs b/tooling/nargo_fmt/src/visitor/expr.rs index 2cd0e881e84..f9836adda18 100644 --- a/tooling/nargo_fmt/src/visitor/expr.rs +++ b/tooling/nargo_fmt/src/visitor/expr.rs @@ -119,11 +119,11 @@ impl FmtVisitor<'_> { self.last_position = block_span.start() + 1; // `{` self.push_str("{"); - self.trim_spaces_after_opening_brace(&block.0); + self.trim_spaces_after_opening_brace(&block.statements); self.indent.block_indent(self.config); - self.visit_stmts(block.0); + self.visit_stmts(block.statements); let span = (self.last_position..block_span.end() - 1).into(); self.close_block(span); diff --git a/tooling/noir_codegen/package.json b/tooling/noir_codegen/package.json index 485f4252e29..1eabc6a1398 100644 --- a/tooling/noir_codegen/package.json +++ b/tooling/noir_codegen/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js/package.json b/tooling/noir_js/package.json index 0da6e695202..c8d4873e095 100644 --- a/tooling/noir_js/package.json +++ b/tooling/noir_js/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index 92b8460d1db..1ea384cdd49 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.30.1", + "@aztec/bb.js": "portal:../../../../barretenberg/ts", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/noir_js_types/package.json b/tooling/noir_js_types/package.json index d7a08debb54..eadb6f49665 100644 --- a/tooling/noir_js_types/package.json +++ b/tooling/noir_js_types/package.json @@ -4,7 +4,7 @@ "The Noir Team " ], "packageManager": "yarn@3.5.1", - "version": "0.25.0", + "version": "0.26.0", "license": "(MIT OR Apache-2.0)", "homepage": "https://noir-lang.org/", "repository": { diff --git a/tooling/noirc_abi_wasm/package.json b/tooling/noirc_abi_wasm/package.json index a6cc5503242..e93a8e6a5e3 100644 --- a/tooling/noirc_abi_wasm/package.json +++ b/tooling/noirc_abi_wasm/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "license": "(MIT OR Apache-2.0)", "homepage": "https://noir-lang.org/", "repository": { diff --git a/yarn.lock b/yarn.lock index 3932935167d..b45678f5d8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,19 +221,18 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.30.1": - version: 0.30.1 - resolution: "@aztec/bb.js@npm:0.30.1" +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": + version: 0.0.0-use.local + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: dest/node/main.js - checksum: 52d0acaaf0966aa969b863adeb688df5c1abe7c8a0595bc2dca8603a8649f11eb39071aacbdc05b19f320f022b98691a41cb18a601ad84e6d82955ae6f885106 + bb.js: ./dest/node/main.js languageName: node - linkType: hard + linkType: soft "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4396,7 +4395,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.30.1 + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 From a26453a714c9e126607a41f5e6abec2f0bb35094 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 27 Mar 2024 13:34:25 +0000 Subject: [PATCH 2/3] chore: bump `bb` --- tooling/bb_abstraction_leaks/build.rs | 2 +- tooling/noir_js_backend_barretenberg/package.json | 2 +- yarn.lock | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tooling/bb_abstraction_leaks/build.rs b/tooling/bb_abstraction_leaks/build.rs index 362d2132952..3fbf8ac8ffa 100644 --- a/tooling/bb_abstraction_leaks/build.rs +++ b/tooling/bb_abstraction_leaks/build.rs @@ -10,7 +10,7 @@ use const_format::formatcp; const USERNAME: &str = "AztecProtocol"; const REPO: &str = "aztec-packages"; -const VERSION: &str = "0.30.1"; +const VERSION: &str = "0.31.0"; const TAG: &str = formatcp!("aztec-packages-v{}", VERSION); const API_URL: &str = diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index 1ea384cdd49..b5e23a79a4e 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "portal:../../../../barretenberg/ts", + "@aztec/bb.js": "0.31.0", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/yarn.lock b/yarn.lock index b45678f5d8b..7e25fcd7d4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,18 +221,19 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": - version: 0.0.0-use.local - resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" +"@aztec/bb.js@npm:0.31.0": + version: 0.31.0 + resolution: "@aztec/bb.js@npm:0.31.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: ./dest/node/main.js + bb.js: dest/node/main.js + checksum: 3bcd8cef1fb0b5767332b757875719b4b4f2c34d5b4ed22984f305b920afbb74e17ccf626b3efe66cae904c3df8f74de1aa8c798b17195be13db60a65730bd98 languageName: node - linkType: soft + linkType: hard "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4395,7 +4396,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": "portal:../../../../barretenberg/ts" + "@aztec/bb.js": 0.31.0 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 From 0522909b6f3a3f4372744581cd55c069f06e0373 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 27 Mar 2024 15:06:50 +0000 Subject: [PATCH 3/3] refactor(avm): unify noir macros flow (https://github.com/AztecProtocol/aztec-packages/pull/5461) Step towards integrating with initializers, etc. However in the future we might want to separate private and public-vm, many things might end up being different enough (see IFs in code). --- .aztec-sync-commit | 2 +- .github/ACVM_PUBLISH_FAILED.md | 10 + .github/pull_request_template.md | 2 +- .github/workflows/publish-acvm.yml | 2 +- .github/workflows/release.yml | 30 + .release-please-manifest.json | 4 +- CHANGELOG.md | 62 + Cargo.lock | 53 +- Cargo.toml | 16 +- acvm-repo/CHANGELOG.md | 81 ++ acvm-repo/acir/Cargo.toml | 2 +- acvm-repo/acir/codegen/acir.cpp | 1245 ++++++++--------- .../acir/tests/test_program_serialization.rs | 46 +- acvm-repo/acir_field/Cargo.toml | 2 +- acvm-repo/acvm/Cargo.toml | 2 +- .../acvm/src/compiler/transformers/mod.rs | 5 +- .../acvm/src/compiler/transformers/r1cs.rs | 16 - acvm-repo/acvm/src/pwg/brillig.rs | 20 +- acvm-repo/acvm/tests/solver.rs | 41 +- acvm-repo/acvm_js/Cargo.toml | 2 +- acvm-repo/acvm_js/package.json | 2 +- acvm-repo/acvm_js/src/foreign_call/inputs.rs | 4 +- acvm-repo/acvm_js/src/foreign_call/outputs.rs | 8 +- .../test/shared/complex_foreign_call.ts | 14 +- acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/blackbox_solver/Cargo.toml | 2 +- acvm-repo/bn254_blackbox_solver/Cargo.toml | 2 +- acvm-repo/brillig/Cargo.toml | 2 +- acvm-repo/brillig/src/foreign_call.rs | 26 +- acvm-repo/brillig/src/lib.rs | 3 - acvm-repo/brillig/src/opcodes.rs | 15 +- acvm-repo/brillig/src/value.rs | 103 -- acvm-repo/brillig_vm/Cargo.toml | 3 +- acvm-repo/brillig_vm/src/arithmetic.rs | 136 +- acvm-repo/brillig_vm/src/black_box.rs | 67 +- acvm-repo/brillig_vm/src/lib.rs | 754 +++++----- acvm-repo/brillig_vm/src/memory.rs | 176 ++- aztec_macros/src/lib.rs | 15 +- aztec_macros/src/transforms/events.rs | 12 +- aztec_macros/src/transforms/functions.rs | 233 ++- aztec_macros/src/transforms/storage.rs | 2 +- .../brillig/brillig_gen/brillig_black_box.rs | 12 +- .../src/brillig/brillig_gen/brillig_block.rs | 10 +- .../brillig_gen/brillig_block_variables.rs | 7 +- .../brillig/brillig_gen/brillig_directive.rs | 37 +- .../src/brillig/brillig_gen/brillig_fn.rs | 16 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 238 ++-- .../noirc_evaluator/src/brillig/brillig_ir.rs | 17 +- .../brillig/brillig_ir/brillig_variable.rs | 15 +- .../src/brillig/brillig_ir/codegen_binary.rs | 4 +- .../brillig/brillig_ir/codegen_intrinsic.rs | 14 +- .../src/brillig/brillig_ir/debug_show.rs | 11 +- .../src/brillig/brillig_ir/entry_point.rs | 34 +- .../src/brillig/brillig_ir/instructions.rs | 42 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 16 +- .../src/ssa/ir/instruction/call.rs | 9 +- compiler/noirc_evaluator/src/ssa/ir/types.rs | 7 + .../ssa/opt/flatten_cfg/capacity_tracker.rs | 14 +- compiler/noirc_frontend/src/ast/expression.rs | 32 +- compiler/noirc_frontend/src/ast/function.rs | 2 +- compiler/noirc_frontend/src/ast/statement.rs | 14 +- compiler/noirc_frontend/src/debug/mod.rs | 38 +- .../src/hir/resolution/resolver.rs | 6 +- .../src/hir/type_check/errors.rs | 5 +- .../noirc_frontend/src/hir/type_check/mod.rs | 3 +- .../noirc_frontend/src/hir/type_check/stmt.rs | 5 + compiler/noirc_frontend/src/hir_def/expr.rs | 8 +- compiler/noirc_frontend/src/hir_def/types.rs | 15 +- .../src/monomorphization/mod.rs | 2 +- compiler/noirc_frontend/src/parser/parser.rs | 20 +- compiler/noirc_printable_type/src/lib.rs | 16 +- compiler/wasm/package.json | 2 +- docs/docs/how_to/how-to-oracles.md | 2 +- .../docs/noir/concepts/data_types/integers.md | 2 +- docs/docs/tutorials/noirjs_app.md | 4 +- .../version-v0.24.0/how_to/how-to-oracles.md | 2 +- .../version-v0.24.0/tutorials/noirjs_app.md | 4 +- .../version-v0.25.0/how_to/how-to-oracles.md | 2 +- .../version-v0.25.0/tutorials/noirjs_app.md | 4 +- flake.nix | 2 +- noir_stdlib/src/collections/bounded_vec.nr | 9 + noir_stdlib/src/field.nr | 2 +- release-please-config.json | 2 +- .../array_to_slice/src/main.nr | 23 + .../regression_capacity_tracker/Nargo.toml | 7 + .../regression_capacity_tracker/Prover.toml | 3 + .../regression_capacity_tracker/src/main.nr | 19 + .../slice_coercion/Nargo.toml | 7 + .../slice_coercion/Prover.toml | 2 + .../slice_coercion/src/main.nr | 19 + tooling/debugger/src/context.rs | 12 +- tooling/debugger/src/foreign_calls.rs | 17 +- tooling/debugger/src/repl.rs | 12 +- tooling/nargo/src/artifacts/debug_vars.rs | 12 +- tooling/nargo/src/ops/foreign_calls.rs | 43 +- tooling/nargo_fmt/src/visitor/expr.rs | 4 +- tooling/noir_codegen/package.json | 2 +- tooling/noir_js/package.json | 2 +- .../noir_js_backend_barretenberg/package.json | 4 +- tooling/noir_js_types/package.json | 2 +- tooling/noirc_abi_wasm/package.json | 2 +- yarn.lock | 13 +- 102 files changed, 2356 insertions(+), 1785 deletions(-) create mode 100644 .github/ACVM_PUBLISH_FAILED.md delete mode 100644 acvm-repo/acvm/src/compiler/transformers/r1cs.rs delete mode 100644 acvm-repo/brillig/src/value.rs create mode 100644 test_programs/execution_success/regression_capacity_tracker/Nargo.toml create mode 100644 test_programs/execution_success/regression_capacity_tracker/Prover.toml create mode 100644 test_programs/execution_success/regression_capacity_tracker/src/main.nr create mode 100644 test_programs/execution_success/slice_coercion/Nargo.toml create mode 100644 test_programs/execution_success/slice_coercion/Prover.toml create mode 100644 test_programs/execution_success/slice_coercion/src/main.nr diff --git a/.aztec-sync-commit b/.aztec-sync-commit index ead8f3147c0..31f1e1918ec 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -208abbb63af4c9a3f25d723fe1c49e82aa461061 +54aee58952b2433ccad83f1b5fc3088957b10fbb diff --git a/.github/ACVM_PUBLISH_FAILED.md b/.github/ACVM_PUBLISH_FAILED.md new file mode 100644 index 00000000000..00e692a64d8 --- /dev/null +++ b/.github/ACVM_PUBLISH_FAILED.md @@ -0,0 +1,10 @@ +--- +title: "ACVM crates failed to publish" +assignees: TomAFrench, Savio-Sou +--- + +The {{env.CRATE_VERSION}} release of the ACVM crates failed. + +Check the [Publish ACVM crates]({{env.WORKFLOW_URL}}) workflow for details. + +This issue was raised by the workflow `{{env.WORKFLOW_NAME}}` diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e81ede7199d..dfb141e29f7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,7 +17,7 @@ Resolves Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. -- [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. +- [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* diff --git a/.github/workflows/publish-acvm.yml b/.github/workflows/publish-acvm.yml index 959cd8e4bca..d17d8f294fb 100644 --- a/.github/workflows/publish-acvm.yml +++ b/.github/workflows/publish-acvm.yml @@ -74,4 +74,4 @@ jobs: WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} with: update_existing: true - filename: .github/JS_PUBLISH_FAILED.md \ No newline at end of file + filename: .github/ACVM_PUBLISH_FAILED.md \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 83e8e479181..249d83afecc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -100,6 +100,36 @@ jobs: git commit -m "chore(docs): cut new docs version for tag ${{ steps.noir-version.outputs.semver }}" git push + release-end: + name: Release End + runs-on: ubuntu-latest + # We want this job to always run (even if the dependant jobs fail) as we need apply changes to the sticky comment. + if: ${{ always() }} + + needs: + - update-acvm-workspace-package-versions + - update-docs + + env: + # We treat any skipped or failing jobs as a failure for the workflow as a whole. + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') } + + steps: + - name: Add warning to sticky comment + uses: marocchino/sticky-pull-request-comment@v2 + with: + # delete the comment in case failures have been fixed + delete: ${{ !env.FAIL }} + message: "The release workflow has not completed successfully. Releasing now will result in a broken release" + + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + build-binaries: name: Build binaries needs: [release-please] diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b38234ca0b9..d4cc095c484 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,4 @@ { - ".": "0.25.0", - "acvm-repo": "0.41.0" + ".": "0.26.0", + "acvm-repo": "0.42.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cdbccf768ca..7c4bcad5840 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,67 @@ # Changelog +## [0.26.0](https://github.com/noir-lang/noir/compare/v0.25.0...v0.26.0) (2024-03-25) + + +### ⚠ BREAKING CHANGES + +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) +* automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) +* separating out array and slice types in the AST ([#4504](https://github.com/noir-lang/noir/issues/4504)) +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) +* Remove open keyword from Noir (https://github.com/AztecProtocol/aztec-packages/pull/4967) + +### Features + +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add `break` and `continue` in unconstrained code ([#4569](https://github.com/noir-lang/noir/issues/4569)) ([f2f827d](https://github.com/noir-lang/noir/commit/f2f827d51e6fe99fa3d17f125b22743da25e25be)) +* Add `nargo compile --watch` command ([#4464](https://github.com/noir-lang/noir/issues/4464)) ([44e60b6](https://github.com/noir-lang/noir/commit/44e60b67469de88f20842c4eead64d736f7bd4a0)) +* Add as_slice builtin function, add execution test ([#4523](https://github.com/noir-lang/noir/issues/4523)) ([6a9ea35](https://github.com/noir-lang/noir/commit/6a9ea35c4f1578058179aa08eedf44eb18bad4a1)) +* Add checks for bit size consistency on brillig gen ([#4542](https://github.com/noir-lang/noir/issues/4542)) ([f3243b7](https://github.com/noir-lang/noir/commit/f3243b763c0b15ae90beb8e35630df27f3d314c0)) +* Add CMOV instruction to brillig and brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5308) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add experimental `quote` expression to parser ([#4595](https://github.com/noir-lang/noir/issues/4595)) ([4c3a30b](https://github.com/noir-lang/noir/commit/4c3a30b4991a329d3c52e1dfa59d854d7e6910db)) +* Add more impls on Option ([#4549](https://github.com/noir-lang/noir/issues/4549)) ([4cf700b](https://github.com/noir-lang/noir/commit/4cf700bcfe157ebc82cdf7321a16959b7a4add57)) +* Add specific error for attempting `string[x] = ".."` ([#4611](https://github.com/noir-lang/noir/issues/4611)) ([ff95fd9](https://github.com/noir-lang/noir/commit/ff95fd93451b2053360a16b7d3204ca251199296)) +* Allow usage of noir `#[test]` syntax in stdlib ([#4553](https://github.com/noir-lang/noir/issues/4553)) ([a8b7cdb](https://github.com/noir-lang/noir/commit/a8b7cdb8a3698bc8923b6fa8714deebb8bf3923f)) +* Automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **avm:** Brillig CONST of size > u128 (https://github.com/AztecProtocol/aztec-packages/pull/5217) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Brillig IR refactor (https://github.com/AztecProtocol/aztec-packages/pull/5233) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Check initialization arguments in constructors (https://github.com/AztecProtocol/aztec-packages/pull/5144) ([d4213a0](https://github.com/noir-lang/noir/commit/d4213a03c9f77ee8e7663fc965a825258d90a368)) +* Check initializer msg.sender matches deployer from address preimage (https://github.com/AztecProtocol/aztec-packages/pull/5222) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Initial Earthly CI (https://github.com/AztecProtocol/aztec-packages/pull/5069) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Integrated native ACVM (https://github.com/AztecProtocol/aztec-packages/pull/4903) ([a6016b4](https://github.com/noir-lang/noir/commit/a6016b46abf6da6de4566cf6d35a675d805dd9b5)) +* Make brillig-gen more AVM-friendly (https://github.com/AztecProtocol/aztec-packages/pull/5091) ([a6016b4](https://github.com/noir-lang/noir/commit/a6016b46abf6da6de4566cf6d35a675d805dd9b5)) +* New brillig field operations and refactor of binary operations (https://github.com/AztecProtocol/aztec-packages/pull/5208) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Optimize sha2 implementation ([#4441](https://github.com/noir-lang/noir/issues/4441)) ([80373d6](https://github.com/noir-lang/noir/commit/80373d612c023e3e165b49b6d1729486b0ba3b4b)) +* RC optimization pass ([#4560](https://github.com/noir-lang/noir/issues/4560)) ([dfa5126](https://github.com/noir-lang/noir/commit/dfa5126f2c65843c34701cacddf2cbcfb0d7ff11)) +* Remove curly braces with fmt ([#4529](https://github.com/noir-lang/noir/issues/4529)) ([fe9a437](https://github.com/noir-lang/noir/commit/fe9a437b6d7ddc3f78665df1a576236555880c51)) +* Separating out array and slice types in the AST ([#4504](https://github.com/noir-lang/noir/issues/4504)) ([9a241f9](https://github.com/noir-lang/noir/commit/9a241f9622b342cd9d56bf8481219cfc374c0510)) +* Signed integer division and modulus in brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5279) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5234) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5286) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Visible aliases for nargo commands ([#4453](https://github.com/noir-lang/noir/issues/4453)) ([773cf19](https://github.com/noir-lang/noir/commit/773cf190ee21381d826ba80391a5d7d5efae9174)) + + +### Bug Fixes + +* **acir_gen:** More granular element sizes array check ([#4528](https://github.com/noir-lang/noir/issues/4528)) ([f93d16e](https://github.com/noir-lang/noir/commit/f93d16e3e89c5df358c982deae4f3c2d4c82b77f)) +* Added error messages for passing oracles and references from unconstrained to constrained functions ([#4570](https://github.com/noir-lang/noir/issues/4570)) ([265bd8b](https://github.com/noir-lang/noir/commit/265bd8b284e5acd572a3812a94a99fc102227ff2)) +* Allow non-integer globals to reference struct methods ([#4490](https://github.com/noir-lang/noir/issues/4490)) ([00d6494](https://github.com/noir-lang/noir/commit/00d6494ae70b10e1872d96fb4e57ecb0b5f01787)) +* Dynamic assert messages in brillig ([#4531](https://github.com/noir-lang/noir/issues/4531)) ([e24d3fc](https://github.com/noir-lang/noir/commit/e24d3fc5a084610d9511e3c5421275cb9c84a548)) +* Evaluate operators in globals in types ([#4537](https://github.com/noir-lang/noir/issues/4537)) ([c8aa16b](https://github.com/noir-lang/noir/commit/c8aa16bc7e78456cce1736fac82496996a8761f4)) +* Make `nargo` the default binary for cargo run ([#4554](https://github.com/noir-lang/noir/issues/4554)) ([de4986e](https://github.com/noir-lang/noir/commit/de4986eb74b28b2e1065fa6b413d02457ddf61b0)) +* Signed integer comparisons in brillig ([#4579](https://github.com/noir-lang/noir/issues/4579)) ([938d5e8](https://github.com/noir-lang/noir/commit/938d5e85eda00a05de5014e64d3dc9fc7c24936d)) +* **ssa:** Use accurate type during SSA AsSlice simplficiation ([#4610](https://github.com/noir-lang/noir/issues/4610)) ([0473497](https://github.com/noir-lang/noir/commit/04734976e92475b1ab94257e30bc3438c7358681)) +* Substitute generics when checking the field count of a type ([#4547](https://github.com/noir-lang/noir/issues/4547)) ([eeeebac](https://github.com/noir-lang/noir/commit/eeeebacd10698e847f773e26dac8a4a5eb8e84ed)) + + +### Miscellaneous Chores + +* Remove open keyword from Noir (https://github.com/AztecProtocol/aztec-packages/pull/4967) ([a6016b4](https://github.com/noir-lang/noir/commit/a6016b46abf6da6de4566cf6d35a675d805dd9b5)) + ## [0.25.0](https://github.com/noir-lang/noir/compare/v0.24.0...v0.25.0) (2024-03-11) diff --git a/Cargo.lock b/Cargo.lock index 99c19417267..8c47f03b267 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acir" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir_field", "base64 0.21.2", @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.41.0" +version = "0.42.0" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -37,7 +37,7 @@ dependencies = [ [[package]] name = "acvm" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -53,7 +53,7 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir", "blake2", @@ -88,7 +88,7 @@ dependencies = [ [[package]] name = "acvm_js" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acvm", "bn254_blackbox_solver", @@ -232,7 +232,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arena" -version = "0.25.0" +version = "0.26.0" [[package]] name = "ark-bls12-381" @@ -433,7 +433,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aztec_macros" -version = "0.25.0" +version = "0.26.0" dependencies = [ "convert_case 0.6.0", "iter-extended", @@ -600,7 +600,7 @@ dependencies = [ [[package]] name = "bn254_blackbox_solver" -version = "0.39.0" +version = "0.42.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -623,7 +623,7 @@ dependencies = [ [[package]] name = "brillig" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir_field", "serde", @@ -631,12 +631,13 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.41.0" +version = "0.42.0" dependencies = [ "acir", "acvm_blackbox_solver", "num-bigint", "num-traits", + "thiserror", ] [[package]] @@ -1736,7 +1737,7 @@ dependencies = [ [[package]] name = "fm" -version = "0.25.0" +version = "0.26.0" dependencies = [ "codespan-reporting", "iter-extended", @@ -2357,7 +2358,7 @@ dependencies = [ [[package]] name = "iter-extended" -version = "0.25.0" +version = "0.26.0" [[package]] name = "itertools" @@ -2742,7 +2743,7 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "nargo" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "codespan-reporting", @@ -2769,7 +2770,7 @@ dependencies = [ [[package]] name = "nargo_cli" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "assert_cmd", @@ -2824,7 +2825,7 @@ dependencies = [ [[package]] name = "nargo_fmt" -version = "0.25.0" +version = "0.26.0" dependencies = [ "bytecount", "noirc_frontend", @@ -2836,7 +2837,7 @@ dependencies = [ [[package]] name = "nargo_toml" -version = "0.25.0" +version = "0.26.0" dependencies = [ "dirs", "fm", @@ -2909,7 +2910,7 @@ dependencies = [ [[package]] name = "noir_debugger" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "assert_cmd", @@ -2944,7 +2945,7 @@ dependencies = [ [[package]] name = "noir_lsp" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "async-lsp", @@ -2970,7 +2971,7 @@ dependencies = [ [[package]] name = "noir_wasm" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "build-data", @@ -2993,7 +2994,7 @@ dependencies = [ [[package]] name = "noirc_abi" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "iter-extended", @@ -3010,7 +3011,7 @@ dependencies = [ [[package]] name = "noirc_abi_wasm" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "build-data", @@ -3027,7 +3028,7 @@ dependencies = [ [[package]] name = "noirc_driver" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "aztec_macros", @@ -3048,7 +3049,7 @@ dependencies = [ [[package]] name = "noirc_errors" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "base64 0.21.2", @@ -3066,7 +3067,7 @@ dependencies = [ [[package]] name = "noirc_evaluator" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "fxhash", @@ -3082,7 +3083,7 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "arena", @@ -3107,7 +3108,7 @@ dependencies = [ [[package]] name = "noirc_printable_type" -version = "0.25.0" +version = "0.26.0" dependencies = [ "acvm", "iter-extended", diff --git a/Cargo.toml b/Cargo.toml index b8f9b9ceacc..46ccb401fbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ resolver = "2" [workspace.package] # x-release-please-start-version -version = "0.25.0" +version = "0.26.0" # x-release-please-end authors = ["The Noir Team "] edition = "2021" @@ -52,13 +52,13 @@ repository = "https://github.com/noir-lang/noir/" [workspace.dependencies] # ACVM workspace dependencies -acir_field = { version = "0.41.0", path = "acvm-repo/acir_field", default-features = false } -acir = { version = "0.41.0", path = "acvm-repo/acir", default-features = false } -acvm = { version = "0.41.0", path = "acvm-repo/acvm" } -brillig = { version = "0.41.0", path = "acvm-repo/brillig", default-features = false } -brillig_vm = { version = "0.41.0", path = "acvm-repo/brillig_vm", default-features = false } -acvm_blackbox_solver = { version = "0.41.0", path = "acvm-repo/blackbox_solver", default-features = false } -bn254_blackbox_solver = { version = "0.39.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } +acir_field = { version = "0.42.0", path = "acvm-repo/acir_field", default-features = false } +acir = { version = "0.42.0", path = "acvm-repo/acir", default-features = false } +acvm = { version = "0.42.0", path = "acvm-repo/acvm" } +brillig = { version = "0.42.0", path = "acvm-repo/brillig", default-features = false } +brillig_vm = { version = "0.42.0", path = "acvm-repo/brillig_vm", default-features = false } +acvm_blackbox_solver = { version = "0.42.0", path = "acvm-repo/blackbox_solver", default-features = false } +bn254_blackbox_solver = { version = "0.42.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } # Noir compiler workspace dependencies arena = { path = "compiler/utils/arena" } diff --git a/acvm-repo/CHANGELOG.md b/acvm-repo/CHANGELOG.md index 4f220d6eeba..33cc83d7dd9 100644 --- a/acvm-repo/CHANGELOG.md +++ b/acvm-repo/CHANGELOG.md @@ -5,6 +5,87 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.42.0](https://github.com/noir-lang/noir/compare/v0.41.0...v0.42.0) (2024-03-25) + + +### ⚠ BREAKING CHANGES + +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) +* automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) +* move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) +* note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) +* rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) +* init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) +* Rename Arithmetic opcode to AssertZero ([#3840](https://github.com/noir-lang/noir/issues/3840)) +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) + +### Features + +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add bit size to const opcode (https://github.com/AztecProtocol/aztec-packages/pull/4385) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add CMOV instruction to brillig and brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5308) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add instrumentation for tracking variables in debugging ([#4122](https://github.com/noir-lang/noir/issues/4122)) ([c58d691](https://github.com/noir-lang/noir/commit/c58d69141b54a918cd1675400c00bfd48720f896)) +* Add poseidon2 opcode implementation for acvm/brillig, and Noir ([#4398](https://github.com/noir-lang/noir/issues/4398)) ([10e8292](https://github.com/noir-lang/noir/commit/10e82920798380f50046e52db4a20ca205191ab7)) +* Add support for overriding expression width ([#4117](https://github.com/noir-lang/noir/issues/4117)) ([c8026d5](https://github.com/noir-lang/noir/commit/c8026d557d535b10fe455165d6445076df7a03de)) +* Added cast opcode and cast calldata (https://github.com/AztecProtocol/aztec-packages/pull/4423) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Allow brillig to read arrays directly from memory (https://github.com/AztecProtocol/aztec-packages/pull/4460) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow nested arrays and vectors in Brillig foreign calls (https://github.com/AztecProtocol/aztec-packages/pull/4478) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow variables and stack trace inspection in the debugger ([#4184](https://github.com/noir-lang/noir/issues/4184)) ([bf263fc](https://github.com/noir-lang/noir/commit/bf263fc8d843940f328a90f6366edd2671fb2682)) +* Automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **avm:** Back in avm context with macro - refactor context (https://github.com/AztecProtocol/aztec-packages/pull/4438) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* **avm:** Brillig CONST of size > u128 (https://github.com/AztecProtocol/aztec-packages/pull/5217) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **aztec-nr:** Initial work for aztec public vm macro (https://github.com/AztecProtocol/aztec-packages/pull/4400) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Aztec-packages ([#3754](https://github.com/noir-lang/noir/issues/3754)) ([c043265](https://github.com/noir-lang/noir/commit/c043265e550b59bd4296504826fe15d3ce3e9ad2)) +* Backpropagate constants in ACIR during optimization ([#3926](https://github.com/noir-lang/noir/issues/3926)) ([aad0da0](https://github.com/noir-lang/noir/commit/aad0da024c69663f42e6913e674682d5864b26ae)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) ([5be049e](https://github.com/noir-lang/noir/commit/5be049eee6c342649462282ee04f6411e6ea392c)) +* Brillig IR refactor (https://github.com/AztecProtocol/aztec-packages/pull/5233) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Check initializer msg.sender matches deployer from address preimage (https://github.com/AztecProtocol/aztec-packages/pull/5222) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Evaluation of dynamic assert messages ([#4101](https://github.com/noir-lang/noir/issues/4101)) ([c284e01](https://github.com/noir-lang/noir/commit/c284e01bfe20ceae4414dc123624b5cbb8b66d09)) +* Init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Initial Earthly CI (https://github.com/AztecProtocol/aztec-packages/pull/5069) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* New brillig field operations and refactor of binary operations (https://github.com/AztecProtocol/aztec-packages/pull/5208) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove range constraints from witnesses which are constrained to be constants ([#3928](https://github.com/noir-lang/noir/issues/3928)) ([afe9c7a](https://github.com/noir-lang/noir/commit/afe9c7a38bb9d4245205d3aa46d4ce23d70a5671)) +* Remove replacement of boolean range opcodes with `AssertZero` opcodes ([#4107](https://github.com/noir-lang/noir/issues/4107)) ([dac0e87](https://github.com/noir-lang/noir/commit/dac0e87ee3be3446b92bbb12ef4832fd493fcee3)) +* Signed integer division and modulus in brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5279) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Speed up transformation of debug messages ([#3815](https://github.com/noir-lang/noir/issues/3815)) ([2a8af1e](https://github.com/noir-lang/noir/commit/2a8af1e4141ffff61547ee1c2837a6392bd5db48)) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync `aztec-packages` ([#4011](https://github.com/noir-lang/noir/issues/4011)) ([fee2452](https://github.com/noir-lang/noir/commit/fee24523c427c27f0bdaf98ea09a852a2da3e94c)) +* Sync commits from `aztec-packages` ([#4068](https://github.com/noir-lang/noir/issues/4068)) ([7a8f3a3](https://github.com/noir-lang/noir/commit/7a8f3a33b57875e681e3d81e667e3570a1cdbdcc)) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) ([0205d3b](https://github.com/noir-lang/noir/commit/0205d3b4ad0cf5ffd775a43eb5af273a772cf138)) +* Sync from aztec-packages ([#4483](https://github.com/noir-lang/noir/issues/4483)) ([fe8f277](https://github.com/noir-lang/noir/commit/fe8f2776ccfde29209a2c3fc162311c99e4f59be)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5234) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5286) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) + + +### Bug Fixes + +* Deserialize odd length hex literals ([#3747](https://github.com/noir-lang/noir/issues/3747)) ([4000fb2](https://github.com/noir-lang/noir/commit/4000fb279221eb07187d657bfaa7f1c7b311abf2)) +* Noir test incorrect reporting (https://github.com/AztecProtocol/aztec-packages/pull/4925) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* Remove panic from `init_log_level` in `acvm_js` ([#4195](https://github.com/noir-lang/noir/issues/4195)) ([2e26530](https://github.com/noir-lang/noir/commit/2e26530bf53006c1ed4fee310bcaa905c95dd95b)) +* Return error rather instead of panicking on invalid circuit ([#3976](https://github.com/noir-lang/noir/issues/3976)) ([67201bf](https://github.com/noir-lang/noir/commit/67201bfc21a9c8858aa86be9cd47d463fb78d925)) + + +### Miscellaneous Chores + +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove partial backend feature ([#3805](https://github.com/noir-lang/noir/issues/3805)) ([0383100](https://github.com/noir-lang/noir/commit/0383100853a80a5b28b797cdfeae0d271f1b7805)) +* Remove unused methods on ACIR opcodes ([#3841](https://github.com/noir-lang/noir/issues/3841)) ([9e5d0e8](https://github.com/noir-lang/noir/commit/9e5d0e813d61a0bfb5ee68174ed287c5a20f1579)) +* Rename Arithmetic opcode to AssertZero ([#3840](https://github.com/noir-lang/noir/issues/3840)) ([836f171](https://github.com/noir-lang/noir/commit/836f17145c2901060706294461c2d282dd121b3e)) +* Rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) + ## [0.41.0](https://github.com/noir-lang/noir/compare/v0.40.0...v0.41.0) (2024-03-11) diff --git a/acvm-repo/acir/Cargo.toml b/acvm-repo/acir/Cargo.toml index be859d7d054..368f49258f9 100644 --- a/acvm-repo/acir/Cargo.toml +++ b/acvm-repo/acir/Cargo.toml @@ -2,7 +2,7 @@ name = "acir" description = "ACIR is the IR that the VM processes, it is analogous to LLVM IR" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index ca281d89637..d7ef849ab75 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,957 +5,951 @@ namespace Program { - struct BinaryFieldOp { + struct Witness { + uint32_t value; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const Witness&, const Witness&); + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); + }; + + struct FunctionInput { + Program::Witness witness; + uint32_t num_bits; + + friend bool operator==(const FunctionInput&, const FunctionInput&); + std::vector bincodeSerialize() const; + static FunctionInput bincodeDeserialize(std::vector); + }; + + struct BlackBoxFuncCall { + + struct AND { + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; + + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct XOR { + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; + + friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static XOR bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct RANGE { + Program::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static RANGE bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct SHA256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static SHA256 bincodeDeserialize(std::vector); }; - struct IntegerDiv { - friend bool operator==(const IntegerDiv&, const IntegerDiv&); + struct Blake2s { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static IntegerDiv bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct Blake3 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct SchnorrVerify { + Program::FunctionInput public_key_x; + Program::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Program::Witness output; + + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; + + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - std::variant value; + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Program::Witness output; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); - std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); + }; - struct BinaryIntOp { + struct EcdsaSecp256k1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct EcdsaSecp256r1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; + + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct FixedBaseScalarMul { + Program::FunctionInput low; + Program::FunctionInput high; + std::array outputs; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct EmbeddedCurveAdd { + Program::FunctionInput input1_x; + Program::FunctionInput input1_y; + Program::FunctionInput input2_x; + Program::FunctionInput input2_y; + std::array outputs; + + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct Keccak256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct Keccak256VariableLength { + std::vector inputs; + Program::FunctionInput var_message_size; + std::vector outputs; + + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static Keccak256VariableLength bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Program::FunctionInput key_hash; + + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); + static RecursiveAggregation bincodeDeserialize(std::vector); }; - struct Or { - friend bool operator==(const Or&, const Or&); + struct BigIntAdd { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); + static BigIntAdd bincodeDeserialize(std::vector); }; - struct Xor { - friend bool operator==(const Xor&, const Xor&); + struct BigIntSub { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; - struct Shl { - friend bool operator==(const Shl&, const Shl&); + struct BigIntMul { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + struct BigIntDiv { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - std::variant value; + struct BigIntFromLeBytes { + std::vector inputs; + std::vector modulus; + uint32_t output; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + std::vector bincodeSerialize() const; + static BigIntFromLeBytes bincodeDeserialize(std::vector); + }; - struct MemoryAddress { - uint64_t value; + struct BigIntToLeBytes { + uint32_t input; + std::vector outputs; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + std::vector bincodeSerialize() const; + static BigIntToLeBytes bincodeDeserialize(std::vector); + }; - struct HeapArray { - Program::MemoryAddress pointer; - uint64_t size; + struct Poseidon2Permutation { + std::vector inputs; + std::vector outputs; + uint32_t len; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + std::vector bincodeSerialize() const; + static Poseidon2Permutation bincodeDeserialize(std::vector); + }; + + struct Sha256Compression { + std::vector inputs; + std::vector hash_values; + std::vector outputs; + + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static BlackBoxFuncCall bincodeDeserialize(std::vector); }; - struct HeapVector { - Program::MemoryAddress pointer; - Program::MemoryAddress size; + struct BlockId { + uint32_t value; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const BlockId&, const BlockId&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static BlockId bincodeDeserialize(std::vector); }; - struct BlackBoxOp { + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; - struct Sha256 { - Program::HeapVector message; - Program::HeapArray output; + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); + }; - friend bool operator==(const Sha256&, const Sha256&); - std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); - }; + struct BrilligInputs { - struct Blake2s { - Program::HeapVector message; - Program::HeapArray output; + struct Single { + Program::Expression value; - friend bool operator==(const Blake2s&, const Blake2s&); + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct Blake3 { - Program::HeapVector message; - Program::HeapArray output; + struct Array { + std::vector value; - friend bool operator==(const Blake3&, const Blake3&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Keccak256 { - Program::HeapVector message; - Program::HeapArray output; + struct MemoryArray { + Program::BlockId value; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Program::HeapVector message; - Program::HeapArray output; + std::variant value; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); - std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); - }; + friend bool operator==(const BrilligInputs&, const BrilligInputs&); + std::vector bincodeSerialize() const; + static BrilligInputs bincodeDeserialize(std::vector); + }; - struct EcdsaSecp256k1 { - Program::HeapVector hashed_msg; - Program::HeapArray public_key_x; - Program::HeapArray public_key_y; - Program::HeapArray signature; - Program::MemoryAddress result; + struct BinaryFieldOp { - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - Program::HeapVector hashed_msg; - Program::HeapArray public_key_x; - Program::HeapArray public_key_y; - Program::HeapArray signature; - Program::MemoryAddress result; - - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Program::MemoryAddress public_key_x; - Program::MemoryAddress public_key_y; - Program::HeapVector message; - Program::HeapVector signature; - Program::MemoryAddress result; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::HeapArray output; - - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; - struct PedersenHash { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::MemoryAddress output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); + struct IntegerDiv { + friend bool operator==(const IntegerDiv&, const IntegerDiv&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static IntegerDiv bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Program::MemoryAddress low; - Program::MemoryAddress high; - Program::HeapArray result; - - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Program::MemoryAddress input1_x; - Program::MemoryAddress input1_y; - Program::MemoryAddress input2_x; - Program::MemoryAddress input2_y; - Program::HeapArray result; - - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - struct BigIntAdd { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; - - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static LessThanEquals bincodeDeserialize(std::vector); }; - struct BigIntSub { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + std::variant value; - friend bool operator==(const BigIntSub&, const BigIntSub&); - std::vector bincodeSerialize() const; - static BigIntSub bincodeDeserialize(std::vector); - }; + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + std::vector bincodeSerialize() const; + static BinaryFieldOp bincodeDeserialize(std::vector); + }; - struct BigIntMul { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + struct BinaryIntOp { - friend bool operator==(const BigIntMul&, const BigIntMul&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct BigIntDiv { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; - - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - Program::HeapVector inputs; - Program::HeapVector modulus; - Program::MemoryAddress output; - - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - Program::MemoryAddress input; - Program::HeapVector output; - - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - Program::HeapVector message; - Program::HeapArray output; - Program::MemoryAddress len; - - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct Sha256Compression { - Program::HeapVector input; - Program::HeapVector hash_values; - Program::HeapArray output; - - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); - std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); - }; - - struct HeapValueType; - - struct HeapValueType { + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; - struct Simple { - friend bool operator==(const Simple&, const Simple&); + struct And { + friend bool operator==(const And&, const And&); std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); + static And bincodeDeserialize(std::vector); }; - struct Array { - std::vector value_types; - uint64_t size; + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; - friend bool operator==(const Array&, const Array&); + struct Xor { + friend bool operator==(const Xor&, const Xor&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static Xor bincodeDeserialize(std::vector); }; - struct Vector { - std::vector value_types; + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; - friend bool operator==(const Vector&, const Vector&); + struct Shr { + friend bool operator==(const Shr&, const Shr&); std::vector bincodeSerialize() const; - static Vector bincodeDeserialize(std::vector); + static Shr bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const HeapValueType&, const HeapValueType&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static HeapValueType bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct Value { - std::string inner; + struct MemoryAddress { + uint64_t value; - friend bool operator==(const Value&, const Value&); + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct ValueOrArray { + struct HeapArray { + Program::MemoryAddress pointer; + uint64_t size; - struct MemoryAddress { - Program::MemoryAddress value; + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; + struct HeapVector { + Program::MemoryAddress pointer; + Program::MemoryAddress size; - struct HeapArray { - Program::HeapArray value; + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; - friend bool operator==(const HeapArray&, const HeapArray&); - std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); - }; + struct BlackBoxOp { - struct HeapVector { - Program::HeapVector value; + struct Sha256 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static Sha256 bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const ValueOrArray&, const ValueOrArray&); - std::vector bincodeSerialize() const; - static ValueOrArray bincodeDeserialize(std::vector); - }; - - struct BrilligOpcode { - - struct BinaryFieldOp { - Program::MemoryAddress destination; - Program::BinaryFieldOp op; - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; + struct Blake2s { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct BinaryIntOp { - Program::MemoryAddress destination; - Program::BinaryIntOp op; - uint32_t bit_size; - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; + struct Blake3 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - struct Cast { - Program::MemoryAddress destination; - Program::MemoryAddress source; - uint32_t bit_size; + struct Keccak256 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const Cast&, const Cast&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static Cast bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct JumpIfNot { - Program::MemoryAddress condition; - uint64_t location; + struct Keccakf1600 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const JumpIfNot&, const JumpIfNot&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct JumpIf { - Program::MemoryAddress condition; - uint64_t location; + struct EcdsaSecp256k1 { + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; - friend bool operator==(const JumpIf&, const JumpIf&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - struct Jump { - uint64_t location; + struct EcdsaSecp256r1 { + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; - friend bool operator==(const Jump&, const Jump&); + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); + static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct CalldataCopy { - Program::MemoryAddress destination_address; - uint64_t size; - uint64_t offset; + struct SchnorrVerify { + Program::MemoryAddress public_key_x; + Program::MemoryAddress public_key_y; + Program::HeapVector message; + Program::HeapVector signature; + Program::MemoryAddress result; - friend bool operator==(const CalldataCopy&, const CalldataCopy&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static CalldataCopy bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Call { - uint64_t location; + struct PedersenCommitment { + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::HeapArray output; - friend bool operator==(const Call&, const Call&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct Const { - Program::MemoryAddress destination; - uint32_t bit_size; - Program::Value value; + struct PedersenHash { + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::MemoryAddress output; - friend bool operator==(const Const&, const Const&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct Return { - friend bool operator==(const Return&, const Return&); + struct FixedBaseScalarMul { + Program::MemoryAddress low; + Program::MemoryAddress high; + Program::HeapArray result; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector destination_value_types; - std::vector inputs; - std::vector input_value_types; + struct EmbeddedCurveAdd { + Program::MemoryAddress input1_x; + Program::MemoryAddress input1_y; + Program::MemoryAddress input2_x; + Program::MemoryAddress input2_y; + Program::HeapArray result; - friend bool operator==(const ForeignCall&, const ForeignCall&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct Mov { - Program::MemoryAddress destination; - Program::MemoryAddress source; + struct BigIntAdd { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Mov&, const Mov&); + friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); + static BigIntAdd bincodeDeserialize(std::vector); }; - struct ConditionalMov { - Program::MemoryAddress destination; - Program::MemoryAddress source_a; - Program::MemoryAddress source_b; - Program::MemoryAddress condition; + struct BigIntSub { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const ConditionalMov&, const ConditionalMov&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static ConditionalMov bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; - struct Load { - Program::MemoryAddress destination; - Program::MemoryAddress source_pointer; + struct BigIntMul { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Load&, const Load&); + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct Store { - Program::MemoryAddress destination_pointer; - Program::MemoryAddress source; + struct BigIntDiv { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Store&, const Store&); + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - struct BlackBox { - Program::BlackBoxOp value; + struct BigIntFromLeBytes { + Program::HeapVector inputs; + Program::HeapVector modulus; + Program::MemoryAddress output; - friend bool operator==(const BlackBox&, const BlackBox&); + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); + static BigIntFromLeBytes bincodeDeserialize(std::vector); }; - struct Trap { - friend bool operator==(const Trap&, const Trap&); + struct BigIntToLeBytes { + Program::MemoryAddress input; + Program::HeapVector output; + + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); + static BigIntToLeBytes bincodeDeserialize(std::vector); }; - struct Stop { - uint64_t return_data_offset; - uint64_t return_data_size; + struct Poseidon2Permutation { + Program::HeapVector message; + Program::HeapArray output; + Program::MemoryAddress len; - friend bool operator==(const Stop&, const Stop&); + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static Poseidon2Permutation bincodeDeserialize(std::vector); }; - std::variant value; + struct Sha256Compression { + Program::HeapVector input; + Program::HeapVector hash_values; + Program::HeapArray output; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); - std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); - }; + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; - struct Witness { - uint32_t value; + std::variant value; - friend bool operator==(const Witness&, const Witness&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct FunctionInput { - Program::Witness witness; - uint32_t num_bits; - - friend bool operator==(const FunctionInput&, const FunctionInput&); - std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); - }; + struct HeapValueType; - struct BlackBoxFuncCall { + struct HeapValueType { - struct AND { - Program::FunctionInput lhs; - Program::FunctionInput rhs; - Program::Witness output; + struct Simple { + uint32_t value; - friend bool operator==(const AND&, const AND&); + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; - struct XOR { - Program::FunctionInput lhs; - Program::FunctionInput rhs; - Program::Witness output; + struct Array { + std::vector value_types; + uint64_t size; - friend bool operator==(const XOR&, const XOR&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct RANGE { - Program::FunctionInput input; + struct Vector { + std::vector value_types; - friend bool operator==(const RANGE&, const RANGE&); + friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Vector bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const SHA256&, const SHA256&); - std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); - }; + std::variant value; - struct Blake2s { - std::vector inputs; - std::vector outputs; + friend bool operator==(const HeapValueType&, const HeapValueType&); + std::vector bincodeSerialize() const; + static HeapValueType bincodeDeserialize(std::vector); + }; - friend bool operator==(const Blake2s&, const Blake2s&); - std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); - }; + struct ValueOrArray { - struct Blake3 { - std::vector inputs; - std::vector outputs; + struct MemoryAddress { + Program::MemoryAddress value; - friend bool operator==(const Blake3&, const Blake3&); + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Program::FunctionInput public_key_x; - Program::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Program::Witness output; + struct HeapArray { + Program::HeapArray value; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct HeapVector { + Program::HeapVector value; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Program::Witness output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); - std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); - }; + std::variant value; - struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Program::Witness output; + friend bool operator==(const ValueOrArray&, const ValueOrArray&); + std::vector bincodeSerialize() const; + static ValueOrArray bincodeDeserialize(std::vector); + }; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); - std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); - }; + struct BrilligOpcode { - struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Program::Witness output; + struct BinaryFieldOp { + Program::MemoryAddress destination; + Program::BinaryFieldOp op; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Program::FunctionInput low; - Program::FunctionInput high; - std::array outputs; + struct BinaryIntOp { + Program::MemoryAddress destination; + Program::BinaryIntOp op; + uint32_t bit_size; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Program::FunctionInput input1_x; - Program::FunctionInput input1_y; - Program::FunctionInput input2_x; - Program::FunctionInput input2_y; - std::array outputs; + struct Cast { + Program::MemoryAddress destination; + Program::MemoryAddress source; + uint32_t bit_size; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Cast&, const Cast&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Cast bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - std::vector outputs; + struct JumpIfNot { + Program::MemoryAddress condition; + uint64_t location; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Program::FunctionInput var_message_size; - std::vector outputs; + struct JumpIf { + Program::MemoryAddress condition; + uint64_t location; - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + struct Jump { + uint64_t location; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Program::FunctionInput key_hash; + struct CalldataCopy { + Program::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Call { + uint64_t location; - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct BigIntSub { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Const { + Program::MemoryAddress destination; + uint32_t bit_size; + std::string value; - friend bool operator==(const BigIntSub&, const BigIntSub&); + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static BigIntSub bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; - - friend bool operator==(const BigIntMul&, const BigIntMul&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct ForeignCall { + std::string function; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + struct Mov { + Program::MemoryAddress destination; + Program::MemoryAddress source; - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + struct ConditionalMov { + Program::MemoryAddress destination; + Program::MemoryAddress source_a; + Program::MemoryAddress source_b; + Program::MemoryAddress condition; - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + friend bool operator==(const ConditionalMov&, const ConditionalMov&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static ConditionalMov bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + struct Load { + Program::MemoryAddress destination; + Program::MemoryAddress source_pointer; - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + struct Store { + Program::MemoryAddress destination_pointer; + Program::MemoryAddress source; - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static Store bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; - - friend bool operator==(const Expression&, const Expression&); - std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); - }; - - struct BrilligInputs { - - struct Single { - Program::Expression value; + struct BlackBox { + Program::BlackBoxOp value; - friend bool operator==(const Single&, const Single&); + friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static BlackBox bincodeDeserialize(std::vector); }; - struct Array { - std::vector value; - - friend bool operator==(const Array&, const Array&); + struct Trap { + friend bool operator==(const Trap&, const Trap&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static Trap bincodeDeserialize(std::vector); }; - struct MemoryArray { - Program::BlockId value; + struct Stop { + uint64_t return_data_offset; + uint64_t return_data_size; - friend bool operator==(const MemoryArray&, const MemoryArray&); + friend bool operator==(const Stop&, const Stop&); std::vector bincodeSerialize() const; - static MemoryArray bincodeDeserialize(std::vector); + static Stop bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligInputs&, const BrilligInputs&); + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); + static BrilligOpcode bincodeDeserialize(std::vector); }; struct BrilligOutputs { @@ -5645,6 +5639,7 @@ Program::HeapValueType serde::Deserializable::deserializ namespace Program { inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } @@ -5668,12 +5663,14 @@ namespace Program { template <> template void serde::Serializable::serialize(const Program::HeapValueType::Simple &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template Program::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { Program::HeapValueType::Simple obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } @@ -6419,48 +6416,6 @@ Program::PublicInputs serde::Deserializable::deserialize( return obj; } -namespace Program { - - inline bool operator==(const Value &lhs, const Value &rhs) { - if (!(lhs.inner == rhs.inner)) { return false; } - return true; - } - - inline std::vector Value::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline Value Value::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::Value &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.inner, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -Program::Value serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Program::Value obj; - obj.inner = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} - namespace Program { inline bool operator==(const ValueOrArray &lhs, const ValueOrArray &rhs) { diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 64385a37582..8b04292dfaa 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -190,9 +190,9 @@ fn simple_brillig_foreign_call() { brillig::Opcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], @@ -211,11 +211,11 @@ fn simple_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 214, - 159, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, - 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, 251, 164, 235, 53, 94, 218, 247, 75, - 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, 251, 208, - 106, 207, 232, 150, 65, 100, 53, 33, 2, 22, 232, 178, 27, 144, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 61, 10, 192, 48, 8, 133, 53, 133, 82, 186, + 245, 38, 233, 13, 122, 153, 14, 93, 58, 132, 144, 227, 135, 252, 41, 56, 36, 46, 201, 7, + 162, 168, 200, 123, 34, 52, 142, 28, 72, 245, 38, 106, 9, 247, 30, 202, 118, 142, 27, 215, + 221, 178, 82, 175, 33, 15, 133, 189, 163, 159, 57, 197, 252, 251, 195, 235, 188, 230, 186, + 16, 65, 255, 12, 239, 92, 131, 89, 149, 198, 77, 3, 10, 9, 119, 8, 198, 242, 152, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -264,8 +264,8 @@ fn complex_brillig_foreign_call() { }, brillig::Opcode::Const { destination: MemoryAddress(0), - value: brillig::Value::from(32_usize), - bit_size: 32, + value: FieldElement::from(32_usize), + bit_size: 64, }, brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(1), @@ -280,8 +280,8 @@ fn complex_brillig_foreign_call() { ValueOrArray::MemoryAddress(MemoryAddress::from(1)), ], input_value_types: vec![ - HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, - HeapValueType::Simple, + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::field()] }, + HeapValueType::field(), ], destinations: vec![ ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), @@ -289,9 +289,9 @@ fn complex_brillig_foreign_call() { ValueOrArray::MemoryAddress(MemoryAddress::from(36)), ], destination_value_types: vec![ - HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, - HeapValueType::Simple, - HeapValueType::Simple, + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::field()] }, + HeapValueType::field(), + HeapValueType::field(), ], }, brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 }, @@ -311,15 +311,15 @@ fn complex_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 222, - 246, 7, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, - 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, 205, 200, 157, 49, 124, 227, 44, 129, 207, - 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, 160, 209, 156, - 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, - 254, 196, 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, - 47, 178, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, - 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, 164, 50, 165, 0, 137, 17, - 72, 139, 88, 97, 4, 173, 98, 132, 157, 33, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 93, 10, 131, 48, 12, 78, 218, 233, 100, 111, + 187, 193, 96, 59, 64, 231, 9, 188, 139, 248, 166, 232, 163, 167, 23, 11, 126, 197, 24, 250, + 34, 86, 208, 64, 72, 218, 252, 125, 36, 105, 153, 22, 42, 60, 51, 116, 235, 217, 64, 103, + 156, 37, 5, 191, 10, 210, 29, 163, 63, 167, 203, 229, 206, 194, 104, 110, 128, 209, 158, + 128, 49, 236, 195, 69, 231, 157, 114, 46, 73, 251, 103, 35, 239, 231, 225, 57, 243, 156, + 227, 252, 132, 44, 112, 79, 176, 125, 84, 223, 73, 248, 145, 152, 69, 149, 4, 107, 233, + 114, 90, 119, 145, 85, 237, 151, 192, 89, 247, 221, 208, 54, 163, 85, 174, 26, 234, 87, + 232, 63, 101, 103, 21, 55, 169, 216, 73, 72, 249, 5, 197, 234, 132, 123, 179, 35, 247, 155, + 214, 246, 102, 20, 73, 204, 72, 168, 123, 191, 161, 25, 66, 136, 159, 187, 53, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acir_field/Cargo.toml b/acvm-repo/acir_field/Cargo.toml index c2056b73277..d63a885bfd8 100644 --- a/acvm-repo/acir_field/Cargo.toml +++ b/acvm-repo/acir_field/Cargo.toml @@ -2,7 +2,7 @@ name = "acir_field" description = "The field implementation being used by ACIR." # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index d585850170a..d0ea52e859d 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm" description = "The virtual machine that processes ACIR given a backend/proof system." # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index 2e549854521..18f49c154f1 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -6,10 +6,8 @@ use acir::{ use indexmap::IndexMap; mod csat; -mod r1cs; pub(crate) use csat::CSatTransformer; -pub(crate) use r1cs::R1CSTransformer; use super::{transform_assert_messages, AcirTransformationMap}; @@ -43,8 +41,7 @@ pub(super) fn transform_internal( ) -> (Circuit, Vec) { let mut transformer = match &expression_width { ExpressionWidth::Unbounded => { - let transformer = R1CSTransformer::new(acir); - return (transformer.transform(), acir_opcode_positions); + return (acir, acir_opcode_positions); } ExpressionWidth::Bounded { width } => { let mut csat = CSatTransformer::new(*width); diff --git a/acvm-repo/acvm/src/compiler/transformers/r1cs.rs b/acvm-repo/acvm/src/compiler/transformers/r1cs.rs deleted file mode 100644 index 3bdd29c9c53..00000000000 --- a/acvm-repo/acvm/src/compiler/transformers/r1cs.rs +++ /dev/null @@ -1,16 +0,0 @@ -use acir::circuit::Circuit; - -/// Currently a "noop" transformer. -pub(crate) struct R1CSTransformer { - acir: Circuit, -} - -impl R1CSTransformer { - pub(crate) fn new(acir: Circuit) -> Self { - Self { acir } - } - // TODO: We could possibly make sure that all polynomials are at most degree-2 - pub(crate) fn transform(self) -> Circuit { - self.acir - } -} diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 51c7f4c6203..bcf736cd926 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use acir::{ - brillig::{ForeignCallParam, ForeignCallResult, Value}, + brillig::{ForeignCallParam, ForeignCallResult}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, opcodes::BlockId, @@ -11,7 +11,7 @@ use acir::{ FieldElement, }; use acvm_blackbox_solver::BlackBoxFunctionSolver; -use brillig_vm::{VMStatus, VM}; +use brillig_vm::{MemoryValue, VMStatus, VM}; use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; @@ -73,7 +73,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { acir_index: usize, ) -> Result { // Set input values - let mut calldata: Vec = Vec::new(); + let mut calldata: Vec = Vec::new(); // Each input represents an expression or array of expressions to evaluate. // Iterate over each input and evaluate the expression(s) associated with it. // Push the results into memory. @@ -81,7 +81,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { for input in &brillig.inputs { match input { BrilligInputs::Single(expr) => match get_value(expr, initial_witness) { - Ok(value) => calldata.push(value.into()), + Ok(value) => calldata.push(value), Err(_) => { return Err(OpcodeResolutionError::OpcodeNotSolvable( OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), @@ -92,7 +92,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { // Attempt to fetch all array input values for expr in expr_arr.iter() { match get_value(expr, initial_witness) { - Ok(value) => calldata.push(value.into()), + Ok(value) => calldata.push(value), Err(_) => { return Err(OpcodeResolutionError::OpcodeNotSolvable( OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()), @@ -110,7 +110,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { .block_value .get(&memory_index) .expect("All memory is initialized on creation"); - calldata.push((*memory_value).into()); + calldata.push(*memory_value); } } } @@ -122,11 +122,11 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { Ok(Self { vm, acir_index }) } - pub fn get_memory(&self) -> &[Value] { + pub fn get_memory(&self) -> &[MemoryValue] { self.vm.get_memory() } - pub fn write_memory_at(&mut self, ptr: usize, value: Value) { + pub fn write_memory_at(&mut self, ptr: usize, value: MemoryValue) { self.vm.write_memory_at(ptr, value); } @@ -206,13 +206,13 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { for output in brillig.outputs.iter() { match output { BrilligOutputs::Simple(witness) => { - insert_value(witness, memory[current_ret_data_idx].to_field(), witness_map)?; + insert_value(witness, memory[current_ret_data_idx].value, witness_map)?; current_ret_data_idx += 1; } BrilligOutputs::Array(witness_arr) => { for witness in witness_arr.iter() { let value = memory[current_ret_data_idx]; - insert_value(witness, value.to_field(), witness_map)?; + insert_value(witness, value.value, witness_map)?; current_ret_data_idx += 1; } } diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index b267c3005a8..a708db5b030 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use acir::{ - brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, Value, ValueOrArray}, + brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, opcodes::{BlockId, MemOp}, @@ -70,9 +70,9 @@ fn inversion_brillig_oracle_equivalence() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, ], @@ -120,8 +120,7 @@ fn inversion_brillig_oracle_equivalence() { assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); // As caller of VM, need to resolve foreign calls - let foreign_call_result = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let foreign_call_result = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); // Alter Brillig oracle opcode with foreign call resolution acvm.resolve_pending_foreign_call(foreign_call_result.into()); @@ -199,16 +198,16 @@ fn double_inversion_brillig_oracle() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, ], @@ -257,8 +256,7 @@ fn double_inversion_brillig_oracle() { acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); - let x_plus_y_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let x_plus_y_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); // Resolve Brillig foreign call acvm.resolve_pending_foreign_call(x_plus_y_inverse.into()); @@ -275,8 +273,7 @@ fn double_inversion_brillig_oracle() { acvm.get_pending_foreign_call().expect("should have a brillig foreign call request"); assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); - let i_plus_j_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let i_plus_j_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); assert_ne!(x_plus_y_inverse, i_plus_j_inverse); // Alter Brillig oracle opcode @@ -334,16 +331,16 @@ fn oracle_dependent_execution() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, ], @@ -389,8 +386,7 @@ fn oracle_dependent_execution() { assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); // Resolve Brillig foreign call - let x_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let x_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); acvm.resolve_pending_foreign_call(x_inverse.into()); // After filling data request, continue solving @@ -406,8 +402,7 @@ fn oracle_dependent_execution() { assert_eq!(foreign_call_wait_info.inputs.len(), 1, "Should be waiting for a single input"); // Resolve Brillig foreign call - let y_inverse = - Value::from(foreign_call_wait_info.inputs[0].unwrap_value().to_field().inverse()); + let y_inverse = foreign_call_wait_info.inputs[0].unwrap_field().inverse(); acvm.resolve_pending_foreign_call(y_inverse.into()); // We've resolved all the brillig foreign calls so we should be able to complete execution now. @@ -464,9 +459,9 @@ fn brillig_oracle_predicate() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, ], predicate: Some(Expression::default()), diff --git a/acvm-repo/acvm_js/Cargo.toml b/acvm-repo/acvm_js/Cargo.toml index 63fca2bd32a..65c072b1d96 100644 --- a/acvm-repo/acvm_js/Cargo.toml +++ b/acvm-repo/acvm_js/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_js" description = "Typescript wrapper around the ACVM allowing execution of ACIR code" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm_js/package.json b/acvm-repo/acvm_js/package.json index 2f444ba565a..55345a2ddf6 100644 --- a/acvm-repo/acvm_js/package.json +++ b/acvm-repo/acvm_js/package.json @@ -1,6 +1,6 @@ { "name": "@noir-lang/acvm_js", - "version": "0.41.0", + "version": "0.42.0", "publishConfig": { "access": "public" }, diff --git a/acvm-repo/acvm_js/src/foreign_call/inputs.rs b/acvm-repo/acvm_js/src/foreign_call/inputs.rs index 728fc2d3d2f..ebd29fb7d58 100644 --- a/acvm-repo/acvm_js/src/foreign_call/inputs.rs +++ b/acvm-repo/acvm_js/src/foreign_call/inputs.rs @@ -8,8 +8,8 @@ pub(super) fn encode_foreign_call_inputs( let inputs = js_sys::Array::default(); for input in foreign_call_inputs { let input_array = js_sys::Array::default(); - for value in input.values() { - let hex_js_string = field_element_to_js_string(&value.to_field()); + for value in input.fields() { + let hex_js_string = field_element_to_js_string(&value); input_array.push(&hex_js_string); } inputs.push(&input_array); diff --git a/acvm-repo/acvm_js/src/foreign_call/outputs.rs b/acvm-repo/acvm_js/src/foreign_call/outputs.rs index 630b1afb6fd..78fa520aa15 100644 --- a/acvm-repo/acvm_js/src/foreign_call/outputs.rs +++ b/acvm-repo/acvm_js/src/foreign_call/outputs.rs @@ -1,18 +1,18 @@ -use acvm::brillig_vm::brillig::{ForeignCallParam, ForeignCallResult, Value}; +use acvm::brillig_vm::brillig::{ForeignCallParam, ForeignCallResult}; use wasm_bindgen::JsValue; use crate::js_witness_map::js_value_to_field_element; fn decode_foreign_call_output(output: JsValue) -> Result { if output.is_string() { - let value = Value::from(js_value_to_field_element(output)?); + let value = js_value_to_field_element(output)?; Ok(ForeignCallParam::Single(value)) } else if output.is_array() { let output = js_sys::Array::from(&output); - let mut values: Vec = Vec::with_capacity(output.length() as usize); + let mut values: Vec<_> = Vec::with_capacity(output.length() as usize); for elem in output.iter() { - values.push(Value::from(js_value_to_field_element(elem)?)); + values.push(js_value_to_field_element(elem)?); } Ok(ForeignCallParam::Array(values)) } else { diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index fba8470585f..e074cf1ad38 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 222, 246, 7, 38, 187, 15, 96, - 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, - 205, 200, 157, 49, 124, 227, 44, 129, 207, 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, - 160, 209, 156, 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, 254, 196, - 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, 47, 178, 186, 251, 37, 116, 86, 93, - 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, - 164, 50, 165, 0, 137, 17, 72, 139, 88, 97, 4, 173, 98, 132, 157, 33, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 93, 10, 131, 48, 12, 78, 218, 233, 100, 111, 187, 193, 96, 59, 64, 231, 9, + 188, 139, 248, 166, 232, 163, 167, 23, 11, 126, 197, 24, 250, 34, 86, 208, 64, 72, 218, 252, 125, 36, 105, 153, 22, + 42, 60, 51, 116, 235, 217, 64, 103, 156, 37, 5, 191, 10, 210, 29, 163, 63, 167, 203, 229, 206, 194, 104, 110, 128, + 209, 158, 128, 49, 236, 195, 69, 231, 157, 114, 46, 73, 251, 103, 35, 239, 231, 225, 57, 243, 156, 227, 252, 132, 44, + 112, 79, 176, 125, 84, 223, 73, 248, 145, 152, 69, 149, 4, 107, 233, 114, 90, 119, 145, 85, 237, 151, 192, 89, 247, + 221, 208, 54, 163, 85, 174, 26, 234, 87, 232, 63, 101, 103, 21, 55, 169, 216, 73, 72, 249, 5, 197, 234, 132, 123, 179, + 35, 247, 155, 214, 246, 102, 20, 73, 204, 72, 168, 123, 191, 161, 25, 66, 136, 159, 187, 53, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index dd010f0c5e5..eb14cb2e9f1 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 214, 159, 216, 31, 244, 51, 61, - 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, - 251, 164, 235, 53, 94, 218, 247, 75, 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, - 251, 208, 106, 207, 232, 150, 65, 100, 53, 33, 2, 22, 232, 178, 27, 144, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 61, 10, 192, 48, 8, 133, 53, 133, 82, 186, 245, 38, 233, 13, 122, 153, + 14, 93, 58, 132, 144, 227, 135, 252, 41, 56, 36, 46, 201, 7, 162, 168, 200, 123, 34, 52, 142, 28, 72, 245, 38, 106, 9, + 247, 30, 202, 118, 142, 27, 215, 221, 178, 82, 175, 33, 15, 133, 189, 163, 159, 57, 197, 252, 251, 195, 235, 188, 230, + 186, 16, 65, 255, 12, 239, 92, 131, 89, 149, 198, 77, 3, 10, 9, 119, 8, 198, 242, 152, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/blackbox_solver/Cargo.toml b/acvm-repo/blackbox_solver/Cargo.toml index a783193edba..8f5ff862360 100644 --- a/acvm-repo/blackbox_solver/Cargo.toml +++ b/acvm-repo/blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_blackbox_solver" description = "A solver for the blackbox functions found in ACIR and Brillig" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/bn254_blackbox_solver/Cargo.toml b/acvm-repo/bn254_blackbox_solver/Cargo.toml index a0a15409604..396e4aa0146 100644 --- a/acvm-repo/bn254_blackbox_solver/Cargo.toml +++ b/acvm-repo/bn254_blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "bn254_blackbox_solver" description = "Solvers for black box functions which are specific for the bn254 curve" # x-release-please-start-version -version = "0.39.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig/Cargo.toml b/acvm-repo/brillig/Cargo.toml index 57f89e091b4..d3f082fda86 100644 --- a/acvm-repo/brillig/Cargo.toml +++ b/acvm-repo/brillig/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig" description = "Brillig is the bytecode ACIR uses for non-determinism." # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig/src/foreign_call.rs b/acvm-repo/brillig/src/foreign_call.rs index 3f124a9a0a7..e547b99f0eb 100644 --- a/acvm-repo/brillig/src/foreign_call.rs +++ b/acvm-repo/brillig/src/foreign_call.rs @@ -1,34 +1,34 @@ -use crate::value::Value; +use acir_field::FieldElement; use serde::{Deserialize, Serialize}; /// Single output of a [foreign call][crate::Opcode::ForeignCall]. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] pub enum ForeignCallParam { - Single(Value), - Array(Vec), + Single(FieldElement), + Array(Vec), } -impl From for ForeignCallParam { - fn from(value: Value) -> Self { +impl From for ForeignCallParam { + fn from(value: FieldElement) -> Self { ForeignCallParam::Single(value) } } -impl From> for ForeignCallParam { - fn from(values: Vec) -> Self { +impl From> for ForeignCallParam { + fn from(values: Vec) -> Self { ForeignCallParam::Array(values) } } impl ForeignCallParam { - pub fn values(&self) -> Vec { + pub fn fields(&self) -> Vec { match self { ForeignCallParam::Single(value) => vec![*value], ForeignCallParam::Array(values) => values.clone(), } } - pub fn unwrap_value(&self) -> Value { + pub fn unwrap_field(&self) -> FieldElement { match self { ForeignCallParam::Single(value) => *value, ForeignCallParam::Array(_) => panic!("Expected single value, found array"), @@ -43,14 +43,14 @@ pub struct ForeignCallResult { pub values: Vec, } -impl From for ForeignCallResult { - fn from(value: Value) -> Self { +impl From for ForeignCallResult { + fn from(value: FieldElement) -> Self { ForeignCallResult { values: vec![value.into()] } } } -impl From> for ForeignCallResult { - fn from(values: Vec) -> Self { +impl From> for ForeignCallResult { + fn from(values: Vec) -> Self { ForeignCallResult { values: vec![values.into()] } } } diff --git a/acvm-repo/brillig/src/lib.rs b/acvm-repo/brillig/src/lib.rs index 0661e794360..40f2e15acfe 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -13,7 +13,6 @@ mod black_box; mod foreign_call; mod opcodes; -mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; @@ -21,5 +20,3 @@ pub use opcodes::{ BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, }; pub use opcodes::{BrilligOpcode as Opcode, Label}; -pub use value::Typ; -pub use value::Value; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 22a0ebe1170..d1345351986 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -1,4 +1,5 @@ -use crate::{black_box::BlackBoxOp, Value}; +use crate::black_box::BlackBoxOp; +use acir_field::FieldElement; use serde::{Deserialize, Serialize}; pub type Label = usize; @@ -22,8 +23,8 @@ impl From for MemoryAddress { /// Describes the memory layout for an array/vector element #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum HeapValueType { - // A single field element is enough to represent the value - Simple, + // A single field element is enough to represent the value with a given bit size + Simple(u32), // The value read should be interpreted as a pointer to a heap array, which // consists of a pointer to a slice of memory of size elements, and a // reference count @@ -36,7 +37,11 @@ pub enum HeapValueType { impl HeapValueType { pub fn all_simple(types: &[HeapValueType]) -> bool { - types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + types.iter().all(|typ| matches!(typ, HeapValueType::Simple(_))) + } + + pub fn field() -> HeapValueType { + HeapValueType::Simple(FieldElement::max_num_bits()) } } @@ -131,7 +136,7 @@ pub enum BrilligOpcode { Const { destination: MemoryAddress, bit_size: u32, - value: Value, + value: FieldElement, }, Return, /// Used to get data from an outside source. diff --git a/acvm-repo/brillig/src/value.rs b/acvm-repo/brillig/src/value.rs deleted file mode 100644 index 5a532cbc1a7..00000000000 --- a/acvm-repo/brillig/src/value.rs +++ /dev/null @@ -1,103 +0,0 @@ -use acir_field::FieldElement; -use serde::{Deserialize, Serialize}; -use std::ops::{Add, Div, Mul, Neg, Sub}; - -/// Types of values allowed in the VM -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] -pub enum Typ { - Field, - Unsigned { bit_size: u32 }, - Signed { bit_size: u32 }, -} - -/// `Value` represents the base descriptor for a value in the VM. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Value { - inner: FieldElement, -} - -impl Value { - /// Returns `true` if the `Value` represents `zero` - pub fn is_zero(&self) -> bool { - self.inner.is_zero() - } - - /// Converts `Value` into a `FieldElement`. - pub fn to_field(&self) -> FieldElement { - self.inner - } - - /// Converts `Value` into a `u128`. - // TODO: Check what happens if `Value` cannot fit into a u128 - pub fn to_u128(&self) -> u128 { - self.to_field().to_u128() - } - - /// Converts `Value` into a u64 and then casts it into a usize. - /// Panics: If `Value` cannot fit into a u64 or `Value` does - //// not fit into a usize. - pub fn to_usize(&self) -> usize { - usize::try_from(self.inner.try_to_u64().expect("value does not fit into u64")) - .expect("value does not fit into usize") - } -} - -impl From for Value { - fn from(value: usize) -> Self { - Value { inner: FieldElement::from(value as u128) } - } -} - -impl From for Value { - fn from(value: u128) -> Self { - Value { inner: FieldElement::from(value) } - } -} - -impl From for Value { - fn from(value: FieldElement) -> Self { - Value { inner: value } - } -} - -impl From for Value { - fn from(value: bool) -> Self { - Value { inner: FieldElement::from(value) } - } -} - -impl Add for Value { - type Output = Value; - - fn add(self, rhs: Self) -> Self::Output { - Value { inner: self.inner + rhs.inner } - } -} -impl Sub for Value { - type Output = Value; - - fn sub(self, rhs: Self) -> Self::Output { - Value { inner: self.inner - rhs.inner } - } -} -impl Mul for Value { - type Output = Value; - - fn mul(self, rhs: Self) -> Self::Output { - Value { inner: self.inner * rhs.inner } - } -} -impl Div for Value { - type Output = Value; - - fn div(self, rhs: Self) -> Self::Output { - Value { inner: self.inner / rhs.inner } - } -} -impl Neg for Value { - type Output = Value; - - fn neg(self) -> Self::Output { - Value { inner: -self.inner } - } -} diff --git a/acvm-repo/brillig_vm/Cargo.toml b/acvm-repo/brillig_vm/Cargo.toml index 1c7add5cb40..95675469479 100644 --- a/acvm-repo/brillig_vm/Cargo.toml +++ b/acvm-repo/brillig_vm/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig_vm" description = "The virtual machine that processes Brillig bytecode, used to introduce non-determinism to the ACVM" # x-release-please-start-version -version = "0.41.0" +version = "0.42.0" # x-release-please-end authors.workspace = true edition.workspace = true @@ -17,6 +17,7 @@ acir.workspace = true acvm_blackbox_solver.workspace = true num-bigint.workspace = true num-traits.workspace = true +thiserror.workspace = true [features] default = ["bn254"] diff --git a/acvm-repo/brillig_vm/src/arithmetic.rs b/acvm-repo/brillig_vm/src/arithmetic.rs index 81103be582d..3d77982ffb1 100644 --- a/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/acvm-repo/brillig_vm/src/arithmetic.rs @@ -3,56 +3,98 @@ use acir::FieldElement; use num_bigint::BigUint; use num_traits::{One, ToPrimitive, Zero}; -/// Evaluate a binary operation on two FieldElements and return the result as a FieldElement. +use crate::memory::MemoryValue; + +#[derive(Debug, thiserror::Error)] +pub(crate) enum BrilligArithmeticError { + #[error("Bit size for lhs {lhs_bit_size} does not match op bit size {op_bit_size}")] + MismatchedLhsBitSize { lhs_bit_size: u32, op_bit_size: u32 }, + #[error("Bit size for rhs {rhs_bit_size} does not match op bit size {op_bit_size}")] + MismatchedRhsBitSize { rhs_bit_size: u32, op_bit_size: u32 }, + #[error("Shift with bit size {op_bit_size} is invalid")] + InvalidShift { op_bit_size: u32 }, +} + +/// Evaluate a binary operation on two FieldElement memory values. pub(crate) fn evaluate_binary_field_op( op: &BinaryFieldOp, - a: FieldElement, - b: FieldElement, -) -> FieldElement { - match op { + lhs: MemoryValue, + rhs: MemoryValue, +) -> Result { + if lhs.bit_size != FieldElement::max_num_bits() { + return Err(BrilligArithmeticError::MismatchedLhsBitSize { + lhs_bit_size: lhs.bit_size, + op_bit_size: FieldElement::max_num_bits(), + }); + } + if rhs.bit_size != FieldElement::max_num_bits() { + return Err(BrilligArithmeticError::MismatchedRhsBitSize { + rhs_bit_size: rhs.bit_size, + op_bit_size: FieldElement::max_num_bits(), + }); + } + + let a = lhs.value; + let b = rhs.value; + Ok(match op { // Perform addition, subtraction, multiplication, and division based on the BinaryOp variant. - BinaryFieldOp::Add => a + b, - BinaryFieldOp::Sub => a - b, - BinaryFieldOp::Mul => a * b, - BinaryFieldOp::Div => a / b, + BinaryFieldOp::Add => (a + b).into(), + BinaryFieldOp::Sub => (a - b).into(), + BinaryFieldOp::Mul => (a * b).into(), + BinaryFieldOp::Div => (a / b).into(), BinaryFieldOp::IntegerDiv => { let a_big = BigUint::from_bytes_be(&a.to_be_bytes()); let b_big = BigUint::from_bytes_be(&b.to_be_bytes()); let result = a_big / b_big; - FieldElement::from_be_bytes_reduce(&result.to_bytes_be()) + FieldElement::from_be_bytes_reduce(&result.to_bytes_be()).into() } BinaryFieldOp::Equals => (a == b).into(), BinaryFieldOp::LessThan => (a < b).into(), BinaryFieldOp::LessThanEquals => (a <= b).into(), - } + }) } -/// Evaluate a binary operation on two unsigned big integers with a given bit size and return the result as a big integer. -pub(crate) fn evaluate_binary_bigint_op( +/// Evaluate a binary operation on two unsigned big integers with a given bit size. +pub(crate) fn evaluate_binary_int_op( op: &BinaryIntOp, - a: BigUint, - b: BigUint, + lhs: MemoryValue, + rhs: MemoryValue, bit_size: u32, -) -> Result { +) -> Result { + if lhs.bit_size != bit_size { + return Err(BrilligArithmeticError::MismatchedLhsBitSize { + lhs_bit_size: lhs.bit_size, + op_bit_size: bit_size, + }); + } + if rhs.bit_size != bit_size { + return Err(BrilligArithmeticError::MismatchedRhsBitSize { + rhs_bit_size: rhs.bit_size, + op_bit_size: bit_size, + }); + } + + let lhs = BigUint::from_bytes_be(&lhs.value.to_be_bytes()); + let rhs = BigUint::from_bytes_be(&rhs.value.to_be_bytes()); + let bit_modulo = &(BigUint::one() << bit_size); let result = match op { // Perform addition, subtraction, and multiplication, applying a modulo operation to keep the result within the bit size. - BinaryIntOp::Add => (a + b) % bit_modulo, - BinaryIntOp::Sub => (bit_modulo + a - b) % bit_modulo, - BinaryIntOp::Mul => (a * b) % bit_modulo, + BinaryIntOp::Add => (lhs + rhs) % bit_modulo, + BinaryIntOp::Sub => (bit_modulo + lhs - rhs) % bit_modulo, + BinaryIntOp::Mul => (lhs * rhs) % bit_modulo, // Perform unsigned division using the modulo operation on a and b. BinaryIntOp::Div => { - let b_mod = b % bit_modulo; - if b_mod.is_zero() { + if rhs.is_zero() { BigUint::zero() } else { - (a % bit_modulo) / b_mod + lhs / rhs } } // Perform a == operation, returning 0 or 1 BinaryIntOp::Equals => { - if (a % bit_modulo) == (b % bit_modulo) { + if lhs == rhs { BigUint::one() } else { BigUint::zero() @@ -60,7 +102,7 @@ pub(crate) fn evaluate_binary_bigint_op( } // Perform a < operation, returning 0 or 1 BinaryIntOp::LessThan => { - if (a % bit_modulo) < (b % bit_modulo) { + if lhs < rhs { BigUint::one() } else { BigUint::zero() @@ -68,29 +110,40 @@ pub(crate) fn evaluate_binary_bigint_op( } // Perform a <= operation, returning 0 or 1 BinaryIntOp::LessThanEquals => { - if (a % bit_modulo) <= (b % bit_modulo) { + if lhs <= rhs { BigUint::one() } else { BigUint::zero() } } // Perform bitwise AND, OR, XOR, left shift, and right shift operations, applying a modulo operation to keep the result within the bit size. - BinaryIntOp::And => (a & b) % bit_modulo, - BinaryIntOp::Or => (a | b) % bit_modulo, - BinaryIntOp::Xor => (a ^ b) % bit_modulo, + BinaryIntOp::And => lhs & rhs, + BinaryIntOp::Or => lhs | rhs, + BinaryIntOp::Xor => lhs ^ rhs, BinaryIntOp::Shl => { - assert!(bit_size <= 128, "unsupported bit size for right shift"); - let b = b.to_u128().unwrap(); - (a << b) % bit_modulo + if bit_size > 128 { + return Err(BrilligArithmeticError::InvalidShift { op_bit_size: bit_size }); + } + let rhs = rhs.to_u128().unwrap(); + (lhs << rhs) % bit_modulo } BinaryIntOp::Shr => { - assert!(bit_size <= 128, "unsupported bit size for right shift"); - let b = b.to_u128().unwrap(); - (a >> b) % bit_modulo + if bit_size > 128 { + return Err(BrilligArithmeticError::InvalidShift { op_bit_size: bit_size }); + } + let rhs = rhs.to_u128().unwrap(); + lhs >> rhs } }; - Ok(result) + let result_as_field = FieldElement::from_be_bytes_reduce(&result.to_bytes_be()); + + Ok(match op { + BinaryIntOp::Equals | BinaryIntOp::LessThan | BinaryIntOp::LessThanEquals => { + MemoryValue::new(result_as_field, 1) + } + _ => MemoryValue::new(result_as_field, bit_size), + }) } #[cfg(test)] @@ -104,12 +157,15 @@ mod tests { } fn evaluate_u128(op: &BinaryIntOp, a: u128, b: u128, bit_size: u32) -> u128 { - // Convert to big integers - let lhs_big = BigUint::from(a); - let rhs_big = BigUint::from(b); - let result_value = evaluate_binary_bigint_op(op, lhs_big, rhs_big, bit_size).unwrap(); + let result_value = evaluate_binary_int_op( + op, + MemoryValue::new(a.into(), bit_size), + MemoryValue::new(b.into(), bit_size), + bit_size, + ) + .unwrap(); // Convert back to u128 - result_value.to_u128().unwrap() + result_value.value.to_u128() } fn to_negative(a: u128, bit_size: u32) -> u128 { diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index 73b57b907f3..ab4358739e9 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -1,33 +1,33 @@ -use acir::brillig::{BlackBoxOp, HeapArray, HeapVector, Value}; +use acir::brillig::{BlackBoxOp, HeapArray, HeapVector}; use acir::{BlackBoxFunc, FieldElement}; use acvm_blackbox_solver::{ blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, keccakf1600, sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; +use crate::memory::MemoryValue; use crate::Memory; -fn read_heap_vector<'a>(memory: &'a Memory, vector: &HeapVector) -> &'a [Value] { - memory.read_slice(memory.read_ref(vector.pointer), memory.read(vector.size).to_usize()) +fn read_heap_vector<'a>(memory: &'a Memory, vector: &HeapVector) -> &'a [MemoryValue] { + let size = memory.read(vector.size); + memory.read_slice(memory.read_ref(vector.pointer), size.to_usize()) } -fn read_heap_array<'a>(memory: &'a Memory, array: &HeapArray) -> &'a [Value] { +fn read_heap_array<'a>(memory: &'a Memory, array: &HeapArray) -> &'a [MemoryValue] { memory.read_slice(memory.read_ref(array.pointer), array.size) } /// Extracts the last byte of every value -fn to_u8_vec(inputs: &[Value]) -> Vec { +fn to_u8_vec(inputs: &[MemoryValue]) -> Vec { let mut result = Vec::with_capacity(inputs.len()); - for input in inputs { - let field_bytes = input.to_field().to_be_bytes(); - let byte = field_bytes.last().unwrap(); - result.push(*byte); + for &input in inputs { + result.push(input.try_into().unwrap()); } result } -fn to_value_vec(input: &[u8]) -> Vec { - input.iter().map(|x| Value::from(*x as usize)).collect() +fn to_value_vec(input: &[u8]) -> Vec { + input.iter().map(|&x| x.into()).collect() } pub(crate) fn evaluate_black_box( @@ -63,14 +63,13 @@ pub(crate) fn evaluate_black_box( BlackBoxOp::Keccakf1600 { message, output } => { let state_vec: Vec = read_heap_vector(memory, message) .iter() - .map(|value| value.to_field().try_to_u64().unwrap()) + .map(|&memory_value| memory_value.try_into().unwrap()) .collect(); let state: [u64; 25] = state_vec.try_into().unwrap(); let new_state = keccakf1600(state)?; - let new_state: Vec = - new_state.into_iter().map(|x| Value::from(x as usize)).collect(); + let new_state: Vec = new_state.into_iter().map(|x| x.into()).collect(); memory.write_slice(memory.read_ref(output.pointer), &new_state); Ok(()) } @@ -125,8 +124,8 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::SchnorrVerify { public_key_x, public_key_y, message, signature, result } => { - let public_key_x = memory.read(*public_key_x).to_field(); - let public_key_y = memory.read(*public_key_y).to_field(); + let public_key_x = memory.read(*public_key_x).try_into().unwrap(); + let public_key_y = memory.read(*public_key_y).try_into().unwrap(); let message: Vec = to_u8_vec(read_heap_vector(memory, message)); let signature: Vec = to_u8_vec(read_heap_vector(memory, signature)); let verified = @@ -135,26 +134,26 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::FixedBaseScalarMul { low, high, result } => { - let low = memory.read(*low).to_field(); - let high = memory.read(*high).to_field(); + let low = memory.read(*low).try_into().unwrap(); + let high = memory.read(*high).try_into().unwrap(); let (x, y) = solver.fixed_base_scalar_mul(&low, &high)?; memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, result } => { - let input1_x = memory.read(*input1_x).to_field(); - let input1_y = memory.read(*input1_y).to_field(); - let input2_x = memory.read(*input2_x).to_field(); - let input2_y = memory.read(*input2_y).to_field(); + let input1_x = memory.read(*input1_x).try_into().unwrap(); + let input1_y = memory.read(*input1_y).try_into().unwrap(); + let input2_x = memory.read(*input2_x).try_into().unwrap(); + let input2_y = memory.read(*input2_y).try_into().unwrap(); let (x, y) = solver.ec_add(&input1_x, &input1_y, &input2_x, &input2_y)?; memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { let inputs: Vec = - read_heap_vector(memory, inputs).iter().map(|x| x.to_field()).collect(); + read_heap_vector(memory, inputs).iter().map(|&x| x.try_into().unwrap()).collect(); let domain_separator: u32 = - memory.read(*domain_separator).to_u128().try_into().map_err(|_| { + memory.read(*domain_separator).try_into().map_err(|_| { BlackBoxResolutionError::Failed( BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), @@ -166,9 +165,9 @@ pub(crate) fn evaluate_black_box( } BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { let inputs: Vec = - read_heap_vector(memory, inputs).iter().map(|x| x.to_field()).collect(); + read_heap_vector(memory, inputs).iter().map(|&x| x.try_into().unwrap()).collect(); let domain_separator: u32 = - memory.read(*domain_separator).to_u128().try_into().map_err(|_| { + memory.read(*domain_separator).try_into().map_err(|_| { BlackBoxResolutionError::Failed( BlackBoxFunc::PedersenCommitment, "Invalid signature length".to_string(), @@ -186,12 +185,12 @@ pub(crate) fn evaluate_black_box( BlackBoxOp::BigIntToLeBytes { .. } => todo!(), BlackBoxOp::Poseidon2Permutation { message, output, len } => { let input = read_heap_vector(memory, message); - let input: Vec = input.iter().map(|x| x.to_field()).collect(); - let len = memory.read(*len).to_u128() as u32; + let input: Vec = input.iter().map(|&x| x.try_into().unwrap()).collect(); + let len = memory.read(*len).try_into().unwrap(); let result = solver.poseidon2_permutation(&input, len)?; let mut values = Vec::new(); for i in result { - values.push(Value::from(i)); + values.push(i.into()); } memory.write_slice(memory.read_ref(output.pointer), &values); Ok(()) @@ -205,8 +204,8 @@ pub(crate) fn evaluate_black_box( format!("Expected 16 inputs but encountered {}", &inputs.len()), )); } - for (i, input) in inputs.iter().enumerate() { - message[i] = input.to_u128() as u32; + for (i, &input) in inputs.iter().enumerate() { + message[i] = input.try_into().unwrap(); } let mut state = [0; 8]; let values = read_heap_vector(memory, hash_values); @@ -216,12 +215,12 @@ pub(crate) fn evaluate_black_box( format!("Expected 8 values but encountered {}", &values.len()), )); } - for (i, value) in values.iter().enumerate() { - state[i] = value.to_u128() as u32; + for (i, &value) in values.iter().enumerate() { + state[i] = value.try_into().unwrap(); } sha256compression(&mut state, &message); - let state = state.map(|x| Value::from(x as u128)); + let state = state.map(|x| x.into()); memory.write_slice(memory.read_ref(output.pointer), &state); Ok(()) diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index e2a037618a4..0f430b0d5b2 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -13,23 +13,22 @@ use acir::brillig::{ BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, - HeapVector, MemoryAddress, Opcode, Value, ValueOrArray, + HeapVector, MemoryAddress, Opcode, ValueOrArray, }; use acir::FieldElement; +use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; +use arithmetic::{evaluate_binary_field_op, evaluate_binary_int_op, BrilligArithmeticError}; +use black_box::evaluate_black_box; +use num_bigint::BigUint; + // Re-export `brillig`. pub use acir::brillig; +pub use memory::{Memory, MemoryValue, MEMORY_ADDRESSING_BIT_SIZE}; mod arithmetic; mod black_box; mod memory; -use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; -use arithmetic::{evaluate_binary_bigint_op, evaluate_binary_field_op}; -use black_box::evaluate_black_box; - -pub use memory::Memory; -use num_bigint::BigUint; - /// The error call stack contains the opcode indexes of the call stack at the time of failure, plus the index of the opcode that failed. pub type ErrorCallStack = Vec; @@ -63,7 +62,7 @@ pub enum VMStatus { /// VM encapsulates the state of the Brillig VM during execution. pub struct VM<'a, B: BlackBoxFunctionSolver> { /// Calldata to the brillig function - calldata: Vec, + calldata: Vec, /// Instruction pointer program_counter: usize, /// A counter maintained throughout a Brillig process that determines @@ -79,7 +78,7 @@ pub struct VM<'a, B: BlackBoxFunctionSolver> { /// Memory of the VM memory: Memory, /// Call stack - call_stack: Vec, + call_stack: Vec, /// The solver for blackbox functions black_box_solver: &'a B, } @@ -87,7 +86,7 @@ pub struct VM<'a, B: BlackBoxFunctionSolver> { impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { /// Constructs a new VM instance pub fn new( - calldata: Vec, + calldata: Vec, bytecode: &'a [Opcode], foreign_call_results: Vec, black_box_solver: &'a B, @@ -143,8 +142,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { /// Indicating that the VM encountered a `Trap` Opcode /// or an invalid state. fn fail(&mut self, message: String) -> VMStatus { - let mut error_stack: Vec<_> = - self.call_stack.iter().map(|value| value.to_usize()).collect(); + let mut error_stack: Vec<_> = self.call_stack.clone(); error_stack.push(self.program_counter); self.status(VMStatus::Failure { call_stack: error_stack, message }); self.status.clone() @@ -159,22 +157,18 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.status.clone() } - pub fn get_memory(&self) -> &[Value] { + pub fn get_memory(&self) -> &[MemoryValue] { self.memory.values() } - pub fn write_memory_at(&mut self, ptr: usize, value: Value) { + pub fn write_memory_at(&mut self, ptr: usize, value: MemoryValue) { self.memory.write(MemoryAddress(ptr), value); } /// Returns the VM's current call stack, including the actual program /// counter in the last position of the returned vector. pub fn get_call_stack(&self) -> Vec { - self.call_stack - .iter() - .map(|program_counter| program_counter.to_usize()) - .chain(std::iter::once(self.program_counter)) - .collect() + self.call_stack.iter().copied().chain(std::iter::once(self.program_counter)).collect() } /// Process a single opcode and modify the program counter. @@ -182,13 +176,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let opcode = &self.bytecode[self.program_counter]; match opcode { Opcode::BinaryFieldOp { op, lhs, rhs, destination: result } => { - self.process_binary_field_op(*op, *lhs, *rhs, *result); - self.increment_program_counter() + if let Err(error) = self.process_binary_field_op(*op, *lhs, *rhs, *result) { + self.fail(error.to_string()) + } else { + self.increment_program_counter() + } } Opcode::BinaryIntOp { op, bit_size, lhs, rhs, destination: result } => { if let Err(error) = self.process_binary_int_op(*op, *bit_size, *lhs, *rhs, *result) { - self.fail(error) + self.fail(error.to_string()) } else { self.increment_program_counter() } @@ -204,26 +201,29 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // Check if condition is true // We use 0 to mean false and any other value to mean true let condition_value = self.memory.read(*condition); - if !condition_value.is_zero() { + if condition_value.try_into().expect("condition value is not a boolean") { return self.set_program_counter(*destination); } self.increment_program_counter() } Opcode::JumpIfNot { condition, location: destination } => { let condition_value = self.memory.read(*condition); - if condition_value.is_zero() { - return self.set_program_counter(*destination); + if condition_value.try_into().expect("condition value is not a boolean") { + return self.increment_program_counter(); } - self.increment_program_counter() + self.set_program_counter(*destination) } Opcode::CalldataCopy { destination_address, size, offset } => { - let values = &self.calldata[*offset..(*offset + size)]; - self.memory.write_slice(*destination_address, values); + let values: Vec<_> = self.calldata[*offset..(*offset + size)] + .iter() + .map(|value| MemoryValue::new_field(*value)) + .collect(); + self.memory.write_slice(*destination_address, &values); self.increment_program_counter() } Opcode::Return => { if let Some(return_location) = self.call_stack.pop() { - self.set_program_counter(return_location.to_usize() + 1) + self.set_program_counter(return_location + 1) } else { self.fail("return opcode hit, but callstack already empty".to_string()) } @@ -254,81 +254,14 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { return self.wait_for_foreign_call(function.clone(), resolved_inputs); } - let values = &self.foreign_call_results[self.foreign_call_counter].values; + let write_result = self.write_foreign_call_result( + destinations, + destination_value_types, + self.foreign_call_counter, + ); - let mut invalid_foreign_call_result = false; - for ((destination, value_type), output) in - destinations.iter().zip(destination_value_types).zip(values) - { - match (destination, value_type) { - (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { - match output { - ForeignCallParam::Single(value) => { - self.memory.write(*value_index, *value); - } - _ => unreachable!( - "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" - ), - } - } - ( - ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), - HeapValueType::Array { value_types, size: type_size }, - ) if size == type_size => { - if HeapValueType::all_simple(value_types) { - match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; - } - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") - } - } - } else { - unimplemented!("deflattening heap arrays from foreign calls"); - } - } - ( - ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), - HeapValueType::Vector { value_types }, - ) => { - if HeapValueType::all_simple(value_types) { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size address - self.memory.write(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") - } - } - } else { - unimplemented!("deflattening heap vectors from foreign calls"); - } - } - _ => { - unreachable!("Unexpected value type {value_type:?} for destination {destination:?}"); - } - } - } - - // These checks must come after resolving the foreign call outputs as `fail` uses a mutable reference - if destinations.len() != values.len() { - self.fail(format!("{} output values were provided as a foreign call result for {} destination slots", values.len(), destinations.len())); - } - if invalid_foreign_call_result { - self.fail("Function result size does not match brillig bytecode".to_owned()); + if let Err(e) = write_result { + return self.fail(e); } self.foreign_call_counter += 1; @@ -341,10 +274,10 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } Opcode::ConditionalMov { destination, source_a, source_b, condition } => { let condition_value = self.memory.read(*condition); - if condition_value.is_zero() { - self.memory.write(*destination, self.memory.read(*source_b)); - } else { + if condition_value.try_into().expect("condition value is not a boolean") { self.memory.write(*destination, self.memory.read(*source_a)); + } else { + self.memory.write(*destination, self.memory.read(*source_b)); } self.increment_program_counter() } @@ -369,11 +302,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } Opcode::Call { location } => { // Push a return location - self.call_stack.push(Value::from(self.program_counter)); + self.call_stack.push(self.program_counter); self.set_program_counter(*location) } - Opcode::Const { destination, value, bit_size: _ } => { - self.memory.write(*destination, *value); + Opcode::Const { destination, value, bit_size } => { + // Consts are not checked in runtime to fit in the bit size, since they can safely be checked statically. + self.memory.write(*destination, MemoryValue::new(*value, *bit_size)); self.increment_program_counter() } Opcode::BlackBox(black_box_op) => { @@ -413,15 +347,19 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { value_type: &HeapValueType, ) -> ForeignCallParam { match (input, value_type) { - (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { - self.memory.read(value_index).into() + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple(_)) => { + self.memory.read(value_index).value.into() } ( ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), HeapValueType::Array { value_types, size: type_size }, ) if *type_size == size => { let start = self.memory.read_ref(pointer_index); - self.read_slice_of_values_from_memory(start, size, value_types).into() + self.read_slice_of_values_from_memory(start, size, value_types) + .into_iter() + .map(|mem_value| mem_value.value) + .collect::>() + .into() } ( ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }), @@ -429,7 +367,11 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { ) => { let start = self.memory.read_ref(pointer_index); let size = self.memory.read(size_index).to_usize(); - self.read_slice_of_values_from_memory(start, size, value_types).into() + self.read_slice_of_values_from_memory(start, size, value_types) + .into_iter() + .map(|mem_value| mem_value.value) + .collect::>() + .into() } _ => { unreachable!("Unexpected value type {value_type:?} for input {input:?}"); @@ -444,7 +386,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { start: MemoryAddress, size: usize, value_types: &[HeapValueType], - ) -> Vec { + ) -> Vec { if HeapValueType::all_simple(value_types) { self.memory.read_slice(start, size).to_vec() } else { @@ -459,9 +401,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { .flat_map(|(i, value_type)| { let value_address: MemoryAddress = (start.to_usize() + i).into(); match value_type { - HeapValueType::Simple => { - let value = self.memory.read(value_address); - vec![value] + HeapValueType::Simple(_) => { + vec![self.memory.read(value_address)] } HeapValueType::Array { value_types, size } => { let array_address = self.memory.read_ref(value_address); @@ -486,6 +427,124 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } } + fn write_foreign_call_result( + &mut self, + destinations: &[ValueOrArray], + destination_value_types: &[HeapValueType], + foreign_call_index: usize, + ) -> Result<(), String> { + let values = &self.foreign_call_results[foreign_call_index].values; + + if destinations.len() != values.len() { + return Err(format!( + "{} output values were provided as a foreign call result for {} destination slots", + values.len(), + destinations.len() + )); + } + + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { + match (destination, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple(bit_size)) => { + match output { + ForeignCallParam::Single(value) => { + let memory_value = MemoryValue::new_checked(*value, *bit_size); + if let Some(memory_value) = memory_value { + self.memory.write(*value_index, memory_value); + } else { + return Err(format!( + "Foreign call result value {} does not fit in bit size {}", + value, + bit_size + )); + } + } + _ => return Err(format!( + "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}") + ), + } + } + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if size == type_size => { + if HeapValueType::all_simple(value_types) { + let bit_sizes_iterator = value_types.iter().map(|typ| match typ { + HeapValueType::Simple(bit_size) => *bit_size, + _ => unreachable!("Expected simple value type"), + }).cycle(); + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + return Err("Foreign call result array doesn't match expected size".to_string()); + } + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + let memory_values: Option> = values.iter().zip(bit_sizes_iterator).map( + |(value, bit_size)| MemoryValue::new_checked(*value, bit_size)).collect(); + if let Some(memory_values) = memory_values { + self.memory.write_slice(destination, &memory_values); + } else { + return Err(format!( + "Foreign call result values {:?} do not match expected bit sizes", + values, + )); + } + } + _ => { + return Err("Function result size does not match brillig bytecode size".to_string()); + } + } + } else { + unimplemented!("deflattening heap arrays from foreign calls"); + } + } + ( + ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { + if HeapValueType::all_simple(value_types) { + let bit_sizes_iterator = value_types.iter().map(|typ| match typ { + HeapValueType::Simple(bit_size) => *bit_size, + _ => unreachable!("Expected simple value type"), + }).cycle(); + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size address + self.memory.write(*size_index, values.len().into()); + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + let memory_values: Option> = values.iter().zip(bit_sizes_iterator).map(|(value, bit_size)| MemoryValue::new_checked(*value, bit_size)).collect(); + if let Some(memory_values) = memory_values { + self.memory.write_slice(destination, &memory_values); + }else{ + return Err(format!( + "Foreign call result values {:?} do not match expected bit sizes", + values, + )); + } + } + _ => { + return Err("Function result size does not match brillig bytecode size".to_string()); + } + } + } else { + unimplemented!("deflattening heap vectors from foreign calls"); + } + } + _ => { + return Err(format!("Unexpected value type {value_type:?} for destination {destination:?}")); + } + } + } + + Ok(()) + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( @@ -494,14 +553,15 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { lhs: MemoryAddress, rhs: MemoryAddress, result: MemoryAddress, - ) { + ) -> Result<(), BrilligArithmeticError> { let lhs_value = self.memory.read(lhs); let rhs_value = self.memory.read(rhs); - let result_value = - evaluate_binary_field_op(&op, lhs_value.to_field(), rhs_value.to_field()); + let result_value = evaluate_binary_field_op(&op, lhs_value, rhs_value)?; + + self.memory.write(result, result_value); - self.memory.write(result, result_value.into()); + Ok(()) } /// Process a binary operation. @@ -513,25 +573,23 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { lhs: MemoryAddress, rhs: MemoryAddress, result: MemoryAddress, - ) -> Result<(), String> { + ) -> Result<(), BrilligArithmeticError> { let lhs_value = self.memory.read(lhs); let rhs_value = self.memory.read(rhs); - // Convert to big integers - let lhs_big = BigUint::from_bytes_be(&lhs_value.to_field().to_be_bytes()); - let rhs_big = BigUint::from_bytes_be(&rhs_value.to_field().to_be_bytes()); - let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size)?; - // Convert back to field element - self.memory - .write(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into()); + let result_value = evaluate_binary_int_op(&op, lhs_value, rhs_value, bit_size)?; + self.memory.write(result, result_value); Ok(()) } /// Casts a value to a different bit size. - fn cast(&self, bit_size: u32, value: Value) -> Value { - let lhs_big = BigUint::from_bytes_be(&value.to_field().to_be_bytes()); + fn cast(&self, bit_size: u32, source_value: MemoryValue) -> MemoryValue { + let lhs_big = BigUint::from_bytes_be(&source_value.value.to_be_bytes()); let mask = BigUint::from(2_u32).pow(bit_size) - 1_u32; - FieldElement::from_be_bytes_reduce(&(lhs_big & mask).to_bytes_be()).into() + MemoryValue { + value: FieldElement::from_be_bytes_reduce(&(lhs_big & mask).to_bytes_be()), + bit_size, + } } } @@ -592,7 +650,7 @@ mod tests { #[test] fn add_single_step_smoke() { - let calldata = vec![Value::from(27u128)]; + let calldata = vec![FieldElement::from(27u128)]; // Add opcode to add the value in address `0` and `1` // and place the output in address `2` @@ -618,7 +676,7 @@ mod tests { let VM { memory, .. } = vm; let output_value = memory.read(MemoryAddress::from(0)); - assert_eq!(output_value, Value::from(27u128)); + assert_eq!(output_value.value, FieldElement::from(27u128)); } #[test] @@ -627,12 +685,12 @@ mod tests { let mut opcodes = vec![]; let lhs = { - calldata.push(Value::from(2u128)); + calldata.push(2u128.into()); MemoryAddress::from(calldata.len() - 1) }; let rhs = { - calldata.push(Value::from(2u128)); + calldata.push(2u128.into()); MemoryAddress::from(calldata.len() - 1) }; @@ -643,11 +701,10 @@ mod tests { size: 2, offset: 0, }); - let equal_cmp_opcode = - Opcode::BinaryIntOp { op: BinaryIntOp::Equals, bit_size: 1, lhs, rhs, destination }; - opcodes.push(equal_cmp_opcode); + + opcodes.push(Opcode::BinaryFieldOp { destination, op: BinaryFieldOp::Equals, lhs, rhs }); opcodes.push(Opcode::Jump { location: 3 }); - opcodes.push(Opcode::JumpIf { condition: MemoryAddress::from(2), location: 4 }); + opcodes.push(Opcode::JumpIf { condition: destination, location: 4 }); let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); @@ -657,8 +714,8 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_cmp_value, Value::from(true)); + let output_cmp_value = vm.memory.read(destination); + assert_eq!(output_cmp_value.value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -669,7 +726,7 @@ mod tests { #[test] fn jmpifnot_opcode() { - let calldata = vec![Value::from(1u128), Value::from(2u128)]; + let calldata = vec![1u128.into(), 2u128.into()]; let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -717,7 +774,7 @@ mod tests { assert_eq!(status, VMStatus::InProgress); let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_cmp_value, Value::from(false)); + assert_eq!(output_cmp_value.value, false.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); @@ -734,12 +791,12 @@ mod tests { // The address at index `2` should have not changed as we jumped over the add opcode let VM { memory, .. } = vm; let output_value = memory.read(MemoryAddress::from(2)); - assert_eq!(output_value, Value::from(false)); + assert_eq!(output_value.value, false.into()); } #[test] fn cast_opcode() { - let calldata = vec![Value::from((2_u128.pow(32)) - 1)]; + let calldata = vec![((2_u128.pow(32)) - 1).into()]; let opcodes = &[ Opcode::CalldataCopy { @@ -768,12 +825,12 @@ mod tests { let VM { memory, .. } = vm; let casted_value = memory.read(MemoryAddress::from(1)); - assert_eq!(casted_value, Value::from(2_u128.pow(8) - 1)); + assert_eq!(casted_value.value, (2_u128.pow(8) - 1).into()); } #[test] fn mov_opcode() { - let calldata = vec![Value::from(1u128), Value::from(2u128), Value::from(3u128)]; + let calldata = vec![(1u128).into(), (2u128).into(), (3u128).into()]; let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -796,16 +853,15 @@ mod tests { let VM { memory, .. } = vm; let destination_value = memory.read(MemoryAddress::from(2)); - assert_eq!(destination_value, Value::from(1u128)); + assert_eq!(destination_value.value, (1u128).into()); let source_value = memory.read(MemoryAddress::from(0)); - assert_eq!(source_value, Value::from(1u128)); + assert_eq!(source_value.value, (1u128).into()); } #[test] fn cmov_opcode() { - let calldata = - vec![Value::from(0u128), Value::from(1u128), Value::from(2u128), Value::from(3u128)]; + let calldata = vec![(0u128).into(), (1u128).into(), (2u128).into(), (3u128).into()]; let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -813,8 +869,22 @@ mod tests { offset: 0, }; + let cast_zero = Opcode::Cast { + destination: MemoryAddress::from(0), + source: MemoryAddress::from(0), + bit_size: 1, + }; + + let cast_one = Opcode::Cast { + destination: MemoryAddress::from(1), + source: MemoryAddress::from(1), + bit_size: 1, + }; + let opcodes = &[ calldata_copy, + cast_zero, + cast_one, Opcode::ConditionalMov { destination: MemoryAddress(4), // Sets 3_u128 to memory address 4 source_a: MemoryAddress(2), @@ -836,28 +906,30 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + let status = vm.process_opcode(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); let VM { memory, .. } = vm; let destination_value = memory.read(MemoryAddress::from(4)); - assert_eq!(destination_value, Value::from(3_u128)); + assert_eq!(destination_value.value, (3_u128).into()); let source_value = memory.read(MemoryAddress::from(5)); - assert_eq!(source_value, Value::from(2_u128)); + assert_eq!(source_value.value, (2_u128).into()); } #[test] fn cmp_binary_ops() { let bit_size = 32; - let calldata = vec![ - Value::from(2u128), - Value::from(2u128), - Value::from(0u128), - Value::from(5u128), - Value::from(6u128), - ]; + let calldata = + vec![(2u128).into(), (2u128).into(), (0u128).into(), (5u128).into(), (6u128).into()]; + let calldata_size = calldata.len(); let calldata_copy = Opcode::CalldataCopy { destination_address: MemoryAddress::from(0), @@ -865,6 +937,14 @@ mod tests { offset: 0, }; + let cast_opcodes: Vec<_> = (0..calldata_size) + .map(|index| Opcode::Cast { + destination: MemoryAddress::from(index), + source: MemoryAddress::from(index), + bit_size, + }) + .collect(); + let equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::Equals, @@ -897,42 +977,47 @@ mod tests { destination: MemoryAddress::from(2), }; - let opcodes = [ - calldata_copy, - equal_opcode, - not_equal_opcode, - less_than_opcode, - less_than_equal_opcode, - ]; + let opcodes: Vec<_> = std::iter::once(calldata_copy) + .chain(cast_opcodes) + .chain([equal_opcode, not_equal_opcode, less_than_opcode, less_than_equal_opcode]) + .collect(); let mut vm = VM::new(calldata, &opcodes, vec![], &DummyBlackBoxSolver); + // Calldata copy let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); + for _ in 0..calldata_size { + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + } + + // Equals let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let output_eq_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_eq_value, Value::from(true)); + assert_eq!(output_eq_value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let output_neq_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(output_neq_value, Value::from(false)); + assert_eq!(output_neq_value, false.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); let lt_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(lt_value, Value::from(true)); + assert_eq!(lt_value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); let lte_value = vm.memory.read(MemoryAddress::from(2)); - assert_eq!(lte_value, Value::from(true)); + assert_eq!(lte_value, true.into()); } + #[test] fn store_opcode() { /// Brillig code for the following: @@ -942,8 +1027,8 @@ mod tests { /// memory[i] = i as Value; /// i += 1; /// } - fn brillig_write_memory(item_count: usize) -> Vec { - let bit_size = 32; + fn brillig_write_memory(item_count: usize) -> Vec { + let bit_size = 64; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_tmp = MemoryAddress::from(2); @@ -951,21 +1036,17 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, // len = memory.len() (approximation) - Opcode::Const { - destination: r_len, - value: Value::from(item_count as u128), - bit_size: 32, - }, + Opcode::Const { destination: r_len, value: item_count.into(), bit_size }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size }, ]; let loop_body = [ // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1000,17 +1081,12 @@ mod tests { } let memory = brillig_write_memory(5); - let expected = vec![ - Value::from(0u128), - Value::from(1u128), - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - ]; + let expected = + vec![(0u64).into(), (1u64).into(), (2u64).into(), (3u64).into(), (4u64).into()]; assert_eq!(memory, expected); let memory = brillig_write_memory(1024); - let expected: Vec = (0..1024).map(|i| Value::from(i as u128)).collect(); + let expected: Vec<_> = (0..1024).map(|i: u64| i.into()).collect(); assert_eq!(memory, expected); } @@ -1024,8 +1100,8 @@ mod tests { /// sum += memory[i]; /// i += 1; /// } - fn brillig_sum_memory(memory: Vec) -> Value { - let bit_size = 32; + fn brillig_sum_memory(memory: Vec) -> FieldElement { + let bit_size = 64; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_sum = MemoryAddress::from(2); @@ -1034,17 +1110,17 @@ mod tests { let start = [ // sum = 0 - Opcode::Const { destination: r_sum, value: 0u128.into(), bit_size: 32 }, - // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, - // len = array.len() (approximation) Opcode::Const { - destination: r_len, - value: Value::from(memory.len() as u128), - bit_size: 32, + destination: r_sum, + value: 0u128.into(), + bit_size: FieldElement::max_num_bits(), }, + // i = 0 + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, + // len = array.len() (approximation) + Opcode::Const { destination: r_len, value: memory.len().into(), bit_size }, // pointer = array_ptr - Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size }, Opcode::CalldataCopy { destination_address: MemoryAddress(5), size: memory.len(), @@ -1055,15 +1131,14 @@ mod tests { // tmp = *i Opcode::Load { destination: r_tmp, source_pointer: r_pointer }, // sum = sum + tmp - Opcode::BinaryIntOp { + Opcode::BinaryFieldOp { destination: r_sum, lhs: r_sum, - op: BinaryIntOp::Add, + op: BinaryFieldOp::Add, rhs: r_tmp, - bit_size, }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1094,20 +1169,20 @@ mod tests { let opcodes = [&start[..], &loop_body[..]].concat(); let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.memory.read(r_sum) + vm.memory.read(r_sum).value } assert_eq!( brillig_sum_memory(vec![ - Value::from(1u128), - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - Value::from(5u128), + (1u128).into(), + (2u128).into(), + (3u128).into(), + (4u128).into(), + (5u128).into(), ]), - Value::from(15u128) + (15u128).into() ); - assert_eq!(brillig_sum_memory(vec![Value::from(1u128); 1024]), Value::from(1024u128)); + assert_eq!(brillig_sum_memory(vec![(1u128).into(); 1024]), (1024u128).into()); } #[test] @@ -1121,8 +1196,8 @@ mod tests { /// recursive_write(memory, i + 1, len); /// } /// Note we represent a 100% in-stack optimized form in brillig - fn brillig_recursive_write_memory(size: usize) -> Vec { - let bit_size = 32; + fn brillig_recursive_write_memory(size: usize) -> Vec { + let bit_size = 64; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_tmp = MemoryAddress::from(2); @@ -1130,15 +1205,15 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, // len = size - Opcode::Const { destination: r_len, value: size.into(), bit_size: 32 }, + Opcode::Const { destination: r_len, value: size.into(), bit_size }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size }, // call recursive_fn Opcode::Call { - location: 5, // Call after 'start' - }, + location: 5, // Call after 'start' + }, // end program by jumping to end Opcode::Jump { location: 100 }, ]; @@ -1160,7 +1235,7 @@ mod tests { // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1188,23 +1263,18 @@ mod tests { } let memory = brillig_recursive_write_memory(5); - let expected = vec![ - Value::from(0u128), - Value::from(1u128), - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - ]; + let expected = + vec![(0u64).into(), (1u64).into(), (2u64).into(), (3u64).into(), (4u64).into()]; assert_eq!(memory, expected); let memory = brillig_recursive_write_memory(1024); - let expected: Vec = (0..1024).map(|i| Value::from(i as u128)).collect(); + let expected: Vec<_> = (0..1024).map(|i: u64| i.into()).collect(); assert_eq!(memory, expected); } /// Helper to execute brillig code fn brillig_execute_and_get_vm( - calldata: Vec, + calldata: Vec, opcodes: &[Opcode], ) -> VM<'_, DummyBlackBoxSolver> { let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver); @@ -1230,14 +1300,14 @@ mod tests { let double_program = vec![ // Load input address with value 5 - Opcode::Const { destination: r_input, value: Value::from(5u128), bit_size: 32 }, + Opcode::Const { destination: r_input, value: (5u128).into(), bit_size: 32 }, // Call foreign function "double" with the input address Opcode::ForeignCall { function: "double".into(), destinations: vec![ValueOrArray::MemoryAddress(r_result)], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::Simple(32)], inputs: vec![ValueOrArray::MemoryAddress(r_input)], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::Simple(32)], }, ]; @@ -1248,13 +1318,13 @@ mod tests { vm.status, VMStatus::ForeignCallWait { function: "double".into(), - inputs: vec![Value::from(5u128).into()] + inputs: vec![FieldElement::from(5usize).into()] } ); // Push result we're waiting for vm.resolve_foreign_call( - Value::from(10u128).into(), // Result of doubling 5u128 + FieldElement::from(10u128).into(), // Result of doubling 5u128 ); // Resume VM @@ -1265,7 +1335,7 @@ mod tests { // Check result address let result_value = vm.memory.read(r_result); - assert_eq!(result_value, Value::from(10u128)); + assert_eq!(result_value, (10u32).into()); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); @@ -1277,12 +1347,11 @@ mod tests { let r_output = MemoryAddress::from(1); // Define a simple 2x2 matrix in memory - let initial_matrix = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; + let initial_matrix = vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; // Transpose of the matrix (but arbitrary for this test, the 'correct value') - let expected_result = - vec![Value::from(1u128), Value::from(3u128), Value::from(2u128), Value::from(4u128)]; + let expected_result: Vec = + vec![(1u128).into(), (3u128).into(), (2u128).into(), (4u128).into()]; let invert_program = vec![ Opcode::CalldataCopy { @@ -1291,9 +1360,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 32 }, + Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 64 }, // output = 0 - Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 32 }, + Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 64 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1303,14 +1372,14 @@ mod tests { })], destination_value_types: vec![HeapValueType::Array { size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], input_value_types: vec![HeapValueType::Array { - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], size: initial_matrix.len(), }], }, @@ -1338,7 +1407,10 @@ mod tests { // Check result in memory let result_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); - assert_eq!(result_values, expected_result); + assert_eq!( + result_values.into_iter().map(|mem_value| mem_value.value).collect::>(), + expected_result + ); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); @@ -1354,10 +1426,10 @@ mod tests { let r_output_size = MemoryAddress::from(3); // Our first string to use the identity function with - let input_string = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; + let input_string: Vec = + vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; // Double the string (concatenate it with itself) - let mut output_string: Vec = + let mut output_string: Vec<_> = input_string.iter().cloned().chain(input_string.clone()).collect(); // Reverse the concatenated string output_string.reverse(); @@ -1370,24 +1442,24 @@ mod tests { offset: 0, }, // input_pointer = 4 - Opcode::Const { destination: r_input_pointer, value: Value::from(4u128), bit_size: 32 }, + Opcode::Const { destination: r_input_pointer, value: (4u128).into(), bit_size: 64 }, // input_size = input_string.len() (constant here) Opcode::Const { destination: r_input_size, - value: Value::from(input_string.len()), - bit_size: 32, + value: input_string.len().into(), + bit_size: 64, }, // output_pointer = 4 + input_size Opcode::Const { destination: r_output_pointer, - value: Value::from(4 + input_string.len()), - bit_size: 32, + value: (4 + input_string.len()).into(), + bit_size: 64, }, // output_size = input_size * 2 Opcode::Const { destination: r_output_size, - value: Value::from(input_string.len() * 2), - bit_size: 32, + value: (input_string.len() * 2).into(), + bit_size: 64, }, // output_pointer[0..output_size] = string_double(input_pointer[0...input_size]) Opcode::ForeignCall { @@ -1397,14 +1469,14 @@ mod tests { size: r_output_size, })], destination_value_types: vec![HeapValueType::Vector { - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ValueOrArray::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, })], input_value_types: vec![HeapValueType::Vector { - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], }, ]; @@ -1432,10 +1504,12 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm + let result_values: Vec<_> = vm .memory .read_slice(MemoryAddress(4 + input_string.len()), output_string.len()) - .to_vec(); + .iter() + .map(|mem_val| mem_val.value) + .collect(); assert_eq!(result_values, output_string); // Ensure the foreign call counter has been incremented @@ -1448,12 +1522,11 @@ mod tests { let r_output = MemoryAddress::from(1); // Define a simple 2x2 matrix in memory - let initial_matrix = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; + let initial_matrix = vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; // Transpose of the matrix (but arbitrary for this test, the 'correct value') - let expected_result = - vec![Value::from(1u128), Value::from(3u128), Value::from(2u128), Value::from(4u128)]; + let expected_result: Vec = + vec![(1u128).into(), (3u128).into(), (2u128).into(), (4u128).into()]; let invert_program = vec![ Opcode::CalldataCopy { @@ -1462,9 +1535,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: Value::from(2u128), bit_size: 32 }, + Opcode::Const { destination: r_input, value: (2u128).into(), bit_size: 64 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(6u128), bit_size: 32 }, + Opcode::Const { destination: r_output, value: (6u128).into(), bit_size: 64 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1474,7 +1547,7 @@ mod tests { })], destination_value_types: vec![HeapValueType::Array { size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, @@ -1482,7 +1555,7 @@ mod tests { })], input_value_types: vec![HeapValueType::Array { size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], }, ]; @@ -1508,11 +1581,13 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check initial memory still in place - let initial_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); + let initial_values: Vec<_> = + vm.memory.read_slice(MemoryAddress(2), 4).iter().map(|mem_val| mem_val.value).collect(); assert_eq!(initial_values, initial_matrix); // Check result in memory - let result_values = vm.memory.read_slice(MemoryAddress(6), 4).to_vec(); + let result_values: Vec<_> = + vm.memory.read_slice(MemoryAddress(6), 4).iter().map(|mem_val| mem_val.value).collect(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented @@ -1526,23 +1601,13 @@ mod tests { let r_output = MemoryAddress::from(2); // Define a simple 2x2 matrix in memory - let matrix_a = - vec![Value::from(1u128), Value::from(2u128), Value::from(3u128), Value::from(4u128)]; - - let matrix_b = vec![ - Value::from(10u128), - Value::from(11u128), - Value::from(12u128), - Value::from(13u128), - ]; + let matrix_a = vec![(1u128).into(), (2u128).into(), (3u128).into(), (4u128).into()]; + + let matrix_b = vec![(10u128).into(), (11u128).into(), (12u128).into(), (13u128).into()]; // Transpose of the matrix (but arbitrary for this test, the 'correct value') - let expected_result = vec![ - Value::from(34u128), - Value::from(37u128), - Value::from(78u128), - Value::from(85u128), - ]; + let expected_result: Vec = + vec![(34u128).into(), (37u128).into(), (78u128).into(), (85u128).into()]; let matrix_mul_program = vec![ Opcode::CalldataCopy { @@ -1551,11 +1616,11 @@ mod tests { offset: 0, }, // input = 3 - Opcode::Const { destination: r_input_a, value: Value::from(3u128), bit_size: 32 }, + Opcode::Const { destination: r_input_a, value: (3u128).into(), bit_size: 64 }, // input = 7 - Opcode::Const { destination: r_input_b, value: Value::from(7u128), bit_size: 32 }, + Opcode::Const { destination: r_input_b, value: (7u128).into(), bit_size: 64 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(0u128), bit_size: 32 }, + Opcode::Const { destination: r_output, value: (0u128).into(), bit_size: 64 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1565,7 +1630,7 @@ mod tests { })], destination_value_types: vec![HeapValueType::Array { size: matrix_a.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }], inputs: vec![ ValueOrArray::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len() }), @@ -1574,11 +1639,11 @@ mod tests { input_value_types: vec![ HeapValueType::Array { size: matrix_a.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }, HeapValueType::Array { size: matrix_b.len(), - value_types: vec![HeapValueType::Simple], + value_types: vec![HeapValueType::field()], }, ], }, @@ -1606,7 +1671,8 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm.memory.read_slice(MemoryAddress(0), 4).to_vec(); + let result_values: Vec<_> = + vm.memory.read_slice(MemoryAddress(0), 4).iter().map(|mem_val| mem_val.value).collect(); assert_eq!(result_values, expected_result); // Ensure the foreign call counter has been incremented @@ -1617,47 +1683,54 @@ mod tests { fn foreign_call_opcode_nested_arrays_and_slices_input() { // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] - let v2 = vec![Value::from(2u128), Value::from(3u128)]; - let a4 = vec![Value::from(4u128)]; - let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; - let a9 = vec![Value::from(9u128)]; + let v2: Vec = vec![ + MemoryValue::from(FieldElement::from(2u128)), + MemoryValue::from(FieldElement::from(3u128)), + ]; + let a4: Vec = vec![FieldElement::from(4u128).into()]; + let v6: Vec = vec![ + MemoryValue::from(FieldElement::from(6u128)), + MemoryValue::from(FieldElement::from(7u128)), + MemoryValue::from(FieldElement::from(8u128)), + ]; + let a9: Vec = vec![FieldElement::from(9u128).into()]; // construct memory by declaring all inner arrays/vectors first - let v2_ptr = 0u128; + let v2_ptr: usize = 0usize; let mut memory = v2.clone(); let v2_start = memory.len(); - memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(v2_ptr), v2.len().into(), MemoryValue::from(1_usize)]); let a4_ptr = memory.len(); memory.extend(a4.clone()); let a4_start = memory.len(); - memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(a4_ptr), MemoryValue::from(1_usize)]); let v6_ptr = memory.len(); memory.extend(v6.clone()); let v6_start = memory.len(); - memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(v6_ptr), v6.len().into(), MemoryValue::from(1_usize)]); let a9_ptr = memory.len(); memory.extend(a9.clone()); let a9_start = memory.len(); - memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + memory.extend(vec![MemoryValue::from(a9_ptr), MemoryValue::from(1_usize)]); // finally we add the contents of the outer array let outer_ptr = memory.len(); let outer_array = vec![ - Value::from(1u128), - Value::from(v2.len()), - Value::from(v2_start), - Value::from(a4_start), - Value::from(5u128), - Value::from(v6.len()), - Value::from(v6_start), - Value::from(a9_start), + MemoryValue::from(FieldElement::from(1u128)), + MemoryValue::from(v2.len()), + MemoryValue::from(v2_start), + MemoryValue::from(a4_start), + MemoryValue::from(FieldElement::from(5u128)), + MemoryValue::from(v6.len()), + MemoryValue::from(v6_start), + MemoryValue::from(a9_start), ]; memory.extend(outer_array.clone()); - let input_array_value_types = vec![ - HeapValueType::Simple, - HeapValueType::Simple, // size of following vector - HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, - HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + let input_array_value_types: Vec = vec![ + HeapValueType::field(), + HeapValueType::Simple(64), // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::field()] }, + HeapValueType::Array { value_types: vec![HeapValueType::field()], size: 1 }, ]; // memory address of the end of the above data structures @@ -1666,19 +1739,24 @@ mod tests { let r_input = MemoryAddress::from(r_ptr); let r_output = MemoryAddress::from(r_ptr + 1); - let program = vec![ - Opcode::CalldataCopy { - destination_address: MemoryAddress::from(0), - size: memory.len(), - offset: 0, - }, + let program: Vec<_> = std::iter::once(Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: memory.len(), + offset: 0, + }) + .chain(memory.iter().enumerate().map(|(index, mem_value)| Opcode::Cast { + destination: MemoryAddress(index), + source: MemoryAddress(index), + bit_size: mem_value.bit_size, + })) + .chain(vec![ // input = 0 - Opcode::Const { destination: r_input, value: Value::from(outer_ptr), bit_size: 32 }, + Opcode::Const { destination: r_input, value: (outer_ptr).into(), bit_size: 64 }, // some_function(input) Opcode::ForeignCall { function: "flat_sum".into(), destinations: vec![ValueOrArray::MemoryAddress(r_output)], - destination_value_types: vec![HeapValueType::Simple], + destination_value_types: vec![HeapValueType::field()], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: outer_array.len(), @@ -1688,9 +1766,13 @@ mod tests { size: outer_array.len(), }], }, - ]; + ]) + .collect(); - let mut vm = brillig_execute_and_get_vm(memory, &program); + let mut vm = brillig_execute_and_get_vm( + memory.into_iter().map(|mem_value| mem_value.value).collect(), + &program, + ); // Check that VM is waiting assert_eq!( @@ -1698,23 +1780,23 @@ mod tests { VMStatus::ForeignCallWait { function: "flat_sum".into(), inputs: vec![ForeignCallParam::Array(vec![ - Value::from(1u128), - Value::from(2u128), // size of following vector - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - Value::from(5u128), - Value::from(3u128), // size of following vector - Value::from(6u128), - Value::from(7u128), - Value::from(8u128), - Value::from(9u128), + (1u128).into(), + (2u128).into(), // size of following vector + (2u128).into(), + (3u128).into(), + (4u128).into(), + (5u128).into(), + (3u128).into(), // size of following vector + (6u128).into(), + (7u128).into(), + (8u128).into(), + (9u128).into(), ])], } ); // Push result we're waiting for - vm.resolve_foreign_call(Value::from(45u128).into()); + vm.resolve_foreign_call(FieldElement::from(45u128).into()); // Resume VM brillig_execute(&mut vm); @@ -1724,7 +1806,7 @@ mod tests { // Check result let result_value = vm.memory.read(r_output); - assert_eq!(result_value, Value::from(45u128)); + assert_eq!(result_value, MemoryValue::from(FieldElement::from(45u128))); // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); diff --git a/acvm-repo/brillig_vm/src/memory.rs b/acvm-repo/brillig_vm/src/memory.rs index d1c81447170..ae442ac2628 100644 --- a/acvm-repo/brillig_vm/src/memory.rs +++ b/acvm-repo/brillig_vm/src/memory.rs @@ -1,30 +1,188 @@ use acir::{brillig::MemoryAddress, FieldElement}; -use crate::Value; +pub const MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MemoryValue { + pub value: FieldElement, + pub bit_size: u32, +} + +#[derive(Debug, thiserror::Error)] +pub enum MemoryTypeError { + #[error("Bit size for value {value_bit_size} does not match the expected bit size {expected_bit_size}")] + MismatchedBitSize { value_bit_size: u32, expected_bit_size: u32 }, +} + +impl MemoryValue { + pub fn new(value: FieldElement, bit_size: u32) -> Self { + MemoryValue { value, bit_size } + } + + pub fn new_checked(value: FieldElement, bit_size: u32) -> Option { + if value.num_bits() > bit_size { + return None; + } + + Some(MemoryValue::new(value, bit_size)) + } + + pub fn new_field(value: FieldElement) -> Self { + MemoryValue { value, bit_size: FieldElement::max_num_bits() } + } + + pub fn to_usize(&self) -> usize { + assert!(self.bit_size == MEMORY_ADDRESSING_BIT_SIZE, "value is not typed as brillig usize"); + usize::try_from(self.value.try_to_u64().expect("value does not fit into u64")) + .expect("value does not fit into usize") + } + + pub fn expect_bit_size(&self, expected_bit_size: u32) -> Result<(), MemoryTypeError> { + if self.bit_size != expected_bit_size { + return Err(MemoryTypeError::MismatchedBitSize { + value_bit_size: self.bit_size, + expected_bit_size, + }); + } + Ok(()) + } +} + +impl std::fmt::Display for MemoryValue { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let typ = match self.bit_size { + 0 => "null".to_string(), + 1 => "bool".to_string(), + _ if self.bit_size == FieldElement::max_num_bits() => "field".to_string(), + _ => format!("u{}", self.bit_size), + }; + f.write_str(format!("{}: {}", self.value, typ).as_str()) + } +} + +impl Default for MemoryValue { + fn default() -> Self { + MemoryValue::new(FieldElement::zero(), 0) + } +} + +impl From for MemoryValue { + fn from(field: FieldElement) -> Self { + MemoryValue::new_field(field) + } +} + +impl From for MemoryValue { + fn from(value: usize) -> Self { + MemoryValue::new(value.into(), MEMORY_ADDRESSING_BIT_SIZE) + } +} + +impl From for MemoryValue { + fn from(value: u64) -> Self { + MemoryValue::new((value as u128).into(), 64) + } +} + +impl From for MemoryValue { + fn from(value: u32) -> Self { + MemoryValue::new((value as u128).into(), 32) + } +} + +impl From for MemoryValue { + fn from(value: u8) -> Self { + MemoryValue::new((value as u128).into(), 8) + } +} + +impl From for MemoryValue { + fn from(value: bool) -> Self { + MemoryValue::new(value.into(), 1) + } +} + +impl TryFrom for FieldElement { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(FieldElement::max_num_bits())?; + Ok(memory_value.value) + } +} + +impl TryFrom for u64 { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(64)?; + Ok(memory_value.value.try_to_u64().expect("value typed as u64 does not fit into u64")) + } +} + +impl TryFrom for u32 { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(32)?; + let as_u64 = + memory_value.value.try_to_u64().expect("value typed as u32 does not fit into u64"); + Ok(u32::try_from(as_u64).expect("value typed as u32 does not fit into u32")) + } +} + +impl TryFrom for u8 { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(8)?; + + Ok(u8::try_from( + memory_value.value.try_to_u64().expect("value typed as u8 does not fit into u64"), + ) + .expect("value typed as u8 does not fit into u8")) + } +} + +impl TryFrom for bool { + type Error = MemoryTypeError; + + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_bit_size(1)?; + + if memory_value.value == FieldElement::zero() { + Ok(false) + } else if memory_value.value == FieldElement::one() { + Ok(true) + } else { + unreachable!("value typed as bool is greater than one") + } + } +} #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct Memory { // Memory is a vector of values. // We grow the memory when values past the end are set, extending with 0s. - inner: Vec, + inner: Vec, } impl Memory { /// Gets the value at pointer - pub fn read(&self, ptr: MemoryAddress) -> Value { - self.inner.get(ptr.to_usize()).copied().unwrap_or(0_u128.into()) + pub fn read(&self, ptr: MemoryAddress) -> MemoryValue { + self.inner.get(ptr.to_usize()).copied().unwrap_or_default() } pub fn read_ref(&self, ptr: MemoryAddress) -> MemoryAddress { MemoryAddress(self.read(ptr).to_usize()) } - pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[Value] { + pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[MemoryValue] { &self.inner[addr.to_usize()..(addr.to_usize() + len)] } /// Sets the value at pointer `ptr` to `value` - pub fn write(&mut self, ptr: MemoryAddress, value: Value) { + pub fn write(&mut self, ptr: MemoryAddress, value: MemoryValue) { self.resize_to_fit(ptr.to_usize() + 1); self.inner[ptr.to_usize()] = value; } @@ -33,17 +191,17 @@ impl Memory { // Calculate new memory size let new_size = std::cmp::max(self.inner.len(), size); // Expand memory to new size with default values if needed - self.inner.resize(new_size, Value::from(FieldElement::zero())); + self.inner.resize(new_size, MemoryValue::default()); } /// Sets the values after pointer `ptr` to `values` - pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[Value]) { + pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[MemoryValue]) { self.resize_to_fit(ptr.to_usize() + values.len()); self.inner[ptr.to_usize()..(ptr.to_usize() + values.len())].copy_from_slice(values); } /// Returns the values of the memory - pub fn values(&self) -> &[Value] { + pub fn values(&self) -> &[MemoryValue] { &self.inner } } diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index 0fe450e6cb1..3ee6f9c21b9 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -4,7 +4,7 @@ mod utils; use transforms::{ compute_note_hash_and_nullifier::inject_compute_note_hash_and_nullifier, events::{generate_selector_impl, transform_events}, - functions::{transform_function, transform_unconstrained, transform_vm_function}, + functions::{transform_function, transform_unconstrained}, note_interface::generate_note_interface_impl, storage::{ assign_storage_slots, check_for_storage_definition, check_for_storage_implementation, @@ -138,9 +138,15 @@ fn transform_module(module: &mut SortedModule) -> Result } // Apply transformations to the function based on collected attributes - if is_private || is_public { + if is_private || is_public || is_public_vm { transform_function( - if is_private { "Private" } else { "Public" }, + if is_private { + "Private" + } else if is_public_vm { + "Avm" + } else { + "Public" + }, func, storage_defined, is_initializer, @@ -148,9 +154,6 @@ fn transform_module(module: &mut SortedModule) -> Result is_internal, )?; has_transformed_module = true; - } else if is_public_vm { - transform_vm_function(func, storage_defined)?; - has_transformed_module = true; } else if storage_defined && func.def.is_unconstrained { transform_unconstrained(func); has_transformed_module = true; diff --git a/aztec_macros/src/transforms/events.rs b/aztec_macros/src/transforms/events.rs index b02709efacb..e7e39ed29ba 100644 --- a/aztec_macros/src/transforms/events.rs +++ b/aztec_macros/src/transforms/events.rs @@ -47,10 +47,14 @@ pub fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { let mut from_signature_path = selector_path.clone(); from_signature_path.segments.push(ident("from_signature")); - let selector_fun_body = BlockExpression(vec![make_statement(StatementKind::Expression(call( - variable_path(from_signature_path), - vec![expression(ExpressionKind::Literal(Literal::Str(SIGNATURE_PLACEHOLDER.to_string())))], - )))]); + let selector_fun_body = BlockExpression { + statements: vec![make_statement(StatementKind::Expression(call( + variable_path(from_signature_path), + vec![expression(ExpressionKind::Literal(Literal::Str( + SIGNATURE_PLACEHOLDER.to_string(), + )))], + )))], + }; // Define `FunctionSelector` return type let return_type = diff --git a/aztec_macros/src/transforms/functions.rs b/aztec_macros/src/transforms/functions.rs index c719651e10e..9844abc30fe 100644 --- a/aztec_macros/src/transforms/functions.rs +++ b/aztec_macros/src/transforms/functions.rs @@ -35,93 +35,84 @@ pub fn transform_function( let context_name = format!("{}Context", ty); let inputs_name = format!("{}ContextInputs", ty); let return_type_name = format!("{}CircuitPublicInputs", ty); + let is_avm = ty == "Avm"; // Add check that msg sender equals this address and flag function as internal if is_internal { let is_internal_check = create_internal_check(func.name()); - func.def.body.0.insert(0, is_internal_check); + func.def.body.statements.insert(0, is_internal_check); } // Add initialization check if insert_init_check { let init_check = create_init_check(); - func.def.body.0.insert(0, init_check); + func.def.body.statements.insert(0, init_check); } // Add assertion for initialization arguments and sender if is_initializer { - func.def.body.0.insert(0, create_assert_initializer()); + func.def.body.statements.insert(0, create_assert_initializer()); } // Add access to the storage struct if storage_defined { let storage_def = abstract_storage(&ty.to_lowercase(), false); - func.def.body.0.insert(0, storage_def); + func.def.body.statements.insert(0, storage_def); } // Insert the context creation as the first action - let create_context = create_context(&context_name, &func.def.parameters)?; - func.def.body.0.splice(0..0, (create_context).iter().cloned()); + let create_context = if !is_avm { + create_context(&context_name, &func.def.parameters)? + } else { + create_context_avm()? + }; + func.def.body.statements.splice(0..0, (create_context).iter().cloned()); // Add the inputs to the params let input = create_inputs(&inputs_name); func.def.parameters.insert(0, input); // Abstract return types such that they get added to the kernel's return_values - if let Some(return_values) = abstract_return_values(func) { - // In case we are pushing return values to the context, we remove the statement that originated it - // This avoids running duplicate code, since blocks like if/else can be value returning statements - func.def.body.0.pop(); - // Add the new return statement - func.def.body.0.push(return_values); + if !is_avm { + if let Some(return_values) = abstract_return_values(func) { + // In case we are pushing return values to the context, we remove the statement that originated it + // This avoids running duplicate code, since blocks like if/else can be value returning statements + func.def.body.statements.pop(); + // Add the new return statement + func.def.body.statements.push(return_values); + } } // Before returning mark the contract as initialized if is_initializer { let mark_initialized = create_mark_as_initialized(); - func.def.body.0.push(mark_initialized); + func.def.body.statements.push(mark_initialized); } // Push the finish method call to the end of the function - let finish_def = create_context_finish(); - func.def.body.0.push(finish_def); + if !is_avm { + let finish_def = create_context_finish(); + func.def.body.statements.push(finish_def); + } - let return_type = create_return_type(&return_type_name); - func.def.return_type = return_type; - func.def.return_visibility = Visibility::Public; + // The AVM doesn't need a return type yet. + if !is_avm { + let return_type = create_return_type(&return_type_name); + func.def.return_type = return_type; + func.def.return_visibility = Visibility::Public; + } // Distinct return types are only required for private functions // Public functions should have unconstrained auto-inferred match ty { "Private" => func.def.return_distinctness = Distinctness::Distinct, - "Public" => func.def.is_unconstrained = true, + "Public" | "Avm" => func.def.is_unconstrained = true, _ => (), } Ok(()) } -/// Transform a function to work with AVM bytecode -pub fn transform_vm_function( - func: &mut NoirFunction, - storage_defined: bool, -) -> Result<(), AztecMacroError> { - // Create access to storage - if storage_defined { - let storage = abstract_storage("public_vm", true); - func.def.body.0.insert(0, storage); - } - - // Push Avm context creation to the beginning of the function - let create_context = create_avm_context()?; - func.def.body.0.insert(0, create_context); - - // We want the function to be seen as a public function - func.def.is_unconstrained = true; - - Ok(()) -} - /// Transform Unconstrained /// /// Inserts the following code at the beginning of an unconstrained function @@ -131,7 +122,7 @@ pub fn transform_vm_function( /// /// This will allow developers to access their contract' storage struct in unconstrained functions pub fn transform_unconstrained(func: &mut NoirFunction) { - func.def.body.0.insert(0, abstract_storage("Unconstrained", true)); + func.def.body.statements.insert(0, abstract_storage("Unconstrained", true)); } /// Helper function that returns what the private context would look like in the ast @@ -232,62 +223,62 @@ fn create_assert_initializer() -> Statement { /// ```noir /// #[aztec(private)] /// fn foo(structInput: SomeStruct, arrayInput: [u8; 10], fieldInput: Field) -> Field { -/// // Create the hasher object -/// let mut hasher = Hasher::new(); +/// // Create the bounded vec object +/// let mut serialized_args = BoundedVec::new(); /// /// // struct inputs call serialize on them to add an array of fields -/// hasher.add_multiple(structInput.serialize()); +/// serialized_args.extend_from_array(structInput.serialize()); /// -/// // Array inputs are iterated over and each element is added to the hasher (as a field) +/// // Array inputs are iterated over and each element is added to the bounded vec (as a field) /// for i in 0..arrayInput.len() { -/// hasher.add(arrayInput[i] as Field); +/// serialized_args.push(arrayInput[i] as Field); /// } -/// // Field inputs are added to the hasher -/// hasher.add({ident}); +/// // Field inputs are added to the bounded vec +/// serialized_args.push({ident}); /// /// // Create the context /// // The inputs (injected by this `create_inputs`) and completed hash object are passed to the context -/// let mut context = PrivateContext::new(inputs, hasher.hash()); +/// let mut context = PrivateContext::new(inputs, hash_args(serialized_args)); /// } /// ``` fn create_context(ty: &str, params: &[Param]) -> Result, AztecMacroError> { let mut injected_expressions: Vec = vec![]; - // `let mut hasher = Hasher::new();` - let let_hasher = mutable_assignment( - "hasher", // Assigned to + // `let mut serialized_args = BoundedVec::new();` + let let_serialized_args = mutable_assignment( + "serialized_args", // Assigned to call( - variable_path(chained_dep!("aztec", "hasher", "Hasher", "new")), // Path - vec![], // args + variable_path(chained_dep!("std", "collections", "bounded_vec", "BoundedVec", "new")), // Path + vec![], // args ), ); - // Completes: `let mut hasher = Hasher::new();` - injected_expressions.push(let_hasher); + // Completes: `let mut serialized_args = BoundedVec::new();` + injected_expressions.push(let_serialized_args); - // Iterate over each of the function parameters, adding to them to the hasher + // Iterate over each of the function parameters, adding to them to the bounded vec for Param { pattern, typ, span, .. } in params { match pattern { Pattern::Identifier(identifier) => { // Match the type to determine the padding to do let unresolved_type = &typ.typ; let expression = match unresolved_type { - // `hasher.add_multiple({ident}.serialize())` - UnresolvedTypeData::Named(..) => add_struct_to_hasher(identifier), + // `serialized_args.extend_from_array({ident}.serialize())` + UnresolvedTypeData::Named(..) => add_struct_to_serialized_args(identifier), UnresolvedTypeData::Array(_, arr_type) => { - add_array_to_hasher(identifier, arr_type) + add_array_to_serialized_args(identifier, arr_type) } - // `hasher.add({ident})` - UnresolvedTypeData::FieldElement => add_field_to_hasher(identifier), - // Add the integer to the hasher, casted to a field - // `hasher.add({ident} as Field)` + // `serialized_args.push({ident})` + UnresolvedTypeData::FieldElement => add_field_to_serialized_args(identifier), + // Add the integer to the serialized args, casted to a field + // `serialized_args.push({ident} as Field)` UnresolvedTypeData::Integer(..) | UnresolvedTypeData::Bool => { - add_cast_to_hasher(identifier) + add_cast_to_serialized_args(identifier) } UnresolvedTypeData::String(..) => { let (var_bytes, id) = str_to_bytes(identifier); injected_expressions.push(var_bytes); - add_array_to_hasher( + add_array_to_serialized_args( &id, &UnresolvedType { typ: UnresolvedTypeData::Integer( @@ -313,11 +304,10 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac // Create the inputs to the context let inputs_expression = variable("inputs"); - // `hasher.hash()` - let hash_call = method_call( - variable("hasher"), // variable - "hash", // method name - vec![], // args + // `hash_args(serialized_args)` + let hash_call = call( + variable_path(chained_dep!("aztec", "hash", "hash_args")), // variable + vec![variable("serialized_args")], // args ); let path_snippet = ty.to_case(Case::Snake); // e.g. private_context @@ -336,33 +326,36 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac Ok(injected_expressions) } -/// Creates an mutable avm context +/// Creates the private context object to be accessed within the function, the parameters need to be extracted to be +/// appended into the args hash object. /// +/// The replaced code: /// ```noir -/// /// Before /// #[aztec(public-vm)] -/// fn foo() -> Field { -/// let mut context = aztec::context::AVMContext::new(); -/// let timestamp = context.timestamp(); -/// // ... -/// } -/// -/// /// After -/// #[aztec(private)] -/// fn foo() -> Field { -/// let mut timestamp = context.timestamp(); -/// // ... +/// fn foo(inputs: AvmContextInputs, ...) -> Field { +/// let mut context = AvmContext::new(inputs); /// } -fn create_avm_context() -> Result { +/// ``` +fn create_context_avm() -> Result, AztecMacroError> { + let mut injected_expressions: Vec = vec![]; + + // Create the inputs to the context + let ty = "AvmContext"; + let inputs_expression = variable("inputs"); + let path_snippet = ty.to_case(Case::Snake); // e.g. private_context + + // let mut context = {ty}::new(inputs, hash); let let_context = mutable_assignment( "context", // Assigned to call( - variable_path(chained_dep!("aztec", "context", "AVMContext", "new")), // Path - vec![], // args + variable_path(chained_dep!("aztec", "context", &path_snippet, ty, "new")), // Path + vec![inputs_expression], // args ), ); + injected_expressions.push(let_context); - Ok(let_context) + // Return all expressions that will be injected by the hasher + Ok(injected_expressions) } /// Abstract Return Type @@ -393,7 +386,7 @@ fn create_avm_context() -> Result { /// Any primitive type that can be cast will be casted to a field and pushed to the context. fn abstract_return_values(func: &NoirFunction) -> Option { let current_return_type = func.return_type().typ; - let last_statement = func.def.body.0.last()?; + let last_statement = func.def.body.statements.last()?; // TODO: (length, type) => We can limit the size of the array returned to be limited by kernel size // Doesn't need done until we have settled on a kernel size @@ -598,11 +591,11 @@ fn create_context_finish() -> Statement { } // -// Methods to create hasher inputs +// Methods to create hash_args inputs // -fn add_struct_to_hasher(identifier: &Ident) -> Statement { - // If this is a struct, we call serialize and add the array to the hasher +fn add_struct_to_serialized_args(identifier: &Ident) -> Statement { + // If this is a struct, we call serialize and add the array to the serialized args let serialized_call = method_call( variable_path(path(identifier.clone())), // variable "serialize", // method name @@ -610,9 +603,9 @@ fn add_struct_to_hasher(identifier: &Ident) -> Statement { ); make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add_multiple", // method name - vec![serialized_call], // args + variable("serialized_args"), // variable + "extend_from_array", // method name + vec![serialized_call], // args ))) } @@ -632,7 +625,7 @@ fn str_to_bytes(identifier: &Ident) -> (Statement, Ident) { } fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the hasher + // If this is an array of primitive types (integers / fields) we can add them each to the serialized args // casted to a field let span = var.span; @@ -644,8 +637,10 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { ); // What will be looped over - // - `hasher.add({ident}[i] as Field)` - let for_loop_block = expression(ExpressionKind::Block(BlockExpression(loop_body))); + + // - `serialized_args.push({ident}[i] as Field)` + let for_loop_block = + expression(ExpressionKind::Block(BlockExpression { statements: loop_body })); // `for i in 0..{ident}.len()` make_statement(StatementKind::For(ForLoopStatement { @@ -662,66 +657,66 @@ fn create_loop_over(var: Expression, loop_body: Vec) -> Statement { })) } -fn add_array_to_hasher(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { - // If this is an array of primitive types (integers / fields) we can add them each to the hasher +fn add_array_to_serialized_args(identifier: &Ident, arr_type: &UnresolvedType) -> Statement { + // If this is an array of primitive types (integers / fields) we can add them each to the serialized_args // casted to a field // Wrap in the semi thing - does that mean ended with semi colon? - // `hasher.add({ident}[i] as Field)` + // `serialized_args.push({ident}[i] as Field)` let arr_index = index_array(identifier.clone(), "i"); - let (add_expression, hasher_method_name) = match arr_type.typ { + let (add_expression, vec_method_name) = match arr_type.typ { UnresolvedTypeData::Named(..) => { - let hasher_method_name = "add_multiple".to_owned(); + let vec_method_name = "extend_from_array".to_owned(); let call = method_call( // All serialize on each element arr_index, // variable "serialize", // method name vec![], // args ); - (call, hasher_method_name) + (call, vec_method_name) } _ => { - let hasher_method_name = "add".to_owned(); + let vec_method_name = "push".to_owned(); let call = cast( arr_index, // lhs - `ident[i]` UnresolvedTypeData::FieldElement, // cast to - `as Field` ); - (call, hasher_method_name) + (call, vec_method_name) } }; let block_statement = make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - &hasher_method_name, // method name + variable("serialized_args"), // variable + &vec_method_name, // method name vec![add_expression], ))); create_loop_over(variable_ident(identifier.clone()), vec![block_statement]) } -fn add_field_to_hasher(identifier: &Ident) -> Statement { - // `hasher.add({ident})` +fn add_field_to_serialized_args(identifier: &Ident) -> Statement { + // `serialized_args.push({ident})` let ident = variable_path(path(identifier.clone())); make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add", // method name - vec![ident], // args + variable("serialized_args"), // variable + "push", // method name + vec![ident], // args ))) } -fn add_cast_to_hasher(identifier: &Ident) -> Statement { - // `hasher.add({ident} as Field)` +fn add_cast_to_serialized_args(identifier: &Ident) -> Statement { + // `serialized_args.push({ident} as Field)` // `{ident} as Field` let cast_operation = cast( variable_path(path(identifier.clone())), // lhs UnresolvedTypeData::FieldElement, // rhs ); - // `hasher.add({ident} as Field)` + // `serialized_args.push({ident} as Field)` make_statement(StatementKind::Semi(method_call( - variable("hasher"), // variable - "add", // method name - vec![cast_operation], // args + variable("serialized_args"), // variable + "push", // method name + vec![cast_operation], // args ))) } diff --git a/aztec_macros/src/transforms/storage.rs b/aztec_macros/src/transforms/storage.rs index 40a094f78e3..10f44d01bb4 100644 --- a/aztec_macros/src/transforms/storage.rs +++ b/aztec_macros/src/transforms/storage.rs @@ -150,7 +150,7 @@ pub fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), true, )), )], - &BlockExpression(vec![storage_constructor_statement]), + &BlockExpression { statements: vec![storage_constructor_statement] }, &[], &return_type(chained_path!("Self")), )); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 36e5c99a2ca..874be06b86c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,7 +1,7 @@ use acvm::acir::{brillig::BlackBoxOp, BlackBoxFunc}; use crate::brillig::brillig_ir::{ - brillig_variable::{BrilligVariable, BrilligVector}, + brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, BrilligContext, }; @@ -56,17 +56,23 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::Keccak256 => { if let ( - [message, BrilligVariable::SingleAddr(array_size)], + [message, BrilligVariable::SingleAddr(message_size)], [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { let mut message_vector = convert_array_or_vector(brillig_context, message, bb_func); - message_vector.size = array_size.address; + let message_size_as_usize = + SingleAddrVariable::new_usize(brillig_context.allocate_register()); + // Message_size is not usize + brillig_context.cast_instruction(message_size_as_usize, *message_size); + + message_vector.size = message_size_as_usize.address; brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { message: message_vector.to_heap_vector(), output: result_array.to_heap_array(), }); + brillig_context.deallocate_single_addr(message_size_as_usize); } else { unreachable!("ICE: Keccak256 expects message, message size and result array") } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 94e81d02053..cf2501ab1c0 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -514,7 +514,7 @@ impl<'block> BrilligBlock<'block> { .extract_vector(); // Update the user-facing slice length - self.brillig_context.mov_instruction(target_len.address, limb_count.address); + self.brillig_context.cast_instruction(target_len, limb_count); self.brillig_context.codegen_to_radix( source, @@ -522,6 +522,7 @@ impl<'block> BrilligBlock<'block> { radix, limb_count, matches!(endianness, Endian::Big), + 8, ); } Value::Intrinsic(Intrinsic::ToBits(endianness)) => { @@ -554,7 +555,7 @@ impl<'block> BrilligBlock<'block> { let radix = self.brillig_context.make_constant_instruction(2_usize.into(), 32); // Update the user-facing slice length - self.brillig_context.mov_instruction(target_len.address, limb_count.address); + self.brillig_context.cast_instruction(target_len, limb_count); self.brillig_context.codegen_to_radix( source, @@ -562,6 +563,7 @@ impl<'block> BrilligBlock<'block> { radix, limb_count, matches!(endianness, Endian::Big), + 1, ); self.brillig_context.deallocate_single_addr(radix); @@ -654,7 +656,7 @@ impl<'block> BrilligBlock<'block> { // Create a field constant with the max let max = BigUint::from(2_u128).pow(*max_bit_size) - BigUint::from(1_u128); let right = self.brillig_context.make_constant_instruction( - FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), + FieldElement::from_be_bytes_reduce(&max.to_bytes_be()), FieldElement::max_num_bits(), ); @@ -1584,7 +1586,7 @@ impl<'block> BrilligBlock<'block> { self.variables.allocate_constant(self.brillig_context, value_id, dfg); self.brillig_context - .const_instruction(new_variable.extract_single_addr(), (*constant).into()); + .const_instruction(new_variable.extract_single_addr(), *constant); new_variable } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs index dc9900daee3..892e82d771a 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs @@ -2,7 +2,10 @@ use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use crate::{ brillig::brillig_ir::{ - brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, + brillig_variable::{ + get_bit_size_from_ssa_type, BrilligArray, BrilligVariable, BrilligVector, + SingleAddrVariable, + }, BrilligContext, }, ssa::ir::{ @@ -13,7 +16,7 @@ use crate::{ }, }; -use super::brillig_fn::{get_bit_size_from_ssa_type, FunctionContext}; +use super::brillig_fn::FunctionContext; #[derive(Debug, Default)] pub(crate) struct BlockVariables { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 26b21e918ff..15a2a531e78 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,5 +1,5 @@ use acvm::{ - acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value}, + acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode}, FieldElement, }; @@ -16,18 +16,32 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // We store the result in this register too. let input = MemoryAddress::from(0); let one_const = MemoryAddress::from(1); + let zero_const = MemoryAddress::from(2); + let input_is_zero = MemoryAddress::from(3); // Location of the stop opcode - let stop_location = 3; + let stop_location = 6; GeneratedBrillig { byte_code: vec![ BrilligOpcode::CalldataCopy { destination_address: input, size: 1, offset: 0 }, + // Put value zero in register (2) + BrilligOpcode::Const { + destination: zero_const, + value: FieldElement::from(0_usize), + bit_size: FieldElement::max_num_bits(), + }, + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + lhs: input, + rhs: zero_const, + destination: input_is_zero, + }, // If the input is zero, then we jump to the stop opcode - BrilligOpcode::JumpIfNot { condition: input, location: stop_location }, + BrilligOpcode::JumpIf { condition: input_is_zero, location: stop_location }, // Put value one in register (1) BrilligOpcode::Const { destination: one_const, - value: Value::from(1_usize), + value: FieldElement::from(1_usize), bit_size: FieldElement::max_num_bits(), }, // Divide 1 by the input, and set the result of the division into register (0) @@ -53,9 +67,12 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { /// (a/b, a-a/b*b) /// } /// ``` -pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { +pub(crate) fn directive_quotient(mut bit_size: u32) -> GeneratedBrillig { // `a` is (0) (i.e register index 0) // `b` is (1) + if bit_size > FieldElement::max_num_bits() { + bit_size = FieldElement::max_num_bits(); + } GeneratedBrillig { byte_code: vec![ BrilligOpcode::CalldataCopy { @@ -63,6 +80,16 @@ pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { size: 2, offset: 0, }, + BrilligOpcode::Cast { + destination: MemoryAddress(0), + source: MemoryAddress(0), + bit_size, + }, + BrilligOpcode::Cast { + destination: MemoryAddress(1), + source: MemoryAddress(1), + bit_size, + }, //q = a/b is set into register (2) BrilligOpcode::BinaryIntOp { op: BinaryIntOp::Div, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index 42765d10ce2..92027026ce8 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -3,8 +3,8 @@ use iter_extended::vecmap; use crate::{ brillig::brillig_ir::{ artifact::{BrilligParameter, Label}, - brillig_variable::BrilligVariable, - BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + brillig_variable::{get_bit_size_from_ssa_type, BrilligVariable}, + BrilligContext, }, ssa::ir::{ basic_block::BasicBlockId, @@ -112,15 +112,3 @@ impl FunctionContext { .collect() } } - -pub(crate) fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { - match typ { - Type::Numeric(num_type) => num_type.bit_size(), - Type::Reference(_) => BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - // NB. function references are converted to a constant when - // translating from SSA to Brillig (to allow for debugger - // instrumentation to work properly) - Type::Function => 32, - _ => unreachable!("ICE bit size not on a non numeric type"), - } -} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 98dd17ce080..e42b2787f73 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -354,7 +354,7 @@ impl<'block> BrilligBlock<'block> { mod tests { use std::vec; - use acvm::acir::brillig::Value; + use acvm::FieldElement; use crate::brillig::brillig_gen::brillig_block::BrilligBlock; use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; @@ -400,9 +400,9 @@ mod tests { fn test_slice_push_operation() { fn test_case_push( push_back: bool, - array: Vec, - item_to_push: Value, - expected_return: Vec, + array: Vec, + item_to_push: FieldElement, + expected_return: Vec, ) { let arguments = vec![ BrilligParameter::Array( @@ -462,44 +462,65 @@ mod tests { create_and_run_vm(array.into_iter().chain(vec![item_to_push]).collect(), &bytecode); assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_push( true, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], + FieldElement::from(27_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(27_usize), + ], + ); + test_case_push( + true, + vec![], + FieldElement::from(27_usize), + vec![FieldElement::from(27_usize)], ); - test_case_push(true, vec![], Value::from(27_usize), vec![Value::from(27_usize)]); test_case_push( false, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), vec![ - Value::from(27_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + vec![ + FieldElement::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], ); - test_case_push(false, vec![], Value::from(27_usize), vec![Value::from(27_usize)]); + test_case_push( + false, + vec![], + FieldElement::from(27_usize), + vec![FieldElement::from(27_usize)], + ); } #[test] fn test_slice_pop_back_operation() { fn test_case_pop( pop_back: bool, - array: Vec, - expected_return_array: Vec, - expected_return_item: Value, + array: Vec, + expected_return_array: Vec, + expected_return_item: FieldElement, ) { let arguments = vec![BrilligParameter::Array( vec![BrilligParameter::SingleAddr(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], @@ -566,33 +587,44 @@ mod tests { assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_pop( true, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![Value::from(1_usize), Value::from(2_usize)], - Value::from(3_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + vec![FieldElement::from(1_usize), FieldElement::from(2_usize)], + FieldElement::from(3_usize), ); - test_case_pop(true, vec![Value::from(1_usize)], vec![], Value::from(1_usize)); + test_case_pop(true, vec![FieldElement::from(1_usize)], vec![], FieldElement::from(1_usize)); test_case_pop( false, - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - vec![Value::from(2_usize), Value::from(3_usize)], - Value::from(1_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + vec![FieldElement::from(2_usize), FieldElement::from(3_usize)], + FieldElement::from(1_usize), ); } #[test] fn test_slice_insert_operation() { fn test_case_insert( - array: Vec, - item: Value, - index: Value, - expected_return: Vec, + array: Vec, + item: FieldElement, + index: FieldElement, + expected_return: Vec, ) { let arguments = vec![ BrilligParameter::Array( @@ -651,71 +683,90 @@ mod tests { assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(1_usize), vec![ - Value::from(1_usize), - Value::from(27_usize), - Value::from(2_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(1_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(27_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], ); test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(0_usize), vec![ - Value::from(27_usize), - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(0_usize), + vec![ + FieldElement::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), ], ); test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(2_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(27_usize), - Value::from(3_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(2_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(27_usize), + FieldElement::from(3_usize), ], ); test_case_insert( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(27_usize), - Value::from(3_usize), vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(27_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(27_usize), + FieldElement::from(3_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(27_usize), ], ); test_case_insert( vec![], - Value::from(27_usize), - Value::from(0_usize), - vec![Value::from(27_usize)], + FieldElement::from(27_usize), + FieldElement::from(0_usize), + vec![FieldElement::from(27_usize)], ); } #[test] fn test_slice_remove_operation() { fn test_case_remove( - array: Vec, - index: Value, - expected_array: Vec, - expected_removed_item: Value, + array: Vec, + index: FieldElement, + expected_array: Vec, + expected_removed_item: FieldElement, ) { let arguments = vec![ BrilligParameter::Array( @@ -784,36 +835,51 @@ mod tests { assert_eq!(return_data_size, expected_return.len()); assert_eq!( - vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())], + vm.get_memory()[return_data_offset..(return_data_offset + expected_return.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), expected_return ); } test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(0_usize), - vec![Value::from(2_usize), Value::from(3_usize)], - Value::from(1_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(0_usize), + vec![FieldElement::from(2_usize), FieldElement::from(3_usize)], + FieldElement::from(1_usize), ); test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(1_usize), - vec![Value::from(1_usize), Value::from(3_usize)], - Value::from(2_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(1_usize), + vec![FieldElement::from(1_usize), FieldElement::from(3_usize)], + FieldElement::from(2_usize), ); test_case_remove( - vec![Value::from(1_usize), Value::from(2_usize), Value::from(3_usize)], - Value::from(2_usize), - vec![Value::from(1_usize), Value::from(2_usize)], - Value::from(3_usize), + vec![ + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + ], + FieldElement::from(2_usize), + vec![FieldElement::from(1_usize), FieldElement::from(2_usize)], + FieldElement::from(3_usize), ); test_case_remove( - vec![Value::from(1_usize)], - Value::from(0_usize), + vec![FieldElement::from(1_usize)], + FieldElement::from(0_usize), vec![], - Value::from(1_usize), + FieldElement::from(1_usize), ); } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 9138f57083a..e5c731be679 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -122,7 +122,7 @@ pub(crate) mod tests { use std::vec; use acvm::acir::brillig::{ - ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, ValueOrArray, + ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, ValueOrArray, }; use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; @@ -205,7 +205,7 @@ pub(crate) mod tests { } pub(crate) fn create_and_run_vm( - calldata: Vec, + calldata: Vec, bytecode: &[BrilligOpcode], ) -> (VM<'_, DummyBlackBoxSolver>, usize, usize) { let mut vm = VM::new(calldata, bytecode, vec![], &DummyBlackBoxSolver); @@ -234,20 +234,20 @@ pub(crate) mod tests { let mut context = BrilligContext::new(true); let r_stack = ReservedRegisters::free_memory_pointer(); // Start stack pointer at 0 - context.usize_const_instruction(r_stack, Value::from(ReservedRegisters::len() + 3)); + context.usize_const_instruction(r_stack, FieldElement::from(ReservedRegisters::len() + 3)); let r_input_size = MemoryAddress::from(ReservedRegisters::len()); let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); - context.usize_const_instruction(r_input_size, Value::from(12_usize)); + context.usize_const_instruction(r_input_size, FieldElement::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); context.foreign_call_instruction( "make_number_sequence".into(), &[ValueOrArray::MemoryAddress(r_input_size)], - &[HeapValueType::Simple], + &[HeapValueType::Simple(32)], &[ValueOrArray::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], - &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple(32)] }], ); // push stack frame by r_returned_size context.memory_op_instruction(r_stack, r_output_size, r_stack, BrilligBinaryOp::Add); @@ -266,8 +266,9 @@ pub(crate) mod tests { context.stop_instruction(); - let bytecode = context.artifact().finish().byte_code; - let number_sequence: Vec = (0_usize..12_usize).map(Value::from).collect(); + let bytecode: Vec = context.artifact().finish().byte_code; + let number_sequence: Vec = + (0_usize..12_usize).map(FieldElement::from).collect(); let mut vm = VM::new( vec![], &bytecode, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index b415421dd92..bbfdbb69f7c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -125,7 +125,9 @@ impl BrilligVariable { pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { match typ { - Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Numeric(_) | Type::Reference(_) | Type::Function => { + HeapValueType::Simple(get_bit_size_from_ssa_type(typ)) + } Type::Array(elem_type, size) => HeapValueType::Array { value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), size: typ.element_size() * size, @@ -135,3 +137,14 @@ pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { }, } } + +pub(crate) fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { + match typ { + Type::Reference(_) => BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + // NB. function references are converted to a constant when + // translating from SSA to Brillig (to allow for debugger + // instrumentation to work properly) + Type::Function => 32, + typ => typ.bit_size(), + } +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs index 248a304d820..4ef279bd532 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs @@ -1,4 +1,4 @@ -use acvm::acir::brillig::{MemoryAddress, Value}; +use acvm::{acir::brillig::MemoryAddress, FieldElement}; use super::{instructions::BrilligBinaryOp, BrilligContext}; @@ -21,7 +21,7 @@ impl BrilligContext { op: BrilligBinaryOp, constant: usize, ) { - let const_register = self.make_usize_constant_instruction(Value::from(constant)); + let const_register = self.make_usize_constant_instruction(FieldElement::from(constant)); self.memory_op_instruction(operand, const_register.address, destination, op); // Mark as no longer used for this purpose, frees for reuse self.deallocate_single_addr(const_register); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index be262d9dee7..ab756217bcd 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -39,6 +39,7 @@ impl BrilligContext { radix: SingleAddrVariable, limb_count: SingleAddrVariable, big_endian: bool, + limb_bit_size: u32, ) { assert!(source_field.bit_size == FieldElement::max_num_bits()); assert!(radix.bit_size == 32); @@ -55,19 +56,23 @@ impl BrilligContext { SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); self.mov_instruction(shifted_field.address, source_field.address); - let modulus_field = + let limb_field = SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + let limb_casted = SingleAddrVariable::new(self.allocate_register(), limb_bit_size); + self.codegen_loop(target_vector.size, |ctx, iterator_register| { // Compute the modulus ctx.binary_instruction( shifted_field, radix_as_field, - modulus_field, + limb_field, BrilligBinaryOp::Modulo, ); + // Cast it + ctx.cast_instruction(limb_casted, limb_field); // Write it - ctx.codegen_array_set(target_vector.pointer, iterator_register, modulus_field.address); + ctx.codegen_array_set(target_vector.pointer, iterator_register, limb_casted.address); // Integer div the field ctx.binary_instruction( shifted_field, @@ -79,7 +84,8 @@ impl BrilligContext { // Deallocate our temporary registers self.deallocate_single_addr(shifted_field); - self.deallocate_single_addr(modulus_field); + self.deallocate_single_addr(limb_field); + self.deallocate_single_addr(limb_casted); self.deallocate_single_addr(radix_as_field); if big_endian { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 5611905697c..4ca1144b6a4 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -2,7 +2,10 @@ use super::BrilligBinaryOp; use crate::brillig::brillig_ir::ReservedRegisters; -use acvm::acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, Value, ValueOrArray}; +use acvm::{ + acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, ValueOrArray}, + FieldElement, +}; /// Trait for converting values into debug-friendly strings. trait DebugToString { @@ -66,9 +69,9 @@ impl DebugToString for BrilligBinaryOp { } } -impl DebugToString for Value { +impl DebugToString for FieldElement { fn debug_to_string(&self) -> String { - self.to_usize().to_string() + self.to_string() } } @@ -167,7 +170,7 @@ impl DebugShow { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: Value) { + pub(crate) fn const_instruction(&self, result: MemoryAddress, constant: FieldElement) { debug_println!(self.enable_debug_trace, " CONST {} = {}", result, constant); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 14c4ada8606..1d823ded718 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -453,7 +453,8 @@ impl BrilligContext { #[cfg(test)] mod tests { - use acvm::brillig_vm::brillig::Value; + + use acvm::FieldElement; use crate::brillig::brillig_ir::{ artifact::BrilligParameter, @@ -464,12 +465,12 @@ mod tests { #[test] fn entry_point_with_nested_array_parameter() { let calldata = vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(4_usize), + FieldElement::from(5_usize), + FieldElement::from(6_usize), ]; let arguments = vec![BrilligParameter::Array( vec![ @@ -496,18 +497,18 @@ mod tests { let (vm, return_data_offset, return_data_size) = create_and_run_vm(calldata.clone(), &bytecode); assert_eq!(return_data_size, 1, "Return data size is incorrect"); - assert_eq!(vm.get_memory()[return_data_offset], Value::from(1_usize)); + assert_eq!(vm.get_memory()[return_data_offset].value, FieldElement::from(1_usize)); } #[test] fn entry_point_with_nested_array_return() { let flattened_array = vec![ - Value::from(1_usize), - Value::from(2_usize), - Value::from(3_usize), - Value::from(4_usize), - Value::from(5_usize), - Value::from(6_usize), + FieldElement::from(1_usize), + FieldElement::from(2_usize), + FieldElement::from(3_usize), + FieldElement::from(4_usize), + FieldElement::from(5_usize), + FieldElement::from(6_usize), ]; let array_param = BrilligParameter::Array( vec![ @@ -536,7 +537,10 @@ mod tests { let memory = vm.get_memory(); assert_eq!( - memory[return_data_pointer..(return_data_pointer + flattened_array.len())], + memory[return_data_pointer..(return_data_pointer + flattened_array.len())] + .iter() + .map(|mem_val| mem_val.value) + .collect::>(), flattened_array ); assert_eq!(return_data_size, flattened_array.len()); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index 99fb4c89f64..f305eb81b01 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -1,7 +1,7 @@ use acvm::{ acir::brillig::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, MemoryAddress, - Opcode as BrilligOpcode, Value, ValueOrArray, + Opcode as BrilligOpcode, ValueOrArray, }, FieldElement, }; @@ -43,7 +43,7 @@ impl BrilligContext { // Compile !x as ((-1) - x) let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(input.bit_size as i128)) - FieldElement::one(); - let max = self.make_constant(Value::from(u_max), input.bit_size); + let max = self.make_constant(u_max, input.bit_size); self.binary(max, input, result, BrilligBinaryOp::Sub); self.deallocate_single_addr(max); @@ -397,21 +397,23 @@ impl BrilligContext { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: Value) { + pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: FieldElement) { self.debug_show.const_instruction(result.address, constant); self.constant(result, constant); } - fn constant(&mut self, result: SingleAddrVariable, constant: Value) { - if result.bit_size > 128 && !constant.to_field().fits_in_u128() { - let high = Value::from(FieldElement::from_be_bytes_reduce( - constant - .to_field() - .to_be_bytes() - .get(0..16) - .expect("FieldElement::to_be_bytes() too short!"), - )); - let low = Value::from(constant.to_u128()); + fn constant(&mut self, result: SingleAddrVariable, constant: FieldElement) { + assert!( + result.bit_size >= constant.num_bits(), + "Constant {} does not fit in bit size {}", + constant, + result.bit_size + ); + if result.bit_size > 128 && !constant.fits_in_u128() { + let high = FieldElement::from_be_bytes_reduce( + constant.to_be_bytes().get(0..16).expect("FieldElement::to_be_bytes() too short!"), + ); + let low = FieldElement::from(constant.to_u128()); let high_register = SingleAddrVariable::new(self.allocate_register(), 254); let low_register = SingleAddrVariable::new(self.allocate_register(), 254); let intermediate_register = SingleAddrVariable::new(self.allocate_register(), 254); @@ -419,7 +421,7 @@ impl BrilligContext { self.constant(low_register, low); // I want to multiply high by 2^128, but I can't get that big constant in. // So I'll multiply by 2^64 twice. - self.constant(intermediate_register, Value::from(1_u128 << 64)); + self.constant(intermediate_register, FieldElement::from(1_u128 << 64)); self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); // Now we can add. @@ -437,14 +439,18 @@ impl BrilligContext { } } - pub(crate) fn usize_const_instruction(&mut self, result: MemoryAddress, constant: Value) { + pub(crate) fn usize_const_instruction( + &mut self, + result: MemoryAddress, + constant: FieldElement, + ) { self.const_instruction(SingleAddrVariable::new_usize(result), constant); } /// Returns a register which holds the value of a constant pub(crate) fn make_constant_instruction( &mut self, - constant: Value, + constant: FieldElement, bit_size: u32, ) -> SingleAddrVariable { let var = SingleAddrVariable::new(self.allocate_register(), bit_size); @@ -452,7 +458,7 @@ impl BrilligContext { var } - fn make_constant(&mut self, constant: Value, bit_size: u32) -> SingleAddrVariable { + fn make_constant(&mut self, constant: FieldElement, bit_size: u32) -> SingleAddrVariable { let var = SingleAddrVariable::new(self.allocate_register(), bit_size); self.constant(var, constant); var @@ -461,7 +467,7 @@ impl BrilligContext { /// Returns a register which holds the value of an usize constant pub(crate) fn make_usize_constant_instruction( &mut self, - constant: Value, + constant: FieldElement, ) -> SingleAddrVariable { let register = self.allocate_register(); self.usize_const_instruction(register, constant); diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index fb11bae556c..7e951cf4e00 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -11,7 +11,7 @@ use acvm::acir::circuit::brillig::{BrilligInputs, BrilligOutputs}; use acvm::acir::circuit::opcodes::{BlockId, MemOp}; use acvm::acir::circuit::Opcode; use acvm::blackbox_solver; -use acvm::brillig_vm::{brillig::Value, VMStatus, VM}; +use acvm::brillig_vm::{MemoryValue, VMStatus, VM}; use acvm::{ acir::{ brillig::Opcode as BrilligOpcode, @@ -1623,7 +1623,7 @@ impl AcirContext { let outputs_var = vecmap(outputs_types.iter(), |output| match output { AcirType::NumericType(_) => { let var = self.add_data(AcirVarData::Const( - memory.next().expect("Missing return data").to_field(), + memory.next().expect("Missing return data").value, )); AcirValue::Var(var, output.clone()) } @@ -1640,7 +1640,7 @@ impl AcirContext { &mut self, element_types: &[AcirType], size: usize, - memory_iter: &mut impl Iterator, + memory_iter: &mut impl Iterator, ) -> AcirValue { let mut array_values = im::Vector::new(); for _ in 0..size { @@ -1657,7 +1657,7 @@ impl AcirContext { AcirType::NumericType(_) => { let memory_value = memory_iter.next().expect("ICE: Unexpected end of memory"); - let var = self.add_data(AcirVarData::Const(memory_value.to_field())); + let var = self.add_data(AcirVarData::Const(memory_value.value)); array_values.push_back(AcirValue::Var(var, element_type.clone())); } } @@ -1839,21 +1839,21 @@ pub(crate) struct AcirVar(usize); /// Returns the finished state of the Brillig VM if execution can complete. /// /// Returns `None` if complete execution of the Brillig bytecode is not possible. -fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option> { +fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option> { // Set input values - let mut calldata: Vec = Vec::new(); + let mut calldata: Vec = Vec::new(); // Each input represents a constant or array of constants. // Iterate over each input and push it into registers and/or memory. for input in inputs { match input { BrilligInputs::Single(expr) => { - calldata.push(expr.to_const()?.into()); + calldata.push(expr.to_const()?); } BrilligInputs::Array(expr_arr) => { // Attempt to fetch all array input values for expr in expr_arr.iter() { - calldata.push(expr.to_const()?.into()); + calldata.push(expr.to_const()?); } } BrilligInputs::MemoryArray(_) => { diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 8b800e0db54..5b268de239d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -85,10 +85,11 @@ pub(super) fn simplify_call( } } Intrinsic::AsSlice => { - let slice = dfg.get_array_constant(arguments[0]); - if let Some((slice, element_type)) = slice { - let slice_length = dfg.make_constant(slice.len().into(), Type::length_type()); - let new_slice = dfg.make_array(slice, element_type); + let array = dfg.get_array_constant(arguments[0]); + if let Some((array, array_type)) = array { + let slice_length = dfg.make_constant(array.len().into(), Type::length_type()); + let inner_element_types = array_type.element_types(); + let new_slice = dfg.make_array(array, Type::Slice(inner_element_types)); SimplifyResult::SimplifiedToMultiple(vec![slice_length, new_slice]) } else { SimplifyResult::None diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index ea3f5393245..48036580d29 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -159,6 +159,13 @@ impl Type { Type::Reference(element) => element.contains_an_array(), } } + + pub(crate) fn element_types(self) -> Rc> { + match self { + Type::Array(element_types, _) | Type::Slice(element_types) => element_types, + other => panic!("element_types: Expected array or slice, found {other}"), + } + } } /// Composite Types are essentially flattened struct or tuple types. diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index bdfc04f0bbe..93e52542278 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -73,6 +73,7 @@ impl<'a> SliceCapacityTracker<'a> { Intrinsic::SlicePopFront => (Some(1), results.len() - 1), // The slice capacity of these intrinsics is not determined by the arguments of the function. Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => (None, 1), + Intrinsic::AsSlice => (Some(0), 1), _ => return, }; let result_slice = results[result_index]; @@ -90,6 +91,7 @@ impl<'a> SliceCapacityTracker<'a> { self.compute_slice_capacity(*arg, slice_sizes); } } + if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { let new_capacity = *contents_capacity + 1; slice_sizes.insert(result_slice, new_capacity); @@ -102,9 +104,6 @@ impl<'a> SliceCapacityTracker<'a> { .expect("ICE: Should have an argument index for slice intrinsics"); let slice_contents = arguments[argument_index]; - // We do not decrement the size on intrinsics that could remove values from a slice. - // This is because we could potentially go back to the smaller slice and not fill in dummies. - // This pass should be tracking the potential max that a slice ***could be*** if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { let new_capacity = *contents_capacity - 1; slice_sizes.insert(result_slice, new_capacity); @@ -121,6 +120,15 @@ impl<'a> SliceCapacityTracker<'a> { slice_sizes .insert(result_slice, FieldElement::max_num_bytes() as usize); } + Intrinsic::AsSlice => { + let argument_index = argument_index + .expect("ICE: Should have an argument index for AsSlice builtin"); + let array_size = self + .dfg + .try_get_array_length(arguments[argument_index]) + .expect("ICE: Should be have an array length for AsSlice input"); + slice_sizes.insert(result_slice, array_size); + } _ => {} } } diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index d646a6ca98a..0e5919bf7db 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -192,16 +192,18 @@ impl Expression { // with tuples without calling them. E.g. `if c { t } else { e }(a, b)` is interpreted // as a sequence of { if, tuple } rather than a function call. This behavior matches rust. let kind = if matches!(&lhs.kind, ExpressionKind::If(..)) { - ExpressionKind::Block(BlockExpression(vec![ - Statement { kind: StatementKind::Expression(lhs), span }, - Statement { - kind: StatementKind::Expression(Expression::new( - ExpressionKind::Tuple(arguments), + ExpressionKind::Block(BlockExpression { + statements: vec![ + Statement { kind: StatementKind::Expression(lhs), span }, + Statement { + kind: StatementKind::Expression(Expression::new( + ExpressionKind::Tuple(arguments), + span, + )), span, - )), - span, - }, - ])) + }, + ], + }) } else { ExpressionKind::Call(Box::new(CallExpression { func: Box::new(lhs), arguments })) }; @@ -452,19 +454,21 @@ pub struct IndexExpression { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct BlockExpression(pub Vec); +pub struct BlockExpression { + pub statements: Vec, +} impl BlockExpression { pub fn pop(&mut self) -> Option { - self.0.pop().map(|stmt| stmt.kind) + self.statements.pop().map(|stmt| stmt.kind) } pub fn len(&self) -> usize { - self.0.len() + self.statements.len() } pub fn is_empty(&self) -> bool { - self.0.is_empty() + self.statements.is_empty() } } @@ -542,7 +546,7 @@ impl Display for Literal { impl Display for BlockExpression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "{{")?; - for statement in &self.0 { + for statement in &self.statements { let statement = statement.kind.to_string(); for line in statement.lines() { writeln!(f, " {line}")?; diff --git a/compiler/noirc_frontend/src/ast/function.rs b/compiler/noirc_frontend/src/ast/function.rs index 46f0ac0fa0f..3e8b78c1312 100644 --- a/compiler/noirc_frontend/src/ast/function.rs +++ b/compiler/noirc_frontend/src/ast/function.rs @@ -83,7 +83,7 @@ impl NoirFunction { &mut self.def } pub fn number_of_statements(&self) -> usize { - self.def.body.0.len() + self.def.body.statements.len() } pub fn span(&self) -> Span { self.def.span diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index fb7f520ee71..b14ead8ad42 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -603,10 +603,12 @@ impl ForRange { }; let block_span = block.span; - let new_block = BlockExpression(vec![ - let_elem, - Statement { kind: StatementKind::Expression(block), span: block_span }, - ]); + let new_block = BlockExpression { + statements: vec![ + let_elem, + Statement { kind: StatementKind::Expression(block), span: block_span }, + ], + }; let new_block = Expression::new(ExpressionKind::Block(new_block), block_span); let for_loop = Statement { kind: StatementKind::For(ForLoopStatement { @@ -618,7 +620,9 @@ impl ForRange { span: for_loop_span, }; - let block = ExpressionKind::Block(BlockExpression(vec![let_array, for_loop])); + let block = ExpressionKind::Block(BlockExpression { + statements: vec![let_array, for_loop], + }); StatementKind::Expression(Expression::new(block, for_loop_span)) } } diff --git a/compiler/noirc_frontend/src/debug/mod.rs b/compiler/noirc_frontend/src/debug/mod.rs index 05916502d73..8e5c174d270 100644 --- a/compiler/noirc_frontend/src/debug/mod.rs +++ b/compiler/noirc_frontend/src/debug/mod.rs @@ -113,7 +113,7 @@ impl DebugInstrumenter { }) .collect(); - let func_body = &mut func.body.0; + let func_body = &mut func.body.statements; let mut statements = take(func_body); self.walk_scope(&mut statements, func.span); @@ -243,7 +243,9 @@ impl DebugInstrumenter { pattern: ast::Pattern::Tuple(vars_pattern, let_stmt.pattern.span()), r#type: ast::UnresolvedType::unspecified(), expression: ast::Expression { - kind: ast::ExpressionKind::Block(ast::BlockExpression(block_stmts)), + kind: ast::ExpressionKind::Block(ast::BlockExpression { + statements: block_stmts, + }), span: let_stmt.expression.span, }, }), @@ -330,11 +332,13 @@ impl DebugInstrumenter { kind: ast::StatementKind::Assign(ast::AssignStatement { lvalue: assign_stmt.lvalue.clone(), expression: ast::Expression { - kind: ast::ExpressionKind::Block(ast::BlockExpression(vec![ - ast::Statement { kind: let_kind, span: expression_span }, - new_assign_stmt, - ast::Statement { kind: ret_kind, span: expression_span }, - ])), + kind: ast::ExpressionKind::Block(ast::BlockExpression { + statements: vec![ + ast::Statement { kind: let_kind, span: expression_span }, + new_assign_stmt, + ast::Statement { kind: ret_kind, span: expression_span }, + ], + }), span: expression_span, }, }), @@ -344,7 +348,7 @@ impl DebugInstrumenter { fn walk_expr(&mut self, expr: &mut ast::Expression) { match &mut expr.kind { - ast::ExpressionKind::Block(ast::BlockExpression(ref mut statements)) => { + ast::ExpressionKind::Block(ast::BlockExpression { ref mut statements, .. }) => { self.scope.push(HashMap::default()); self.walk_scope(statements, expr.span); } @@ -415,14 +419,16 @@ impl DebugInstrumenter { self.walk_expr(&mut for_stmt.block); for_stmt.block = ast::Expression { - kind: ast::ExpressionKind::Block(ast::BlockExpression(vec![ - set_stmt, - ast::Statement { - kind: ast::StatementKind::Semi(for_stmt.block.clone()), - span: for_stmt.block.span, - }, - drop_stmt, - ])), + kind: ast::ExpressionKind::Block(ast::BlockExpression { + statements: vec![ + set_stmt, + ast::Statement { + kind: ast::StatementKind::Semi(for_stmt.block.clone()), + span: for_stmt.block.span, + }, + drop_stmt, + ], + }), span: for_stmt.span, }; } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 3fbde8a890b..f8e3c4cab60 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -252,7 +252,7 @@ impl<'a> Resolver<'a> { typ: typ.clone(), span: name.span(), }), - body: BlockExpression(Vec::new()), + body: BlockExpression { statements: Vec::new() }, span: name.span(), where_clause: where_clause.to_vec(), return_type: return_type.clone(), @@ -1952,8 +1952,8 @@ impl<'a> Resolver<'a> { fn resolve_block(&mut self, block_expr: BlockExpression) -> HirExpression { let statements = - self.in_new_scope(|this| vecmap(block_expr.0, |stmt| this.intern_stmt(stmt))); - HirExpression::Block(HirBlockExpression(statements)) + self.in_new_scope(|this| vecmap(block_expr.statements, |stmt| this.intern_stmt(stmt))); + HirExpression::Block(HirBlockExpression { statements }) } pub fn intern_block(&mut self, block: BlockExpression) -> ExprId { diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 642cebc83b0..6beb6929ce1 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -140,6 +140,8 @@ pub enum TypeCheckError { method_name: String, span: Span, }, + #[error("Strings do not support indexed assignment")] + StringIndexAssign { span: Span }, } impl TypeCheckError { @@ -237,7 +239,8 @@ impl From for Diagnostic { | TypeCheckError::ConstrainedReferenceToUnconstrained { span } | TypeCheckError::UnconstrainedReferenceToConstrained { span } | TypeCheckError::UnconstrainedSliceReturnToConstrained { span } - | TypeCheckError::NonConstantSliceLength { span } => { + | TypeCheckError::NonConstantSliceLength { span } + | TypeCheckError::StringIndexAssign { span } => { Diagnostic::simple_error(error.to_string(), String::new(), span) } TypeCheckError::PublicReturnType { typ, span } => Diagnostic::simple_error( diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index ab759f454e5..137608f8037 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -468,7 +468,8 @@ mod test { expression: expr_id, }; let stmt_id = interner.push_stmt(HirStatement::Let(let_stmt)); - let expr_id = interner.push_expr(HirExpression::Block(HirBlockExpression(vec![stmt_id]))); + let expr_id = interner + .push_expr(HirExpression::Block(HirBlockExpression { statements: vec![stmt_id] })); interner.push_expr_location(expr_id, Span::single_char(0), file); // Create function to enclose the let statement diff --git a/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/compiler/noirc_frontend/src/hir/type_check/stmt.rs index 49ba3244dc9..69363d5f00a 100644 --- a/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -258,6 +258,11 @@ impl<'interner> TypeChecker<'interner> { Type::Array(_, elem_type) => *elem_type, Type::Slice(elem_type) => *elem_type, Type::Error => Type::Error, + Type::String(_) => { + let (_lvalue_name, lvalue_span) = self.get_lvalue_name_and_span(&lvalue); + self.errors.push(TypeCheckError::StringIndexAssign { span: lvalue_span }); + Type::Error + } other => { // TODO: Need a better span here self.errors.push(TypeCheckError::TypeMismatch { diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index 61743d2cdc7..c2f6031bf6d 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -37,7 +37,7 @@ pub enum HirExpression { impl HirExpression { /// Returns an empty block expression pub const fn empty_block() -> HirExpression { - HirExpression::Block(HirBlockExpression(vec![])) + HirExpression::Block(HirBlockExpression { statements: vec![] }) } } @@ -249,11 +249,13 @@ pub struct HirIndexExpression { } #[derive(Debug, Clone)] -pub struct HirBlockExpression(pub Vec); +pub struct HirBlockExpression { + pub statements: Vec, +} impl HirBlockExpression { pub fn statements(&self) -> &[StmtId] { - &self.0 + &self.statements } } diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 3c5627f739b..65592407d7d 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -1662,14 +1662,19 @@ fn convert_array_expression_to_slice( let as_slice = HirExpression::Ident(HirIdent::non_trait_method(as_slice_id, location)); let func = interner.push_expr(as_slice); - let arguments = vec![expression]; + // Copy the expression and give it a new ExprId. The old one + // will be mutated in place into a Call expression. + let argument = interner.expression(&expression); + let argument = interner.push_expr(argument); + interner.push_expr_type(argument, array_type.clone()); + interner.push_expr_location(argument, location.span, location.file); + + let arguments = vec![argument]; let call = HirExpression::Call(HirCallExpression { func, arguments, location }); - let call = interner.push_expr(call); + interner.replace_expr(&expression, call); - interner.push_expr_location(call, location.span, location.file); interner.push_expr_location(func, location.span, location.file); - - interner.push_expr_type(call, target_type.clone()); + interner.push_expr_type(expression, target_type.clone()); let func_type = Type::Function(vec![array_type], Box::new(target_type), Box::new(Type::Unit)); interner.push_expr_type(func, func_type); diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 9b0f57a7d39..618eba8f190 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -430,7 +430,7 @@ impl<'interner> Monomorphizer<'interner> { } }, HirExpression::Literal(HirLiteral::Unit) => ast::Expression::Block(vec![]), - HirExpression::Block(block) => self.block(block.0)?, + HirExpression::Block(block) => self.block(block.statements)?, HirExpression::Prefix(prefix) => { let location = self.interner.expr_location(&expr); diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index dec1c7aa9ce..a40355be8aa 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -347,7 +347,7 @@ fn block<'a>( [(LeftParen, RightParen), (LeftBracket, RightBracket)], |span| vec![Statement { kind: StatementKind::Error, span }], )) - .map(BlockExpression) + .map(|statements| BlockExpression { statements }) } fn check_statements_require_semicolon( @@ -1015,10 +1015,12 @@ where // Wrap the inner `if` expression in a block expression. // i.e. rewrite the sugared form `if cond1 {} else if cond2 {}` as `if cond1 {} else { if cond2 {} }`. let if_expression = Expression::new(kind, span); - let desugared_else = BlockExpression(vec![Statement { - kind: StatementKind::Expression(if_expression), - span, - }]); + let desugared_else = BlockExpression { + statements: vec![Statement { + kind: StatementKind::Expression(if_expression), + span, + }], + }; Expression::new(ExpressionKind::Block(desugared_else), span) })); @@ -1399,13 +1401,13 @@ mod test { // Regression for #1310: this should be parsed as a block and not a function call let res = parse_with(block(fresh_statement()), "{ if true { 1 } else { 2 } (3, 4) }").unwrap(); - match unwrap_expr(&res.0.last().unwrap().kind) { + match unwrap_expr(&res.statements.last().unwrap().kind) { // The `if` followed by a tuple is currently creates a block around both in case // there was none to start with, so there is an extra block here. ExpressionKind::Block(block) => { - assert_eq!(block.0.len(), 2); - assert!(matches!(unwrap_expr(&block.0[0].kind), ExpressionKind::If(_))); - assert!(matches!(unwrap_expr(&block.0[1].kind), ExpressionKind::Tuple(_))); + assert_eq!(block.statements.len(), 2); + assert!(matches!(unwrap_expr(&block.statements[0].kind), ExpressionKind::If(_))); + assert!(matches!(unwrap_expr(&block.statements[1].kind), ExpressionKind::Tuple(_))); } _ => unreachable!(), } diff --git a/compiler/noirc_printable_type/src/lib.rs b/compiler/noirc_printable_type/src/lib.rs index d3d20654adc..b9240203a5e 100644 --- a/compiler/noirc_printable_type/src/lib.rs +++ b/compiler/noirc_printable_type/src/lib.rs @@ -88,7 +88,7 @@ impl TryFrom<&[ForeignCallParam]> for PrintableValueDisplay { let (is_fmt_str, foreign_call_inputs) = foreign_call_inputs.split_last().ok_or(ForeignCallError::MissingForeignCallInputs)?; - if is_fmt_str.unwrap_value().to_field().is_one() { + if is_fmt_str.unwrap_field().is_one() { convert_fmt_string_inputs(foreign_call_inputs) } else { convert_string_inputs(foreign_call_inputs) @@ -106,8 +106,7 @@ fn convert_string_inputs( let printable_type = fetch_printable_type(printable_type_as_values)?; // We must use a flat map here as each value in a struct will be in a separate input value - let mut input_values_as_fields = - input_values.iter().flat_map(|param| vecmap(param.values(), |value| value.to_field())); + let mut input_values_as_fields = input_values.iter().flat_map(|param| param.fields()); let value = decode_value(&mut input_values_as_fields, &printable_type); @@ -120,7 +119,7 @@ fn convert_fmt_string_inputs( let (message, input_and_printable_types) = foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?; - let message_as_fields = vecmap(message.values(), |value| value.to_field()); + let message_as_fields = message.fields(); let message_as_string = decode_string_value(&message_as_fields); let (num_values, input_and_printable_types) = input_and_printable_types @@ -128,12 +127,11 @@ fn convert_fmt_string_inputs( .ok_or(ForeignCallError::MissingForeignCallInputs)?; let mut output = Vec::new(); - let num_values = num_values.unwrap_value().to_field().to_u128() as usize; + let num_values = num_values.unwrap_field().to_u128() as usize; let types_start_at = input_and_printable_types.len() - num_values; - let mut input_iter = input_and_printable_types[0..types_start_at] - .iter() - .flat_map(|param| vecmap(param.values(), |value| value.to_field())); + let mut input_iter = + input_and_printable_types[0..types_start_at].iter().flat_map(|param| param.fields()); for printable_type in input_and_printable_types.iter().skip(types_start_at) { let printable_type = fetch_printable_type(printable_type)?; let value = decode_value(&mut input_iter, &printable_type); @@ -147,7 +145,7 @@ fn convert_fmt_string_inputs( fn fetch_printable_type( printable_type: &ForeignCallParam, ) -> Result { - let printable_type_as_fields = vecmap(printable_type.values(), |value| value.to_field()); + let printable_type_as_fields = printable_type.fields(); let printable_type_as_string = decode_string_value(&printable_type_as_fields); let printable_type: PrintableType = serde_json::from_str(&printable_type_as_string)?; diff --git a/compiler/wasm/package.json b/compiler/wasm/package.json index 8db3876a753..6d11a5ba5c8 100644 --- a/compiler/wasm/package.json +++ b/compiler/wasm/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "license": "(MIT OR Apache-2.0)", "main": "dist/main.js", "types": "./dist/types/src/index.d.cts", diff --git a/docs/docs/how_to/how-to-oracles.md b/docs/docs/how_to/how-to-oracles.md index 0d84d992320..ab225b9421f 100644 --- a/docs/docs/how_to/how-to-oracles.md +++ b/docs/docs/how_to/how-to-oracles.md @@ -198,7 +198,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo ```js const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc -await noir.generateFinalProof(inputs, foreignCallHandler) +await noir.generateProof(inputs, foreignCallHandler) ``` As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. diff --git a/docs/docs/noir/concepts/data_types/integers.md b/docs/docs/noir/concepts/data_types/integers.md index 4d58d96fed5..1c6b375db49 100644 --- a/docs/docs/noir/concepts/data_types/integers.md +++ b/docs/docs/noir/concepts/data_types/integers.md @@ -51,7 +51,7 @@ The built-in structure `U128` allows you to use 128-bit unsigned integers almost - You cannot cast between a native integer and `U128` - There is a higher performance cost when using `U128`, compared to a native type. -Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. `from_integer` also accepts the `Field` type as input. ```rust fn main() { diff --git a/docs/docs/tutorials/noirjs_app.md b/docs/docs/tutorials/noirjs_app.md index ad76dd255cc..12beb476994 100644 --- a/docs/docs/tutorials/noirjs_app.md +++ b/docs/docs/tutorials/noirjs_app.md @@ -243,7 +243,7 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul await setup(); // let's squeeze our wasm inits here display('logs', 'Generating proof... ⌛'); -const proof = await noir.generateFinalProof(input); +const proof = await noir.generateProof(input); display('logs', 'Generating proof... ✅'); display('results', proof.proof); ``` @@ -264,7 +264,7 @@ Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add th ```js display('logs', 'Verifying proof... ⌛'); -const verification = await noir.verifyFinalProof(proof); +const verification = await noir.verifyProof(proof); if (verification) display('logs', 'Verifying proof... ✅'); ``` diff --git a/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md b/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md index 0d84d992320..ab225b9421f 100644 --- a/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md +++ b/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md @@ -198,7 +198,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo ```js const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc -await noir.generateFinalProof(inputs, foreignCallHandler) +await noir.generateProof(inputs, foreignCallHandler) ``` As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. diff --git a/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md index ad76dd255cc..12beb476994 100644 --- a/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md @@ -243,7 +243,7 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul await setup(); // let's squeeze our wasm inits here display('logs', 'Generating proof... ⌛'); -const proof = await noir.generateFinalProof(input); +const proof = await noir.generateProof(input); display('logs', 'Generating proof... ✅'); display('results', proof.proof); ``` @@ -264,7 +264,7 @@ Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add th ```js display('logs', 'Verifying proof... ⌛'); -const verification = await noir.verifyFinalProof(proof); +const verification = await noir.verifyProof(proof); if (verification) display('logs', 'Verifying proof... ✅'); ``` diff --git a/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md b/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md index 0d84d992320..ab225b9421f 100644 --- a/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md +++ b/docs/versioned_docs/version-v0.25.0/how_to/how-to-oracles.md @@ -198,7 +198,7 @@ For example, if your Noir program expects the host machine to provide CPU pseudo ```js const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc -await noir.generateFinalProof(inputs, foreignCallHandler) +await noir.generateProof(inputs, foreignCallHandler) ``` As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. diff --git a/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md index ad76dd255cc..12beb476994 100644 --- a/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md @@ -243,7 +243,7 @@ Now we're ready to prove stuff! Let's feed some inputs to our circuit and calcul await setup(); // let's squeeze our wasm inits here display('logs', 'Generating proof... ⌛'); -const proof = await noir.generateFinalProof(input); +const proof = await noir.generateProof(input); display('logs', 'Generating proof... ✅'); display('results', proof.proof); ``` @@ -264,7 +264,7 @@ Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add th ```js display('logs', 'Verifying proof... ⌛'); -const verification = await noir.verifyFinalProof(proof); +const verification = await noir.verifyProof(proof); if (verification) display('logs', 'Verifying proof... ✅'); ``` diff --git a/flake.nix b/flake.nix index 785d5aead56..1cb421a49ef 100644 --- a/flake.nix +++ b/flake.nix @@ -73,7 +73,7 @@ # Configuration shared between builds config = { # x-release-please-start-version - version = "0.25.0"; + version = "0.26.0"; # x-release-please-end src = pkgs.lib.cleanSourceWith { diff --git a/noir_stdlib/src/collections/bounded_vec.nr b/noir_stdlib/src/collections/bounded_vec.nr index 752b96d6591..6d5fbd44247 100644 --- a/noir_stdlib/src/collections/bounded_vec.nr +++ b/noir_stdlib/src/collections/bounded_vec.nr @@ -48,6 +48,15 @@ impl BoundedVec { self.len = new_len; } + pub fn extend_from_slice(&mut self, slice: [T]) { + let new_len = self.len + slice.len(); + assert(new_len as u64 <= MaxLen as u64, "extend_from_slice out of bounds"); + for i in 0..slice.len() { + self.storage[self.len + i] = slice[i]; + } + self.len = new_len; + } + pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) { let append_len = vec.len(); let new_len = self.len + append_len; diff --git a/noir_stdlib/src/field.nr b/noir_stdlib/src/field.nr index 0f4c2caffdf..b876bcc967b 100644 --- a/noir_stdlib/src/field.nr +++ b/noir_stdlib/src/field.nr @@ -97,7 +97,7 @@ pub fn modulus_be_bytes() -> [u8] {} #[builtin(modulus_le_bytes)] pub fn modulus_le_bytes() -> [u8] {} -// Convert a 32 byte array to a field element +// Convert a 32 byte array to a field element by modding pub fn bytes32_to_field(bytes32: [u8; 32]) -> Field { // Convert it to a field element let mut v = 1; diff --git a/release-please-config.json b/release-please-config.json index e73993ca974..217a86303a1 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -61,8 +61,8 @@ "acir_field/Cargo.toml", "acvm/Cargo.toml", "acvm_js/Cargo.toml", - "barretenberg_blackbox_solver/Cargo.toml", "blackbox_solver/Cargo.toml", + "bn254_blackbox_solver/Cargo.toml", "brillig/Cargo.toml", "brillig_vm/Cargo.toml", { diff --git a/test_programs/execution_success/array_to_slice/src/main.nr b/test_programs/execution_success/array_to_slice/src/main.nr index b97f68fc280..0d0f9562d7b 100644 --- a/test_programs/execution_success/array_to_slice/src/main.nr +++ b/test_programs/execution_success/array_to_slice/src/main.nr @@ -7,6 +7,7 @@ fn as_slice_push(xs: [T; N]) -> [T] { slice } +// Expected that x == 0 and y == 1 fn main(x: Field, y: pub Field) { let xs: [Field; 0] = []; let ys: [Field; 1] = [1]; @@ -30,4 +31,26 @@ fn main(x: Field, y: pub Field) { assert(dynamic.as_slice()[2] == dynamic_expected[2]); assert(dynamic.as_slice()[3] == dynamic_expected[3]); assert(dynamic.as_slice().len() == 4); + + regression_4609_append_slices(x, y); + regression_4609_append_dynamic_slices(x, y); +} + +fn regression_4609_append_slices(x: Field, y: Field) { + let sl = [x, 1, 2, 3].as_slice(); + let sl2 = [y, 5, 6].as_slice(); + let sl3 = sl.append(sl2); + assert(sl3[0] == x); + assert(sl3[4] == y); +} + +fn regression_4609_append_dynamic_slices(x: Field, y: Field) { + let mut sl = [x, 1, 2, 3].as_slice(); + sl[x] = x + 10; + let mut sl2 = [y, 5, 6].as_slice(); + sl2[y] = y + 5; + let sl3 = sl.append(sl2); + assert(sl3[0] == 10); + assert(sl3[4] == y); + assert(sl3[5] == 6); } diff --git a/test_programs/execution_success/regression_capacity_tracker/Nargo.toml b/test_programs/execution_success/regression_capacity_tracker/Nargo.toml new file mode 100644 index 00000000000..d5a3839626f --- /dev/null +++ b/test_programs/execution_success/regression_capacity_tracker/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_capacity_tracker" +type = "bin" +authors = [""] +compiler_version = ">=0.26.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/regression_capacity_tracker/Prover.toml b/test_programs/execution_success/regression_capacity_tracker/Prover.toml new file mode 100644 index 00000000000..bbf35b23a0f --- /dev/null +++ b/test_programs/execution_success/regression_capacity_tracker/Prover.toml @@ -0,0 +1,3 @@ +expected = "10" +first = "10" +input = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] \ No newline at end of file diff --git a/test_programs/execution_success/regression_capacity_tracker/src/main.nr b/test_programs/execution_success/regression_capacity_tracker/src/main.nr new file mode 100644 index 00000000000..be645c811d2 --- /dev/null +++ b/test_programs/execution_success/regression_capacity_tracker/src/main.nr @@ -0,0 +1,19 @@ +// Reference https://github.com/noir-lang/noir/issues/4395#issuecomment-2018948631 +// for context. +// We were not accurately accounting for situations where the slice capacity tracker +// was expecting a capacity from slice intrinsic results. +fn main(expected: pub Field, first: Field, input: [Field; 20]) { + let mut hasher_slice = input.as_slice(); + hasher_slice = hasher_slice.push_front(first); + assert(hasher_slice[0] == expected); + // We need a conditional based upon witnesses + // to force a store of the slice. + // If this successfully compiles it means we have stored + // the results of the slice intrinsics used above. + if expected as u32 > 10 { + hasher_slice[expected - 10] = 100; + } else { + hasher_slice[expected] = 100; + } + assert(hasher_slice[0] == expected); +} diff --git a/test_programs/execution_success/slice_coercion/Nargo.toml b/test_programs/execution_success/slice_coercion/Nargo.toml new file mode 100644 index 00000000000..659677cc560 --- /dev/null +++ b/test_programs/execution_success/slice_coercion/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "slice_coercion" +type = "bin" +authors = [""] +compiler_version = ">=0.25.0" + +[dependencies] diff --git a/test_programs/execution_success/slice_coercion/Prover.toml b/test_programs/execution_success/slice_coercion/Prover.toml new file mode 100644 index 00000000000..09c44a855b0 --- /dev/null +++ b/test_programs/execution_success/slice_coercion/Prover.toml @@ -0,0 +1,2 @@ +first = 3 +expected = 3 diff --git a/test_programs/execution_success/slice_coercion/src/main.nr b/test_programs/execution_success/slice_coercion/src/main.nr new file mode 100644 index 00000000000..a3785e79afa --- /dev/null +++ b/test_programs/execution_success/slice_coercion/src/main.nr @@ -0,0 +1,19 @@ +struct Hasher { + fields: [Field], +} + +impl Hasher { + pub fn new() -> Self { + Self { fields: [] } + } + + pub fn add(&mut self, field: Field) { + self.fields = self.fields.push_back(field); + } +} + +fn main(expected: pub Field, first: Field) { + let mut hasher = Hasher::new(); + hasher.add(first); + assert(hasher.fields[0] == expected); +} diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index a3ee89263a4..f0de8d5d1c8 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -2,7 +2,7 @@ use crate::foreign_calls::DebugForeignCallExecutor; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; use acvm::brillig_vm::brillig::ForeignCallResult; -use acvm::brillig_vm::brillig::Value; +use acvm::brillig_vm::MemoryValue; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, }; @@ -506,13 +506,13 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { acir_index < opcodes.len() && matches!(opcodes[acir_index], Opcode::Brillig(..)) } - pub(super) fn get_brillig_memory(&self) -> Option<&[Value]> { + pub(super) fn get_brillig_memory(&self) -> Option<&[MemoryValue]> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) } - pub(super) fn write_brillig_memory(&mut self, ptr: usize, value: FieldElement) { + pub(super) fn write_brillig_memory(&mut self, ptr: usize, value: FieldElement, bit_size: u32) { if let Some(solver) = self.brillig_solver.as_mut() { - solver.write_memory_at(ptr, value.into()); + solver.write_memory_at(ptr, MemoryValue::new(value, bit_size)); } } @@ -667,7 +667,7 @@ mod tests { }, BrilligOpcode::Const { destination: MemoryAddress::from(1), - value: Value::from(fe_0), + value: fe_0, bit_size: 32, }, BrilligOpcode::ForeignCall { @@ -675,7 +675,7 @@ mod tests { destinations: vec![], destination_value_types: vec![], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::Simple], + input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, ], diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 25f126ff490..aae2212fd54 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -1,6 +1,7 @@ use acvm::{ - acir::brillig::{ForeignCallParam, ForeignCallResult, Value}, + acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, + FieldElement, }; use nargo::{ artifacts::debug::{DebugArtifact, DebugVars, StackFrame}, @@ -81,11 +82,11 @@ impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor { } } -fn debug_var_id(value: &Value) -> DebugVarId { +fn debug_var_id(value: &FieldElement) -> DebugVarId { DebugVarId(value.to_u128() as u32) } -fn debug_fn_id(value: &Value) -> DebugFnId { +fn debug_fn_id(value: &FieldElement) -> DebugFnId { DebugFnId(value.to_u128() as u32) } @@ -100,8 +101,8 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { let fcp_var_id = &foreign_call.inputs[0]; if let ForeignCallParam::Single(var_id_value) = fcp_var_id { let var_id = debug_var_id(var_id_value); - let values: Vec = - foreign_call.inputs[1..].iter().flat_map(|x| x.values()).collect(); + let values: Vec = + foreign_call.inputs[1..].iter().flat_map(|x| x.fields()).collect(); self.debug_vars.assign_var(var_id, &values); } Ok(ForeignCallResult::default().into()) @@ -129,12 +130,12 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { } }) .collect(); - let values: Vec = (0..n - 1 - arity) + let values: Vec = (0..n - 1 - arity) .flat_map(|i| { foreign_call .inputs .get(1 + i) - .map(|fci| fci.values()) + .map(|fci| fci.fields()) .unwrap_or_default() }) .collect(); @@ -147,7 +148,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { let fcp_value = &foreign_call.inputs[1]; if let ForeignCallParam::Single(var_id_value) = fcp_var_id { let var_id = debug_var_id(var_id_value); - self.debug_vars.assign_deref(var_id, &fcp_value.values()); + self.debug_vars.assign_deref(var_id, &fcp_value.fields()); } Ok(ForeignCallResult::default().into()) } diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 41dbf604f99..1c077c6ee9b 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -319,12 +319,12 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { return; }; - for (index, value) in memory.iter().enumerate() { - println!("{index} = {}", value.to_field()); + for (index, value) in memory.iter().enumerate().filter(|(_, value)| value.bit_size > 0) { + println!("{index} = {}", value); } } - pub fn write_brillig_memory(&mut self, index: usize, value: String) { + pub fn write_brillig_memory(&mut self, index: usize, value: String, bit_size: u32) { let Some(field_value) = FieldElement::try_from_str(&value) else { println!("Invalid value: {value}"); return; @@ -333,7 +333,7 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { println!("Not executing a Brillig block"); return; } - self.context.write_brillig_memory(index, field_value); + self.context.write_brillig_memory(index, field_value, bit_size); } pub fn show_vars(&self) { @@ -513,8 +513,8 @@ pub fn run( "memset", command! { "update a Brillig memory cell with the given value", - (index: usize, value: String) => |index, value| { - ref_context.borrow_mut().write_brillig_memory(index, value); + (index: usize, value: String, bit_size: u32) => |index, value, bit_size| { + ref_context.borrow_mut().write_brillig_memory(index, value, bit_size); Ok(CommandStatus::Done) } }, diff --git a/tooling/nargo/src/artifacts/debug_vars.rs b/tooling/nargo/src/artifacts/debug_vars.rs index 0e9e177e023..8e5c2bc46a4 100644 --- a/tooling/nargo/src/artifacts/debug_vars.rs +++ b/tooling/nargo/src/artifacts/debug_vars.rs @@ -1,4 +1,4 @@ -use acvm::brillig_vm::brillig::Value; +use acvm::FieldElement; use noirc_errors::debug_info::{ DebugFnId, DebugFunction, DebugInfo, DebugTypeId, DebugVarId, DebugVariable, }; @@ -66,7 +66,7 @@ impl DebugVars { } } - pub fn assign_var(&mut self, var_id: DebugVarId, values: &[Value]) { + pub fn assign_var(&mut self, var_id: DebugVarId, values: &[FieldElement]) { let type_id = &self.variables.get(&var_id).unwrap().debug_type_id; let ptype = self.types.get(type_id).unwrap(); @@ -74,10 +74,10 @@ impl DebugVars { .last_mut() .expect("unexpected empty stack frames") .1 - .insert(var_id, decode_value(&mut values.iter().map(|v| v.to_field()), ptype)); + .insert(var_id, decode_value(&mut values.iter().copied(), ptype)); } - pub fn assign_field(&mut self, var_id: DebugVarId, indexes: Vec, values: &[Value]) { + pub fn assign_field(&mut self, var_id: DebugVarId, indexes: Vec, values: &[FieldElement]) { let current_frame = &mut self.frames.last_mut().expect("unexpected empty stack frames").1; let mut cursor: &mut PrintableValue = current_frame .get_mut(&var_id) @@ -147,10 +147,10 @@ impl DebugVars { } }; } - *cursor = decode_value(&mut values.iter().map(|v| v.to_field()), cursor_type); + *cursor = decode_value(&mut values.iter().copied(), cursor_type); } - pub fn assign_deref(&mut self, _var_id: DebugVarId, _values: &[Value]) { + pub fn assign_deref(&mut self, _var_id: DebugVarId, _values: &[FieldElement]) { unimplemented![] } diff --git a/tooling/nargo/src/ops/foreign_calls.rs b/tooling/nargo/src/ops/foreign_calls.rs index f7f36c65c90..ea67f17af2a 100644 --- a/tooling/nargo/src/ops/foreign_calls.rs +++ b/tooling/nargo/src/ops/foreign_calls.rs @@ -1,6 +1,7 @@ use acvm::{ - acir::brillig::{ForeignCallParam, ForeignCallResult, Value}, + acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, + FieldElement, }; use jsonrpc::{arg as build_json_rpc_arg, minreq_http::Builder, Client}; use noirc_printable_type::{decode_string_value, ForeignCallError, PrintableValueDisplay}; @@ -46,15 +47,15 @@ impl From for NargoForeignCallResult { } } -impl From for NargoForeignCallResult { - fn from(value: Value) -> Self { +impl From for NargoForeignCallResult { + fn from(value: FieldElement) -> Self { let foreign_call_result: ForeignCallResult = value.into(); foreign_call_result.into() } } -impl From> for NargoForeignCallResult { - fn from(values: Vec) -> Self { +impl From> for NargoForeignCallResult { + fn from(values: Vec) -> Self { let foreign_call_result: ForeignCallResult = values.into(); foreign_call_result.into() } @@ -178,7 +179,10 @@ impl DefaultForeignCallExecutor { ) -> Result<(usize, &[ForeignCallParam]), ForeignCallError> { let (id, params) = foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?; - Ok((id.unwrap_value().to_usize(), params)) + let id = + usize::try_from(id.unwrap_field().try_to_u64().expect("value does not fit into u64")) + .expect("value does not fit into usize"); + Ok((id, params)) } fn find_mock_by_id(&mut self, id: usize) -> Option<&mut MockedCall> { @@ -186,12 +190,12 @@ impl DefaultForeignCallExecutor { } fn parse_string(param: &ForeignCallParam) -> String { - let fields: Vec<_> = param.values().into_iter().map(|value| value.to_field()).collect(); + let fields: Vec<_> = param.fields().to_vec(); decode_string_value(&fields) } fn execute_print(foreign_call_inputs: &[ForeignCallParam]) -> Result<(), ForeignCallError> { - let skip_newline = foreign_call_inputs[0].unwrap_value().is_zero(); + let skip_newline = foreign_call_inputs[0].unwrap_field().is_zero(); let foreign_call_inputs = foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?.1; @@ -242,7 +246,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { self.mocked_responses.push(MockedCall::new(id, mock_oracle_name)); self.last_mock_id += 1; - Ok(Value::from(id).into()) + Ok(FieldElement::from(id).into()) } Some(ForeignCall::SetMockParams) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -262,11 +266,8 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { } Some(ForeignCall::SetMockTimes) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; - let times = params[0] - .unwrap_value() - .to_field() - .try_to_u64() - .expect("Invalid bit size of times"); + let times = + params[0].unwrap_field().try_to_u64().expect("Invalid bit size of times"); self.find_mock_by_id(id) .unwrap_or_else(|| panic!("Unknown mock id {}", id)) @@ -325,10 +326,8 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { #[cfg(test)] mod tests { use acvm::{ - acir::brillig::ForeignCallParam, - brillig_vm::brillig::{ForeignCallResult, Value}, - pwg::ForeignCallWaitInfo, - FieldElement, + acir::brillig::ForeignCallParam, brillig_vm::brillig::ForeignCallResult, + pwg::ForeignCallWaitInfo, FieldElement, }; use jsonrpc_core::Result as RpcResult; use jsonrpc_derive::rpc; @@ -356,11 +355,11 @@ mod tests { fn sum(&self, array: ForeignCallParam) -> RpcResult { let mut res: FieldElement = 0_usize.into(); - for value in array.values() { - res += value.to_field(); + for value in array.fields() { + res += value; } - Ok(Value::from(res).into()) + Ok(res.into()) } } @@ -406,7 +405,7 @@ mod tests { }; let result = executor.execute(&foreign_call); - assert_eq!(result.unwrap(), Value::from(3_usize).into()); + assert_eq!(result.unwrap(), FieldElement::from(3_usize).into()); server.close(); } diff --git a/tooling/nargo_fmt/src/visitor/expr.rs b/tooling/nargo_fmt/src/visitor/expr.rs index 2cd0e881e84..f9836adda18 100644 --- a/tooling/nargo_fmt/src/visitor/expr.rs +++ b/tooling/nargo_fmt/src/visitor/expr.rs @@ -119,11 +119,11 @@ impl FmtVisitor<'_> { self.last_position = block_span.start() + 1; // `{` self.push_str("{"); - self.trim_spaces_after_opening_brace(&block.0); + self.trim_spaces_after_opening_brace(&block.statements); self.indent.block_indent(self.config); - self.visit_stmts(block.0); + self.visit_stmts(block.statements); let span = (self.last_position..block_span.end() - 1).into(); self.close_block(span); diff --git a/tooling/noir_codegen/package.json b/tooling/noir_codegen/package.json index 485f4252e29..1eabc6a1398 100644 --- a/tooling/noir_codegen/package.json +++ b/tooling/noir_codegen/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js/package.json b/tooling/noir_js/package.json index 0da6e695202..c8d4873e095 100644 --- a/tooling/noir_js/package.json +++ b/tooling/noir_js/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index 92b8460d1db..1ea384cdd49 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.30.1", + "@aztec/bb.js": "portal:../../../../barretenberg/ts", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/noir_js_types/package.json b/tooling/noir_js_types/package.json index d7a08debb54..eadb6f49665 100644 --- a/tooling/noir_js_types/package.json +++ b/tooling/noir_js_types/package.json @@ -4,7 +4,7 @@ "The Noir Team " ], "packageManager": "yarn@3.5.1", - "version": "0.25.0", + "version": "0.26.0", "license": "(MIT OR Apache-2.0)", "homepage": "https://noir-lang.org/", "repository": { diff --git a/tooling/noirc_abi_wasm/package.json b/tooling/noirc_abi_wasm/package.json index a6cc5503242..e93a8e6a5e3 100644 --- a/tooling/noirc_abi_wasm/package.json +++ b/tooling/noirc_abi_wasm/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.25.0", + "version": "0.26.0", "license": "(MIT OR Apache-2.0)", "homepage": "https://noir-lang.org/", "repository": { diff --git a/yarn.lock b/yarn.lock index 3932935167d..b45678f5d8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,19 +221,18 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.30.1": - version: 0.30.1 - resolution: "@aztec/bb.js@npm:0.30.1" +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": + version: 0.0.0-use.local + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: dest/node/main.js - checksum: 52d0acaaf0966aa969b863adeb688df5c1abe7c8a0595bc2dca8603a8649f11eb39071aacbdc05b19f320f022b98691a41cb18a601ad84e6d82955ae6f885106 + bb.js: ./dest/node/main.js languageName: node - linkType: hard + linkType: soft "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4396,7 +4395,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.30.1 + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3