diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index f3443d5f68..cf4a54a96d 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 with: components: rustfmt, clippy - uses: actions/checkout@v3 diff --git a/.github/workflows/cairo_1_programs.yml b/.github/workflows/cairo_1_programs.yml index d8a4c1f3f4..c2872a03b4 100644 --- a/.github/workflows/cairo_1_programs.yml +++ b/.github/workflows/cairo_1_programs.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Set up Cargo cache uses: Swatinem/rust-cache@v2 - name: Checkout diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 657974f5a9..75d450dcd7 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: dangoslen/changelog-enforcer@v3 with: - skipLabels: pipelines,coverage + skipLabels: pipelines,tests,documentation diff --git a/.github/workflows/fresh_run.yml b/.github/workflows/fresh_run.yml index f733076e77..fd523f7c75 100644 --- a/.github/workflows/fresh_run.yml +++ b/.github/workflows/fresh_run.yml @@ -38,7 +38,7 @@ jobs: uses: actions/checkout@v3 - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Install Pyenv uses: "gabrielfalcao/pyenv-action@v13" diff --git a/.github/workflows/hint_accountant.yml b/.github/workflows/hint_accountant.yml index 4a3a1e023f..3bd9ca4ff0 100644 --- a/.github/workflows/hint_accountant.yml +++ b/.github/workflows/hint_accountant.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Set up Cargo cache uses: Swatinem/rust-cache@v2 - name: Checkout diff --git a/.github/workflows/hyperfine.yml b/.github/workflows/hyperfine.yml index 87bf26f3e3..6fb098b6a6 100644 --- a/.github/workflows/hyperfine.yml +++ b/.github/workflows/hyperfine.yml @@ -74,7 +74,7 @@ jobs: - name: Install Rust if: ${{ steps.cache.outputs.cache-hit != 'true' }} - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Checkout if: ${{ steps.cache.outputs.cache-hit != 'true' }} diff --git a/.github/workflows/iai_main.yml b/.github/workflows/iai_main.yml index e1217085ba..f61eef7e3e 100644 --- a/.github/workflows/iai_main.yml +++ b/.github/workflows/iai_main.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Set up cargo cache uses: Swatinem/rust-cache@v2 - name: Python3 Build diff --git a/.github/workflows/iai_pr.yml b/.github/workflows/iai_pr.yml index db446adeb9..afb9e3a97c 100644 --- a/.github/workflows/iai_pr.yml +++ b/.github/workflows/iai_pr.yml @@ -23,7 +23,7 @@ jobs: - name: Install Rust if: ${{ steps.cache-iai-results.outputs.cache-hit != 'true' }} - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Set up cargo cache if: ${{ steps.cache-iai-results.outputs.cache-hit != 'true' }} uses: Swatinem/rust-cache@v2 @@ -51,7 +51,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Set up cargo cache uses: Swatinem/rust-cache@v2 - name: Python3 Build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f4ea9e2193..a06efe8806 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v2 - name: Install stable toolchain - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Publish crate cairo-vm env: CRATES_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a6a7a38f43..83452c25ff 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,7 +22,23 @@ env: PROPTEST_CASES: 100 jobs: + + # We need to use the same files across all jobs or else hashing will fail + upload_proof_programs_symlinks: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Create proof_programs symlinks + run: make create-proof-programs-symlinks + - uses: actions/upload-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/*.cairo + build-programs: + needs: upload_proof_programs_symlinks strategy: matrix: # NOTE: we build cairo_bench_programs so clippy can check the benchmarks too @@ -41,6 +57,11 @@ jobs: with: fetch-depth: 0 + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Fetch from cache uses: actions/cache@v3 id: cache-programs @@ -91,6 +112,11 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ - name: Fetch test programs uses: actions/cache/restore@v3 @@ -135,7 +161,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 with: components: rustfmt, clippy - name: Set up cargo cache @@ -143,9 +169,15 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Format run: make check-fmt + - name: Fetch programs uses: actions/cache/restore@v3 with: @@ -162,10 +194,14 @@ jobs: smoke: needs: merge-caches name: Make sure all builds work + strategy: + fail-fast: false + matrix: + crate: ["vm", "cairo-vm-cli", "cairo1-run"] runs-on: ubuntu-22.04 steps: - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 with: targets: wasm32-unknown-unknown @@ -178,9 +214,15 @@ jobs: uses: taiki-e/install-action@v2 with: tool: cargo-all-features + - name: Checkout uses: actions/checkout@v3 + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Fetch programs uses: actions/cache/restore@v3 with: @@ -189,19 +231,86 @@ jobs: fail-on-cache-miss: true # NOTE: we do this separately because --workspace operates in weird ways - - name: Check all features (vm) + - name: Check all features (${{ matrix.crate }}) run: | - cd vm + cd ${{ matrix.crate }} cargo check-all-features + cargo check-all-features --workspace --all-targets + + smoke-workspace: + needs: merge-caches + name: Make sure all builds work (workspace) + strategy: + fail-fast: false + matrix: + chunk: [1, 2, 3, 4, 5, 6] + runs-on: ubuntu-22.04 + steps: + - name: Install Rust + uses: dtolnay/rust-toolchain@1.74.1 + with: + targets: wasm32-unknown-unknown + + - name: Set up cargo cache + uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Install cargo-all-features + uses: taiki-e/install-action@v2 + with: + tool: cargo-all-features + + - name: Checkout + uses: actions/checkout@v3 + + - name: Download proof programs symlinks + uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + + - name: Fetch programs + uses: actions/cache/restore@v3 + with: + path: ${{ env.CAIRO_PROGRAMS_PATH }} + key: all-programs-cache-${{ hashFiles('cairo_programs/**/*.cairo', 'examples/wasm-demo/src/array_sum.cairo') }} + fail-on-cache-miss: true - - name: Check all features (CLI) - run: | - cd cairo-vm-cli - cargo check-all-features - - name: Check all features (workspace) run: | - cargo check-all-features --workspace --all-targets + cargo check-all-features --n-chunks 6 --chunk ${{ matrix.chunk }} --workspace --all-targets + + smoke-no-std: + needs: merge-caches + name: Make sure all builds work (no_std) + runs-on: ubuntu-22.04 + steps: + - name: Install Rust + uses: dtolnay/rust-toolchain@1.74.1 + with: + targets: wasm32-unknown-unknown + + - name: Set up cargo cache + uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Checkout + uses: actions/checkout@v3 + + - name: Download proof programs symlinks + uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + + - name: Fetch programs + uses: actions/cache/restore@v3 + with: + path: ${{ env.CAIRO_PROGRAMS_PATH }} + key: all-programs-cache-${{ hashFiles('cairo_programs/**/*.cairo', 'examples/wasm-demo/src/array_sum.cairo') }} + fail-on-cache-miss: true - name: Check no-std run: | @@ -214,13 +323,13 @@ jobs: strategy: fail-fast: false matrix: - special_features: ["", "extensive_hints"] + special_features: ["", "extensive_hints", "mod_builtin"] target: [ test#1, test#2, test#3, test#4, test-no_std#1, test-no_std#2, test-no_std#3, test-no_std#4, test-wasm ] name: Run tests runs-on: ubuntu-22.04 steps: - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 with: components: llvm-tools-preview - name: Set up cargo cache @@ -228,6 +337,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Fetch programs uses: actions/cache/restore@v3 with: @@ -281,7 +395,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Install Rust - uses: dtolnay/rust-toolchain@1.70.0 + uses: dtolnay/rust-toolchain@1.74.1 - name: Set up cargo cache uses: Swatinem/rust-cache@v2 - name: Checkout @@ -314,6 +428,11 @@ jobs: with: fetch-depth: 0 + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Check cache uses: actions/cache@v3 id: trace-cache @@ -381,6 +500,11 @@ jobs: path: target/release/cairo-vm-cli fail-on-cache-miss: true + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Fetch programs uses: actions/cache/restore@v3 with: @@ -496,6 +620,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + - name: Fetch traces for cairo-lang uses: actions/cache/restore@v3 with: @@ -556,3 +685,42 @@ jobs: cairo-compile cairo_programs/array_sum.cairo --no_debug_info --output cairo_programs/array_sum.json cd examples/wasm-demo wasm-pack build --target=web + + compare-factorial-outputs-all-layouts: + name: Compare factorial outputs for all layouts + needs: [ build-programs, build-release ] + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Python3 Build + uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pip' + + - name: Install cairo-lang and deps + run: pip install -r requirements.txt + + - name: Fetch release binary + uses: actions/cache/restore@v3 + with: + key: cli-bin-rel-${{ github.sha }} + path: target/release/cairo-vm-cli + fail-on-cache-miss: true + + - uses: actions/download-artifact@master + with: + name: proof_programs + path: cairo_programs/proof_programs/ + + - name: Fetch programs + uses: actions/cache/restore@v3 + with: + path: ${{ env.CAIRO_PROGRAMS_PATH }} + key: cairo_proof_programs-cache-${{ hashFiles('cairo_programs/**/*.cairo', 'examples/wasm-demo/src/array_sum.cairo') }} + fail-on-cache-miss: true + + - name: Run script + run: ./vm/src/tests/compare_factorial_outputs_all_layouts.sh diff --git a/.gitignore b/.gitignore index a6f4053583..2e1f8ff93e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ **/*.memory **/*.air_public_input **/*.air_private_input +**/*.pie.zip **/*.swp bench/results .python-version @@ -22,5 +23,6 @@ cairo-vm-pypy-env/* cairo1-run/corelib/ cairo-vm-cli/air_input.pub ensure-no_std/Cargo.lock +cairo_programs/proof_programs/*.cairo !vm/src/tests/cairo_pie_test_output.json diff --git a/CHANGELOG.md b/CHANGELOG.md index e764150f68..3fbaa1b980 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,132 @@ #### Upcoming Changes +* refactor: Remove unused code & use constants whenever possible for builtin instance definitions[#1707](https://github.com/lambdaclass/cairo-vm/pull/1707) + +* feat: missing EC hints for Starknet OS 0.13.1 [#1706](https://github.com/lambdaclass/cairo-vm/pull/1706) + +* fix(BREAKING): Use program builtins in `initialize_main_entrypoint` & `read_return_values`[#1703](https://github.com/lambdaclass/cairo-vm/pull/1703) + * `initialize_main_entrypoint` now iterates over the program builtins when building the stack & inserts 0 for any missing builtin + * `read_return_values` now only computes the final stack of the builtins in the program + * BREAKING: `read_return_values` now takes a boolean argument `allow_missing_builtins` + * Added method `BuiltinRunner::identifier` to get the `BuiltinName` of each builtin + * BREAKING: `OutputBuiltinRunner::get_public_memory` now takes a reference to `MemorySegmentManager` + * BREAKING: method `VirtualMachine::get_memory_segment_addresses` moved to `CairoRunner::get_memory_segment_addresses` + +* feat(BREAKING): Add range_check96 builtin[#1698](https://github.com/lambdaclass/cairo-vm/pull/1698) + * Add the new `range_check96` builtin to the `all_cairo` layout. + * `RangeCheckBuiltinRunner` changes: + * Remove field `n_parts`, replacing it with const generic `N_PARTS`. + * Remome `n_parts` argument form method `new`. + * Remove field `_bound`, replacing it with public method `bound`. + * Add public methods `name` & `n_parts`. + +* feat(BREAKING): Add mod builtin [#1673](https://github.com/lambdaclass/cairo-vm/pull/1673) + + Main Changes: + * Add the new `ModBuiltinRunner`, implementing the builtins `add_mod` & `mul_mod` + * Adds `add_mod` & `mul_mod` to the `all_cairo` & `dynamic` layouts under the `mod_builtin` feature flag. This will be added to the main code in a future update. + * Add method `VirtualMachine::fill_memory` in order to perform the new builtin's main logic from within hints + * Add hints to run arithmetic circuits using `add_mod` and/or `mul_mod` builtins + + Other Changes: + * BREAKING: BuiltinRunner method signature change from + `air_private_input(&self, memory: &Memory) -> Vec` to `pub fn air_private_input(&self, segments: &MemorySegmentManager) -> Vec` + * Add `MayleRelocatable::sub_usize` + * Implement `Add for Relocatable` + * Add `Memory::get_usize` + * BREAKING: Clean up unused/duplicated code from builtins module: + * Remove unused method `get_memory_segment_addresses` from all builtin runners & the enum + * Remove empty implementations of `deduce_memory_cell` & `add_validation_rules` from all builtin runners + * Remove duplicated implementation of `final_stack` from all builtin runners except output and move it to the enum implementation + +* bugfix(BREAKING): Handle off2 immediate case in `get_integer_from_reference`[#1701](https://github.com/lambdaclass/cairo-vm/pull/1701) + * `get_integer_from_reference` & `get_integer_from_var_name` output changed from `Result, HintError>` to `Result` + +* feat: Reorganized builtins to be in the top of stack at the end of a run (Cairo1). + +* BREAKING: Remove `CairoRunner::add_additional_hash_builtin` & `VirtualMachine::disable_trace`[#1658](https://github.com/lambdaclass/cairo-vm/pull/1658) + +* feat: output builtin add_attribute method [#1691](https://github.com/lambdaclass/cairo-vm/pull/1691) + +* feat: add a method to retrieve the output builtin from the VM [#1690](https://github.com/lambdaclass/cairo-vm/pull/1690) + +* feat: Add zero segment [#1668](https://github.com/lambdaclass/cairo-vm/pull/1668) + +* feat: Bump cairo_lang to 0.13.1 in testing env [#1687](https://github.com/lambdaclass/cairo-vm/pull/1687) + +* feat(BREAKING): Use return type info from sierra when serializing return values in cairo1-run crate [#1665](https://github.com/lambdaclass/cairo-vm/pull/1665) + * Removed public function `serialize_output`. + * Add field `serialize_output` to `Cairo1RunConfig`. + * Function `cairo_run_program` now returns an extra `Option` value with the serialized output if `serialize_output` is enabled in the config. + * Output serialization improved as it now uses the sierra program data to identify return value's types. + +* feat: Create hyper_threading crate to benchmark the `cairo-vm` in a hyper-threaded environment [#1679](https://github.com/lambdaclass/cairo-vm/pull/1679) + +* feat: add a `--tracer` option which hosts a web server that shows the line by line execution of cairo code along with memory registers [#1265](https://github.com/lambdaclass/cairo-vm/pull/1265) + +* feat: Fix error handling in `initialize_state`[#1657](https://github.com/lambdaclass/cairo-vm/pull/1657) + +* feat: Make air public inputs deserializable [#1657](https://github.com/lambdaclass/cairo-vm/pull/1648) + +* feat: Show only layout builtins in air private input [#1651](https://github.com/lambdaclass/cairo-vm/pull/1651) + +* feat: Sort builtin segment info upon serialization for Cairo PIE [#1654](https://github.com/lambdaclass/cairo-vm/pull/1654) + +* feat: Fix output serialization for cairo 1 [#1645](https://github.com/lambdaclass/cairo-vm/pull/1645) + * Reverts changes added by #1630 + * Extends the serialization of Arrays added by the `print_output` flag to Spans and Dictionaries + * Now dereferences references upon serialization + +* feat: Add flag to append return values to output segment when not running in proof_mode [#1646](https://github.com/lambdaclass/cairo-vm/pull/1646) + * Adds the flag `append_return_values` to both the CLI and `Cairo1RunConfig` struct. + * Enabling flag will add the output builtin and the necessary instructions to append the return values to the output builtin's memory segment. + +* feat: Compute program hash chain [#1647](https://github.com/lambdaclass/cairo-vm/pull/1647) + +* feat: Add cairo1-run output pretty-printing for felts, arrays/spans and dicts [#1630](https://github.com/lambdaclass/cairo-vm/pull/1630) + +* feat: output builtin features for bootloader support [#1580](https://github.com/lambdaclass/cairo-vm/pull/1580) + +#### [1.0.0-rc1] - 2024-02-23 + +* Bump `starknet-types-core` dependency version to 0.0.9 [#1628](https://github.com/lambdaclass/cairo-vm/pull/1628) + +* feat: Implement `Display` for `MemorySegmentManager`[#1606](https://github.com/lambdaclass/cairo-vm/pull/1606) + +* fix: make Felt252DictEntryUpdate work with MaybeRelocatable instead of only Felt [#1624](https://github.com/lambdaclass/cairo-vm/pull/1624). + +* chore: bump `cairo-lang-` dependencies to 2.5.4 [#1629](https://github.com/lambdaclass/cairo-vm/pull/1629) + +* chore: bump `cairo-lang-` dependencies to 2.5.3 [#1596](https://github.com/lambdaclass/cairo-vm/pull/1596) + +* refactor: Refactor `cairo1-run` crate [#1601](https://github.com/lambdaclass/cairo-vm/pull/1601) + * Add function `cairo_run_program` & struct `Cairo1RunConfig` in `cairo1-run::cairo_run` module. + * Function `serialize_output` & structs `FuncArg` and `Error` in crate `cairo1-run` are now public. + +* feat(BREAKING): Add `allow_missing_builtins` flag [#1600](https://github.com/lambdaclass/cairo-vm/pull/1600) + + This new flag will skip the check that all builtins used by the program need to be present in the selected layout if enabled. It will also be enabled by default when running in proof_mode. + + * Add `allow_missing_builtins` flag to `cairo-vm-cli` crate + * Add `allow_missing_builtins` field to `CairoRunConfig` struct + * Add `allow_missing_builtins` boolean argument to `CairoRunner` methods `initialize` & `initialize_builtins` + +* feat: Append return values to the output segment when running cairo1-run in proof_mode [#1597](https://github.com/lambdaclass/cairo-vm/pull/1597) + * Add instructions to the proof_mode header to copy return values to the output segment before initiating the infinite loop + * Output builtin is now always included when running cairo 1 programs in proof_mode + +* feat: deserialize AIR private input [#1589](https://github.com/lambdaclass/cairo-vm/pull/1589) + +* feat(BREAKING): Remove unecessary conversion functions between `Felt` & `BigUint`/`BigInt` [#1562](https://github.com/lambdaclass/cairo-vm/pull/1562) + * Remove the following functions: + * felt_from_biguint + * felt_from_bigint + * felt_to_biguint + * felt_to_bigint + +* perf: optimize instruction cache allocations by using `VirtualMachine::load_data` [#1441](https://github.com/lambdaclass/cairo-vm/pull/1441) + * feat: Add `print_output` flag to `cairo-1` crate [#1575] (https://github.com/lambdaclass/cairo-vm/pull/1575) * bugfixes(BREAKING): Fix memory hole count inconsistencies #[1585] (https://github.com/lambdaclass/cairo-vm/pull/1585) diff --git a/CODEOWNERS b/CODEOWNERS index 6d1f46e986..4e1812b071 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @igaray @Oppen @fmoletta @entropidelic @juanbono @pefontana +* @igaray @Oppen @fmoletta @juanbono @pefontana diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0811b93ec7..fea1f676b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -138,6 +138,15 @@ Enhancement suggestions are tracked as [GitHub issues](https://github.com/lambda - `merge` - `wip` +### Labels + +We recommend using the corresponding labels for each PR's purpose, the most commonly used labels include: + +- `documentation`: Improvements or additions to documentation +- `tests`: Implementation of tests +- `pipelines`: Improving CI/CD workflows +- `enhancement`: Implementation of new features +- `performance`: Performance-related improvements ## Attribution This guide is based on the **contributing.md**. [Make your own](https://contributing.md/)! diff --git a/Cargo.lock b/Cargo.lock index 4c72f36e19..d51294e05e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -10,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -21,9 +30,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -32,9 +41,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" dependencies = [ "cfg-if", "once_cell", @@ -51,6 +60,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -65,9 +89,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" dependencies = [ "anstyle", "anstyle-parse", @@ -79,43 +103,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arbitrary" @@ -140,7 +164,7 @@ dependencies = [ "digest", "itertools 0.10.5", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "paste", "rustc_version", "zeroize", @@ -163,7 +187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "proc-macro2", "quote", "syn 1.0.109", @@ -186,7 +210,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", ] @@ -211,12 +235,109 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-compression" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd 0.13.0", + "zstd-safe 7.0.0", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64ct" version = "1.6.0" @@ -255,9 +376,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bitvec" @@ -280,11 +401,32 @@ dependencies = [ "generic-array", ] +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byte-slice-cast" @@ -298,6 +440,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "bzip2" version = "0.4.4" @@ -321,39 +469,36 @@ dependencies = [ [[package]] name = "cairo-felt" -version = "0.8.7" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5972097b8800ca5dffb458040e74c724a2ac4fa4b5b480b50f5b96c7e67d6427" +checksum = "ae932292b9ba497a4e892b56aa4e0c6f329a455180fdbdc132700dfe68d9b153" dependencies = [ "lazy_static", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "serde", ] [[package]] name = "cairo-lang-casm" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24abd6752c41f3d2276fba63fa0434875ccf6e7cbcdebfebc790db1201eb0892" +checksum = "8ceb71a4cbf5b474bd671c79b2c05e8168a97199bfea1c01ef63b1bdaac3db03" dependencies = [ "cairo-lang-utils", "indoc", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "parity-scale-codec", - "parity-scale-codec-derive", - "schemars", "serde", - "thiserror", ] [[package]] name = "cairo-lang-compiler" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5699f44b183ddc2982976efdd72bbdfafc13a64f9593b44eb86f8a335f3b90da" +checksum = "95c1aab3213462c5b7c21508f1a4330bdf0766c90e6dd4ed79b0002c2b96a715" dependencies = [ "anyhow", "cairo-lang-defs", @@ -367,25 +512,24 @@ dependencies = [ "cairo-lang-sierra-generator", "cairo-lang-syntax", "cairo-lang-utils", - "itertools 0.11.0", "salsa", "thiserror", ] [[package]] name = "cairo-lang-debug" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a52b381fab22b723818692fa93aafc2e1490a79a4c8bd856e8996f1253f16a8" +checksum = "03623ba892200c6b3c55fab260d4aa0bff833d6bcecdb1fb022565ac00d5a683" dependencies = [ "cairo-lang-utils", ] [[package]] name = "cairo-lang-defs" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d436dcaa5a3ea69f60b990036d23dc3e54adc623c14cff824cb1230f974ce44" +checksum = "09131755b08a485322656e061ad05602215a198dd4a2daf3897e64dc76e7544e" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -400,9 +544,9 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07771c7268044b6a7be828a4f4938bb823944efe6668a974bf5e52a6801ef366" +checksum = "3b8185cc9472c648ac9db970ce558595c71259eebd55d25a502fe569cb871448" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -412,9 +556,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fc8c224c0aaadc01c961fac234e8d8d3563a8fbb8544186a69969765a0c2a5" +checksum = "8ae71750096b64d4dd54dd2c39ef50651bb4aff4bc829e3d07549a5035620e0a" dependencies = [ "cairo-lang-utils", "good_lp", @@ -422,9 +566,9 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d62a519bd68f158cd1b5ee2f1f1dc2aa916a8dcb14914444846d39ff8fb33789" +checksum = "1819ef5a5396df695dcec993500c46bc44c309590b503da26965c873dfe8a84a" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -436,9 +580,9 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989744e09f351ff24a0bc076dba8e3420ab957b99edc46acde58a484ebb09ed9" +checksum = "0968f0da6117dca1a70d6ac7d2e252d8b1710f333458c54ce08dbef1c0323881" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -450,11 +594,10 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "id-arena", - "indexmap 2.1.0", "itertools 0.11.0", "log", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "salsa", "smol_str", @@ -462,9 +605,9 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5b262ae2d11b4d5783a8b66d8e31cbeab45bb4e14d6ddb13ba280e9c41824" +checksum = "ae556e49c0a90d30e52f068b0fb5ed4d419766661d3713a1644f3894a9255a5a" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -474,7 +617,7 @@ dependencies = [ "colored", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "salsa", "smol_str", "unescaper", @@ -482,9 +625,9 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcfe1e269ab2027bad187d9c61c7e1e324374c722b75f3a7d7fba77c977f8ca" +checksum = "a8d319f3e84ff679159f97e3baa1d918d369ba9e3ade5ad490e0a9e4eca19591" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -501,20 +644,20 @@ dependencies = [ [[package]] name = "cairo-lang-proc-macros" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bc4f93f28bda29d879acb9b9e26b32108591225a507ffb5aff9bbf58524c4f" +checksum = "fef002aac874d76492eb9577dab663f9a84fe4584b4215c7ebfda7d025fcadae" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] name = "cairo-lang-project" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d490a3d00dd45228c1691c390f177449b45a907a2cb4b3ad8f305faea82a0c" +checksum = "7f384c26e6907de9c94b44051e386498159e8c9e1567b9b1eae9c22e16ff17e5" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -526,9 +669,9 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcc25adf813972129dcac6c7d87026d47644f3d4e975c042d27e1166a2a0489" +checksum = "311434caae9542b7c442ac69a04e3c8eaa477654f215abe0bd7dfd3c0de70669" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -543,7 +686,7 @@ dependencies = [ "indoc", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "salsa", "smol_str", @@ -551,11 +694,12 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc9571dbb143e33979fc02d38bbb4d7b608d6f53cde585b08551bbedfb0c217" +checksum = "52c00c34fcaf97bbc4111d1631af8c65838841a38b3502b5bbc04355b7d46982" dependencies = [ "anyhow", + "cairo-felt", "cairo-lang-utils", "const-fnv1a-hash", "convert_case", @@ -564,7 +708,7 @@ dependencies = [ "lalrpop", "lalrpop-util", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "regex", "salsa", "serde", @@ -576,37 +720,39 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16894bfe0072f82b549e4b2be42c7dc8f0611ac5049dfb069b95b10c51ec7cb5" +checksum = "c99a0be021b359c51383cce4372cb1061f7d53438d80f208c56af2154583c98e" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", "cairo-lang-sierra-type-size", "cairo-lang-utils", "itertools 0.11.0", + "num-traits 0.2.18", "thiserror", ] [[package]] name = "cairo-lang-sierra-gas" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fbc8baef18b3c315d3fb7a0cf59f0ee14df5cefc7dd147598248cdb7b2252d" +checksum = "f273d4de9d30e556e72ebe2751f9ed6bf3d84a70f6c76f52b178c24cddb12e43" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", "cairo-lang-sierra-type-size", "cairo-lang-utils", "itertools 0.11.0", + "num-traits 0.2.18", "thiserror", ] [[package]] name = "cairo-lang-sierra-generator" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75700bf5fd1c1cdd8ca29af338c65de8b03c905472f9bdce22b3034f3f3755d9" +checksum = "734f72e9e8b1ec7a96208aa8dfba87ca1614188e3646ae67c519afe707569490" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -618,7 +764,6 @@ dependencies = [ "cairo-lang-sierra", "cairo-lang-syntax", "cairo-lang-utils", - "indexmap 2.1.0", "itertools 0.11.0", "num-bigint", "once_cell", @@ -628,9 +773,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0bc8edaf95bdb9577c6b801c36b24538ec08042e1d74b98fc08d50621427061" +checksum = "842ae37ee3f1cd06b926aceb480fd70b84300aae82e9606b876678d30c21649a" dependencies = [ "assert_matches", "cairo-felt", @@ -643,15 +788,15 @@ dependencies = [ "indoc", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "thiserror", ] [[package]] name = "cairo-lang-sierra-type-size" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b028f3e06e150005e82b07500d4ea509ee8350f841d5645fbcf00bb49c4537" +checksum = "f969cbaf81f3beb1dc693674fc792a815bf8fc13471227020a5faf309d5faf80" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -659,9 +804,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f55ffe2cbd277b6f3040e23bde028ae0b68e8e4910a9dd1c2f78ed668974d2a" +checksum = "67cd2d120f39369c7bd7d124dee638c250495054030d01d4e1d1b88f0063bd80" dependencies = [ "anyhow", "cairo-felt", @@ -671,6 +816,7 @@ dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-lowering", + "cairo-lang-plugins", "cairo-lang-semantic", "cairo-lang-sierra", "cairo-lang-sierra-generator", @@ -684,7 +830,7 @@ dependencies = [ "itertools 0.11.0", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "serde", "serde_json", @@ -696,15 +842,15 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6d745c72ac1cef893239d36bc749742d2622136ffc1434a2c70b07096d02de0" +checksum = "552d3438fec55832976bc7c7d7490100e8ce7385d3f3f1539f9a46fffa2197c6" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", "cairo-lang-utils", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "salsa", "smol_str", "unescaper", @@ -712,9 +858,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c9f119185b736b5318325e7a0fc1378b706116c1c558e1ced1bdf55367813b" +checksum = "9dab4d07bd78658f0fdc3fd20f1236bc3e6ebdd8a8fc72ece95a5dd03b7a09da" dependencies = [ "genco", "xshell", @@ -722,22 +868,22 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.4.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343ac08a5b9d34c9f4bbac7249453a31edad4cf4ff54487197cc344f8293dc4f" +checksum = "12d0939f42d40fb1d975cae073d7d4f82d83de4ba2149293115525245425f909" dependencies = [ - "indexmap 2.1.0", + "hashbrown 0.14.3", + "indexmap 2.2.3", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", - "parity-scale-codec", + "num-traits 0.2.18", "schemars", "serde", ] [[package]] name = "cairo-vm" -version = "1.0.0-rc0" +version = "1.0.0-rc1" dependencies = [ "anyhow", "arbitrary", @@ -750,7 +896,7 @@ dependencies = [ "cairo-lang-starknet", "criterion", "generic-array", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "hex", "iai-callgrind", "keccak", @@ -760,7 +906,7 @@ dependencies = [ "num-bigint", "num-integer", "num-prime", - "num-traits 0.2.17", + "num-traits 0.2.18", "proptest", "rand", "rstest", @@ -777,11 +923,12 @@ dependencies = [ [[package]] name = "cairo-vm-cli" -version = "1.0.0-rc0" +version = "1.0.0-rc1" dependencies = [ "assert_matches", "bincode", "cairo-vm", + "cairo-vm-tracer", "clap", "mimalloc", "nom", @@ -789,9 +936,28 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cairo-vm-tracer" +version = "1.0.0-rc1" +dependencies = [ + "axum", + "cairo-vm", + "include_dir", + "mime_guess", + "num-bigint", + "num-traits 0.2.18", + "serde", + "thiserror-no-std", + "tokio", + "tower", + "tower-http", + "tracing", + "tracing-subscriber", +] + [[package]] name = "cairo1-run" -version = "1.0.0-rc0" +version = "1.0.0-rc1" dependencies = [ "assert_matches", "bincode", @@ -807,6 +973,7 @@ dependencies = [ "clap", "itertools 0.11.0", "mimalloc", + "num-traits 0.2.18", "rstest", "thiserror", ] @@ -819,11 +986,10 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" dependencies = [ - "jobserver", "libc", ] @@ -835,9 +1001,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -846,15 +1012,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -872,9 +1038,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -882,9 +1048,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -894,21 +1060,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -918,13 +1084,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -980,18 +1145,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -1009,7 +1174,7 @@ dependencies = [ "criterion-plot", "is-terminal", "itertools 0.10.5", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "oorandom", "plotters", @@ -1034,36 +1199,28 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1120,7 +1277,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] @@ -1169,9 +1326,9 @@ checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "ena" @@ -1190,12 +1347,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1226,6 +1383,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "funty" version = "2.0.0" @@ -1234,9 +1400,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1249,9 +1415,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1259,15 +1425,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1276,44 +1442,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1346,7 +1512,7 @@ checksum = "d4cf186fea4af17825116f72932fe52cce9a13bae39ff63b4dc0cfdb3fb4bde1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] @@ -1361,9 +1527,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -1372,6 +1538,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "good_lp" version = "1.7.0" @@ -1384,9 +1556,13 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -1394,16 +1570,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.9", "allocator-api2", "serde", ] @@ -1425,9 +1601,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -1437,7 +1613,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hint_accountant" -version = "1.0.0-rc0" +version = "1.0.0-rc1" dependencies = [ "cairo-vm", "serde", @@ -1453,6 +1629,78 @@ dependencies = [ "digest", ] +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper_threading" +version = "1.0.0-rc1" +dependencies = [ + "cairo-vm", + "rayon", + "tracing", +] + [[package]] name = "iai-callgrind" version = "0.3.1" @@ -1476,6 +1724,25 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indent" version = "0.1.1" @@ -1495,12 +1762,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "serde", ] @@ -1528,15 +1795,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "iri-string" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21859b667d66a4c1dacd9df0863b3efb65785474255face87f5bca39dd8407c0" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", - "rustix", - "windows-sys", + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -1559,33 +1836,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "jobserver" -version = "0.1.27" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -1622,13 +1890,26 @@ dependencies = [ "regex", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4c222d5b2fdc0faf702d3ab361d14589b097f40eac9dc550e27083483edc65" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2", + "sha3", +] + [[package]] name = "lambdaworks-math" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6c4d0ddd1fcd235be5196b1bcc404f89ad3e911f4c190fa01459e05dbf40f8" +checksum = "9ee7dcab3968c71896b8ee4dc829147acc918cffe897af6265b1894527fe3add" dependencies = [ - "thiserror", + "serde", + "serde_json", ] [[package]] @@ -1642,9 +1923,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.150" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libm" @@ -1668,16 +1949,16 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -1704,6 +1985,12 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "matrixmultiply" version = "0.2.4" @@ -1715,26 +2002,33 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] -name = "memoffset" -version = "0.9.0" +name = "mimalloc" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" dependencies = [ - "autocfg", + "libmimalloc-sys", ] [[package]] -name = "mimalloc" -version = "0.1.39" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" dependencies = [ - "libmimalloc-sys", + "mime", + "unicase", ] [[package]] @@ -1755,23 +2049,34 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] -name = "ndarray" -version = "0.13.1" +name = "mio" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac06db03ec2f46ee0ecdca1a1c34a99c0d188a0d83439b84bf0cb4b386e4ab09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ - "matrixmultiply", - "num-complex", + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "ndarray" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac06db03ec2f46ee0ecdca1a1c34a99c0d188a0d83439b84bf0cb4b386e4ab09" +dependencies = [ + "matrixmultiply", + "num-complex", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rawpointer", ] @@ -1791,6 +2096,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -1799,7 +2114,7 @@ checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", "serde", ] @@ -1811,17 +2126,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" dependencies = [ "autocfg", - "num-traits 0.2.17", + "num-traits 0.2.18", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -1832,7 +2152,7 @@ checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" dependencies = [ "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -1847,7 +2167,7 @@ dependencies = [ "num-bigint", "num-integer", "num-modular", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", ] @@ -1857,24 +2177,43 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -1882,24 +2221,31 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", + "parity-scale-codec-derive", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1952,7 +2298,7 @@ dependencies = [ "libc", "redox_syscall 0.4.1", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1990,6 +2336,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "petgraph" version = "0.6.4" @@ -1997,7 +2349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.3", ] [[package]] @@ -2015,6 +2367,26 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2029,9 +2401,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" @@ -2039,7 +2411,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", "plotters-backend", "plotters-svg", "wasm-bindgen", @@ -2081,19 +2453,18 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "toml_edit 0.20.7", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2106,9 +2477,9 @@ checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.1", + "bitflags 2.4.2", "lazy_static", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", "rand_chacha", "rand_xorshift", @@ -2126,9 +2497,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2186,9 +2557,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -2196,9 +2567,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -2235,9 +2606,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -2247,9 +2618,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -2270,9 +2641,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "relative-path" -version = "1.9.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" [[package]] name = "rfc6979" @@ -2310,6 +2681,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2327,15 +2704,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2358,9 +2735,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "salsa" @@ -2439,28 +2816,28 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] @@ -2476,21 +2853,43 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ + "form_urlencoded", + "itoa", + "ryu", "serde", ] @@ -2526,6 +2925,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -2543,19 +2951,29 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smol_str" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -2584,7 +3002,7 @@ dependencies = [ "hmac", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rfc6979", "sha2", "starknet-crypto-codegen", @@ -2601,23 +3019,23 @@ checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ "starknet-curve", "starknet-ff", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] name = "starknet-curve" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68a0d87ae56572abf83ddbfd44259a7c90dbeeee1629a1ffe223e7f9a8f3052" +checksum = "63c454fecadfb3fe56ee82c405439d663c8a037667cc9d8e4acb1fb17e15b1af" dependencies = [ "starknet-ff", ] [[package]] name = "starknet-ff" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7584bc732e4d2a8ccebdd1dda8236f7940a79a339e30ebf338d45c329659e36c" +checksum = "067419451efdea1ee968df8438369960c167e0e905c05b84afd074f50e1d6f3d" dependencies = [ "ark-ff", "crypto-bigint", @@ -2627,17 +3045,18 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.0.6" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6b868f545d43b474c2c00e9349c489fdeb7ff17eb00cdf339744ac4cae0930" +checksum = "6d53160556d1f23425100f42b3230df747ea05763efee685a2cd939dfb640701" dependencies = [ "arbitrary", "bitvec", + "lambdaworks-crypto", "lambdaworks-math", "lazy_static", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "serde", ] @@ -2656,9 +3075,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "subtle" @@ -2679,15 +3098,21 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "tap" version = "1.0.1" @@ -2696,15 +3121,14 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2720,22 +3144,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] @@ -2758,13 +3182,24 @@ dependencies = [ "thiserror-impl-no-std", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", + "num-conv", "powerfmt", "serde", "time-core", @@ -2795,16 +3230,57 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.0", + "toml_edit 0.22.6", ] [[package]] @@ -2818,28 +3294,150 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.3", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.2", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "async-compression", + "base64", + "bitflags 2.4.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "httpdate", + "iri-string", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "uuid", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.17.0" @@ -2854,13 +3452,22 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unescaper" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f0f68e58d297ba8b22b8b5a96a87b863ba6bb46aaf51e19a4b02c5a6dd5b7f" +checksum = "0adf6ad32eb5b3cadff915f7b770faaac8f7ff0476633aa29eb0d9584d889d34" dependencies = [ "thiserror", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -2869,9 +3476,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-xid" @@ -2885,6 +3492,21 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -2910,6 +3532,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2918,9 +3549,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2928,24 +3559,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" dependencies = [ "cfg-if", "js-sys", @@ -2955,9 +3586,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2965,28 +3596,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "wasm-bindgen-test" -version = "0.3.38" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6433b7c56db97397842c46b67e11873eda263170afeb3a2dc74a7cb370fee0d" +checksum = "143ddeb4f833e2ed0d252e618986e18bfc7b0e52f2d28d77d05b2f045dd8eb61" dependencies = [ "console_error_panic_hook", "js-sys", @@ -2998,18 +3629,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.38" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735" +checksum = "a5211b7550606857312bba1d978a8ec75692eae187becc5e680444fffc5e6f89" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] name = "wasm-demo" -version = "1.0.0-rc0" +version = "1.0.0-rc1" dependencies = [ "cairo-vm", "console_error_panic_hook", @@ -3020,9 +3651,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -3065,7 +3696,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.3", ] [[package]] @@ -3074,13 +3714,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +dependencies = [ + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", ] [[package]] @@ -3089,47 +3744,98 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" -version = "0.5.19" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178" dependencies = [ "memchr", ] @@ -3160,22 +3866,22 @@ checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e" [[package]] name = "zerocopy" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] @@ -3195,7 +3901,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.50", ] [[package]] @@ -3215,7 +3921,7 @@ dependencies = [ "pbkdf2", "sha1", "time", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -3224,7 +3930,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe 7.0.0", ] [[package]] @@ -3237,6 +3952,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.9+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index 426e992ca6..f3825f5efa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,9 @@ members = [ "vm", "hint_accountant", "examples/wasm-demo", - "cairo1-run" + "cairo1-run", + "cairo-vm-tracer", + "examples/hyper_threading" ] default-members = [ "cairo-vm-cli", @@ -18,7 +20,7 @@ exclude = ["ensure-no_std"] resolver = "2" [workspace.package] -version = "1.0.0-rc0" +version = "1.0.0-rc1" edition = "2021" license = "Apache-2.0" repository = "https://github.com/lambdaclass/cairo-vm/" @@ -26,7 +28,8 @@ readme = "README.md" keywords = ["starknet", "cairo", "vm", "wasm", "no_std"] [workspace.dependencies] -cairo-vm = { path = "./vm", version = "1.0.0-rc0", default-features = false } +cairo-vm = { path = "./vm", version = "1.0.0-rc1", default-features = false } +cairo-vm-tracer = { path = "./cairo-vm-tracer", version = "1.0.0-rc1", default-features = false } mimalloc = { version = "0.1.37", default-features = false } num-bigint = { version = "0.4", default-features = false, features = [ "serde", @@ -63,14 +66,14 @@ thiserror-no-std = { version = "2.0.2", default-features = false } bitvec = { version = "1", default-features = false, features = ["alloc"] } # Dependencies for cairo-1-hints feature -cairo-lang-starknet = { version = "2.4.2", default-features = false } -cairo-lang-casm = { version = "2.4.2", default-features = false } +cairo-lang-starknet = { version = "2.5.4", default-features = false } +cairo-lang-casm = { version = "2.5.4", default-features = false } -cairo-lang-compiler = { version = "2.4.2", default-features = false } -cairo-lang-sierra-to-casm = { version = "2.4.2", default-features = false } -cairo-lang-sierra = { version = "2.4.2", default-features = false } -cairo-lang-runner = { version = "2.4.2", default-features = false } -cairo-lang-utils = { version = "2.4.2", default-features = false } +cairo-lang-compiler = { version = "2.5.4", default-features = false } +cairo-lang-sierra-to-casm = { version = "2.5.4", default-features = false } +cairo-lang-sierra = { version = "2.5.4", default-features = false } +cairo-lang-runner = { version = "2.5.4", default-features = false } +cairo-lang-utils = { version = "2.5.4", default-features = false } # TODO: check these dependencies for wasm compatibility ark-ff = { version = "0.4.2", default-features = false } diff --git a/Makefile b/Makefile index 18c7774bc9..86b6d7d7df 100644 --- a/Makefile +++ b/Makefile @@ -13,13 +13,14 @@ ifndef PROPTEST_CASES endif .PHONY: build-cairo-1-compiler build-cairo-1-compiler-macos build-cairo-2-compiler build-cairo-2-compiler-macos \ - deps deps-macos cargo-deps build run check test clippy coverage benchmark \ + deps deps-macos cargo-deps build run check test clippy coverage benchmark flamegraph\ compare_benchmarks_deps compare_benchmarks docs clean \ compare_trace_memory compare_trace compare_memory compare_pie compare_all_no_proof \ compare_trace_memory_proof compare_all_proof compare_trace_proof compare_memory_proof compare_air_public_input compare_air_private_input\ + hyper-threading-benchmarks \ cairo_bench_programs cairo_proof_programs cairo_test_programs cairo_1_test_contracts cairo_2_test_contracts \ cairo_trace cairo-vm_trace cairo_proof_trace cairo-vm_proof_trace \ - fuzzer-deps fuzzer-run-cairo-compiled fuzzer-run-hint-diff build-cairo-lang hint-accountant \ + fuzzer-deps fuzzer-run-cairo-compiled fuzzer-run-hint-diff build-cairo-lang hint-accountant \ create-proof-programs-symlinks \ $(RELBIN) $(DBGBIN) # Proof mode consumes too much memory with cairo-lang to execute @@ -48,6 +49,10 @@ PROOF_BENCH_DIR=cairo_programs/benchmarks PROOF_BENCH_FILES:=$(wildcard $(PROOF_BENCH_DIR)/*.cairo) PROOF_COMPILED_BENCHES:=$(patsubst $(PROOF_BENCH_DIR)/%.cairo, $(PROOF_BENCH_DIR)/%.json, $(PROOF_BENCH_FILES)) +MOD_BUILTIN_TEST_PROOF_DIR=cairo_programs/mod_builtin_feature/proof +MOD_BUILTIN_TEST_PROOF_FILES:=$(wildcard $(MOD_BUILTIN_TEST_PROOF_DIR)/*.cairo) +COMPILED_MOD_BUILTIN_PROOF_TESTS:=$(patsubst $(MOD_BUILTIN_TEST_PROOF_DIR)/%.cairo, $(MOD_BUILTIN_TEST_PROOF_DIR)/%.json, $(MOD_BUILTIN_TEST_PROOF_FILES)) + $(TEST_PROOF_DIR)/%.json: $(TEST_PROOF_DIR)/%.cairo cairo-compile --cairo_path="$(TEST_PROOF_DIR):$(PROOF_BENCH_DIR)" $< --output $@ --proof_mode @@ -60,6 +65,9 @@ $(TEST_PROOF_DIR)/%.trace $(TEST_PROOF_DIR)/%.memory $(TEST_PROOF_DIR)/%.air_pub $(PROOF_BENCH_DIR)/%.json: $(PROOF_BENCH_DIR)/%.cairo cairo-compile --cairo_path="$(TEST_PROOF_DIR):$(PROOF_BENCH_DIR)" $< --output $@ --proof_mode +$(MOD_BUILTIN_TEST_PROOF_DIR)/%.json: $(MOD_BUILTIN_TEST_PROOF_DIR)/%.cairo + cairo-compile --cairo_path="$(MOD_BUILTIN_TEST_PROOF_DIR):$(MOD_BUILTIN_TEST_PROOF_DIR)" $< --output $@ --proof_mode + # ====================== # Run without proof mode # ====================== @@ -86,6 +94,10 @@ PRINT_TEST_DIR=cairo_programs/print_feature PRINT_TEST_FILES:=$(wildcard $(PRINT_TEST_DIR)/*.cairo) COMPILED_PRINT_TESTS:=$(patsubst $(PRINT_TEST_DIR)/%.cairo, $(PRINT_TEST_DIR)/%.json, $(PRINT_TEST_FILES)) +MOD_BUILTIN_TEST_DIR=cairo_programs/mod_builtin_feature +MOD_BUILTIN_TEST_FILES:=$(wildcard $(MOD_BUILTIN_TEST_DIR)/*.cairo) +COMPILED_MOD_BUILTIN_TESTS:=$(patsubst $(MOD_BUILTIN_TEST_DIR)/%.cairo, $(MOD_BUILTIN_TEST_DIR)/%.json, $(MOD_BUILTIN_TEST_FILES)) + NORETROCOMPAT_DIR:=cairo_programs/noretrocompat NORETROCOMPAT_FILES:=$(wildcard $(NORETROCOMPAT_DIR)/*.cairo) COMPILED_NORETROCOMPAT_TESTS:=$(patsubst $(NORETROCOMPAT_DIR)/%.cairo, $(NORETROCOMPAT_DIR)/%.json, $(NORETROCOMPAT_FILES)) @@ -168,7 +180,7 @@ $(CAIRO_2_CONTRACTS_TEST_DIR)/%.casm: $(CAIRO_2_CONTRACTS_TEST_DIR)/%.sierra # ====================== CAIRO_2_REPO_DIR = cairo2 -CAIRO_2_VERSION = 2.4.2 +CAIRO_2_VERSION = 2.5.4 build-cairo-2-compiler-macos: @if [ ! -d "$(CAIRO_2_REPO_DIR)" ]; then \ @@ -187,17 +199,16 @@ build-cairo-2-compiler: cargo-deps: cargo install --version 0.3.1 iai-callgrind-runner cargo install --version 1.1.0 cargo-criterion - # Temporarily removed due to version issues. Installing cargo flamegraph pumps an error in rust 1.70 - # cargo install --version 0.6.1 flamegraph + cargo install --version 0.6.1 flamegraph --locked cargo install --version 1.14.0 hyperfine - cargo install --version 0.9.49 cargo-nextest + cargo install --version 0.9.49 cargo-nextest --locked cargo install --version 0.5.9 cargo-llvm-cov - cargo install --version 0.12.1 wasm-pack + cargo install --version 0.12.1 wasm-pack --locked cairo1-run-deps: cd cairo1-run; make deps -deps: cargo-deps build-cairo-1-compiler build-cairo-2-compiler cairo1-run-deps +deps: create-proof-programs-symlinks cargo-deps build-cairo-1-compiler build-cairo-2-compiler cairo1-run-deps pyenv install -s pypy3.9-7.3.9 PYENV_VERSION=pypy3.9-7.3.9 python -m venv cairo-vm-pypy-env . cairo-vm-pypy-env/bin/activate ; \ @@ -207,7 +218,7 @@ deps: cargo-deps build-cairo-1-compiler build-cairo-2-compiler cairo1-run-deps . cairo-vm-env/bin/activate ; \ pip install -r requirements.txt ; \ -deps-macos: cargo-deps build-cairo-1-compiler-macos build-cairo-2-compiler-macos cairo1-run-deps +deps-macos: create-proof-programs-symlinks cargo-deps build-cairo-1-compiler-macos build-cairo-2-compiler-macos cairo1-run-deps arch -x86_64 pyenv install -s pypy3.9-7.3.9 PYENV_VERSION=pypy3.9-7.3.9 python -m venv cairo-vm-pypy-env . cairo-vm-pypy-env/bin/activate ; \ @@ -228,8 +239,8 @@ run: check: cargo check -cairo_test_programs: $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) $(COMPILED_NORETROCOMPAT_TESTS) $(COMPILED_PRINT_TESTS) -cairo_proof_programs: $(COMPILED_PROOF_TESTS) +cairo_test_programs: $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) $(COMPILED_NORETROCOMPAT_TESTS) $(COMPILED_PRINT_TESTS) $(COMPILED_MOD_BUILTIN_TESTS) +cairo_proof_programs: $(COMPILED_PROOF_TESTS) $(COMPILED_MOD_BUILTIN_PROOF_TESTS) cairo_bench_programs: $(COMPILED_BENCHES) cairo_1_test_contracts: $(CAIRO_1_COMPILED_CASM_CONTRACTS) cairo_2_test_contracts: $(CAIRO_2_COMPILED_CASM_CONTRACTS) @@ -279,9 +290,8 @@ benchmark-action: cairo_bench_programs iai-benchmark-action: cairo_bench_programs cargo bench --bench iai_benchmark -# Temporarily removed due to version issues. Installing cargo flamegraph pumps an error in rust 1.70 -# flamegraph: -# cargo flamegraph --root --bench criterion_benchmark -- --bench +flamegraph: + cargo flamegraph --root --bench criterion_benchmark -- --bench compare_benchmarks: cairo_bench_programs cd bench && ./run_benchmarks.sh @@ -333,6 +343,7 @@ clean: rm -f $(PRINT_TEST_DIR)/*.json rm -f $(CAIRO_1_CONTRACTS_TEST_DIR)/*.sierra rm -f $(CAIRO_1_CONTRACTS_TEST_DIR)/*.casm + rm -f $(TEST_PROOF_DIR)/*.cairo rm -f $(CAIRO_2_CONTRACTS_TEST_DIR)/*.sierra rm -f $(CAIRO_2_CONTRACTS_TEST_DIR)/*.casm rm -f $(TEST_PROOF_DIR)/*.json @@ -374,3 +385,9 @@ build-cairo-lang: | $(CAIRO_LANG_REPO_DIR) hint-accountant: build-cairo-lang cargo r -p hint_accountant +create-proof-programs-symlinks: + cd cairo_programs/proof_programs; ln -s ../*.cairo . + +hyper-threading-benchmarks: cairo_bench_programs + cargo build -p hyper_threading --release && \ + sh examples/hyper_threading/hyper-threading.sh diff --git a/README.md b/README.md index 1d7d274d46..a213ad393e 100644 --- a/README.md +++ b/README.md @@ -21,42 +21,45 @@ A faster and safer implementation of the Cairo VM in Rust ## Table of Contents -- [Disclaimer](#%EF%B8%8F-disclaimer) -- [About](#-about) +- [Table of Contents](#table-of-contents) +- [📖 About](#-about) - [The Cairo language](#the-cairo-language) -- [Getting Started](#-getting-started) +- [🌅 Getting Started](#-getting-started) - [Dependencies](#dependencies) -- [Usage](#-usage) + - [Required](#required) + - [Optional](#optional) + - [Installation script](#installation-script) +- [🚀 Usage](#-usage) - [Adding cairo-vm as a dependency](#adding-cairo-vm-as-a-dependency) - - [Running cairo-vm from the CLI](#running-cairo-vm-from-cli) + - [Running cairo-vm from CLI](#running-cairo-vm-from-cli) - [Using hints](#using-hints) - [Running a function in a Cairo program with arguments](#running-a-function-in-a-cairo-program-with-arguments) - [WebAssembly Demo](#webassembly-demo) - [Testing](#testing) -- [Benchmarks](#-benchmarks) -- [Changelog](#-changelog) -- [Contributing](#-contributing) -- [Related Projects](#-related-projects) -- [Documentation](#-documentation) + - [Tracer](#tracer) +- [📊 Benchmarks](#-benchmarks) +- [📜 Changelog](#-changelog) +- [🛠 Contributing](#-contributing) +- [🌞 Related Projects](#-related-projects) +- [📚 Documentation](#-documentation) - [Cairo](#cairo) - [Original Cairo VM Internals](#original-cairo-vm-internals) - [Compilers and Interpreters](#compilers-and-interpreters) - [StarkNet](#starknet) - - [Computational Integrity and Zero-Knowledge Proofs](#computational-integrity-and-zero-knowledge-proofs) -- [License](#%EF%B8%8F-license) + - [Computational Integrity and Zero Knowledge Proofs](#computational-integrity-and-zero-knowledge-proofs) + - [Basics](#basics) + - [ZK SNARKs](#zk-snarks) + - [STARKs](#starks) +- [⚖️ License](#️-license) -## ⚠️ Disclaimer - -🚧 `cairo-vm` is still being built therefore breaking changes might happen often so use it at your own risk. 🚧 -Cargo doesn't comply with [semver](https://semver.org/), so we advise to pin the version to 0.1.0. This can be done adding `cairo-vm = "0.1.0"` to your Cargo.toml ## 📖 About Cairo VM is the virtual machine for the [Cairo language](https://www.cairo-lang.org/). -There's an older version of [Cairo VM](https://github.com/starkware-libs/cairo-lang) written in Python, which is **currently in production**. +Previously, there was a version of [Cairo VM](https://github.com/starkware-libs/cairo-lang) written in Python, which **was used in production**. -This repository contains the newer version, written in Rust. It's faster and has safer and more expressive typing. Once completed, it will replace the older one as the sole Cairo VM. +This repository contains the newer version, written in Rust. It's faster and has safer and more expressive typing. Now in production, it has replaced the older Python version to become the primary Cairo VM. ### The Cairo language @@ -72,7 +75,7 @@ It's Turing-complete and it was created by [Starkware](https://starkware.co/) as These are needed in order to compile and use the project. -- [Rust 1.70.0 or newer](https://www.rust-lang.org/tools/install) +- [Rust 1.74.1 or newer](https://www.rust-lang.org/tools/install) - Cargo #### Optional @@ -105,21 +108,17 @@ You can then activate this environment by running You can add the following to your rust project's `Cargo.toml`: ```toml -cairo-vm = { version = '0.7.0', features = ["lambdaworks-felt"] } +cairo-vm = { version = '0.7.0'} ``` -The `features = ["lambdaworks-felt"]` part adds usage of [`lambdaworks-math`](https://github.com/lambdaclass/lambdaworks) as the backend for `Felt252`. This improves performance by more than 20%, and will be the default in the future. - ### Running cairo-vm from CLI To run programs from the command line, first compile the repository from the cairo-vm-cli folder: ```bash -cd cairo-vm-cli; cargo build --release -F lambdaworks-felt; cd .. +cd cairo-vm-cli; cargo build --release; cd .. ``` -The `-F lambdaworks-felt` part adds usage of [`lambdaworks-math`](https://github.com/lambdaclass/lambdaworks) as the backend for `Felt252`. This improves performance by more than 20%, and will be the default in the future. - Once the binary is built, it can be found in `target/release/` under the name `cairo-vm-cli`. In order to compile Cairo programs you need to activate the environment created while installing dependencies. To start it, run: @@ -169,7 +168,7 @@ The cairo-vm-cli supports the following optional arguments: - `--proof_mode`: Runs the program in proof_mode -- `--secure_run`: Runs security checks after execution. Enabled by default when not in proof_mode +- `--secure_run`: Runs security checks after execution. Enabled by default when not in proof_mode. - `--air_public_input `: Receives the name of a file and outputs the AIR public inputs into it. Can only be used if proof_mode is also enabled. @@ -177,6 +176,8 @@ The cairo-vm-cli supports the following optional arguments: - `--cairo_pie_output `: Receives the name of a file and outputs the Cairo PIE into it. Can only be used if proof_mode, is not enabled. +- `--allow_missing_builtins`: Disables the check that all builtins used by the program need to be included in the selected layout. Enabled by default when in proof_mode. + For example, to obtain the air public inputs from a fibonacci program run, we can run : ```bash @@ -262,6 +263,10 @@ Now that you have the dependencies necessary to run the test suite you can run: make test ``` +### Tracer + +Cairo-vm offers a tracer which gives you a visualization of how your memory and registers change line after line as the VM executes the code. You can read more about it [here](./docs/tracer/README.md) + ## 📊 Benchmarks Running a [Cairo program](./cairo_programs/benchmarks/big_fibonacci.cairo) that gets the 1.5 millionth Fibonacci number we got the following benchmarks: @@ -290,6 +295,12 @@ Run only the `iai_benchmark` benchmark suite with cargo: cargo bench --bench iai_benchmark ``` +Benchmark the `cairo-vm` in a hyper-threaded environment with the [`examples/hyper_threading/ crate`](examples/hyper_threading/) +```bash +make hyper-threading-benchmarks +``` + + ## 📜 Changelog Keeps track of the latest changes [here](CHANGELOG.md). diff --git a/bench/criterion_benchmark.rs b/bench/criterion_benchmark.rs index d1f4029a4f..48b095cc1f 100644 --- a/bench/criterion_benchmark.rs +++ b/bench/criterion_benchmark.rs @@ -4,10 +4,8 @@ use cairo_vm::{ }; use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; -#[cfg(feature = "with_mimalloc")] use mimalloc::MiMalloc; -#[cfg(feature = "with_mimalloc")] #[global_allocator] static ALLOC: MiMalloc = MiMalloc; @@ -52,7 +50,9 @@ fn load_program_data(c: &mut Criterion) { VirtualMachine::new(false), ) }, - |(mut runner, mut vm)| _ = black_box(runner.initialize(black_box(&mut vm)).unwrap()), + |(mut runner, mut vm)| { + _ = black_box(runner.initialize(black_box(&mut vm), false).unwrap()) + }, BatchSize::SmallInput, ) }); diff --git a/bench/iai_benchmark.rs b/bench/iai_benchmark.rs index b12c209514..02666c93c4 100644 --- a/bench/iai_benchmark.rs +++ b/bench/iai_benchmark.rs @@ -6,10 +6,8 @@ use cairo_vm::{ vm::{runners::cairo_runner::CairoRunner, vm_core::VirtualMachine}, }; -#[cfg(feature = "with_mimalloc")] use mimalloc::MiMalloc; -#[cfg(feature = "with_mimalloc")] #[global_allocator] static ALLOC: MiMalloc = MiMalloc; @@ -51,7 +49,7 @@ fn build_runner_helper() -> (CairoRunner, VirtualMachine) { #[inline(never)] fn load_program_data() { let (mut runner, mut vm) = build_runner_helper(); - _ = black_box(runner.initialize(black_box(&mut vm)).unwrap()); + _ = black_box(runner.initialize(black_box(&mut vm), false).unwrap()); } main!( diff --git a/cairo-vm-cli/Cargo.toml b/cairo-vm-cli/Cargo.toml index 572c4db8af..0b63d2745e 100644 --- a/cairo-vm-cli/Cargo.toml +++ b/cairo-vm-cli/Cargo.toml @@ -9,6 +9,7 @@ keywords.workspace = true [dependencies] cairo-vm = { workspace = true, features = ["std"] } +cairo-vm-tracer = { workspace = true, optional = true } clap = { version = "4.3.10", features = ["derive"] } mimalloc = { version = "0.1.37", default-features = false, optional = true } nom = "7" @@ -21,4 +22,6 @@ rstest = "0.17.0" [features] default = ["with_mimalloc"] -with_mimalloc = ["cairo-vm/with_mimalloc", "dep:mimalloc"] +with_mimalloc = ["dep:mimalloc"] +with_tracer = ["cairo-vm/tracer", "cairo-vm-tracer"] +mod_builtin = ["cairo-vm/mod_builtin"] diff --git a/cairo-vm-cli/src/main.rs b/cairo-vm-cli/src/main.rs index a3c349d79a..ddb97c068a 100644 --- a/cairo-vm-cli/src/main.rs +++ b/cairo-vm-cli/src/main.rs @@ -4,9 +4,19 @@ use bincode::enc::write::Writer; use cairo_vm::air_public_input::PublicInputError; use cairo_vm::cairo_run::{self, EncodeTraceError}; use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; +#[cfg(feature = "with_tracer")] +use cairo_vm::serde::deserialize_program::DebugInfo; use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; use cairo_vm::vm::errors::trace_errors::TraceError; use cairo_vm::vm::errors::vm_errors::VirtualMachineError; +#[cfg(feature = "with_tracer")] +use cairo_vm::vm::runners::cairo_runner::CairoRunner; +#[cfg(feature = "with_tracer")] +use cairo_vm::vm::vm_core::VirtualMachine; +#[cfg(feature = "with_tracer")] +use cairo_vm_tracer::error::trace_data_errors::TraceDataError; +#[cfg(feature = "with_tracer")] +use cairo_vm_tracer::tracer::run_tracer; use clap::{Parser, ValueHint}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; @@ -42,7 +52,7 @@ struct Args { air_public_input: Option, #[clap( long = "air_private_input", - requires_all = ["proof_mode", "trace_file", "memory_file"] + requires_all = ["proof_mode", "trace_file", "memory_file"] )] air_private_input: Option, #[clap( @@ -52,6 +62,11 @@ struct Args { conflicts_with_all = ["proof_mode", "air_private_input", "air_public_input"] )] cairo_pie_output: Option, + #[structopt(long = "allow_missing_builtins")] + allow_missing_builtins: Option, + #[structopt(long = "tracer")] + #[cfg(feature = "with_tracer")] + tracer: bool, } fn validate_layout(value: &str) -> Result { @@ -59,6 +74,7 @@ fn validate_layout(value: &str) -> Result { "plain" | "small" | "dex" + | "recursive" | "starknet" | "starknet_with_keccak" | "recursive_large_output" @@ -85,6 +101,9 @@ enum Error { Trace(#[from] TraceError), #[error(transparent)] PublicInput(#[from] PublicInputError), + #[error(transparent)] + #[cfg(feature = "with_tracer")] + TraceDataError(#[from] TraceDataError), } struct FileWriter { @@ -120,6 +139,31 @@ impl FileWriter { } } +#[cfg(feature = "with_tracer")] +fn start_tracer(cairo_runner: &CairoRunner, vm: &VirtualMachine) -> Result<(), TraceDataError> { + let relocation_table = vm + .relocate_segments() + .map_err(TraceDataError::FailedToGetRelocationTable)?; + let instruction_locations = cairo_runner + .get_program() + .get_relocated_instruction_locations(relocation_table.as_ref()); + let debug_info = instruction_locations.map(DebugInfo::new); + + let relocated_trace = cairo_runner + .relocated_trace + .clone() + .ok_or(TraceDataError::FailedToGetRelocatedTrace)?; + + run_tracer( + cairo_runner.get_program().clone(), + cairo_runner.relocated_memory.clone(), + relocated_trace.clone(), + 1, + debug_info, + )?; + Ok(()) +} + fn run(args: impl Iterator) -> Result<(), Error> { let args = Args::try_parse_from(args)?; @@ -132,6 +176,7 @@ fn run(args: impl Iterator) -> Result<(), Error> { layout: &args.layout, proof_mode: args.proof_mode, secure_run: args.secure_run, + allow_missing_builtins: args.allow_missing_builtins, ..Default::default() }; @@ -180,6 +225,11 @@ fn run(args: impl Iterator) -> Result<(), Error> { std::fs::write(file_path, json)?; } + #[cfg(feature = "with_tracer")] + if args.tracer { + start_tracer(&cairo_runner, &vm)?; + } + if let (Some(file_path), Some(ref trace_file), Some(ref memory_file)) = (args.air_private_input, args.trace_file, args.memory_file) { @@ -288,7 +338,6 @@ mod tests { #[values(false, true)] memory_file: bool, #[values(false, true)] mut trace_file: bool, #[values(false, true)] proof_mode: bool, - #[values(false, true)] secure_run: bool, #[values(false, true)] print_output: bool, #[values(false, true)] entrypoint: bool, #[values(false, true)] air_public_input: bool, @@ -321,9 +370,6 @@ mod tests { if trace_file { args.extend_from_slice(&["--trace_file".to_string(), "/dev/null".to_string()]); } - if secure_run { - args.extend_from_slice(&["--secure_run".to_string(), "true".to_string()]); - } if print_output { args.extend_from_slice(&["--print_output".to_string()]); } diff --git a/cairo-vm-tracer/Cargo.toml b/cairo-vm-tracer/Cargo.toml new file mode 100644 index 0000000000..e8f933f4b0 --- /dev/null +++ b/cairo-vm-tracer/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "cairo-vm-tracer" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true + +[features] +default = ["std"] +std = [] +alloc = [] + +[dependencies] +cairo-vm = { workspace = true, features = ["arbitrary", "std"] } +thiserror-no-std = { workspace = true } +num-bigint = { workspace = true } +num-traits = { workspace = true } +axum = "0.6.18" +tokio = {version = "1.28.2", features = ["rt", "macros","rt-multi-thread"]} +serde = { workspace = true } +tower = { version = "0.4.13", features = ["util"] } +tower-http = { version = "0.4.0", features = ["full"] } +tracing = "0.1.37" +tracing-subscriber = "0.3.17" +include_dir = "0.7.3" +mime_guess = "2.0.4" diff --git a/cairo-vm-tracer/src/error/mod.rs b/cairo-vm-tracer/src/error/mod.rs new file mode 100644 index 0000000000..67535674a0 --- /dev/null +++ b/cairo-vm-tracer/src/error/mod.rs @@ -0,0 +1 @@ +pub mod trace_data_errors; diff --git a/cairo-vm-tracer/src/error/trace_data_errors.rs b/cairo-vm-tracer/src/error/trace_data_errors.rs new file mode 100644 index 0000000000..7af3f540cf --- /dev/null +++ b/cairo-vm-tracer/src/error/trace_data_errors.rs @@ -0,0 +1,24 @@ +use cairo_vm::vm::errors::{memory_errors::MemoryError, vm_errors::VirtualMachineError}; +use thiserror_no_std::Error; + +#[derive(Debug, Error)] +pub enum TraceDataError { + #[error("Instruction is None at pc {0} when encoding")] + InstructionIsNone(String), + #[error(transparent)] + InstructionDecodeError(#[from] VirtualMachineError), + #[error(transparent)] + FailedToGetRelocationTable(#[from] MemoryError), + #[error("Failed to get relocated trace")] + FailedToGetRelocatedTrace, + #[error("Failed to read file {0}")] + FailedToReadFile(String), + #[error("Input file is None {0}")] + InputFileIsNone(String), + #[error("Instruction encoding must be convertible to a u64")] + FailedToConvertInstructionEncoding, + #[error("Offset must be convertible to a usize")] + FailedToConvertOffset, + #[error("Imm address {0} must be convertible to a usize")] + FailedToImmAddress(String), +} diff --git a/cairo-vm-tracer/src/lib.rs b/cairo-vm-tracer/src/lib.rs new file mode 100644 index 0000000000..a17ac87737 --- /dev/null +++ b/cairo-vm-tracer/src/lib.rs @@ -0,0 +1,4 @@ +pub mod error; +pub mod tracer; +mod tracer_data; +mod types; diff --git a/cairo-vm-tracer/src/tracer.rs b/cairo-vm-tracer/src/tracer.rs new file mode 100644 index 0000000000..0edf2f9fe1 --- /dev/null +++ b/cairo-vm-tracer/src/tracer.rs @@ -0,0 +1,134 @@ +use std::{collections::HashMap, net::SocketAddr}; + +use axum::{ + body::{self, Empty, Full}, + extract::{Path, State}, + http::{header, HeaderValue, Response, StatusCode}, + response::IntoResponse, + routing::get, + Json, Router, +}; +use cairo_vm::utils::PRIME_STR; +use cairo_vm::vm::trace::trace_entry::RelocatedTraceEntry; +use cairo_vm::{serde::deserialize_program::DebugInfo, types::program::Program, Felt252}; +use include_dir::{include_dir, Dir}; +use num_bigint::BigInt; +use num_traits::{One, Signed}; +use serde::Serialize; +use tower_http::trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer}; +use tracing::Level; + +use crate::{ + error::trace_data_errors::TraceDataError, tracer_data::TracerData, + types::memory_access::MemoryAccess, +}; + +static STATIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/static"); + +#[tokio::main] +pub async fn run_tracer( + program: Program, + memory: Vec>, + trace: Vec, + program_base: u64, + debug_info: Option, +) -> Result<(), TraceDataError> { + let tracer_data = TracerData::new(program, memory, trace, program_base, debug_info)?; + + tracing_subscriber::fmt::init(); + let app = Router::new() + .route("/static/data.json", get(get_data)) + .route("/static/eval.json", get(get_eval)) + .route("/static/*path", get(static_path)) + .with_state(tracer_data) + .layer( + TraceLayer::new_for_http() + .make_span_with(DefaultMakeSpan::new().level(Level::INFO)) + .on_response(DefaultOnResponse::new().level(Level::INFO)), + ); + + let addr = SocketAddr::from(([127, 0, 0, 1], 8100)); + tracing::info!("listening on http://{}/static/index.html", addr); + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); + Ok(()) +} + +async fn get_data(tracer_data: State) -> Json { + let data_response = DataReponse { + code: tracer_data + .input_files + .iter() + .map(|(k, v)| (k.clone(), v.to_html())) + .collect(), + trace: tracer_data.trace.clone(), + memory: tracer_data + .memory + .iter() + .filter_map(|x| x.as_ref().map(|_| (*x).unwrap())) + .map(|x| { + field_element_repr( + &x.to_bigint(), + &BigInt::parse_bytes(PRIME_STR[2..].as_bytes(), 16).unwrap(), + ) + }) + .enumerate() + .map(|(i, v)| (i + 1, v)) + .collect(), + memory_accesses: tracer_data.memory_accesses.clone(), + public_memory: vec![], + }; + + // filter a vector of options to remove none values + + Json(data_response) +} + +async fn get_eval(_tracer_data: State) {} + +async fn static_path(Path(path): Path) -> impl IntoResponse { + let path = path.trim_start_matches('/'); + let mime_type = mime_guess::from_path(path).first_or_text_plain(); + + match STATIC_DIR.get_file(path) { + None => Response::builder() + .status(StatusCode::NOT_FOUND) + .body(body::boxed(Empty::new())) + .unwrap(), + Some(file) => Response::builder() + .status(StatusCode::OK) + .header( + header::CONTENT_TYPE, + HeaderValue::from_str(mime_type.as_ref()).unwrap(), + ) + .body(body::boxed(Full::from(file.contents()))) + .unwrap(), + } +} + +fn field_element_repr(val: &BigInt, prime: &BigInt) -> String { + // Shift val to the range (-prime / 2, prime / 2). + let shifted_val: BigInt = (val.clone() + prime.clone() / 2) % prime.clone() - prime.clone() / 2; + // If shifted_val is small, use decimal representation. + let two_pow_40: BigInt = BigInt::one() << 40; + if shifted_val.abs() < two_pow_40 { + return shifted_val.to_string(); + } + // Otherwise, use hex representation (allowing a sign if the number is close to prime). + let two_pow_100: BigInt = BigInt::one() << 100; + if shifted_val.abs() < two_pow_100 { + return format!("0x{:x}", shifted_val); + } + format!("0x{:x}", val) +} + +#[derive(Serialize)] +struct DataReponse { + code: HashMap, + trace: Vec, + memory: HashMap, + public_memory: Vec, + memory_accesses: Vec, +} diff --git a/cairo-vm-tracer/src/tracer_data.rs b/cairo-vm-tracer/src/tracer_data.rs new file mode 100644 index 0000000000..7c5268152e --- /dev/null +++ b/cairo-vm-tracer/src/tracer_data.rs @@ -0,0 +1,221 @@ +use std::collections::{BTreeMap, HashMap}; + +use cairo_vm::vm::trace::trace_entry::RelocatedTraceEntry; +use cairo_vm::{ + serde::deserialize_program::{DebugInfo, InstructionLocation}, + types::{ + instruction::Op1Addr, + program::Program, + relocatable::{MaybeRelocatable, Relocatable}, + }, + vm::{context::run_context::RunContext, decoding::decoder::decode_instruction}, + Felt252, +}; +use num_bigint::BigUint; +use num_traits::ToPrimitive; + +use crate::{error::trace_data_errors::TraceDataError, types::memory_access::MemoryAccess}; + +#[derive(Clone)] +pub struct InputCodeFile { + content: String, + lines: Vec, + tags: Vec<(usize, isize, String)>, +} + +impl InputCodeFile { + fn new(content: &str) -> Self { + let lines: Vec = content.lines().map(|line| line.to_string()).collect(); + InputCodeFile { + content: content.to_string(), + lines, + tags: Vec::new(), + } + } + + fn mark_text( + &mut self, + line_start: usize, + col_start: usize, + line_end: usize, + col_end: usize, + classes: &[&str], + ) { + let offset_start = self + .lines + .iter() + .take(line_start - 1) + .map(|line| line.len()) + .sum::() + + line_start + + col_start + - 2; + + let offset_end = self + .lines + .iter() + .take(line_end - 1) + .map(|line| line.len()) + .sum::() + + line_end + + col_end + - 2; + + self.tags.push(( + offset_start, + -(offset_end as isize), + format!("", classes.join(" ")), + )); + self.tags + .push((offset_end, -std::isize::MAX, "".to_string())); + } + + pub fn to_html(&self) -> String { + let mut res = self.content.replace(' ', "\0"); + let mut sorted_tags = self.tags.clone(); + sorted_tags.sort_by_key(|&(key, _, _)| key); + for &(pos, _, ref tag_content) in sorted_tags.iter().rev() { + res.insert_str(pos, tag_content); + } + res.replace('\0', " ").replace('\n', "
\n") + } +} + +// TODO: add support for taking air_public_input as an argument +#[derive(Clone)] +pub struct TracerData { + pub(crate) _program: Program, + pub(crate) memory: Vec>, + pub(crate) trace: Vec, + pub(crate) _program_base: u64, // TODO: adjust size based on maximum instructions possible + pub(crate) _debug_info: Option, + pub(crate) memory_accesses: Vec, + pub(crate) input_files: HashMap, +} + +impl TracerData { + pub fn new( + program: Program, + memory: Vec>, + trace: Vec, + program_base: u64, + debug_info: Option, + ) -> Result { + let mut input_files = HashMap::::new(); + + if let Some(debug_info) = debug_info.clone() { + // loop over debug_info + + //sort hashmap by key + let instruction_locations: BTreeMap = + debug_info.get_instruction_locations().into_iter().collect(); + for (pc_offset, instruction_location) in instruction_locations.iter() { + let loc = &instruction_location.inst; + let filename = &loc.input_file.filename; + let content = loc + .input_file + .get_content() + .map_err(|_| TraceDataError::FailedToReadFile(filename.clone()))?; + if !input_files.contains_key(filename) { + input_files.insert(filename.clone(), InputCodeFile::new(content.as_str())); + } + let input_file = input_files.get_mut(filename); + if input_file.is_none() { + return Err(TraceDataError::InputFileIsNone(filename.clone())); + } + let input_file = input_file.unwrap(); + + input_file.mark_text( + loc.start_line as usize, + loc.start_col as usize, + loc.end_line as usize, + loc.end_col as usize, + &[format!("inst{}", pc_offset).as_str(), "instruction"], + ); + } + } + + let mut memory_accesses: Vec = vec![]; + //loop of trace + for entry in trace.iter() { + let run_context = RunContext::new(Relocatable::from((0, entry.pc)), entry.ap, entry.fp); + + let (instruction_encoding, _) = + get_instruction_encoding(entry.pc, &memory, program.prime())?; + + let instruction_encoding = instruction_encoding.to_u64(); + if instruction_encoding.is_none() { + return Err(TraceDataError::FailedToConvertInstructionEncoding); + } + let instruction_encoding = instruction_encoding.unwrap(); + let instruction = decode_instruction(instruction_encoding)?; + + // get dst_addr + let dst_addr = run_context.compute_dst_addr(&instruction)?.offset; + + // get op0_addr + let op0_addr = run_context.compute_op0_addr(&instruction)?.offset; + + // get op1_addr + let mut op0: Result, TraceDataError> = Ok(None); + if instruction.op1_addr == Op1Addr::Op0 { + let op0_memory = &memory[op0_addr]; + op0 = match op0_memory { + None => Ok(None), + Some(felt) => { + let offset = felt.clone().to_usize(); + if offset.is_none() { + return Err(TraceDataError::FailedToConvertOffset); + } + let offset = offset.unwrap(); + Ok(Some(MaybeRelocatable::RelocatableValue(Relocatable { + segment_index: 1_isize, + offset, + }))) + } + }; + } + let op0 = op0?; + let op1_addr = run_context + .compute_op1_addr(&instruction, op0.as_ref())? + .offset; + + // add to memory access + memory_accesses.push(MemoryAccess { + dst: dst_addr, + op0: op0_addr, + op1: op1_addr, + }); + } + + Ok(TracerData { + _program: program, + memory, + trace, + _program_base: program_base, + _debug_info: debug_info, + memory_accesses, + input_files, + }) + } +} + +// Returns the encoded instruction (the value at pc) and the immediate value (the value at +// pc + 1, if it exists in the memory). +pub fn get_instruction_encoding( + pc: usize, + memory: &[Option], + prime: &str, +) -> Result<(Felt252, Option), TraceDataError> { + if memory[pc].is_none() { + return Err(TraceDataError::InstructionIsNone(pc.to_string())); + } + let instruction_encoding = memory[pc].unwrap(); + let prime = BigUint::parse_bytes(prime[2..].as_bytes(), 16).unwrap(); + + let imm_addr = BigUint::from(pc + 1) % prime; + let imm_addr = usize::try_from(imm_addr.clone()) + .map_err(|_| TraceDataError::FailedToImmAddress(imm_addr.to_string()))?; + let optional_imm = memory[imm_addr]; + Ok((instruction_encoding, optional_imm)) +} diff --git a/cairo-vm-tracer/src/types/memory_access.rs b/cairo-vm-tracer/src/types/memory_access.rs new file mode 100644 index 0000000000..21507b313f --- /dev/null +++ b/cairo-vm-tracer/src/types/memory_access.rs @@ -0,0 +1,9 @@ +use serde::Serialize; + +// TODO: check if the sizes are corect +#[derive(Serialize, Clone)] +pub struct MemoryAccess { + pub(crate) dst: usize, + pub(crate) op0: usize, + pub(crate) op1: usize, +} diff --git a/cairo-vm-tracer/src/types/mod.rs b/cairo-vm-tracer/src/types/mod.rs new file mode 100644 index 0000000000..8b7ec4be21 --- /dev/null +++ b/cairo-vm-tracer/src/types/mod.rs @@ -0,0 +1 @@ +pub mod memory_access; diff --git a/cairo-vm-tracer/static/index.html b/cairo-vm-tracer/static/index.html new file mode 100644 index 0000000000..9606f87125 --- /dev/null +++ b/cairo-vm-tracer/static/index.html @@ -0,0 +1,56 @@ + + + + + + Cairo Tracer + + + + + + + +
+
+
+
+
+
+ Follow: + +
+
+
+
+ (s) Step
+ (S) Previous step
+ (n) Step over
+ (N) Previous step over
+ (o) Step out
+ (b) Run until next breakpoint
+ (B) Run until previous breakpoint
+
+ pc =
+ ap =
+ fp =
+
+ dst_addr =
+ op0_addr =
+ op1_addr =
+
+ Stack trace: +
+
+ + +
+ + + diff --git a/cairo-vm-tracer/static/tracer.css b/cairo-vm-tracer/static/tracer.css new file mode 100644 index 0000000000..c4ec672eed --- /dev/null +++ b/cairo-vm-tracer/static/tracer.css @@ -0,0 +1,81 @@ +html, body { + margin: 0px; + padding: 0px; + height: 100%; +} + +#code_div, #info_td, #memory_div_parent { + font-family: monospace; +} + +.current_instruction, .current_pc_mem { + background: yellow !important; +} + +.highlight_instruction { + background: lightblue; +} + +.breakpoint { + background: #99ccff; +} + +#code_div_parent, #memory_div_parent { + flex-flow: column; + height: 100%; + vertical-align: top; +} + +#code_div_parent { + background: rgb(238, 255, 255); + overflow-y: scroll; +} + +#memory_div_parent { + background: rgb(255, 255, 250); + display: flex; +} + +#memory_div { + overflow-y: scroll; + flex-flow: row; +} + +.mem_info { + display: inline-block; + width: 40px; + text-align: right; + font-size: 70%; +} + +#main_table { + height: 100%; +} + +#code_div { + margin: 10px; +} + +#memory_div>table { + height: 100%; + margin: 10px; +} + +.table_with_border { + border-collapse: collapse; +} + +.table_with_border>tr>td, .table_with_border>tr>th { + border: 1px black solid; +} + +.filename { + font-weight: bold; + text-decoration: underline; + margin-top: 10px; + margin-bottom: 5px; +} + +.public_memory { + background-color: #f0fff8; +} diff --git a/cairo-vm-tracer/static/tracer.js b/cairo-vm-tracer/static/tracer.js new file mode 100644 index 0000000000..61b97a60b5 --- /dev/null +++ b/cairo-vm-tracer/static/tracer.js @@ -0,0 +1,387 @@ +/* + The number of the current step being viewed in the tracer. +*/ +var current_step; + +var trace; +var memory; +var memory_accesses; + +/* + A list of objects {watch_expr: ..., watch_result: ...} where watch_expr is the element + and watch_result is the result element. +*/ +var watch_exprs = []; + +/* + The maximum number of entries shown in the stack trace. +*/ +const MAX_STACK_TRACE = 100; + +function load_json() { + $.getJSON("data.json", function (data) { + trace = data.trace; + memory = data.memory; + memory_accesses = data.memory_accesses; + for (const filename in data.code) { + $("#code_div") + .append($("
").addClass("filename").text(filename)) + .append($("
").html(data.code[filename])); + } + $("#slider_div").append(create_slider()); + $("#memory_div").append(create_memory_table()); + $("#watch_table").append(create_watch_row()); + mark_public_memory(data.public_memory); + goto_step(0); + + $(".instruction").dblclick(toggle_breakpoint); + $(".mem_row").dblclick(toggle_breakpoint); + }); +} + +/* + Adds a slider that tracks the progress of the program. +*/ +function create_slider() { + const slider = $("").attr({ + id: "slider", + type: "range", + min: 0, + max: trace.length - 1, + value: 0, + }); + + slider[0].oninput = function () { + goto_step(parseInt($("#slider").val())); + }; + + return slider; +} + +function create_memory_table() { + const table = $("").addClass("table_with_border"); + for (const addr in memory) { + table.append( + $("") + .attr({ id: "mem_row" + addr }) + .addClass("mem_row") + .append( + $("") + .append($("").append(fp_cell).append(pc_cell); + + pc_cell.mouseenter(function () { + $(".inst" + pc).addClass("highlight_instruction"); + }); + pc_cell.mouseleave(function () { + $(".inst" + pc).removeClass("highlight_instruction"); + }); + + return row; +} + +function create_watch_row() { + const watch_expr = $("").attr({ type: "text" }); + const watch_result = $(""); + + watch_exprs.push({ watch_expr: watch_expr, watch_result: watch_result }); + + watch_expr.keyup(function (event) { + if (event.key == "Enter") { + update_watch(); + } + }); + + const n_watches = watch_exprs.length; + watch_expr.change(function (event) { + // Add new watch if needed. + if (watch_expr.val() != "" && watch_exprs.length == n_watches) { + $("#watch_table").append(create_watch_row()); + } + + update_watch(); + }); + + // Make sure navigation keys (s, n, ...) will not work when watch_expr is focused. + watch_expr.keypress(function (event) { + event.stopPropagation(); + }); + + return $("") + .append($("
").append( + $("") + .attr({ id: "mem_info" + addr }) + .addClass("mem_info") + ) + ) + .append($("").text(addr)) + .append($("").text(memory[addr])) + ); + } + return table; +} + +function mark_public_memory(public_memory) { + for (const addr of public_memory) { + $("#mem_row" + addr).addClass("public_memory"); + } +} + +function update_current_instruction_view() { + const entry = trace[current_step]; + const pc = entry.pc; + const ap = entry.ap; + const fp = entry.fp; + + $(".instruction").removeClass("current_instruction"); + $(".inst" + pc).addClass("current_instruction"); + $("#pc").text(pc); + $("#ap").text(ap); + $("#fp").text(fp); + + const mem_accesses = memory_accesses[current_step]; + $("#dst_addr").text(mem_accesses.dst); + $("#op0_addr").text(mem_accesses.op0); + $("#op1_addr").text(mem_accesses.op1); + + $(".mem_row").removeClass("current_pc_mem"); + $("#mem_row" + pc).addClass("current_pc_mem"); + + $(".mem_info").text(""); + $("#mem_info" + ap).append("ap "); + $("#mem_info" + fp).append("fp "); + + update_stack_trace_view(); + + if ($("#slider").val() != current_step) { + $("#slider").val(current_step); + } + + scrollIntoViewIfNeeded($(".inst" + pc)[0]); + + if ($("#memory_follow").val() == "pc") { + scrollIntoViewIfNeeded($("#mem_row" + pc)[0]); + } else if ($("#memory_follow").val() == "ap") { + scrollIntoViewIfNeeded($("#mem_row" + ap)[0]); + } else if ($("#memory_follow").val() == "fp") { + scrollIntoViewIfNeeded($("#mem_row" + fp)[0]); + } + + update_watch(); +} + +function scrollIntoViewIfNeeded(target) { + if (target === undefined) { + return; + } + + const rect = target.getBoundingClientRect(); + const scrollParent = getScrollParent(target); + const scrollParentRect = scrollParent.getBoundingClientRect(); + if (rect.bottom > scrollParentRect.bottom) { + // Scroll down. + const scrollMargin = 64; + const targetBottom = scrollParent.scrollTop + rect.bottom; + scrollParent.scrollTo({ + top: targetBottom - scrollParent.clientHeight + scrollMargin, + behavior: "smooth", + }); + } else if (rect.top < scrollParentRect.top) { + // Scroll up. + const scrollMargin = 32; + const targetTop = scrollParent.scrollTop + rect.top; + scrollParent.scrollTo({ + top: targetTop - scrollMargin, + behavior: "smooth", + }); + } +} + +function getScrollParent(node) { + node = node.parentNode; + while (getComputedStyle(node)["overflow-y"] != "scroll") { + node = node.parentNode; + } + return node; +} + +function update_stack_trace_view() { + const entry = trace[current_step]; + const initial_fp = trace[0].fp; + + $(".mem_row").css("border-top", ""); + + const stack_trace = $("#stack_trace"); + stack_trace + .empty() + .append( + $("
").append("fp")) + .append($("").append("return pc")) + ); + + var fp = entry.fp; + for (var i = 0; i < MAX_STACK_TRACE && fp != initial_fp; i++) { + const pc = memory[fp - 1]; + stack_trace.append(create_stack_trace_row(fp, pc)); + $("#mem_row" + fp).css("border-top", "2px black solid"); + fp = memory[fp - 2]; + } +} + +function create_stack_trace_row(fp, pc) { + const fp_cell = $("").append(fp); + const pc_cell = $("").append(pc); + const row = $("
").append(watch_expr)) + .append($("").append(watch_result)); +} + +var update_watch_ajax = { abort: function () {} }; + +function update_watch() { + // REMOVE RETURN TO EVALUATION EXPRESSION + return; + var query_str = "eval.json?step=" + encodeURIComponent(current_step); + for (const entry of watch_exprs) { + const expr_txt = entry.watch_expr.val(); + query_str += + "&expr=" + encodeURIComponent(expr_txt == "" ? "null" : expr_txt); + } + // Abort previous AJAX request if exists. + update_watch_ajax.abort(); + update_watch_ajax = $.getJSON(query_str, function (data) { + for (var idx = 0; idx < data.length; ++idx) { + watch_exprs[idx].watch_result.text(data[idx]); + } + }); +} + +/* + Clears the text selection in the window. + This function was copied from + https://stackoverflow.com/questions/880512/prevent-text-selection-after-double-click. +*/ +function clearSelection() { + if (document.selection && document.selection.empty) { + document.selection.empty(); + } else if (window.getSelection) { + var sel = window.getSelection(); + sel.removeAllRanges(); + } +} + +function toggle_breakpoint(event) { + $(this).toggleClass("breakpoint"); + clearSelection(); + event.stopPropagation(); +} + +function has_breakpoint(step) { + return ( + $("#mem_row" + trace[step].pc).hasClass("breakpoint") || + $("#mem_row" + memory_accesses[step].dst).hasClass("breakpoint") || + $("#mem_row" + memory_accesses[step].op0).hasClass("breakpoint") || + $("#mem_row" + memory_accesses[step].op1).hasClass("breakpoint") + ); +} + +function goto_step(i) { + // Update global variable. + current_step = i; + update_current_instruction_view(); +} + +function step() { + if (current_step < trace.length - 1) { + goto_step(current_step + 1); + } +} + +function previous_step() { + if (current_step > 0) { + goto_step(current_step - 1); + } +} + +function step_over() { + const current_fp = trace[current_step].fp; + for (var i = current_step + 1; i < trace.length; i++) { + if (trace[i].fp == current_fp || has_breakpoint(i)) { + goto_step(i); + return; + } + } +} + +function previous_step_over() { + const current_fp = trace[current_step].fp; + for (var i = current_step - 1; i >= 0; i--) { + if (trace[i].fp == current_fp) { + goto_step(i); + return; + } + } +} + +function step_out() { + const current_fp = trace[current_step].fp; + const previous_fp = memory[current_fp - 2]; + for (var i = current_step + 1; i < trace.length; i++) { + if (trace[i].fp == previous_fp) { + goto_step(i); + return; + } + } +} + +function next_breakpoint() { + for (var i = current_step + 1; i < trace.length; i++) { + if (has_breakpoint(i)) { + goto_step(i); + return; + } + } +} + +function previous_breakpoint() { + const current_fp = trace[current_step].fp; + for (var i = current_step - 1; i >= 0; i--) { + if (has_breakpoint(i)) { + goto_step(i); + return; + } + } +} + +$(document).ready(function () { + load_json(); +}); + +$(document).keypress(function (event) { + if (event.key == "s") { + step(); + event.stopPropagation(); + } + if (event.key == "S") { + previous_step(); + event.stopPropagation(); + } + if (event.key == "n") { + step_over(); + event.stopPropagation(); + } + if (event.key == "N") { + previous_step_over(); + event.stopPropagation(); + } + if (event.key == "o") { + step_out(); + event.stopPropagation(); + } + if (event.key == "b") { + next_breakpoint(); + event.stopPropagation(); + } + if (event.key == "B") { + previous_breakpoint(); + event.stopPropagation(); + } +}); diff --git a/cairo1-run/Cargo.toml b/cairo1-run/Cargo.toml index 34138ce983..a4423fabf8 100644 --- a/cairo1-run/Cargo.toml +++ b/cairo1-run/Cargo.toml @@ -11,10 +11,10 @@ keywords.workspace = true [dependencies] cairo-vm = {workspace = true, features = ["std", "cairo-1-hints"]} -cairo-lang-sierra-type-size = { version = "2.3.1", default-features = false } -cairo-lang-sierra-ap-change = { version = "2.3.1", default-features = false } -cairo-lang-sierra-gas = { version = "2.3.1", default-features = false } -cairo-lang-sierra-to-casm.workspace = true +cairo-lang-sierra-type-size = { version = "2.5.4", default-features = false } +cairo-lang-sierra-ap-change = { version = "2.5.4", default-features = false } +cairo-lang-sierra-gas = { version = "2.5.4", default-features = false } +cairo-lang-sierra-to-casm.workspace = true cairo-lang-compiler.workspace = true cairo-lang-sierra.workspace = true cairo-lang-utils.workspace = true @@ -26,7 +26,8 @@ bincode.workspace = true assert_matches = "1.5.0" rstest = "0.17.0" mimalloc = { version = "0.1.37", default-features = false, optional = true } +num-traits = { version = "0.2", default-features = false } [features] default = ["with_mimalloc"] -with_mimalloc = ["cairo-vm/with_mimalloc", "dep:mimalloc"] +with_mimalloc = ["dep:mimalloc"] diff --git a/cairo1-run/Makefile b/cairo1-run/Makefile index 26b9b9341a..c2869d9972 100644 --- a/cairo1-run/Makefile +++ b/cairo1-run/Makefile @@ -15,14 +15,14 @@ MEMORY:=$(patsubst $(CAIRO_1_FOLDER)/%.cairo, $(CAIRO_1_FOLDER)/%.memory, $(CAIR deps: git clone https://github.com/starkware-libs/cairo.git \ && cd cairo \ - && git checkout v2.4.2 \ + && git checkout v2.5.4 \ && cd .. \ && mv cairo/corelib/ . \ && rm -rf cairo/ run: $(TRACES) $(MEMORY) -test: +test: cargo test clean: diff --git a/cairo1-run/README.md b/cairo1-run/README.md index 2f0cc5a8b3..8b7244314f 100644 --- a/cairo1-run/README.md +++ b/cairo1-run/README.md @@ -66,3 +66,5 @@ The cairo1-run cli supports the following optional arguments: * `--air_private_input `: Receives the name of a file and outputs the AIR private inputs into it. Can only be used if proof_mode, trace_file & memory_file are also enabled. * `--cairo_pie_output `: Receives the name of a file and outputs the Cairo PIE into it. Can only be used if proof_mode, is not enabled. + +* `--append_return_values`: Adds extra instructions to the program in order to append the return values to the output builtin's segment. This is the default behaviour for proof_mode. diff --git a/cairo1-run/src/cairo_run.rs b/cairo1-run/src/cairo_run.rs new file mode 100644 index 0000000000..8477eb7d88 --- /dev/null +++ b/cairo1-run/src/cairo_run.rs @@ -0,0 +1,1206 @@ +use cairo_lang_casm::{ + casm, casm_extend, hints::Hint, inline::CasmContext, instructions::Instruction, +}; +use cairo_lang_sierra::{ + extensions::{ + bitwise::BitwiseType, + core::{CoreLibfunc, CoreType}, + ec::EcOpType, + gas::{CostTokenType, GasBuiltinType}, + pedersen::PedersenType, + poseidon::PoseidonType, + range_check::RangeCheckType, + segment_arena::SegmentArenaType, + starknet::syscalls::SystemType, + ConcreteType, NamedType, + }, + ids::ConcreteTypeId, + program::{Function, GenericArg, Program as SierraProgram}, + program_registry::ProgramRegistry, +}; +use cairo_lang_sierra_ap_change::calc_ap_changes; +use cairo_lang_sierra_gas::{gas_info::GasInfo, objects::CostInfoProvider}; +use cairo_lang_sierra_to_casm::{ + compiler::CairoProgram, + metadata::{calc_metadata, Metadata, MetadataComputationConfig, MetadataError}, +}; +use cairo_lang_sierra_type_size::get_type_size_map; +use cairo_lang_utils::{casts::IntoOrPanic, unordered_hash_map::UnorderedHashMap}; +use cairo_vm::{ + hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor, + math_utils::signed_felt, + serde::deserialize_program::{ + ApTracking, BuiltinName, FlowTrackingData, HintParams, ReferenceManager, + }, + types::{program::Program, relocatable::MaybeRelocatable}, + vm::{ + errors::{runner_errors::RunnerError, vm_errors::VirtualMachineError}, + runners::{ + builtin_runner::{ + BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, OUTPUT_BUILTIN_NAME, + POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, + }, + cairo_runner::{CairoRunner, RunResources, RunnerMode}, + }, + vm_core::VirtualMachine, + }, + Felt252, +}; +use itertools::{chain, Itertools}; +use num_traits::{cast::ToPrimitive, Zero}; +use std::{collections::HashMap, iter::Peekable}; + +use crate::{Error, FuncArg}; + +#[derive(Debug)] +pub struct Cairo1RunConfig<'a> { + pub args: &'a [FuncArg], + // Serializes program output into a user-friendly format + pub serialize_output: bool, + pub trace_enabled: bool, + pub relocate_mem: bool, + pub layout: &'a str, + pub proof_mode: bool, + // Should be true if either air_public_input or cairo_pie_output are needed + // Sets builtins stop_ptr by calling `final_stack` on each builtin + pub finalize_builtins: bool, + // Appends return values to the output segment. This is performed by default when running in proof_mode + pub append_return_values: bool, +} + +impl Default for Cairo1RunConfig<'_> { + fn default() -> Self { + Self { + args: Default::default(), + serialize_output: false, + trace_enabled: false, + relocate_mem: false, + layout: "plain", + proof_mode: false, + finalize_builtins: false, + append_return_values: false, + } + } +} + +// Runs a Cairo 1 program +// Returns the runner & VM after execution + the return values + the serialized return values (if serialize_output is enabled) +pub fn cairo_run_program( + sierra_program: &SierraProgram, + cairo_run_config: Cairo1RunConfig, +) -> Result< + ( + CairoRunner, + VirtualMachine, + Vec, + Option, + ), + Error, +> { + let metadata = create_metadata(sierra_program, Some(Default::default()))?; + let sierra_program_registry = ProgramRegistry::::new(sierra_program)?; + let type_sizes = + get_type_size_map(sierra_program, &sierra_program_registry).unwrap_or_default(); + let casm_program = + cairo_lang_sierra_to_casm::compiler::compile(sierra_program, &metadata, true)?; + + let main_func = find_function(sierra_program, "::main")?; + + let initial_gas = 9999999999999_usize; + + // Modified entry code to be compatible with custom cairo1 Proof Mode. + // This adds code that's needed for dictionaries, adjusts ap for builtin pointers, adds initial gas for the gas builtin if needed, and sets up other necessary code for cairo1 + let (entry_code, builtins) = create_entry_code( + &sierra_program_registry, + &casm_program, + &type_sizes, + main_func, + initial_gas, + &cairo_run_config, + )?; + + // Fetch return type data + let return_type_id = main_func + .signature + .ret_types + .last() + .ok_or(Error::NoRetTypesInSignature)?; + let return_type_size = type_sizes + .get(return_type_id) + .cloned() + .ok_or_else(|| Error::NoTypeSizeForId(return_type_id.clone()))?; + + // This footer is used by lib funcs + let libfunc_footer = create_code_footer(); + let builtin_count: i16 = builtins.len().into_or_panic(); + + // This is the program we are actually running/proving + // With (embedded proof mode), cairo1 header and the libfunc footer + let instructions = chain!( + entry_code.instructions.iter(), + casm_program.instructions.iter(), + libfunc_footer.iter(), + ); + + let (processor_hints, program_hints) = build_hints_vec(instructions.clone()); + + let mut hint_processor = Cairo1HintProcessor::new(&processor_hints, RunResources::default()); + + let data: Vec = instructions + .flat_map(|inst| inst.assemble().encode()) + .map(|x| Felt252::from(&x)) + .map(MaybeRelocatable::from) + .collect(); + + let data_len = data.len(); + + let program = if cairo_run_config.proof_mode { + Program::new_for_proof( + builtins.clone(), + data, + 0, + // Proof mode is on top + // `jmp rel 0` is the last line of the entry code. + entry_code.current_code_offset - 2, + program_hints, + ReferenceManager { + references: Vec::new(), + }, + HashMap::new(), + vec![], + None, + )? + } else { + Program::new( + builtins.clone(), + data, + Some(0), + program_hints, + ReferenceManager { + references: Vec::new(), + }, + HashMap::new(), + vec![], + None, + )? + }; + + let runner_mode = if cairo_run_config.proof_mode { + RunnerMode::ProofModeCairo1 + } else { + RunnerMode::ExecutionMode + }; + + let mut runner = CairoRunner::new_v2(&program, cairo_run_config.layout, runner_mode)?; + let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled); + let end = runner.initialize(&mut vm, cairo_run_config.proof_mode)?; + + additional_initialization(&mut vm, data_len)?; + + // Run it until the end / infinite loop in proof_mode + runner.run_until_pc(end, &mut vm, &mut hint_processor)?; + if cairo_run_config.proof_mode { + runner.run_for_steps(1, &mut vm, &mut hint_processor)?; + } + + runner.end_run(false, false, &mut vm, &mut hint_processor)?; + + let skip_output = cairo_run_config.proof_mode || cairo_run_config.append_return_values; + // Fetch return values + let return_values = fetch_return_values( + return_type_size, + return_type_id, + &vm, + builtin_count, + skip_output, + )?; + + let serialized_output = if cairo_run_config.serialize_output { + Some(serialize_output( + &return_values, + &mut vm, + return_type_id, + &sierra_program_registry, + &type_sizes, + )) + } else { + None + }; + + // Set stop pointers for builtins so we can obtain the air public input + if cairo_run_config.finalize_builtins { + if skip_output { + // Set stop pointer for each builtin + vm.builtins_final_stack_from_stack_pointer_dict( + &builtins + .iter() + .enumerate() + .map(|(i, builtin)| { + ( + builtin.name(), + (vm.get_ap() - (builtins.len() - 1 - i)).unwrap(), + ) + }) + .collect(), + false, + )?; + } else { + finalize_builtins( + &main_func.signature.ret_types, + &type_sizes, + &mut vm, + builtin_count, + )?; + } + + // Build execution public memory + if cairo_run_config.proof_mode { + runner.finalize_segments(&mut vm)?; + } + } + + runner.relocate(&mut vm, true)?; + + Ok((runner, vm, return_values, serialized_output)) +} + +fn additional_initialization(vm: &mut VirtualMachine, data_len: usize) -> Result<(), Error> { + // Create the builtin cost segment + let builtin_cost_segment = vm.add_memory_segment(); + for token_type in CostTokenType::iter_precost() { + vm.insert_value( + (builtin_cost_segment + (token_type.offset_in_builtin_costs() as usize)) + .map_err(VirtualMachineError::Math)?, + Felt252::default(), + )? + } + // Put a pointer to the builtin cost segment at the end of the program (after the + // additional `ret` statement). + vm.insert_value( + (vm.get_pc() + data_len).map_err(VirtualMachineError::Math)?, + builtin_cost_segment, + )?; + + Ok(()) +} + +#[allow(clippy::type_complexity)] +fn build_hints_vec<'b>( + instructions: impl Iterator, +) -> (Vec<(usize, Vec)>, HashMap>) { + let mut hints: Vec<(usize, Vec)> = Vec::new(); + let mut program_hints: HashMap> = HashMap::new(); + + let mut hint_offset = 0; + + for instruction in instructions { + if !instruction.hints.is_empty() { + hints.push((hint_offset, instruction.hints.clone())); + program_hints.insert( + hint_offset, + vec![HintParams { + code: hint_offset.to_string(), + accessible_scopes: Vec::new(), + flow_tracking_data: FlowTrackingData { + ap_tracking: ApTracking::default(), + reference_ids: HashMap::new(), + }, + }], + ); + } + hint_offset += instruction.body.op_size(); + } + (hints, program_hints) +} + +/// Finds first function ending with `name_suffix`. +fn find_function<'a>( + sierra_program: &'a SierraProgram, + name_suffix: &'a str, +) -> Result<&'a Function, RunnerError> { + sierra_program + .funcs + .iter() + .find(|f| { + if let Some(name) = &f.id.debug_name { + name.ends_with(name_suffix) + } else { + false + } + }) + .ok_or_else(|| RunnerError::MissingMain) +} + +/// Creates a list of instructions that will be appended to the program's bytecode. +fn create_code_footer() -> Vec { + casm! { + // Add a `ret` instruction used in libfuncs that retrieve the current value of the `fp` + // and `pc` registers. + ret; + } + .instructions +} + +/// Returns the instructions to add to the beginning of the code to successfully call the main +/// function, as well as the builtins required to execute the program. +fn create_entry_code( + sierra_program_registry: &ProgramRegistry, + casm_program: &CairoProgram, + type_sizes: &UnorderedHashMap, + func: &Function, + initial_gas: usize, + config: &Cairo1RunConfig, +) -> Result<(CasmContext, Vec), Error> { + let copy_to_output_builtin = config.proof_mode || config.append_return_values; + let signature = &func.signature; + // The builtins in the formatting expected by the runner. + let (builtins, builtin_offset) = + get_function_builtins(&signature.param_types, copy_to_output_builtin); + let mut ctx = casm! {}; + // Load all vecs to memory. + // Load all array args content to memory. + let mut array_args_data = vec![]; + let mut ap_offset: i16 = 0; + for arg in config.args { + let FuncArg::Array(values) = arg else { + continue; + }; + array_args_data.push(ap_offset); + casm_extend! {ctx, + %{ memory[ap + 0] = segments.add() %} + ap += 1; + } + for (i, v) in values.iter().enumerate() { + let arr_at = (i + 1) as i16; + casm_extend! {ctx, + [ap + 0] = (v.to_bigint()); + [ap + 0] = [[ap - arr_at] + (i as i16)], ap++; + }; + } + ap_offset += (1 + values.len()) as i16; + } + let mut array_args_data_iter = array_args_data.iter(); + let after_arrays_data_offset = ap_offset; + let mut arg_iter = config.args.iter().enumerate(); + let mut param_index = 0; + let mut expected_arguments_size = 0; + if signature.param_types.iter().any(|ty| { + get_info(sierra_program_registry, ty) + .map(|x| x.long_id.generic_id == SegmentArenaType::ID) + .unwrap_or_default() + }) { + casm_extend! {ctx, + // SegmentArena segment. + %{ memory[ap + 0] = segments.add() %} + // Infos segment. + %{ memory[ap + 1] = segments.add() %} + ap += 2; + [ap + 0] = 0, ap++; + // Write Infos segment, n_constructed (0), and n_destructed (0) to the segment. + [ap - 2] = [[ap - 3]]; + [ap - 1] = [[ap - 3] + 1]; + [ap - 1] = [[ap - 3] + 2]; + } + ap_offset += 3; + } + + for ty in &signature.param_types { + let info = get_info(sierra_program_registry, ty) + .ok_or_else(|| Error::NoInfoForType(ty.clone()))?; + let generic_ty = &info.long_id.generic_id; + if let Some(offset) = builtin_offset.get(generic_ty) { + casm_extend!(ctx, [ap + 0] = [fp - *offset], ap++;); + ap_offset += 1; + } else if generic_ty == &SystemType::ID { + casm_extend! {ctx, + %{ memory[ap + 0] = segments.add() %} + ap += 1; + } + ap_offset += 1; + } else if generic_ty == &GasBuiltinType::ID { + casm_extend!(ctx, [ap + 0] = initial_gas, ap++;); + ap_offset += 1; + } else if generic_ty == &SegmentArenaType::ID { + let offset = -ap_offset + after_arrays_data_offset; + casm_extend!(ctx, [ap + 0] = [ap + offset] + 3, ap++;); + ap_offset += 1; + } else { + let ty_size = type_sizes[ty]; + let param_ap_offset_end = ap_offset + ty_size; + expected_arguments_size += ty_size; + while ap_offset < param_ap_offset_end { + let Some((arg_index, arg)) = arg_iter.next() else { + break; + }; + match arg { + FuncArg::Single(value) => { + casm_extend! {ctx, + [ap + 0] = (value.to_bigint()), ap++; + } + ap_offset += 1; + } + FuncArg::Array(values) => { + let offset = -ap_offset + array_args_data_iter.next().unwrap(); + casm_extend! {ctx, + [ap + 0] = [ap + (offset)], ap++; + [ap + 0] = [ap - 1] + (values.len()), ap++; + } + ap_offset += 2; + if ap_offset > param_ap_offset_end { + return Err(Error::ArgumentUnaligned { + param_index, + arg_index, + }); + } + } + } + } + param_index += 1; + }; + } + let actual_args_size = config + .args + .iter() + .map(|arg| match arg { + FuncArg::Single(_) => 1, + FuncArg::Array(_) => 2, + }) + .sum::(); + if expected_arguments_size != actual_args_size { + return Err(Error::ArgumentsSizeMismatch { + expected: expected_arguments_size, + actual: actual_args_size, + }); + } + + let before_final_call = ctx.current_code_offset; + + let return_type_id = signature + .ret_types + .last() + .ok_or(Error::NoRetTypesInSignature)?; + let return_type_size = type_sizes + .get(return_type_id) + .cloned() + .ok_or_else(|| Error::NoTypeSizeForId(return_type_id.clone()))?; + let builtin_count: i16 = builtins.len().into_or_panic(); + let builtin_locations: Vec = builtins + .iter() + .enumerate() + .map(|(i, name)| { + let fp_loc = i.into_or_panic::() - builtin_count - 2; + let generic = match name { + BuiltinName::range_check => RangeCheckType::ID, + BuiltinName::pedersen => PedersenType::ID, + BuiltinName::bitwise => BitwiseType::ID, + BuiltinName::ec_op => EcOpType::ID, + BuiltinName::poseidon => PoseidonType::ID, + BuiltinName::segment_arena => SegmentArenaType::ID, + BuiltinName::keccak + | BuiltinName::ecdsa + | BuiltinName::output + | BuiltinName::range_check96 + | BuiltinName::add_mod + | BuiltinName::mul_mod => return fp_loc, + }; + signature + .ret_types + .iter() + .position(|ty| { + sierra_program_registry + .get_type(ty) + .unwrap() + .info() + .long_id + .generic_id + == generic + }) + .map(|i| (signature.ret_types.len() - i).into_or_panic()) + .unwrap_or(fp_loc) + }) + .collect(); + if copy_to_output_builtin { + assert!( + builtins.iter().contains(&BuiltinName::output), + "Output builtin is required for proof mode or append_return_values" + ); + } + + let final_call_size = + // The call. + 2 + // The copying of the return values to the output segment. + + if copy_to_output_builtin { return_type_size.into_or_panic::() + 1 } else { 0 } + // Rewriting the builtins to top of the stack. + + builtins.len() + // The return or infinite loop. + + if config.proof_mode { 2 } else { 1 }; + let offset = final_call_size + + casm_program.debug_info.sierra_statement_info[func.entry_point.0].code_offset; + + casm_extend!(ctx, call rel offset;); + + if copy_to_output_builtin { + let Some(output_builtin_idx) = builtins.iter().position(|b| b == &BuiltinName::output) + else { + panic!("Output builtin is required for proof mode or append_return_values."); + }; + let output_fp_offset: i16 = builtin_locations[output_builtin_idx]; + for (i, j) in (1..return_type_size + 1).rev().enumerate() { + casm_extend! {ctx, + // [ap -j] is where each return value is located in memory + // [[fp + output_fp_offet] + 0] is the base of the output segment + [ap - j] = [[fp + output_fp_offset] + i as i16]; + }; + } + } + let mut ret_builtin_offset = return_type_size - 1; + for (builtin, location) in builtins.iter().zip(builtin_locations) { + if builtin == &BuiltinName::output && copy_to_output_builtin { + casm_extend!(ctx, [ap + 0] = [fp + location] + return_type_size, ap++;); + } else if location < 0 { + casm_extend!(ctx, [ap + 0] = [fp + location], ap++;); + } else { + casm_extend!(ctx, [ap + 0] = [ap - (ret_builtin_offset + location)], ap++;); + } + ret_builtin_offset += 1; + } + + if config.proof_mode { + casm_extend!(ctx, jmp rel 0;); + } else { + casm_extend!(ctx, ret;); + } + + assert_eq!(before_final_call + final_call_size, ctx.current_code_offset); + + Ok((ctx, builtins)) +} + +fn get_info<'a>( + sierra_program_registry: &'a ProgramRegistry, + ty: &'a cairo_lang_sierra::ids::ConcreteTypeId, +) -> Option<&'a cairo_lang_sierra::extensions::types::TypeInfo> { + sierra_program_registry + .get_type(ty) + .ok() + .map(|ctc| ctc.info()) +} + +/// Creates the metadata required for a Sierra program lowering to casm. +fn create_metadata( + sierra_program: &cairo_lang_sierra::program::Program, + metadata_config: Option, +) -> Result { + if let Some(metadata_config) = metadata_config { + calc_metadata(sierra_program, metadata_config).map_err(|err| match err { + MetadataError::ApChangeError(_) => VirtualMachineError::Unexpected, + MetadataError::CostError(_) => VirtualMachineError::Unexpected, + }) + } else { + Ok(Metadata { + ap_change_info: calc_ap_changes(sierra_program, |_, _| 0) + .map_err(|_| VirtualMachineError::Unexpected)?, + gas_info: GasInfo { + variable_values: Default::default(), + function_costs: Default::default(), + }, + }) + } +} + +fn get_function_builtins( + params: &[cairo_lang_sierra::ids::ConcreteTypeId], + append_output: bool, +) -> ( + Vec, + HashMap, +) { + let mut builtins = Vec::new(); + let mut builtin_offset: HashMap = HashMap::new(); + let mut current_offset = 3; + for (debug_name, builtin_name, sierra_id) in [ + ("Poseidon", BuiltinName::poseidon, PoseidonType::ID), + ("EcOp", BuiltinName::ec_op, EcOpType::ID), + ("Bitwise", BuiltinName::bitwise, BitwiseType::ID), + ("RangeCheck", BuiltinName::range_check, RangeCheckType::ID), + ("Pedersen", BuiltinName::pedersen, PedersenType::ID), + ] { + if params + .iter() + .any(|id| id.debug_name.as_deref() == Some(debug_name)) + { + builtins.push(builtin_name); + builtin_offset.insert(sierra_id, current_offset); + current_offset += 1; + } + } + // Force an output builtin so that we can write the program output into it's segment + if append_output { + builtins.push(BuiltinName::output); + } + builtins.reverse(); + (builtins, builtin_offset) +} + +fn fetch_return_values( + return_type_size: i16, + return_type_id: &ConcreteTypeId, + vm: &VirtualMachine, + builtin_count: i16, + fetch_from_output: bool, +) -> Result, Error> { + let mut return_values = if fetch_from_output { + let output_builtin_end = vm + .get_relocatable((vm.get_ap() + (-builtin_count as i32)).unwrap()) + .unwrap(); + let output_builtin_base = (output_builtin_end + (-return_type_size as i32)).unwrap(); + vm.get_continuous_range(output_builtin_base, return_type_size.into_or_panic())? + } else { + vm.get_continuous_range( + (vm.get_ap() - (return_type_size + builtin_count) as usize).unwrap(), + return_type_size as usize, + )? + }; + // Check if this result is a Panic result + if return_type_id + .debug_name + .as_ref() + .ok_or_else(|| Error::TypeIdNoDebugName(return_type_id.clone()))? + .starts_with("core::panics::PanicResult::") + { + // Check the failure flag (aka first return value) + if return_values.first() != Some(&MaybeRelocatable::from(0)) { + // In case of failure, extract the error from the return values (aka last two values) + let panic_data_end = return_values + .last() + .ok_or(Error::FailedToExtractReturnValues)? + .get_relocatable() + .ok_or(Error::FailedToExtractReturnValues)?; + let panic_data_start = return_values + .get(return_values.len() - 2) + .ok_or(Error::FailedToExtractReturnValues)? + .get_relocatable() + .ok_or(Error::FailedToExtractReturnValues)?; + let panic_data = vm.get_integer_range( + panic_data_start, + (panic_data_end - panic_data_start).map_err(VirtualMachineError::Math)?, + )?; + return Err(Error::RunPanic( + panic_data.iter().map(|c| *c.as_ref()).collect(), + )); + } else { + if return_values.len() < 3 { + return Err(Error::FailedToExtractReturnValues); + } + return_values = return_values[2..].to_vec() + } + } + Ok(return_values) +} + +// Calculates builtins' final_stack setting each stop_ptr +// Calling this function is a must if either air_public_input or cairo_pie are needed +fn finalize_builtins( + main_ret_types: &[ConcreteTypeId], + type_sizes: &UnorderedHashMap, + vm: &mut VirtualMachine, + builtin_count: i16, +) -> Result<(), Error> { + // Set stop pointers for builtins so we can obtain the air public input + // Cairo 1 programs have other return values aside from the used builtin's final pointers, so we need to hand-pick them + let ret_types_sizes = main_ret_types + .iter() + .map(|id| type_sizes.get(id).cloned().unwrap_or_default()); + let ret_types_and_sizes = main_ret_types.iter().zip(ret_types_sizes.clone()); + + let full_ret_types_size: i16 = ret_types_sizes.sum(); + let mut stack_pointer = (vm.get_ap() + - (full_ret_types_size as usize + builtin_count as usize).saturating_sub(1)) + .map_err(VirtualMachineError::Math)?; + + // Calculate the stack_ptr for each return builtin in the return values + let mut builtin_name_to_stack_pointer = HashMap::new(); + for (id, size) in ret_types_and_sizes { + if let Some(ref name) = id.debug_name { + let builtin_name = match &*name.to_string() { + "RangeCheck" => RANGE_CHECK_BUILTIN_NAME, + "Poseidon" => POSEIDON_BUILTIN_NAME, + "EcOp" => EC_OP_BUILTIN_NAME, + "Bitwise" => BITWISE_BUILTIN_NAME, + "Pedersen" => HASH_BUILTIN_NAME, + "Output" => OUTPUT_BUILTIN_NAME, + "Ecdsa" => SIGNATURE_BUILTIN_NAME, + _ => { + stack_pointer.offset += size as usize; + continue; + } + }; + builtin_name_to_stack_pointer.insert(builtin_name, stack_pointer); + } + stack_pointer.offset += size as usize; + } + + // Set stop pointer for each builtin + vm.builtins_final_stack_from_stack_pointer_dict(&builtin_name_to_stack_pointer, false)?; + Ok(()) +} + +fn serialize_output( + return_values: &[MaybeRelocatable], + vm: &mut VirtualMachine, + return_type_id: &ConcreteTypeId, + sierra_program_registry: &ProgramRegistry, + type_sizes: &UnorderedHashMap, +) -> String { + let mut output_string = String::new(); + let mut return_values_iter = return_values.iter().peekable(); + serialize_output_inner( + &mut return_values_iter, + &mut output_string, + vm, + return_type_id, + sierra_program_registry, + type_sizes, + ); + output_string +} + +fn serialize_output_inner<'a>( + return_values_iter: &mut Peekable>, + output_string: &mut String, + vm: &mut VirtualMachine, + return_type_id: &ConcreteTypeId, + sierra_program_registry: &ProgramRegistry, + type_sizes: &UnorderedHashMap, +) { + match sierra_program_registry.get_type(return_type_id).unwrap() { + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Array(info) => { + // Fetch array from memory + let array_start = return_values_iter + .next() + .expect("Missing return value") + .get_relocatable() + .expect("Array start_ptr not Relocatable"); + // Arrays can come in two formats: either [start_ptr, end_ptr] or [end_ptr], with the start_ptr being implicit (base of the end_ptr's segment) + let (array_start, array_size ) = match return_values_iter.peek().and_then(|mr| mr.get_relocatable()) { + Some(array_end) if array_end.segment_index == array_start.segment_index && array_end.offset >= array_start.offset => { + // Pop the value we just peeked + return_values_iter.next(); + (array_start, (array_end - array_start).unwrap()) + } + _ => ((array_start.segment_index, 0).into(), array_start.offset), + }; + let array_data = vm.get_continuous_range(array_start, array_size).unwrap(); + let mut array_data_iter = array_data.iter().peekable(); + let array_elem_id = &info.ty; + // Serialize array data + maybe_add_whitespace(output_string); + output_string.push('['); + while array_data_iter.peek().is_some() { + serialize_output_inner( + &mut array_data_iter, + output_string, + vm, + array_elem_id, + sierra_program_registry, + type_sizes, + ) + } + output_string.push(']'); + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Box(info) => { + // As this represents a pointer, we need to extract it's values + let ptr = return_values_iter + .next() + .expect("Missing return value") + .get_relocatable() + .expect("Box Pointer is not Relocatable"); + let type_size = type_sizes.type_size(&info.ty); + let data = vm + .get_continuous_range(ptr, type_size) + .expect("Failed to extract value from nullable ptr"); + let mut data_iter = data.iter().peekable(); + serialize_output_inner( + &mut data_iter, + output_string, + vm, + &info.ty, + sierra_program_registry, + type_sizes, + ) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Const(_) => { + unimplemented!("Not supported in the current version") + }, + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Felt252(_) + // Only unsigned integer values implement Into + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Bytes31(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Uint8(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Uint16(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Uint32(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Uint64(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Uint128(_) => { + maybe_add_whitespace(output_string); + let val = return_values_iter + .next() + .expect("Missing return value") + .get_int() + .expect("Value is not an integer"); + output_string.push_str(&val.to_string()); + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Sint8(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Sint16(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Sint32(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Sint64(_) + | cairo_lang_sierra::extensions::core::CoreTypeConcrete::Sint128(_) => { + maybe_add_whitespace(output_string); + let val = return_values_iter + .next() + .expect("Missing return value") + .get_int() + .expect("Value is not an integer"); + output_string.push_str(&signed_felt(val).to_string()); + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::NonZero(info) => { + serialize_output_inner( + return_values_iter, + output_string, + vm, + &info.ty, + sierra_program_registry, + type_sizes, + ) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Nullable(info) => { + // As this represents a pointer, we need to extract it's values + let ptr = match return_values_iter.next().expect("Missing return value") { + MaybeRelocatable::RelocatableValue(ptr) => *ptr, + MaybeRelocatable::Int(felt) if felt.is_zero() => { + // Nullable is Null + maybe_add_whitespace(output_string); + output_string.push_str("null"); + return; + } + _ => panic!("Invalid Nullable"), + }; + let type_size = type_sizes.type_size(&info.ty); + let data = vm + .get_continuous_range(ptr, type_size) + .expect("Failed to extract value from nullable ptr"); + let mut data_iter = data.iter().peekable(); + serialize_output_inner( + &mut data_iter, + output_string, + vm, + &info.ty, + sierra_program_registry, + type_sizes, + ) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Enum(info) => { + // First we check if it is a Panic enum, as we already handled panics when fetching return values, + // we can ignore them and move on to the non-panic variant + if let GenericArg::UserType(user_type) = &info.info.long_id.generic_args[0] { + if user_type + .debug_name + .as_ref() + .is_some_and(|n| n.starts_with("core::panics::PanicResult")) + { + return serialize_output_inner( + return_values_iter, + output_string, + vm, + &info.variants[0], + sierra_program_registry, + type_sizes, + ); + } + } + let num_variants = &info.variants.len(); + let casm_variant_idx: usize = return_values_iter + .next() + .expect("Missing return value") + .get_int() + .expect("Enum tag is not integer") + .to_usize() + .expect("Invalid enum tag"); + // Convert casm variant idx to sierra variant idx + let variant_idx = if *num_variants > 2 { + num_variants - 1 - (casm_variant_idx >> 1) + } else { + casm_variant_idx + }; + let variant_type_id = &info.variants[variant_idx]; + + // Handle core::bool separately + if let GenericArg::UserType(user_type) = &info.info.long_id.generic_args[0] { + if user_type + .debug_name + .as_ref() + .is_some_and(|n| n == "core::bool") + { + // Sanity checks + assert!( + *num_variants == 2 + && variant_idx < 2 + && type_sizes + .get(&info.variants[0]) + .is_some_and(|size| size.is_zero()) + && type_sizes + .get(&info.variants[1]) + .is_some_and(|size| size.is_zero()), + "Malformed bool enum" + ); + + let boolean_string = match variant_idx { + 0 => "false", + _ => "true", + }; + maybe_add_whitespace(output_string); + output_string.push_str(boolean_string); + return; + } + } + // TODO: Something similar to the bool handling could be done for unit enum variants if we could get the type info with the variant names + + // Space is always allocated for the largest enum member, padding with zeros in front for the smaller variants + let mut max_variant_size = 0; + for variant in &info.variants { + let variant_size = type_sizes.get(variant).unwrap(); + max_variant_size = std::cmp::max(max_variant_size, *variant_size) + } + for _ in 0..max_variant_size - type_sizes.get(variant_type_id).unwrap() { + // Remove padding + assert_eq!( + return_values_iter.next(), + Some(&MaybeRelocatable::from(0)), + "Malformed enum" + ); + } + serialize_output_inner( + return_values_iter, + output_string, + vm, + variant_type_id, + sierra_program_registry, + type_sizes, + ) + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Struct(info) => { + for member_type_id in &info.members { + serialize_output_inner( + return_values_iter, + output_string, + vm, + member_type_id, + sierra_program_registry, + type_sizes, + ) + } + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Felt252Dict(info) => { + // Process Dictionary + let dict_ptr = return_values_iter + .next() + .expect("Missing return val") + .get_relocatable() + .expect("Dict Ptr not Relocatable"); + if !(dict_ptr.offset + == vm + .get_segment_size(dict_ptr.segment_index as usize) + .unwrap_or_default() + && dict_ptr.offset % 3 == 0) + { + panic!("Return value is not a valid Felt252Dict") + } + // Fetch dictionary values type id + let value_type_id = &info.ty; + // Fetch the dictionary's memory + let dict_mem = vm + .get_continuous_range((dict_ptr.segment_index, 0).into(), dict_ptr.offset) + .expect("Malformed dictionary memory"); + // Serialize the dictionary + output_string.push('{'); + // The dictionary's memory is made up of (key, prev_value, next_value) tuples + // The prev value is not relevant to the user so we can skip over it for calrity + for (key, _, value) in dict_mem.iter().tuples() { + maybe_add_whitespace(output_string); + // Serialize the key wich should always be a Felt value + output_string.push_str(&key.to_string()); + output_string.push(':'); + // Serialize the value + // We create a peekable array here in order to use the serialize_output_inner as the value could be a span + let value_vec = vec![value.clone()]; + let mut value_iter = value_vec.iter().peekable(); + serialize_output_inner( + &mut value_iter, + output_string, + vm, + value_type_id, + sierra_program_registry, + type_sizes, + ); + } + output_string.push('}'); + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::SquashedFelt252Dict(info) => { + // Process Dictionary + let dict_start = return_values_iter + .next() + .expect("Missing return val") + .get_relocatable() + .expect("Squashed dict_start ptr not Relocatable"); + let dict_end = return_values_iter + .next() + .expect("Missing return val") + .get_relocatable() + .expect("Squashed dict_end ptr not Relocatable"); + let dict_size = (dict_end - dict_start).unwrap(); + if dict_size % 3 != 0 { + panic!("Return value is not a valid SquashedFelt252Dict") + } + // Fetch dictionary values type id + let value_type_id = &info.ty; + // Fetch the dictionary's memory + let dict_mem = vm + .get_continuous_range(dict_start, dict_size) + .expect("Malformed squashed dictionary memory"); + // Serialize the dictionary + output_string.push('{'); + // The dictionary's memory is made up of (key, prev_value, next_value) tuples + // The prev value is not relevant to the user so we can skip over it for calrity + for (key, _, value) in dict_mem.iter().tuples() { + maybe_add_whitespace(output_string); + // Serialize the key wich should always be a Felt value + output_string.push_str(&key.to_string()); + output_string.push(':'); + // Serialize the value + // We create a peekable array here in order to use the serialize_output_inner as the value could be a span + let value_vec = vec![value.clone()]; + let mut value_iter = value_vec.iter().peekable(); + serialize_output_inner( + &mut value_iter, + output_string, + vm, + value_type_id, + sierra_program_registry, + type_sizes, + ); + } + output_string.push('}'); + } + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Span(_) => unimplemented!("Span types get resolved to Array in the current version"), + cairo_lang_sierra::extensions::core::CoreTypeConcrete::Snapshot(info) => { + serialize_output_inner( + return_values_iter, + output_string, + vm, + &info.ty, + sierra_program_registry, + type_sizes, + ) + } + _ => panic!("Unexpected return type") + } +} + +fn maybe_add_whitespace(string: &mut String) { + if !string.is_empty() && !string.ends_with('[') && !string.ends_with('{') { + string.push(' '); + } +} + +#[cfg(test)] +mod tests { + use std::path::Path; + + use super::*; + use cairo_lang_compiler::{compile_cairo_project_at_path, CompilerConfig}; + use cairo_vm::types::relocatable::Relocatable; + use rstest::rstest; + + fn compile_to_sierra(filename: &str) -> SierraProgram { + let compiler_config = CompilerConfig { + replace_ids: true, + ..CompilerConfig::default() + }; + + compile_cairo_project_at_path(Path::new(filename), compiler_config).unwrap() + } + + fn main_hash_panic_result(sierra_program: &SierraProgram) -> bool { + let main_func = find_function(sierra_program, "::main").unwrap(); + main_func + .signature + .ret_types + .last() + .and_then(|rt| { + rt.debug_name + .as_ref() + .map(|n| n.as_ref().starts_with("core::panics::PanicResult::")) + }) + .unwrap_or_default() + } + + #[rstest] + #[case("../cairo_programs/cairo-1-programs/array_append.cairo")] + #[case("../cairo_programs/cairo-1-programs/array_get.cairo")] + #[case("../cairo_programs/cairo-1-programs/dictionaries.cairo")] + #[case("../cairo_programs/cairo-1-programs/enum_flow.cairo")] + #[case("../cairo_programs/cairo-1-programs/enum_match.cairo")] + #[case("../cairo_programs/cairo-1-programs/factorial.cairo")] + #[case("../cairo_programs/cairo-1-programs/fibonacci.cairo")] + #[case("../cairo_programs/cairo-1-programs/hello.cairo")] + #[case("../cairo_programs/cairo-1-programs/pedersen_example.cairo")] + #[case("../cairo_programs/cairo-1-programs/poseidon.cairo")] + #[case("../cairo_programs/cairo-1-programs/print.cairo")] + #[case("../cairo_programs/cairo-1-programs/array_append.cairo")] + #[case("../cairo_programs/cairo-1-programs/recursion.cairo")] + #[case("../cairo_programs/cairo-1-programs/sample.cairo")] + #[case("../cairo_programs/cairo-1-programs/simple_struct.cairo")] + #[case("../cairo_programs/cairo-1-programs/simple.cairo")] + #[case("../cairo_programs/cairo-1-programs/struct_span_return.cairo")] + fn check_append_ret_values_to_output_segment( + #[case] filename: &str, + #[values(true, false)] proof_mode: bool, + ) { + // Compile to sierra + let sierra_program = compile_to_sierra(filename); + // Set proof_mode + let cairo_run_config = Cairo1RunConfig { + proof_mode, + layout: "all_cairo", + append_return_values: !proof_mode, // This is so we can test appending return values when not running in proof_mode + finalize_builtins: true, + ..Default::default() + }; + // Run program + let (runner, vm, return_values, _) = + cairo_run_program(&sierra_program, cairo_run_config).unwrap(); + // When the return type is a PanicResult, we remove the panic wrapper when returning the ret values + // And handle the panics returning an error, so we need to add it here + let return_values = if main_hash_panic_result(&sierra_program) { + let mut rv = vec![Felt252::ZERO.into(), Felt252::ZERO.into()]; + rv.extend_from_slice(&return_values); + rv + } else { + return_values + }; + // Check that the output segment contains the return values + // The output builtin will always be the first builtin, so we know it's segment is 2 + let output_builtin_segment = vm + .get_continuous_range((2, 0).into(), return_values.len()) + .unwrap(); + assert_eq!(output_builtin_segment, return_values, "{}", filename); + // Just for consistency, we will check that there are no values in the output segment after the return values + assert!(vm + .get_maybe(&Relocatable::from((2_isize, return_values.len()))) + .is_none()); + + // Check that cairo_pie can be outputted when not running in proof_mode + if !proof_mode { + assert!(runner.get_cairo_pie(&vm).is_ok()) + } + } +} diff --git a/cairo1-run/src/main.rs b/cairo1-run/src/main.rs index 002f42129c..8e2a99e021 100644 --- a/cairo1-run/src/main.rs +++ b/cairo1-run/src/main.rs @@ -1,81 +1,28 @@ -#![allow(unused_imports)] use bincode::enc::write::Writer; -use cairo_lang_casm::casm; -use cairo_lang_casm::casm_extend; -use cairo_lang_casm::hints::Hint; -use cairo_lang_casm::instructions::Instruction; -use cairo_lang_compiler::db; use cairo_lang_compiler::{compile_cairo_project_at_path, CompilerConfig}; -use cairo_lang_sierra::extensions::bitwise::BitwiseType; -use cairo_lang_sierra::extensions::core::{CoreLibfunc, CoreType}; -use cairo_lang_sierra::extensions::ec::EcOpType; -use cairo_lang_sierra::extensions::gas::GasBuiltinType; -use cairo_lang_sierra::extensions::pedersen::PedersenType; -use cairo_lang_sierra::extensions::poseidon::PoseidonType; -use cairo_lang_sierra::extensions::range_check::RangeCheckType; -use cairo_lang_sierra::extensions::segment_arena::SegmentArenaType; -use cairo_lang_sierra::extensions::starknet::syscalls::SystemType; -use cairo_lang_sierra::extensions::ConcreteType; -use cairo_lang_sierra::extensions::NamedType; -use cairo_lang_sierra::ids::ConcreteTypeId; -use cairo_lang_sierra::program::Function; -use cairo_lang_sierra::program::Program as SierraProgram; -use cairo_lang_sierra::program_registry::{ProgramRegistry, ProgramRegistryError}; -use cairo_lang_sierra::{extensions::gas::CostTokenType, ProgramParser}; -use cairo_lang_sierra_ap_change::calc_ap_changes; -use cairo_lang_sierra_gas::gas_info::GasInfo; -use cairo_lang_sierra_to_casm::compiler::CairoProgram; -use cairo_lang_sierra_to_casm::compiler::CompilationError; -use cairo_lang_sierra_to_casm::metadata::Metadata; -use cairo_lang_sierra_to_casm::metadata::MetadataComputationConfig; -use cairo_lang_sierra_to_casm::metadata::MetadataError; -use cairo_lang_sierra_to_casm::{compiler::compile, metadata::calc_metadata}; -use cairo_lang_sierra_type_size::get_type_size_map; -use cairo_lang_utils::extract_matches; -use cairo_lang_utils::ordered_hash_map::OrderedHashMap; -use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; -use cairo_vm::air_public_input::PublicInputError; -use cairo_vm::cairo_run; -use cairo_vm::cairo_run::EncodeTraceError; -use cairo_vm::hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor; -use cairo_vm::serde::deserialize_program::BuiltinName; -use cairo_vm::serde::deserialize_program::{ApTracking, FlowTrackingData, HintParams}; -use cairo_vm::types::errors::program_errors::ProgramError; -use cairo_vm::types::relocatable::Relocatable; -use cairo_vm::utils::bigint_to_felt; -use cairo_vm::vm::decoding::decoder::decode_instruction; -use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; -use cairo_vm::vm::errors::memory_errors::MemoryError; -use cairo_vm::vm::errors::runner_errors::RunnerError; -use cairo_vm::vm::errors::trace_errors::TraceError; -use cairo_vm::vm::errors::vm_errors::VirtualMachineError; -use cairo_vm::vm::runners::builtin_runner::{ - BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, OUTPUT_BUILTIN_NAME, - POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, -}; -use cairo_vm::vm::runners::cairo_runner::CairoArg; -use cairo_vm::vm::runners::cairo_runner::RunnerMode; -use cairo_vm::vm::vm_memory::memory::Memory; +use cairo_lang_sierra::{ids::ConcreteTypeId, program_registry::ProgramRegistryError}; +use cairo_lang_sierra_to_casm::{compiler::CompilationError, metadata::MetadataError}; +use cairo_run::Cairo1RunConfig; use cairo_vm::{ - serde::deserialize_program::ReferenceManager, - types::{program::Program, relocatable::MaybeRelocatable}, - vm::{ - runners::cairo_runner::{CairoRunner, RunResources}, - vm_core::VirtualMachine, + air_public_input::PublicInputError, + cairo_run::EncodeTraceError, + types::errors::program_errors::ProgramError, + vm::errors::{ + memory_errors::MemoryError, runner_errors::RunnerError, trace_errors::TraceError, + vm_errors::VirtualMachineError, }, Felt252, }; -use clap::{CommandFactory, Parser, ValueHint}; -use itertools::{chain, Itertools}; -use std::borrow::Cow; -use std::io::BufWriter; -use std::io::Write; -use std::iter::Peekable; -use std::path::PathBuf; -use std::slice::Iter; -use std::{collections::HashMap, io, path::Path}; +use clap::{Parser, ValueHint}; +use itertools::Itertools; +use std::{ + io::{self, Write}, + path::PathBuf, +}; use thiserror::Error; +pub mod cairo_run; + #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { @@ -109,10 +56,17 @@ struct Args { args: FuncArgs, #[clap(long = "print_output", value_parser)] print_output: bool, + #[clap( + long = "append_return_values", + // We need to add these air_private_input & air_public_input or else + // passing cairo_pie_output + either of these without proof_mode will not fail + conflicts_with_all = ["proof_mode", "air_private_input", "air_public_input"] + )] + append_return_values: bool, } #[derive(Debug, Clone)] -enum FuncArg { +pub enum FuncArg { Array(Vec), Single(Felt252), } @@ -160,6 +114,7 @@ fn validate_layout(value: &str) -> Result { "plain" | "small" | "dex" + | "recursive" | "starknet" | "starknet_with_keccak" | "recursive_large_output" @@ -171,7 +126,7 @@ fn validate_layout(value: &str) -> Result { } #[derive(Debug, Error)] -enum Error { +pub enum Error { #[error("Invalid arguments")] Cli(#[from] clap::Error), #[error("Failed to interact with the file system")] @@ -255,232 +210,27 @@ impl FileWriter { fn run(args: impl Iterator) -> Result, Error> { let args = Args::try_parse_from(args)?; + let cairo_run_config = Cairo1RunConfig { + proof_mode: args.proof_mode, + serialize_output: args.print_output, + relocate_mem: args.memory_file.is_some() || args.air_public_input.is_some(), + layout: &args.layout, + trace_enabled: args.trace_file.is_some() || args.air_public_input.is_some(), + args: &args.args.0, + finalize_builtins: args.air_private_input.is_some() || args.cairo_pie_output.is_some(), + append_return_values: args.append_return_values, + }; + let compiler_config = CompilerConfig { replace_ids: true, ..CompilerConfig::default() }; + let sierra_program = compile_cairo_project_at_path(&args.filename, compiler_config) .map_err(|err| Error::SierraCompilation(err.to_string()))?; - let metadata_config = Some(Default::default()); - - let gas_usage_check = metadata_config.is_some(); - let metadata = create_metadata(&sierra_program, metadata_config)?; - let sierra_program_registry = ProgramRegistry::::new(&sierra_program)?; - let type_sizes = - get_type_size_map(&sierra_program, &sierra_program_registry).unwrap_or_default(); - let casm_program = - cairo_lang_sierra_to_casm::compiler::compile(&sierra_program, &metadata, gas_usage_check)?; - - let main_func = find_function(&sierra_program, "::main")?; - - let initial_gas = 9999999999999_usize; - - // Modified entry code to be compatible with custom cairo1 Proof Mode. - // This adds code that's needed for dictionaries, adjusts ap for builtin pointers, adds initial gas for the gas builtin if needed, and sets up other necessary code for cairo1 - let (entry_code, builtins) = create_entry_code( - &sierra_program_registry, - &casm_program, - &type_sizes, - main_func, - initial_gas, - args.proof_mode, - &args.args.0, - )?; - - // Get the user program instructions - let program_instructions = casm_program.instructions.iter(); - - // This footer is used by lib funcs - let libfunc_footer = create_code_footer(); - - let proof_mode_header = if args.proof_mode { - println!("Compiling with proof mode and running ..."); - - // This information can be useful for the users using the prover. - println!("Builtins used: {:?}", builtins); - - // Prepare "canonical" proof mode instructions. These are usually added by the compiler in cairo 0 - let mut ctx = casm! {}; - casm_extend! {ctx, - call rel 4; - jmp rel 0; - }; - ctx.instructions - } else { - casm! {}.instructions - }; - - // This is the program we are actually running/proving - // With (embedded proof mode), cairo1 header and the libfunc footer - let instructions = chain!( - proof_mode_header.iter(), - entry_code.iter(), - program_instructions, - libfunc_footer.iter() - ); - - let (processor_hints, program_hints) = build_hints_vec(instructions.clone()); - - let mut hint_processor = Cairo1HintProcessor::new(&processor_hints, RunResources::default()); - - let data: Vec = instructions - .flat_map(|inst| inst.assemble().encode()) - .map(|x| bigint_to_felt(&x).unwrap_or_default()) - .map(MaybeRelocatable::from) - .collect(); - - let data_len = data.len(); - - let program = if args.proof_mode { - Program::new_for_proof( - builtins, - data, - 0, - // Proof mode is on top - // jmp rel 0 is on PC == 2 - 2, - program_hints, - ReferenceManager { - references: Vec::new(), - }, - HashMap::new(), - vec![], - None, - )? - } else { - Program::new( - builtins, - data, - Some(0), - program_hints, - ReferenceManager { - references: Vec::new(), - }, - HashMap::new(), - vec![], - None, - )? - }; - - let runner_mode = if args.proof_mode { - RunnerMode::ProofModeCairo1 - } else { - RunnerMode::ExecutionMode - }; - - let mut runner = CairoRunner::new_v2(&program, &args.layout, runner_mode)?; - let mut vm = VirtualMachine::new(args.trace_file.is_some() || args.air_public_input.is_some()); - let end = runner.initialize(&mut vm)?; - - additional_initialization(&mut vm, data_len)?; - - // Run it until the end/ infinite loop in proof_mode - runner.run_until_pc(end, &mut vm, &mut hint_processor)?; - runner.end_run(false, false, &mut vm, &mut hint_processor)?; - - // Fetch return type data - let return_type_id = main_func - .signature - .ret_types - .last() - .ok_or(Error::NoRetTypesInSignature)?; - let return_type_size = type_sizes - .get(return_type_id) - .cloned() - .ok_or_else(|| Error::NoTypeSizeForId(return_type_id.clone()))?; - - let mut return_values = vm.get_return_values(return_type_size as usize)?; - // Check if this result is a Panic result - if return_type_id - .debug_name - .as_ref() - .ok_or_else(|| Error::TypeIdNoDebugName(return_type_id.clone()))? - .starts_with("core::panics::PanicResult::") - { - // Check the failure flag (aka first return value) - if return_values.first() != Some(&MaybeRelocatable::from(0)) { - // In case of failure, extract the error from the return values (aka last two values) - let panic_data_end = return_values - .last() - .ok_or(Error::FailedToExtractReturnValues)? - .get_relocatable() - .ok_or(Error::FailedToExtractReturnValues)?; - let panic_data_start = return_values - .get(return_values.len() - 2) - .ok_or(Error::FailedToExtractReturnValues)? - .get_relocatable() - .ok_or(Error::FailedToExtractReturnValues)?; - let panic_data = vm.get_integer_range( - panic_data_start, - (panic_data_end - panic_data_start).map_err(VirtualMachineError::Math)?, - )?; - return Err(Error::RunPanic( - panic_data.iter().map(|c| *c.as_ref()).collect(), - )); - } else { - if return_values.len() < 3 { - return Err(Error::FailedToExtractReturnValues); - } - return_values = return_values[2..].to_vec() - } - } - - let output_string = if args.print_output { - Some(serialize_output(&vm, &return_values)) - } else { - None - }; - - // Set stop pointers for builtins so we can obtain the air public input - if args.air_public_input.is_some() || args.cairo_pie_output.is_some() { - // Cairo 1 programs have other return values aside from the used builtin's final pointers, so we need to hand-pick them - let ret_types_sizes = main_func - .signature - .ret_types - .iter() - .map(|id| type_sizes.get(id).cloned().unwrap_or_default()); - let ret_types_and_sizes = main_func - .signature - .ret_types - .iter() - .zip(ret_types_sizes.clone()); - - let full_ret_types_size: i16 = ret_types_sizes.sum(); - let mut stack_pointer = (vm.get_ap() - (full_ret_types_size as usize).saturating_sub(1)) - .map_err(VirtualMachineError::Math)?; - - // Calculate the stack_ptr for each return builtin in the return values - let mut builtin_name_to_stack_pointer = HashMap::new(); - for (id, size) in ret_types_and_sizes { - if let Some(ref name) = id.debug_name { - let builtin_name = match &*name.to_string() { - "RangeCheck" => RANGE_CHECK_BUILTIN_NAME, - "Poseidon" => POSEIDON_BUILTIN_NAME, - "EcOp" => EC_OP_BUILTIN_NAME, - "Bitwise" => BITWISE_BUILTIN_NAME, - "Pedersen" => HASH_BUILTIN_NAME, - "Output" => OUTPUT_BUILTIN_NAME, - "Ecdsa" => SIGNATURE_BUILTIN_NAME, - _ => { - stack_pointer.offset += size as usize; - continue; - } - }; - builtin_name_to_stack_pointer.insert(builtin_name, stack_pointer); - } - stack_pointer.offset += size as usize; - } - // Set stop pointer for each builtin - vm.builtins_final_stack_from_stack_pointer_dict(&builtin_name_to_stack_pointer)?; - - // Build execution public memory - if args.proof_mode { - runner.finalize_segments(&mut vm)?; - } - } - - runner.relocate(&mut vm, true)?; + let (runner, vm, _, serialized_output) = + cairo_run::cairo_run_program(&sierra_program, cairo_run_config)?; if let Some(file_path) = args.air_public_input { let json = runner.get_air_public_input(&vm)?.serialize_json()?; @@ -526,7 +276,7 @@ fn run(args: impl Iterator) -> Result, Error> { let mut trace_writer = FileWriter::new(io::BufWriter::with_capacity(3 * 1024 * 1024, trace_file)); - cairo_run::write_encoded_trace(&relocated_trace, &mut trace_writer)?; + cairo_vm::cairo_run::write_encoded_trace(&relocated_trace, &mut trace_writer)?; trace_writer.flush()?; } if let Some(memory_path) = args.memory_file { @@ -534,31 +284,11 @@ fn run(args: impl Iterator) -> Result, Error> { let mut memory_writer = FileWriter::new(io::BufWriter::with_capacity(5 * 1024 * 1024, memory_file)); - cairo_run::write_encoded_memory(&runner.relocated_memory, &mut memory_writer)?; + cairo_vm::cairo_run::write_encoded_memory(&runner.relocated_memory, &mut memory_writer)?; memory_writer.flush()?; } - Ok(output_string) -} - -fn additional_initialization(vm: &mut VirtualMachine, data_len: usize) -> Result<(), Error> { - // Create the builtin cost segment - let builtin_cost_segment = vm.add_memory_segment(); - for token_type in CostTokenType::iter_precost() { - vm.insert_value( - (builtin_cost_segment + (token_type.offset_in_builtin_costs() as usize)) - .map_err(VirtualMachineError::Math)?, - Felt252::default(), - )? - } - // Put a pointer to the builtin cost segment at the end of the program (after the - // additional `ret` statement). - vm.insert_value( - (vm.get_pc() + data_len).map_err(VirtualMachineError::Math)?, - builtin_cost_segment, - )?; - - Ok(()) + Ok(serialized_output) } fn main() -> Result<(), Error> { @@ -592,345 +322,8 @@ fn main() -> Result<(), Error> { } } -#[allow(clippy::type_complexity)] -fn build_hints_vec<'b>( - instructions: impl Iterator, -) -> (Vec<(usize, Vec)>, HashMap>) { - let mut hints: Vec<(usize, Vec)> = Vec::new(); - let mut program_hints: HashMap> = HashMap::new(); - - let mut hint_offset = 0; - - for instruction in instructions { - if !instruction.hints.is_empty() { - hints.push((hint_offset, instruction.hints.clone())); - program_hints.insert( - hint_offset, - vec![HintParams { - code: hint_offset.to_string(), - accessible_scopes: Vec::new(), - flow_tracking_data: FlowTrackingData { - ap_tracking: ApTracking::default(), - reference_ids: HashMap::new(), - }, - }], - ); - } - hint_offset += instruction.body.op_size(); - } - (hints, program_hints) -} - -/// Finds first function ending with `name_suffix`. -fn find_function<'a>( - sierra_program: &'a SierraProgram, - name_suffix: &'a str, -) -> Result<&'a Function, RunnerError> { - sierra_program - .funcs - .iter() - .find(|f| { - if let Some(name) = &f.id.debug_name { - name.ends_with(name_suffix) - } else { - false - } - }) - .ok_or_else(|| RunnerError::MissingMain) -} - -/// Creates a list of instructions that will be appended to the program's bytecode. -fn create_code_footer() -> Vec { - casm! { - // Add a `ret` instruction used in libfuncs that retrieve the current value of the `fp` - // and `pc` registers. - ret; - } - .instructions -} - -/// Returns the instructions to add to the beginning of the code to successfully call the main -/// function, as well as the builtins required to execute the program. -fn create_entry_code( - sierra_program_registry: &ProgramRegistry, - casm_program: &CairoProgram, - type_sizes: &UnorderedHashMap, - func: &Function, - initial_gas: usize, - proof_mode: bool, - args: &Vec, -) -> Result<(Vec, Vec), Error> { - let mut ctx = casm! {}; - // The builtins in the formatting expected by the runner. - let (builtins, builtin_offset) = get_function_builtins(func); - // Load all vecs to memory. - // Load all array args content to memory. - let mut array_args_data = vec![]; - let mut ap_offset: i16 = 0; - for arg in args { - let FuncArg::Array(values) = arg else { continue }; - array_args_data.push(ap_offset); - casm_extend! {ctx, - %{ memory[ap + 0] = segments.add() %} - ap += 1; - } - for (i, v) in values.iter().enumerate() { - let arr_at = (i + 1) as i16; - casm_extend! {ctx, - [ap + 0] = (v.to_bigint()); - [ap + 0] = [[ap - arr_at] + (i as i16)], ap++; - }; - } - ap_offset += (1 + values.len()) as i16; - } - let mut array_args_data_iter = array_args_data.iter(); - let after_arrays_data_offset = ap_offset; - let mut arg_iter = args.iter().enumerate(); - let mut param_index = 0; - let mut expected_arguments_size = 0; - if func.signature.param_types.iter().any(|ty| { - get_info(sierra_program_registry, ty) - .map(|x| x.long_id.generic_id == SegmentArenaType::ID) - .unwrap_or_default() - }) { - casm_extend! {ctx, - // SegmentArena segment. - %{ memory[ap + 0] = segments.add() %} - // Infos segment. - %{ memory[ap + 1] = segments.add() %} - ap += 2; - [ap + 0] = 0, ap++; - // Write Infos segment, n_constructed (0), and n_destructed (0) to the segment. - [ap - 2] = [[ap - 3]]; - [ap - 1] = [[ap - 3] + 1]; - [ap - 1] = [[ap - 3] + 2]; - } - ap_offset += 3; - } - for ty in func.signature.param_types.iter() { - let info = get_info(sierra_program_registry, ty) - .ok_or_else(|| Error::NoInfoForType(ty.clone()))?; - let generic_ty = &info.long_id.generic_id; - if let Some(offset) = builtin_offset.get(generic_ty) { - let mut offset = *offset; - if proof_mode { - // Everything is off by 2 due to the proof mode header - offset += 2; - } - casm_extend! {ctx, - [ap + 0] = [fp - offset], ap++; - } - ap_offset += 1; - } else if generic_ty == &SystemType::ID { - casm_extend! {ctx, - %{ memory[ap + 0] = segments.add() %} - ap += 1; - } - ap_offset += 1; - } else if generic_ty == &GasBuiltinType::ID { - casm_extend! {ctx, - [ap + 0] = initial_gas, ap++; - } - ap_offset += 1; - } else if generic_ty == &SegmentArenaType::ID { - let offset = -ap_offset + after_arrays_data_offset; - casm_extend! {ctx, - [ap + 0] = [ap + offset] + 3, ap++; - } - ap_offset += 1; - } else { - let ty_size = type_sizes[ty]; - let param_ap_offset_end = ap_offset + ty_size; - expected_arguments_size += ty_size; - while ap_offset < param_ap_offset_end { - let Some((arg_index, arg)) = arg_iter.next() else { - break; - }; - match arg { - FuncArg::Single(value) => { - casm_extend! {ctx, - [ap + 0] = (value.to_bigint()), ap++; - } - ap_offset += 1; - } - FuncArg::Array(values) => { - let offset = -ap_offset + array_args_data_iter.next().unwrap(); - casm_extend! {ctx, - [ap + 0] = [ap + (offset)], ap++; - [ap + 0] = [ap - 1] + (values.len()), ap++; - } - ap_offset += 2; - if ap_offset > param_ap_offset_end { - return Err(Error::ArgumentUnaligned { - param_index, - arg_index, - }); - } - } - } - } - param_index += 1; - }; - } - let actual_args_size = args - .iter() - .map(|arg| match arg { - FuncArg::Single(_) => 1, - FuncArg::Array(_) => 2, - }) - .sum::(); - if expected_arguments_size != actual_args_size { - return Err(Error::ArgumentsSizeMismatch { - expected: expected_arguments_size, - actual: actual_args_size, - }); - } - - let before_final_call = ctx.current_code_offset; - let final_call_size = 3; - let offset = final_call_size - + casm_program.debug_info.sierra_statement_info[func.entry_point.0].code_offset; - - casm_extend! {ctx, - call rel offset; - ret; - } - assert_eq!(before_final_call + final_call_size, ctx.current_code_offset); - - Ok((ctx.instructions, builtins)) -} - -fn get_info<'a>( - sierra_program_registry: &'a ProgramRegistry, - ty: &'a cairo_lang_sierra::ids::ConcreteTypeId, -) -> Option<&'a cairo_lang_sierra::extensions::types::TypeInfo> { - sierra_program_registry - .get_type(ty) - .ok() - .map(|ctc| ctc.info()) -} - -/// Creates the metadata required for a Sierra program lowering to casm. -fn create_metadata( - sierra_program: &cairo_lang_sierra::program::Program, - metadata_config: Option, -) -> Result { - if let Some(metadata_config) = metadata_config { - calc_metadata(sierra_program, metadata_config).map_err(|err| match err { - MetadataError::ApChangeError(_) => VirtualMachineError::Unexpected, - MetadataError::CostError(_) => VirtualMachineError::Unexpected, - }) - } else { - Ok(Metadata { - ap_change_info: calc_ap_changes(sierra_program, |_, _| 0) - .map_err(|_| VirtualMachineError::Unexpected)?, - gas_info: GasInfo { - variable_values: Default::default(), - function_costs: Default::default(), - }, - }) - } -} - -fn get_function_builtins( - func: &Function, -) -> ( - Vec, - HashMap, -) { - let entry_params = &func.signature.param_types; - let mut builtins = Vec::new(); - let mut builtin_offset: HashMap = HashMap::new(); - let mut current_offset = 3; - // Fetch builtins from the entry_params in the standard order - if entry_params - .iter() - .any(|ti| ti.debug_name == Some("Poseidon".into())) - { - builtins.push(BuiltinName::poseidon); - builtin_offset.insert(PoseidonType::ID, current_offset); - current_offset += 1; - } - if entry_params - .iter() - .any(|ti| ti.debug_name == Some("EcOp".into())) - { - builtins.push(BuiltinName::ec_op); - builtin_offset.insert(EcOpType::ID, current_offset); - current_offset += 1 - } - if entry_params - .iter() - .any(|ti| ti.debug_name == Some("Bitwise".into())) - { - builtins.push(BuiltinName::bitwise); - builtin_offset.insert(BitwiseType::ID, current_offset); - current_offset += 1; - } - if entry_params - .iter() - .any(|ti| ti.debug_name == Some("RangeCheck".into())) - { - builtins.push(BuiltinName::range_check); - builtin_offset.insert(RangeCheckType::ID, current_offset); - current_offset += 1; - } - if entry_params - .iter() - .any(|ti| ti.debug_name == Some("Pedersen".into())) - { - builtins.push(BuiltinName::pedersen); - builtin_offset.insert(PedersenType::ID, current_offset); - } - builtins.reverse(); - (builtins, builtin_offset) -} - -fn serialize_output(vm: &VirtualMachine, return_values: &[MaybeRelocatable]) -> String { - let mut output_string = String::new(); - let mut return_values_iter: Peekable> = return_values.iter().peekable(); - serialize_output_inner(&mut return_values_iter, &mut output_string, vm); - fn serialize_output_inner( - iter: &mut Peekable>, - output_string: &mut String, - vm: &VirtualMachine, - ) { - while let Some(val) = iter.next() { - if let MaybeRelocatable::RelocatableValue(x) = val { - // Check if the next value is a relocatable of the same index - if let Some(MaybeRelocatable::RelocatableValue(y)) = iter.peek() { - // Check if the two relocatable values represent a valid array in memory - if x.segment_index == y.segment_index && x.offset <= y.offset { - // Fetch the y value from the iterator so we don't serialize it twice - iter.next(); - // Fetch array - maybe_add_whitespace(output_string); - output_string.push('['); - let array = vm.get_continuous_range(*x, y.offset - x.offset).unwrap(); - let mut array_iter: Peekable> = - array.iter().peekable(); - serialize_output_inner(&mut array_iter, output_string, vm); - output_string.push(']'); - continue; - } - } - } - maybe_add_whitespace(output_string); - output_string.push_str(&val.to_string()); - } - } - - fn maybe_add_whitespace(string: &mut String) { - if !string.is_empty() && !string.ends_with('[') { - string.push(' '); - } - } - output_string -} - #[cfg(test)] mod tests { - #![allow(clippy::too_many_arguments)] use super::*; use assert_matches::assert_matches; use rstest::rstest; @@ -980,7 +373,7 @@ mod tests { #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/hello.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] fn test_run_hello_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); - assert_matches!(run(args), Ok(Some(res)) if res == "1 1234"); + assert_matches!(run(args), Ok(Some(res)) if res == "1234"); } #[rstest] @@ -1044,7 +437,7 @@ mod tests { #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] fn test_run_simple_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); - assert_matches!(run(args), Ok(Some(res)) if res == "1"); + assert_matches!(run(args), Ok(Some(res)) if res == "true"); } #[rstest] @@ -1103,6 +496,14 @@ mod tests { assert_matches!(run(args), Ok(Some(res)) if res == "12"); } + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/struct_span_return.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/struct_span_return.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_struct_span_return(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(Some(res)) if res == "[[4 3] [2 1]]"); + } + #[rstest] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/with_input/tensor.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null", "--args", "[2 2] [1 2 3 4]"].as_slice())] #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/with_input/tensor.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null", "--args", "[2 2] [1 2 3 4]"].as_slice())] @@ -1110,4 +511,93 @@ mod tests { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(Some(res)) if res == "1"); } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/nullable_dict.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/nullable_dict.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_nullable_dict_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(Some(res)) if res.is_empty()); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/felt_dict.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/felt_dict.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_felt_dict(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "{66675: [8 9 10 11] 66676: [1 2 3]}"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/felt_span.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/felt_span.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_felt_span(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "[8 9 10 11]"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/array_integer_tuple.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/array_integer_tuple.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_array_integer_tuple(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "[1] 1"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/nullable_box_vec.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/nullable_box_vec.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_nullable_box_vec(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "{0: 10 1: 20 2: 30} 3"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/dict_with_struct.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/dict_with_struct.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_dict_with_struct(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "{0: 1 true 1: 1 false 2: 1 true}"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/felt_dict_squash.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/felt_dict_squash.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_felt_dict_squash(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "{66675: [4 5 6] 66676: [1 2 3]}"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/null_ret.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/null_ret.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_null_ret(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "null"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/bytes31_ret.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/bytes31_ret.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_bytes31_ret(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "123"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/tensor_new.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--cairo_pie_output", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/tensor_new.cairo", "--print_output", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo", "--proof_mode", "--air_public_input", "/dev/null", "--air_private_input", "/dev/null"].as_slice())] + fn test_run_tensor_new(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + let expected_output = "[1 2] [1 false 1 true]"; + assert_matches!(run(args), Ok(Some(res)) if res == expected_output); + } } diff --git a/cairo_programs/cairo-1-programs/array_append.cairo b/cairo_programs/cairo-1-programs/array_append.cairo index 81d7f2fc9f..f17418ef7b 100644 --- a/cairo_programs/cairo-1-programs/array_append.cairo +++ b/cairo_programs/cairo-1-programs/array_append.cairo @@ -4,6 +4,6 @@ fn main() -> Array { let mut numbers = ArrayTrait::new(); numbers.append(4_u32); numbers.append(2_u32); - numbers.pop_front(); + let _x = numbers.pop_front(); numbers } diff --git a/cairo_programs/cairo-1-programs/array_integer_tuple.cairo b/cairo_programs/cairo-1-programs/array_integer_tuple.cairo new file mode 100644 index 0000000000..cb018f3a4a --- /dev/null +++ b/cairo_programs/cairo-1-programs/array_integer_tuple.cairo @@ -0,0 +1,9 @@ +use core::array::ArrayTrait; + + +fn main() -> (Array, u32) { + let mut numbers = ArrayTrait::new(); + numbers.append(1); + + (numbers, 1) +} diff --git a/cairo_programs/cairo-1-programs/bytes31_ret.cairo b/cairo_programs/cairo-1-programs/bytes31_ret.cairo new file mode 100644 index 0000000000..3a67f9cbf5 --- /dev/null +++ b/cairo_programs/cairo-1-programs/bytes31_ret.cairo @@ -0,0 +1,5 @@ +fn main() -> bytes31 { + let a: u128 = 123; + let b: bytes31 = a.into(); + b +} diff --git a/cairo_programs/cairo-1-programs/dict_with_struct.cairo b/cairo_programs/cairo-1-programs/dict_with_struct.cairo new file mode 100644 index 0000000000..e24df874c2 --- /dev/null +++ b/cairo_programs/cairo-1-programs/dict_with_struct.cairo @@ -0,0 +1,24 @@ +use core::nullable::{nullable_from_box, match_nullable, FromNullableResult}; + + +#[derive(Drop, Copy)] +struct FP16x16 { + mag: u32, + sign: bool +} + +fn main() -> Felt252Dict> { + // Create the dictionary + let mut d: Felt252Dict> = Default::default(); + + let box_a = BoxTrait::new(FP16x16 { mag: 1, sign: false }); + let box_b = BoxTrait::new(FP16x16 { mag: 1, sign: true }); + let box_c = BoxTrait::new(FP16x16 { mag: 1, sign: true }); + + // Insert it as a `Span` + d.insert(0, nullable_from_box(box_c)); + d.insert(1, nullable_from_box(box_a)); + d.insert(2, nullable_from_box(box_b)); + + d +} diff --git a/cairo_programs/cairo-1-programs/dictionaries.cairo b/cairo_programs/cairo-1-programs/dictionaries.cairo index 56176777b5..67465ee2d1 100644 --- a/cairo_programs/cairo-1-programs/dictionaries.cairo +++ b/cairo_programs/cairo-1-programs/dictionaries.cairo @@ -3,13 +3,13 @@ use dict::Felt252DictTrait; fn main() -> felt252 { let mut dict_u8 = felt252_dict_new::(); let mut dict_felt = felt252_dict_new::(); - let mut dict_felt2 = felt252_dict_new::(); + let _dict_felt2 = felt252_dict_new::(); dict_u8.insert(10, 110); dict_u8.insert(10, 110); - let val10 = dict_u8[10]; // 110 - let val11 = dict_felt[11]; // 0 + let _val10 = dict_u8[10]; // 110 + let _val11 = dict_felt[11]; // 0 dict_felt.insert(11, 1024); dict_felt[11] // 1024 } diff --git a/cairo_programs/cairo-1-programs/enum_flow.cairo b/cairo_programs/cairo-1-programs/enum_flow.cairo index 17d4e5a56b..38b99f4489 100644 --- a/cairo_programs/cairo-1-programs/enum_flow.cairo +++ b/cairo_programs/cairo-1-programs/enum_flow.cairo @@ -26,9 +26,9 @@ fn main() -> felt252 { match_long(el1); let el2 = MyEnumLong::c(22); match_long(el2); - let eg1: MyEnumGeneric<(), felt252> = MyEnumGeneric::<(), felt252>::a(30); - let eg2: MyEnumGeneric<(), felt252> = MyEnumGeneric::<(), felt252>::b(()); - let eg3: MyEnumGeneric<(), felt252> = MyEnumGeneric::<(), felt252>::c(32); + let _eg1: MyEnumGeneric<(), felt252> = MyEnumGeneric::<(), felt252>::a(30); + let _eg2: MyEnumGeneric<(), felt252> = MyEnumGeneric::<(), felt252>::b(()); + let _eg3: MyEnumGeneric<(), felt252> = MyEnumGeneric::<(), felt252>::c(32); 300 } diff --git a/cairo_programs/cairo-1-programs/felt_dict.cairo b/cairo_programs/cairo-1-programs/felt_dict.cairo new file mode 100644 index 0000000000..9934d4dcc9 --- /dev/null +++ b/cairo_programs/cairo-1-programs/felt_dict.cairo @@ -0,0 +1,15 @@ +use core::nullable::{nullable_from_box, match_nullable, FromNullableResult}; + +fn main() -> Felt252Dict>> { + // Create the dictionary + let mut d: Felt252Dict>> = Default::default(); + + // Create the array to insert + let a = array![8, 9, 10, 11]; + let b = array![1, 2, 3]; + + // Insert it as a `Span` + d.insert(66675, nullable_from_box(BoxTrait::new(a.span()))); + d.insert(66676, nullable_from_box(BoxTrait::new(b.span()))); + d +} diff --git a/cairo_programs/cairo-1-programs/felt_dict_squash.cairo b/cairo_programs/cairo-1-programs/felt_dict_squash.cairo new file mode 100644 index 0000000000..7f1e284e32 --- /dev/null +++ b/cairo_programs/cairo-1-programs/felt_dict_squash.cairo @@ -0,0 +1,18 @@ +use core::nullable::{nullable_from_box, match_nullable, FromNullableResult}; +use core::dict::Felt252DictEntry; + +fn main() -> SquashedFelt252Dict>> { + // Create the dictionary + let mut d: Felt252Dict>> = Default::default(); + + // Create the array to insert + let a = array![8, 9, 10, 11]; + let b = array![1, 2, 3]; + let c = array![4, 5, 6]; + + // Insert it as a `Span` + d.insert(66675, nullable_from_box(BoxTrait::new(a.span()))); + d.insert(66676, nullable_from_box(BoxTrait::new(b.span()))); + d.insert(66675, nullable_from_box(BoxTrait::new(c.span()))); + d.squash() +} diff --git a/cairo_programs/cairo-1-programs/felt_span.cairo b/cairo_programs/cairo-1-programs/felt_span.cairo new file mode 100644 index 0000000000..a1a9d708fe --- /dev/null +++ b/cairo_programs/cairo-1-programs/felt_span.cairo @@ -0,0 +1,6 @@ +use core::nullable::{nullable_from_box, match_nullable, FromNullableResult}; + +fn main() -> Nullable> { + let a = array![8, 9, 10, 11]; + nullable_from_box(BoxTrait::new(a.span())) +} diff --git a/cairo_programs/cairo-1-programs/null_ret.cairo b/cairo_programs/cairo-1-programs/null_ret.cairo new file mode 100644 index 0000000000..85769a8e15 --- /dev/null +++ b/cairo_programs/cairo-1-programs/null_ret.cairo @@ -0,0 +1,3 @@ +fn main() -> Nullable { + null() +} diff --git a/cairo_programs/cairo-1-programs/nullable_box_vec.cairo b/cairo_programs/cairo-1-programs/nullable_box_vec.cairo new file mode 100644 index 0000000000..37b2b8042a --- /dev/null +++ b/cairo_programs/cairo-1-programs/nullable_box_vec.cairo @@ -0,0 +1,19 @@ +struct NullableVec { + items: Felt252Dict>>, + len: usize, +} + +fn main() -> NullableVec { + let mut d: Felt252Dict>> = Default::default(); + + // Populate the dictionary + d.insert(0, nullable_from_box(BoxTrait::new(BoxTrait::new(10)))); + d.insert(1, nullable_from_box(BoxTrait::new(BoxTrait::new(20)))); + d.insert(2, nullable_from_box(BoxTrait::new(BoxTrait::new(30)))); + + // Return NullableVec + NullableVec { + items: d, + len: 3, + } +} diff --git a/cairo_programs/cairo-1-programs/nullable_dict.cairo b/cairo_programs/cairo-1-programs/nullable_dict.cairo new file mode 100644 index 0000000000..969e16bb0f --- /dev/null +++ b/cairo_programs/cairo-1-programs/nullable_dict.cairo @@ -0,0 +1,12 @@ +use core::nullable::{nullable_from_box, match_nullable, FromNullableResult}; + +fn main() { + // Create the dictionary + let mut d: Felt252Dict>> = Default::default(); + + // Create the array to insert + let a = array![8, 9, 10]; + + // Insert it as a `Span` + d.insert(0, nullable_from_box(BoxTrait::new(a.span()))); +} diff --git a/cairo_programs/cairo-1-programs/tensor_new.cairo b/cairo_programs/cairo-1-programs/tensor_new.cairo new file mode 100644 index 0000000000..2af717beed --- /dev/null +++ b/cairo_programs/cairo-1-programs/tensor_new.cairo @@ -0,0 +1,65 @@ +// FP16x16 +#[derive(Serde, Copy, Drop)] +struct FP16x16 { + mag: u32, + sign: bool +} + +trait FixedTrait { + fn new(mag: MAG, sign: bool) -> T; +} + +impl FP16x16Impl of FixedTrait { + fn new(mag: u32, sign: bool) -> FP16x16 { + FP16x16 { mag: mag, sign: sign } + } +} + +//Tensor +#[derive(Copy, Drop)] +struct Tensor { + shape: Span, + data: Span, +} + +trait TensorTrait { + fn new(shape: Span, data: Span) -> Tensor; +} + +impl FP16x16Tensor of TensorTrait { + fn new(shape: Span, data: Span) -> Tensor { + new_tensor(shape, data) + } +} + +fn new_tensor(shape: Span, data: Span) -> Tensor { + check_shape::(shape, data); + Tensor:: { shape, data } +} + +fn check_shape(shape: Span, data: Span) { + assert(len_from_shape(shape) == data.len(), 'wrong tensor shape'); +} + +fn len_from_shape(mut shape: Span) -> usize { + let mut result: usize = 1; + + loop { + match shape.pop_front() { + Option::Some(item) => { result *= *item; }, + Option::None => { break; } + }; + }; + + result +} + +fn main() -> Tensor { + TensorTrait::new( + array![1, 2].span(), + array![ + FixedTrait::new(1, false), + FixedTrait::new(1, true) + ].span() + ) +} diff --git a/cairo_programs/cairo-2-contracts/uint256_div_mod.cairo b/cairo_programs/cairo-2-contracts/uint256_div_mod.cairo index e06dec4ed7..4855c7fa35 100644 --- a/cairo_programs/cairo-2-contracts/uint256_div_mod.cairo +++ b/cairo_programs/cairo-2-contracts/uint256_div_mod.cairo @@ -16,7 +16,7 @@ mod TestUint256DivMod { #[storage] struct Storage {} - #[external(v0)] + #[abi(embed_v0)] impl TestUint256DivMod of super::ITestUint256DivMod { fn test_uint256_div_mod_max(ref self: ContractState) { let a = BoundedInt::max(); diff --git a/cairo_programs/mod_builtin_feature/apply_poly.cairo b/cairo_programs/mod_builtin_feature/apply_poly.cairo new file mode 100644 index 0000000000..da42bd84c6 --- /dev/null +++ b/cairo_programs/mod_builtin_feature/apply_poly.cairo @@ -0,0 +1,140 @@ +%builtins range_check range_check96 add_mod mul_mod +// TODO: Import directly from common library once released +from cairo_programs.mod_builtin_feature.common.modulo import ModBuiltin, UInt384, run_mod_p_circuit +// from starkware.cairo.common.modulo import run_mod_p_circuit +// from starkware.cairo.common.cairo_builtins import ModBuiltin, UInt384 +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.alloc import alloc + +// Computes the polynomial f(x) = x^8 + 5*x^2 + 1. +func apply_poly{ + range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin* +}(x: UInt384*, p: UInt384) -> (res: UInt384*) { + + // Copy inputs and constants into the values_ptr segment. + memcpy(dst=range_check96_ptr, src=x, len=UInt384.SIZE); + let (constants_ptr) = get_label_location(constants); + memcpy(dst=range_check96_ptr + UInt384.SIZE, src=constants_ptr, len=2 * UInt384.SIZE); + let values_ptr = cast(range_check96_ptr, UInt384*); + let range_check96_ptr = range_check96_ptr + 36; + + + let (add_mod_offsets_ptr) = get_label_location(add_offsets); + let (mul_mod_offsets_ptr) = get_label_location(mul_offsets); + run_mod_p_circuit( + p=p, + values_ptr=values_ptr, + add_mod_offsets_ptr=add_mod_offsets_ptr, + add_mod_n=2, + mul_mod_offsets_ptr=mul_mod_offsets_ptr, + mul_mod_n=4, + ); + + return (res=values_ptr + 32); + + // values_ptr points to a segment within the range_check96_ptr segment that looks like this: + // + // offset value + // 0 x + // 4 1 + // 8 5 + // 12 x^2 + // 16 x^4 + // 20 x^8 + // 24 5*x^2 + // 28 x^8 + 5*x^2 + // 32 x^8 + 5*x^2 + 1 + + constants: + dw 1; + dw 0; + dw 0; + dw 0; + + dw 5; + dw 0; + dw 0; + dw 0; + + add_offsets: + dw 20; // x^8 + dw 24; // 5*x^2 + dw 28; // x^8 + 5*x^2 + + dw 4; // 1 + dw 28; // x^8 + 5*x^2 + dw 32; // x^8 + 5*x^2 + 1 + + // Placeholders (copies of the first 3 offsets): + dw 20; + dw 24; + dw 28; + dw 20; + dw 24; + dw 28; + dw 20; + dw 24; + dw 28; + dw 20; + dw 24; + dw 28; + dw 20; + dw 24; + dw 28; + dw 20; + dw 24; + dw 28; + + + mul_offsets: + dw 0; // x + dw 0; // x + dw 12; // x^2 + + dw 12; // x^2 + dw 12; // x^2 + dw 16; // x^4 + + dw 16; // x^4 + dw 16; // x^4 + dw 20; // x^8 + + dw 8; // 5 + dw 12; // x^2 + dw 24; // 5*x^2 + + // Placeholders (copies of the first 3 offsets): + dw 0; + dw 0; + dw 12; + dw 0; + dw 0; + dw 12; + dw 0; + dw 0; + dw 12; + dw 0; + dw 0; + dw 12; +} + +func main{range_check_ptr, range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + alloc_locals; + + let p = UInt384(d0=0xffff, d1=0xffff, d2=0xffff, d3=0xffff); + let (local inputs: UInt384*) = alloc(); + assert inputs[0] = UInt384(d0=0xbbbb, d1=0xaaaa, d2=0x6666, d3=0xffff); + + let res: UInt384* = apply_poly(inputs, p); + + assert res[0].d0 = 0xdb0030d69941baf9893cd667; + assert res[0].d1 = 0xfffffffffffffffee43128e7; + assert res[0].d2 = 0xfd4c69cdf6010eab465c3055; + assert res[0].d3 = 0xea52; + + return(); +} diff --git a/cairo_programs/mod_builtin_feature/common/modulo.cairo b/cairo_programs/mod_builtin_feature/common/modulo.cairo new file mode 100644 index 0000000000..b52a85370e --- /dev/null +++ b/cairo_programs/mod_builtin_feature/common/modulo.cairo @@ -0,0 +1,124 @@ +// This file is a copy of common/modulo.cairo + added structs from common/cairo_builtins.cairo so that we can run modulo programs in CI +from starkware.cairo.common.math import safe_div, unsigned_div_rem +from starkware.cairo.common.registers import get_label_location + +// Represents a 384-bit unsigned integer d0 + 2**96 * d1 + 2**192 * d2 + 2**288 * d3 +// where each di is in [0, 2**96). +struct UInt384 { + d0: felt, + d1: felt, + d2: felt, + d3: felt, +} + +// Specifies the Add and Mul Mod builtins memory structure. +struct ModBuiltin { + // The modulus. + p: UInt384, + // A pointer to input values, the intermediate results and the output. + values_ptr: UInt384*, + // A pointer to offsets inside the values array, defining the circuit. + // The offsets array should contain 3 * n elements. + offsets_ptr: felt*, + // The number of operations to perform. + n: felt, +} + +const BATCH_SIZE = 1; + +// Returns the smallest felt 0 <= q < rc_bound such that x <= q * y. +func div_ceil{range_check_ptr}(x: felt, y: felt) -> felt { + let (q, r) = unsigned_div_rem(x, y); + if (r != 0) { + return q + 1; + } else { + return q; + } +} + +// Fills the first instance of the add_mod and mul_mod builtins and calls the fill_memory hint to +// fill the rest of the instances and the missing values in the values table. +// +// This function uses a hardcoded value of batch_size=8, and asserts the instance definitions use +// the same value. +func run_mod_p_circuit_with_large_batch_size{ + range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}( + p: UInt384, + values_ptr: UInt384*, + add_mod_offsets_ptr: felt*, + add_mod_n: felt, + mul_mod_offsets_ptr: felt*, + mul_mod_n: felt, +) { + const BATCH_SIZE = 8; + let add_mod_n_instances = div_ceil(add_mod_n, BATCH_SIZE); + assert add_mod_ptr[0] = ModBuiltin( + p=p, + values_ptr=values_ptr, + offsets_ptr=add_mod_offsets_ptr, + n=add_mod_n_instances * BATCH_SIZE, + ); + + let mul_mod_n_instances = div_ceil(mul_mod_n, BATCH_SIZE); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, + values_ptr=values_ptr, + offsets_ptr=mul_mod_offsets_ptr, + n=mul_mod_n_instances * BATCH_SIZE, + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == ids.BATCH_SIZE + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == ids.BATCH_SIZE + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) + %} + + let add_mod_ptr = &add_mod_ptr[add_mod_n_instances]; + let mul_mod_ptr = &mul_mod_ptr[mul_mod_n_instances]; + return (); +} + +// Fills the first instance of the add_mod and mul_mod builtins and calls the fill_memory hint to +// fill the rest of the instances and the missing values in the values table. +// +// This function uses a hardcoded value of batch_size=1, and asserts the instance definitions use +// the same value. +func run_mod_p_circuit{add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + p: UInt384, + values_ptr: UInt384*, + add_mod_offsets_ptr: felt*, + add_mod_n: felt, + mul_mod_offsets_ptr: felt*, + mul_mod_n: felt, +) { + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=values_ptr, offsets_ptr=add_mod_offsets_ptr, n=add_mod_n + ); + + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=values_ptr, offsets_ptr=mul_mod_offsets_ptr, n=mul_mod_n + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) + %} + + let add_mod_ptr = &add_mod_ptr[add_mod_n]; + let mul_mod_ptr = &mul_mod_ptr[mul_mod_n]; + return (); +} diff --git a/cairo_programs/mod_builtin_feature/mod_builtin.cairo b/cairo_programs/mod_builtin_feature/mod_builtin.cairo new file mode 100644 index 0000000000..f7ca04517e --- /dev/null +++ b/cairo_programs/mod_builtin_feature/mod_builtin.cairo @@ -0,0 +1,53 @@ +%builtins range_check add_mod mul_mod +// TODO: Import directly from common library once released +from cairo_programs.mod_builtin_feature.common.modulo import ModBuiltin, UInt384, run_mod_p_circuit +// from starkware.common.cairo_builtins import ModBuiltin, UInt384 +// from starkware.cairo.common.modulo import run_mod_p_circuit +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.alloc import alloc + +func main{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + alloc_locals; + + let p = UInt384(d0=1, d1=1, d2=0, d3=0); + let x1 = UInt384(d0=1, d1=0, d2=0, d3=0); + let x2 = UInt384(d0=2, d1=1, d2=0, d3=0); + let x3 = UInt384(d0=2, d1=0, d2=0, d3=0); + let res = UInt384(d0=1, d1=0, d2=0, d3=0); + + let (local values_arr: UInt384*) = alloc(); + assert values_arr[0] = x1; + assert values_arr[1] = x2; + assert values_arr[2] = x3; + assert values_arr[7] = res; + + let (local add_mod_offsets_arr: felt*) = alloc(); + assert add_mod_offsets_arr[0] = 0; // x1 + assert add_mod_offsets_arr[1] = 12; // x2 - x1 + assert add_mod_offsets_arr[2] = 4; // x2 + assert add_mod_offsets_arr[3] = 16; // (x2 - x1) * x3 + assert add_mod_offsets_arr[4] = 20; // x1 * x3 + assert add_mod_offsets_arr[5] = 24; // (x2 - x1) * x3 + x1 * x3 + + let (local mul_mod_offsets_arr: felt*) = alloc(); + assert mul_mod_offsets_arr[0] = 12; // x2 - x1 + assert mul_mod_offsets_arr[1] = 8; // x3 + assert mul_mod_offsets_arr[2] = 16; // (x2 - x1) * x3 + assert mul_mod_offsets_arr[3] = 0; // x1 + assert mul_mod_offsets_arr[4] = 8; // x3 + assert mul_mod_offsets_arr[5] = 20; // x1 * x3 + assert mul_mod_offsets_arr[6] = 8; // x3 + assert mul_mod_offsets_arr[7] = 28; // ((x2 - x1) * x3 + x1 * x3) / x3 = x2 mod p + assert mul_mod_offsets_arr[8] = 24; // (x2 - x1) * x3 + x1 * x3 + + run_mod_p_circuit( + p=p, + values_ptr=values_arr, + add_mod_offsets_ptr=add_mod_offsets_arr, + add_mod_n=2, + mul_mod_offsets_ptr=mul_mod_offsets_arr, + mul_mod_n=3, + ); + + return (); +} diff --git a/cairo_programs/mod_builtin_feature/mod_builtin_failure.cairo b/cairo_programs/mod_builtin_feature/mod_builtin_failure.cairo new file mode 100644 index 0000000000..6e7a9a3175 --- /dev/null +++ b/cairo_programs/mod_builtin_feature/mod_builtin_failure.cairo @@ -0,0 +1,53 @@ +%builtins range_check add_mod mul_mod +// TODO: Import directly from common library once released +from cairo_programs.mod_builtin_feature.common.modulo import ModBuiltin, UInt384, run_mod_p_circuit +// from starkware.common.cairo_builtins import ModBuiltin, UInt384 +// from starkware.cairo.common.modulo import run_mod_p_circuit +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.alloc import alloc + +func main{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + alloc_locals; + + let p = UInt384(d0=1, d1=1, d2=0, d3=0); + let x1 = UInt384(d0=1, d1=0, d2=0, d3=0); + let x2 = UInt384(d0=2, d1=1, d2=0, d3=0); + let x3 = UInt384(d0=2, d1=0, d2=0, d3=0); + let res = UInt384(d0=2, d1=0, d2=0, d3=0); + + let (local values_arr: UInt384*) = alloc(); + assert values_arr[0] = x1; + assert values_arr[1] = x2; + assert values_arr[2] = x3; + assert values_arr[7] = res; + + let (local add_mod_offsets_arr: felt*) = alloc(); + assert add_mod_offsets_arr[0] = 0; // x1 + assert add_mod_offsets_arr[1] = 12; // x2 - x1 + assert add_mod_offsets_arr[2] = 4; // x2 + assert add_mod_offsets_arr[3] = 16; // (x2 - x1) * x3 + assert add_mod_offsets_arr[4] = 20; // x1 * x3 + assert add_mod_offsets_arr[5] = 24; // (x2 - x1) * x3 + x1 * x3 + + let (local mul_mod_offsets_arr: felt*) = alloc(); + assert mul_mod_offsets_arr[0] = 12; // x2 - x1 + assert mul_mod_offsets_arr[1] = 8; // x3 + assert mul_mod_offsets_arr[2] = 16; // (x2 - x1) * x3 + assert mul_mod_offsets_arr[3] = 0; // x1 + assert mul_mod_offsets_arr[4] = 8; // x3 + assert mul_mod_offsets_arr[5] = 20; // x1 * x3 + assert mul_mod_offsets_arr[6] = 8; // x3 + assert mul_mod_offsets_arr[7] = 28; // ((x2 - x1) * x3 + x1 * x3) / x3 = x2 mod p + assert mul_mod_offsets_arr[8] = 24; // (x2 - x1) * x3 + x1 * x3 + + run_mod_p_circuit( + p=p, + values_ptr=values_arr, + add_mod_offsets_ptr=add_mod_offsets_arr, + add_mod_n=2, + mul_mod_offsets_ptr=mul_mod_offsets_arr, + mul_mod_n=3, + ); + + return (); +} diff --git a/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size.cairo b/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size.cairo new file mode 100644 index 0000000000..e25670459e --- /dev/null +++ b/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size.cairo @@ -0,0 +1,53 @@ +%builtins range_check add_mod mul_mod +// TODO: Import directly from common library once released +from cairo_programs.mod_builtin_feature.common.modulo import ModBuiltin, UInt384, run_mod_p_circuit_with_large_batch_size +// from starkware.common.cairo_builtins import ModBuiltin, UInt384 +// from starkware.cairo.common.modulo import run_mod_p_circuit_with_large_batch_size +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.alloc import alloc + +func main{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + alloc_locals; + + let p = UInt384(d0=1, d1=1, d2=0, d3=0); + let x1 = UInt384(d0=1, d1=0, d2=0, d3=0); + let x2 = UInt384(d0=2, d1=1, d2=0, d3=0); + let x3 = UInt384(d0=2, d1=0, d2=0, d3=0); + let res = UInt384(d0=1, d1=0, d2=0, d3=0); + + let (local values_arr: UInt384*) = alloc(); + assert values_arr[0] = x1; + assert values_arr[1] = x2; + assert values_arr[2] = x3; + assert values_arr[7] = res; + + let (local add_mod_offsets_arr: felt*) = alloc(); + assert add_mod_offsets_arr[0] = 0; // x1 + assert add_mod_offsets_arr[1] = 12; // x2 - x1 + assert add_mod_offsets_arr[2] = 4; // x2 + assert add_mod_offsets_arr[3] = 16; // (x2 - x1) * x3 + assert add_mod_offsets_arr[4] = 20; // x1 * x3 + assert add_mod_offsets_arr[5] = 24; // (x2 - x1) * x3 + x1 * x3 + + let (local mul_mod_offsets_arr: felt*) = alloc(); + assert mul_mod_offsets_arr[0] = 12; // x2 - x1 + assert mul_mod_offsets_arr[1] = 8; // x3 + assert mul_mod_offsets_arr[2] = 16; // (x2 - x1) * x3 + assert mul_mod_offsets_arr[3] = 0; // x1 + assert mul_mod_offsets_arr[4] = 8; // x3 + assert mul_mod_offsets_arr[5] = 20; // x1 * x3 + assert mul_mod_offsets_arr[6] = 8; // x3 + assert mul_mod_offsets_arr[7] = 28; // ((x2 - x1) * x3 + x1 * x3) / x3 = x2 mod p + assert mul_mod_offsets_arr[8] = 24; // (x2 - x1) * x3 + x1 * x3 + + run_mod_p_circuit_with_large_batch_size( + p=p, + values_ptr=values_arr, + add_mod_offsets_ptr=add_mod_offsets_arr, + add_mod_n=2, + mul_mod_offsets_ptr=mul_mod_offsets_arr, + mul_mod_n=3, + ); + + return (); +} diff --git a/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_benchmark.cairo b/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_benchmark.cairo new file mode 100644 index 0000000000..21d643af34 --- /dev/null +++ b/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_benchmark.cairo @@ -0,0 +1,65 @@ +%builtins range_check add_mod mul_mod +// TODO: Import directly from common library once released +from cairo_programs.mod_builtin_feature.common.modulo import ModBuiltin, UInt384, run_mod_p_circuit_with_large_batch_size +// from starkware.common.cairo_builtins import ModBuiltin, UInt384 +// from starkware.cairo.common.modulo import run_mod_p_circuit_with_large_batch_size +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.alloc import alloc + +func run_circuit{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + alloc_locals; + + let p = UInt384(d0=1, d1=1, d2=0, d3=0); + let x1 = UInt384(d0=1, d1=0, d2=0, d3=0); + let x2 = UInt384(d0=2, d1=1, d2=0, d3=0); + let x3 = UInt384(d0=2, d1=0, d2=0, d3=0); + let res = UInt384(d0=1, d1=0, d2=0, d3=0); + + let (local values_arr: UInt384*) = alloc(); + assert values_arr[0] = x1; + assert values_arr[1] = x2; + assert values_arr[2] = x3; + assert values_arr[7] = res; + + let (local add_mod_offsets_arr: felt*) = alloc(); + assert add_mod_offsets_arr[0] = 0; // x1 + assert add_mod_offsets_arr[1] = 12; // x2 - x1 + assert add_mod_offsets_arr[2] = 4; // x2 + assert add_mod_offsets_arr[3] = 16; // (x2 - x1) * x3 + assert add_mod_offsets_arr[4] = 20; // x1 * x3 + assert add_mod_offsets_arr[5] = 24; // (x2 - x1) * x3 + x1 * x3 + + let (local mul_mod_offsets_arr: felt*) = alloc(); + assert mul_mod_offsets_arr[0] = 12; // x2 - x1 + assert mul_mod_offsets_arr[1] = 8; // x3 + assert mul_mod_offsets_arr[2] = 16; // (x2 - x1) * x3 + assert mul_mod_offsets_arr[3] = 0; // x1 + assert mul_mod_offsets_arr[4] = 8; // x3 + assert mul_mod_offsets_arr[5] = 20; // x1 * x3 + assert mul_mod_offsets_arr[6] = 8; // x3 + assert mul_mod_offsets_arr[7] = 28; // ((x2 - x1) * x3 + x1 * x3) / x3 = x2 mod p + assert mul_mod_offsets_arr[8] = 24; // (x2 - x1) * x3 + x1 * x3 + + run_mod_p_circuit_with_large_batch_size( + p=p, + values_ptr=values_arr, + add_mod_offsets_ptr=add_mod_offsets_arr, + add_mod_n=2, + mul_mod_offsets_ptr=mul_mod_offsets_arr, + mul_mod_n=3, + ); + + return (); +} + +func run_loop{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(n: felt) { + if (n == 0) { + return (); + } + run_circuit(); + return run_loop(n - 1); +} + +func main{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + return run_loop(100); +} diff --git a/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_failure.cairo b/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_failure.cairo new file mode 100644 index 0000000000..9605de779a --- /dev/null +++ b/cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_failure.cairo @@ -0,0 +1,53 @@ +%builtins range_check add_mod mul_mod +// TODO: Import directly from common library once released +from cairo_programs.mod_builtin_feature.common.modulo import ModBuiltin, UInt384, run_mod_p_circuit_with_large_batch_size +// from starkware.common.cairo_builtins import ModBuiltin, UInt384 +// from starkware.cairo.common.modulo import run_mod_p_circuit_with_large_batch_size +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.alloc import alloc + +func main{range_check_ptr, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}() { + alloc_locals; + + let p = UInt384(d0=1, d1=1, d2=0, d3=0); + let x1 = UInt384(d0=1, d1=0, d2=0, d3=0); + let x2 = UInt384(d0=2, d1=1, d2=0, d3=0); + let x3 = UInt384(d0=2, d1=0, d2=0, d3=0); + let res = UInt384(d0=2, d1=0, d2=0, d3=0); + + let (local values_arr: UInt384*) = alloc(); + assert values_arr[0] = x1; + assert values_arr[1] = x2; + assert values_arr[2] = x3; + assert values_arr[7] = res; + + let (local add_mod_offsets_arr: felt*) = alloc(); + assert add_mod_offsets_arr[0] = 0; // x1 + assert add_mod_offsets_arr[1] = 12; // x2 - x1 + assert add_mod_offsets_arr[2] = 4; // x2 + assert add_mod_offsets_arr[3] = 16; // (x2 - x1) * x3 + assert add_mod_offsets_arr[4] = 20; // x1 * x3 + assert add_mod_offsets_arr[5] = 24; // (x2 - x1) * x3 + x1 * x3 + + let (local mul_mod_offsets_arr: felt*) = alloc(); + assert mul_mod_offsets_arr[0] = 12; // x2 - x1 + assert mul_mod_offsets_arr[1] = 8; // x3 + assert mul_mod_offsets_arr[2] = 16; // (x2 - x1) * x3 + assert mul_mod_offsets_arr[3] = 0; // x1 + assert mul_mod_offsets_arr[4] = 8; // x3 + assert mul_mod_offsets_arr[5] = 20; // x1 * x3 + assert mul_mod_offsets_arr[6] = 8; // x3 + assert mul_mod_offsets_arr[7] = 28; // ((x2 - x1) * x3 + x1 * x3) / x3 = x2 mod p + assert mul_mod_offsets_arr[8] = 24; // (x2 - x1) * x3 + x1 * x3 + + run_mod_p_circuit_with_large_batch_size( + p=p, + values_ptr=values_arr, + add_mod_offsets_ptr=add_mod_offsets_arr, + add_mod_n=2, + mul_mod_offsets_ptr=mul_mod_offsets_arr, + mul_mod_n=3, + ); + + return (); +} diff --git a/cairo_programs/mod_builtin_feature/proof/apply_poly.cairo b/cairo_programs/mod_builtin_feature/proof/apply_poly.cairo new file mode 120000 index 0000000000..70d9ba18e4 --- /dev/null +++ b/cairo_programs/mod_builtin_feature/proof/apply_poly.cairo @@ -0,0 +1 @@ +../apply_poly.cairo \ No newline at end of file diff --git a/cairo_programs/mod_builtin_feature/proof/mod_builtin.cairo b/cairo_programs/mod_builtin_feature/proof/mod_builtin.cairo new file mode 120000 index 0000000000..754dd814da --- /dev/null +++ b/cairo_programs/mod_builtin_feature/proof/mod_builtin.cairo @@ -0,0 +1 @@ +../mod_builtin.cairo \ No newline at end of file diff --git a/cairo_programs/mod_builtin_feature/proof/mod_builtin_failure.cairo b/cairo_programs/mod_builtin_feature/proof/mod_builtin_failure.cairo new file mode 120000 index 0000000000..11df1c30ef --- /dev/null +++ b/cairo_programs/mod_builtin_feature/proof/mod_builtin_failure.cairo @@ -0,0 +1 @@ +../mod_builtin_failure.cairo \ No newline at end of file diff --git a/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size.cairo b/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size.cairo new file mode 120000 index 0000000000..edcda419b0 --- /dev/null +++ b/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size.cairo @@ -0,0 +1 @@ +../mod_builtin_large_batch_size.cairo \ No newline at end of file diff --git a/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size_benchmark.cairo b/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size_benchmark.cairo new file mode 120000 index 0000000000..07b4071b7e --- /dev/null +++ b/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size_benchmark.cairo @@ -0,0 +1 @@ +../mod_builtin_large_batch_size_benchmark.cairo \ No newline at end of file diff --git a/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size_failure.cairo b/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size_failure.cairo new file mode 120000 index 0000000000..1882352a93 --- /dev/null +++ b/cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size_failure.cairo @@ -0,0 +1 @@ +../mod_builtin_large_batch_size_failure.cairo \ No newline at end of file diff --git a/cairo_programs/pedersen_extra_builtins.cairo b/cairo_programs/pedersen_extra_builtins.cairo new file mode 100644 index 0000000000..513ce93ddb --- /dev/null +++ b/cairo_programs/pedersen_extra_builtins.cairo @@ -0,0 +1,11 @@ +%builtins output pedersen range_check ecdsa bitwise ec_op + +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.hash import hash2 + +func main{output_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, ecdsa_ptr, bitwise_ptr, ec_op_ptr}() { + let (seed) = hash2{hash_ptr=pedersen_ptr}(0, 0); + assert [output_ptr] = seed; + let output_ptr = output_ptr + 1; + return (); +} diff --git a/cairo_programs/proof_programs/.gitkeep b/cairo_programs/proof_programs/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cairo_programs/proof_programs/abs_value_array.cairo b/cairo_programs/proof_programs/abs_value_array.cairo deleted file mode 120000 index 0094c34916..0000000000 --- a/cairo_programs/proof_programs/abs_value_array.cairo +++ /dev/null @@ -1 +0,0 @@ -../abs_value_array.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/array_sum.cairo b/cairo_programs/proof_programs/array_sum.cairo deleted file mode 120000 index 81a03089e0..0000000000 --- a/cairo_programs/proof_programs/array_sum.cairo +++ /dev/null @@ -1 +0,0 @@ -../array_sum.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/assert_250_bit_element_array.cairo b/cairo_programs/proof_programs/assert_250_bit_element_array.cairo deleted file mode 120000 index 1b3b523a17..0000000000 --- a/cairo_programs/proof_programs/assert_250_bit_element_array.cairo +++ /dev/null @@ -1 +0,0 @@ -../assert_250_bit_element_array.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/assert_le_felt_hint.cairo b/cairo_programs/proof_programs/assert_le_felt_hint.cairo deleted file mode 120000 index 24ab14a6b2..0000000000 --- a/cairo_programs/proof_programs/assert_le_felt_hint.cairo +++ /dev/null @@ -1 +0,0 @@ -../assert_le_felt_hint.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/assert_le_felt_old.cairo b/cairo_programs/proof_programs/assert_le_felt_old.cairo deleted file mode 120000 index 578084defe..0000000000 --- a/cairo_programs/proof_programs/assert_le_felt_old.cairo +++ /dev/null @@ -1 +0,0 @@ -../assert_le_felt_old.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/assert_lt_felt.cairo b/cairo_programs/proof_programs/assert_lt_felt.cairo deleted file mode 120000 index c904928089..0000000000 --- a/cairo_programs/proof_programs/assert_lt_felt.cairo +++ /dev/null @@ -1 +0,0 @@ -../assert_lt_felt.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/assert_nn.cairo b/cairo_programs/proof_programs/assert_nn.cairo deleted file mode 120000 index 3a651e8db7..0000000000 --- a/cairo_programs/proof_programs/assert_nn.cairo +++ /dev/null @@ -1 +0,0 @@ -../assert_nn.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/assert_not_zero.cairo b/cairo_programs/proof_programs/assert_not_zero.cairo deleted file mode 120000 index 1a988d387d..0000000000 --- a/cairo_programs/proof_programs/assert_not_zero.cairo +++ /dev/null @@ -1 +0,0 @@ -../assert_not_zero.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/big_struct.cairo b/cairo_programs/proof_programs/big_struct.cairo deleted file mode 120000 index ce2ed42bd0..0000000000 --- a/cairo_programs/proof_programs/big_struct.cairo +++ /dev/null @@ -1 +0,0 @@ -../big_struct.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/bigint.cairo b/cairo_programs/proof_programs/bigint.cairo deleted file mode 120000 index 81d408cee4..0000000000 --- a/cairo_programs/proof_programs/bigint.cairo +++ /dev/null @@ -1 +0,0 @@ -../bigint.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/bitand_hint.cairo b/cairo_programs/proof_programs/bitand_hint.cairo deleted file mode 120000 index 1ba1561a2d..0000000000 --- a/cairo_programs/proof_programs/bitand_hint.cairo +++ /dev/null @@ -1 +0,0 @@ -../bitand_hint.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/bitwise_builtin_test.cairo b/cairo_programs/proof_programs/bitwise_builtin_test.cairo deleted file mode 120000 index 36126fb09b..0000000000 --- a/cairo_programs/proof_programs/bitwise_builtin_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../bitwise_builtin_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/bitwise_output.cairo b/cairo_programs/proof_programs/bitwise_output.cairo deleted file mode 120000 index eade6ee7ce..0000000000 --- a/cairo_programs/proof_programs/bitwise_output.cairo +++ /dev/null @@ -1 +0,0 @@ -../bitwise_output.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/bitwise_recursion.cairo b/cairo_programs/proof_programs/bitwise_recursion.cairo deleted file mode 120000 index 081e16d5b5..0000000000 --- a/cairo_programs/proof_programs/bitwise_recursion.cairo +++ /dev/null @@ -1 +0,0 @@ -../bitwise_recursion.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/blake2s_felts.cairo b/cairo_programs/proof_programs/blake2s_felts.cairo deleted file mode 120000 index e04d6b2caf..0000000000 --- a/cairo_programs/proof_programs/blake2s_felts.cairo +++ /dev/null @@ -1 +0,0 @@ -../blake2s_felts.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/blake2s_hello_world_hash.cairo b/cairo_programs/proof_programs/blake2s_hello_world_hash.cairo deleted file mode 120000 index 8b8f951db8..0000000000 --- a/cairo_programs/proof_programs/blake2s_hello_world_hash.cairo +++ /dev/null @@ -1 +0,0 @@ -../blake2s_hello_world_hash.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/blake2s_integration_tests.cairo b/cairo_programs/proof_programs/blake2s_integration_tests.cairo deleted file mode 120000 index e96d8f88fb..0000000000 --- a/cairo_programs/proof_programs/blake2s_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../blake2s_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/cairo_finalize_keccak.cairo b/cairo_programs/proof_programs/cairo_finalize_keccak.cairo deleted file mode 120000 index c3191e2201..0000000000 --- a/cairo_programs/proof_programs/cairo_finalize_keccak.cairo +++ /dev/null @@ -1 +0,0 @@ -../cairo_finalize_keccak.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/cairo_finalize_keccak_block_size_1000.cairo b/cairo_programs/proof_programs/cairo_finalize_keccak_block_size_1000.cairo deleted file mode 120000 index 69fa41ec38..0000000000 --- a/cairo_programs/proof_programs/cairo_finalize_keccak_block_size_1000.cairo +++ /dev/null @@ -1 +0,0 @@ -../cairo_finalize_keccak_block_size_1000.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/call_function_assign_param_by_name.cairo b/cairo_programs/proof_programs/call_function_assign_param_by_name.cairo deleted file mode 120000 index cd1fd2cc14..0000000000 --- a/cairo_programs/proof_programs/call_function_assign_param_by_name.cairo +++ /dev/null @@ -1 +0,0 @@ -../call_function_assign_param_by_name.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/chained_ec_op.cairo b/cairo_programs/proof_programs/chained_ec_op.cairo deleted file mode 120000 index 562981744b..0000000000 --- a/cairo_programs/proof_programs/chained_ec_op.cairo +++ /dev/null @@ -1 +0,0 @@ -../chained_ec_op.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/common_signature.cairo b/cairo_programs/proof_programs/common_signature.cairo deleted file mode 120000 index 9a92f8aa35..0000000000 --- a/cairo_programs/proof_programs/common_signature.cairo +++ /dev/null @@ -1 +0,0 @@ -../common_signature.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/compare_arrays.cairo b/cairo_programs/proof_programs/compare_arrays.cairo deleted file mode 120000 index dd23ad1a38..0000000000 --- a/cairo_programs/proof_programs/compare_arrays.cairo +++ /dev/null @@ -1 +0,0 @@ -../compare_arrays.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/compare_different_arrays.cairo b/cairo_programs/proof_programs/compare_different_arrays.cairo deleted file mode 120000 index 1688f8e5c9..0000000000 --- a/cairo_programs/proof_programs/compare_different_arrays.cairo +++ /dev/null @@ -1 +0,0 @@ -../compare_different_arrays.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/compare_greater_array.cairo b/cairo_programs/proof_programs/compare_greater_array.cairo deleted file mode 120000 index d3b8a39554..0000000000 --- a/cairo_programs/proof_programs/compare_greater_array.cairo +++ /dev/null @@ -1 +0,0 @@ -../compare_greater_array.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/compare_lesser_array.cairo b/cairo_programs/proof_programs/compare_lesser_array.cairo deleted file mode 120000 index b72440deab..0000000000 --- a/cairo_programs/proof_programs/compare_lesser_array.cairo +++ /dev/null @@ -1 +0,0 @@ -../compare_lesser_array.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/compute_doubling_slope_v2.cairo b/cairo_programs/proof_programs/compute_doubling_slope_v2.cairo deleted file mode 120000 index e3400f66cb..0000000000 --- a/cairo_programs/proof_programs/compute_doubling_slope_v2.cairo +++ /dev/null @@ -1 +0,0 @@ -../compute_doubling_slope_v2.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/compute_slope_v2.cairo b/cairo_programs/proof_programs/compute_slope_v2.cairo deleted file mode 120000 index 99e22890e9..0000000000 --- a/cairo_programs/proof_programs/compute_slope_v2.cairo +++ /dev/null @@ -1 +0,0 @@ -../compute_slope_v2.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/dict.cairo b/cairo_programs/proof_programs/dict.cairo deleted file mode 120000 index a1a9c2277d..0000000000 --- a/cairo_programs/proof_programs/dict.cairo +++ /dev/null @@ -1 +0,0 @@ -../dict.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/dict_integration_tests.cairo b/cairo_programs/proof_programs/dict_integration_tests.cairo deleted file mode 120000 index e13fe2fab5..0000000000 --- a/cairo_programs/proof_programs/dict_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../dict_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/dict_squash.cairo b/cairo_programs/proof_programs/dict_squash.cairo deleted file mode 120000 index 2191191a74..0000000000 --- a/cairo_programs/proof_programs/dict_squash.cairo +++ /dev/null @@ -1 +0,0 @@ -../dict_squash.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/dict_store_cast_ptr.cairo b/cairo_programs/proof_programs/dict_store_cast_ptr.cairo deleted file mode 120000 index 8d1e6a7409..0000000000 --- a/cairo_programs/proof_programs/dict_store_cast_ptr.cairo +++ /dev/null @@ -1 +0,0 @@ -../dict_store_cast_ptr.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/dict_update.cairo b/cairo_programs/proof_programs/dict_update.cairo deleted file mode 120000 index 268649e28a..0000000000 --- a/cairo_programs/proof_programs/dict_update.cairo +++ /dev/null @@ -1 +0,0 @@ -../dict_update.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/div_mod_n.cairo b/cairo_programs/proof_programs/div_mod_n.cairo deleted file mode 120000 index e262b1292a..0000000000 --- a/cairo_programs/proof_programs/div_mod_n.cairo +++ /dev/null @@ -1 +0,0 @@ -../div_mod_n.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ec_double_assign_new_x_v3.cairo b/cairo_programs/proof_programs/ec_double_assign_new_x_v3.cairo deleted file mode 120000 index 8a7e7d4150..0000000000 --- a/cairo_programs/proof_programs/ec_double_assign_new_x_v3.cairo +++ /dev/null @@ -1 +0,0 @@ -../ec_double_assign_new_x_v3.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ec_double_slope.cairo b/cairo_programs/proof_programs/ec_double_slope.cairo deleted file mode 120000 index ff9fbd912f..0000000000 --- a/cairo_programs/proof_programs/ec_double_slope.cairo +++ /dev/null @@ -1 +0,0 @@ -../ec_double_slope.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ec_double_v4.cairo b/cairo_programs/proof_programs/ec_double_v4.cairo deleted file mode 120000 index ec8291916a..0000000000 --- a/cairo_programs/proof_programs/ec_double_v4.cairo +++ /dev/null @@ -1 +0,0 @@ -../ec_double_v4.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ec_negate.cairo b/cairo_programs/proof_programs/ec_negate.cairo deleted file mode 120000 index c8a8af8d5c..0000000000 --- a/cairo_programs/proof_programs/ec_negate.cairo +++ /dev/null @@ -1 +0,0 @@ -../ec_negate.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ec_op.cairo b/cairo_programs/proof_programs/ec_op.cairo deleted file mode 120000 index ed20b661af..0000000000 --- a/cairo_programs/proof_programs/ec_op.cairo +++ /dev/null @@ -1 +0,0 @@ -../ec_op.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ec_recover.cairo b/cairo_programs/proof_programs/ec_recover.cairo deleted file mode 120000 index a0629529c6..0000000000 --- a/cairo_programs/proof_programs/ec_recover.cairo +++ /dev/null @@ -1 +0,0 @@ -../ec_recover.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ed25519_ec.cairo b/cairo_programs/proof_programs/ed25519_ec.cairo deleted file mode 120000 index d60a0f17c4..0000000000 --- a/cairo_programs/proof_programs/ed25519_ec.cairo +++ /dev/null @@ -1 +0,0 @@ -../ed25519_ec.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/ed25519_field.cairo b/cairo_programs/proof_programs/ed25519_field.cairo deleted file mode 120000 index 55fb9bae0e..0000000000 --- a/cairo_programs/proof_programs/ed25519_field.cairo +++ /dev/null @@ -1 +0,0 @@ -../ed25519_field.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/efficient_secp256r1_ec.cairo b/cairo_programs/proof_programs/efficient_secp256r1_ec.cairo deleted file mode 120000 index cd0e2fb3f9..0000000000 --- a/cairo_programs/proof_programs/efficient_secp256r1_ec.cairo +++ /dev/null @@ -1 +0,0 @@ -../efficient_secp256r1_ec.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/example_blake2s.cairo b/cairo_programs/proof_programs/example_blake2s.cairo deleted file mode 120000 index 77d4b53f0f..0000000000 --- a/cairo_programs/proof_programs/example_blake2s.cairo +++ /dev/null @@ -1 +0,0 @@ -../example_blake2s.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/example_program.cairo b/cairo_programs/proof_programs/example_program.cairo deleted file mode 120000 index 9bf1899363..0000000000 --- a/cairo_programs/proof_programs/example_program.cairo +++ /dev/null @@ -1 +0,0 @@ -../example_program.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/factorial.cairo b/cairo_programs/proof_programs/factorial.cairo deleted file mode 120000 index 5ba977181a..0000000000 --- a/cairo_programs/proof_programs/factorial.cairo +++ /dev/null @@ -1 +0,0 @@ -../factorial.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/fast_ec_add_v2.cairo b/cairo_programs/proof_programs/fast_ec_add_v2.cairo deleted file mode 120000 index a6012da8d3..0000000000 --- a/cairo_programs/proof_programs/fast_ec_add_v2.cairo +++ /dev/null @@ -1 +0,0 @@ -../fast_ec_add_v2.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/fast_ec_add_v3.cairo b/cairo_programs/proof_programs/fast_ec_add_v3.cairo deleted file mode 120000 index ed334949da..0000000000 --- a/cairo_programs/proof_programs/fast_ec_add_v3.cairo +++ /dev/null @@ -1 +0,0 @@ -../fast_ec_add_v3.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/fibonacci.cairo b/cairo_programs/proof_programs/fibonacci.cairo deleted file mode 120000 index 713038ee51..0000000000 --- a/cairo_programs/proof_programs/fibonacci.cairo +++ /dev/null @@ -1 +0,0 @@ -../fibonacci.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/field_arithmetic.cairo b/cairo_programs/proof_programs/field_arithmetic.cairo deleted file mode 120000 index 2ad65272a2..0000000000 --- a/cairo_programs/proof_programs/field_arithmetic.cairo +++ /dev/null @@ -1 +0,0 @@ -../field_arithmetic.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/finalize_blake2s.cairo b/cairo_programs/proof_programs/finalize_blake2s.cairo deleted file mode 120000 index cb5922050e..0000000000 --- a/cairo_programs/proof_programs/finalize_blake2s.cairo +++ /dev/null @@ -1 +0,0 @@ -../finalize_blake2s.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/finalize_blake2s_v2_hint.cairo b/cairo_programs/proof_programs/finalize_blake2s_v2_hint.cairo deleted file mode 120000 index 36ff9954b3..0000000000 --- a/cairo_programs/proof_programs/finalize_blake2s_v2_hint.cairo +++ /dev/null @@ -1 +0,0 @@ -../finalize_blake2s_v2_hint.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/find_element.cairo b/cairo_programs/proof_programs/find_element.cairo deleted file mode 120000 index 66d8ee0928..0000000000 --- a/cairo_programs/proof_programs/find_element.cairo +++ /dev/null @@ -1 +0,0 @@ -../find_element.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/fq.cairo b/cairo_programs/proof_programs/fq.cairo deleted file mode 120000 index d67bd7ebd5..0000000000 --- a/cairo_programs/proof_programs/fq.cairo +++ /dev/null @@ -1 +0,0 @@ -../fq.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/fq_test.cairo b/cairo_programs/proof_programs/fq_test.cairo deleted file mode 120000 index 7d8b5f7573..0000000000 --- a/cairo_programs/proof_programs/fq_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../fq_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/function_return.cairo b/cairo_programs/proof_programs/function_return.cairo deleted file mode 120000 index 03d33cbdf4..0000000000 --- a/cairo_programs/proof_programs/function_return.cairo +++ /dev/null @@ -1 +0,0 @@ -../function_return.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/function_return_if_print.cairo b/cairo_programs/proof_programs/function_return_if_print.cairo deleted file mode 120000 index 8501e61e92..0000000000 --- a/cairo_programs/proof_programs/function_return_if_print.cairo +++ /dev/null @@ -1 +0,0 @@ -../function_return_if_print.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/function_return_to_variable.cairo b/cairo_programs/proof_programs/function_return_to_variable.cairo deleted file mode 120000 index da13eb840b..0000000000 --- a/cairo_programs/proof_programs/function_return_to_variable.cairo +++ /dev/null @@ -1 +0,0 @@ -../function_return_to_variable.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/garaga.cairo b/cairo_programs/proof_programs/garaga.cairo deleted file mode 120000 index 2c29bb6184..0000000000 --- a/cairo_programs/proof_programs/garaga.cairo +++ /dev/null @@ -1 +0,0 @@ -../garaga.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/highest_bitlen.cairo b/cairo_programs/proof_programs/highest_bitlen.cairo deleted file mode 120000 index 1b72bcb0b6..0000000000 --- a/cairo_programs/proof_programs/highest_bitlen.cairo +++ /dev/null @@ -1 +0,0 @@ -../highest_bitlen.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/if_and_prime.cairo b/cairo_programs/proof_programs/if_and_prime.cairo deleted file mode 120000 index b784d11400..0000000000 --- a/cairo_programs/proof_programs/if_and_prime.cairo +++ /dev/null @@ -1 +0,0 @@ -../if_and_prime.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/if_in_function.cairo b/cairo_programs/proof_programs/if_in_function.cairo deleted file mode 120000 index b7b49c33e5..0000000000 --- a/cairo_programs/proof_programs/if_in_function.cairo +++ /dev/null @@ -1 +0,0 @@ -../if_in_function.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/if_list.cairo b/cairo_programs/proof_programs/if_list.cairo deleted file mode 120000 index 0c7f81ccc4..0000000000 --- a/cairo_programs/proof_programs/if_list.cairo +++ /dev/null @@ -1 +0,0 @@ -../if_list.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/if_reloc_equal.cairo b/cairo_programs/proof_programs/if_reloc_equal.cairo deleted file mode 120000 index bec0afd84d..0000000000 --- a/cairo_programs/proof_programs/if_reloc_equal.cairo +++ /dev/null @@ -1 +0,0 @@ -../if_reloc_equal.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/integration.cairo b/cairo_programs/proof_programs/integration.cairo deleted file mode 120000 index 73e75a2630..0000000000 --- a/cairo_programs/proof_programs/integration.cairo +++ /dev/null @@ -1 +0,0 @@ -../integration.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/integration_with_alloc_locals.cairo b/cairo_programs/proof_programs/integration_with_alloc_locals.cairo deleted file mode 120000 index c81a4016ce..0000000000 --- a/cairo_programs/proof_programs/integration_with_alloc_locals.cairo +++ /dev/null @@ -1 +0,0 @@ -../integration_with_alloc_locals.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/inv_mod_p_uint512.cairo b/cairo_programs/proof_programs/inv_mod_p_uint512.cairo deleted file mode 120000 index cc8662e6db..0000000000 --- a/cairo_programs/proof_programs/inv_mod_p_uint512.cairo +++ /dev/null @@ -1 +0,0 @@ -../inv_mod_p_uint512.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/is_quad_residue_test.cairo b/cairo_programs/proof_programs/is_quad_residue_test.cairo deleted file mode 120000 index 1ea92a4976..0000000000 --- a/cairo_programs/proof_programs/is_quad_residue_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../is_quad_residue_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/is_zero.cairo b/cairo_programs/proof_programs/is_zero.cairo deleted file mode 120000 index c564d75006..0000000000 --- a/cairo_programs/proof_programs/is_zero.cairo +++ /dev/null @@ -1 +0,0 @@ -../is_zero.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/is_zero_pack.cairo b/cairo_programs/proof_programs/is_zero_pack.cairo deleted file mode 120000 index afa37d803c..0000000000 --- a/cairo_programs/proof_programs/is_zero_pack.cairo +++ /dev/null @@ -1 +0,0 @@ -../is_zero_pack.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/jmp.cairo b/cairo_programs/proof_programs/jmp.cairo deleted file mode 120000 index 64d4cc6476..0000000000 --- a/cairo_programs/proof_programs/jmp.cairo +++ /dev/null @@ -1 +0,0 @@ -../jmp.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/jmp_if_condition.cairo b/cairo_programs/proof_programs/jmp_if_condition.cairo deleted file mode 120000 index 4fba05b1a5..0000000000 --- a/cairo_programs/proof_programs/jmp_if_condition.cairo +++ /dev/null @@ -1 +0,0 @@ -../jmp_if_condition.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak.cairo b/cairo_programs/proof_programs/keccak.cairo deleted file mode 120000 index 85e66e5a21..0000000000 --- a/cairo_programs/proof_programs/keccak.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak_add_uint256.cairo b/cairo_programs/proof_programs/keccak_add_uint256.cairo deleted file mode 120000 index d0fb471b98..0000000000 --- a/cairo_programs/proof_programs/keccak_add_uint256.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak_add_uint256.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak_alternative_hint.cairo b/cairo_programs/proof_programs/keccak_alternative_hint.cairo deleted file mode 120000 index 6960b2186f..0000000000 --- a/cairo_programs/proof_programs/keccak_alternative_hint.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak_alternative_hint.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak_builtin.cairo b/cairo_programs/proof_programs/keccak_builtin.cairo deleted file mode 120000 index 71b14b43ff..0000000000 --- a/cairo_programs/proof_programs/keccak_builtin.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak_builtin.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak_copy_inputs.cairo b/cairo_programs/proof_programs/keccak_copy_inputs.cairo deleted file mode 120000 index 8e8e429ccd..0000000000 --- a/cairo_programs/proof_programs/keccak_copy_inputs.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak_copy_inputs.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak_integration_tests.cairo b/cairo_programs/proof_programs/keccak_integration_tests.cairo deleted file mode 120000 index 5f2e6d3225..0000000000 --- a/cairo_programs/proof_programs/keccak_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/keccak_uint256.cairo b/cairo_programs/proof_programs/keccak_uint256.cairo deleted file mode 120000 index a2da091a09..0000000000 --- a/cairo_programs/proof_programs/keccak_uint256.cairo +++ /dev/null @@ -1 +0,0 @@ -../keccak_uint256.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/math_cmp.cairo b/cairo_programs/proof_programs/math_cmp.cairo deleted file mode 120000 index 431fdeccff..0000000000 --- a/cairo_programs/proof_programs/math_cmp.cairo +++ /dev/null @@ -1 +0,0 @@ -../math_cmp.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/math_cmp_and_pow_integration_tests.cairo b/cairo_programs/proof_programs/math_cmp_and_pow_integration_tests.cairo deleted file mode 120000 index d2c2d9c790..0000000000 --- a/cairo_programs/proof_programs/math_cmp_and_pow_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../math_cmp_and_pow_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/math_integration_tests.cairo b/cairo_programs/proof_programs/math_integration_tests.cairo deleted file mode 120000 index 041d4ae8c5..0000000000 --- a/cairo_programs/proof_programs/math_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../math_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/memcpy_test.cairo b/cairo_programs/proof_programs/memcpy_test.cairo deleted file mode 120000 index 8fe365be61..0000000000 --- a/cairo_programs/proof_programs/memcpy_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../memcpy_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/memory_holes.cairo b/cairo_programs/proof_programs/memory_holes.cairo deleted file mode 120000 index e1fadbb4fb..0000000000 --- a/cairo_programs/proof_programs/memory_holes.cairo +++ /dev/null @@ -1 +0,0 @@ -../memory_holes.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/memory_integration_tests.cairo b/cairo_programs/proof_programs/memory_integration_tests.cairo deleted file mode 120000 index bfe860f09c..0000000000 --- a/cairo_programs/proof_programs/memory_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../memory_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/memset.cairo b/cairo_programs/proof_programs/memset.cairo deleted file mode 120000 index 72599c1ecb..0000000000 --- a/cairo_programs/proof_programs/memset.cairo +++ /dev/null @@ -1 +0,0 @@ -../memset.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/mul_s_inv.cairo b/cairo_programs/proof_programs/mul_s_inv.cairo deleted file mode 120000 index e1a7cd0deb..0000000000 --- a/cairo_programs/proof_programs/mul_s_inv.cairo +++ /dev/null @@ -1 +0,0 @@ -../mul_s_inv.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/multiplicative_inverse.cairo b/cairo_programs/proof_programs/multiplicative_inverse.cairo deleted file mode 120000 index e281f13e2d..0000000000 --- a/cairo_programs/proof_programs/multiplicative_inverse.cairo +++ /dev/null @@ -1 +0,0 @@ -../multiplicative_inverse.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/n_bit.cairo b/cairo_programs/proof_programs/n_bit.cairo deleted file mode 120000 index 49b68729a0..0000000000 --- a/cairo_programs/proof_programs/n_bit.cairo +++ /dev/null @@ -1 +0,0 @@ -../n_bit.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/nondet_bigint3_v2.cairo b/cairo_programs/proof_programs/nondet_bigint3_v2.cairo deleted file mode 120000 index 62d24de45b..0000000000 --- a/cairo_programs/proof_programs/nondet_bigint3_v2.cairo +++ /dev/null @@ -1 +0,0 @@ -../nondet_bigint3_v2.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/normalize_address.cairo b/cairo_programs/proof_programs/normalize_address.cairo deleted file mode 120000 index 52b57a98f6..0000000000 --- a/cairo_programs/proof_programs/normalize_address.cairo +++ /dev/null @@ -1 +0,0 @@ -../normalize_address.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/not_main.cairo b/cairo_programs/proof_programs/not_main.cairo deleted file mode 120000 index 38ec87e9b2..0000000000 --- a/cairo_programs/proof_programs/not_main.cairo +++ /dev/null @@ -1 +0,0 @@ -../not_main.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/operations_with_data_structures.cairo b/cairo_programs/proof_programs/operations_with_data_structures.cairo deleted file mode 120000 index 34c73ce7f6..0000000000 --- a/cairo_programs/proof_programs/operations_with_data_structures.cairo +++ /dev/null @@ -1 +0,0 @@ -../operations_with_data_structures.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/packed_sha256.cairo b/cairo_programs/proof_programs/packed_sha256.cairo deleted file mode 120000 index d98488a7d2..0000000000 --- a/cairo_programs/proof_programs/packed_sha256.cairo +++ /dev/null @@ -1 +0,0 @@ -../packed_sha256.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/packed_sha256_test.cairo b/cairo_programs/proof_programs/packed_sha256_test.cairo deleted file mode 120000 index dfb0a9b318..0000000000 --- a/cairo_programs/proof_programs/packed_sha256_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../packed_sha256_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/pedersen_test.cairo b/cairo_programs/proof_programs/pedersen_test.cairo deleted file mode 120000 index fb98bd6900..0000000000 --- a/cairo_programs/proof_programs/pedersen_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../pedersen_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/pointers.cairo b/cairo_programs/proof_programs/pointers.cairo deleted file mode 120000 index 799b56b537..0000000000 --- a/cairo_programs/proof_programs/pointers.cairo +++ /dev/null @@ -1 +0,0 @@ -../pointers.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/poseidon_builtin.cairo b/cairo_programs/proof_programs/poseidon_builtin.cairo deleted file mode 120000 index bc4fb83e23..0000000000 --- a/cairo_programs/proof_programs/poseidon_builtin.cairo +++ /dev/null @@ -1 +0,0 @@ -../poseidon_builtin.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/poseidon_hash.cairo b/cairo_programs/proof_programs/poseidon_hash.cairo deleted file mode 120000 index 190a72caae..0000000000 --- a/cairo_programs/proof_programs/poseidon_hash.cairo +++ /dev/null @@ -1 +0,0 @@ -../poseidon_hash.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/poseidon_multirun.cairo b/cairo_programs/proof_programs/poseidon_multirun.cairo deleted file mode 120000 index 30c32a782d..0000000000 --- a/cairo_programs/proof_programs/poseidon_multirun.cairo +++ /dev/null @@ -1 +0,0 @@ -../poseidon_multirun.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/pow.cairo b/cairo_programs/proof_programs/pow.cairo deleted file mode 120000 index 501ee61467..0000000000 --- a/cairo_programs/proof_programs/pow.cairo +++ /dev/null @@ -1 +0,0 @@ -../pow.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/print.cairo b/cairo_programs/proof_programs/print.cairo deleted file mode 120000 index 38c1608575..0000000000 --- a/cairo_programs/proof_programs/print.cairo +++ /dev/null @@ -1 +0,0 @@ -../print.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/recover_y.cairo b/cairo_programs/proof_programs/recover_y.cairo deleted file mode 120000 index 4fdd3f9e3d..0000000000 --- a/cairo_programs/proof_programs/recover_y.cairo +++ /dev/null @@ -1 +0,0 @@ -../recover_y.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/reduce.cairo b/cairo_programs/proof_programs/reduce.cairo deleted file mode 120000 index 42dbc59c35..0000000000 --- a/cairo_programs/proof_programs/reduce.cairo +++ /dev/null @@ -1 +0,0 @@ -../reduce.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/relocate_segments.cairo b/cairo_programs/proof_programs/relocate_segments.cairo deleted file mode 120000 index 44ad753198..0000000000 --- a/cairo_programs/proof_programs/relocate_segments.cairo +++ /dev/null @@ -1 +0,0 @@ -../relocate_segments.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/relocate_segments_with_offset.cairo b/cairo_programs/proof_programs/relocate_segments_with_offset.cairo deleted file mode 120000 index 71dd71fe10..0000000000 --- a/cairo_programs/proof_programs/relocate_segments_with_offset.cairo +++ /dev/null @@ -1 +0,0 @@ -../relocate_segments_with_offset.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/relocate_temporary_segment_append.cairo b/cairo_programs/proof_programs/relocate_temporary_segment_append.cairo deleted file mode 120000 index 1f0e8ac7cf..0000000000 --- a/cairo_programs/proof_programs/relocate_temporary_segment_append.cairo +++ /dev/null @@ -1 +0,0 @@ -../relocate_temporary_segment_append.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/relocate_temporary_segment_into_new.cairo b/cairo_programs/proof_programs/relocate_temporary_segment_into_new.cairo deleted file mode 120000 index 02d22be9c6..0000000000 --- a/cairo_programs/proof_programs/relocate_temporary_segment_into_new.cairo +++ /dev/null @@ -1 +0,0 @@ -../relocate_temporary_segment_into_new.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/return.cairo b/cairo_programs/proof_programs/return.cairo deleted file mode 120000 index 4f0747ca34..0000000000 --- a/cairo_programs/proof_programs/return.cairo +++ /dev/null @@ -1 +0,0 @@ -../return.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/reversed_register_instructions.cairo b/cairo_programs/proof_programs/reversed_register_instructions.cairo deleted file mode 120000 index 6f68fd0a23..0000000000 --- a/cairo_programs/proof_programs/reversed_register_instructions.cairo +++ /dev/null @@ -1 +0,0 @@ -../reversed_register_instructions.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/search_sorted_lower.cairo b/cairo_programs/proof_programs/search_sorted_lower.cairo deleted file mode 120000 index b95d849382..0000000000 --- a/cairo_programs/proof_programs/search_sorted_lower.cairo +++ /dev/null @@ -1 +0,0 @@ -../search_sorted_lower.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/secp.cairo b/cairo_programs/proof_programs/secp.cairo deleted file mode 120000 index cd957092e2..0000000000 --- a/cairo_programs/proof_programs/secp.cairo +++ /dev/null @@ -1 +0,0 @@ -../secp.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/secp256r1_div_mod_n.cairo b/cairo_programs/proof_programs/secp256r1_div_mod_n.cairo deleted file mode 120000 index 2049ea105b..0000000000 --- a/cairo_programs/proof_programs/secp256r1_div_mod_n.cairo +++ /dev/null @@ -1 +0,0 @@ -../secp256r1_div_mod_n.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/secp256r1_fast_ec_add.cairo b/cairo_programs/proof_programs/secp256r1_fast_ec_add.cairo deleted file mode 120000 index 9e8a00dff3..0000000000 --- a/cairo_programs/proof_programs/secp256r1_fast_ec_add.cairo +++ /dev/null @@ -1 +0,0 @@ -../secp256r1_fast_ec_add.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/secp256r1_slope.cairo b/cairo_programs/proof_programs/secp256r1_slope.cairo deleted file mode 120000 index 7e44c983fa..0000000000 --- a/cairo_programs/proof_programs/secp256r1_slope.cairo +++ /dev/null @@ -1 +0,0 @@ -../secp256r1_slope.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/secp_ec.cairo b/cairo_programs/proof_programs/secp_ec.cairo deleted file mode 120000 index 1426f88cee..0000000000 --- a/cairo_programs/proof_programs/secp_ec.cairo +++ /dev/null @@ -1 +0,0 @@ -../secp_ec.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/secp_integration_tests.cairo b/cairo_programs/proof_programs/secp_integration_tests.cairo deleted file mode 120000 index 5b1fd2cc64..0000000000 --- a/cairo_programs/proof_programs/secp_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../secp_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/set_add.cairo b/cairo_programs/proof_programs/set_add.cairo deleted file mode 120000 index 8732851995..0000000000 --- a/cairo_programs/proof_programs/set_add.cairo +++ /dev/null @@ -1 +0,0 @@ -../set_add.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/set_integration_tests.cairo b/cairo_programs/proof_programs/set_integration_tests.cairo deleted file mode 120000 index 95aaa7e749..0000000000 --- a/cairo_programs/proof_programs/set_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../set_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/sha256.cairo b/cairo_programs/proof_programs/sha256.cairo deleted file mode 120000 index 05f56ec086..0000000000 --- a/cairo_programs/proof_programs/sha256.cairo +++ /dev/null @@ -1 +0,0 @@ -../sha256.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/sha256_test.cairo b/cairo_programs/proof_programs/sha256_test.cairo deleted file mode 120000 index 63f8a51ea5..0000000000 --- a/cairo_programs/proof_programs/sha256_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../sha256_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/signature.cairo b/cairo_programs/proof_programs/signature.cairo deleted file mode 120000 index fa2f440398..0000000000 --- a/cairo_programs/proof_programs/signature.cairo +++ /dev/null @@ -1 +0,0 @@ -../signature.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/signed_div_rem.cairo b/cairo_programs/proof_programs/signed_div_rem.cairo deleted file mode 120000 index 2013d6439b..0000000000 --- a/cairo_programs/proof_programs/signed_div_rem.cairo +++ /dev/null @@ -1 +0,0 @@ -../signed_div_rem.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/simple_print.cairo b/cairo_programs/proof_programs/simple_print.cairo deleted file mode 120000 index 0352f30c9d..0000000000 --- a/cairo_programs/proof_programs/simple_print.cairo +++ /dev/null @@ -1 +0,0 @@ -../simple_print.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/split_felt.cairo b/cairo_programs/proof_programs/split_felt.cairo deleted file mode 120000 index ba534b7ce1..0000000000 --- a/cairo_programs/proof_programs/split_felt.cairo +++ /dev/null @@ -1 +0,0 @@ -../split_felt.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/split_int.cairo b/cairo_programs/proof_programs/split_int.cairo deleted file mode 120000 index 98218d4d99..0000000000 --- a/cairo_programs/proof_programs/split_int.cairo +++ /dev/null @@ -1 +0,0 @@ -../split_int.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/split_int_big.cairo b/cairo_programs/proof_programs/split_int_big.cairo deleted file mode 120000 index 4ab22844b8..0000000000 --- a/cairo_programs/proof_programs/split_int_big.cairo +++ /dev/null @@ -1 +0,0 @@ -../split_int_big.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/split_xx_hint.cairo b/cairo_programs/proof_programs/split_xx_hint.cairo deleted file mode 120000 index a816a67cf3..0000000000 --- a/cairo_programs/proof_programs/split_xx_hint.cairo +++ /dev/null @@ -1 +0,0 @@ -../split_xx_hint.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/sqrt.cairo b/cairo_programs/proof_programs/sqrt.cairo deleted file mode 120000 index 5c171547ee..0000000000 --- a/cairo_programs/proof_programs/sqrt.cairo +++ /dev/null @@ -1 +0,0 @@ -../sqrt.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/squash_dict.cairo b/cairo_programs/proof_programs/squash_dict.cairo deleted file mode 120000 index 1c22456028..0000000000 --- a/cairo_programs/proof_programs/squash_dict.cairo +++ /dev/null @@ -1 +0,0 @@ -../squash_dict.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/struct.cairo b/cairo_programs/proof_programs/struct.cairo deleted file mode 120000 index 4eb4120348..0000000000 --- a/cairo_programs/proof_programs/struct.cairo +++ /dev/null @@ -1 +0,0 @@ -../struct.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/test_addition_if.cairo b/cairo_programs/proof_programs/test_addition_if.cairo deleted file mode 120000 index 5689bff959..0000000000 --- a/cairo_programs/proof_programs/test_addition_if.cairo +++ /dev/null @@ -1 +0,0 @@ -../test_addition_if.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/test_reverse_if.cairo b/cairo_programs/proof_programs/test_reverse_if.cairo deleted file mode 120000 index afdc5ee805..0000000000 --- a/cairo_programs/proof_programs/test_reverse_if.cairo +++ /dev/null @@ -1 +0,0 @@ -../test_reverse_if.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/test_subtraction_if.cairo b/cairo_programs/proof_programs/test_subtraction_if.cairo deleted file mode 120000 index 367f1ba841..0000000000 --- a/cairo_programs/proof_programs/test_subtraction_if.cairo +++ /dev/null @@ -1 +0,0 @@ -../test_subtraction_if.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint256.cairo b/cairo_programs/proof_programs/uint256.cairo deleted file mode 120000 index 13750cfcfa..0000000000 --- a/cairo_programs/proof_programs/uint256.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint256.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint256_improvements.cairo b/cairo_programs/proof_programs/uint256_improvements.cairo deleted file mode 120000 index d44d558e6d..0000000000 --- a/cairo_programs/proof_programs/uint256_improvements.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint256_improvements.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint256_integration_tests.cairo b/cairo_programs/proof_programs/uint256_integration_tests.cairo deleted file mode 120000 index 08f7ce05e4..0000000000 --- a/cairo_programs/proof_programs/uint256_integration_tests.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint256_integration_tests.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint384.cairo b/cairo_programs/proof_programs/uint384.cairo deleted file mode 120000 index 1bf594c3ae..0000000000 --- a/cairo_programs/proof_programs/uint384.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint384.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint384_extension.cairo b/cairo_programs/proof_programs/uint384_extension.cairo deleted file mode 120000 index aa817df393..0000000000 --- a/cairo_programs/proof_programs/uint384_extension.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint384_extension.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint384_extension_test.cairo b/cairo_programs/proof_programs/uint384_extension_test.cairo deleted file mode 120000 index 74fd0c8187..0000000000 --- a/cairo_programs/proof_programs/uint384_extension_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint384_extension_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/uint384_test.cairo b/cairo_programs/proof_programs/uint384_test.cairo deleted file mode 120000 index d956e6dae8..0000000000 --- a/cairo_programs/proof_programs/uint384_test.cairo +++ /dev/null @@ -1 +0,0 @@ -../uint384_test.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/unsafe_keccak.cairo b/cairo_programs/proof_programs/unsafe_keccak.cairo deleted file mode 120000 index 847d284f83..0000000000 --- a/cairo_programs/proof_programs/unsafe_keccak.cairo +++ /dev/null @@ -1 +0,0 @@ -../unsafe_keccak.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/unsafe_keccak_finalize.cairo b/cairo_programs/proof_programs/unsafe_keccak_finalize.cairo deleted file mode 120000 index 892b2bb4e5..0000000000 --- a/cairo_programs/proof_programs/unsafe_keccak_finalize.cairo +++ /dev/null @@ -1 +0,0 @@ -../unsafe_keccak_finalize.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/unsigned_div_rem.cairo b/cairo_programs/proof_programs/unsigned_div_rem.cairo deleted file mode 120000 index d814de6b45..0000000000 --- a/cairo_programs/proof_programs/unsigned_div_rem.cairo +++ /dev/null @@ -1 +0,0 @@ -../unsigned_div_rem.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/use_imported_module.cairo b/cairo_programs/proof_programs/use_imported_module.cairo deleted file mode 120000 index a413a84acf..0000000000 --- a/cairo_programs/proof_programs/use_imported_module.cairo +++ /dev/null @@ -1 +0,0 @@ -../use_imported_module.cairo \ No newline at end of file diff --git a/cairo_programs/proof_programs/usort.cairo b/cairo_programs/proof_programs/usort.cairo deleted file mode 120000 index 4a7e19e63f..0000000000 --- a/cairo_programs/proof_programs/usort.cairo +++ /dev/null @@ -1 +0,0 @@ -../usort.cairo \ No newline at end of file diff --git a/cairo_programs/secp.cairo b/cairo_programs/secp.cairo index 747d8c7421..c7e9018eb0 100644 --- a/cairo_programs/secp.cairo +++ b/cairo_programs/secp.cairo @@ -1,6 +1,6 @@ %builtins range_check -from starkware.cairo.common.cairo_secp.bigint import nondet_bigint3, BigInt3, bigint_to_uint256 - +from starkware.cairo.common.cairo_secp.bigint3 import BigInt3, SumBigInt3 +from starkware.cairo.common.cairo_secp.bigint import nondet_bigint3, bigint_to_uint256 from starkware.cairo.common.cairo_secp.field import verify_zero, UnreducedBigInt3, reduce, is_zero func main{range_check_ptr: felt}() { @@ -43,17 +43,17 @@ func main{range_check_ptr: felt}() { ); // is_zero - let (u) = is_zero(BigInt3(0, 0, 0)); + let (u) = is_zero(SumBigInt3(0, 0, 0)); assert u = 1; let (v) = is_zero( - BigInt3(232113757366008801543585, 232113757366008801543585, 232113757366008801543585) + SumBigInt3(232113757366008801543585, 232113757366008801543585, 232113757366008801543585) ); assert v = 0; - let (w) = is_zero(BigInt3(-10, -10, -10)); + let (w) = is_zero(SumBigInt3(-10, -10, -10)); assert w = 0; - let (z) = is_zero(BigInt3(1833312543, 67523423, 8790312)); + let (z) = is_zero(SumBigInt3(1833312543, 67523423, 8790312)); assert z = 0; return (); diff --git a/cairo_programs/secp_integration_tests.cairo b/cairo_programs/secp_integration_tests.cairo index 7eeaae615b..45ec410248 100644 --- a/cairo_programs/secp_integration_tests.cairo +++ b/cairo_programs/secp_integration_tests.cairo @@ -1,12 +1,12 @@ %builtins range_check from starkware.cairo.common.cairo_secp.bigint import ( - BigInt3, bigint_mul, nondet_bigint3, bigint_to_uint256, uint256_to_bigint, ) +from starkware.cairo.common.cairo_secp.bigint3 import BigInt3, SumBigInt3 from starkware.cairo.common.cairo_secp.signature import ( get_generator_point, validate_signature_entry, @@ -86,7 +86,7 @@ func test_operations{range_check_ptr}(point: EcPoint) { let (zero_uint, _) = uint256_add(slope_uint, neg_slope); let (zero) = uint256_to_bigint(zero_uint); - let (is_z) = is_zero(zero); + let (is_z) = is_zero(SumBigInt3(d0=zero.d0, d1=zero.d1, d2=zero.d2)); assert is_z = 1; let (pow2, scaled) = ec_mul_inner(point, 0, 0); diff --git a/docs/README.md b/docs/README.md index dd1d40c420..f25a1c762a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,3 +4,4 @@ * [Custom Hint Processor](./hint_processor/) * [How to run a cairo program with custom hints](./hint_processor/builtin_hint_processor) * [References parsing](./references_parsing/) +* [Tracer](./tracer/) diff --git a/docs/hint_processor/README.md b/docs/hint_processor/README.md index 5b51765b77..a616cc0bfd 100644 --- a/docs/hint_processor/README.md +++ b/docs/hint_processor/README.md @@ -24,11 +24,10 @@ The purpose of this method is to organize the data related to hints in the way i ### `execute_hint` This method is called at the start of each VM step when there is a hint to execute. -It receives the dynamic structure created by `compile_hint` along with the program constants and a set of proxies containing a limited access to the VM's Internals: +It receives the dynamic structure created by `compile_hint` along with the program constants and a some of the VM's Internals: -* `exec_scopes_proxy` is the hint's gateway to interact with the execution_scopes in the VM and share data between hints without inserting them into the cairo execution. It provides methods to create and remove scopes and to modify the current scope, along with several helper methods to allow inserting and retrieving variables of specific types. This proxy only allows modifying the current scope, which is the last available scope before the hint's execution (Note that calling enter_scope and exit_scope won't change the current scope for the duration of the hint´s execution) -* `vm_proxy` is the hint's gateway to the internal values of the VM, it provides mutable references to the memory segment manager and the run context, and immutable references to the builtin runners and the program's prime, it also contains a memory proxy: -* `MemoryProxy`: It grants a more limited access to the VM's memory, providing the necessary methods to modify it in a controlled manner. +* `exec_scopes` Allows sharing data between hints without inserting them into the cairo execution. It provides methods to create and remove scopes and to modify the current scope, along with several helper methods to allow inserting and retrieving variables. It only allows modifying the current scope, which is the last available scope before the hint's execution (Note that calling enter_scope and exit_scope won't change the current scope for the duration of the hint´s execution) +* `vm` a mutable reference to the `VirtualMachine`, interaction with it is limited to its public fields and methods allowing to mutate it in a controlled manner The purpose of this method is to carry out the execution of the hint, given the data from `compile_hint` @@ -92,15 +91,15 @@ impl HintProcessor for MyHintProcessor { fn execute_hint( &mut self, - vm_proxy: &mut VMProxy, - exec_scopes_proxy: &mut ExecutionScopesProxy, + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, hint_data: &Box, ) -> Result<(), VirtualMachineError> { let hint_data = hint_data .downcast_ref::() .ok_or(VirtualMachineError::WrongHintData)?; match &*hint_data.code { - SPLIT_FELT => split_felt(vm_proxy, &hint_data.ids_data, &hint_data.ap_tracking), + SPLIT_FELT => split_felt(vm, &hint_data.ids_data, &hint_data.ap_tracking), _ => Err(VirtualMachineError::UnknownHint(code.to_string())), } } @@ -133,14 +132,14 @@ fn get_ids_data( This is the hint's implementation using the provided data and helpers: ```rust pub fn split_felt( - vm_proxy: &mut VMProxy, + vm: &mut VirtualMachine, ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), VirtualMachineError> { - let value = get_integer_from_reference(vm_proxy, ids_data.get("value")?, ap_tracking)?; + let value = get_integer_from_reference(vm, ids_data.get("value")?, ap_tracking)?; let low: BigInt = value & ((bigint!(1).shl(128_u8)) - bigint!(1)); let high: BigInt = value.shr(128_u8); - insert_value_from_reference(high, vm_proxy, ids_data.get("high")?, ap_tracking)?; - insert_value_from_reference(low, vm_proxy, ids_data.get("low")?, ap_tracking) + insert_value_from_reference(high, vm, ids_data.get("high")?, ap_tracking)?; + insert_value_from_reference(low, vm, ids_data.get("low")?, ap_tracking) } ``` diff --git a/docs/tracer/README.md b/docs/tracer/README.md new file mode 100644 index 0000000000..5e5e3b6404 --- /dev/null +++ b/docs/tracer/README.md @@ -0,0 +1,39 @@ +# Cairo Tracer + +Cairo-vm offers a tracer which gives you a visualization of how your memory and registers change line after line as the VM executes the code. + +## Setting up the tracer + +To use the tracer, you need to build your the VM using the `with_tracer` feature flag. + +```bash +cargo build --release --features with_tracer +``` + +## Running the tracer + +Once the build in the above step is complete, you can use the `cairo-vm-cli` as you do normally with an additional argument `--tracer true`. This tells the VM to start a server where you can visualize the exection of your cairo program. + +```bash +target/release/cairo-vm-cli --layout --memory_file --trace_file --tracer true +``` + +### NOTE +> The `--memory_file` and `--trace_file` arguments are compulsory at the moment as the current code relocates the memory and trace only when these arguments are supplied. However, edits can be made in future versions to relocate if only the `--tracer` option is specified. + + +## Using the tracer + +![tracer](tracer.png) + +You can go to [http://127.0.0.1:8100/static/index.html](http://127.0.0.1:8100/static/index.html) to see the tracer. + +Use the following commands to visualize the code execution + +- `s` to go to the next step +- `Shift + s` to go to the previous step +- `n` to step over +- `N` to previous step over +- `o` to step out +- `b` to run until you reach the next breakpoint +- `B` to run until you reach the previous breakpoint diff --git a/docs/tracer/tracer.png b/docs/tracer/tracer.png new file mode 100644 index 0000000000..9cb29af0d9 Binary files /dev/null and b/docs/tracer/tracer.png differ diff --git a/examples/hyper_threading/Cargo.toml b/examples/hyper_threading/Cargo.toml new file mode 100644 index 0000000000..854e2c3fde --- /dev/null +++ b/examples/hyper_threading/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "hyper_threading" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true +keywords.workspace = true + + +[dependencies] +cairo-vm = { workspace = true, features = ["std"] } +rayon = "1.9.0" +tracing = "0.1.40" diff --git a/examples/hyper_threading/README.md b/examples/hyper_threading/README.md new file mode 100644 index 0000000000..e69152ef2a --- /dev/null +++ b/examples/hyper_threading/README.md @@ -0,0 +1,11 @@ +# Hyper-Threading Benchmarks for Cairo-VM + +## Overview +This crate is designed to benchmark the performance of Cairo-VM in a hyper-threaded environment. By leveraging the [Rayon library](https://docs.rs/rayon/latest/rayon/), we can transform sequential computations into parallel ones, maximizing the utilization of available CPU cores. + +### Running Benchmarks +To execute the benchmarks, navigate to the project's root directory and run the following command: + +```bash +make hyper-threading-benchmarks +``` diff --git a/examples/hyper_threading/hyper-threading.sh b/examples/hyper_threading/hyper-threading.sh new file mode 100644 index 0000000000..912b6cac75 --- /dev/null +++ b/examples/hyper_threading/hyper-threading.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +thread_counts=(1 2 4 6 8 10 12 16 24 32 ) +binary="target/release/hyper_threading" + + +cmd="hyperfine -r 1" + +# Build the command string with all thread counts +for threads in "${thread_counts[@]}"; do + # For hyperfine, wrap each command in 'sh -c' to correctly handle the environment variable + cmd+=" -n \"threads: ${threads}\" 'sh -c \"RAYON_NUM_THREADS=${threads} ${binary}\"'" +done + +# Execute the hyperfine command +echo "Executing benchmark for all thread counts" +eval $cmd diff --git a/examples/hyper_threading/src/main.rs b/examples/hyper_threading/src/main.rs new file mode 100644 index 0000000000..eb6fbf47c9 --- /dev/null +++ b/examples/hyper_threading/src/main.rs @@ -0,0 +1,68 @@ +use cairo_vm::{ + cairo_run::{cairo_run_program, CairoRunConfig}, + hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor, + types::program::Program, +}; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use std::path::Path; + +// Define build_filename macro to prepend a relative path to the file names +macro_rules! build_filename { + ($fname:expr) => { + format!("cairo_programs/benchmarks/{}", $fname) + }; +} + +fn main() { + let mut programs = Vec::new(); + + let program_filenames: [String; 18] = [ + build_filename!("big_factorial.json"), + build_filename!("big_fibonacci.json"), + build_filename!("blake2s_integration_benchmark.json"), + build_filename!("compare_arrays_200000.json"), + build_filename!("dict_integration_benchmark.json"), + build_filename!("field_arithmetic_get_square_benchmark.json"), + build_filename!("integration_builtins.json"), + build_filename!("keccak_integration_benchmark.json"), + build_filename!("linear_search.json"), + build_filename!("math_cmp_and_pow_integration_benchmark.json"), + build_filename!("math_integration_benchmark.json"), + build_filename!("memory_integration_benchmark.json"), + build_filename!("operations_with_data_structures_benchmarks.json"), + build_filename!("pedersen.json"), + build_filename!("poseidon_integration_benchmark.json"), + build_filename!("secp_integration_benchmark.json"), + build_filename!("set_integration_benchmark.json"), + build_filename!("uint256_integration_benchmark.json"), + ]; + + let n_programs = &program_filenames.len(); + + for filename in program_filenames { + programs.push(Program::from_file(Path::new(&filename), Some("main")).unwrap()) + } + + let start_time = std::time::Instant::now(); + + // Parallel execution of the program processing + programs.into_par_iter().for_each(|program| { + let cairo_run_config = CairoRunConfig { + entrypoint: "main", + trace_enabled: false, + relocate_mem: false, + layout: "all_cairo", + proof_mode: true, + secure_run: Some(false), + ..Default::default() + }; + let mut hint_executor = BuiltinHintProcessor::new_empty(); + + // Execute each program in parallel + let _result = cairo_run_program(&program, &cairo_run_config, &mut hint_executor) + .expect("Couldn't run program"); + }); + let elapsed = start_time.elapsed(); + + tracing::info!(%n_programs, ?elapsed, "Finished"); +} diff --git a/fuzzer/Cargo.lock b/fuzzer/Cargo.lock index 236551e8c5..b48dfec845 100644 --- a/fuzzer/Cargo.lock +++ b/fuzzer/Cargo.lock @@ -2,6 +2,23 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.7.7" @@ -116,6 +133,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -158,9 +181,36 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cairo-vm" -version = "1.0.0-rc0" +version = "1.0.0-rc1" dependencies = [ "anyhow", "arbitrary", @@ -171,7 +221,6 @@ dependencies = [ "hex", "keccak", "lazy_static", - "mimalloc", "nom", "num-bigint", "num-integer", @@ -185,6 +234,7 @@ dependencies = [ "starknet-crypto", "starknet-types-core", "thiserror-no-std", + "zip", ] [[package]] @@ -203,6 +253,22 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "cpufeatures" version = "0.2.11" @@ -212,6 +278,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -233,6 +314,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivative" version = "2.2.0" @@ -272,6 +362,16 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "funty" version = "2.0.0" @@ -368,6 +468,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "itertools" version = "0.10.5" @@ -410,13 +519,26 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4c222d5b2fdc0faf702d3ab361d14589b097f40eac9dc550e27083483edc65" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2", + "sha3", +] + [[package]] name = "lambdaworks-math" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6c4d0ddd1fcd235be5196b1bcc404f89ad3e911f4c190fa01459e05dbf40f8" +checksum = "9ee7dcab3968c71896b8ee4dc829147acc918cffe897af6265b1894527fe3add" dependencies = [ - "thiserror", + "serde", + "serde_json", ] [[package]] @@ -445,16 +567,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "libmimalloc-sys" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "lock_api" version = "0.4.11" @@ -504,21 +616,21 @@ dependencies = [ "autocfg", ] -[[package]] -name = "mimalloc" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" -dependencies = [ - "libmimalloc-sys", -] - [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "nom" version = "7.1.3" @@ -542,6 +654,12 @@ dependencies = [ "serde", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -617,12 +735,47 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -820,6 +973,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -907,12 +1071,13 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.0.6" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6b868f545d43b474c2c00e9349c489fdeb7ff17eb00cdf339744ac4cae0930" +checksum = "6d53160556d1f23425100f42b3230df747ea05763efee685a2cd939dfb640701" dependencies = [ "arbitrary", "bitvec", + "lambdaworks-crypto", "lambdaworks-math", "lazy_static", "num-bigint", @@ -961,26 +1126,6 @@ version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" -[[package]] -name = "thiserror" -version = "1.0.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "thiserror-impl-no-std" version = "2.0.2" @@ -1001,6 +1146,25 @@ dependencies = [ "thiserror-impl-no-std", ] +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "typenum" version = "1.17.0" @@ -1190,3 +1354,52 @@ dependencies = [ "quote", "syn 2.0.39", ] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/fuzzer/src/fuzz_json.rs b/fuzzer/src/fuzz_json.rs index 09193c512b..4306a29c67 100644 --- a/fuzzer/src/fuzz_json.rs +++ b/fuzzer/src/fuzz_json.rs @@ -29,7 +29,7 @@ const HEX_SYMBOLS: [&str; 16] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", ]; -const HINTS_CODE: [&str; 184] = [ +const HINTS_CODE: [&str; 186] = [ ADD_SEGMENT, VM_ENTER_SCOPE, VM_EXIT_SCOPE, @@ -139,10 +139,12 @@ const HINTS_CODE: [&str; 184] = [ EC_DOUBLE_SLOPE_V1, EC_DOUBLE_SLOPE_V2, EC_DOUBLE_SLOPE_V3, + EC_DOUBLE_SLOPE_V4, EC_DOUBLE_SLOPE_EXTERNAL_CONSTS, COMPUTE_SLOPE_V1, COMPUTE_SLOPE_V2, - COMPUTE_SLOPE_SECP256R1, + COMPUTE_SLOPE_SECP256R1_V1, + COMPUTE_SLOPE_SECP256R1_V2, IMPORT_SECP256R1_P, COMPUTE_SLOPE_WHITELIST, EC_DOUBLE_ASSIGN_NEW_X_V1, diff --git a/requirements.txt b/requirements.txt index 5eca66949f..41c32affe0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ ecdsa==0.18.0 bitarray==2.7.3 -fastecdsa==2.2.3 +fastecdsa==2.3.0 sympy==1.11.1 typeguard==2.13.3 -cairo-lang==0.12.2 +cairo-lang==0.13.1 diff --git a/rust-toolchain b/rust-toolchain index 2d24a1e077..4da0ec7b8e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "1.70.0" +channel = "1.74.1" components = ["rustfmt", "clippy"] profile = "minimal" diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 6c33144a20..d1b25dace9 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -9,8 +9,7 @@ readme.workspace = true keywords.workspace = true [features] -default = ["std", "with_mimalloc"] -with_mimalloc = ["dep:mimalloc"] +default = ["std"] std = [ "serde_json/std", "bincode/std", @@ -27,6 +26,8 @@ cairo-1-hints = [ "dep:ark-ff", "dep:ark-std", ] +tracer = [] +mod_builtin = [] # Note that these features are not retro-compatible with the cairo Python VM. test_utils = [ @@ -44,7 +45,6 @@ print = ["std"] [dependencies] zip = {version = "0.6.6", optional = true } -mimalloc = { workspace = true, optional = true } num-bigint = { workspace = true } rand = { workspace = true } num-traits = { workspace = true } @@ -63,7 +63,7 @@ keccak = { workspace = true } hashbrown = { workspace = true } anyhow = { workspace = true } thiserror-no-std = { workspace = true } -starknet-types-core = { version = "0.0.6", default-features = false, features = ["serde", "curve", "num-traits"] } +starknet-types-core = { version = "0.0.9", default-features = false, features = ["serde", "curve", "num-traits"] } # only for std num-prime = { version = "0.4.3", features = ["big-int"], optional = true } @@ -92,6 +92,7 @@ wasm-bindgen-test = "0.3.34" iai-callgrind = "0.3.1" criterion = { version = "0.5.1", features = ["html_reports"] } proptest = "1.0.0" +mimalloc.workspace = true [[bench]] path = "../bench/iai_benchmark.rs" diff --git a/vm/src/air_private_input.rs b/vm/src/air_private_input.rs index 4ea30d0d44..d1c5f1a8ca 100644 --- a/vm/src/air_private_input.rs +++ b/vm/src/air_private_input.rs @@ -1,11 +1,12 @@ use crate::{ stdlib::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, prelude::{String, Vec}, }, vm::runners::builtin_runner::{ - BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, KECCAK_BUILTIN_NAME, - POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, + ADD_MOD_BUILTIN_NAME, BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, + KECCAK_BUILTIN_NAME, MUL_MOD_BUILTIN_NAME, POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, + SIGNATURE_BUILTIN_NAME, }, }; use serde::{Deserialize, Serialize}; @@ -17,13 +18,24 @@ use crate::Felt252; pub struct AirPrivateInputSerializable { trace_path: String, memory_path: String, - pedersen: Vec, - range_check: Vec, - ecdsa: Vec, - bitwise: Vec, - ec_op: Vec, - keccak: Vec, - poseidon: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pedersen: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + range_check: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + ecdsa: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + bitwise: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + ec_op: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + keccak: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + poseidon: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + add_mod: Option, + #[serde(skip_serializing_if = "Option::is_none")] + mul_mod: Option, } // Contains only builtin public inputs, useful for library users @@ -39,6 +51,7 @@ pub enum PrivateInput { PoseidonState(PrivateInputPoseidonState), KeccakState(PrivateInputKeccakState), Signature(PrivateInputSignature), + Mod(ModInput), } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] @@ -99,6 +112,44 @@ pub struct SignatureInput { pub w: Felt252, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct ModInput { + pub instances: Vec, + pub zero_value_address: usize, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct ModInputInstance { + pub index: usize, + pub p0: Felt252, + pub p1: Felt252, + pub p2: Felt252, + pub p3: Felt252, + pub values_ptr: usize, + pub offsets_ptr: usize, + pub n: usize, + pub batch: BTreeMap, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)] +pub struct ModInputMemoryVars { + pub a_offset: usize, + pub a0: Felt252, + pub a1: Felt252, + pub a2: Felt252, + pub a3: Felt252, + pub b_offset: usize, + pub b0: Felt252, + pub b1: Felt252, + pub b2: Felt252, + pub b3: Felt252, + pub c_offset: usize, + pub c0: Felt252, + pub c1: Felt252, + pub c2: Felt252, + pub c3: Felt252, +} + impl AirPrivateInput { pub fn to_serializable( &self, @@ -108,35 +159,159 @@ impl AirPrivateInput { AirPrivateInputSerializable { trace_path, memory_path, - pedersen: self.0.get(HASH_BUILTIN_NAME).cloned().unwrap_or_default(), - range_check: self + pedersen: self.0.get(HASH_BUILTIN_NAME).cloned(), + range_check: self.0.get(RANGE_CHECK_BUILTIN_NAME).cloned(), + ecdsa: self.0.get(SIGNATURE_BUILTIN_NAME).cloned(), + bitwise: self.0.get(BITWISE_BUILTIN_NAME).cloned(), + ec_op: self.0.get(EC_OP_BUILTIN_NAME).cloned(), + keccak: self.0.get(KECCAK_BUILTIN_NAME).cloned(), + poseidon: self.0.get(POSEIDON_BUILTIN_NAME).cloned(), + add_mod: self .0 - .get(RANGE_CHECK_BUILTIN_NAME) - .cloned() - .unwrap_or_default(), - ecdsa: self + .get(ADD_MOD_BUILTIN_NAME) + .and_then(|pi| pi.first()) + .cloned(), + mul_mod: self .0 - .get(SIGNATURE_BUILTIN_NAME) - .cloned() - .unwrap_or_default(), - bitwise: self - .0 - .get(BITWISE_BUILTIN_NAME) - .cloned() - .unwrap_or_default(), - ec_op: self.0.get(EC_OP_BUILTIN_NAME).cloned().unwrap_or_default(), - keccak: self.0.get(KECCAK_BUILTIN_NAME).cloned().unwrap_or_default(), - poseidon: self - .0 - .get(POSEIDON_BUILTIN_NAME) - .cloned() - .unwrap_or_default(), + .get(MUL_MOD_BUILTIN_NAME) + .and_then(|pi| pi.first()) + .cloned(), } } } +impl From for AirPrivateInput { + fn from(private_input: AirPrivateInputSerializable) -> Self { + let mut inputs = HashMap::new(); + let mut insert_input = |input_name, input| { + if let Some(input) = input { + inputs.insert(input_name, input); + } + }; + insert_input(HASH_BUILTIN_NAME, private_input.pedersen); + insert_input(RANGE_CHECK_BUILTIN_NAME, private_input.range_check); + insert_input(SIGNATURE_BUILTIN_NAME, private_input.ecdsa); + insert_input(BITWISE_BUILTIN_NAME, private_input.bitwise); + insert_input(EC_OP_BUILTIN_NAME, private_input.ec_op); + insert_input(KECCAK_BUILTIN_NAME, private_input.keccak); + insert_input(POSEIDON_BUILTIN_NAME, private_input.poseidon); + + Self(inputs) + } +} + impl AirPrivateInputSerializable { pub fn serialize_json(&self) -> Result { serde_json::to_string_pretty(&self) } } + +#[cfg(test)] +mod tests { + #[cfg(feature = "std")] + use { + super::*, + crate::air_private_input::{AirPrivateInput, AirPrivateInputSerializable}, + crate::vm::runners::builtin_runner::{ + BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, KECCAK_BUILTIN_NAME, + POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, + }, + assert_matches::assert_matches, + }; + + #[cfg(any(target_arch = "wasm32", no_std, not(feature = "std")))] + use crate::alloc::string::ToString; + + #[cfg(feature = "std")] + #[test] + fn test_from_serializable() { + let serializable_private_input = AirPrivateInputSerializable { + trace_path: "trace.bin".to_string(), + memory_path: "memory.bin".to_string(), + pedersen: Some(vec![PrivateInput::Pair(PrivateInputPair { + index: 0, + x: Felt252::from(100), + y: Felt252::from(200), + })]), + range_check: Some(vec![PrivateInput::Value(PrivateInputValue { + index: 10000, + value: Felt252::from(8000), + })]), + ecdsa: Some(vec![PrivateInput::Signature(PrivateInputSignature { + index: 0, + pubkey: Felt252::from(123), + msg: Felt252::from(456), + signature_input: SignatureInput { + r: Felt252::from(654), + w: Felt252::from(321), + }, + })]), + bitwise: Some(vec![PrivateInput::Pair(PrivateInputPair { + index: 4, + x: Felt252::from(7), + y: Felt252::from(8), + })]), + ec_op: Some(vec![PrivateInput::EcOp(PrivateInputEcOp { + index: 1, + p_x: Felt252::from(10), + p_y: Felt252::from(10), + m: Felt252::from(100), + q_x: Felt252::from(11), + q_y: Felt252::from(14), + })]), + keccak: Some(vec![PrivateInput::KeccakState(PrivateInputKeccakState { + index: 0, + input_s0: Felt252::from(0), + input_s1: Felt252::from(1), + input_s2: Felt252::from(2), + input_s3: Felt252::from(3), + input_s4: Felt252::from(4), + input_s5: Felt252::from(5), + input_s6: Felt252::from(6), + input_s7: Felt252::from(7), + })]), + poseidon: Some(vec![PrivateInput::PoseidonState( + PrivateInputPoseidonState { + index: 42, + input_s0: Felt252::from(1), + input_s1: Felt252::from(2), + input_s2: Felt252::from(3), + }, + )]), + add_mod: None, + mul_mod: None, + }; + + let private_input = AirPrivateInput::from(serializable_private_input.clone()); + + assert_matches!(private_input.0.get(HASH_BUILTIN_NAME), data if data == serializable_private_input.pedersen.as_ref()); + assert_matches!(private_input.0.get(RANGE_CHECK_BUILTIN_NAME), data if data == serializable_private_input.range_check.as_ref()); + assert_matches!(private_input.0.get(SIGNATURE_BUILTIN_NAME), data if data == serializable_private_input.ecdsa.as_ref()); + assert_matches!(private_input.0.get(BITWISE_BUILTIN_NAME), data if data == serializable_private_input.bitwise.as_ref()); + assert_matches!(private_input.0.get(EC_OP_BUILTIN_NAME), data if data == serializable_private_input.ec_op.as_ref()); + assert_matches!(private_input.0.get(KECCAK_BUILTIN_NAME), data if data == serializable_private_input.keccak.as_ref()); + assert_matches!(private_input.0.get(POSEIDON_BUILTIN_NAME), data if data == serializable_private_input.poseidon.as_ref()); + } + + #[test] + fn serialize_air_private_input_small_layout_only_builtins() { + let config = crate::cairo_run::CairoRunConfig { + proof_mode: true, + relocate_mem: true, + trace_enabled: true, + layout: "small", + ..Default::default() + }; + let (runner, vm) = crate::cairo_run::cairo_run(include_bytes!("../../cairo_programs/proof_programs/fibonacci.json"), &config, &mut crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor::new_empty()).unwrap(); + let public_input = runner.get_air_private_input(&vm); + let serialized_public_input = + public_input.to_serializable("/dev/null".to_string(), "/dev/null".to_string()); + assert!(serialized_public_input.pedersen.is_some()); + assert!(serialized_public_input.range_check.is_some()); + assert!(serialized_public_input.ecdsa.is_some()); + assert!(serialized_public_input.bitwise.is_none()); + assert!(serialized_public_input.ec_op.is_none()); + assert!(serialized_public_input.keccak.is_none()); + assert!(serialized_public_input.poseidon.is_none()); + } +} diff --git a/vm/src/air_public_input.rs b/vm/src/air_public_input.rs index 692f391f2a..3a2bf8bc37 100644 --- a/vm/src/air_public_input.rs +++ b/vm/src/air_public_input.rs @@ -1,5 +1,5 @@ use crate::Felt252; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use thiserror_no_std::Error; use crate::{ @@ -14,18 +14,21 @@ use crate::{ }, }; -#[derive(Serialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct PublicMemoryEntry { pub address: usize, #[serde(serialize_with = "mem_value_serde::serialize")] + #[serde(deserialize_with = "mem_value_serde::deserialize")] pub value: Option, pub page: usize, } mod mem_value_serde { + use core::fmt; + use super::*; - use serde::Serializer; + use serde::{de, Deserializer, Serializer}; pub(crate) fn serialize( value: &Option, @@ -37,9 +40,41 @@ mod mem_value_serde { serializer.serialize_none() } } + + pub(crate) fn deserialize<'de, D: Deserializer<'de>>( + d: D, + ) -> Result, D::Error> { + d.deserialize_str(Felt252OptionVisitor) + } + + struct Felt252OptionVisitor; + + impl<'de> de::Visitor<'de> for Felt252OptionVisitor { + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Could not deserialize hexadecimal string") + } + + fn visit_none(self) -> Result + where + E: de::Error, + { + Ok(None) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Felt252::from_hex(value) + .map_err(de::Error::custom) + .map(Some) + } + } } -#[derive(Serialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct MemorySegmentAddresses { pub begin_addr: usize, pub stop_ptr: usize, @@ -55,7 +90,7 @@ impl From<(usize, usize)> for MemorySegmentAddresses { } } -#[derive(Serialize, Debug)] +#[derive(Serialize, Deserialize, Debug)] pub struct PublicInput<'a> { pub layout: &'a str, pub rc_min: isize, @@ -64,6 +99,7 @@ pub struct PublicInput<'a> { pub memory_segments: HashMap<&'a str, MemorySegmentAddresses>, pub public_memory: Vec, #[serde(rename = "dynamic_params")] + #[serde(skip_deserializing)] // This is set to None by default so we can skip it layout_params: Option<&'a CairoLayout>, } @@ -139,3 +175,52 @@ pub enum PublicInputError { #[error(transparent)] Trace(#[from] TraceError), } +#[cfg(test)] +mod tests { + #[cfg(feature = "std")] + use super::*; + #[cfg(feature = "std")] + use rstest::rstest; + + #[cfg(feature = "std")] + #[rstest] + #[case(include_bytes!("../../cairo_programs/proof_programs/fibonacci.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/bitwise_output.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/keccak_builtin.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/poseidon_builtin.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/relocate_temporary_segment_append.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/pedersen_test.json"))] + #[case(include_bytes!("../../cairo_programs/proof_programs/ec_op.json"))] + fn serialize_and_deserialize_air_public_input(#[case] program_content: &[u8]) { + let config = crate::cairo_run::CairoRunConfig { + proof_mode: true, + relocate_mem: true, + trace_enabled: true, + layout: "all_cairo", + ..Default::default() + }; + let (runner, vm) = crate::cairo_run::cairo_run(program_content, &config, &mut crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor::new_empty()).unwrap(); + let public_input = runner.get_air_public_input(&vm).unwrap(); + // We already know serialization works as expected due to the comparison against python VM + let serialized_public_input = public_input.serialize_json().unwrap(); + let deserialized_public_input: PublicInput = + serde_json::from_str(&serialized_public_input).unwrap(); + // Check that the deserialized public input is equal to the one we obtained from the vm first + assert_eq!(public_input.layout, deserialized_public_input.layout); + assert_eq!(public_input.rc_max, deserialized_public_input.rc_max); + assert_eq!(public_input.rc_min, deserialized_public_input.rc_min); + assert_eq!(public_input.n_steps, deserialized_public_input.n_steps); + assert_eq!( + public_input.memory_segments, + deserialized_public_input.memory_segments + ); + assert_eq!( + public_input.public_memory, + deserialized_public_input.public_memory + ); + assert!( + public_input.layout_params.is_none() + && deserialized_public_input.layout_params.is_none() + ); + } +} diff --git a/vm/src/cairo_run.rs b/vm/src/cairo_run.rs index 2ddb1c0de2..07c3a29c77 100644 --- a/vm/src/cairo_run.rs +++ b/vm/src/cairo_run.rs @@ -28,6 +28,7 @@ pub struct CairoRunConfig<'a> { pub proof_mode: bool, pub secure_run: Option, pub disable_trace_padding: bool, + pub allow_missing_builtins: Option, } #[cfg(feature = "arbitrary")] @@ -56,6 +57,7 @@ impl<'a> Default for CairoRunConfig<'a> { proof_mode: false, secure_run: None, disable_trace_padding: false, + allow_missing_builtins: None, } } } @@ -69,6 +71,10 @@ pub fn cairo_run_program( .secure_run .unwrap_or(!cairo_run_config.proof_mode); + let allow_missing_builtins = cairo_run_config + .allow_missing_builtins + .unwrap_or(cairo_run_config.proof_mode); + let mut cairo_runner = CairoRunner::new( program, cairo_run_config.layout, @@ -76,12 +82,16 @@ pub fn cairo_run_program( )?; let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled); - let end = cairo_runner.initialize(&mut vm)?; + let end = cairo_runner.initialize(&mut vm, allow_missing_builtins)?; // check step calculation cairo_runner .run_until_pc(end, &mut vm, hint_executor) .map_err(|err| VmException::from_vm_error(&cairo_runner, &vm, err))?; + + if cairo_run_config.proof_mode { + cairo_runner.run_for_steps(1, &mut vm, hint_executor)?; + } cairo_runner.end_run( cairo_run_config.disable_trace_padding, false, @@ -90,7 +100,7 @@ pub fn cairo_run_program( )?; vm.verify_auto_deductions()?; - cairo_runner.read_return_values(&mut vm)?; + cairo_runner.read_return_values(&mut vm, allow_missing_builtins)?; if cairo_run_config.proof_mode { cairo_runner.finalize_segments(&mut vm)?; } @@ -125,6 +135,10 @@ pub fn cairo_run_fuzzed_program( .secure_run .unwrap_or(!cairo_run_config.proof_mode); + let allow_missing_builtins = cairo_run_config + .allow_missing_builtins + .unwrap_or(cairo_run_config.proof_mode); + let mut cairo_runner = CairoRunner::new( &program, cairo_run_config.layout, @@ -133,7 +147,7 @@ pub fn cairo_run_fuzzed_program( let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled); - let _end = cairo_runner.initialize(&mut vm)?; + let _end = cairo_runner.initialize(&mut vm, allow_missing_builtins)?; let res = match cairo_runner.run_until_steps(steps_limit, &mut vm, hint_executor) { Err(VirtualMachineError::EndOfProgram(_remaining)) => Ok(()), // program ran OK but ended before steps limit @@ -145,7 +159,7 @@ pub fn cairo_run_fuzzed_program( cairo_runner.end_run(false, false, &mut vm, hint_executor)?; vm.verify_auto_deductions()?; - cairo_runner.read_return_values(&mut vm)?; + cairo_runner.read_return_values(&mut vm, allow_missing_builtins)?; if cairo_run_config.proof_mode { cairo_runner.finalize_segments(&mut vm)?; } @@ -230,7 +244,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(true); let end = cairo_runner - .initialize(&mut vm) + .initialize(&mut vm, false) .map_err(CairoRunError::Runner)?; assert!(cairo_runner @@ -252,7 +266,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_ok()); @@ -372,7 +386,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_ok()); diff --git a/vm/src/hint_processor/builtin_hint_processor/bigint.rs b/vm/src/hint_processor/builtin_hint_processor/bigint.rs index 2069446fb7..ff5326bd58 100644 --- a/vm/src/hint_processor/builtin_hint_processor/bigint.rs +++ b/vm/src/hint_processor/builtin_hint_processor/bigint.rs @@ -103,7 +103,6 @@ mod test { use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData; use crate::hint_processor::builtin_hint_processor::hint_code; use crate::hint_processor::hint_processor_definition::{HintProcessorLogic, HintReference}; - use crate::stdlib::collections::HashMap; use crate::types::exec_scope::ExecutionScopes; use crate::utils::test_utils::*; use crate::vm::vm_core::VirtualMachine; diff --git a/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs b/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs index 5f5fe2ef83..e56258018e 100644 --- a/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/blake2s_utils.rs @@ -271,9 +271,8 @@ pub fn example_blake2s_compress( let blake2s_start = get_ptr_from_var_name("blake2s_start", vm, ids_data, ap_tracking)?; let output = get_ptr_from_var_name("output", vm, ids_data, ap_tracking)?; let n_bytes = get_integer_from_var_name("n_bytes", vm, ids_data, ap_tracking).map(|x| { - x.to_u32().ok_or_else(|| { - HintError::Math(MathError::Felt252ToU32Conversion(Box::new(x.into_owned()))) - }) + x.to_u32() + .ok_or_else(|| HintError::Math(MathError::Felt252ToU32Conversion(Box::new(x)))) })??; let message = get_fixed_size_u32_array::<16>(&vm.get_integer_range(blake2s_start, 16)?)?; @@ -302,7 +301,6 @@ mod tests { hint_processor_definition::HintProcessorLogic, }, relocatable, - types::exec_scope::ExecutionScopes, utils::test_utils::*, vm::errors::memory_errors::MemoryError, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index ee441e9f46..621dbdb51b 100644 --- a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -5,6 +5,7 @@ use super::{ ec_recover_sub_a_b, }, field_arithmetic::{u256_get_square_root, u384_get_square_root, uint384_div}, + mod_circuit::{run_p_mod_circuit, run_p_mod_circuit_with_large_batch_size}, secp::{ ec_utils::{ compute_doubling_slope_external_consts, compute_slope_and_assing_secp_p, @@ -57,7 +58,7 @@ use crate::{ math_utils::*, memcpy_hint_utils::{add_segment, enter_scope, exit_scope, memcpy_enter_scope}, memset_utils::{memset_enter_scope, memset_step_loop}, - poseidon_utils::{n_greater_than_10, n_greater_than_2}, + poseidon_utils::{elements_over_x, n_greater_than_10, n_greater_than_2}, pow_utils::pow, secp::{ bigint_utils::{bigint_to_uint256, hi_max_bitlen, nondet_bigint3}, @@ -118,6 +119,9 @@ use crate::hint_processor::builtin_hint_processor::skip_next_instruction::skip_n #[cfg(feature = "print")] use crate::hint_processor::builtin_hint_processor::print::{print_array, print_dict, print_felt}; +use crate::hint_processor::builtin_hint_processor::secp::secp_utils::{ + SECP256R1_ALPHA, SECP256R1_P, +}; use super::blake2s_utils::example_blake2s_compress; @@ -531,6 +535,15 @@ impl HintProcessorLogic for BuiltinHintProcessor { &SECP_P, &ALPHA, ), + hint_code::EC_DOUBLE_SLOPE_V4 => compute_doubling_slope( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + "point", + &SECP256R1_P, + &SECP256R1_ALPHA, + ), hint_code::EC_DOUBLE_SLOPE_EXTERNAL_CONSTS => compute_doubling_slope_external_consts( vm, exec_scopes, @@ -558,13 +571,23 @@ impl HintProcessorLogic for BuiltinHintProcessor { "point1", &SECP_P_V2, ), - hint_code::COMPUTE_SLOPE_SECP256R1 => compute_slope( + hint_code::COMPUTE_SLOPE_SECP256R1_V1 => compute_slope( vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking, "point0", "point1", + "SECP_P", + ), + hint_code::COMPUTE_SLOPE_SECP256R1_V2 => compute_slope( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + "point0", + "point1", + "SECP256R1_P", ), hint_code::IMPORT_SECP256R1_P => import_secp256r1_p(exec_scopes), hint_code::COMPUTE_SLOPE_WHITELIST => compute_slope_and_assing_secp_p( @@ -731,6 +754,12 @@ impl HintProcessorLogic for BuiltinHintProcessor { hint_code::NONDET_N_GREATER_THAN_2 => { n_greater_than_2(vm, &hint_data.ids_data, &hint_data.ap_tracking) } + hint_code::NONDET_ELEMENTS_OVER_TEN => { + elements_over_x(vm, &hint_data.ids_data, &hint_data.ap_tracking, 10) + } + hint_code::NONDET_ELEMENTS_OVER_TWO => { + elements_over_x(vm, &hint_data.ids_data, &hint_data.ap_tracking, 2) + } hint_code::RANDOM_EC_POINT => { random_ec_point_hint(vm, &hint_data.ids_data, &hint_data.ap_tracking) } @@ -816,6 +845,17 @@ impl HintProcessorLogic for BuiltinHintProcessor { } hint_code::EC_RECOVER_PRODUCT_DIV_M => ec_recover_product_div_m(exec_scopes), hint_code::SPLIT_XX => split_xx(vm, &hint_data.ids_data, &hint_data.ap_tracking), + hint_code::RUN_P_CIRCUIT => { + run_p_mod_circuit(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } + hint_code::RUN_P_CIRCUIT_WITH_LARGE_BATCH_SIZE => { + run_p_mod_circuit_with_large_batch_size( + vm, + &hint_data.ids_data, + &hint_data.ap_tracking, + constants, + ) + } #[cfg(feature = "skip_next_instruction_hint")] hint_code::SKIP_NEXT_INSTRUCTION => skip_next_instruction(vm), #[cfg(feature = "print")] diff --git a/vm/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs b/vm/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs index 0beea39ee9..202cba60a0 100644 --- a/vm/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs +++ b/vm/src/hint_processor/builtin_hint_processor/cairo_keccak/keccak_hints.rs @@ -375,7 +375,7 @@ mod tests { }, hint_processor_definition::{HintProcessorLogic, HintReference}, }, - types::{exec_scope::ExecutionScopes, relocatable::Relocatable}, + types::relocatable::Relocatable, utils::test_utils::*, vm::vm_core::VirtualMachine, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/ec_utils.rs b/vm/src/hint_processor/builtin_hint_processor/ec_utils.rs index 08f211b5a8..2b8b0e7685 100644 --- a/vm/src/hint_processor/builtin_hint_processor/ec_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/ec_utils.rs @@ -1,5 +1,5 @@ use crate::stdlib::{borrow::Cow, boxed::Box, collections::HashMap, prelude::*}; -use crate::utils::{bigint_to_felt, biguint_to_felt, felt_to_biguint, CAIRO_PRIME}; +use crate::utils::CAIRO_PRIME; use crate::Felt252; use crate::{ hint_processor::{ @@ -62,7 +62,7 @@ pub fn random_ec_point_hint( ) -> Result<(), HintError> { let p = EcPoint::from_var_name("p", vm, ids_data, ap_tracking)?; let q = EcPoint::from_var_name("q", vm, ids_data, ap_tracking)?; - let m = get_integer_from_var_name("m", vm, ids_data, ap_tracking)?; + let m = Cow::Owned(get_integer_from_var_name("m", vm, ids_data, ap_tracking)?); let bytes: Vec = [p.x, p.y, m, q.x, q.y] .iter() .flat_map(|x| x.to_bytes_be()) @@ -109,7 +109,7 @@ pub fn chained_ec_op_random_ec_point_hint( ) -> Result<(), HintError> { let n_elms = get_integer_from_var_name("len", vm, ids_data, ap_tracking)?; if n_elms.is_zero() || n_elms.to_usize().is_none() { - return Err(HintError::InvalidLenValue(Box::new(n_elms.into_owned()))); + return Err(HintError::InvalidLenValue(Box::new(n_elms))); } let n_elms = n_elms.to_usize().unwrap(); let p = EcPoint::from_var_name("p", vm, ids_data, ap_tracking)?; @@ -141,13 +141,13 @@ pub fn recover_y_hint( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - let p_x = get_integer_from_var_name("x", vm, ids_data, ap_tracking)?.into_owned(); + let p_x = get_integer_from_var_name("x", vm, ids_data, ap_tracking)?; let p_addr = get_relocatable_from_var_name("p", vm, ids_data, ap_tracking)?; vm.insert_value(p_addr, p_x)?; - let p_y = biguint_to_felt( - &recover_y(&felt_to_biguint(p_x)) + let p_y = Felt252::from( + &recover_y(&p_x.to_biguint()) .ok_or_else(|| HintError::RecoverYPointNotOnCurve(Box::new(p_x)))?, - )?; + ); vm.insert_value((p_addr + 1)?, p_y)?; Ok(()) } @@ -174,8 +174,8 @@ fn random_ec_point_seeded(seed_bytes: Vec) -> Result<(Felt252, Felt252), Hin if let Some(y) = y { // Conversion from BigUint to BigInt doesnt fail return Ok(( - biguint_to_felt(&x)?, - bigint_to_felt(&(y.to_bigint().unwrap() * y_coef))?, + Felt252::from(&x), + Felt252::from(&(y.to_bigint().unwrap() * y_coef)), )); } } @@ -188,7 +188,7 @@ lazy_static! { 10 ) .unwrap(); - static ref FELT_MAX_HALVED: BigUint = felt_to_biguint(Felt252::MAX) / 2_u32; + static ref FELT_MAX_HALVED: BigUint = Felt252::MAX.to_biguint() / 2_u32; } // Recovers the corresponding y coordinate on the elliptic curve @@ -198,7 +198,7 @@ lazy_static! { fn recover_y(x: &BigUint) -> Option { let y_squared: BigUint = x.modpow(&BigUint::from(3_u32), &CAIRO_PRIME) + ALPHA * x + &*BETA; if is_quad_residue(&y_squared) { - Some(felt_to_biguint(biguint_to_felt(&y_squared).ok()?.sqrt()?)) + Some(Felt252::from(&y_squared).sqrt()?.to_biguint()) } else { None } @@ -220,7 +220,6 @@ mod tests { use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData; use crate::hint_processor::hint_processor_definition::HintProcessorLogic; use crate::relocatable; - use crate::types::exec_scope::ExecutionScopes; use crate::types::relocatable::Relocatable; use num_traits::Zero; diff --git a/vm/src/hint_processor/builtin_hint_processor/field_arithmetic.rs b/vm/src/hint_processor/builtin_hint_processor/field_arithmetic.rs index 6f5430a387..9c4ce28fe3 100644 --- a/vm/src/hint_processor/builtin_hint_processor/field_arithmetic.rs +++ b/vm/src/hint_processor/builtin_hint_processor/field_arithmetic.rs @@ -274,7 +274,6 @@ mod tests { }, hint_processor_definition::HintProcessorLogic, }, - types::exec_scope::ExecutionScopes, utils::test_utils::*, vm::vm_core::VirtualMachine, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/find_element_hint.rs b/vm/src/hint_processor/builtin_hint_processor/find_element_hint.rs index 7837a7ea91..b1be97bb82 100644 --- a/vm/src/hint_processor/builtin_hint_processor/find_element_hint.rs +++ b/vm/src/hint_processor/builtin_hint_processor/find_element_hint.rs @@ -30,9 +30,7 @@ pub fn find_element( .to_usize() .ok_or_else(|| HintError::ValueOutOfRange(Box::new(*elm_size_bigint.as_ref())))?; if elm_size == 0 { - return Err(HintError::ValueOutOfRange(Box::new( - elm_size_bigint.into_owned(), - ))); + return Err(HintError::ValueOutOfRange(Box::new(elm_size_bigint))); } if let Some(find_element_index_value) = find_element_index { @@ -44,7 +42,7 @@ pub fn find_element( if found_key.as_ref() != key.as_ref() { return Err(HintError::InvalidIndex(Box::new(( find_element_index_value, - key.into_owned(), + key, found_key.into_owned(), )))); } @@ -56,13 +54,13 @@ pub fn find_element( if n_elms.as_ref() > find_element_max_size { return Err(HintError::FindElemMaxSize(Box::new(( *find_element_max_size, - n_elms.into_owned(), + n_elms, )))); } } let n_elms_iter: u32 = n_elms .to_u32() - .ok_or_else(|| MathError::Felt252ToI32Conversion(Box::new(n_elms.into_owned())))?; + .ok_or_else(|| MathError::Felt252ToI32Conversion(Box::new(n_elms)))?; for i in 0..n_elms_iter { let iter_key = vm @@ -80,9 +78,7 @@ pub fn find_element( } } - Err(HintError::NoValueForKeyFindElement(Box::new( - key.into_owned(), - ))) + Err(HintError::NoValueForKeyFindElement(Box::new(key))) } } @@ -93,10 +89,10 @@ pub fn search_sorted_lower( ap_tracking: &ApTracking, ) -> Result<(), HintError> { let find_element_max_size = exec_scopes.get::("find_element_max_size"); - let n_elms = *get_integer_from_var_name("n_elms", vm, ids_data, ap_tracking)?; + let n_elms = get_integer_from_var_name("n_elms", vm, ids_data, ap_tracking)?; let rel_array_ptr = get_relocatable_from_var_name("array_ptr", vm, ids_data, ap_tracking)?; - let elm_size = *get_integer_from_var_name("elm_size", vm, ids_data, ap_tracking)?; - let key = *get_integer_from_var_name("key", vm, ids_data, ap_tracking)?; + let elm_size = get_integer_from_var_name("elm_size", vm, ids_data, ap_tracking)?; + let key = get_integer_from_var_name("key", vm, ids_data, ap_tracking)?; if elm_size == Felt252::ZERO { return Err(HintError::ValueOutOfRange(Box::new(elm_size))); @@ -167,7 +163,7 @@ mod tests { vm.segments.add(); } - let addresses = vec![ + let addresses = [ Relocatable::from((1, 0)), Relocatable::from((1, 1)), Relocatable::from((1, 2)), diff --git a/vm/src/hint_processor/builtin_hint_processor/garaga.rs b/vm/src/hint_processor/builtin_hint_processor/garaga.rs index fe4db1830f..aef295c8c2 100644 --- a/vm/src/hint_processor/builtin_hint_processor/garaga.rs +++ b/vm/src/hint_processor/builtin_hint_processor/garaga.rs @@ -29,7 +29,6 @@ mod tests { use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData; use crate::hint_processor::hint_processor_definition::HintProcessorLogic; - use crate::types::exec_scope::ExecutionScopes; use crate::Felt252; use crate::{hint_processor::builtin_hint_processor::hint_code, utils::test_utils::*}; diff --git a/vm/src/hint_processor/builtin_hint_processor/hint_code.rs b/vm/src/hint_processor/builtin_hint_processor/hint_code.rs index 77365943f8..03bab59189 100644 --- a/vm/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/vm/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -694,6 +694,15 @@ x = pack(ids.pt.x, PRIME) y = pack(ids.pt.y, PRIME) value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)"#; +pub const EC_DOUBLE_SLOPE_V4: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA, SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack +from starkware.python.math_utils import ec_double_slope + +# Compute the slope. +x = pack(ids.point.x, SECP256R1_P) +y = pack(ids.point.y, SECP256R1_P) +value = slope = ec_double_slope(point=(x, y), alpha=SECP256R1_ALPHA, p=SECP256R1_P)"#; + pub const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack from starkware.python.math_utils import ec_double_slope @@ -722,7 +731,7 @@ x1 = pack(ids.point1.x, PRIME) y1 = pack(ids.point1.y, PRIME) value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#; -pub const COMPUTE_SLOPE_SECP256R1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack +pub const COMPUTE_SLOPE_SECP256R1_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack from starkware.python.math_utils import line_slope # Compute the slope. @@ -732,6 +741,17 @@ x1 = pack(ids.point1.x, PRIME) y1 = pack(ids.point1.y, PRIME) value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#; +pub const COMPUTE_SLOPE_SECP256R1_V2: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P +from starkware.cairo.common.cairo_secp.secp_utils import pack +from starkware.python.math_utils import line_slope + +# Compute the slope. +x0 = pack(ids.point0.x, PRIME) +y0 = pack(ids.point0.y, PRIME) +x1 = pack(ids.point1.x, PRIME) +y1 = pack(ids.point1.y, PRIME) +value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP256R1_P)"#; + pub const IMPORT_SECP256R1_P: &str = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P"; @@ -1421,3 +1441,12 @@ data = __dict_manager.get_dict(ids.dict_ptr) print( {k: v if isinstance(v, int) else [memory[v + i] for i in range(ids.pointer_size)] for k, v in data.items()} )"#; + +pub const RUN_P_CIRCUIT: &str = "from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner\nassert builtin_runners[\"add_mod_builtin\"].instance_def.batch_size == 1\nassert builtin_runners[\"mul_mod_builtin\"].instance_def.batch_size == 1\n\nModBuiltinRunner.fill_memory(\n memory=memory,\n add_mod=(ids.add_mod_ptr.address_, builtin_runners[\"add_mod_builtin\"], ids.add_mod_n),\n mul_mod=(ids.mul_mod_ptr.address_, builtin_runners[\"mul_mod_builtin\"], ids.mul_mod_n),\n)"; + +pub const RUN_P_CIRCUIT_WITH_LARGE_BATCH_SIZE: &str = "from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner\nassert builtin_runners[\"add_mod_builtin\"].instance_def.batch_size == ids.BATCH_SIZE\nassert builtin_runners[\"mul_mod_builtin\"].instance_def.batch_size == ids.BATCH_SIZE\n\nModBuiltinRunner.fill_memory(\n memory=memory,\n add_mod=(ids.add_mod_ptr.address_, builtin_runners[\"add_mod_builtin\"], ids.add_mod_n),\n mul_mod=(ids.mul_mod_ptr.address_, builtin_runners[\"mul_mod_builtin\"], ids.mul_mod_n),\n)"; + +pub const NONDET_ELEMENTS_OVER_TEN: &str = + "memory[ap] = to_felt_or_relocatable(ids.elements_end - ids.elements >= 10)"; +pub const NONDET_ELEMENTS_OVER_TWO: &str = + "memory[ap] = to_felt_or_relocatable(ids.elements_end - ids.elements >= 2)"; diff --git a/vm/src/hint_processor/builtin_hint_processor/hint_utils.rs b/vm/src/hint_processor/builtin_hint_processor/hint_utils.rs index 3a1808b5a0..07eef72a88 100644 --- a/vm/src/hint_processor/builtin_hint_processor/hint_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/hint_utils.rs @@ -1,4 +1,4 @@ -use crate::stdlib::{borrow::Cow, boxed::Box, collections::HashMap, prelude::*}; +use crate::stdlib::{boxed::Box, collections::HashMap, prelude::*}; use crate::Felt252; @@ -83,12 +83,12 @@ pub fn get_relocatable_from_var_name( //Gets the value of a variable name. //If the value is an MaybeRelocatable::Int(Bigint) return &Bigint //else raises Err -pub fn get_integer_from_var_name<'a>( - var_name: &'a str, - vm: &'a VirtualMachine, - ids_data: &'a HashMap, +pub fn get_integer_from_var_name( + var_name: &str, + vm: &VirtualMachine, + ids_data: &HashMap, ap_tracking: &ApTracking, -) -> Result, HintError> { +) -> Result { let reference = get_reference_from_var_name(var_name, ids_data)?; match get_integer_from_reference(vm, reference, ap_tracking) { // Map internal errors into more descriptive variants @@ -260,7 +260,7 @@ mod tests { assert_matches!( get_integer_from_var_name("value", &vm, &ids_data, &ApTracking::new()), - Ok(Cow::Borrowed(x)) if x == &Felt252::from(1) + Ok(x) if x == Felt252::from(1) ); } diff --git a/vm/src/hint_processor/builtin_hint_processor/keccak_utils.rs b/vm/src/hint_processor/builtin_hint_processor/keccak_utils.rs index 8a22530f9b..69b593e36f 100644 --- a/vm/src/hint_processor/builtin_hint_processor/keccak_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/keccak_utils.rs @@ -56,7 +56,7 @@ pub fn unsafe_keccak( if let Ok(keccak_max_size) = exec_scopes.get::("__keccak_max_size") { if length.as_ref() > &keccak_max_size { return Err(HintError::KeccakMaxSize(Box::new(( - length.into_owned(), + length, keccak_max_size, )))); } @@ -71,7 +71,7 @@ pub fn unsafe_keccak( // transform to u64 to make ranges cleaner in the for loop below let u64_length = length .to_u64() - .ok_or_else(|| HintError::InvalidKeccakInputLength(Box::new(length.into_owned())))?; + .ok_or_else(|| HintError::InvalidKeccakInputLength(Box::new(length)))?; const ZEROES: [u8; 32] = [0u8; 32]; let mut keccak_input = Vec::new(); @@ -243,9 +243,8 @@ pub fn split_n_bytes( ) -> Result<(), HintError> { let n_bytes = get_integer_from_var_name("n_bytes", vm, ids_data, ap_tracking).and_then(|x| { - x.to_u64().ok_or_else(|| { - HintError::Math(MathError::Felt252ToU64Conversion(Box::new(x.into_owned()))) - }) + x.to_u64() + .ok_or_else(|| HintError::Math(MathError::Felt252ToU64Conversion(Box::new(x)))) })?; let bytes_in_word = constants .get(BYTES_IN_WORD) @@ -298,7 +297,6 @@ mod tests { }, hint_processor_definition::{HintProcessorLogic, HintReference}, }, - types::exec_scope::ExecutionScopes, utils::test_utils::*, vm::vm_core::VirtualMachine, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/math_utils.rs b/vm/src/hint_processor/builtin_hint_processor/math_utils.rs index 1265c8ed8f..a0fa71dddb 100644 --- a/vm/src/hint_processor/builtin_hint_processor/math_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/math_utils.rs @@ -3,7 +3,6 @@ use crate::{ math_utils::signed_felt, stdlib::{boxed::Box, collections::HashMap, prelude::*}, types::errors::math_errors::MathError, - utils::{bigint_to_felt, biguint_to_felt, felt_to_bigint, felt_to_biguint}, }; use lazy_static::lazy_static; use num_traits::{Signed, Zero}; @@ -46,13 +45,9 @@ pub fn is_nn( ap_tracking: &ApTracking, ) -> Result<(), HintError> { let a = get_integer_from_var_name("a", vm, ids_data, ap_tracking)?; - let range_check_builtin = vm.get_range_check_builtin()?; + let range_check_bound = vm.get_range_check_builtin()?.bound(); //Main logic (assert a is not negative and within the expected range) - let value = match &range_check_builtin._bound { - Some(bound) if a.as_ref() >= bound => Felt252::ONE, - _ => Felt252::ZERO, - }; - insert_value_into_ap(vm, value) + insert_value_into_ap(vm, Felt252::from(a.as_ref() >= range_check_bound)) } //Implements hint: memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1 @@ -63,15 +58,9 @@ pub fn is_nn_out_of_range( ) -> Result<(), HintError> { let a = get_integer_from_var_name("a", vm, ids_data, ap_tracking)?; let a = a.as_ref(); - let range_check_builtin = vm.get_range_check_builtin()?; + let range_check_bound = vm.get_range_check_builtin()?.bound(); //Main logic (assert a is not negative and within the expected range) - //let value = if (-a - 1usize).mod_floor(vm.get_prime()) < range_check_builtin._bound { - let value = match &range_check_builtin._bound { - Some(bound) if Felt252::ZERO - (a + 1u64) < *bound => Felt252::ZERO, - None => Felt252::ZERO, - _ => Felt252::ONE, - }; - insert_value_into_ap(vm, value) + insert_value_into_ap(vm, Felt252::from(-(a + 1) >= *range_check_bound)) } /* Implements hint:from starkware.cairo.common.math_utils import assert_integer %{ @@ -112,8 +101,8 @@ pub fn assert_le_felt( let prime_over_2_high = constants .get(PRIME_OVER_2_HIGH) .ok_or_else(|| HintError::MissingConstant(Box::new(PRIME_OVER_2_HIGH)))?; - let a = felt_to_biguint(*get_integer_from_var_name("a", vm, ids_data, ap_tracking)?); - let b = felt_to_biguint(*get_integer_from_var_name("b", vm, ids_data, ap_tracking)?); + let a = get_integer_from_var_name("a", vm, ids_data, ap_tracking)?.to_biguint(); + let b = get_integer_from_var_name("b", vm, ids_data, ap_tracking)?.to_biguint(); let range_check_ptr = get_ptr_from_var_name("range_check_ptr", vm, ids_data, ap_tracking)?; // TODO: use UnsignedInteger for this @@ -122,8 +111,8 @@ pub fn assert_le_felt( if a > b { return Err(HintError::NonLeFelt252(Box::new(( - biguint_to_felt(&a)?, - biguint_to_felt(&b)?, + Felt252::from(&a), + Felt252::from(&b), )))); } @@ -134,23 +123,23 @@ pub fn assert_le_felt( // TODO: I believe this check can be removed if lengths_and_indices[0].0 > &prime_div3 || lengths_and_indices[1].0 > &prime_div2 { return Err(HintError::ArcTooBig(Box::new(( - biguint_to_felt(&lengths_and_indices[0].0.clone())?, - biguint_to_felt(&prime_div2)?, - biguint_to_felt(&lengths_and_indices[1].0.clone())?, - biguint_to_felt(&prime_div3)?, + Felt252::from(&lengths_and_indices[0].0.clone()), + Felt252::from(&prime_div2), + Felt252::from(&lengths_and_indices[1].0.clone()), + Felt252::from(&prime_div3), )))); } let excluded = lengths_and_indices[2].1; exec_scopes.assign_or_update_variable("excluded", any_box!(Felt252::from(excluded))); - let (q_0, r_0) = (lengths_and_indices[0].0).div_mod_floor(&felt_to_biguint(*prime_over_3_high)); - let (q_1, r_1) = (lengths_and_indices[1].0).div_mod_floor(&felt_to_biguint(*prime_over_2_high)); + let (q_0, r_0) = (lengths_and_indices[0].0).div_mod_floor(&prime_over_3_high.to_biguint()); + let (q_1, r_1) = (lengths_and_indices[1].0).div_mod_floor(&prime_over_2_high.to_biguint()); - vm.insert_value(range_check_ptr, biguint_to_felt(&r_0)?)?; - vm.insert_value((range_check_ptr + 1_i32)?, biguint_to_felt(&q_0)?)?; - vm.insert_value((range_check_ptr + 2_i32)?, biguint_to_felt(&r_1)?)?; - vm.insert_value((range_check_ptr + 3_i32)?, biguint_to_felt(&q_1)?)?; + vm.insert_value(range_check_ptr, Felt252::from(&r_0))?; + vm.insert_value((range_check_ptr + 1_i32)?, Felt252::from(&q_0))?; + vm.insert_value((range_check_ptr + 2_i32)?, Felt252::from(&r_1))?; + vm.insert_value((range_check_ptr + 3_i32)?, Felt252::from(&q_1))?; Ok(()) } @@ -162,11 +151,8 @@ pub fn assert_le_felt_v_0_6( let a = &get_integer_from_var_name("a", vm, ids_data, ap_tracking)?; let b = &get_integer_from_var_name("b", vm, ids_data, ap_tracking)?; - if a.as_ref() > b.as_ref() { - return Err(HintError::NonLeFelt252(Box::new(( - a.clone().into_owned(), - b.clone().into_owned(), - )))); + if a > b { + return Err(HintError::NonLeFelt252(Box::new((*a, *b)))); } Ok(()) } @@ -179,15 +165,11 @@ pub fn assert_le_felt_v_0_8( let a = &get_integer_from_var_name("a", vm, ids_data, ap_tracking)?; let b = &get_integer_from_var_name("b", vm, ids_data, ap_tracking)?; - if a.as_ref() > b.as_ref() { - return Err(HintError::NonLeFelt252(Box::new(( - a.clone().into_owned(), - b.clone().into_owned(), - )))); + if a > b { + return Err(HintError::NonLeFelt252(Box::new((*a, *b)))); } - let bound = vm.get_range_check_builtin()?._bound.unwrap_or_default(); - let small_inputs = - Felt252::from((a.as_ref() < &bound && b.as_ref() - a.as_ref() < bound) as u8); + let bound = vm.get_range_check_builtin()?.bound(); + let small_inputs = Felt252::from((a < bound && b - a < *bound) as u8); insert_value_from_var_name("small_inputs", small_inputs, vm, ids_data, ap_tracking) } @@ -300,11 +282,10 @@ pub fn assert_nn( let range_check_builtin = vm.get_range_check_builtin()?; // assert 0 <= ids.a % PRIME < range_check_builtin.bound // as prime > 0, a % prime will always be > 0 - match &range_check_builtin._bound { - Some(bound) if a.as_ref() >= bound => { - Err(HintError::AssertNNValueOutOfRange(Box::new(a.into_owned()))) - } - _ => Ok(()), + if a.as_ref() >= range_check_builtin.bound() { + Err(HintError::AssertNNValueOutOfRange(Box::new(a))) + } else { + Ok(()) } } @@ -322,7 +303,7 @@ pub fn assert_not_zero( let value = get_integer_from_var_name("value", vm, ids_data, ap_tracking)?; if value.is_zero() { return Err(HintError::AssertNotZero(Box::new(( - value.into_owned(), + value, crate::utils::PRIME_STR.to_string(), )))); }; @@ -376,20 +357,15 @@ pub fn is_positive( ap_tracking: &ApTracking, ) -> Result<(), HintError> { let value = get_integer_from_var_name("value", vm, ids_data, ap_tracking)?; - let value_as_int = signed_felt(*value); + let value_as_int = signed_felt(value); let range_check_builtin = vm.get_range_check_builtin()?; // Avoid using abs so we don't allocate a new BigInt let (sign, abs_value) = value_as_int.into_parts(); //Main logic (assert a is positive) - match &range_check_builtin._bound { - Some(bound) if abs_value > felt_to_biguint(*bound) => { - return Err(HintError::ValueOutsideValidRange(Box::new( - value.into_owned(), - ))) - } - _ => {} - }; + if abs_value >= range_check_builtin.bound().to_biguint() { + return Err(HintError::ValueOutsideValidRange(Box::new(value))); + } let result = Felt252::from((sign == Sign::Plus) as u8); insert_value_from_var_name("is_positive", result, vm, ids_data, ap_tracking) @@ -448,16 +424,13 @@ pub fn sqrt( ) -> Result<(), HintError> { let mod_value = get_integer_from_var_name("value", vm, ids_data, ap_tracking)?; //This is equal to mod_value > Felt252::from(2).pow(250) - if *mod_value > pow2_const(250) { - return Err(HintError::ValueOutside250BitRange(Box::new( - mod_value.into_owned(), - ))); + if mod_value > pow2_const(250) { + return Err(HintError::ValueOutside250BitRange(Box::new(mod_value))); //This is equal to mod_value > bigint!(2).pow(250) } - #[allow(deprecated)] insert_value_from_var_name( "root", - biguint_to_felt(&isqrt(&felt_to_biguint(*mod_value))?)?, + Felt252::from(&isqrt(&mod_value.to_biguint())?), vm, ids_data, ap_tracking, @@ -475,38 +448,35 @@ pub fn signed_div_rem( let bound = get_integer_from_var_name("bound", vm, ids_data, ap_tracking)?; let builtin = vm.get_range_check_builtin()?; - let builtin_bound = &builtin._bound.unwrap_or(Felt252::MAX); + let builtin_bound = builtin.bound(); if div.is_zero() || div.as_ref() > &div_prime_by_bound(*builtin_bound)? { - return Err(HintError::OutOfValidRange(Box::new(( - div.into_owned(), - *builtin_bound, - )))); + return Err(HintError::OutOfValidRange(Box::new((div, *builtin_bound)))); } let builtin_bound_div_2 = builtin_bound.field_div(&Felt252::TWO.try_into().unwrap()); - if *bound > builtin_bound_div_2 { + if bound > builtin_bound_div_2 { return Err(HintError::OutOfValidRange(Box::new(( - bound.into_owned(), + bound, builtin_bound_div_2, )))); } let int_value = signed_felt(*value); - let int_div = felt_to_bigint(*div); - let int_bound = felt_to_bigint(*bound); + let int_div = div.to_bigint(); + let int_bound = bound.to_bigint(); let (q, r) = int_value.div_mod_floor(&int_div); if int_bound.abs() < q.abs() { return Err(HintError::OutOfValidRange(Box::new(( - bigint_to_felt(&q)?, - bound.into_owned(), + Felt252::from(&q), + bound, )))); } let biased_q = q + int_bound; - insert_value_from_var_name("r", bigint_to_felt(&r)?, vm, ids_data, ap_tracking)?; + insert_value_from_var_name("r", Felt252::from(&r), vm, ids_data, ap_tracking)?; insert_value_from_var_name( "biased_q", - bigint_to_felt(&biased_q)?, + Felt252::from(&biased_q), vm, ids_data, ap_tracking, @@ -529,28 +499,14 @@ pub fn unsigned_div_rem( ) -> Result<(), HintError> { let div = get_integer_from_var_name("div", vm, ids_data, ap_tracking)?; let value = get_integer_from_var_name("value", vm, ids_data, ap_tracking)?; - let builtin = vm.get_range_check_builtin()?; + let builtin_bound = vm.get_range_check_builtin()?.bound(); // Main logic - match &builtin._bound { - Some(builtin_bound) - if div.is_zero() || div.as_ref() > &div_prime_by_bound(*builtin_bound)? => - { - return Err(HintError::OutOfValidRange(Box::new(( - div.into_owned(), - *builtin_bound, - )))); - } - None if div.is_zero() => { - return Err(HintError::OutOfValidRange(Box::new(( - div.into_owned(), - Felt252::ZERO - Felt252::ONE, - )))); - } - _ => {} + if div.is_zero() || div.as_ref() > &div_prime_by_bound(*builtin_bound)? { + return Err(HintError::OutOfValidRange(Box::new((div, *builtin_bound)))); } - let (q, r) = value.div_rem(&(*div).try_into().map_err(|_| MathError::DividedByZero)?); + let (q, r) = value.div_rem(&(div).try_into().map_err(|_| MathError::DividedByZero)?); insert_value_from_var_name("r", r, vm, ids_data, ap_tracking)?; insert_value_from_var_name("q", q, vm, ids_data, ap_tracking) } @@ -576,12 +532,12 @@ pub fn assert_250_bit( let shift = constants .get(SHIFT) .map_or_else(|| get_constant_from_var_name("SHIFT", constants), Ok)?; - let value = bigint_to_felt(&signed_felt(*get_integer_from_var_name( + let value = Felt252::from(&signed_felt(get_integer_from_var_name( "value", vm, ids_data, ap_tracking, - )?))?; + )?)); //Main logic if &value > upper_bound { return Err(HintError::ValueOutside250BitRange(Box::new(value))); @@ -625,11 +581,10 @@ pub fn is_addr_bounded( ) -> Result<(), HintError> { let addr = get_integer_from_var_name("addr", vm, ids_data, ap_tracking)?; - let addr_bound = felt_to_biguint( - *constants - .get(ADDR_BOUND) - .ok_or_else(|| HintError::MissingConstant(Box::new(ADDR_BOUND)))?, - ); + let addr_bound = constants + .get(ADDR_BOUND) + .ok_or_else(|| HintError::MissingConstant(Box::new(ADDR_BOUND)))? + .to_biguint(); let lower_bound = BigUint::one() << 250_usize; let upper_bound = BigUint::one() << 251_usize; @@ -650,7 +605,7 @@ pub fn is_addr_bounded( } // Main logic: ids.is_small = 1 if ids.addr < ADDR_BOUND else 0 - let is_small = Felt252::from((addr.as_ref() < &biguint_to_felt(&addr_bound)?) as u8); + let is_small = Felt252::from((addr.as_ref() < &Felt252::from(&addr_bound)) as u8); insert_value_from_var_name("is_small", is_small, vm, ids_data, ap_tracking) } @@ -678,10 +633,7 @@ pub fn assert_lt_felt( // assert (ids.a % PRIME) < (ids.b % PRIME), \ // f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.' if a >= b { - return Err(HintError::AssertLtFelt252(Box::new(( - a.into_owned(), - b.into_owned(), - )))); + return Err(HintError::AssertLtFelt252(Box::new((a, b)))); }; Ok(()) } @@ -691,7 +643,7 @@ pub fn is_quad_residue( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - let x = *get_integer_from_var_name("x", vm, ids_data, ap_tracking)?; + let x = get_integer_from_var_name("x", vm, ids_data, ap_tracking)?; if x.is_zero() || x == Felt252::ONE { insert_value_from_var_name("y", *x.as_ref(), vm, ids_data, ap_tracking) @@ -714,9 +666,8 @@ pub fn is_quad_residue( fn div_prime_by_bound(bound: Felt252) -> Result { let prime: &BigUint = &CAIRO_PRIME; - #[allow(deprecated)] - let limit = prime / felt_to_biguint(bound); - Ok(biguint_to_felt(&limit)?) + let limit = prime / bound.to_biguint(); + Ok(Felt252::from(&limit)) } fn prime_div_constant(bound: u32) -> Result { @@ -780,7 +731,7 @@ pub fn split_xx( ) -> Result<(), HintError> { let xx = Uint256::from_var_name("xx", vm, ids_data, ap_tracking)?; let x_addr = get_relocatable_from_var_name("x", vm, ids_data, ap_tracking)?; - let xx: BigUint = felt_to_biguint(*xx.low) + felt_to_biguint(*xx.high * pow2_const(128)); + let xx: BigUint = xx.low.to_biguint() + (*xx.high * pow2_const(128)).to_biguint(); let mut x = xx.modpow( &(&*SPLIT_XX_PRIME + 3_u32).div_floor(&BigUint::from(8_u32)), &SPLIT_XX_PRIME, @@ -794,9 +745,9 @@ pub fn split_xx( vm.insert_value( x_addr, - biguint_to_felt(&(&x & &BigUint::from(u128::max_value())))?, + Felt252::from(&(&x & &BigUint::from(u128::max_value()))), )?; - vm.insert_value((x_addr + 1)?, biguint_to_felt(&(x >> 128_u32))?)?; + vm.insert_value((x_addr + 1)?, Felt252::from(&(x >> 128_u32)))?; Ok(()) } @@ -1833,9 +1784,9 @@ mod tests { //Initialize fp vm.run_context.fp = 6; //Insert ids into memory - let bound = vm.get_range_check_builtin().unwrap()._bound; + let bound = vm.get_range_check_builtin().unwrap().bound(); vm.segments = segments![((1, 3), (5)), ((1, 4), 10)]; - vm.insert_value((1, 5).into(), bound.unwrap()).unwrap(); + vm.insert_value((1, 5).into(), bound).unwrap(); //Create ids let ids_data = ids_data!["r", "biased_q", "range_check_ptr", "div", "value", "bound"]; //Execute the hint @@ -1843,7 +1794,7 @@ mod tests { assert_matches!( run_hint!(vm, ids_data, hint_code), Err(HintError::OutOfValidRange(bx)) - if *bx == (bound.unwrap(), builtin_bound.field_div(&Felt252::TWO.try_into().unwrap())) + if *bx == (*bound, builtin_bound.field_div(&Felt252::TWO.try_into().unwrap())) ) } diff --git a/vm/src/hint_processor/builtin_hint_processor/memcpy_hint_utils.rs b/vm/src/hint_processor/builtin_hint_processor/memcpy_hint_utils.rs index 4709545bbc..2e9b4c55e4 100644 --- a/vm/src/hint_processor/builtin_hint_processor/memcpy_hint_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/memcpy_hint_utils.rs @@ -36,8 +36,7 @@ pub fn memcpy_enter_scope( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - let len: Box = - Box::new(get_integer_from_var_name("len", vm, ids_data, ap_tracking)?.into_owned()); + let len: Box = Box::new(get_integer_from_var_name("len", vm, ids_data, ap_tracking)?); exec_scopes.enter_scope(HashMap::from([(String::from("n"), len)])); Ok(()) } diff --git a/vm/src/hint_processor/builtin_hint_processor/memset_utils.rs b/vm/src/hint_processor/builtin_hint_processor/memset_utils.rs index 4ad693968c..066884f920 100644 --- a/vm/src/hint_processor/builtin_hint_processor/memset_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/memset_utils.rs @@ -21,8 +21,7 @@ pub fn memset_enter_scope( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - let n: Box = - Box::new(get_integer_from_var_name("n", vm, ids_data, ap_tracking)?.into_owned()); + let n: Box = Box::new(get_integer_from_var_name("n", vm, ids_data, ap_tracking)?); exec_scopes.enter_scope(HashMap::from([(String::from("n"), n)])); Ok(()) } diff --git a/vm/src/hint_processor/builtin_hint_processor/mod.rs b/vm/src/hint_processor/builtin_hint_processor/mod.rs index 8236f8a866..a890ad6ebe 100644 --- a/vm/src/hint_processor/builtin_hint_processor/mod.rs +++ b/vm/src/hint_processor/builtin_hint_processor/mod.rs @@ -16,6 +16,7 @@ pub mod keccak_utils; pub mod math_utils; pub mod memcpy_hint_utils; pub mod memset_utils; +mod mod_circuit; pub mod poseidon_utils; pub mod pow_utils; #[cfg(feature = "print")] diff --git a/vm/src/hint_processor/builtin_hint_processor/mod_circuit.rs b/vm/src/hint_processor/builtin_hint_processor/mod_circuit.rs new file mode 100644 index 0000000000..22fbc57d19 --- /dev/null +++ b/vm/src/hint_processor/builtin_hint_processor/mod_circuit.rs @@ -0,0 +1,93 @@ +use crate::stdlib::prelude::String; +use crate::{ + hint_processor::hint_processor_definition::HintReference, + serde::deserialize_program::ApTracking, + stdlib::collections::HashMap, + vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, + Felt252, +}; +#[cfg(not(feature = "mod_builtin"))] +use crate::{stdlib::prelude::Box, types::errors::math_errors::MathError}; +use num_traits::ToPrimitive; + +use super::hint_utils::{get_integer_from_var_name, get_ptr_from_var_name}; +/* Implements Hint: +%{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) +%} +*/ +pub fn run_p_mod_circuit( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + run_p_mod_circuit_inner(vm, ids_data, ap_tracking, 1) +} + +/* Implements Hint: + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == ids.BATCH_SIZE + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == ids.BATCH_SIZE + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) + %} +*/ +#[allow(unused_variables)] +pub fn run_p_mod_circuit_with_large_batch_size( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, + constants: &HashMap, +) -> Result<(), HintError> { + #[cfg(not(feature = "mod_builtin"))] + const LARGE_BATCH_SIZE_PATH: &str = + "starkware.cairo.common.modulo.run_mod_p_circuit_with_large_batch_size.BATCH_SIZE"; + #[cfg(not(feature = "mod_builtin"))] + let batch_size = constants + .get(LARGE_BATCH_SIZE_PATH) + .ok_or_else(|| HintError::MissingConstant(Box::new(LARGE_BATCH_SIZE_PATH)))?; + #[cfg(not(feature = "mod_builtin"))] + let batch_size = batch_size + .to_usize() + .ok_or_else(|| MathError::Felt252ToUsizeConversion(Box::new(*batch_size)))?; + #[cfg(feature = "mod_builtin")] + let batch_size = 8; // Hardcoded here as we are not importing from the common lib yet + run_p_mod_circuit_inner(vm, ids_data, ap_tracking, batch_size) +} + +pub fn run_p_mod_circuit_inner( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, + batch_size: usize, +) -> Result<(), HintError> { + let add_mod_ptr = get_ptr_from_var_name("add_mod_ptr", vm, ids_data, ap_tracking)?; + let mul_mod_ptr = get_ptr_from_var_name("mul_mod_ptr", vm, ids_data, ap_tracking)?; + let add_mod_n = get_integer_from_var_name("add_mod_n", vm, ids_data, ap_tracking)? + .as_ref() + .to_usize() + .unwrap(); + let mul_mod_n = get_integer_from_var_name("mul_mod_n", vm, ids_data, ap_tracking)? + .as_ref() + .to_usize() + .unwrap(); + vm.mod_builtin_fill_memory( + Some((add_mod_ptr, add_mod_n)), + Some((mul_mod_ptr, mul_mod_n)), + Some(batch_size), + ) + .map_err(HintError::Internal) +} diff --git a/vm/src/hint_processor/builtin_hint_processor/poseidon_utils.rs b/vm/src/hint_processor/builtin_hint_processor/poseidon_utils.rs index 7ba388fa7b..1cc19daa4d 100644 --- a/vm/src/hint_processor/builtin_hint_processor/poseidon_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/poseidon_utils.rs @@ -8,7 +8,7 @@ use crate::{ vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, }; -use super::hint_utils::{get_integer_from_var_name, insert_value_into_ap}; +use super::hint_utils::{get_integer_from_var_name, get_ptr_from_var_name, insert_value_into_ap}; use num_traits::ToPrimitive; // Implements hint: "memory[ap] = to_felt_or_relocatable(ids.n >= 10)" @@ -37,6 +37,19 @@ pub fn n_greater_than_2( insert_value_into_ap(vm, value) } +// Implements hint: "memory[ap] = to_felt_or_relocatable(ids.elements_end - ids.elements >= x)" +pub fn elements_over_x( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, + x: usize, +) -> Result<(), HintError> { + let elements_end = get_ptr_from_var_name("elements_end", vm, ids_data, ap_tracking)?; + let elements = get_ptr_from_var_name("elements", vm, ids_data, ap_tracking)?; + let value = Felt252::from(((elements_end - elements)? >= x) as usize); + insert_value_into_ap(vm, value) +} + #[cfg(test)] mod tests { use crate::any_box; @@ -44,8 +57,6 @@ mod tests { use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData; use crate::hint_processor::hint_processor_definition::HintProcessorLogic; use crate::hint_processor::hint_processor_definition::HintReference; - use crate::stdlib::collections::HashMap; - use crate::types::exec_scope::ExecutionScopes; use crate::vm::vm_core::VirtualMachine; use crate::{hint_processor::builtin_hint_processor::hint_code, utils::test_utils::*}; diff --git a/vm/src/hint_processor/builtin_hint_processor/pow_utils.rs b/vm/src/hint_processor/builtin_hint_processor/pow_utils.rs index a749f4b896..0a31277a18 100644 --- a/vm/src/hint_processor/builtin_hint_processor/pow_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/pow_utils.rs @@ -45,7 +45,7 @@ mod tests { builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData, hint_processor_definition::HintProcessorLogic, }, - types::{exec_scope::ExecutionScopes, relocatable::MaybeRelocatable}, + types::relocatable::MaybeRelocatable, utils::test_utils::*, vm::{errors::memory_errors::MemoryError, vm_core::VirtualMachine}, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/print.rs b/vm/src/hint_processor/builtin_hint_processor/print.rs index a73f8e8950..12a3e2c1df 100644 --- a/vm/src/hint_processor/builtin_hint_processor/print.rs +++ b/vm/src/hint_processor/builtin_hint_processor/print.rs @@ -12,7 +12,6 @@ use crate::stdlib::collections::HashMap; use crate::types::exec_scope::ExecutionScopes; use crate::types::relocatable::MaybeRelocatable; -use crate::utils::felt_to_bigint; use crate::vm::errors::hint_errors::HintError; use crate::{ hint_processor::hint_processor_definition::HintReference, vm::vm_core::VirtualMachine, @@ -34,7 +33,7 @@ fn print_name( ap_tracking: &ApTracking, ) -> Result<(), HintError> { let name = get_integer_from_var_name("name", vm, ids_data, ap_tracking)?; - let name = String::from_utf8(felt_to_bigint(*name.as_ref()).to_signed_bytes_be()) + let name = String::from_utf8(name.as_ref().to_bigint().to_signed_bytes_be()) .map_err(|err| HintError::CustomHint(err.to_string().into_boxed_str()))?; println!("{name}"); Ok(()) diff --git a/vm/src/hint_processor/builtin_hint_processor/secp/bigint_utils.rs b/vm/src/hint_processor/builtin_hint_processor/secp/bigint_utils.rs index c0e4a6d07a..5b32f4e691 100644 --- a/vm/src/hint_processor/builtin_hint_processor/secp/bigint_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/secp/bigint_utils.rs @@ -3,8 +3,6 @@ use core::ops::Shl; use crate::hint_processor::builtin_hint_processor::uint_utils::{pack, split}; use crate::math_utils::signed_felt; use crate::stdlib::{borrow::Cow, boxed::Box, collections::HashMap, prelude::*}; -use crate::types::errors::math_errors::MathError; -use crate::utils::biguint_to_felt; use crate::Felt252; use crate::{ hint_processor::{ @@ -130,8 +128,8 @@ pub fn nondet_bigint3( .ok_or(HintError::BigIntToBigUintFail)?; let arg: Vec = bigint3_split(&value)? .into_iter() - .map(|ref n| biguint_to_felt(n).map(MaybeRelocatable::from)) - .collect::, MathError>>()?; + .map(|ref n| Felt252::from(n).into()) + .collect::>(); vm.write_arg(res_reloc, &arg).map_err(HintError::Memory)?; Ok(()) } diff --git a/vm/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs b/vm/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs index 700c5778ea..fdafd49e07 100644 --- a/vm/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs @@ -1,4 +1,3 @@ -use crate::utils::{biguint_to_felt, felt_to_biguint}; use crate::Felt252; use crate::{ hint_processor::{ @@ -199,6 +198,7 @@ pub fn compute_slope_and_assing_secp_p( ap_tracking, point0_alias, point1_alias, + "SECP_P", ) } @@ -209,13 +209,14 @@ pub fn compute_slope( ap_tracking: &ApTracking, point0_alias: &str, point1_alias: &str, + secp_p_name: &str, ) -> Result<(), HintError> { //ids.point0 let point0 = EcPoint::from_var_name(point0_alias, vm, ids_data, ap_tracking)?; //ids.point1 let point1 = EcPoint::from_var_name(point1_alias, vm, ids_data, ap_tracking)?; - let secp_p: BigInt = exec_scopes.get("SECP_P")?; + let secp_p: BigInt = exec_scopes.get(secp_p_name)?; let value = line_slope( &(point0.x.pack86(), point0.y.pack86()), @@ -503,7 +504,7 @@ pub fn n_pair_bits( return Err(HintError::NPairBitsTooLowM); } - let (scalar_v, scalar_u) = (felt_to_biguint(*scalar_v), felt_to_biguint(*scalar_u)); + let (scalar_v, scalar_u) = (scalar_v.to_biguint(), scalar_u.to_biguint()); // Each step, fetches the bits in mth position for v and u, // and appends them to the accumulator. i.e: @@ -512,7 +513,7 @@ pub fn n_pair_bits( // 1010101__ -> 101010110 let get_bit = |x: &BigUint, i| m.checked_sub(i).map(|i| x.bit(i.into())).unwrap_or(false) as u32; - let res: Felt252 = biguint_to_felt( + let res = Felt252::from( &(0..number_of_pairs) .map(|i| { // This code is definitely verbose, but it's the only way I found to avoid a `panic` @@ -527,7 +528,7 @@ pub fn n_pair_bits( acc += x; acc }), - )?; + ); /* ids.quad_bit = ( 8 * ((ids.scalar_v >> ids.m) & 1) diff --git a/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs b/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs index 8f34b1bead..fb620f6eab 100644 --- a/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs @@ -1,4 +1,3 @@ -use crate::utils::bigint_to_felt; use crate::Felt252; use crate::{ hint_processor::{ @@ -42,7 +41,7 @@ pub fn verify_zero( return Err(HintError::SecpVerifyZero(Box::new(val))); } - insert_value_from_var_name("q", bigint_to_felt(&q)?, vm, ids_data, ap_tracking) + insert_value_from_var_name("q", Felt252::from(&q), vm, ids_data, ap_tracking) } /* @@ -68,7 +67,7 @@ pub fn verify_zero_with_external_const( return Err(HintError::SecpVerifyZero(Box::new(val))); } - insert_value_from_var_name("q", bigint_to_felt(&q)?, vm, ids_data, ap_tracking) + insert_value_from_var_name("q", Felt252::from(&q), vm, ids_data, ap_tracking) } /* diff --git a/vm/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs b/vm/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs index 7f34ea4436..4457c975b3 100644 --- a/vm/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs @@ -106,20 +106,17 @@ mod tests { constants.insert(BASE_86.to_string(), crate::math_utils::pow2_const(86)); let array_1 = bigint3_split(&BigUint::zero()); - #[allow(deprecated)] let array_2 = bigint3_split( &bigint!(999992) .to_biguint() .expect("Couldn't convert to BigUint"), ); - #[allow(deprecated)] let array_3 = bigint3_split( &bigint_str!("7737125245533626718119526477371252455336267181195264773712524553362") .to_biguint() .expect("Couldn't convert to BigUint"), ); //TODO, Check SecpSplitutOfRange limit - #[allow(deprecated)] let array_4 = bigint3_split( &bigint_str!( "773712524553362671811952647737125245533626718119526477371252455336267181195264" diff --git a/vm/src/hint_processor/builtin_hint_processor/secp/signature.rs b/vm/src/hint_processor/builtin_hint_processor/secp/signature.rs index f8000d465b..57d72b5bba 100644 --- a/vm/src/hint_processor/builtin_hint_processor/secp/signature.rs +++ b/vm/src/hint_processor/builtin_hint_processor/secp/signature.rs @@ -1,4 +1,3 @@ -use crate::utils::{felt_to_bigint, felt_to_biguint}; use crate::Felt252; use crate::{ any_box, @@ -110,12 +109,10 @@ pub fn get_point_from_x( constants: &HashMap, ) -> Result<(), HintError> { exec_scopes.insert_value("SECP_P", SECP_P.clone()); - #[allow(deprecated)] - let beta = felt_to_bigint( - *constants - .get(BETA) - .ok_or_else(|| HintError::MissingConstant(Box::new(BETA)))?, - ); + let beta = constants + .get(BETA) + .ok_or_else(|| HintError::MissingConstant(Box::new(BETA)))? + .to_bigint(); let x_cube_int = Uint384::from_var_name("x_cube", vm, ids_data, ap_tracking)? .pack86() @@ -124,8 +121,7 @@ pub fn get_point_from_x( // Divide by 4 let mut y = y_cube_int.modpow(&(&*SECP_P + 1_u32).shr(2_u32), &SECP_P); - #[allow(deprecated)] - let v = felt_to_biguint(*get_integer_from_var_name("v", vm, ids_data, ap_tracking)?); + let v = get_integer_from_var_name("v", vm, ids_data, ap_tracking)?.to_bigint(); if v.is_even() != y.is_even() { y = &*SECP_P - y; } diff --git a/vm/src/hint_processor/builtin_hint_processor/segments.rs b/vm/src/hint_processor/builtin_hint_processor/segments.rs index c23c58d3d4..36576973d9 100644 --- a/vm/src/hint_processor/builtin_hint_processor/segments.rs +++ b/vm/src/hint_processor/builtin_hint_processor/segments.rs @@ -57,7 +57,6 @@ mod tests { }, hint_processor_definition::HintProcessorLogic, }, - types::exec_scope::ExecutionScopes, utils::test_utils::*, vm::vm_core::VirtualMachine, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/set.rs b/vm/src/hint_processor/builtin_hint_processor/set.rs index 9d93590c87..86fc4fdadb 100644 --- a/vm/src/hint_processor/builtin_hint_processor/set.rs +++ b/vm/src/hint_processor/builtin_hint_processor/set.rs @@ -23,7 +23,7 @@ pub fn set_add( let elm_size = get_integer_from_var_name("elm_size", vm, ids_data, ap_tracking).and_then(|x| { x.to_usize() - .ok_or_else(|| MathError::Felt252ToUsizeConversion(Box::new(x.into_owned())).into()) + .ok_or_else(|| MathError::Felt252ToUsizeConversion(Box::new(x)).into()) })?; let elm_ptr = get_ptr_from_var_name("elm_ptr", vm, ids_data, ap_tracking)?; let set_end_ptr = get_ptr_from_var_name("set_end_ptr", vm, ids_data, ap_tracking)?; @@ -66,7 +66,7 @@ mod tests { }, hint_processor_definition::HintProcessorLogic, }, - types::{exec_scope::ExecutionScopes, relocatable::MaybeRelocatable}, + types::relocatable::MaybeRelocatable, utils::test_utils::*, vm::vm_core::VirtualMachine, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/sha256_utils.rs b/vm/src/hint_processor/builtin_hint_processor/sha256_utils.rs index 659c752036..a7e77bd42c 100644 --- a/vm/src/hint_processor/builtin_hint_processor/sha256_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/sha256_utils.rs @@ -223,7 +223,6 @@ mod tests { }, hint_processor_definition::{HintProcessorLogic, HintReference}, }, - types::exec_scope::ExecutionScopes, utils::test_utils::*, vm::vm_core::VirtualMachine, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/signature.rs b/vm/src/hint_processor/builtin_hint_processor/signature.rs index 97b03c764d..878a379b7a 100644 --- a/vm/src/hint_processor/builtin_hint_processor/signature.rs +++ b/vm/src/hint_processor/builtin_hint_processor/signature.rs @@ -20,10 +20,8 @@ pub fn verify_ecdsa_signature( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - let signature_r = - get_integer_from_var_name("signature_r", vm, ids_data, ap_tracking)?.into_owned(); - let signature_s = - get_integer_from_var_name("signature_s", vm, ids_data, ap_tracking)?.into_owned(); + let signature_r = get_integer_from_var_name("signature_r", vm, ids_data, ap_tracking)?; + let signature_s = get_integer_from_var_name("signature_s", vm, ids_data, ap_tracking)?; let ecdsa_ptr = get_ptr_from_var_name("ecdsa_ptr", vm, ids_data, ap_tracking)?; let ecdsa_builtin = &mut vm.get_signature_builtin()?; if ecdsa_ptr.segment_index != ecdsa_builtin.base() as isize { @@ -54,9 +52,6 @@ mod tests { }, hint_processor_definition::HintProcessorLogic, }, - types::{ - exec_scope::ExecutionScopes, instance_definitions::ecdsa_instance_def::EcdsaInstanceDef, - }, utils::test_utils::*, vm::runners::builtin_runner::SignatureBuiltinRunner, }; @@ -69,8 +64,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn verify_ecdsa_signature_valid() { let mut vm = vm!(); - vm.builtin_runners = - vec![SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true).into()]; + vm.builtin_runners = vec![SignatureBuiltinRunner::new(Some(512), true).into()]; vm.segments = segments![ ((1, 0), (0, 0)), ( @@ -96,8 +90,7 @@ mod tests { #[test] fn verify_ecdsa_signature_invalid_ecdsa_ptr() { let mut vm = vm!(); - vm.builtin_runners = - vec![SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true).into()]; + vm.builtin_runners = vec![SignatureBuiltinRunner::new(Some(512), true).into()]; vm.segments = segments![ ((1, 0), (3, 0)), ( @@ -123,8 +116,7 @@ mod tests { #[test] fn verify_ecdsa_signature_invalid_input_cell() { let mut vm = vm!(); - vm.builtin_runners = - vec![SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true).into()]; + vm.builtin_runners = vec![SignatureBuiltinRunner::new(Some(512), true).into()]; vm.segments = segments![ ((1, 0), (0, 3)), ( diff --git a/vm/src/hint_processor/builtin_hint_processor/squash_dict_utils.rs b/vm/src/hint_processor/builtin_hint_processor/squash_dict_utils.rs index 32ea9cb253..23dc562dae 100644 --- a/vm/src/hint_processor/builtin_hint_processor/squash_dict_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/squash_dict_utils.rs @@ -176,7 +176,7 @@ pub fn squash_dict_inner_used_accesses_assert( if n_used_accesses.as_ref() != &Felt252::from(access_indices_at_key.len()) { return Err(HintError::NumUsedAccessesAssertFail(Box::new(( - n_used_accesses.into_owned(), + n_used_accesses, access_indices_at_key.len(), key, )))); @@ -247,8 +247,7 @@ pub fn squash_dict( let ptr_diff = get_integer_from_var_name("ptr_diff", vm, ids_data, ap_tracking)?; let n_accesses = get_integer_from_var_name("n_accesses", vm, ids_data, ap_tracking)?; //Get range_check_builtin - let range_check_builtin = vm.get_range_check_builtin()?; - let range_check_bound = range_check_builtin._bound; + let range_check_bound = *vm.get_range_check_builtin()?.bound(); //Main Logic let ptr_diff = ptr_diff .to_usize() @@ -260,14 +259,13 @@ pub fn squash_dict( if let Ok(max_size) = squash_dict_max_size { if n_accesses.as_ref() > &max_size { return Err(HintError::SquashDictMaxSizeExceeded(Box::new(( - max_size, - n_accesses.into_owned(), + max_size, n_accesses, )))); }; }; let n_accesses_usize = n_accesses .to_usize() - .ok_or_else(|| HintError::NAccessesTooBig(Box::new(n_accesses.into_owned())))?; + .ok_or_else(|| HintError::NAccessesTooBig(Box::new(n_accesses)))?; //A map from key to the list of indices accessing it. let mut access_indices = HashMap::>::new(); for i in 0..n_accesses_usize { @@ -285,7 +283,7 @@ pub fn squash_dict( keys.sort(); keys.reverse(); //Are the keys used bigger than the range_check bound. - let big_keys = if keys[0] >= range_check_bound.unwrap() { + let big_keys = if keys[0] >= range_check_bound { Felt252::ONE } else { Felt252::ZERO diff --git a/vm/src/hint_processor/builtin_hint_processor/uint256_utils.rs b/vm/src/hint_processor/builtin_hint_processor/uint256_utils.rs index 1416fec21d..9c91fafa8a 100644 --- a/vm/src/hint_processor/builtin_hint_processor/uint256_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/uint256_utils.rs @@ -1,4 +1,3 @@ -use crate::utils::{biguint_to_felt, felt_to_biguint}; use crate::Felt252; use crate::{ hint_processor::builtin_hint_processor::hint_utils::{ @@ -76,13 +75,13 @@ impl<'a> Uint256<'a> { } pub(crate) fn pack(self) -> BigUint { - (felt_to_biguint(*self.high) << 128) + felt_to_biguint(*self.low) + (self.high.to_biguint() << 128) + self.low.to_biguint() } pub(crate) fn split(num: &BigUint) -> Self { let mask_low: BigUint = u128::MAX.into(); - let low = biguint_to_felt(&(num & mask_low)).unwrap(); - let high = biguint_to_felt(&(num >> 128)).unwrap(); + let low = Felt252::from(&(num & mask_low)); + let high = Felt252::from(&(num >> 128)); Self::from_values(low, high) } } @@ -292,7 +291,7 @@ pub fn uint256_sqrt( )); } - let root = biguint_to_felt(&root)?; + let root = Felt252::from(&root); if only_low { insert_value_from_var_name("root", root, vm, ids_data, ap_tracking)?; @@ -394,8 +393,8 @@ pub fn uint256_offseted_unsigned_div_rem( //ids.remainder.low = remainder & ((1 << 128) - 1) //ids.remainder.high = remainder >> 128 - let a = (felt_to_biguint(*a_high) << 128_u32) + felt_to_biguint(*a_low); - let div = (felt_to_biguint(*div_high) << 128_u32) + felt_to_biguint(*div_low); + let a = (a_high.to_biguint() << 128_u32) + a_low.to_biguint(); + let div = (div_high.to_biguint() << 128_u32) + div_low.to_biguint(); //a and div will always be positive numbers //Then, Rust div_rem equals Python divmod let (quotient, remainder) = div_rem(a, div); @@ -453,9 +452,9 @@ pub fn uint256_mul_div_mod( let div_high = div_high.as_ref(); // Main Logic - let a = felt_to_biguint(*a_high).shl(128_usize) + felt_to_biguint(*a_low); - let b = felt_to_biguint(*b_high).shl(128_usize) + felt_to_biguint(*b_low); - let div = felt_to_biguint(*div_high).shl(128_usize) + felt_to_biguint(*div_low); + let a = a_high.to_biguint().shl(128_usize) + a_low.to_biguint(); + let b = b_high.to_biguint().shl(128_usize) + b_low.to_biguint(); + let div = div_high.to_biguint().shl(128_usize) + div_low.to_biguint(); if div.is_zero() { return Err(MathError::DividedByZero.into()); } @@ -464,32 +463,32 @@ pub fn uint256_mul_div_mod( // ids.quotient_low.low vm.insert_value( quotient_low_addr, - biguint_to_felt(&("ient & &BigUint::from(u128::MAX)))?, + Felt252::from(&("ient & &BigUint::from(u128::MAX))), )?; // ids.quotient_low.high vm.insert_value( (quotient_low_addr + 1)?, - biguint_to_felt(&(("ient).shr(128_u32) & &BigUint::from(u128::MAX)))?, + Felt252::from(&(("ient).shr(128_u32) & &BigUint::from(u128::MAX))), )?; // ids.quotient_high.low vm.insert_value( quotient_high_addr, - biguint_to_felt(&(("ient).shr(256_u32) & &BigUint::from(u128::MAX)))?, + Felt252::from(&(("ient).shr(256_u32) & &BigUint::from(u128::MAX))), )?; // ids.quotient_high.high vm.insert_value( (quotient_high_addr + 1)?, - biguint_to_felt(&(("ient).shr(384_u32)))?, + Felt252::from(&(("ient).shr(384_u32))), )?; //ids.remainder.low vm.insert_value( remainder_addr, - biguint_to_felt(&(&remainder & &BigUint::from(u128::MAX)))?, + Felt252::from(&(&remainder & &BigUint::from(u128::MAX))), )?; //ids.remainder.high vm.insert_value( (remainder_addr + 1)?, - biguint_to_felt(&remainder.shr(128_u32))?, + Felt252::from(&remainder.shr(128_u32)), )?; Ok(()) @@ -508,10 +507,7 @@ mod tests { }, hint_processor_definition::HintProcessorLogic, }, - types::{ - exec_scope::ExecutionScopes, - relocatable::{MaybeRelocatable, Relocatable}, - }, + types::relocatable::{MaybeRelocatable, Relocatable}, utils::test_utils::*, vm::{errors::memory_errors::MemoryError, vm_core::VirtualMachine}, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/uint384.rs b/vm/src/hint_processor/builtin_hint_processor/uint384.rs index c7d6ba3465..a973fb9d3d 100644 --- a/vm/src/hint_processor/builtin_hint_processor/uint384.rs +++ b/vm/src/hint_processor/builtin_hint_processor/uint384.rs @@ -1,5 +1,5 @@ -use crate::utils::felt_to_biguint; use crate::Felt252; +use num_bigint::BigUint; use num_integer::Integer; use num_traits::Zero; @@ -107,21 +107,31 @@ pub fn add_no_uint384_check( let a = Uint384::from_var_name("a", vm, ids_data, ap_tracking)?; let b = Uint384::from_var_name("b", vm, ids_data, ap_tracking)?; // This hint is not from the cairo commonlib, and its lib can be found under different paths, so we cant rely on a full path name - let shift = felt_to_biguint(*get_constant_from_var_name("SHIFT", constants)?); - - let sum_d0 = felt_to_biguint(*a.limbs[0].as_ref()) + felt_to_biguint(*b.limbs[0].as_ref()); - let carry_d0 = Felt252::from((sum_d0 >= shift) as usize); - let sum_d1 = felt_to_biguint(*a.limbs[1].as_ref()) - + felt_to_biguint(*b.limbs[1].as_ref()) - + felt_to_biguint(carry_d0); - let carry_d1 = Felt252::from((sum_d1 >= shift) as usize); - let sum_d2 = felt_to_biguint(*a.limbs[2].as_ref()) - + felt_to_biguint(*b.limbs[2].as_ref()) - + felt_to_biguint(carry_d1); + let shift = get_constant_from_var_name("SHIFT", constants)?.to_biguint(); + + let sum_d0 = (a.limbs[0].as_ref().to_biguint()) + (b.limbs[0].as_ref().to_biguint()); + let carry_d0 = BigUint::from((sum_d0 >= shift) as usize); + let sum_d1 = + (a.limbs[1].as_ref().to_biguint()) + (b.limbs[1].as_ref().to_biguint()) + &carry_d0; + let carry_d1 = BigUint::from((sum_d1 >= shift) as usize); + let sum_d2 = + (a.limbs[2].as_ref().to_biguint()) + (b.limbs[2].as_ref().to_biguint()) + &carry_d1; let carry_d2 = Felt252::from((sum_d2 >= shift) as usize); - insert_value_from_var_name("carry_d0", carry_d0, vm, ids_data, ap_tracking)?; - insert_value_from_var_name("carry_d1", carry_d1, vm, ids_data, ap_tracking)?; + insert_value_from_var_name( + "carry_d0", + Felt252::from(&carry_d0), + vm, + ids_data, + ap_tracking, + )?; + insert_value_from_var_name( + "carry_d1", + Felt252::from(&carry_d1), + vm, + ids_data, + ap_tracking, + )?; insert_value_from_var_name("carry_d2", carry_d2, vm, ids_data, ap_tracking) } @@ -242,10 +252,7 @@ mod tests { }, hint_processor_definition::HintProcessorLogic, }, - types::{ - exec_scope::ExecutionScopes, - relocatable::{MaybeRelocatable, Relocatable}, - }, + types::relocatable::{MaybeRelocatable, Relocatable}, utils::test_utils::*, vm::{errors::memory_errors::MemoryError, vm_core::VirtualMachine}, }; diff --git a/vm/src/hint_processor/builtin_hint_processor/uint384_extension.rs b/vm/src/hint_processor/builtin_hint_processor/uint384_extension.rs index 85c3cf6af8..b7ee55bf7d 100644 --- a/vm/src/hint_processor/builtin_hint_processor/uint384_extension.rs +++ b/vm/src/hint_processor/builtin_hint_processor/uint384_extension.rs @@ -73,7 +73,6 @@ mod tests { use crate::hint_processor::builtin_hint_processor::hint_code; use crate::hint_processor::builtin_hint_processor::secp::bigint_utils::Uint768; use crate::hint_processor::hint_processor_definition::HintProcessorLogic; - use crate::types::exec_scope::ExecutionScopes; use crate::utils::test_utils::*; use assert_matches::assert_matches; diff --git a/vm/src/hint_processor/builtin_hint_processor/uint_utils.rs b/vm/src/hint_processor/builtin_hint_processor/uint_utils.rs index 7db0b95593..ac2018bd3a 100644 --- a/vm/src/hint_processor/builtin_hint_processor/uint_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/uint_utils.rs @@ -1,7 +1,4 @@ -use crate::{ - utils::{biguint_to_felt, felt_to_biguint}, - Felt252, -}; +use crate::Felt252; use num_bigint::BigUint; use num_traits::One; @@ -11,7 +8,7 @@ pub(crate) fn split(num: &BigUint, num_bits_shift: u32) -> [Felt [0; N].map(|_| { let a = &num & bitmask; num >>= num_bits_shift; - biguint_to_felt(&a).unwrap() + Felt252::from(&a) }) } @@ -22,6 +19,6 @@ pub(crate) fn pack( limbs .into_iter() .enumerate() - .map(|(i, limb)| felt_to_biguint(*limb.as_ref()) << (i * num_bits_shift)) + .map(|(i, limb)| limb.as_ref().to_biguint() << (i * num_bits_shift)) .sum() } diff --git a/vm/src/hint_processor/builtin_hint_processor/usort.rs b/vm/src/hint_processor/builtin_hint_processor/usort.rs index f553866fe6..7c22f94fc7 100644 --- a/vm/src/hint_processor/builtin_hint_processor/usort.rs +++ b/vm/src/hint_processor/builtin_hint_processor/usort.rs @@ -43,7 +43,7 @@ pub fn usort_body( if input_len_u64 > usort_max_size { return Err(HintError::UsortOutOfRange(Box::new(( usort_max_size, - input_len.into_owned(), + input_len, )))); } } @@ -98,7 +98,7 @@ pub fn verify_usort( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - let value = get_integer_from_var_name("value", vm, ids_data, ap_tracking)?.clone(); + let value = get_integer_from_var_name("value", vm, ids_data, ap_tracking)?; let mut positions = exec_scopes .get_mut_dict_ref::>("positions_dict")? .remove(value.as_ref()) diff --git a/vm/src/hint_processor/builtin_hint_processor/vrf/fq.rs b/vm/src/hint_processor/builtin_hint_processor/vrf/fq.rs index 91ca9e7f8e..c31047d8e0 100644 --- a/vm/src/hint_processor/builtin_hint_processor/vrf/fq.rs +++ b/vm/src/hint_processor/builtin_hint_processor/vrf/fq.rs @@ -123,7 +123,6 @@ mod tests { use crate::hint_processor::builtin_hint_processor::hint_code; use crate::hint_processor::hint_processor_definition::HintProcessorLogic; use crate::types::errors::math_errors::MathError; - use crate::types::exec_scope::ExecutionScopes; use crate::utils::test_utils::*; use assert_matches::assert_matches; diff --git a/vm/src/hint_processor/builtin_hint_processor/vrf/inv_mod_p_uint512.rs b/vm/src/hint_processor/builtin_hint_processor/vrf/inv_mod_p_uint512.rs index 8854c15a34..ef8748a1bc 100644 --- a/vm/src/hint_processor/builtin_hint_processor/vrf/inv_mod_p_uint512.rs +++ b/vm/src/hint_processor/builtin_hint_processor/vrf/inv_mod_p_uint512.rs @@ -1,7 +1,7 @@ use crate::hint_processor::builtin_hint_processor::secp::bigint_utils::Uint512; use crate::hint_processor::builtin_hint_processor::uint256_utils::Uint256; use crate::stdlib::prelude::String; -use crate::utils::bigint_to_felt; +use crate::Felt252; use crate::{ hint_processor::hint_processor_definition::HintReference, math_utils::div_mod, serde::deserialize_program::ApTracking, stdlib::collections::HashMap, @@ -38,11 +38,11 @@ pub fn inv_mod_p_uint512( let p = Uint256::from_var_name("p", vm, ids_data, ap_tracking)?.pack(); - let x_inverse_mod_p = bigint_to_felt(&div_mod( + let x_inverse_mod_p = Felt252::from(&div_mod( &BigInt::one(), &BigInt::from(x), &BigInt::from(p), - )?)?; + )?); let x_inverse_mod_p = Uint256::from(x_inverse_mod_p); x_inverse_mod_p.insert_from_var_name("x_inverse_mod_p", vm, ids_data, ap_tracking)?; diff --git a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs index 69a8e77b36..354e332f03 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/dict_manager.rs @@ -3,6 +3,7 @@ use num_traits::One; use crate::stdlib::collections::HashMap; use crate::stdlib::prelude::*; +use crate::types::relocatable::MaybeRelocatable; use crate::vm::errors::hint_errors::HintError; use crate::Felt252; use crate::{types::relocatable::Relocatable, vm::vm_core::VirtualMachine}; @@ -10,9 +11,8 @@ use crate::{types::relocatable::Relocatable, vm::vm_core::VirtualMachine}; /// Stores the data of a specific dictionary. pub struct DictTrackerExecScope { /// The data of the dictionary. - data: HashMap, + data: HashMap, /// The index of the dictionary in the dict_infos segment. - #[allow(dead_code)] idx: usize, } @@ -80,13 +80,22 @@ impl DictManagerExecScope { } /// Inserts a value to the dict tracker corresponding to a given pointer to a dict segment. - pub fn insert_to_tracker(&mut self, dict_end: Relocatable, key: Felt252, value: Felt252) { + pub fn insert_to_tracker( + &mut self, + dict_end: Relocatable, + key: Felt252, + value: MaybeRelocatable, + ) { self.get_dict_tracker_mut(dict_end).data.insert(key, value); } /// Gets a value from the dict tracker corresponding to a given pointer to a dict segment. /// None if the key does not exist in the tracker data. - pub fn get_from_tracker(&self, dict_end: Relocatable, key: &Felt252) -> Option { + pub fn get_from_tracker( + &self, + dict_end: Relocatable, + key: &Felt252, + ) -> Option { self.get_dict_tracker(dict_end).ok()?.data.get(key).cloned() } } diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs index b97107f865..864c6277d1 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor.rs @@ -4,9 +4,7 @@ use crate::any_box; use crate::hint_processor::cairo_1_hint_processor::dict_manager::DictSquashExecScope; use crate::hint_processor::hint_processor_definition::HintReference; use crate::stdlib::{boxed::Box, collections::HashMap, prelude::*}; -use crate::types::relocatable::Relocatable; -use crate::utils::biguint_to_felt; -use crate::utils::felt_to_biguint; +use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::runners::cairo_runner::ResourceTracker; use crate::vm::runners::cairo_runner::RunResources; use crate::Felt252; @@ -278,9 +276,9 @@ impl Cairo1HintProcessor { value: &ResOperand, dst: &CellRef, ) -> Result<(), HintError> { - let value = felt_to_biguint(res_operand_get_val(vm, value)?); + let value = res_operand_get_val(vm, value)?.to_biguint(); let result = value.sqrt(); - vm.insert_value(cell_ref_to_relocatable(dst, vm)?, biguint_to_felt(&result)?) + vm.insert_value(cell_ref_to_relocatable(dst, vm)?, Felt252::from(&result)) .map_err(HintError::from) } @@ -309,7 +307,7 @@ impl Cairo1HintProcessor { ) -> Result<(), HintError> { let a_val = res_operand_get_val(vm, a)?; let b_val = res_operand_get_val(vm, b)?; - let mut lengths_and_indices = vec![ + let mut lengths_and_indices = [ (a_val, 0), (b_val - a_val, 1), (Felt252::from(-1) - b_val, 2), @@ -324,19 +322,19 @@ impl Cairo1HintProcessor { let range_check_ptr = get_ptr(vm, range_check_base, &range_check_offset)?; vm.insert_value( range_check_ptr, - biguint_to_felt(&(felt_to_biguint(lengths_and_indices[0].0) % prime_over_3_high))?, + Felt252::from(&(lengths_and_indices[0].0.to_biguint() % prime_over_3_high)), )?; vm.insert_value( (range_check_ptr + 1)?, - biguint_to_felt(&(felt_to_biguint(lengths_and_indices[0].0) / prime_over_3_high))?, + Felt252::from(&(lengths_and_indices[0].0.to_biguint() / prime_over_3_high)), )?; vm.insert_value( (range_check_ptr + 2)?, - biguint_to_felt(&(felt_to_biguint(lengths_and_indices[1].0) % prime_over_2_high))?, + Felt252::from(&(lengths_and_indices[1].0.to_biguint() % prime_over_2_high)), )?; vm.insert_value( (range_check_ptr + 3)?, - biguint_to_felt(&(felt_to_biguint(lengths_and_indices[1].0) / prime_over_2_high))?, + Felt252::from(&(lengths_and_indices[1].0.to_biguint() / prime_over_2_high)), ) .map_err(HintError::from) } @@ -371,10 +369,10 @@ impl Cairo1HintProcessor { quotient: &CellRef, remainder: &CellRef, ) -> Result<(), HintError> { - let lhs_value = felt_to_biguint(res_operand_get_val(vm, lhs)?); - let rhs_value = felt_to_biguint(res_operand_get_val(vm, rhs)?); - let quotient_value = biguint_to_felt(&(&lhs_value / &rhs_value))?; - let remainder_value = biguint_to_felt(&(lhs_value % rhs_value))?; + let lhs_value = res_operand_get_val(vm, lhs)?.to_biguint(); + let rhs_value = res_operand_get_val(vm, rhs)?.to_biguint(); + let quotient_value = Felt252::from(&(&lhs_value / &rhs_value)); + let remainder_value = Felt252::from(&(lhs_value % rhs_value)); vm.insert_value(cell_ref_to_relocatable(quotient, vm)?, quotient_value)?; vm.insert_value(cell_ref_to_relocatable(remainder, vm)?, remainder_value) .map_err(HintError::from) @@ -412,30 +410,30 @@ impl Cairo1HintProcessor { remainder1: &CellRef, ) -> Result<(), HintError> { let pow_2_128 = BigUint::from(u128::MAX) + 1u32; - let dividend0 = felt_to_biguint(get_val(vm, dividend0)?); - let dividend1 = felt_to_biguint(get_val(vm, dividend1)?); - let divisor0 = felt_to_biguint(get_val(vm, divisor0)?); - let divisor1 = felt_to_biguint(get_val(vm, divisor1)?); + let dividend0 = get_val(vm, dividend0)?.to_biguint(); + let dividend1 = get_val(vm, dividend1)?.to_biguint(); + let divisor0 = get_val(vm, divisor0)?.to_biguint(); + let divisor1 = get_val(vm, divisor1)?.to_biguint(); let dividend: BigUint = dividend0 + dividend1.shl(128); let divisor = divisor0 + divisor1.shl(128); let (quotient, remainder) = dividend.div_rem(&divisor); let (limb1, limb0) = quotient.div_rem(&pow_2_128); vm.insert_value( cell_ref_to_relocatable(quotient0, vm)?, - biguint_to_felt(&limb0)?, + Felt252::from(&limb0), )?; vm.insert_value( cell_ref_to_relocatable(quotient1, vm)?, - biguint_to_felt(&limb1)?, + Felt252::from(&limb1), )?; let (limb1, limb0) = remainder.div_rem(&pow_2_128); vm.insert_value( cell_ref_to_relocatable(remainder0, vm)?, - biguint_to_felt(&limb0)?, + Felt252::from(&limb0), )?; vm.insert_value( cell_ref_to_relocatable(remainder1, vm)?, - biguint_to_felt(&limb1)?, + Felt252::from(&limb1), )?; Ok(()) @@ -462,15 +460,15 @@ impl Cairo1HintProcessor { x: &CellRef, y: &CellRef, ) -> Result<(), HintError> { - let value = felt_to_biguint(res_operand_get_val(vm, value)?); - let scalar = felt_to_biguint(res_operand_get_val(vm, scalar)?); - let max_x = felt_to_biguint(res_operand_get_val(vm, max_x)?); + let value = res_operand_get_val(vm, value)?.to_biguint(); + let scalar = res_operand_get_val(vm, scalar)?.to_biguint(); + let max_x = res_operand_get_val(vm, max_x)?.to_biguint(); let x_value = (&value / &scalar).min(max_x); let y_value = value - &x_value * &scalar; - vm.insert_value(cell_ref_to_relocatable(x, vm)?, biguint_to_felt(&x_value)?) + vm.insert_value(cell_ref_to_relocatable(x, vm)?, Felt252::from(&x_value)) .map_err(HintError::from)?; - vm.insert_value(cell_ref_to_relocatable(y, vm)?, biguint_to_felt(&y_value)?) + vm.insert_value(cell_ref_to_relocatable(y, vm)?, Felt252::from(&y_value)) .map_err(HintError::from)?; Ok(()) @@ -482,7 +480,7 @@ impl Cairo1HintProcessor { x: &CellRef, y: &CellRef, ) -> Result<(), HintError> { - let beta = Fq::from(felt_to_biguint(get_beta())); + let beta = Fq::from(get_beta().to_biguint()); let mut rng = ark_std::test_rng(); let (random_x, random_y_squared) = loop { @@ -502,8 +500,8 @@ impl Cairo1HintProcessor { .into_bigint() .into(); - vm.insert_value(cell_ref_to_relocatable(x, vm)?, biguint_to_felt(&x_bigint)?)?; - vm.insert_value(cell_ref_to_relocatable(y, vm)?, biguint_to_felt(&y_bigint)?)?; + vm.insert_value(cell_ref_to_relocatable(x, vm)?, Felt252::from(&x_bigint))?; + vm.insert_value(cell_ref_to_relocatable(y, vm)?, Felt252::from(&y_bigint))?; Ok(()) } @@ -590,7 +588,11 @@ impl Cairo1HintProcessor { let (dict_base, dict_offset) = extract_buffer(dict_ptr)?; let dict_address = get_ptr(vm, dict_base, &dict_offset)?; let key = res_operand_get_val(vm, key)?; - let value = res_operand_get_val(vm, value)?; + let value = if let ResOperand::Deref(cell) = value { + get_mayberelocatable(vm, cell)? + } else { + MaybeRelocatable::Int(res_operand_get_val(vm, value)?) + }; let dict_manager_exec_scope = exec_scopes.get_mut_ref::("dict_manager_exec_scope")?; @@ -621,12 +623,12 @@ impl Cairo1HintProcessor { remainder1: &CellRef, ) -> Result<(), HintError> { let pow_2_128 = BigUint::from(u128::MAX) + 1u32; - let dividend0 = felt_to_biguint(res_operand_get_val(vm, dividend0)?); - let dividend1 = felt_to_biguint(res_operand_get_val(vm, dividend1)?); - let dividend2 = felt_to_biguint(res_operand_get_val(vm, dividend2)?); - let dividend3 = felt_to_biguint(res_operand_get_val(vm, dividend3)?); - let divisor0 = felt_to_biguint(res_operand_get_val(vm, divisor0)?); - let divisor1 = felt_to_biguint(res_operand_get_val(vm, divisor1)?); + let dividend0 = res_operand_get_val(vm, dividend0)?.to_biguint(); + let dividend1 = res_operand_get_val(vm, dividend1)?.to_biguint(); + let dividend2 = res_operand_get_val(vm, dividend2)?.to_biguint(); + let dividend3 = res_operand_get_val(vm, dividend3)?.to_biguint(); + let divisor0 = res_operand_get_val(vm, divisor0)?.to_biguint(); + let divisor1 = res_operand_get_val(vm, divisor1)?.to_biguint(); let dividend: BigUint = dividend0 + dividend1.shl(128) + dividend2.shl(256) + dividend3.shl(384); let divisor = divisor0 + divisor1.shl(128); @@ -635,33 +637,33 @@ impl Cairo1HintProcessor { vm.insert_value( cell_ref_to_relocatable(quotient0, vm)?, - biguint_to_felt(&limb0)?, + Felt252::from(&limb0), )?; let (quotient, limb1) = quotient.div_rem(&pow_2_128); vm.insert_value( cell_ref_to_relocatable(quotient1, vm)?, - biguint_to_felt(&limb1)?, + Felt252::from(&limb1), )?; let (limb3, limb2) = quotient.div_rem(&pow_2_128); vm.insert_value( cell_ref_to_relocatable(quotient2, vm)?, - biguint_to_felt(&limb2)?, + Felt252::from(&limb2), )?; vm.insert_value( cell_ref_to_relocatable(quotient3, vm)?, - biguint_to_felt(&limb3)?, + Felt252::from(&limb3), )?; let (limb1, limb0) = remainder.div_rem(&pow_2_128); vm.insert_value( cell_ref_to_relocatable(remainder0, vm)?, - biguint_to_felt(&limb0)?, + Felt252::from(&limb0), )?; vm.insert_value( cell_ref_to_relocatable(remainder1, vm)?, - biguint_to_felt(&limb1)?, + Felt252::from(&limb1), )?; Ok(()) @@ -681,8 +683,8 @@ impl Cairo1HintProcessor { ) -> Result<(), HintError> { let pow_2_128 = BigUint::from(u128::MAX) + 1u32; let pow_2_64 = BigUint::from(u64::MAX) + 1u32; - let value_low = felt_to_biguint(res_operand_get_val(vm, value_low)?); - let value_high = felt_to_biguint(res_operand_get_val(vm, value_high)?); + let value_low = res_operand_get_val(vm, value_low)?.to_biguint(); + let value_high = res_operand_get_val(vm, value_high)?.to_biguint(); let value = value_low + value_high * pow_2_128.clone(); let sqrt = value.sqrt(); let remainder = value - sqrt.clone() * sqrt.clone(); @@ -693,22 +695,22 @@ impl Cairo1HintProcessor { let (sqrt1_val, sqrt0_val) = sqrt.div_rem(&pow_2_64); vm.insert_value( cell_ref_to_relocatable(sqrt0, vm)?, - biguint_to_felt(&sqrt0_val)?, + Felt252::from(&sqrt0_val), )?; vm.insert_value( cell_ref_to_relocatable(sqrt1, vm)?, - biguint_to_felt(&sqrt1_val)?, + Felt252::from(&sqrt1_val), )?; let (remainder_high_val, remainder_low_val) = remainder.div_rem(&pow_2_128); vm.insert_value( cell_ref_to_relocatable(remainder_low, vm)?, - biguint_to_felt(&remainder_low_val)?, + Felt252::from(&remainder_low_val), )?; vm.insert_value( cell_ref_to_relocatable(remainder_high, vm)?, - biguint_to_felt(&remainder_high_val)?, + Felt252::from(&remainder_high_val), )?; vm.insert_value( cell_ref_to_relocatable(sqrt_mul_2_minus_remainder_ge_u128, vm)?, @@ -831,7 +833,11 @@ impl Cairo1HintProcessor { let (dict_base, dict_offset) = extract_buffer(dict_ptr)?; let dict_address = get_ptr(vm, dict_base, &dict_offset)?; let key = get_double_deref_val(vm, dict_base, &(dict_offset + Felt252::from(-3)))?; - let value = res_operand_get_val(vm, value)?; + let value: MaybeRelocatable = if let ResOperand::Deref(cell) = value { + get_mayberelocatable(vm, cell)? + } else { + MaybeRelocatable::Int(res_operand_get_val(vm, value)?) + }; let dict_manager_exec_scope = exec_scopes .get_mut_ref::("dict_manager_exec_scope") .map_err(|_| { @@ -1024,7 +1030,7 @@ impl Cairo1HintProcessor { val: &ResOperand, sqrt: &CellRef, ) -> Result<(), HintError> { - let value = Fq::from(felt_to_biguint(res_operand_get_val(vm, val)?)); + let value = Fq::from(res_operand_get_val(vm, val)?.to_biguint()); let three_fq = Fq::from(BigUint::from(3_u32)); let res = if value.legendre().is_qr() { @@ -1036,7 +1042,7 @@ impl Cairo1HintProcessor { if let Some(root) = res.sqrt() { let root0: BigUint = root.into_bigint().into(); let root1: BigUint = (-root).into_bigint().into(); - let root = biguint_to_felt(&core::cmp::min(root0, root1))?; + let root = Felt252::from(&core::cmp::min(root0, root1)); vm.insert_value(cell_ref_to_relocatable(sqrt, vm)?, root) .map_err(HintError::from) } else { @@ -1055,16 +1061,16 @@ impl Cairo1HintProcessor { low: &CellRef, ) -> Result<(), HintError> { let mask128 = BigUint::from(u128::MAX); - let lhs_val = felt_to_biguint(res_operand_get_val(vm, lhs)?); - let rhs_val = felt_to_biguint(res_operand_get_val(vm, rhs)?); + let lhs_val = res_operand_get_val(vm, lhs)?.to_biguint(); + let rhs_val = res_operand_get_val(vm, rhs)?.to_biguint(); let prod = lhs_val * rhs_val; vm.insert_value( cell_ref_to_relocatable(high, vm)?, - biguint_to_felt(&(prod.clone() >> 128))?, + Felt252::from(&(prod.clone() >> 128)), )?; vm.insert_value( cell_ref_to_relocatable(low, vm)?, - biguint_to_felt(&(prod & mask128))?, + Felt252::from(&(prod & mask128)), ) .map_err(HintError::from) } diff --git a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor_utils.rs b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor_utils.rs index f549fc23a3..46abef74e9 100644 --- a/vm/src/hint_processor/cairo_1_hint_processor/hint_processor_utils.rs +++ b/vm/src/hint_processor/cairo_1_hint_processor/hint_processor_utils.rs @@ -1,6 +1,6 @@ use crate::stdlib::prelude::*; +use crate::types::relocatable::MaybeRelocatable; use crate::types::{errors::math_errors::MathError, relocatable::Relocatable}; -use crate::utils::bigint_to_felt; use crate::vm::errors::{hint_errors::HintError, vm_errors::VirtualMachineError}; use crate::vm::vm_core::VirtualMachine; use crate::Felt252; @@ -12,7 +12,7 @@ pub(crate) fn extract_buffer(buffer: &ResOperand) -> Result<(&CellRef, Felt252), ResOperand::Deref(cell) => (cell, 0.into()), ResOperand::BinOp(bin_op) => { if let DerefOrImmediate::Immediate(val) = &bin_op.b { - (&bin_op.a, bigint_to_felt(&val.value)?) + (&bin_op.a, Felt252::from(&val.value)) } else { return Err(HintError::CustomHint( "Failed to extract buffer, expected ResOperand of BinOp type to have Inmediate b value".to_owned().into_boxed_str() @@ -30,6 +30,16 @@ pub(crate) fn extract_buffer(buffer: &ResOperand) -> Result<(&CellRef, Felt252), Ok((cell, base_offset)) } +pub(crate) fn get_mayberelocatable( + vm: &VirtualMachine, + cell: &CellRef, +) -> Result { + let relocatable = cell_ref_to_relocatable(cell, vm)?; + vm.get_maybe(&relocatable).ok_or_else(|| { + VirtualMachineError::InvalidMemoryValueTemporaryAddress(Box::new(relocatable)) + }) +} + /// Fetches the value of `res_operand` from the vm. pub(crate) fn get_val( vm: &VirtualMachine, @@ -40,12 +50,12 @@ pub(crate) fn get_val( ResOperand::DoubleDeref(cell, offset) => { get_double_deref_val(vm, cell, &Felt252::from(*offset as i32)) } - ResOperand::Immediate(x) => Ok(bigint_to_felt(&x.value)?), + ResOperand::Immediate(x) => Ok(Felt252::from(&x.value)), ResOperand::BinOp(op) => { let a = get_cell_val(vm, &op.a)?; let b = match &op.b { DerefOrImmediate::Deref(cell) => get_cell_val(vm, cell)?, - DerefOrImmediate::Immediate(x) => bigint_to_felt(&x.value)?, + DerefOrImmediate::Immediate(x) => Felt252::from(&x.value), }; match op.op { Operation::Add => Ok(a + b), @@ -108,12 +118,12 @@ pub(crate) fn res_operand_get_val( ResOperand::DoubleDeref(cell, offset) => { get_double_deref_val(vm, cell, &Felt252::from(*offset as i32)) } - ResOperand::Immediate(x) => Ok(bigint_to_felt(&x.value)?), + ResOperand::Immediate(x) => Ok(Felt252::from(&x.value)), ResOperand::BinOp(op) => { let a = get_cell_val(vm, &op.a)?; let b = match &op.b { DerefOrImmediate::Deref(cell) => get_cell_val(vm, cell)?, - DerefOrImmediate::Immediate(x) => bigint_to_felt(&x.value)?, + DerefOrImmediate::Immediate(x) => Felt252::from(&x.value), }; match op.op { Operation::Add => Ok(a + b), diff --git a/vm/src/hint_processor/hint_processor_utils.rs b/vm/src/hint_processor/hint_processor_utils.rs index 38f018dc89..c97ecb51ed 100644 --- a/vm/src/hint_processor/hint_processor_utils.rs +++ b/vm/src/hint_processor/hint_processor_utils.rs @@ -1,4 +1,4 @@ -use crate::stdlib::{borrow::Cow, boxed::Box}; +use crate::stdlib::boxed::Box; use crate::{ serde::deserialize_program::{ApTracking, OffsetValue}, @@ -29,22 +29,26 @@ pub fn insert_value_from_reference( ///Returns the Integer value stored in the given ids variable /// Returns an internal error, users should map it into a more informative type -pub fn get_integer_from_reference<'a>( - vm: &'a VirtualMachine, - hint_reference: &'a HintReference, +pub fn get_integer_from_reference( + vm: &VirtualMachine, + hint_reference: &HintReference, ap_tracking: &ApTracking, -) -> Result, HintError> { - // if the reference register is none, this means it is an immediate value and we - // should return that value. - - if let (OffsetValue::Immediate(int_1), _) = (&hint_reference.offset1, &hint_reference.offset2) { - return Ok(Cow::Borrowed(int_1)); +) -> Result { + // Compute the initial value + let mut val = if let OffsetValue::Immediate(f) = &hint_reference.offset1 { + *f + } else { + let var_addr = compute_addr_from_reference(hint_reference, vm, ap_tracking) + .ok_or(HintError::UnknownIdentifierInternal)?; + vm.get_integer(var_addr) + .map_err(|_| HintError::WrongIdentifierTypeInternal(Box::new(var_addr)))? + .into_owned() + }; + // If offset2 is an immediate, we need to add it's value to the initial value + if let OffsetValue::Immediate(f) = &hint_reference.offset2 { + val += f; } - - let var_addr = compute_addr_from_reference(hint_reference, vm, ap_tracking) - .ok_or(HintError::UnknownIdentifierInternal)?; - vm.get_integer(var_addr) - .map_err(|_| HintError::WrongIdentifierTypeInternal(Box::new(var_addr))) + Ok(val) } ///Returns the Relocatable value stored in the given ids variable @@ -117,7 +121,7 @@ pub fn compute_addr_from_reference( Some((offset1 + value.get_int_ref()?.to_usize()?).ok()?) } OffsetValue::Value(value) => Some((offset1 + *value).ok()?), - _ => None, + _ => Some(offset1), } } @@ -179,7 +183,6 @@ fn get_offset_value_reference( #[cfg(test)] mod tests { use super::*; - use crate::stdlib::collections::HashMap; use crate::{ relocatable, @@ -201,12 +204,31 @@ mod tests { assert_eq!( get_integer_from_reference(&vm, &hint_ref, &ApTracking::new()) - .expect("Unexpected get integer fail") - .into_owned(), + .expect("Unexpected get integer fail"), Felt252::from(2) ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_integer_from_reference_with_immediate_off2() { + let mut vm = vm!(); + vm.segments = segments![((1, 0), 1)]; + let hint_ref = HintReference { + offset1: OffsetValue::Reference(Register::FP, 0, false), + offset2: OffsetValue::Immediate(Felt252::TWO), + dereference: false, + ap_tracking_data: Default::default(), + cairo_type: None, + }; + + assert_eq!( + get_integer_from_reference(&vm, &hint_ref, &ApTracking::new()) + .expect("Unexpected get integer fail"), + Felt252::THREE + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_offset_value_reference_valid() { diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 88415c121c..c4cfbd1334 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -5,10 +5,8 @@ //! - `skip_next_instruction_hint`: Enable the `skip_next_instruction()` hint. Not enabled by default. //! - `hooks`: Enable [`Hooks`](crate::vm::hooks::Hooks) support for the [VirtualMachine](vm::vm_core::VirtualMachine). Not enabled by default. //! - `test_utils`: Enables test utils (`hooks` and `skip_next_instruction` features). Not enabled by default. -//! - `with_mimalloc`: Use [`MiMalloc`](https://crates.io/crates/mimalloc) as the program global allocator. //! - `cairo-1-hints`: Enable hints that were introduced in Cairo 1. Not enabled by default. //! - `arbitrary`: Enables implementations of [`arbitrary::Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/) for some structs. Not enabled by default. -//! - `lambdaworks-felt`: Enables usage of the [**lambdaworks**](https://github.com/lambdaclass/lambdaworks) backend for [`felt::Felt252`]. Not enabled by default. #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(warnings)] @@ -58,6 +56,7 @@ pub mod air_public_input; pub mod cairo_run; pub mod hint_processor; pub mod math_utils; +pub mod program_hash; pub mod serde; pub mod types; pub mod utils; diff --git a/vm/src/math_utils/mod.rs b/vm/src/math_utils/mod.rs index 8381869321..bd5ff0935d 100644 --- a/vm/src/math_utils/mod.rs +++ b/vm/src/math_utils/mod.rs @@ -6,7 +6,7 @@ use core::cmp::min; use crate::stdlib::{boxed::Box, ops::Shr, prelude::Vec}; use crate::types::errors::math_errors::MathError; -use crate::utils::{felt_to_biguint, CAIRO_PRIME}; +use crate::utils::CAIRO_PRIME; use crate::Felt252; use lazy_static::lazy_static; use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt}; @@ -58,7 +58,7 @@ pub fn pow2_const_nz(n: u32) -> &'static NonZeroFelt { /// ``` pub fn signed_felt(felt: Felt252) -> BigInt { - let biguint = felt_to_biguint(felt); + let biguint = felt.to_biguint(); if biguint > *SIGNED_FELT_MAX { BigInt::from_biguint(num_bigint::Sign::Minus, &*CAIRO_PRIME - &biguint) } else { @@ -196,6 +196,20 @@ pub fn div_mod(n: &BigInt, m: &BigInt, p: &BigInt) -> Result Ok((n * a).mod_floor(p)) } +pub(crate) fn div_mod_unsigned( + n: &BigUint, + m: &BigUint, + p: &BigUint, +) -> Result { + // BigUint to BigInt conversion cannot fail & div_mod will always return a positive value if all values are positive so we can safely unwrap here + div_mod( + &n.to_bigint().unwrap(), + &m.to_bigint().unwrap(), + &p.to_bigint().unwrap(), + ) + .map(|i| i.to_biguint().unwrap()) +} + pub fn ec_add( point_a: (BigInt, BigInt), point_b: (BigInt, BigInt), diff --git a/vm/src/program_hash.rs b/vm/src/program_hash.rs new file mode 100644 index 0000000000..3ff1fa798c --- /dev/null +++ b/vm/src/program_hash.rs @@ -0,0 +1,204 @@ +use starknet_crypto::{pedersen_hash, FieldElement}; + +use crate::Felt252; + +use crate::serde::deserialize_program::BuiltinName; +use crate::stdlib::vec::Vec; +use crate::types::relocatable::MaybeRelocatable; +use crate::vm::runners::cairo_pie::StrippedProgram; + +type HashFunction = fn(&FieldElement, &FieldElement) -> FieldElement; + +#[derive(thiserror_no_std::Error, Debug)] +pub enum HashChainError { + #[error("Data array must contain at least one element.")] + EmptyData, +} + +#[derive(thiserror_no_std::Error, Debug)] +pub enum ProgramHashError { + #[error(transparent)] + HashChain(#[from] HashChainError), + + #[error( + "Invalid program builtin: builtin name too long to be converted to field element: {0}" + )] + InvalidProgramBuiltin(&'static str), + + #[error("Invalid program data: data contains relocatable(s)")] + InvalidProgramData, + + /// Conversion from Felt252 to FieldElement failed. This is unlikely to happen + /// unless the implementation of Felt252 changes and this code is not updated properly. + #[error("Conversion from Felt252 to FieldElement failed")] + Felt252ToFieldElementConversionFailed, +} + +/// Computes a hash chain over the data, in the following order: +/// h(data[0], h(data[1], h(..., h(data[n-2], data[n-1])))). +/// +/// Reimplements this Python function: +/// def compute_hash_chain(data, hash_func=pedersen_hash): +/// assert len(data) >= 1, f"len(data) for hash chain computation must be >= 1; got: {len(data)}." +/// return functools.reduce(lambda x, y: hash_func(y, x), data[::-1]) +fn compute_hash_chain<'a, I>( + data: I, + hash_func: HashFunction, +) -> Result +where + I: Iterator + DoubleEndedIterator, +{ + match data.copied().rev().reduce(|x, y| hash_func(&y, &x)) { + Some(result) => Ok(result), + None => Err(HashChainError::EmptyData), + } +} + +/// Creates an instance of `FieldElement` from a builtin name. +/// +/// Converts the builtin name to bytes then attempts to create a field element from +/// these bytes. This function will fail if the builtin name is over 31 characters. +fn builtin_to_field_element(builtin: &BuiltinName) -> Result { + // The Python implementation uses the builtin name without suffix + let builtin_name = builtin + .name() + .strip_suffix("_builtin") + .unwrap_or(builtin.name()); + + FieldElement::from_byte_slice_be(builtin_name.as_bytes()) + .map_err(|_| ProgramHashError::InvalidProgramBuiltin(builtin.name())) +} + +/// The `value: FieldElement` is `pub(crate)` and there is no accessor. +/// This function converts a `Felt252` to a `FieldElement` using a safe, albeit inefficient, +/// method. +fn felt_to_field_element(felt: &Felt252) -> Result { + let bytes = felt.to_bytes_be(); + FieldElement::from_bytes_be(&bytes) + .map_err(|_e| ProgramHashError::Felt252ToFieldElementConversionFailed) +} + +/// Converts a `MaybeRelocatable` into a `FieldElement` value. +/// +/// Returns `InvalidProgramData` if `maybe_relocatable` is not an integer +fn maybe_relocatable_to_field_element( + maybe_relocatable: &MaybeRelocatable, +) -> Result { + let felt = maybe_relocatable + .get_int_ref() + .ok_or(ProgramHashError::InvalidProgramData)?; + felt_to_field_element(felt) +} + +/// Computes the Pedersen hash of a program. +/// +/// Reimplements this Python function: +/// def compute_program_hash_chain(program: ProgramBase, bootloader_version=0): +/// builtin_list = [from_bytes(builtin.encode("ascii")) for builtin in program.builtins] +/// # The program header below is missing the data length, which is later added to the data_chain. +/// program_header = [bootloader_version, program.main, len(program.builtins)] + builtin_list +/// data_chain = program_header + program.data +/// +/// return compute_hash_chain([len(data_chain)] + data_chain) +pub fn compute_program_hash_chain( + program: &StrippedProgram, + bootloader_version: usize, +) -> Result { + let program_main = program.main; + let program_main = FieldElement::from(program_main); + + // Convert builtin names to field elements + let builtin_list: Result, _> = program + .builtins + .iter() + .map(builtin_to_field_element) + .collect(); + let builtin_list = builtin_list?; + + let program_header = vec![ + FieldElement::from(bootloader_version), + program_main, + FieldElement::from(program.builtins.len()), + ]; + + let program_data: Result, _> = program + .data + .iter() + .map(maybe_relocatable_to_field_element) + .collect(); + let program_data = program_data?; + + let data_chain_len = program_header.len() + builtin_list.len() + program_data.len(); + let data_chain_len_vec = vec![FieldElement::from(data_chain_len)]; + + // Prepare a chain of iterators to feed to the hash function + let data_chain = [ + &data_chain_len_vec, + &program_header, + &builtin_list, + &program_data, + ]; + + let hash = compute_hash_chain(data_chain.iter().flat_map(|&v| v.iter()), pedersen_hash)?; + Ok(hash) +} + +#[cfg(test)] +mod tests { + #[cfg(feature = "std")] + use {crate::types::program::Program, rstest::rstest, std::path::PathBuf}; + + use starknet_crypto::pedersen_hash; + + use super::*; + + #[test] + fn test_compute_hash_chain() { + let data: Vec = vec![ + FieldElement::from(1u64), + FieldElement::from(2u64), + FieldElement::from(3u64), + ]; + let expected_hash = pedersen_hash( + &FieldElement::from(1u64), + &pedersen_hash(&FieldElement::from(2u64), &FieldElement::from(3u64)), + ); + let computed_hash = compute_hash_chain(data.iter(), pedersen_hash) + .expect("Hash computation failed unexpectedly"); + + assert_eq!(computed_hash, expected_hash); + } + + #[cfg(feature = "std")] + #[rstest] + // Expected hashes generated with `cairo-hash-program` + #[case::fibonacci( + "../cairo_programs/fibonacci.json", + "0x43b17e9592f33142246af4c06cd2b574b460dd1f718d76b51341175a62b220f" + )] + #[case::field_arithmetic( + "../cairo_programs/field_arithmetic.json", + "0x1031772ca86e618b058101af9c9a3277bac90712b750bcea1cc69d6c7cad8a7" + )] + #[case::keccak_copy_inputs( + "../cairo_programs/keccak_copy_inputs.json", + "0x49484fdc8e7a85061f9f21b7e21fe276d8a88c8e96681101a2518809e686c6c" + )] + fn test_compute_program_hash_chain( + #[case] program_path: PathBuf, + #[case] expected_program_hash: String, + ) { + let program = + Program::from_file(program_path.as_path(), Some("main")) + .expect("Could not load program. Did you compile the sample programs? Run `make test` in the root directory."); + let stripped_program = program.get_stripped_program().unwrap(); + let bootloader_version = 0; + + let program_hash = compute_program_hash_chain(&stripped_program, bootloader_version) + .expect("Failed to compute program hash."); + + let program_hash_hex = format!("{:#x}", program_hash); + + assert_eq!(program_hash_hex, expected_program_hash); + } +} diff --git a/vm/src/serde/deserialize_program.rs b/vm/src/serde/deserialize_program.rs index be314ac364..b897223f87 100644 --- a/vm/src/serde/deserialize_program.rs +++ b/vm/src/serde/deserialize_program.rs @@ -14,10 +14,12 @@ use crate::{ sync::Arc, }, utils::CAIRO_PRIME, + vm::runners::builtin_runner::RANGE_CHECK_96_BUILTIN_NAME, }; use crate::utils::PRIME_STR; use crate::vm::runners::builtin_runner::SEGMENT_ARENA_BUILTIN_NAME; +use crate::vm::runners::builtin_runner::{ADD_MOD_BUILTIN_NAME, MUL_MOD_BUILTIN_NAME}; use crate::Felt252; use crate::{ serde::deserialize_utils, @@ -55,6 +57,9 @@ pub enum BuiltinName { ec_op, poseidon, segment_arena, + range_check96, + add_mod, + mul_mod, } impl BuiltinName { @@ -69,6 +74,9 @@ impl BuiltinName { BuiltinName::ec_op => EC_OP_BUILTIN_NAME, BuiltinName::poseidon => POSEIDON_BUILTIN_NAME, BuiltinName::segment_arena => SEGMENT_ARENA_BUILTIN_NAME, + BuiltinName::range_check96 => RANGE_CHECK_96_BUILTIN_NAME, + BuiltinName::add_mod => ADD_MOD_BUILTIN_NAME, + BuiltinName::mul_mod => MUL_MOD_BUILTIN_NAME, } } } @@ -205,6 +213,17 @@ pub struct DebugInfo { pub(crate) instruction_locations: HashMap, } +impl DebugInfo { + pub fn new(instruction_locations: HashMap) -> Self { + Self { + instruction_locations, + } + } + pub fn get_instruction_locations(&self) -> HashMap { + self.instruction_locations.clone() + } +} + #[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct InstructionLocation { @@ -218,6 +237,17 @@ pub struct InputFile { pub filename: String, } +impl InputFile { + #[cfg(feature = "std")] + pub fn get_content(&self) -> Result { + let content = std::fs::read_to_string(self.filename.clone()); + if let Ok(content) = content { + return Ok(content); + } + Err(format!("Failed to read file {}", self.filename.clone())) + } +} + #[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct HintLocation { diff --git a/vm/src/serde/deserialize_utils.rs b/vm/src/serde/deserialize_utils.rs index d66e48e1c7..7462a53cb6 100644 --- a/vm/src/serde/deserialize_utils.rs +++ b/vm/src/serde/deserialize_utils.rs @@ -233,7 +233,7 @@ fn take_until_unbalanced( .ok_or_else(|| Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil)))? .chars(); match it.next().unwrap_or_default() { - c if c == '\\' => { + '\\' => { // Skip the escape char `\`. index += '\\'.len_utf8(); // Skip also the following char. diff --git a/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs b/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs index 4c5bf3fd50..7f42e94529 100644 --- a/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs +++ b/vm/src/tests/cairo_1_run_from_entrypoint_tests.rs @@ -39,7 +39,7 @@ fn test_uint256_div_mod_hint() { run_cairo_1_entrypoint( program_data.as_slice(), - 104, + 102, &[36_usize.into(), 2_usize.into()], &[Felt252::from(18_usize)], ); diff --git a/vm/src/tests/cairo_run_test.rs b/vm/src/tests/cairo_run_test.rs index c06a3d4e3a..fc1023d23e 100644 --- a/vm/src/tests/cairo_run_test.rs +++ b/vm/src/tests/cairo_run_test.rs @@ -1,6 +1,15 @@ -use num_traits::Zero; - use crate::tests::*; +#[cfg(feature = "mod_builtin")] +use crate::{ + utils::test_utils::Program, + vm::{ + runners::{builtin_runner::BuiltinRunner, cairo_runner::CairoRunner}, + security::verify_secure_runner, + vm_core::VirtualMachine, + }, +}; + +use num_traits::Zero; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] @@ -1061,3 +1070,171 @@ fn cairo_run_print_dict_array() { include_bytes!("../../../cairo_programs/print_feature/print_dict_array.json"); run_program_simple(program_data); } + +#[test] +fn run_program_allow_missing_builtins() { + let program_data = include_bytes!("../../../cairo_programs/pedersen_extra_builtins.json"); + let config = CairoRunConfig { + allow_missing_builtins: Some(true), + layout: "small", // The program logic only uses builtins in the small layout but contains builtins outside of it + ..Default::default() + }; + assert!(crate::cairo_run::cairo_run( + program_data, + &config, + &mut BuiltinHintProcessor::new_empty() + ) + .is_ok()) +} + +#[test] +fn run_program_allow_missing_builtins_proof() { + let program_data = + include_bytes!("../../../cairo_programs/proof_programs/pedersen_extra_builtins.json"); + let config = CairoRunConfig { + proof_mode: true, + allow_missing_builtins: Some(true), + layout: "small", // The program logic only uses builtins in the small layout but contains builtins outside of it + ..Default::default() + }; + assert!(crate::cairo_run::cairo_run( + program_data, + &config, + &mut BuiltinHintProcessor::new_empty() + ) + .is_ok()) +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_mod_builtin() { + let program_data = + include_bytes!("../../../cairo_programs/mod_builtin_feature/mod_builtin.json"); + run_program_with_custom_mod_builtin_params(program_data, false, 1, 3, None); +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_mod_builtin_failure() { + let program_data = + include_bytes!("../../../cairo_programs/mod_builtin_feature/mod_builtin_failure.json"); + let error_msg = "mul_mod_builtin: Expected a * b == c (mod p). Got: instance=2, batch=0, p=9, a=2, b=2, c=2."; + run_program_with_custom_mod_builtin_params(program_data, false, 1, 3, Some(error_msg)); +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_mod_builtin_large_batch_size() { + let program_data = include_bytes!( + "../../../cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size.json" + ); + run_program_with_custom_mod_builtin_params(program_data, false, 8, 3, None); +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_mod_builtin_large_batch_size_failure() { + let program_data = include_bytes!( + "../../../cairo_programs/mod_builtin_feature/mod_builtin_large_batch_size_failure.json" + ); + let error_msg = "mul_mod_builtin: Expected a * b == c (mod p). Got: instance=0, batch=2, p=9, a=2, b=2, c=2."; + run_program_with_custom_mod_builtin_params(program_data, false, 8, 3, Some(error_msg)); +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_mod_builtin_proof() { + let program_data = + include_bytes!("../../../cairo_programs/mod_builtin_feature/proof/mod_builtin.json"); + run_program_with_custom_mod_builtin_params(program_data, true, 1, 3, None); +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_mod_builtin_large_batch_size_proof() { + let program_data = include_bytes!( + "../../../cairo_programs/mod_builtin_feature/proof/mod_builtin_large_batch_size.json" + ); + run_program_with_custom_mod_builtin_params(program_data, true, 8, 3, None); +} + +#[cfg(feature = "mod_builtin")] +fn run_program_with_custom_mod_builtin_params( + data: &[u8], + proof_mode: bool, + batch_size: usize, + word_bit_len: u32, + security_error: Option<&str>, +) { + let cairo_run_config = CairoRunConfig { + layout: "all_cairo", + proof_mode, + ..Default::default() + }; + let mut hint_processor = BuiltinHintProcessor::new_empty(); + let program = Program::from_bytes(data, Some(cairo_run_config.entrypoint)).unwrap(); + let mut cairo_runner = CairoRunner::new( + &program, + cairo_run_config.layout, + cairo_run_config.proof_mode, + ) + .unwrap(); + + let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); + // Modify add_mod & mul_mod params + for runner in vm.get_builtin_runners_as_mut() { + if let BuiltinRunner::Mod(runner) = runner { + runner.override_layout_params(batch_size, word_bit_len) + } + } + + cairo_runner + .run_until_pc(end, &mut vm, &mut hint_processor) + .unwrap(); + + if cairo_run_config.proof_mode { + cairo_runner + .run_for_steps(1, &mut vm, &mut hint_processor) + .unwrap(); + } + cairo_runner + .end_run( + cairo_run_config.disable_trace_padding, + false, + &mut vm, + &mut hint_processor, + ) + .unwrap(); + + vm.verify_auto_deductions().unwrap(); + cairo_runner.read_return_values(&mut vm, false).unwrap(); + if cairo_run_config.proof_mode { + cairo_runner.finalize_segments(&mut vm).unwrap(); + } + if !cairo_run_config.proof_mode { + let security_res = verify_secure_runner(&cairo_runner, true, None, &mut vm); + if let Some(error) = security_error { + assert!(security_res.is_err()); + assert!(security_res.err().unwrap().to_string().contains(error)); + return; + } + security_res.unwrap(); + } +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_apply_poly() { + let program_data = + include_bytes!("../../../cairo_programs/mod_builtin_feature/apply_poly.json"); + run_program(program_data, false, Some("all_cairo"), None, None); +} + +#[test] +#[cfg(feature = "mod_builtin")] +fn cairo_run_apply_poly_proof() { + let program_data = + include_bytes!("../../../cairo_programs/mod_builtin_feature/proof/apply_poly.json"); + run_program(program_data, true, Some("all_cairo"), None, None); +} diff --git a/vm/src/tests/compare_factorial_outputs_all_layouts.sh b/vm/src/tests/compare_factorial_outputs_all_layouts.sh new file mode 100755 index 0000000000..1a2067e4c8 --- /dev/null +++ b/vm/src/tests/compare_factorial_outputs_all_layouts.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env sh + +factorial_compiled="cairo_programs/proof_programs/factorial.json" +passed_tests=0 +failed_tests=0 +exit_code=0 + +for layout in "plain" "small" "dex" "recursive" "starknet" "starknet_with_keccak" "recursive_large_output" "all_solidity" "starknet_with_keccak"; do + # Run cairo_vm + echo "Running cairo-vm with layout $layout" + cargo run -p cairo-vm-cli --release -- --layout $layout --proof_mode $factorial_compiled --trace_file factorial_rs.trace --memory_file factorial_rs.memory --air_public_input factorial_rs.air_public_input --air_private_input factorial_rs.air_private_input + # Run cairo_lang + echo "Running cairo_lang with layout $layout" + cairo-run --layout $layout --proof_mode --program $factorial_compiled --trace_file factorial_py.trace --memory_file factorial_py.memory --air_public_input factorial_py.air_public_input --air_private_input factorial_py.air_private_input + # Compare trace + echo "Running trace comparison for layout $layout" + if ! diff -q factorial_rs.trace factorial_py.trace; then + echo "Trace differs for layout $layout" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi + # Compare memory + echo "Running memory comparison for layout $layout" + if ! ./vm/src/tests/memory_comparator.py factorial_rs.memory factorial_py.memory; then + echo "Memory differs for layout $layout" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi + # Compare air public input + echo "Running air public input comparison for layout $layout" + if ! ./vm/src/tests/air_public_input_comparator.py factorial_rs.air_public_input factorial_py.air_public_input; then + echo "Air public input differs for layout $layout" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi + # Compare air private input + echo "Running air private input comparison for layout $layout" + if ! ./vm/src/tests/air_private_input_comparator.py factorial_rs.air_private_input factorial_py.air_private_input; then + echo "Air private input differs for layout $layout" + exit_code=1 + failed_tests=$((failed_tests + 1)) + else + passed_tests=$((passed_tests + 1)) + fi + # Clean files generated by the script + echo "Cleaning files" + rm factorial_rs.* + rm factorial_py.* +done + +if test $failed_tests != 0; then + echo "Comparisons: $failed_tests failed, $passed_tests passed, $((failed_tests + passed_tests)) total" +elif test $passed_tests = 0; then + echo "No tests ran!" + exit_code=2 +else + echo "All $passed_tests tests passed; no discrepancies found" +fi + +exit "${exit_code}" diff --git a/vm/src/tests/mod.rs b/vm/src/tests/mod.rs index e30a01214d..d09918726f 100644 --- a/vm/src/tests/mod.rs +++ b/vm/src/tests/mod.rs @@ -47,25 +47,26 @@ mod skip_instruction_test; //For simple programs that should just succeed and have no special needs. //Checks memory holes == 0 -pub(self) fn run_program_simple(data: &[u8]) { - run_program(data, Some("all_cairo"), None, None) +fn run_program_simple(data: &[u8]) { + run_program(data, false, Some("all_cairo"), None, None) } //For simple programs that should just succeed but using small layout. -pub(self) fn run_program_small(data: &[u8]) { - run_program(data, Some("small"), None, None) +fn run_program_small(data: &[u8]) { + run_program(data, false, Some("small"), None, None) } -pub(self) fn run_program_with_trace(data: &[u8], trace: &[(usize, usize, usize)]) { - run_program(data, Some("all_cairo"), Some(trace), None) +fn run_program_with_trace(data: &[u8], trace: &[(usize, usize, usize)]) { + run_program(data, false, Some("all_cairo"), Some(trace), None) } -pub(self) fn run_program_with_error(data: &[u8], error: &str) { - run_program(data, Some("all_cairo"), None, Some(error)) +fn run_program_with_error(data: &[u8], error: &str) { + run_program(data, false, Some("all_cairo"), None, Some(error)) } -pub(self) fn run_program( +fn run_program( data: &[u8], + proof_mode: bool, layout: Option<&str>, trace: Option<&[(usize, usize, usize)]>, error: Option<&str>, @@ -75,6 +76,7 @@ pub(self) fn run_program( layout: layout.unwrap_or("all_cairo"), relocate_mem: true, trace_enabled: true, + proof_mode, ..Default::default() }; let res = cairo_run(data, &cairo_run_config, &mut hint_executor); @@ -101,7 +103,7 @@ pub(self) fn run_program( #[cfg(feature = "cairo-1-hints")] // Runs a contract entrypoint with given arguments and checks its return values // Doesn't use a syscall_handler -pub(self) fn run_cairo_1_entrypoint( +fn run_cairo_1_entrypoint( program_content: &[u8], entrypoint_offset: usize, args: &[MaybeRelocatable], @@ -207,7 +209,7 @@ pub(self) fn run_cairo_1_entrypoint( #[cfg(feature = "cairo-1-hints")] /// Equals to fn run_cairo_1_entrypoint /// But with run_resources as an input -pub(self) fn run_cairo_1_entrypoint_with_run_resources( +fn run_cairo_1_entrypoint_with_run_resources( contract_class: CasmContractClass, entrypoint_offset: usize, hint_processor: &mut Cairo1HintProcessor, diff --git a/vm/src/types/instance_definitions/bitwise_instance_def.rs b/vm/src/types/instance_definitions/bitwise_instance_def.rs index e59c219fd3..f5e3ce4354 100644 --- a/vm/src/types/instance_definitions/bitwise_instance_def.rs +++ b/vm/src/types/instance_definitions/bitwise_instance_def.rs @@ -2,34 +2,22 @@ use serde::Serialize; pub(crate) const CELLS_PER_BITWISE: u32 = 5; pub(crate) const INPUT_CELLS_PER_BITWISE: u32 = 2; +pub(crate) const TOTAL_N_BITS: u32 = 251; #[derive(Serialize, Clone, Debug, PartialEq)] pub(crate) struct BitwiseInstanceDef { pub(crate) ratio: Option, - pub(crate) total_n_bits: u32, } -impl BitwiseInstanceDef { - pub(crate) fn default() -> Self { - BitwiseInstanceDef { - ratio: Some(256), - total_n_bits: 251, - } +impl Default for BitwiseInstanceDef { + fn default() -> Self { + BitwiseInstanceDef { ratio: Some(256) } } +} +impl BitwiseInstanceDef { pub(crate) fn new(ratio: Option) -> Self { - BitwiseInstanceDef { - ratio, - total_n_bits: 251, - } - } - - pub(crate) fn _cells_per_builtin(&self) -> u32 { - CELLS_PER_BITWISE - } - - pub(crate) fn _range_check_units_per_builtin(&self) -> u32 { - 0 + BitwiseInstanceDef { ratio } } } @@ -40,37 +28,17 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_range_check_units_per_builtin() { - let builtin_instance = BitwiseInstanceDef::default(); - assert_eq!(builtin_instance._range_check_units_per_builtin(), 0); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_builtin() { - let builtin_instance = BitwiseInstanceDef::default(); - assert_eq!(builtin_instance._cells_per_builtin(), 5); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new() { - let builtin_instance = BitwiseInstanceDef { - ratio: Some(8), - total_n_bits: 251, - }; + let builtin_instance = BitwiseInstanceDef { ratio: Some(8) }; assert_eq!(BitwiseInstanceDef::new(Some(8)), builtin_instance); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_default() { - let builtin_instance = BitwiseInstanceDef { - ratio: Some(256), - total_n_bits: 251, - }; + let builtin_instance = BitwiseInstanceDef { ratio: Some(256) }; assert_eq!(BitwiseInstanceDef::default(), builtin_instance); } } diff --git a/vm/src/types/instance_definitions/builtins_instance_def.rs b/vm/src/types/instance_definitions/builtins_instance_def.rs index 019a926b8f..a6d0bc44cc 100644 --- a/vm/src/types/instance_definitions/builtins_instance_def.rs +++ b/vm/src/types/instance_definitions/builtins_instance_def.rs @@ -1,9 +1,13 @@ +use super::mod_instance_def::ModInstanceDef; use super::{ bitwise_instance_def::BitwiseInstanceDef, ec_op_instance_def::EcOpInstanceDef, ecdsa_instance_def::EcdsaInstanceDef, keccak_instance_def::KeccakInstanceDef, pedersen_instance_def::PedersenInstanceDef, poseidon_instance_def::PoseidonInstanceDef, range_check_instance_def::RangeCheckInstanceDef, }; + +pub(crate) const BUILTIN_INSTANCES_PER_COMPONENT: u32 = 1; + use serde::Serialize; #[derive(Serialize, Debug, PartialEq)] @@ -16,6 +20,9 @@ pub(crate) struct BuiltinsInstanceDef { pub(crate) ec_op: Option, pub(crate) keccak: Option, pub(crate) poseidon: Option, + pub(crate) range_check96: Option, + pub(crate) add_mod: Option, + pub(crate) mul_mod: Option, } impl BuiltinsInstanceDef { @@ -29,6 +36,9 @@ impl BuiltinsInstanceDef { ec_op: None, keccak: None, poseidon: None, + range_check96: None, + add_mod: None, + mul_mod: None, } } @@ -42,6 +52,9 @@ impl BuiltinsInstanceDef { ec_op: None, keccak: None, poseidon: None, + range_check96: None, + add_mod: None, + mul_mod: None, } } @@ -55,71 +68,95 @@ impl BuiltinsInstanceDef { ec_op: None, keccak: None, poseidon: None, + range_check96: None, + add_mod: None, + mul_mod: None, } } pub(crate) fn recursive() -> BuiltinsInstanceDef { BuiltinsInstanceDef { output: true, - pedersen: Some(PedersenInstanceDef::new(Some(128), 1)), + pedersen: Some(PedersenInstanceDef::new(Some(128))), range_check: Some(RangeCheckInstanceDef::default()), ecdsa: None, bitwise: Some(BitwiseInstanceDef::new(Some(8))), ec_op: None, keccak: None, poseidon: None, + range_check96: None, + add_mod: None, + mul_mod: None, } } pub(crate) fn starknet() -> BuiltinsInstanceDef { BuiltinsInstanceDef { output: true, - pedersen: Some(PedersenInstanceDef::new(Some(32), 1)), - range_check: Some(RangeCheckInstanceDef::new(Some(16), 8)), + pedersen: Some(PedersenInstanceDef::new(Some(32))), + range_check: Some(RangeCheckInstanceDef::new(Some(16))), ecdsa: Some(EcdsaInstanceDef::new(Some(2048))), bitwise: Some(BitwiseInstanceDef::new(Some(64))), ec_op: Some(EcOpInstanceDef::new(Some(1024))), keccak: None, poseidon: Some(PoseidonInstanceDef::default()), + range_check96: None, + add_mod: None, + mul_mod: None, } } pub(crate) fn starknet_with_keccak() -> BuiltinsInstanceDef { BuiltinsInstanceDef { output: true, - pedersen: Some(PedersenInstanceDef::new(Some(32), 1)), - range_check: Some(RangeCheckInstanceDef::new(Some(16), 8)), + pedersen: Some(PedersenInstanceDef::new(Some(32))), + range_check: Some(RangeCheckInstanceDef::new(Some(16))), ecdsa: Some(EcdsaInstanceDef::new(Some(2048))), bitwise: Some(BitwiseInstanceDef::new(Some(64))), ec_op: Some(EcOpInstanceDef::new(Some(1024))), - keccak: Some(KeccakInstanceDef::new(Some(2048), vec![200; 8])), + keccak: Some(KeccakInstanceDef::new(Some(2048))), poseidon: Some(PoseidonInstanceDef::default()), + range_check96: None, + add_mod: None, + mul_mod: None, } } pub(crate) fn recursive_large_output() -> BuiltinsInstanceDef { BuiltinsInstanceDef { output: true, - pedersen: Some(PedersenInstanceDef::new(Some(32), 1)), + pedersen: Some(PedersenInstanceDef::new(Some(128))), range_check: Some(RangeCheckInstanceDef::default()), ecdsa: None, bitwise: Some(BitwiseInstanceDef::new(Some(8))), ec_op: None, keccak: None, - poseidon: None, + poseidon: Some(PoseidonInstanceDef::new(Some(8))), + range_check96: None, + add_mod: None, + mul_mod: None, } } pub(crate) fn all_cairo() -> BuiltinsInstanceDef { BuiltinsInstanceDef { output: true, - pedersen: Some(PedersenInstanceDef::new(Some(256), 1)), + pedersen: Some(PedersenInstanceDef::new(Some(256))), range_check: Some(RangeCheckInstanceDef::default()), ecdsa: Some(EcdsaInstanceDef::new(Some(2048))), bitwise: Some(BitwiseInstanceDef::new(Some(16))), ec_op: Some(EcOpInstanceDef::new(Some(1024))), - keccak: Some(KeccakInstanceDef::new(Some(2048), vec![200; 8])), + keccak: Some(KeccakInstanceDef::new(Some(2048))), poseidon: Some(PoseidonInstanceDef::new(Some(256))), + range_check96: Some(RangeCheckInstanceDef::new(Some(8))), + #[cfg(feature = "mod_builtin")] + add_mod: Some(ModInstanceDef::new(Some(128), 1, 96)), + #[cfg(feature = "mod_builtin")] + mul_mod: Some(ModInstanceDef::new(Some(256), 1, 96)), + #[cfg(not(feature = "mod_builtin"))] + add_mod: None, + #[cfg(not(feature = "mod_builtin"))] + mul_mod: None, } } @@ -133,19 +170,31 @@ impl BuiltinsInstanceDef { ec_op: Some(EcOpInstanceDef::default()), keccak: None, poseidon: None, + range_check96: None, + add_mod: None, + mul_mod: None, } } pub(crate) fn dynamic() -> BuiltinsInstanceDef { BuiltinsInstanceDef { output: true, - pedersen: Some(PedersenInstanceDef::new(None, 4)), - range_check: Some(RangeCheckInstanceDef::new(None, 8)), + pedersen: Some(PedersenInstanceDef::new(None)), + range_check: Some(RangeCheckInstanceDef::new(None)), ecdsa: Some(EcdsaInstanceDef::new(None)), bitwise: Some(BitwiseInstanceDef::new(None)), ec_op: Some(EcOpInstanceDef::new(None)), keccak: None, poseidon: None, + range_check96: None, + #[cfg(feature = "mod_builtin")] + add_mod: Some(ModInstanceDef::new(None, 1, 96)), + #[cfg(feature = "mod_builtin")] + mul_mod: Some(ModInstanceDef::new(None, 1, 96)), + #[cfg(not(feature = "mod_builtin"))] + add_mod: None, + #[cfg(not(feature = "mod_builtin"))] + mul_mod: None, } } } @@ -249,7 +298,7 @@ mod tests { assert!(builtins.bitwise.is_some()); assert!(builtins.ec_op.is_none()); assert!(builtins.keccak.is_none()); - assert!(builtins.poseidon.is_none()); + assert!(builtins.poseidon.is_some()); } #[test] diff --git a/vm/src/types/instance_definitions/cpu_instance_def.rs b/vm/src/types/instance_definitions/cpu_instance_def.rs deleted file mode 100644 index 19d22643a1..0000000000 --- a/vm/src/types/instance_definitions/cpu_instance_def.rs +++ /dev/null @@ -1,27 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize, Debug, PartialEq)] -pub(crate) struct CpuInstanceDef { - pub(crate) _safe_call: bool, -} - -impl CpuInstanceDef { - pub(crate) fn default() -> Self { - CpuInstanceDef { _safe_call: true } - } -} - -#[cfg(test)] -mod tests { - use super::CpuInstanceDef; - - #[cfg(target_arch = "wasm32")] - use wasm_bindgen_test::*; - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_default() { - let cpu_instance = CpuInstanceDef::default(); - assert!(cpu_instance._safe_call) - } -} diff --git a/vm/src/types/instance_definitions/ec_op_instance_def.rs b/vm/src/types/instance_definitions/ec_op_instance_def.rs index 75e8039dba..3f4bc6ac2a 100644 --- a/vm/src/types/instance_definitions/ec_op_instance_def.rs +++ b/vm/src/types/instance_definitions/ec_op_instance_def.rs @@ -2,37 +2,22 @@ use serde::Serialize; pub(crate) const CELLS_PER_EC_OP: u32 = 7; pub(crate) const INPUT_CELLS_PER_EC_OP: u32 = 5; +pub(crate) const SCALAR_HEIGHT: u32 = 256; #[derive(Serialize, Clone, Debug, PartialEq)] pub(crate) struct EcOpInstanceDef { pub(crate) ratio: Option, - pub(crate) scalar_height: u32, - pub(crate) _scalar_bits: u32, } -impl EcOpInstanceDef { - pub(crate) fn default() -> Self { - EcOpInstanceDef { - ratio: Some(256), - scalar_height: 256, - _scalar_bits: 252, - } +impl Default for EcOpInstanceDef { + fn default() -> Self { + EcOpInstanceDef { ratio: Some(256) } } +} +impl EcOpInstanceDef { pub(crate) fn new(ratio: Option) -> Self { - EcOpInstanceDef { - ratio, - scalar_height: 256, - _scalar_bits: 252, - } - } - - pub(crate) fn _cells_per_builtin(&self) -> u32 { - CELLS_PER_EC_OP - } - - pub(crate) fn _range_check_units_per_builtin(&self) -> u32 { - 0 + EcOpInstanceDef { ratio } } } @@ -43,39 +28,17 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_range_check_units_per_builtin() { - let builtin_instance = EcOpInstanceDef::default(); - assert_eq!(builtin_instance._range_check_units_per_builtin(), 0); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_builtin() { - let builtin_instance = EcOpInstanceDef::default(); - assert_eq!(builtin_instance._cells_per_builtin(), 7); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new() { - let builtin_instance = EcOpInstanceDef { - ratio: Some(8), - scalar_height: 256, - _scalar_bits: 252, - }; + let builtin_instance = EcOpInstanceDef { ratio: Some(8) }; assert_eq!(EcOpInstanceDef::new(Some(8)), builtin_instance); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_default() { - let builtin_instance = EcOpInstanceDef { - ratio: Some(256), - scalar_height: 256, - _scalar_bits: 252, - }; + let builtin_instance = EcOpInstanceDef { ratio: Some(256) }; assert_eq!(EcOpInstanceDef::default(), builtin_instance); } } diff --git a/vm/src/types/instance_definitions/ecdsa_instance_def.rs b/vm/src/types/instance_definitions/ecdsa_instance_def.rs index 518e5f5288..42f2ad6beb 100644 --- a/vm/src/types/instance_definitions/ecdsa_instance_def.rs +++ b/vm/src/types/instance_definitions/ecdsa_instance_def.rs @@ -1,44 +1,23 @@ use serde::Serialize; pub(crate) const CELLS_PER_SIGNATURE: u32 = 2; -pub(crate) const _INPUTCELLS_PER_SIGNATURE: u32 = 2; -#[derive(Serialize, Debug, PartialEq)] +#[derive(Serialize, Clone, Debug, PartialEq)] pub(crate) struct EcdsaInstanceDef { pub(crate) ratio: Option, - pub(crate) _repetitions: u32, - pub(crate) _height: u32, - pub(crate) _n_hash_bits: u32, } -impl EcdsaInstanceDef { - pub(crate) fn default() -> Self { - EcdsaInstanceDef { - ratio: Some(512), - _repetitions: 1, - _height: 256, - _n_hash_bits: 251, - } +impl Default for EcdsaInstanceDef { + fn default() -> Self { + EcdsaInstanceDef { ratio: Some(512) } } +} +impl EcdsaInstanceDef { pub(crate) fn new(ratio: Option) -> Self { - EcdsaInstanceDef { - ratio, - _repetitions: 1, - _height: 256, - _n_hash_bits: 251, - } - } - - pub(crate) fn _cells_per_builtin(&self) -> u32 { - CELLS_PER_SIGNATURE - } - - pub(crate) fn _range_check_units_per_builtin(&self) -> u32 { - 0 + EcdsaInstanceDef { ratio } } } - #[cfg(test)] mod tests { use super::*; @@ -46,41 +25,17 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_range_check_units_per_builtin() { - let builtin_instance = EcdsaInstanceDef::default(); - assert_eq!(builtin_instance._range_check_units_per_builtin(), 0); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_builtin() { - let builtin_instance = EcdsaInstanceDef::default(); - assert_eq!(builtin_instance._cells_per_builtin(), 2); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new() { - let builtin_instance = EcdsaInstanceDef { - ratio: Some(8), - _repetitions: 1, - _height: 256, - _n_hash_bits: 251, - }; + let builtin_instance = EcdsaInstanceDef { ratio: Some(8) }; assert_eq!(EcdsaInstanceDef::new(Some(8)), builtin_instance); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_default() { - let builtin_instance = EcdsaInstanceDef { - ratio: Some(512), - _repetitions: 1, - _height: 256, - _n_hash_bits: 251, - }; + let builtin_instance = EcdsaInstanceDef { ratio: Some(512) }; assert_eq!(EcdsaInstanceDef::default(), builtin_instance); } } diff --git a/vm/src/types/instance_definitions/keccak_instance_def.rs b/vm/src/types/instance_definitions/keccak_instance_def.rs index 655c361fcc..5746050067 100644 --- a/vm/src/types/instance_definitions/keccak_instance_def.rs +++ b/vm/src/types/instance_definitions/keccak_instance_def.rs @@ -1,39 +1,25 @@ use crate::stdlib::prelude::*; use serde::Serialize; +pub(crate) const INPUT_CELLS_PER_KECCAK: u32 = 8; +pub(crate) const CELLS_PER_KECCAK: u32 = 16; +pub(crate) const KECCAK_INSTANCES_PER_COMPONENT: u32 = 16; + #[derive(Serialize, Clone, Debug, PartialEq)] pub(crate) struct KeccakInstanceDef { pub(crate) ratio: Option, - pub(crate) _state_rep: Vec, - pub(crate) _instance_per_component: u32, } impl Default for KeccakInstanceDef { fn default() -> Self { - Self { - // ratio should be equal to 2 ** 11 -> 2048 - ratio: Some(2048), - _state_rep: vec![200; 8], - _instance_per_component: 16, - } + // ratio should be equal to 2 ** 11 -> 2048 + KeccakInstanceDef { ratio: Some(2048) } } } impl KeccakInstanceDef { - pub(crate) fn new(ratio: Option, _state_rep: Vec) -> Self { - Self { - ratio, - _state_rep, - ..Default::default() - } - } - - pub(crate) fn cells_per_builtin(&self) -> u32 { - 2 * self._state_rep.len() as u32 - } - - pub(crate) fn _range_check_units_per_builtin(&self) -> u32 { - 0 + pub(crate) fn new(ratio: Option) -> Self { + KeccakInstanceDef { ratio } } } @@ -44,42 +30,17 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_range_check_units_per_builtin() { - let builtin_instance = KeccakInstanceDef::default(); - assert_eq!(builtin_instance._range_check_units_per_builtin(), 0); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_builtin() { - let builtin_instance = KeccakInstanceDef::default(); - assert_eq!(builtin_instance.cells_per_builtin(), 16); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new() { - let builtin_instance = KeccakInstanceDef { - ratio: Some(2048), - _state_rep: vec![200; 8], - _instance_per_component: 16, - }; - assert_eq!( - KeccakInstanceDef::new(Some(2048), vec![200; 8]), - builtin_instance - ); + let builtin_instance = KeccakInstanceDef { ratio: Some(2048) }; + assert_eq!(KeccakInstanceDef::new(Some(2048)), builtin_instance); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_default() { - let builtin_instance = KeccakInstanceDef { - ratio: Some(2048), - _state_rep: vec![200; 8], - _instance_per_component: 16, - }; + let builtin_instance = KeccakInstanceDef { ratio: Some(2048) }; assert_eq!(KeccakInstanceDef::default(), builtin_instance); } } diff --git a/vm/src/types/instance_definitions/mod.rs b/vm/src/types/instance_definitions/mod.rs index 53bcc15d1b..8f1bba2198 100644 --- a/vm/src/types/instance_definitions/mod.rs +++ b/vm/src/types/instance_definitions/mod.rs @@ -1,10 +1,11 @@ pub mod bitwise_instance_def; pub mod builtins_instance_def; -pub mod cpu_instance_def; pub mod diluted_pool_instance_def; pub mod ec_op_instance_def; pub mod ecdsa_instance_def; pub mod keccak_instance_def; +#[allow(unused)] +pub mod mod_instance_def; pub mod pedersen_instance_def; pub mod poseidon_instance_def; pub mod range_check_instance_def; diff --git a/vm/src/types/instance_definitions/mod_instance_def.rs b/vm/src/types/instance_definitions/mod_instance_def.rs new file mode 100644 index 0000000000..0b84077d33 --- /dev/null +++ b/vm/src/types/instance_definitions/mod_instance_def.rs @@ -0,0 +1,22 @@ +use serde::Serialize; + +pub(crate) const N_WORDS: usize = 4; + +pub(crate) const CELLS_PER_MOD: u32 = 7; + +#[derive(Serialize, Debug, PartialEq, Clone)] +pub(crate) struct ModInstanceDef { + pub(crate) ratio: Option, + pub(crate) word_bit_len: u32, + pub(crate) batch_size: usize, +} + +impl ModInstanceDef { + pub(crate) fn new(ratio: Option, batch_size: usize, word_bit_len: u32) -> Self { + ModInstanceDef { + ratio, + word_bit_len, + batch_size, + } + } +} diff --git a/vm/src/types/instance_definitions/pedersen_instance_def.rs b/vm/src/types/instance_definitions/pedersen_instance_def.rs index d6273f35f1..5f5bc0e564 100644 --- a/vm/src/types/instance_definitions/pedersen_instance_def.rs +++ b/vm/src/types/instance_definitions/pedersen_instance_def.rs @@ -1,48 +1,22 @@ -use num_bigint::{BigInt, Sign}; use serde::Serialize; pub(crate) const CELLS_PER_HASH: u32 = 3; pub(crate) const INPUT_CELLS_PER_HASH: u32 = 2; -#[derive(Serialize, Debug, PartialEq)] +#[derive(Serialize, Clone, Debug, PartialEq)] pub(crate) struct PedersenInstanceDef { pub(crate) ratio: Option, - pub(crate) _repetitions: u32, - pub(crate) _element_height: u32, - pub(crate) _element_bits: u32, - pub(crate) _n_inputs: u32, - pub(crate) _hash_limit: BigInt, } -impl PedersenInstanceDef { - pub(crate) fn default() -> Self { - PedersenInstanceDef { - ratio: Some(8), - _repetitions: 4, - _element_height: 256, - _element_bits: 252, - _n_inputs: 2, - _hash_limit: BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]), - } - } - - pub(crate) fn new(ratio: Option, _repetitions: u32) -> Self { - PedersenInstanceDef { - ratio, - _repetitions, - _element_height: 256, - _element_bits: 252, - _n_inputs: 2, - _hash_limit: BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]), - } - } - - pub(crate) fn _cells_per_builtin(&self) -> u32 { - CELLS_PER_HASH +impl Default for PedersenInstanceDef { + fn default() -> Self { + PedersenInstanceDef { ratio: Some(8) } } +} - pub(crate) fn _range_check_units_per_builtin(&self) -> u32 { - 0 +impl PedersenInstanceDef { + pub(crate) fn new(ratio: Option) -> Self { + PedersenInstanceDef { ratio } } } @@ -53,45 +27,17 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_range_check_units_per_builtin() { - let builtin_instance = PedersenInstanceDef::default(); - assert_eq!(builtin_instance._range_check_units_per_builtin(), 0); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_builtin() { - let builtin_instance = PedersenInstanceDef::default(); - assert_eq!(builtin_instance._cells_per_builtin(), 3); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new() { - let builtin_instance = PedersenInstanceDef { - ratio: Some(10), - _repetitions: 2, - _element_height: 256, - _element_bits: 252, - _n_inputs: 2, - _hash_limit: BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]), - }; - assert_eq!(PedersenInstanceDef::new(Some(10), 2), builtin_instance); + let builtin_instance = PedersenInstanceDef { ratio: Some(10) }; + assert_eq!(PedersenInstanceDef::new(Some(10)), builtin_instance); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_default() { - let builtin_instance = PedersenInstanceDef { - ratio: Some(8), - _repetitions: 4, - _element_height: 256, - _element_bits: 252, - _n_inputs: 2, - _hash_limit: BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]), - }; + let builtin_instance = PedersenInstanceDef { ratio: Some(8) }; assert_eq!(PedersenInstanceDef::default(), builtin_instance); } } diff --git a/vm/src/types/instance_definitions/poseidon_instance_def.rs b/vm/src/types/instance_definitions/poseidon_instance_def.rs index fa478c4c3d..ae52df75fe 100644 --- a/vm/src/types/instance_definitions/poseidon_instance_def.rs +++ b/vm/src/types/instance_definitions/poseidon_instance_def.rs @@ -8,11 +8,12 @@ pub(crate) struct PoseidonInstanceDef { pub(crate) ratio: Option, } -impl PoseidonInstanceDef { - pub(crate) fn default() -> Self { +impl Default for PoseidonInstanceDef { + fn default() -> Self { PoseidonInstanceDef { ratio: Some(32) } } - +} +impl PoseidonInstanceDef { pub(crate) fn new(ratio: Option) -> Self { PoseidonInstanceDef { ratio } } diff --git a/vm/src/types/instance_definitions/range_check_instance_def.rs b/vm/src/types/instance_definitions/range_check_instance_def.rs index ad46df54c6..4524fca9bb 100644 --- a/vm/src/types/instance_definitions/range_check_instance_def.rs +++ b/vm/src/types/instance_definitions/range_check_instance_def.rs @@ -4,27 +4,17 @@ pub(crate) const CELLS_PER_RANGE_CHECK: u32 = 1; #[derive(Serialize, Debug, PartialEq)] pub(crate) struct RangeCheckInstanceDef { pub(crate) ratio: Option, - pub(crate) n_parts: u32, } -impl RangeCheckInstanceDef { - pub(crate) fn default() -> Self { - RangeCheckInstanceDef { - ratio: Some(8), - n_parts: 8, - } - } - - pub(crate) fn new(ratio: Option, n_parts: u32) -> Self { - RangeCheckInstanceDef { ratio, n_parts } - } - - pub(crate) fn _cells_per_builtin(&self) -> u32 { - CELLS_PER_RANGE_CHECK +impl Default for RangeCheckInstanceDef { + fn default() -> Self { + RangeCheckInstanceDef { ratio: Some(8) } } +} - pub(crate) fn _range_check_units_per_builtin(&self) -> u32 { - self.n_parts +impl RangeCheckInstanceDef { + pub(crate) fn new(ratio: Option) -> Self { + RangeCheckInstanceDef { ratio } } } @@ -35,37 +25,17 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_range_check_units_per_builtin() { - let builtin_instance = RangeCheckInstanceDef::default(); - assert_eq!(builtin_instance._range_check_units_per_builtin(), 8); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_builtin() { - let builtin_instance = RangeCheckInstanceDef::default(); - assert_eq!(builtin_instance._cells_per_builtin(), 1); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new() { - let builtin_instance = RangeCheckInstanceDef { - ratio: Some(10), - n_parts: 10, - }; - assert_eq!(RangeCheckInstanceDef::new(Some(10), 10), builtin_instance); + let builtin_instance = RangeCheckInstanceDef { ratio: Some(10) }; + assert_eq!(RangeCheckInstanceDef::new(Some(10)), builtin_instance); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_default() { - let builtin_instance = RangeCheckInstanceDef { - ratio: Some(8), - n_parts: 8, - }; + let builtin_instance = RangeCheckInstanceDef { ratio: Some(8) }; assert_eq!(RangeCheckInstanceDef::default(), builtin_instance); } } diff --git a/vm/src/types/layout.rs b/vm/src/types/layout.rs index 82eba1bece..3533f817fe 100644 --- a/vm/src/types/layout.rs +++ b/vm/src/types/layout.rs @@ -1,165 +1,120 @@ use crate::stdlib::prelude::*; use super::instance_definitions::{ - builtins_instance_def::BuiltinsInstanceDef, cpu_instance_def::CpuInstanceDef, - diluted_pool_instance_def::DilutedPoolInstanceDef, + builtins_instance_def::BuiltinsInstanceDef, diluted_pool_instance_def::DilutedPoolInstanceDef, }; +pub(crate) const MEMORY_UNITS_PER_STEP: u32 = 8; + use serde::Serialize; #[derive(Serialize, Debug)] pub struct CairoLayout { - pub(crate) _name: String, - pub(crate) _cpu_component_step: u32, + pub(crate) name: String, pub(crate) rc_units: u32, pub(crate) builtins: BuiltinsInstanceDef, - pub(crate) _public_memory_fraction: u32, - pub(crate) _memory_units_per_step: u32, + pub(crate) public_memory_fraction: u32, pub(crate) diluted_pool_instance_def: Option, - pub(crate) _n_trace_colums: u32, - pub(crate) _cpu_instance_def: CpuInstanceDef, } impl CairoLayout { pub(crate) fn plain_instance() -> CairoLayout { CairoLayout { - _name: String::from("plain"), - _cpu_component_step: 1, + name: String::from("plain"), rc_units: 16, builtins: BuiltinsInstanceDef::plain(), - _public_memory_fraction: 4, - _memory_units_per_step: 8, + public_memory_fraction: 4, diluted_pool_instance_def: None, - _n_trace_colums: 8, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn small_instance() -> CairoLayout { CairoLayout { - _name: String::from("small"), - _cpu_component_step: 1, + name: String::from("small"), rc_units: 16, builtins: BuiltinsInstanceDef::small(), - _public_memory_fraction: 4, - _memory_units_per_step: 8, + public_memory_fraction: 4, diluted_pool_instance_def: None, - _n_trace_colums: 25, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn dex_instance() -> CairoLayout { CairoLayout { - _name: String::from("dex"), - _cpu_component_step: 1, + name: String::from("dex"), rc_units: 4, builtins: BuiltinsInstanceDef::dex(), - _public_memory_fraction: 4, - _memory_units_per_step: 8, + public_memory_fraction: 4, diluted_pool_instance_def: None, - _n_trace_colums: 22, - _cpu_instance_def: CpuInstanceDef::default(), } } - #[allow(dead_code)] pub(crate) fn recursive_instance() -> CairoLayout { CairoLayout { - _name: String::from("recursive"), - _cpu_component_step: 1, + name: String::from("recursive"), rc_units: 4, builtins: BuiltinsInstanceDef::recursive(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::default()), - _n_trace_colums: 10, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn starknet_instance() -> CairoLayout { CairoLayout { - _name: String::from("starknet"), - _cpu_component_step: 1, + name: String::from("starknet"), rc_units: 4, builtins: BuiltinsInstanceDef::starknet(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::new(2, 4, 16)), - _n_trace_colums: 10, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn starknet_with_keccak_instance() -> CairoLayout { CairoLayout { - _name: String::from("starknet_with_keccak"), - _cpu_component_step: 1, + name: String::from("starknet_with_keccak"), rc_units: 4, builtins: BuiltinsInstanceDef::starknet_with_keccak(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::default()), - _n_trace_colums: 15, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn recursive_large_output_instance() -> CairoLayout { CairoLayout { - _name: String::from("recursive_large_output"), - _cpu_component_step: 1, + name: String::from("recursive_large_output"), rc_units: 4, builtins: BuiltinsInstanceDef::recursive_large_output(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::default()), - _n_trace_colums: 13, - _cpu_instance_def: CpuInstanceDef::default(), } } - #[allow(dead_code)] pub(crate) fn all_cairo_instance() -> CairoLayout { CairoLayout { - _name: String::from("all_cairo"), - _cpu_component_step: 1, + name: String::from("all_cairo"), rc_units: 4, builtins: BuiltinsInstanceDef::all_cairo(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::default()), - _n_trace_colums: 11, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn all_solidity_instance() -> CairoLayout { CairoLayout { - _name: String::from("all_solidity"), - _cpu_component_step: 1, + name: String::from("all_solidity"), rc_units: 8, builtins: BuiltinsInstanceDef::all_solidity(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::default()), - _n_trace_colums: 27, - _cpu_instance_def: CpuInstanceDef::default(), } } pub(crate) fn dynamic_instance() -> CairoLayout { CairoLayout { - _name: String::from("dynamic"), - _cpu_component_step: 1, + name: String::from("dynamic"), rc_units: 16, builtins: BuiltinsInstanceDef::dynamic(), - _public_memory_fraction: 8, - _memory_units_per_step: 8, + public_memory_fraction: 8, diluted_pool_instance_def: Some(DilutedPoolInstanceDef::default()), - _n_trace_colums: 73, - _cpu_instance_def: CpuInstanceDef::default(), } } } @@ -176,15 +131,11 @@ mod tests { fn get_plain_instance() { let layout = CairoLayout::plain_instance(); let builtins = BuiltinsInstanceDef::plain(); - assert_eq!(&layout._name, "plain"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "plain"); assert_eq!(layout.rc_units, 16); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 4); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 4); assert_eq!(layout.diluted_pool_instance_def, None); - assert_eq!(layout._n_trace_colums, 8); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] @@ -192,15 +143,11 @@ mod tests { fn get_small_instance() { let layout = CairoLayout::small_instance(); let builtins = BuiltinsInstanceDef::small(); - assert_eq!(&layout._name, "small"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "small"); assert_eq!(layout.rc_units, 16); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 4); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 4); assert_eq!(layout.diluted_pool_instance_def, None); - assert_eq!(layout._n_trace_colums, 25); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] @@ -208,140 +155,108 @@ mod tests { fn get_dex_instance() { let layout = CairoLayout::dex_instance(); let builtins = BuiltinsInstanceDef::dex(); - assert_eq!(&layout._name, "dex"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "dex"); assert_eq!(layout.rc_units, 4); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 4); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 4); assert_eq!(layout.diluted_pool_instance_def, None); - assert_eq!(layout._n_trace_colums, 22); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_recursive_instance() { let layout = CairoLayout::recursive_instance(); let builtins = BuiltinsInstanceDef::recursive(); - assert_eq!(&layout._name, "recursive"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "recursive"); assert_eq!(layout.rc_units, 4); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::default()) ); - assert_eq!(layout._n_trace_colums, 10); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_starknet_instance() { let layout = CairoLayout::starknet_instance(); let builtins = BuiltinsInstanceDef::starknet(); - assert_eq!(&layout._name, "starknet"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "starknet"); assert_eq!(layout.rc_units, 4); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::new(2, 4, 16)) ); - assert_eq!(layout._n_trace_colums, 10); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_starknet_with_keccak_instance() { let layout = CairoLayout::starknet_with_keccak_instance(); let builtins = BuiltinsInstanceDef::starknet_with_keccak(); - assert_eq!(&layout._name, "starknet_with_keccak"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "starknet_with_keccak"); assert_eq!(layout.rc_units, 4); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::default()) ); - assert_eq!(layout._n_trace_colums, 15); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_recursive_large_output_instance() { let layout = CairoLayout::recursive_large_output_instance(); let builtins = BuiltinsInstanceDef::recursive_large_output(); - assert_eq!(&layout._name, "recursive_large_output"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "recursive_large_output"); assert_eq!(layout.rc_units, 4); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::default()) ); - assert_eq!(layout._n_trace_colums, 13); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_all_cairo_instance() { let layout = CairoLayout::all_cairo_instance(); let builtins = BuiltinsInstanceDef::all_cairo(); - assert_eq!(&layout._name, "all_cairo"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "all_cairo"); assert_eq!(layout.rc_units, 4); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::default()) ); - assert_eq!(layout._n_trace_colums, 11); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_all_solidity_instance() { let layout = CairoLayout::all_solidity_instance(); let builtins = BuiltinsInstanceDef::all_solidity(); - assert_eq!(&layout._name, "all_solidity"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "all_solidity"); assert_eq!(layout.rc_units, 8); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::default()) ); - assert_eq!(layout._n_trace_colums, 27); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } #[test] fn get_dynamic_instance() { let layout = CairoLayout::dynamic_instance(); let builtins = BuiltinsInstanceDef::dynamic(); - assert_eq!(&layout._name, "dynamic"); - assert_eq!(layout._cpu_component_step, 1); + assert_eq!(&layout.name, "dynamic"); assert_eq!(layout.rc_units, 16); assert_eq!(layout.builtins, builtins); - assert_eq!(layout._public_memory_fraction, 8); - assert_eq!(layout._memory_units_per_step, 8); + assert_eq!(layout.public_memory_fraction, 8); assert_eq!( layout.diluted_pool_instance_def, Some(DilutedPoolInstanceDef::default()) ); - assert_eq!(layout._n_trace_colums, 73); - assert_eq!(layout._cpu_instance_def, CpuInstanceDef::default()); } } diff --git a/vm/src/types/program.rs b/vm/src/types/program.rs index 9601aee445..f5399d059a 100644 --- a/vm/src/types/program.rs +++ b/vm/src/types/program.rs @@ -13,8 +13,6 @@ use crate::{ #[cfg(feature = "cairo-1-hints")] use crate::serde::deserialize_program::{ApTracking, FlowTrackingData}; -#[cfg(feature = "cairo-1-hints")] -use crate::utils::biguint_to_felt; use crate::utils::PRIME_STR; use crate::Felt252; use crate::{ @@ -310,6 +308,22 @@ impl Program { self.shared_program_data.identifiers.get(id) } + pub fn get_relocated_instruction_locations( + &self, + relocation_table: &[usize], + ) -> Option> { + self.shared_program_data.instruction_locations.as_ref()?; + let relocated_instructions = self + .shared_program_data + .instruction_locations + .as_ref() + .unwrap() + .iter() + .map(|(k, v)| (k + relocation_table[0], v.clone())) + .collect(); + Some(relocated_instructions) + } + pub fn iter_identifiers(&self) -> impl Iterator { self.shared_program_data .identifiers @@ -406,7 +420,7 @@ impl TryFrom for Program { let data = value .bytecode .iter() - .map(|x| MaybeRelocatable::from(biguint_to_felt(&x.value).unwrap_or_default())) + .map(|x| MaybeRelocatable::from(Felt252::from(&x.value))) .collect(); //Hint data is going to be hosted processor-side, hints field will only store the pc where hints are located. // Only one pc will be stored, so the hint processor will be responsible for executing all hints for a given pc @@ -481,7 +495,7 @@ mod tests { use super::*; use crate::felt_hex; - use crate::serde::deserialize_program::{ApTracking, FlowTrackingData}; + use crate::serde::deserialize_program::{ApTracking, FlowTrackingData, InputFile, Location}; use crate::utils::test_utils::*; use assert_matches::assert_matches; @@ -947,6 +961,61 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn get_relocated_instruction_locations() { + fn build_instruction_location_for_test(start_line: u32) -> InstructionLocation { + InstructionLocation { + inst: Location { + end_line: 0, + end_col: 0, + input_file: InputFile { + filename: String::from("test"), + }, + parent_location: None, + start_line, + start_col: 0, + }, + hints: vec![], + } + } + + let reference_manager = ReferenceManager { + references: Vec::new(), + }; + let builtins: Vec = Vec::new(); + let data: Vec = vec![]; + let identifiers: HashMap = HashMap::new(); + let mut instruction_locations: HashMap = HashMap::new(); + + let il_1 = build_instruction_location_for_test(0); + let il_2 = build_instruction_location_for_test(2); + let il_3 = build_instruction_location_for_test(3); + instruction_locations.insert(5, il_1.clone()); + instruction_locations.insert(10, il_2.clone()); + instruction_locations.insert(12, il_3.clone()); + + let program = Program::new( + builtins, + data, + None, + HashMap::new(), + reference_manager, + identifiers, + Vec::new(), + Some(instruction_locations), + ) + .unwrap(); + + let relocated_instructions = program.get_relocated_instruction_locations(&[2]); + assert!(relocated_instructions.is_some()); + let relocated_instructions = relocated_instructions.unwrap(); + assert_eq!(relocated_instructions.len(), 3); + assert_eq!(relocated_instructions.get(&7), Some(&il_1)); + assert_eq!(relocated_instructions.get(&12), Some(&il_2)); + assert_eq!(relocated_instructions.get(&14), Some(&il_3)); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn iter_identifiers() { diff --git a/vm/src/types/relocatable.rs b/vm/src/types/relocatable.rs index 4bac0bba46..e569ce7707 100644 --- a/vm/src/types/relocatable.rs +++ b/vm/src/types/relocatable.rs @@ -127,6 +127,13 @@ impl AddAssign for Relocatable { } } +impl Add for Relocatable { + type Output = Result; + fn add(self, other: u32) -> Result { + self + other as usize + } +} + impl Add for Relocatable { type Output = Result; fn add(self, other: i32) -> Result { @@ -225,15 +232,8 @@ impl MaybeRelocatable { pub fn add_int(&self, other: &Felt252) -> Result { match *self { MaybeRelocatable::Int(ref value) => Ok(MaybeRelocatable::Int(value + other)), - MaybeRelocatable::RelocatableValue(ref rel) => { - let big_offset = other + rel.offset as u64; - let new_offset = big_offset.to_usize().ok_or_else(|| { - MathError::RelocatableAddFelt252OffsetExceeded(Box::new((*rel, *other))) - })?; - Ok(MaybeRelocatable::RelocatableValue(Relocatable { - segment_index: rel.segment_index, - offset: new_offset, - })) + MaybeRelocatable::RelocatableValue(rel) => { + Ok(MaybeRelocatable::RelocatableValue((rel + other)?)) } } } @@ -264,6 +264,14 @@ impl MaybeRelocatable { } } + /// Subs a usize from self + pub fn sub_usize(&self, other: usize) -> Result { + Ok(match *self { + MaybeRelocatable::Int(ref value) => MaybeRelocatable::Int(value - other as u64), + MaybeRelocatable::RelocatableValue(rel) => (rel - other)?.into(), + }) + } + /// Substracts two MaybeRelocatable values and returns the result as a MaybeRelocatable value. /// Only values of the same type may be substracted. /// Relocatable values can only be substracted if they belong to the same segment. diff --git a/vm/src/utils.rs b/vm/src/utils.rs index 7627779754..adb68cbc07 100644 --- a/vm/src/utils.rs +++ b/vm/src/utils.rs @@ -1,9 +1,7 @@ +use crate::stdlib::prelude::*; use crate::types::relocatable::Relocatable; -use crate::{stdlib::prelude::*, types::errors::math_errors::MathError}; -use core::ops::Neg; use lazy_static::lazy_static; -use num_bigint::{BigInt, BigUint, Sign, ToBigInt}; -use num_integer::Integer; +use num_bigint::BigUint; use num_traits::Num; pub const PRIME_STR: &str = "0x800000000000011000000000000000000000000000000000000000000000001"; @@ -51,36 +49,6 @@ pub fn from_relocatable_to_indexes(relocatable: Relocatable) -> (usize, usize) { } } -pub fn felt_to_biguint(felt: crate::Felt252) -> BigUint { - let big_digits = felt - .to_le_digits() - .into_iter() - .flat_map(|limb| [limb as u32, (limb >> 32) as u32]) - .collect(); - BigUint::new(big_digits) -} - -pub fn felt_to_bigint(felt: crate::Felt252) -> BigInt { - felt_to_biguint(felt).to_bigint().unwrap() -} - -pub fn biguint_to_felt(biguint: &BigUint) -> Result { - // TODO This funtions should return a Felt252 instead of a Result - Ok(crate::Felt252::from_bytes_le_slice(&biguint.to_bytes_le())) -} - -pub fn bigint_to_felt(bigint: &BigInt) -> Result { - let (sign, bytes) = bigint - .mod_floor(&CAIRO_PRIME.to_bigint().unwrap()) - .to_bytes_le(); - let felt = crate::Felt252::from_bytes_le_slice(&bytes); - if sign == Sign::Minus { - Ok(felt.neg()) - } else { - Ok(felt) - } -} - #[cfg(test)] #[macro_use] pub mod test_utils { @@ -153,14 +121,9 @@ pub mod test_utils { macro_rules! segments { ($( (($si:expr, $off:expr), $val:tt) ),* $(,)? ) => { { - let memory = memory!($( (($si, $off), $val) ),*); - $crate::vm::vm_memory::memory_segments::MemorySegmentManager { - memory, - segment_sizes: HashMap::new(), - segment_used_sizes: None, - public_memory_offsets: HashMap::new(), - } - + let mut segments = $crate::vm::vm_memory::memory_segments::MemorySegmentManager::new(); + segments.memory = memory!($( (($si, $off), $val) ),*); + segments } }; @@ -273,8 +236,11 @@ pub mod test_utils { () => {{ let mut vm = VirtualMachine::new(false); vm.builtin_runners = vec![ - $crate::vm::runners::builtin_runner::RangeCheckBuiltinRunner::new(Some(8), 8, true) - .into(), + $crate::vm::runners::builtin_runner::RangeCheckBuiltinRunner::<8>::new( + Some(8), + true, + ) + .into(), ]; vm }}; @@ -474,7 +440,7 @@ pub mod test_utils { macro_rules! exec_scopes_ref { () => { - &mut ExecutionScopes::new() + &mut crate::types::exec_scope::ExecutionScopes::new() }; } pub(crate) use exec_scopes_ref; diff --git a/vm/src/vm/context/run_context.rs b/vm/src/vm/context/run_context.rs index 32bad1fec8..d5de5d41f5 100644 --- a/vm/src/vm/context/run_context.rs +++ b/vm/src/vm/context/run_context.rs @@ -26,6 +26,10 @@ impl RunContext { self.pc } + pub fn new(pc: Relocatable, ap: usize, fp: usize) -> Self { + RunContext { pc, ap, fp } + } + pub fn compute_dst_addr( &self, instruction: &Instruction, diff --git a/vm/src/vm/errors/runner_errors.rs b/vm/src/vm/errors/runner_errors.rs index dc1533f509..b0961d69df 100644 --- a/vm/src/vm/errors/runner_errors.rs +++ b/vm/src/vm/errors/runner_errors.rs @@ -102,6 +102,30 @@ pub enum RunnerError { Trace(#[from] TraceError), #[error("EcOp builtin: Invalid Point")] InvalidPoint, + #[error("Page ({0}) is not on the expected segment {1}")] + PageNotOnSegment(Relocatable, usize), + #[error("Expected integer at address {} to be smaller than 2^{}. Got: {}.", (*.0).0, (*.0).1, (*.0).2)] + WordExceedsModBuiltinWordBitLen(Box<(Relocatable, u32, Felt252)>), + #[error("{}: Expected n >= 1. Got: {}.", (*.0).0, (*.0).1)] + ModBuiltinNLessThanOne(Box<(&'static str, usize)>), + #[error("{}: Missing value at address {}.", (*.0).0, (*.0).1)] + ModBuiltinMissingValue(Box<(&'static str, Relocatable)>), + #[error("{}: n must be <= {}", (*.0).0, (*.0).1)] + FillMemoryMaxExceeded(Box<(&'static str, usize)>), + #[error("{0}: write_n_words value must be 0 after loop")] + WriteNWordsValueNotZero(&'static str), + #[error("add_mod and mul_mod builtins must have the same n_words and word_bit_len.")] + ModBuiltinsMismatchedInstanceDef, + #[error("At least one of add_mod and mul_mod must be given.")] + FillMemoryNoBuiltinSet, + #[error("Could not fill the values table, add_mod_index={0}, mul_mod_index={1}")] + FillMemoryCoudNotFillTable(usize, usize), + #[error("{}: {}", (*.0).0, (*.0).1)] + ModBuiltinSecurityCheck(Box<(&'static str, String)>), + #[error("{0} is missing")] + MissingBuiltin(&'static str), + #[error("The stop pointer of the missing builtin {0} must be 0")] + MissingBuiltinStopPtrNotZero(&'static str), } #[cfg(test)] diff --git a/vm/src/vm/errors/vm_errors.rs b/vm/src/vm/errors/vm_errors.rs index db8f0278e4..68b8ceed45 100644 --- a/vm/src/vm/errors/vm_errors.rs +++ b/vm/src/vm/errors/vm_errors.rs @@ -81,10 +81,14 @@ pub enum VirtualMachineError { InconsistentAutoDeduction(Box<(&'static str, MaybeRelocatable, Option)>), #[error("Invalid hint encoding at pc: {0}")] InvalidHintEncoding(Box), + #[error("Expected output builtin to be present")] + NoOutputBuiltin, #[error("Expected range_check builtin to be present")] NoRangeCheckBuiltin, #[error("Expected ecdsa builtin to be present")] NoSignatureBuiltin, + #[error("Expected {0} to be present")] + NoModBuiltin(&'static str), #[error("Div out of range: 0 < {} <= {}", (*.0).0, (*.0).1)] OutOfValidRange(Box<(Felt252, Felt252)>), #[error("Failed to compare {} and {}, cant compare a relocatable to an integer value", (*.0).0, (*.0).1)] @@ -129,6 +133,8 @@ pub enum VirtualMachineError { FailedToWriteOutput, #[error("Failed to find index {0} in the vm's relocation table")] RelocationNotFound(usize), + #[error("{} batch size is not {}", (*.0).0, (*.0).1)] + ModBuiltinBatchSize(Box<(&'static str, usize)>), } #[cfg(test)] diff --git a/vm/src/vm/errors/vm_exception.rs b/vm/src/vm/errors/vm_exception.rs index 6e4e762ef4..f8ab67088c 100644 --- a/vm/src/vm/errors/vm_exception.rs +++ b/vm/src/vm/errors/vm_exception.rs @@ -659,7 +659,7 @@ mod test { let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -673,7 +673,7 @@ mod test { let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -711,7 +711,7 @@ cairo_programs/bad_programs/bad_usort.cairo:64:5: (pc=0:60) let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -870,7 +870,7 @@ cairo_programs/bad_programs/bad_range_check.cairo:11:5: (pc=0:6) let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); let error = cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .unwrap_err(); @@ -915,7 +915,7 @@ cairo_programs/bad_programs/bad_usort.cairo:64:5: (pc=0:60) let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); let error = cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .unwrap_err(); @@ -954,7 +954,7 @@ cairo_programs/bad_programs/ec_recover_product_mod_m_zero.cairo:11:5: (pc=0:18) let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); let error = cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .unwrap_err(); @@ -993,7 +993,7 @@ cairo_programs/bad_programs/ec_recover_div_mod_n_packed_n_zero.cairo:11:5: (pc=0 let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); let error = cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .unwrap_err(); @@ -1032,7 +1032,7 @@ cairo_programs/bad_programs/uint512_unsigned_div_rem_div_is_zero.cairo:15:2: (pc let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); let error = cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .unwrap_err(); @@ -1069,7 +1069,7 @@ cairo_programs/bad_programs/uint256_sub_b_gt_256.cairo:10:2: (pc=0:12) let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); let error = cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .unwrap_err(); diff --git a/vm/src/vm/hooks.rs b/vm/src/vm/hooks.rs index d2f88e7eb7..13c7bb86ce 100644 --- a/vm/src/vm/hooks.rs +++ b/vm/src/vm/hooks.rs @@ -131,7 +131,7 @@ mod tests { let mut vm = vm!(); vm.hooks = Hooks::new(None, None, None); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_ok()); @@ -179,7 +179,7 @@ mod tests { let mut vm = vm!(); vm.hooks = Hooks::new(Some(Arc::new(before_first_step_hook)), None, None); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -190,7 +190,7 @@ mod tests { let mut vm = vm!(); vm.hooks = Hooks::new(None, Some(Arc::new(pre_step_hook)), None); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -201,7 +201,7 @@ mod tests { let mut vm = vm!(); vm.hooks = Hooks::new(None, None, Some(Arc::new(post_step_hook))); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -252,7 +252,7 @@ mod tests { Some(Arc::new(post_step_hook)), ); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_ok()); diff --git a/vm/src/vm/runners/builtin_runner/bitwise.rs b/vm/src/vm/runners/builtin_runner/bitwise.rs index 825aab3942..e5901194db 100644 --- a/vm/src/vm/runners/builtin_runner/bitwise.rs +++ b/vm/src/vm/runners/builtin_runner/bitwise.rs @@ -3,9 +3,7 @@ use crate::stdlib::{boxed::Box, vec::Vec}; use crate::Felt252; use crate::{ types::{ - instance_definitions::bitwise_instance_def::{ - BitwiseInstanceDef, CELLS_PER_BITWISE, INPUT_CELLS_PER_BITWISE, - }, + instance_definitions::bitwise_instance_def::{CELLS_PER_BITWISE, TOTAL_N_BITS}, relocatable::{MaybeRelocatable, Relocatable}, }, vm::{ @@ -15,31 +13,21 @@ use crate::{ }; use num_integer::div_ceil; -use super::BITWISE_BUILTIN_NAME; - #[derive(Debug, Clone)] pub struct BitwiseBuiltinRunner { ratio: Option, pub base: usize, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, - bitwise_builtin: BitwiseInstanceDef, pub(crate) stop_ptr: Option, pub(crate) included: bool, - pub(crate) instances_per_component: u32, } impl BitwiseBuiltinRunner { - pub(crate) fn new(instance_def: &BitwiseInstanceDef, included: bool) -> Self { + pub(crate) fn new(ratio: Option, included: bool) -> Self { BitwiseBuiltinRunner { base: 0, - ratio: instance_def.ratio, - cells_per_instance: CELLS_PER_BITWISE, - n_input_cells: INPUT_CELLS_PER_BITWISE, - bitwise_builtin: instance_def.clone(), + ratio, stop_ptr: None, included, - instances_per_component: 1, } } @@ -63,21 +51,20 @@ impl BitwiseBuiltinRunner { self.ratio } - pub fn add_validation_rule(&self, _memory: &mut Memory) {} - pub fn deduce_memory_cell( &self, address: Relocatable, memory: &Memory, ) -> Result, RunnerError> { - let index = address.offset % self.cells_per_instance as usize; + let index = address.offset % CELLS_PER_BITWISE as usize; if index <= 1 { return Ok(None); } let x_addr = (address - index)?; let y_addr = (x_addr + 1_usize)?; - let (Ok(num_x), Ok(num_y)) = (memory.get_integer(x_addr), memory.get_integer(y_addr)) else { + let (Ok(num_x), Ok(num_y)) = (memory.get_integer(x_addr), memory.get_integer(y_addr)) + else { return Ok(None); }; @@ -89,7 +76,7 @@ impl BitwiseBuiltinRunner { if limbs[3] & LEADING_BITS != 0 { return Err(RunnerError::IntegerBiggerThanPowerOfTwo(Box::new(( x_addr, - self.bitwise_builtin.total_n_bits, + TOTAL_N_BITS, *x, )))); } @@ -120,10 +107,6 @@ impl BitwiseBuiltinRunner { )))) } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base) @@ -131,7 +114,7 @@ impl BitwiseBuiltinRunner { } pub fn get_used_diluted_check_units(&self, diluted_spacing: u32, diluted_n_bits: u32) -> usize { - let total_n_bits = self.bitwise_builtin.total_n_bits; + let total_n_bits = TOTAL_N_BITS; let mut partition = Vec::with_capacity(total_n_bits as usize); for i in (0..total_n_bits).step_by((diluted_spacing * diluted_n_bits) as usize) { for j in 0..diluted_spacing { @@ -148,49 +131,12 @@ impl BitwiseBuiltinRunner { 4 * partition_lengh + num_trimmed } - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(BITWISE_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(BITWISE_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - BITWISE_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - BITWISE_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } - } - pub fn get_used_instances( &self, segments: &MemorySegmentManager, ) -> Result { let used_cells = self.get_used_cells(segments)?; - Ok(div_ceil(used_cells, self.cells_per_instance as usize)) + Ok(div_ceil(used_cells, CELLS_PER_BITWISE as usize)) } pub fn air_private_input(&self, memory: &Memory) -> Vec { @@ -223,9 +169,8 @@ mod tests { use super::*; use crate::relocatable; use crate::serde::deserialize_program::BuiltinName; - use crate::stdlib::collections::HashMap; use crate::vm::errors::memory_errors::MemoryError; - use crate::vm::runners::builtin_runner::BuiltinRunner; + use crate::vm::runners::builtin_runner::{BuiltinRunner, BITWISE_BUILTIN_NAME}; use crate::vm::vm_core::VirtualMachine; use crate::Felt252; use crate::{ @@ -239,7 +184,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_instances() { - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let builtin = BitwiseBuiltinRunner::new(Some(10), true); let mut vm = vm!(); @@ -258,7 +203,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -282,7 +227,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -310,7 +255,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_when_notincluded() { - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), false); + let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), false).into(); let mut vm = vm!(); @@ -334,7 +279,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let mut builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -358,8 +303,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_and_allocated_size_test() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true).into(); + let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -393,7 +337,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -405,8 +349,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true).into(); + let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -438,7 +381,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -451,7 +394,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_bitwise_for_preset_memory_valid_and() { let memory = memory![((0, 5), 10), ((0, 6), 12), ((0, 7), 0)]; - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let builtin = BitwiseBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 7)), &memory); assert_eq!(result, Ok(Some(MaybeRelocatable::from(Felt252::from(8))))); } @@ -460,7 +403,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_bitwise_for_preset_memory_valid_xor() { let memory = memory![((0, 5), 10), ((0, 6), 12), ((0, 8), 0)]; - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let builtin = BitwiseBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 8)), &memory); assert_eq!(result, Ok(Some(MaybeRelocatable::from(Felt252::from(6))))); } @@ -469,7 +412,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_bitwise_for_preset_memory_valid_or() { let memory = memory![((0, 5), 10), ((0, 6), 12), ((0, 9), 0)]; - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let builtin = BitwiseBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 9)), &memory); assert_eq!(result, Ok(Some(MaybeRelocatable::from(Felt252::from(14))))); } @@ -478,7 +421,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_bitwise_for_preset_memory_incorrect_offset() { let memory = memory![((0, 3), 10), ((0, 4), 12), ((0, 5), 0)]; - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let builtin = BitwiseBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory); assert_eq!(result, Ok(None)); } @@ -487,75 +430,15 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_bitwise_for_preset_memory_no_values_to_operate() { let memory = memory![((0, 5), 12), ((0, 7), 0)]; - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let builtin = BitwiseBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory); assert_eq!(result, Ok(None)); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None),); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let vm = vm!(); assert_eq!( @@ -567,10 +450,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_empty() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); @@ -580,10 +460,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); @@ -593,40 +470,30 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_a() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); assert_eq!(builtin.get_used_diluted_check_units(12, 2), 535); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_b() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); assert_eq!(builtin.get_used_diluted_check_units(30, 56), 150); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_c() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); assert_eq!(builtin.get_used_diluted_check_units(50, 25), 250); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_air_private_input() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into(); - let memory = memory![ + let segments = segments![ ((0, 0), 0), ((0, 1), 1), ((0, 2), 2), @@ -644,7 +511,7 @@ mod tests { ((0, 14), 14) ]; assert_eq!( - builtin.air_private_input(&memory), + builtin.air_private_input(&segments), (vec![ PrivateInput::Pair(PrivateInputPair { index: 0, diff --git a/vm/src/vm/runners/builtin_runner/ec_op.rs b/vm/src/vm/runners/builtin_runner/ec_op.rs index c824f0153d..8dd50f0ffa 100644 --- a/vm/src/vm/runners/builtin_runner/ec_op.rs +++ b/vm/src/vm/runners/builtin_runner/ec_op.rs @@ -2,7 +2,7 @@ use crate::air_private_input::{PrivateInput, PrivateInputEcOp}; use crate::stdlib::{borrow::Cow, prelude::*}; use crate::stdlib::{cell::RefCell, collections::HashMap}; use crate::types::instance_definitions::ec_op_instance_def::{ - EcOpInstanceDef, CELLS_PER_EC_OP, INPUT_CELLS_PER_EC_OP, + CELLS_PER_EC_OP, INPUT_CELLS_PER_EC_OP, SCALAR_HEIGHT, }; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::MemoryError; @@ -13,32 +13,22 @@ use crate::Felt252; use num_integer::{div_ceil, Integer}; use starknet_types_core::curve::ProjectivePoint; -use super::EC_OP_BUILTIN_NAME; - #[derive(Debug, Clone)] pub struct EcOpBuiltinRunner { ratio: Option, pub base: usize, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, - ec_op_builtin: EcOpInstanceDef, pub(crate) stop_ptr: Option, pub(crate) included: bool, - pub(crate) instances_per_component: u32, cache: RefCell>, } impl EcOpBuiltinRunner { - pub(crate) fn new(instance_def: &EcOpInstanceDef, included: bool) -> Self { + pub(crate) fn new(ratio: Option, included: bool) -> Self { EcOpBuiltinRunner { base: 0, - ratio: instance_def.ratio, - n_input_cells: INPUT_CELLS_PER_EC_OP, - cells_per_instance: CELLS_PER_EC_OP, - ec_op_builtin: instance_def.clone(), + ratio, stop_ptr: None, included, - instances_per_component: 1, cache: RefCell::new(HashMap::new()), } } @@ -104,8 +94,6 @@ impl EcOpBuiltinRunner { self.ratio } - pub fn add_validation_rule(&self, _memory: &mut Memory) {} - pub fn deduce_memory_cell( &self, address: Relocatable, @@ -119,9 +107,7 @@ impl EcOpBuiltinRunner { let beta_high: Felt252 = Felt252::from(0x6f21413efbe40de150e596d72f7a8c5_u128); let beta: Felt252 = (beta_high * (Felt252::ONE + Felt252::from(u128::MAX))) + beta_low; - let index = address - .offset - .mod_floor(&(self.cells_per_instance as usize)); + let index = address.offset.mod_floor(&(CELLS_PER_EC_OP as usize)); //Index should be an output cell if index != OUTPUT_INDICES.0 && index != OUTPUT_INDICES.1 { return Ok(None); @@ -136,8 +122,8 @@ impl EcOpBuiltinRunner { //All input cells should be filled, and be integer values //If an input cell is not filled, return None - let mut input_cells = Vec::<&Felt252>::with_capacity(self.n_input_cells as usize); - for i in 0..self.n_input_cells as usize { + let mut input_cells = Vec::<&Felt252>::with_capacity(INPUT_CELLS_PER_EC_OP as usize); + for i in 0..INPUT_CELLS_PER_EC_OP as usize { match memory.get(&(instance + i)?) { None => return Ok(None), Some(addr) => { @@ -178,7 +164,7 @@ impl EcOpBuiltinRunner { (input_cells[0].to_owned(), input_cells[1].to_owned()), (input_cells[2].to_owned(), input_cells[3].to_owned()), input_cells[4], - self.ec_op_builtin.scalar_height, + SCALAR_HEIGHT, )?; self.cache.borrow_mut().insert(x_addr, result.0); self.cache.borrow_mut().insert( @@ -186,17 +172,13 @@ impl EcOpBuiltinRunner { .map_err(|_| RunnerError::Memory(MemoryError::ExpectedInteger(Box::new(x_addr))))?, result.1, ); - match index - self.n_input_cells as usize { + match index - INPUT_CELLS_PER_EC_OP as usize { 0 => Ok(Some(MaybeRelocatable::Int(result.0))), _ => Ok(Some(MaybeRelocatable::Int(result.1))), //Default case corresponds to 1, as there are no other possible cases } } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base()) @@ -208,44 +190,7 @@ impl EcOpBuiltinRunner { segments: &MemorySegmentManager, ) -> Result { let used_cells = self.get_used_cells(segments)?; - Ok(div_ceil(used_cells, self.cells_per_instance as usize)) - } - - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(EC_OP_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(EC_OP_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - EC_OP_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - EC_OP_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } + Ok(div_ceil(used_cells, CELLS_PER_EC_OP as usize)) } pub fn format_ec_op_error( @@ -298,11 +243,11 @@ mod tests { use super::*; use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; use crate::serde::deserialize_program::BuiltinName; - use crate::stdlib::collections::HashMap; use crate::types::program::Program; use crate::utils::test_utils::*; use crate::vm::errors::cairo_run_errors::CairoRunError; use crate::vm::errors::vm_errors::VirtualMachineError; + use crate::vm::runners::builtin_runner::EC_OP_BUILTIN_NAME; use crate::vm::runners::cairo_runner::CairoRunner; use crate::{felt_hex, felt_str, relocatable}; @@ -319,7 +264,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_instances() { - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), true); + let builtin = EcOpBuiltinRunner::new(Some(10), true); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![1]); @@ -330,7 +275,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), true); + let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -354,7 +299,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), true); + let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -382,7 +327,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_when_notincluded() { - let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), false); + let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), false).into(); let mut vm = vm!(); @@ -406,7 +351,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), true); + let mut builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -430,8 +375,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_and_allocated_size_test() { - let builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), true).into(); + let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -464,7 +408,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -476,8 +420,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units() { - let builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(10)), true).into(); + let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -509,7 +452,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -696,7 +639,7 @@ mod tests { ) ) ]; - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let builtin = EcOpBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((3, 6)), &memory); assert_eq!( @@ -742,7 +685,7 @@ mod tests { ) ]; - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let builtin = EcOpBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((3, 6)), &memory); assert_eq!(result, Ok(None)); } @@ -788,7 +731,7 @@ mod tests { ) ) ]; - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let builtin = EcOpBuiltinRunner::new(Some(256), true); let result = builtin.deduce_memory_cell(Relocatable::from((3, 3)), &memory); assert_eq!(result, Ok(None)); @@ -829,7 +772,7 @@ mod tests { ) ) ]; - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let builtin = EcOpBuiltinRunner::new(Some(256), true); assert_eq!( builtin.deduce_memory_cell(Relocatable::from((3, 6)), &memory), @@ -839,62 +782,10 @@ mod tests { ); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None)); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true)); let vm = vm!(); assert_eq!( @@ -906,8 +797,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_empty() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); @@ -917,8 +807,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); @@ -928,15 +817,14 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initial_stackincluded_test() { - let ec_op_builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); assert_eq!(ec_op_builtin.initial_stack(), vec![mayberelocatable!(0, 0)]) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initial_stack_notincluded_test() { - let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), false); + let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), false); assert_eq!(ec_op_builtin.initial_stack(), Vec::new()) } @@ -994,10 +882,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_air_private_input() { - let builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); - let memory = memory![ + let segments = segments![ ((0, 0), 0), ((0, 1), 1), ((0, 2), 2), @@ -1005,7 +892,7 @@ mod tests { ((0, 4), 4) ]; assert_eq!( - builtin.air_private_input(&memory), + builtin.air_private_input(&segments), (vec![PrivateInput::EcOp(PrivateInputEcOp { index: 0, p_x: 0.into(), diff --git a/vm/src/vm/runners/builtin_runner/hash.rs b/vm/src/vm/runners/builtin_runner/hash.rs index f8e8fbe333..a6d045ade2 100644 --- a/vm/src/vm/runners/builtin_runner/hash.rs +++ b/vm/src/vm/runners/builtin_runner/hash.rs @@ -1,9 +1,7 @@ use crate::air_private_input::{PrivateInput, PrivateInputPair}; use crate::stdlib::{cell::RefCell, prelude::*}; use crate::types::errors::math_errors::MathError; -use crate::types::instance_definitions::pedersen_instance_def::{ - CELLS_PER_HASH, INPUT_CELLS_PER_HASH, -}; +use crate::types::instance_definitions::pedersen_instance_def::CELLS_PER_HASH; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::MemoryError; use crate::vm::errors::runner_errors::RunnerError; @@ -14,17 +12,12 @@ use crate::Felt252; use num_integer::{div_ceil, Integer}; use starknet_crypto::{pedersen_hash, FieldElement}; -use super::HASH_BUILTIN_NAME; - #[derive(Debug, Clone)] pub struct HashBuiltinRunner { pub base: usize, ratio: Option, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, pub(crate) stop_ptr: Option, pub(crate) included: bool, - pub(crate) instances_per_component: u32, // This act as a cache to optimize calls to deduce_memory_cell // Therefore need interior mutability // 1 at position 'n' means offset 'n' relative to base pointer @@ -37,12 +30,9 @@ impl HashBuiltinRunner { HashBuiltinRunner { base: 0, ratio, - cells_per_instance: CELLS_PER_HASH, - n_input_cells: INPUT_CELLS_PER_HASH, stop_ptr: None, verified_addresses: RefCell::new(Vec::new()), included, - instances_per_component: 1, } } @@ -66,17 +56,12 @@ impl HashBuiltinRunner { self.ratio } - pub fn add_validation_rule(&self, _memory: &mut Memory) {} - pub fn deduce_memory_cell( &self, address: Relocatable, memory: &Memory, ) -> Result, RunnerError> { - if address - .offset - .mod_floor(&(self.cells_per_instance as usize)) - != 2 + if address.offset.mod_floor(&(CELLS_PER_HASH as usize)) != 2 || *self .verified_addresses .borrow() @@ -124,10 +109,6 @@ impl HashBuiltinRunner { Ok(None) } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base()) @@ -139,44 +120,7 @@ impl HashBuiltinRunner { segments: &MemorySegmentManager, ) -> Result { let used_cells = self.get_used_cells(segments)?; - Ok(div_ceil(used_cells, self.cells_per_instance as usize)) - } - - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(HASH_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(HASH_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - HASH_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - HASH_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } + Ok(div_ceil(used_cells, CELLS_PER_HASH as usize)) } pub fn get_additional_data(&self) -> BuiltinAdditionalData { @@ -219,9 +163,9 @@ mod tests { use super::*; use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; use crate::serde::deserialize_program::BuiltinName; - use crate::stdlib::collections::HashMap; use crate::types::program::Program; use crate::utils::test_utils::*; + use crate::vm::runners::builtin_runner::HASH_BUILTIN_NAME; use crate::vm::runners::cairo_runner::CairoRunner; use crate::{felt_hex, relocatable}; @@ -247,7 +191,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = HashBuiltinRunner::new(Some(10), true); + let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -271,7 +215,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = HashBuiltinRunner::new(Some(10), true); + let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -299,7 +243,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_when_not_included() { - let mut builtin = HashBuiltinRunner::new(Some(10), false); + let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), false).into(); let mut vm = vm!(); @@ -323,7 +267,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = HashBuiltinRunner::new(Some(10), true); + let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -381,7 +325,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -425,7 +369,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -481,54 +425,6 @@ mod tests { assert_eq!(result, Ok(None)); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = HashBuiltinRunner::new(Some(256), true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None),); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true)); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = BuiltinRunner::Hash(HashBuiltinRunner::new(Some(256), true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { @@ -578,7 +474,7 @@ mod tests { fn get_air_private_input() { let builtin: BuiltinRunner = HashBuiltinRunner::new(None, true).into(); - let memory = memory![ + let segments = segments![ ((0, 0), 0), ((0, 1), 1), ((0, 2), 2), @@ -591,7 +487,7 @@ mod tests { ((0, 9), 9) ]; assert_eq!( - builtin.air_private_input(&memory), + builtin.air_private_input(&segments), (vec![ PrivateInput::Pair(PrivateInputPair { index: 0, diff --git a/vm/src/vm/runners/builtin_runner/keccak.rs b/vm/src/vm/runners/builtin_runner/keccak.rs index 244efa866d..93daf92f82 100644 --- a/vm/src/vm/runners/builtin_runner/keccak.rs +++ b/vm/src/vm/runners/builtin_runner/keccak.rs @@ -1,45 +1,43 @@ use crate::air_private_input::{PrivateInput, PrivateInputKeccakState}; use crate::math_utils::safe_div_usize; use crate::stdlib::{cell::RefCell, collections::HashMap, prelude::*}; -use crate::types::instance_definitions::keccak_instance_def::KeccakInstanceDef; +use crate::types::instance_definitions::keccak_instance_def::{ + CELLS_PER_KECCAK, INPUT_CELLS_PER_KECCAK, +}; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::MemoryError; use crate::vm::errors::runner_errors::RunnerError; -use crate::vm::vm_core::VirtualMachine; use crate::vm::vm_memory::memory::Memory; use crate::vm::vm_memory::memory_segments::MemorySegmentManager; use crate::Felt252; +use lazy_static::lazy_static; use num_bigint::BigUint; use num_integer::div_ceil; use super::KECCAK_BUILTIN_NAME; const KECCAK_FELT_BYTE_SIZE: usize = 25; // 200 / 8 +const BITS: u32 = 200; +lazy_static! { + static ref KECCAK_INPUT_MAX: Felt252 = Felt252::TWO.pow(BITS); +} #[derive(Debug, Clone)] pub struct KeccakBuiltinRunner { ratio: Option, pub base: usize, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, pub(crate) stop_ptr: Option, pub(crate) included: bool, - state_rep: Vec, - pub(crate) instances_per_component: u32, cache: RefCell>, } impl KeccakBuiltinRunner { - pub(crate) fn new(instance_def: &KeccakInstanceDef, included: bool) -> Self { + pub(crate) fn new(ratio: Option, included: bool) -> Self { KeccakBuiltinRunner { base: 0, - ratio: instance_def.ratio, - n_input_cells: instance_def._state_rep.len() as u32, - cells_per_instance: instance_def.cells_per_builtin(), + ratio, stop_ptr: None, included, - instances_per_component: instance_def._instance_per_component, - state_rep: instance_def._state_rep.clone(), cache: RefCell::new(HashMap::new()), } } @@ -64,26 +62,24 @@ impl KeccakBuiltinRunner { self.ratio } - pub fn add_validation_rule(&self, _memory: &mut Memory) {} - pub fn deduce_memory_cell( &self, address: Relocatable, memory: &Memory, ) -> Result, RunnerError> { - let index = address.offset % self.cells_per_instance as usize; - if index < self.n_input_cells as usize { + let index = address.offset % CELLS_PER_KECCAK as usize; + if index < INPUT_CELLS_PER_KECCAK as usize { return Ok(None); } if let Some(felt) = self.cache.borrow().get(&address) { return Ok(Some(felt.into())); } let first_input_addr = (address - index)?; - let first_output_addr = (first_input_addr + self.n_input_cells as usize)?; + let first_output_addr = (first_input_addr + INPUT_CELLS_PER_KECCAK as usize)?; let mut input_felts = vec![]; - for i in 0..self.n_input_cells as usize { + for i in 0..INPUT_CELLS_PER_KECCAK as usize { let m_index = (first_input_addr + i)?; let val = match memory.get(&m_index) { Some(value) => { @@ -93,10 +89,10 @@ impl KeccakBuiltinRunner { KECCAK_BUILTIN_NAME, (first_input_addr + i)?, ))))?; - if num >= &(Felt252::TWO.pow(self.state_rep[i])) { + if num >= &KECCAK_INPUT_MAX { return Err(RunnerError::IntegerBiggerThanPowerOfTwo(Box::new(( (first_input_addr + i)?, - self.state_rep[i], + BITS, *num, )))); } @@ -117,8 +113,8 @@ impl KeccakBuiltinRunner { let keccak_result = Self::keccak_f(&input_message)?; let mut start_index = 0_usize; - for (i, bits) in self.state_rep.iter().enumerate() { - let end_index = start_index + *bits as usize / 8; + for i in 0..INPUT_CELLS_PER_KECCAK { + let end_index = start_index + BITS as usize / 8; self.cache.borrow_mut().insert((first_output_addr + i)?, { let mut bytes = keccak_result[start_index..end_index].to_vec(); bytes.resize(32, 0); @@ -129,10 +125,6 @@ impl KeccakBuiltinRunner { Ok(self.cache.borrow().get(&address).map(|x| x.into())) } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base()) @@ -144,58 +136,7 @@ impl KeccakBuiltinRunner { segments: &MemorySegmentManager, ) -> Result { let used_cells = self.get_used_cells(segments)?; - Ok(div_ceil(used_cells, self.cells_per_instance as usize)) - } - - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(KECCAK_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(KECCAK_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - KECCAK_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - KECCAK_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } - } - - pub fn get_memory_accesses( - &self, - vm: &VirtualMachine, - ) -> Result, MemoryError> { - let segment_size = vm - .segments - .get_segment_size(self.base) - .ok_or(MemoryError::MissingSegmentUsedSizes)?; - - Ok((0..segment_size) - .map(|i| (self.base as isize, i).into()) - .collect()) + Ok(div_ceil(used_cells, CELLS_PER_KECCAK as usize)) } pub fn get_used_diluted_check_units(&self, diluted_n_bits: u32) -> usize { @@ -227,7 +168,7 @@ impl KeccakBuiltinRunner { if let Some(segment) = memory.data.get(self.base) { let segment_len = segment.len(); for (index, off) in (0..segment_len) - .step_by(self.cells_per_instance as usize) + .step_by(CELLS_PER_KECCAK as usize) .enumerate() { // Add the input cells of each keccak instance to the private inputs @@ -272,7 +213,6 @@ impl KeccakBuiltinRunner { mod tests { use super::*; use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; - use crate::stdlib::collections::HashMap; use crate::types::program::Program; use crate::utils::test_utils::*; use crate::vm::runners::cairo_runner::CairoRunner; @@ -290,8 +230,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_instances() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![1]); @@ -302,8 +241,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), true); + let mut builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -327,8 +265,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), true); + let mut builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -355,8 +292,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_when_not_included() { - let mut builtin = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), false); + let mut builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), false).into(); let mut vm = vm!(); @@ -380,8 +316,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), true); + let mut builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -405,8 +340,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_and_allocated_size_test() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -421,7 +355,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -436,8 +370,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(10), vec![200; 8]), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); vm.current_step = 160; @@ -445,59 +378,10 @@ mod tests { assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(256)); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None)); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(2048), true).into(); let vm = vm!(); assert_eq!( @@ -509,8 +393,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_empty() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(2048), true).into(); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); @@ -520,8 +403,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(2048), true).into(); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); @@ -531,7 +413,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initial_stackincluded_test() { - let keccak_builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let keccak_builtin = KeccakBuiltinRunner::new(Some(2048), true); assert_eq!( keccak_builtin.initial_stack(), vec![mayberelocatable!(0, 0)] @@ -541,7 +423,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initial_stack_notincluded_test() { - let keccak_builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), false); + let keccak_builtin = KeccakBuiltinRunner::new(Some(2048), false); assert_eq!(keccak_builtin.initial_stack(), Vec::new()) } @@ -570,7 +452,7 @@ mod tests { ((0, 34), 0), ((0, 35), 0) ]; - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 25)), &memory); assert_eq!( @@ -591,7 +473,7 @@ mod tests { ((0, 7), 120), ((0, 8), 52) ]; - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 1)), &memory); assert_eq!(result, Ok(None)); } @@ -600,7 +482,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_offset_lt_input_cell_length_none() { let memory = memory![((0, 4), 32)]; - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 2)), &memory); assert_eq!(result, Ok(None)); } @@ -610,12 +492,9 @@ mod tests { fn deduce_memory_cell_expected_integer() { let memory = memory![((0, 0), (1, 2))]; - let mut builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let builtin = KeccakBuiltinRunner::new(Some(2048), true); - builtin.n_input_cells = 1; - builtin.cells_per_instance = 100; - - let result = builtin.deduce_memory_cell(Relocatable::from((0, 1)), &memory); + let result = builtin.deduce_memory_cell(Relocatable::from((0, 9)), &memory); assert_eq!( result, @@ -631,37 +510,19 @@ mod tests { fn deduce_memory_cell_missing_input_cells() { let memory = memory![((0, 1), (1, 2))]; - let mut builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - - builtin.n_input_cells = 1; - builtin.cells_per_instance = 100; + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 1)), &memory); assert_eq!(result, Ok(None)); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn deduce_memory_cell_input_cell() { - let memory = memory![((0, 0), (1, 2))]; - - let mut builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - - builtin.n_input_cells = 1; - builtin.cells_per_instance = 100; - - let result = builtin.deduce_memory_cell(Relocatable::from((0, 0)), &memory); - - assert_eq!(result, Ok(None)); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_get_memory_err() { let memory = memory![((0, 35), 0)]; - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 15)), &memory); @@ -671,8 +532,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_memory_int_larger_than_bits() { - let memory = memory![ - ((0, 16), 43), + let mut memory = memory![ ((0, 17), 199), ((0, 18), 0), ((0, 19), 0), @@ -694,8 +554,9 @@ mod tests { ((0, 35), 0) ]; - let keccak_instance = KeccakInstanceDef::new(Some(2048), vec![1; 8]); - let builtin = KeccakBuiltinRunner::new(&keccak_instance, true); + memory.insert((0, 16).into(), Felt252::MAX).unwrap(); + + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result = builtin.deduce_memory_cell(Relocatable::from((0, 25)), &memory); @@ -703,8 +564,8 @@ mod tests { result, Err(RunnerError::IntegerBiggerThanPowerOfTwo(Box::new(( (0, 16).into(), - 1, - 43.into() + BITS, + Felt252::MAX )))) ); } @@ -712,7 +573,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_result() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); + let builtin = KeccakBuiltinRunner::new(Some(2048), true); let result: usize = builtin.get_used_diluted_check_units(16); @@ -730,10 +591,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_air_private_input() { - let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(2048), true).into(); - let memory = memory![ + let segments = segments![ ((0, 0), 0), ((0, 1), 1), ((0, 2), 2), @@ -744,7 +604,7 @@ mod tests { ((0, 7), 7) ]; assert_eq!( - builtin.air_private_input(&memory), + builtin.air_private_input(&segments), (vec![PrivateInput::KeccakState(PrivateInputKeccakState { index: 0, input_s0: 0.into(), diff --git a/vm/src/vm/runners/builtin_runner/mod.rs b/vm/src/vm/runners/builtin_runner/mod.rs index 99778c6333..e034ed46e4 100644 --- a/vm/src/vm/runners/builtin_runner/mod.rs +++ b/vm/src/vm/runners/builtin_runner/mod.rs @@ -1,6 +1,26 @@ use crate::air_private_input::PrivateInput; use crate::math_utils::safe_div_usize; +use crate::serde::deserialize_program::BuiltinName; use crate::stdlib::prelude::*; +use crate::types::instance_definitions::bitwise_instance_def::{ + CELLS_PER_BITWISE, INPUT_CELLS_PER_BITWISE, +}; +use crate::types::instance_definitions::builtins_instance_def::BUILTIN_INSTANCES_PER_COMPONENT; +use crate::types::instance_definitions::ec_op_instance_def::{ + CELLS_PER_EC_OP, INPUT_CELLS_PER_EC_OP, +}; +use crate::types::instance_definitions::ecdsa_instance_def::CELLS_PER_SIGNATURE; +use crate::types::instance_definitions::keccak_instance_def::{ + CELLS_PER_KECCAK, INPUT_CELLS_PER_KECCAK, KECCAK_INSTANCES_PER_COMPONENT, +}; +use crate::types::instance_definitions::mod_instance_def::CELLS_PER_MOD; +use crate::types::instance_definitions::pedersen_instance_def::{ + CELLS_PER_HASH, INPUT_CELLS_PER_HASH, +}; +use crate::types::instance_definitions::poseidon_instance_def::{ + CELLS_PER_POSEIDON, INPUT_CELLS_PER_POSEIDON, +}; +use crate::types::instance_definitions::range_check_instance_def::CELLS_PER_RANGE_CHECK; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::{self, InsufficientAllocatedCellsError, MemoryError}; use crate::vm::errors::runner_errors::RunnerError; @@ -13,21 +33,25 @@ mod bitwise; mod ec_op; mod hash; mod keccak; +mod modulo; mod output; mod poseidon; mod range_check; mod segment_arena; mod signature; -pub use self::keccak::KeccakBuiltinRunner; -pub use self::poseidon::PoseidonBuiltinRunner; -pub use self::segment_arena::SegmentArenaBuiltinRunner; +pub(crate) use self::range_check::{RC_N_PARTS_96, RC_N_PARTS_STANDARD}; +use self::segment_arena::ARENA_BUILTIN_SIZE; pub use bitwise::BitwiseBuiltinRunner; pub use ec_op::EcOpBuiltinRunner; pub use hash::HashBuiltinRunner; +pub use keccak::KeccakBuiltinRunner; +pub use modulo::ModBuiltinRunner; use num_integer::div_floor; pub use output::OutputBuiltinRunner; +pub use poseidon::PoseidonBuiltinRunner; pub use range_check::RangeCheckBuiltinRunner; +pub use segment_arena::SegmentArenaBuiltinRunner; pub use signature::SignatureBuiltinRunner; use super::cairo_pie::BuiltinAdditionalData; @@ -35,12 +59,15 @@ use super::cairo_pie::BuiltinAdditionalData; pub const OUTPUT_BUILTIN_NAME: &str = "output_builtin"; pub const HASH_BUILTIN_NAME: &str = "pedersen_builtin"; pub const RANGE_CHECK_BUILTIN_NAME: &str = "range_check_builtin"; +pub const RANGE_CHECK_96_BUILTIN_NAME: &str = "range_check_96_builtin"; pub const SIGNATURE_BUILTIN_NAME: &str = "ecdsa_builtin"; pub const BITWISE_BUILTIN_NAME: &str = "bitwise_builtin"; pub const EC_OP_BUILTIN_NAME: &str = "ec_op_builtin"; pub const KECCAK_BUILTIN_NAME: &str = "keccak_builtin"; pub const POSEIDON_BUILTIN_NAME: &str = "poseidon_builtin"; pub const SEGMENT_ARENA_BUILTIN_NAME: &str = "segment_arena_builtin"; +pub const ADD_MOD_BUILTIN_NAME: &str = "add_mod_builtin"; +pub const MUL_MOD_BUILTIN_NAME: &str = "mul_mod_builtin"; /* NB: this enum is no accident: we may need (and cairo-vm-py *does* need) * structs containing this to be `Send`. The only two ways to achieve that @@ -56,11 +83,13 @@ pub enum BuiltinRunner { EcOp(EcOpBuiltinRunner), Hash(HashBuiltinRunner), Output(OutputBuiltinRunner), - RangeCheck(RangeCheckBuiltinRunner), + RangeCheck(RangeCheckBuiltinRunner), + RangeCheck96(RangeCheckBuiltinRunner), Keccak(KeccakBuiltinRunner), Signature(SignatureBuiltinRunner), Poseidon(PoseidonBuiltinRunner), SegmentArena(SegmentArenaBuiltinRunner), + Mod(ModBuiltinRunner), } impl BuiltinRunner { @@ -74,12 +103,16 @@ impl BuiltinRunner { BuiltinRunner::RangeCheck(ref mut range_check) => { range_check.initialize_segments(segments) } + BuiltinRunner::RangeCheck96(ref mut range_check) => { + range_check.initialize_segments(segments) + } BuiltinRunner::Keccak(ref mut keccak) => keccak.initialize_segments(segments), BuiltinRunner::Signature(ref mut signature) => signature.initialize_segments(segments), BuiltinRunner::Poseidon(ref mut poseidon) => poseidon.initialize_segments(segments), BuiltinRunner::SegmentArena(ref mut segment_arena) => { segment_arena.initialize_segments(segments) } + BuiltinRunner::Mod(ref mut modulo) => modulo.initialize_segments(segments), } } @@ -90,10 +123,12 @@ impl BuiltinRunner { BuiltinRunner::Hash(ref hash) => hash.initial_stack(), BuiltinRunner::Output(ref output) => output.initial_stack(), BuiltinRunner::RangeCheck(ref range_check) => range_check.initial_stack(), + BuiltinRunner::RangeCheck96(ref range_check) => range_check.initial_stack(), BuiltinRunner::Keccak(ref keccak) => keccak.initial_stack(), BuiltinRunner::Signature(ref signature) => signature.initial_stack(), BuiltinRunner::Poseidon(ref poseidon) => poseidon.initial_stack(), BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.initial_stack(), + BuiltinRunner::Mod(ref modulo) => modulo.initial_stack(), } } @@ -101,26 +136,40 @@ impl BuiltinRunner { pub fn final_stack( &mut self, segments: &MemorySegmentManager, - stack_pointer: Relocatable, + pointer: Relocatable, ) -> Result { - match self { - BuiltinRunner::Bitwise(ref mut bitwise) => bitwise.final_stack(segments, stack_pointer), - BuiltinRunner::EcOp(ref mut ec) => ec.final_stack(segments, stack_pointer), - BuiltinRunner::Hash(ref mut hash) => hash.final_stack(segments, stack_pointer), - BuiltinRunner::Output(ref mut output) => output.final_stack(segments, stack_pointer), - BuiltinRunner::RangeCheck(ref mut range_check) => { - range_check.final_stack(segments, stack_pointer) - } - BuiltinRunner::Keccak(ref mut keccak) => keccak.final_stack(segments, stack_pointer), - BuiltinRunner::Signature(ref mut signature) => { - signature.final_stack(segments, stack_pointer) - } - BuiltinRunner::Poseidon(ref mut poseidon) => { - poseidon.final_stack(segments, stack_pointer) + if let BuiltinRunner::Output(output) = self { + return output.final_stack(segments, pointer); + } + if self.included() { + let stop_pointer_addr = + (pointer - 1).map_err(|_| RunnerError::NoStopPointer(Box::new(self.name())))?; + let stop_pointer = segments + .memory + .get_relocatable(stop_pointer_addr) + .map_err(|_| RunnerError::NoStopPointer(Box::new(self.name())))?; + if self.base() as isize != stop_pointer.segment_index { + return Err(RunnerError::InvalidStopPointerIndex(Box::new(( + self.name(), + stop_pointer, + self.base(), + )))); } - BuiltinRunner::SegmentArena(ref mut segment_arena) => { - segment_arena.final_stack(segments, stack_pointer) + let stop_ptr = stop_pointer.offset; + let num_instances = self.get_used_instances(segments)?; + let used = num_instances * self.cells_per_instance() as usize; + if stop_ptr != used { + return Err(RunnerError::InvalidStopPointer(Box::new(( + self.name(), + Relocatable::from((self.base() as isize, used)), + Relocatable::from((self.base() as isize, stop_ptr)), + )))); } + self.set_stop_ptr(stop_ptr); + Ok(stop_pointer_addr) + } else { + self.set_stop_ptr(0); + Ok(pointer) } } @@ -160,6 +209,23 @@ impl BuiltinRunner { } } + /// Returns if the builtin is included in the program builtins + fn included(&self) -> bool { + match *self { + BuiltinRunner::Bitwise(ref bitwise) => bitwise.included, + BuiltinRunner::EcOp(ref ec) => ec.included, + BuiltinRunner::Hash(ref hash) => hash.included, + BuiltinRunner::Output(ref output) => output.included, + BuiltinRunner::RangeCheck(ref range_check) => range_check.included, + BuiltinRunner::RangeCheck96(ref range_check) => range_check.included, + BuiltinRunner::Keccak(ref keccak) => keccak.included, + BuiltinRunner::Signature(ref signature) => signature.included, + BuiltinRunner::Poseidon(ref poseidon) => poseidon.included, + BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.included, + BuiltinRunner::Mod(ref modulo) => modulo.included, + } + } + ///Returns the builtin's base pub fn base(&self) -> usize { match *self { @@ -168,11 +234,13 @@ impl BuiltinRunner { BuiltinRunner::Hash(ref hash) => hash.base(), BuiltinRunner::Output(ref output) => output.base(), BuiltinRunner::RangeCheck(ref range_check) => range_check.base(), + BuiltinRunner::RangeCheck96(ref range_check) => range_check.base(), BuiltinRunner::Keccak(ref keccak) => keccak.base(), BuiltinRunner::Signature(ref signature) => signature.base(), BuiltinRunner::Poseidon(ref poseidon) => poseidon.base(), //Warning, returns only the segment index, base offset will be 3 BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.base(), + BuiltinRunner::Mod(ref modulo) => modulo.base(), } } @@ -183,25 +251,21 @@ impl BuiltinRunner { BuiltinRunner::Hash(hash) => hash.ratio(), BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) => None, BuiltinRunner::RangeCheck(range_check) => range_check.ratio(), + BuiltinRunner::RangeCheck96(range_check) => range_check.ratio(), BuiltinRunner::Keccak(keccak) => keccak.ratio(), BuiltinRunner::Signature(ref signature) => signature.ratio(), BuiltinRunner::Poseidon(poseidon) => poseidon.ratio(), + BuiltinRunner::Mod(ref modulo) => modulo.ratio(), } } pub fn add_validation_rule(&self, memory: &mut Memory) { match *self { - BuiltinRunner::Bitwise(ref bitwise) => bitwise.add_validation_rule(memory), - BuiltinRunner::EcOp(ref ec) => ec.add_validation_rule(memory), - BuiltinRunner::Hash(ref hash) => hash.add_validation_rule(memory), - BuiltinRunner::Output(ref output) => output.add_validation_rule(memory), BuiltinRunner::RangeCheck(ref range_check) => range_check.add_validation_rule(memory), - BuiltinRunner::Keccak(ref keccak) => keccak.add_validation_rule(memory), + BuiltinRunner::RangeCheck96(ref range_check) => range_check.add_validation_rule(memory), BuiltinRunner::Signature(ref signature) => signature.add_validation_rule(memory), BuiltinRunner::Poseidon(ref poseidon) => poseidon.add_validation_rule(memory), - BuiltinRunner::SegmentArena(ref segment_arena) => { - segment_arena.add_validation_rule(memory) - } + _ => {} } } @@ -214,55 +278,14 @@ impl BuiltinRunner { BuiltinRunner::Bitwise(ref bitwise) => bitwise.deduce_memory_cell(address, memory), BuiltinRunner::EcOp(ref ec) => ec.deduce_memory_cell(address, memory), BuiltinRunner::Hash(ref hash) => hash.deduce_memory_cell(address, memory), - BuiltinRunner::Output(ref output) => output.deduce_memory_cell(address, memory), - BuiltinRunner::RangeCheck(ref range_check) => { - range_check.deduce_memory_cell(address, memory) - } BuiltinRunner::Keccak(ref keccak) => keccak.deduce_memory_cell(address, memory), - BuiltinRunner::Signature(ref signature) => { - signature.deduce_memory_cell(address, memory) - } BuiltinRunner::Poseidon(ref poseidon) => poseidon.deduce_memory_cell(address, memory), - BuiltinRunner::SegmentArena(ref segment_arena) => { - segment_arena.deduce_memory_cell(address, memory) - } + _ => Ok(None), } } - pub fn get_memory_accesses( - &self, - vm: &VirtualMachine, - ) -> Result, MemoryError> { - if let BuiltinRunner::SegmentArena(_) = self { - return Ok(vec![]); - } - let base = self.base(); - let segment_size = vm - .segments - .get_segment_size(base) - .ok_or(MemoryError::MissingSegmentUsedSizes)?; - - Ok((0..segment_size) - .map(|i| (base as isize, i).into()) - .collect()) - } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - match self { - BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_memory_segment_addresses(), - BuiltinRunner::EcOp(ref ec) => ec.get_memory_segment_addresses(), - BuiltinRunner::Hash(ref hash) => hash.get_memory_segment_addresses(), - BuiltinRunner::Output(ref output) => output.get_memory_segment_addresses(), - BuiltinRunner::RangeCheck(ref range_check) => { - range_check.get_memory_segment_addresses() - } - BuiltinRunner::Keccak(ref keccak) => keccak.get_memory_segment_addresses(), - BuiltinRunner::Signature(ref signature) => signature.get_memory_segment_addresses(), - BuiltinRunner::Poseidon(ref poseidon) => poseidon.get_memory_segment_addresses(), - BuiltinRunner::SegmentArena(ref segment_arena) => { - segment_arena.get_memory_segment_addresses() - } - } + (self.base(), self.stop_ptr()) } pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { @@ -272,12 +295,14 @@ impl BuiltinRunner { BuiltinRunner::Hash(ref hash) => hash.get_used_cells(segments), BuiltinRunner::Output(ref output) => output.get_used_cells(segments), BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_cells(segments), + BuiltinRunner::RangeCheck96(ref range_check) => range_check.get_used_cells(segments), BuiltinRunner::Keccak(ref keccak) => keccak.get_used_cells(segments), BuiltinRunner::Signature(ref signature) => signature.get_used_cells(segments), BuiltinRunner::Poseidon(ref poseidon) => poseidon.get_used_cells(segments), BuiltinRunner::SegmentArena(ref segment_arena) => { segment_arena.get_used_cells(segments) } + BuiltinRunner::Mod(ref modulo) => modulo.get_used_cells(segments), } } @@ -291,18 +316,25 @@ impl BuiltinRunner { BuiltinRunner::Hash(ref hash) => hash.get_used_instances(segments), BuiltinRunner::Output(ref output) => output.get_used_instances(segments), BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_instances(segments), + BuiltinRunner::RangeCheck96(ref range_check) => { + range_check.get_used_instances(segments) + } BuiltinRunner::Keccak(ref keccak) => keccak.get_used_instances(segments), BuiltinRunner::Signature(ref signature) => signature.get_used_instances(segments), BuiltinRunner::Poseidon(ref poseidon) => poseidon.get_used_instances(segments), BuiltinRunner::SegmentArena(ref segment_arena) => { segment_arena.get_used_instances(segments) } + BuiltinRunner::Mod(modulo) => modulo.get_used_instances(segments), } } pub fn get_range_check_usage(&self, memory: &Memory) -> Option<(usize, usize)> { match self { BuiltinRunner::RangeCheck(ref range_check) => range_check.get_range_check_usage(memory), + BuiltinRunner::RangeCheck96(ref range_check) => { + range_check.get_range_check_usage(memory) + } _ => None, } } @@ -315,7 +347,11 @@ impl BuiltinRunner { match self { BuiltinRunner::RangeCheck(range_check) => { let (used_cells, _) = self.get_used_cells_and_allocated_size(vm)?; - Ok(used_cells * range_check.n_parts as usize) + Ok(used_cells * range_check.n_parts() as usize) + } + BuiltinRunner::RangeCheck96(range_check) => { + let (used_cells, _) = self.get_used_cells_and_allocated_size(vm)?; + Ok(used_cells * range_check.n_parts() as usize) } _ => Ok(0), } @@ -335,42 +371,38 @@ impl BuiltinRunner { fn cells_per_instance(&self) -> u32 { match self { - BuiltinRunner::Bitwise(builtin) => builtin.cells_per_instance, - BuiltinRunner::EcOp(builtin) => builtin.cells_per_instance, - BuiltinRunner::Hash(builtin) => builtin.cells_per_instance, - BuiltinRunner::RangeCheck(builtin) => builtin.cells_per_instance, + BuiltinRunner::Bitwise(_) => CELLS_PER_BITWISE, + BuiltinRunner::EcOp(_) => CELLS_PER_EC_OP, + BuiltinRunner::Hash(_) => CELLS_PER_HASH, + BuiltinRunner::RangeCheck(_) | BuiltinRunner::RangeCheck96(_) => CELLS_PER_RANGE_CHECK, BuiltinRunner::Output(_) => 0, - BuiltinRunner::Keccak(builtin) => builtin.cells_per_instance, - BuiltinRunner::Signature(builtin) => builtin.cells_per_instance, - BuiltinRunner::Poseidon(builtin) => builtin.cells_per_instance, - BuiltinRunner::SegmentArena(builtin) => builtin.cells_per_instance, + BuiltinRunner::Keccak(_) => CELLS_PER_KECCAK, + BuiltinRunner::Signature(_) => CELLS_PER_SIGNATURE, + BuiltinRunner::Poseidon(_) => CELLS_PER_POSEIDON, + BuiltinRunner::SegmentArena(_) => ARENA_BUILTIN_SIZE, + BuiltinRunner::Mod(_) => CELLS_PER_MOD, } } fn n_input_cells(&self) -> u32 { match self { - BuiltinRunner::Bitwise(builtin) => builtin.n_input_cells, - BuiltinRunner::EcOp(builtin) => builtin.n_input_cells, - BuiltinRunner::Hash(builtin) => builtin.n_input_cells, - BuiltinRunner::RangeCheck(builtin) => builtin.n_input_cells, + BuiltinRunner::Bitwise(_) => INPUT_CELLS_PER_BITWISE, + BuiltinRunner::EcOp(_) => INPUT_CELLS_PER_EC_OP, + BuiltinRunner::Hash(_) => INPUT_CELLS_PER_HASH, + BuiltinRunner::RangeCheck(_) | BuiltinRunner::RangeCheck96(_) => CELLS_PER_RANGE_CHECK, BuiltinRunner::Output(_) => 0, - BuiltinRunner::Keccak(builtin) => builtin.n_input_cells, - BuiltinRunner::Signature(builtin) => builtin.n_input_cells, - BuiltinRunner::Poseidon(builtin) => builtin.n_input_cells, - BuiltinRunner::SegmentArena(builtin) => builtin.n_input_cells_per_instance, + BuiltinRunner::Keccak(_) => INPUT_CELLS_PER_KECCAK, + BuiltinRunner::Signature(_) => CELLS_PER_SIGNATURE, + BuiltinRunner::Poseidon(_) => INPUT_CELLS_PER_POSEIDON, + BuiltinRunner::SegmentArena(_) => ARENA_BUILTIN_SIZE, + BuiltinRunner::Mod(_) => CELLS_PER_MOD, } } fn instances_per_component(&self) -> u32 { match self { - BuiltinRunner::Bitwise(builtin) => builtin.instances_per_component, - BuiltinRunner::EcOp(builtin) => builtin.instances_per_component, - BuiltinRunner::Hash(builtin) => builtin.instances_per_component, - BuiltinRunner::RangeCheck(builtin) => builtin.instances_per_component, - BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) => 1, - BuiltinRunner::Keccak(builtin) => builtin.instances_per_component, - BuiltinRunner::Signature(builtin) => builtin.instances_per_component, - BuiltinRunner::Poseidon(builtin) => builtin.instances_per_component, + BuiltinRunner::Keccak(_) => KECCAK_INSTANCES_PER_COMPONENT, + _ => BUILTIN_INSTANCES_PER_COMPONENT, } } @@ -380,11 +412,29 @@ impl BuiltinRunner { BuiltinRunner::EcOp(_) => EC_OP_BUILTIN_NAME, BuiltinRunner::Hash(_) => HASH_BUILTIN_NAME, BuiltinRunner::RangeCheck(_) => RANGE_CHECK_BUILTIN_NAME, + BuiltinRunner::RangeCheck96(_) => RANGE_CHECK_96_BUILTIN_NAME, BuiltinRunner::Output(_) => OUTPUT_BUILTIN_NAME, BuiltinRunner::Keccak(_) => KECCAK_BUILTIN_NAME, BuiltinRunner::Signature(_) => SIGNATURE_BUILTIN_NAME, BuiltinRunner::Poseidon(_) => POSEIDON_BUILTIN_NAME, BuiltinRunner::SegmentArena(_) => SEGMENT_ARENA_BUILTIN_NAME, + BuiltinRunner::Mod(b) => b.name(), + } + } + + pub fn identifier(&self) -> BuiltinName { + match self { + BuiltinRunner::Bitwise(_) => BuiltinName::bitwise, + BuiltinRunner::EcOp(_) => BuiltinName::ec_op, + BuiltinRunner::Hash(_) => BuiltinName::pedersen, + BuiltinRunner::RangeCheck(_) => BuiltinName::range_check, + BuiltinRunner::RangeCheck96(_) => BuiltinName::range_check96, + BuiltinRunner::Output(_) => BuiltinName::output, + BuiltinRunner::Keccak(_) => BuiltinName::keccak, + BuiltinRunner::Signature(_) => BuiltinName::ecdsa, + BuiltinRunner::Poseidon(_) => BuiltinName::poseidon, + BuiltinRunner::SegmentArena(_) => BuiltinName::segment_arena, + BuiltinRunner::Mod(b) => b.identifier(), } } @@ -392,6 +442,9 @@ impl BuiltinRunner { if let BuiltinRunner::Output(_) | BuiltinRunner::SegmentArena(_) = self { return Ok(()); } + if let BuiltinRunner::Mod(modulo) = self { + modulo.run_additional_security_checks(vm)?; + } let cells_per_instance = self.cells_per_instance() as usize; let n_input_cells = self.n_input_cells() as usize; let builtin_segment_index = self.base(); @@ -485,20 +538,21 @@ impl BuiltinRunner { } // Returns information about the builtin that should be added to the AIR private input. - pub fn air_private_input(&self, memory: &Memory) -> Vec { + pub fn air_private_input(&self, segments: &MemorySegmentManager) -> Vec { match self { - BuiltinRunner::RangeCheck(builtin) => builtin.air_private_input(memory), - BuiltinRunner::Bitwise(builtin) => builtin.air_private_input(memory), - BuiltinRunner::Hash(builtin) => builtin.air_private_input(memory), - BuiltinRunner::EcOp(builtin) => builtin.air_private_input(memory), - BuiltinRunner::Poseidon(builtin) => builtin.air_private_input(memory), - BuiltinRunner::Signature(builtin) => builtin.air_private_input(memory), - BuiltinRunner::Keccak(builtin) => builtin.air_private_input(memory), + BuiltinRunner::RangeCheck(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::RangeCheck96(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::Bitwise(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::Hash(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::EcOp(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::Poseidon(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::Signature(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::Keccak(builtin) => builtin.air_private_input(&segments.memory), + BuiltinRunner::Mod(builtin) => builtin.air_private_input(segments), _ => vec![], } } - #[cfg(test)] pub(crate) fn set_stop_ptr(&mut self, stop_ptr: usize) { match self { BuiltinRunner::Bitwise(ref mut bitwise) => bitwise.stop_ptr = Some(stop_ptr), @@ -506,12 +560,32 @@ impl BuiltinRunner { BuiltinRunner::Hash(ref mut hash) => hash.stop_ptr = Some(stop_ptr), BuiltinRunner::Output(ref mut output) => output.stop_ptr = Some(stop_ptr), BuiltinRunner::RangeCheck(ref mut range_check) => range_check.stop_ptr = Some(stop_ptr), + BuiltinRunner::RangeCheck96(ref mut range_check) => { + range_check.stop_ptr = Some(stop_ptr) + } BuiltinRunner::Keccak(ref mut keccak) => keccak.stop_ptr = Some(stop_ptr), BuiltinRunner::Signature(ref mut signature) => signature.stop_ptr = Some(stop_ptr), BuiltinRunner::Poseidon(ref mut poseidon) => poseidon.stop_ptr = Some(stop_ptr), BuiltinRunner::SegmentArena(ref mut segment_arena) => { segment_arena.stop_ptr = Some(stop_ptr) } + BuiltinRunner::Mod(modulo) => modulo.stop_ptr = Some(stop_ptr), + } + } + + pub(crate) fn stop_ptr(&self) -> Option { + match self { + BuiltinRunner::Bitwise(ref bitwise) => bitwise.stop_ptr, + BuiltinRunner::EcOp(ref ec) => ec.stop_ptr, + BuiltinRunner::Hash(ref hash) => hash.stop_ptr, + BuiltinRunner::Output(ref output) => output.stop_ptr, + BuiltinRunner::RangeCheck(ref range_check) => range_check.stop_ptr, + BuiltinRunner::RangeCheck96(ref range_check) => range_check.stop_ptr, + BuiltinRunner::Keccak(ref keccak) => keccak.stop_ptr, + BuiltinRunner::Signature(ref signature) => signature.stop_ptr, + BuiltinRunner::Poseidon(ref poseidon) => poseidon.stop_ptr, + BuiltinRunner::SegmentArena(ref segment_arena) => segment_arena.stop_ptr, + BuiltinRunner::Mod(ref modulo) => modulo.stop_ptr, } } } @@ -546,12 +620,18 @@ impl From for BuiltinRunner { } } -impl From for BuiltinRunner { - fn from(runner: RangeCheckBuiltinRunner) -> Self { +impl From> for BuiltinRunner { + fn from(runner: RangeCheckBuiltinRunner) -> Self { BuiltinRunner::RangeCheck(runner) } } +impl From> for BuiltinRunner { + fn from(runner: RangeCheckBuiltinRunner) -> Self { + BuiltinRunner::RangeCheck96(runner) + } +} + impl From for BuiltinRunner { fn from(runner: SignatureBuiltinRunner) -> Self { BuiltinRunner::Signature(runner) @@ -570,78 +650,33 @@ impl From for BuiltinRunner { } } +impl From for BuiltinRunner { + fn from(runner: ModBuiltinRunner) -> Self { + BuiltinRunner::Mod(runner) + } +} + #[cfg(test)] mod tests { use super::*; use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; use crate::relocatable; use crate::serde::deserialize_program::BuiltinName; - use crate::types::instance_definitions::ecdsa_instance_def::EcdsaInstanceDef; - use crate::types::instance_definitions::keccak_instance_def::KeccakInstanceDef; use crate::types::program::Program; use crate::vm::errors::memory_errors::InsufficientAllocatedCellsError; use crate::vm::runners::cairo_runner::CairoRunner; - use crate::{ - types::instance_definitions::{ - bitwise_instance_def::BitwiseInstanceDef, ec_op_instance_def::EcOpInstanceDef, - }, - utils::test_utils::*, - vm::vm_core::VirtualMachine, - }; + use crate::{utils::test_utils::*, vm::vm_core::VirtualMachine}; use assert_matches::assert_matches; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_n_input_cells_bitwise() { - let bitwise = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let bitwise = BitwiseBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = bitwise.clone().into(); - assert_eq!(bitwise.n_input_cells, builtin.n_input_cells()) + assert_eq!(INPUT_CELLS_PER_BITWISE, builtin.n_input_cells()) } #[test] @@ -649,31 +684,23 @@ mod tests { fn get_n_input_cells_hash() { let hash = HashBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = hash.clone().into(); - assert_eq!(hash.n_input_cells, builtin.n_input_cells()) - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_n_input_cells_range_check() { - let range_check = RangeCheckBuiltinRunner::new(Some(10), 10, true); - let builtin: BuiltinRunner = range_check.clone().into(); - assert_eq!(range_check.n_input_cells, builtin.n_input_cells()) + assert_eq!(INPUT_CELLS_PER_HASH, builtin.n_input_cells()) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_n_input_cells_ec_op() { - let ec_op = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op.clone().into(); - assert_eq!(ec_op.n_input_cells, builtin.n_input_cells()) + assert_eq!(INPUT_CELLS_PER_EC_OP, builtin.n_input_cells()) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_n_input_cells_ecdsa() { - let signature = SignatureBuiltinRunner::new(&EcdsaInstanceDef::new(Some(10)), true); + let signature = SignatureBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = signature.clone().into(); - assert_eq!(signature.n_input_cells, builtin.n_input_cells()) + assert_eq!(CELLS_PER_SIGNATURE, builtin.n_input_cells()) } #[test] @@ -687,9 +714,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_cells_per_instance_bitwise() { - let bitwise = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let bitwise = BitwiseBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = bitwise.clone().into(); - assert_eq!(bitwise.cells_per_instance, builtin.cells_per_instance()) + assert_eq!(CELLS_PER_BITWISE, builtin.cells_per_instance()) } #[test] @@ -697,31 +724,23 @@ mod tests { fn get_cells_per_instance_hash() { let hash = HashBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = hash.clone().into(); - assert_eq!(hash.cells_per_instance, builtin.cells_per_instance()) - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_instance_range_check() { - let range_check = RangeCheckBuiltinRunner::new(Some(10), 10, true); - let builtin: BuiltinRunner = range_check.clone().into(); - assert_eq!(range_check.cells_per_instance, builtin.cells_per_instance()) + assert_eq!(CELLS_PER_HASH, builtin.cells_per_instance()) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_cells_per_instance_ec_op() { - let ec_op = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op.clone().into(); - assert_eq!(ec_op.cells_per_instance, builtin.cells_per_instance()) + assert_eq!(CELLS_PER_EC_OP, builtin.cells_per_instance()) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_cells_per_instance_ecdsa() { - let signature = SignatureBuiltinRunner::new(&EcdsaInstanceDef::new(Some(10)), true); + let signature = SignatureBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = signature.clone().into(); - assert_eq!(signature.cells_per_instance, builtin.cells_per_instance()) + assert_eq!(CELLS_PER_SIGNATURE, builtin.cells_per_instance()) } #[test] @@ -732,18 +751,10 @@ mod tests { assert_eq!(0, builtin.cells_per_instance()) } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_cells_per_instance_keccak() { - let keccak = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); - let builtin: BuiltinRunner = keccak.clone().into(); - assert_eq!(keccak.cells_per_instance, builtin.cells_per_instance()) - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_name_bitwise() { - let bitwise = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(10)), true); + let bitwise = BitwiseBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = bitwise.into(); assert_eq!(BITWISE_BUILTIN_NAME, builtin.name()) } @@ -759,7 +770,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_name_range_check() { - let range_check = RangeCheckBuiltinRunner::new(Some(10), 10, true); + let range_check = RangeCheckBuiltinRunner::::new(Some(10), true); let builtin: BuiltinRunner = range_check.into(); assert_eq!(RANGE_CHECK_BUILTIN_NAME, builtin.name()) } @@ -767,7 +778,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_name_ec_op() { - let ec_op = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op.into(); assert_eq!(EC_OP_BUILTIN_NAME, builtin.name()) } @@ -775,7 +786,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_name_ecdsa() { - let signature = SignatureBuiltinRunner::new(&EcdsaInstanceDef::new(Some(10)), true); + let signature = SignatureBuiltinRunner::new(Some(10), true); let builtin: BuiltinRunner = signature.into(); assert_eq!(SIGNATURE_BUILTIN_NAME, builtin.name()) } @@ -791,10 +802,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_bitwise_with_items() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::new(Some(10)), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(10), true)); let mut vm = vm!(); @@ -826,7 +834,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -838,10 +846,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_ec_op_with_items() { - let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new( - &EcOpInstanceDef::new(Some(10)), - true, - )); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(10), true)); let mut vm = vm!(); @@ -873,7 +878,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -917,7 +922,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -929,7 +934,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_range_check_with_items() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(10), 12, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(10), true), + ); let mut vm = vm!(); @@ -961,7 +968,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -973,10 +980,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_keccak_with_items() { - let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::new(Some(10), vec![200; 8]), - true, - )); + let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(10), true)); let mut vm = vm!(); vm.current_step = 160; @@ -985,10 +989,7 @@ mod tests { #[test] fn get_allocated_memory_units_keccak_min_steps_not_reached() { - let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::new(Some(10), vec![200; 8]), - true, - )); + let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(10), true)); let mut vm = vm!(); vm.current_step = 10; @@ -1016,7 +1017,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_range_check() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(8), true), + ); let mut vm = vm!(); vm.current_step = 8; assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(1)); @@ -1034,10 +1037,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_bitwise() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.current_step = 256; assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(5)); @@ -1046,8 +1046,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_ec_op() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.current_step = 256; assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(7)); @@ -1056,10 +1055,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units_keccak() { - let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), true)); let mut vm = vm!(); vm.current_step = 32768; assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(256)); @@ -1068,7 +1064,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_usage_range_check() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(8), true), + ); let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)]; assert_eq!(builtin.get_range_check_usage(&memory), Some((0, 4))); } @@ -1092,8 +1090,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_usage_ec_op() { - let builtin = - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true)); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), true)); let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)]; assert_eq!(builtin.get_range_check_usage(&memory), None); } @@ -1101,10 +1098,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_usage_bitwise() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)]; assert_eq!(builtin.get_range_check_usage(&memory), None); } @@ -1112,40 +1106,28 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_bitwise() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); assert_eq!(builtin.get_used_diluted_check_units(270, 7), 1255); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_keccak_zero_case() { - let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), true)); assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_keccak_non_zero_case() { - let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), true)); assert_eq!(builtin.get_used_diluted_check_units(0, 8), 32768); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_ec_op() { - let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new( - &EcOpInstanceDef::new(Some(10)), - true, - )); + let builtin = BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(10), true)); assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0); } @@ -1159,7 +1141,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_diluted_check_units_range_check() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(8), true), + ); assert_eq!(builtin.get_used_diluted_check_units(270, 7), 0); } @@ -1173,18 +1157,17 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_memory_segment_addresses_test() { - let bitwise_builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); + let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into(); assert_eq!(bitwise_builtin.get_memory_segment_addresses(), (0, None),); - let ec_op_builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); assert_eq!(ec_op_builtin.get_memory_segment_addresses(), (0, None),); let hash_builtin: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into(); assert_eq!(hash_builtin.get_memory_segment_addresses(), (0, None),); let output_builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into(); assert_eq!(output_builtin.get_memory_segment_addresses(), (0, None),); - let range_check_builtin: BuiltinRunner = - BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(8), true), + ); assert_eq!( range_check_builtin.get_memory_segment_addresses(), (0, None), @@ -1203,10 +1186,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_empty_memory() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let vm = vm!(); // Unused builtin shouldn't fail security checks assert_matches!(builtin.run_security_checks(&vm), Ok(())); @@ -1215,10 +1195,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_empty_offsets() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.segments.memory.data = vec![vec![]]; @@ -1229,10 +1206,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_bitwise_missing_memory_cells_with_offsets() { - let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), true)); let mut vm = vm!(); vm.segments.memory = memory![ ((0, 1), (0, 1)), @@ -1252,22 +1226,13 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_bitwise_missing_memory_cells() { - let mut bitwise_builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); - - bitwise_builtin.cells_per_instance = 2; - bitwise_builtin.n_input_cells = 5; + let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = bitwise_builtin.into(); let mut vm = vm!(); - vm.segments.memory = memory![ - ((0, 0), (0, 1)), - ((0, 1), (0, 2)), - ((0, 2), (0, 3)), - ((0, 3), (0, 4)), - ((0, 4), (0, 5)) - ]; + vm.segments.memory = memory![((0, 4), (0, 5))]; assert_matches!( builtin.run_security_checks(&vm), @@ -1320,7 +1285,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_range_check_missing_memory_cells_with_offsets() { - let range_check_builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let range_check_builtin = + RangeCheckBuiltinRunner::::new(Some(8), true); let builtin: BuiltinRunner = range_check_builtin.into(); let mut vm = vm!(); @@ -1344,8 +1310,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_range_check_missing_memory_cells() { - let builtin: BuiltinRunner = - BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let builtin: BuiltinRunner = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::< + RC_N_PARTS_STANDARD, + >::new(Some(8), true)); let mut vm = vm!(); vm.segments.memory = memory![((0, 1), 1)]; @@ -1361,7 +1328,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_range_check_empty() { - let range_check_builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let range_check_builtin = + RangeCheckBuiltinRunner::::new(Some(8), true); let builtin: BuiltinRunner = range_check_builtin.into(); @@ -1375,8 +1343,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_checks_validate_auto_deductions() { - let builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into(); let mut vm = vm!(); vm.segments @@ -1398,7 +1365,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_ec_op_check_memory_empty() { - let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op_builtin.into(); @@ -1412,7 +1379,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_ec_op_check_memory_1_element() { - let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op_builtin.into(); @@ -1430,7 +1397,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_ec_op_check_memory_3_elements() { - let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op_builtin.into(); @@ -1449,8 +1416,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_ec_op_missing_memory_cells_with_offsets() { - let builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); let mut vm = vm!(); vm.segments.memory = memory![ ((0, 1), (0, 1)), @@ -1472,7 +1438,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_security_ec_op_check_memory_gap() { - let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let ec_op_builtin = EcOpBuiltinRunner::new(Some(256), true); let builtin: BuiltinRunner = ec_op_builtin.into(); @@ -1505,8 +1471,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_perm_range_check_units_bitwise() { - let builtin_runner: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); + let builtin_runner: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into(); let mut vm = vm!(); vm.current_step = 8; @@ -1519,8 +1484,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_perm_range_check_units_ec_op() { - let builtin_runner: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let builtin_runner: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); let mut vm = vm!(); vm.current_step = 8; @@ -1559,7 +1523,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_perm_range_check_units_range_check() { - let builtin_runner: BuiltinRunner = RangeCheckBuiltinRunner::new(Some(8), 8, true).into(); + let builtin_runner: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(8), true).into(); let mut vm = vm!(); vm.current_step = 8; @@ -1570,21 +1535,19 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_ratio_tests() { - let bitwise_builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); + let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into(); assert_eq!(bitwise_builtin.ratio(), (Some(256)),); - let ec_op_builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); assert_eq!(ec_op_builtin.ratio(), (Some(256)),); let hash_builtin: BuiltinRunner = HashBuiltinRunner::new(Some(8), true).into(); assert_eq!(hash_builtin.ratio(), (Some(8)),); let output_builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into(); assert_eq!(output_builtin.ratio(), None,); - let range_check_builtin: BuiltinRunner = - BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(8), true), + ); assert_eq!(range_check_builtin.ratio(), (Some(8)),); - let keccak_builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true).into(); + let keccak_builtin: BuiltinRunner = KeccakBuiltinRunner::new(Some(2048), true).into(); assert_eq!(keccak_builtin.ratio(), (Some(2048)),); } @@ -1594,8 +1557,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - let bitwise_builtin: BuiltinRunner = - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); + let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(Some(256), true).into(); assert_eq!(bitwise_builtin.get_used_instances(&vm.segments), Ok(1)); } @@ -1605,8 +1567,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - let ec_op_builtin: BuiltinRunner = - EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); + let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(Some(256), true).into(); assert_eq!(ec_op_builtin.get_used_instances(&vm.segments), Ok(1)); } @@ -1635,8 +1596,9 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - let range_check_builtin: BuiltinRunner = - BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, true)); + let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(8), true), + ); assert_eq!(range_check_builtin.get_used_instances(&vm.segments), Ok(4)); } @@ -1644,22 +1606,16 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn runners_final_stack() { let mut builtins = vec![ - BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - false, - )), - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), false)), + BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), false)), + BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), false)), BuiltinRunner::Hash(HashBuiltinRunner::new(Some(1), false)), BuiltinRunner::Output(OutputBuiltinRunner::new(false)), - BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, false)), - BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::default(), - false, - )), - BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), + BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::::new( + Some(8), false, )), + BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), false)), + BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), false)), ]; let vm = vm!(); @@ -1672,22 +1628,16 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn runners_set_stop_ptr() { let builtins = vec![ - BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( - &BitwiseInstanceDef::default(), - false, - )), - BuiltinRunner::EcOp(EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), false)), + BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new(Some(256), false)), + BuiltinRunner::EcOp(EcOpBuiltinRunner::new(Some(256), false)), BuiltinRunner::Hash(HashBuiltinRunner::new(Some(1), false)), BuiltinRunner::Output(OutputBuiltinRunner::new(false)), - BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(8), 8, false)), - BuiltinRunner::Keccak(KeccakBuiltinRunner::new( - &KeccakInstanceDef::default(), - false, - )), - BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), + BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::::new( + Some(8), false, )), + BuiltinRunner::Keccak(KeccakBuiltinRunner::new(Some(2048), false)), + BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), false)), BuiltinRunner::Poseidon(PoseidonBuiltinRunner::new(Some(32), false)), BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(false)), ]; diff --git a/vm/src/vm/runners/builtin_runner/modulo.rs b/vm/src/vm/runners/builtin_runner/modulo.rs new file mode 100644 index 0000000000..91254d4789 --- /dev/null +++ b/vm/src/vm/runners/builtin_runner/modulo.rs @@ -0,0 +1,900 @@ +use crate::{ + air_private_input::{ModInput, ModInputInstance, ModInputMemoryVars, PrivateInput}, + math_utils::{div_mod_unsigned, safe_div_usize}, + serde::deserialize_program::BuiltinName, + stdlib::{ + borrow::Cow, + collections::BTreeMap, + prelude::{Box, Vec}, + }, + types::{ + errors::math_errors::MathError, + instance_definitions::mod_instance_def::{ModInstanceDef, CELLS_PER_MOD, N_WORDS}, + relocatable::{relocate_address, MaybeRelocatable, Relocatable}, + }, + vm::{ + errors::{ + memory_errors::MemoryError, runner_errors::RunnerError, vm_errors::VirtualMachineError, + }, + vm_core::VirtualMachine, + vm_memory::{memory::Memory, memory_segments::MemorySegmentManager}, + }, + Felt252, +}; +use core::{fmt::Display, ops::Shl}; +use num_bigint::BigUint; +use num_integer::div_ceil; +use num_integer::Integer; +use num_traits::One; +use num_traits::Zero; + +//The maximum n value that the function fill_memory accepts. +const FILL_MEMORY_MAX: usize = 100000; + +const VALUES_PTR_OFFSET: u32 = 4; +const OFFSETS_PTR_OFFSET: u32 = 5; +const N_OFFSET: u32 = 6; + +#[derive(Debug, Clone)] +pub struct ModBuiltinRunner { + builtin_type: ModBuiltinType, + base: usize, + pub(crate) stop_ptr: Option, + instance_def: ModInstanceDef, + pub(crate) included: bool, + zero_segment_index: usize, + zero_segment_size: usize, + // Precomputed powers used for reading and writing values that are represented as n_words words of word_bit_len bits each. + shift: BigUint, + shift_powers: [BigUint; N_WORDS], +} + +#[derive(Debug, Clone)] +pub enum ModBuiltinType { + Mul, + Add, +} + +#[derive(Debug)] +pub enum Operation { + Mul, + Add, + Sub, + DivMod(BigUint), +} + +impl Display for Operation { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Operation::Mul => "*".fmt(f), + Operation::Add => "+".fmt(f), + Operation::Sub => "-".fmt(f), + Operation::DivMod(_) => "/".fmt(f), + } + } +} + +#[derive(Debug, Default)] +struct Inputs { + p: BigUint, + p_values: [Felt252; N_WORDS], + values_ptr: Relocatable, + offsets_ptr: Relocatable, + n: usize, +} + +impl ModBuiltinRunner { + pub(crate) fn new_add_mod(instance_def: &ModInstanceDef, included: bool) -> Self { + Self::new(instance_def.clone(), included, ModBuiltinType::Add) + } + + pub(crate) fn new_mul_mod(instance_def: &ModInstanceDef, included: bool) -> Self { + Self::new(instance_def.clone(), included, ModBuiltinType::Mul) + } + + fn new(instance_def: ModInstanceDef, included: bool, builtin_type: ModBuiltinType) -> Self { + let shift = BigUint::one().shl(instance_def.word_bit_len); + let shift_powers = core::array::from_fn(|i| shift.pow(i as u32)); + let zero_segment_size = core::cmp::max(N_WORDS, instance_def.batch_size * 3); + Self { + builtin_type, + base: 0, + stop_ptr: None, + instance_def, + included, + zero_segment_index: 0, + zero_segment_size, + shift, + shift_powers, + } + } + + pub fn name(&self) -> &'static str { + match self.builtin_type { + ModBuiltinType::Mul => super::MUL_MOD_BUILTIN_NAME, + ModBuiltinType::Add => super::ADD_MOD_BUILTIN_NAME, + } + } + + pub fn identifier(&self) -> BuiltinName { + match self.builtin_type { + ModBuiltinType::Mul => BuiltinName::mul_mod, + ModBuiltinType::Add => BuiltinName::add_mod, + } + } + + pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) { + self.base = segments.add().segment_index as usize; // segments.add() always returns a positive index + self.zero_segment_index = segments.add_zero_segment(self.zero_segment_size) + } + + pub fn initial_stack(&self) -> Vec { + if self.included { + vec![MaybeRelocatable::from((self.base as isize, 0))] + } else { + vec![] + } + } + + pub fn base(&self) -> usize { + self.base + } + + pub fn ratio(&self) -> Option { + self.instance_def.ratio + } + + pub fn batch_size(&self) -> usize { + self.instance_def.batch_size + } + + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { + segments + .get_segment_used_size(self.base) + .ok_or(MemoryError::MissingSegmentUsedSizes) + } + + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + let used_cells = self.get_used_cells(segments)?; + Ok(div_ceil(used_cells, CELLS_PER_MOD as usize)) + } + + pub(crate) fn air_private_input(&self, segments: &MemorySegmentManager) -> Vec { + let segment_index = self.base as isize; + let segment_size = segments + .get_segment_used_size(self.base) + .unwrap_or_default(); + let relocation_table = segments.relocate_segments().unwrap_or_default(); + let mut instances = Vec::::new(); + for instance in 0..segment_size + .checked_div(CELLS_PER_MOD as usize) + .unwrap_or_default() + { + let instance_addr_offset = instance * CELLS_PER_MOD as usize; + let values_ptr = segments + .memory + .get_relocatable( + ( + segment_index, + instance_addr_offset + VALUES_PTR_OFFSET as usize, + ) + .into(), + ) + .unwrap_or_default(); + let offsets_ptr = segments + .memory + .get_relocatable( + ( + segment_index, + instance_addr_offset + OFFSETS_PTR_OFFSET as usize, + ) + .into(), + ) + .unwrap_or_default(); + let n = segments + .memory + .get_usize((segment_index, instance_addr_offset + N_OFFSET as usize).into()) + .unwrap_or_default(); + let p_values: [Felt252; N_WORDS] = core::array::from_fn(|i| { + segments + .memory + .get_integer((segment_index, instance_addr_offset + i).into()) + .unwrap_or_default() + .into_owned() + }); + let mut batch = BTreeMap::::new(); + let fetch_offset_and_words = |var_index: usize, + index_in_batch: usize| + -> (usize, [Felt252; N_WORDS]) { + let offset = segments + .memory + .get_usize((offsets_ptr + (3 * index_in_batch + var_index)).unwrap_or_default()) + .unwrap_or_default(); + let words: [Felt252; N_WORDS] = core::array::from_fn(|i| { + segments + .memory + .get_integer((values_ptr + (offset + i)).unwrap_or_default()) + .unwrap_or_default() + .into_owned() + }); + (offset, words) + }; + for index_in_batch in 0..self.batch_size() { + let (a_offset, a_values) = fetch_offset_and_words(0, index_in_batch); + let (b_offset, b_values) = fetch_offset_and_words(1, index_in_batch); + let (c_offset, c_values) = fetch_offset_and_words(2, index_in_batch); + batch.insert( + index_in_batch, + ModInputMemoryVars { + a_offset, + b_offset, + c_offset, + a0: a_values[0], + a1: a_values[1], + a2: a_values[2], + a3: a_values[3], + b0: b_values[0], + b1: b_values[1], + b2: b_values[2], + b3: b_values[3], + c0: c_values[0], + c1: c_values[1], + c2: c_values[2], + c3: c_values[3], + }, + ); + } + instances.push(ModInputInstance { + index: instance, + p0: p_values[0], + p1: p_values[1], + p2: p_values[2], + p3: p_values[3], + values_ptr: relocate_address(values_ptr, &relocation_table).unwrap_or_default(), + offsets_ptr: relocate_address(offsets_ptr, &relocation_table).unwrap_or_default(), + n, + batch, + }); + } + + vec![PrivateInput::Mod(ModInput { + instances, + zero_value_address: relocation_table + .get(self.zero_segment_index) + .cloned() + .unwrap_or_default(), + })] + } + + // Reads N_WORDS from memory, starting at address=addr. + // Returns the words and the value if all words are in memory. + // Verifies that all words are integers and are bounded by 2**self.instance_def.word_bit_len. + fn read_n_words_value( + &self, + memory: &Memory, + addr: Relocatable, + ) -> Result<([Felt252; N_WORDS], Option), RunnerError> { + let mut words = Default::default(); + let mut value = BigUint::zero(); + for i in 0..N_WORDS { + let addr_i = (addr + i)?; + match memory.get(&addr_i).map(Cow::into_owned) { + None => return Ok((words, None)), + Some(MaybeRelocatable::RelocatableValue(_)) => { + return Err(MemoryError::ExpectedInteger(Box::new(addr_i)).into()) + } + Some(MaybeRelocatable::Int(word)) => { + let biguint_word = word.to_biguint(); + if biguint_word >= self.shift { + return Err(RunnerError::WordExceedsModBuiltinWordBitLen(Box::new(( + addr_i, + self.instance_def.word_bit_len, + word, + )))); + } + words[i] = word; + value += biguint_word * &self.shift_powers[i]; + } + } + } + Ok((words, Some(value))) + } + + // Reads the inputs to the builtin (see Inputs) from the memory at address=addr. + // Returns a struct with the inputs. Asserts that it exists in memory. + // Returns also the value of p, not just its words. + fn read_inputs(&self, memory: &Memory, addr: Relocatable) -> Result { + let values_ptr = memory.get_relocatable((addr + VALUES_PTR_OFFSET)?)?; + let offsets_ptr = memory.get_relocatable((addr + OFFSETS_PTR_OFFSET)?)?; + let n = memory.get_usize((addr + N_OFFSET)?)?; + if n < 1 { + return Err(RunnerError::ModBuiltinNLessThanOne(Box::new(( + self.name(), + n, + )))); + } + let (p_values, p) = self.read_n_words_value(memory, addr)?; + let p = p.ok_or_else(|| { + RunnerError::ModBuiltinMissingValue(Box::new(( + self.name(), + (addr + N_WORDS).unwrap_or_default(), + ))) + })?; + Ok(Inputs { + p, + p_values, + values_ptr, + offsets_ptr, + n, + }) + } + + // Reads the memory variables to the builtin (see MEMORY_VARS) from the memory given + // the inputs (specifically, values_ptr and offsets_ptr). + // Computes and returns the values of a, b, and c. + fn read_memory_vars( + &self, + memory: &Memory, + values_ptr: Relocatable, + offsets_ptr: Relocatable, + index_in_batch: usize, + ) -> Result<(BigUint, BigUint, BigUint), RunnerError> { + let compute_value = |index: usize| -> Result { + let offset = memory.get_usize((offsets_ptr + (index + 3 * index_in_batch))?)?; + let value_addr = (values_ptr + offset)?; + let (_, value) = self.read_n_words_value(memory, value_addr)?; + let value = value.ok_or_else(|| { + RunnerError::ModBuiltinMissingValue(Box::new(( + self.name(), + (value_addr + N_WORDS).unwrap_or_default(), + ))) + })?; + Ok(value) + }; + + let a = compute_value(0)?; + let b = compute_value(1)?; + let c = compute_value(2)?; + Ok((a, b, c)) + } + + fn fill_inputs( + &self, + memory: &mut Memory, + builtin_ptr: Relocatable, + inputs: &Inputs, + ) -> Result<(), RunnerError> { + if inputs.n > FILL_MEMORY_MAX { + return Err(RunnerError::FillMemoryMaxExceeded(Box::new(( + self.name(), + FILL_MEMORY_MAX, + )))); + } + let n_instances = safe_div_usize(inputs.n, self.instance_def.batch_size)?; + for instance in 1..n_instances { + let instance_ptr = (builtin_ptr + instance * CELLS_PER_MOD as usize)?; + for i in 0..N_WORDS { + memory.insert_as_accessed((instance_ptr + i)?, &inputs.p_values[i])?; + } + memory.insert_as_accessed((instance_ptr + VALUES_PTR_OFFSET)?, &inputs.values_ptr)?; + memory.insert_as_accessed( + (instance_ptr + OFFSETS_PTR_OFFSET)?, + (inputs.offsets_ptr + (3 * instance * self.instance_def.batch_size))?, + )?; + memory.insert_as_accessed( + (instance_ptr + N_OFFSET)?, + inputs + .n + .saturating_sub(instance * self.instance_def.batch_size), + )?; + } + Ok(()) + } + + // Copies the first offsets in the offsets table to its end, n_copies times. + fn fill_offsets( + &self, + memory: &mut Memory, + offsets_ptr: Relocatable, + index: usize, + n_copies: usize, + ) -> Result<(), RunnerError> { + if n_copies.is_zero() { + return Ok(()); + } + for i in 0..3_usize { + let addr = (offsets_ptr + i)?; + let offset = memory + .get(&((offsets_ptr + i)?)) + .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(addr)))? + .into_owned(); + for copy_i in 0..n_copies { + memory.insert_as_accessed((offsets_ptr + (3 * (index + copy_i) + i))?, &offset)?; + } + } + Ok(()) + } + + // Given a value, writes its n_words to memory, starting at address=addr. + fn write_n_words_value( + &self, + memory: &mut Memory, + addr: Relocatable, + value: BigUint, + ) -> Result<(), RunnerError> { + let mut value = value; + for i in 0..N_WORDS { + let word = value.mod_floor(&self.shift); + memory.insert_as_accessed((addr + i)?, Felt252::from(word))?; + value = value.div_floor(&self.shift) + } + if !value.is_zero() { + return Err(RunnerError::WriteNWordsValueNotZero(self.name())); + } + Ok(()) + } + + // Fills a value in the values table, if exactly one value is missing. + // Returns true on success or if all values are already known. + fn fill_value( + &self, + memory: &mut Memory, + inputs: &Inputs, + index: usize, + op: &Operation, + inv_op: &Operation, + ) -> Result { + let mut addresses = Vec::new(); + let mut values = Vec::new(); + for i in 0..3 { + let addr = (inputs.values_ptr + + memory + .get_integer((inputs.offsets_ptr + (3 * index + i))?)? + .as_ref())?; + addresses.push(addr); + let (_, value) = self.read_n_words_value(memory, addr)?; + values.push(value) + } + let (a, b, c) = (&values[0], &values[1], &values[2]); + match (a, b, c) { + // Deduce c from a and b and write it to memory. + (Some(a), Some(b), None) => { + let value = apply_op(a, b, op)?.mod_floor(&inputs.p); + self.write_n_words_value(memory, addresses[2], value)?; + Ok(true) + } + // Deduce b from a and c and write it to memory. + (Some(a), None, Some(c)) => { + let value = apply_op(c, a, inv_op)?.mod_floor(&inputs.p); + self.write_n_words_value(memory, addresses[1], value)?; + Ok(true) + } + // Deduce a from b and c and write it to memory. + (None, Some(b), Some(c)) => { + let value = apply_op(c, b, inv_op)?.mod_floor(&inputs.p); + self.write_n_words_value(memory, addresses[0], value)?; + Ok(true) + } + // All values are already known. + (Some(_), Some(_), Some(_)) => Ok(true), + _ => Ok(false), + } + } + + /// NOTE: It is advisable to use VirtualMachine::mod_builtin_fill_memory instead of this method directly + /// when implementing hints to avoid cloning the runners + + /// Fills the memory with inputs to the builtin instances based on the inputs to the + /// first instance, pads the offsets table to fit the number of operations writen in the + /// input to the first instance, and caculates missing values in the values table. + + /// For each builtin, the given tuple is of the form (builtin_ptr, builtin_runner, n), + /// where n is the number of operations in the offsets table (i.e., the length of the + /// offsets table is 3*n). + + /// The number of operations written to the input of the first instance n' should be at + /// least n and a multiple of batch_size. Previous offsets are copied to the end of the + /// offsets table to make its length 3n'. + pub fn fill_memory( + memory: &mut Memory, + add_mod: Option<(Relocatable, &ModBuiltinRunner, usize)>, + mul_mod: Option<(Relocatable, &ModBuiltinRunner, usize)>, + ) -> Result<(), RunnerError> { + if add_mod.is_none() && mul_mod.is_none() { + return Err(RunnerError::FillMemoryNoBuiltinSet); + } + // Check that the instance definitions of the builtins are the same. + if let (Some((_, add_mod, _)), Some((_, mul_mod, _))) = (add_mod, mul_mod) { + if add_mod.instance_def.word_bit_len != mul_mod.instance_def.word_bit_len { + return Err(RunnerError::ModBuiltinsMismatchedInstanceDef); + } + } + // Fill the inputs to the builtins. + let (add_mod_inputs, add_mod_n) = + if let Some((add_mod_addr, add_mod, add_mod_index)) = add_mod { + let add_mod_inputs = add_mod.read_inputs(memory, add_mod_addr)?; + add_mod.fill_inputs(memory, add_mod_addr, &add_mod_inputs)?; + add_mod.fill_offsets( + memory, + add_mod_inputs.offsets_ptr, + add_mod_index, + add_mod_inputs.n.saturating_sub(add_mod_index), + )?; + (add_mod_inputs, add_mod_index) + } else { + Default::default() + }; + + let (mul_mod_inputs, mul_mod_n) = + if let Some((mul_mod_addr, mul_mod, mul_mod_index)) = mul_mod { + let mul_mod_inputs = mul_mod.read_inputs(memory, mul_mod_addr)?; + mul_mod.fill_inputs(memory, mul_mod_addr, &mul_mod_inputs)?; + mul_mod.fill_offsets( + memory, + mul_mod_inputs.offsets_ptr, + mul_mod_index, + mul_mod_inputs.n.saturating_sub(mul_mod_index), + )?; + (mul_mod_inputs, mul_mod_index) + } else { + Default::default() + }; + + // Get one of the builtin runners - the rest of this function doesn't depend on batch_size. + let mod_runner = if let Some((_, add_mod, _)) = add_mod { + add_mod + } else { + mul_mod.unwrap().1 + }; + // Fill the values table. + let mut add_mod_index = 0; + let mut mul_mod_index = 0; + // Create operation here to avoid cloning p in the loop + let div_operation = Operation::DivMod(mul_mod_inputs.p.clone()); + while add_mod_index < add_mod_n || mul_mod_index < mul_mod_n { + if add_mod_index < add_mod_n + && mod_runner.fill_value( + memory, + &add_mod_inputs, + add_mod_index, + &Operation::Add, + &Operation::Sub, + )? + { + add_mod_index += 1; + } else if mul_mod_index < mul_mod_n + && mod_runner.fill_value( + memory, + &mul_mod_inputs, + mul_mod_index, + &Operation::Mul, + &div_operation, + )? + { + mul_mod_index += 1; + } else { + return Err(RunnerError::FillMemoryCoudNotFillTable( + add_mod_index, + mul_mod_index, + )); + } + } + Ok(()) + } + + // Additional checks added to the standard builtin runner security checks + pub(crate) fn run_additional_security_checks( + &self, + vm: &VirtualMachine, + ) -> Result<(), VirtualMachineError> { + let segment_size = vm + .get_segment_used_size(self.base) + .ok_or(MemoryError::MissingSegmentUsedSizes)?; + let n_instances = div_ceil(segment_size, CELLS_PER_MOD as usize); + let mut prev_inputs = Inputs::default(); + for instance in 0..n_instances { + let inputs = self.read_inputs( + &vm.segments.memory, + (self.base as isize, instance * CELLS_PER_MOD as usize).into(), + )?; + if !instance.is_zero() && prev_inputs.n > self.instance_def.batch_size { + for i in 0..N_WORDS { + if inputs.p_values[i] != prev_inputs.p_values[i] { + return Err(RunnerError::ModBuiltinSecurityCheck(Box::new((self.name(), format!("inputs.p_values[i] != prev_inputs.p_values[i]. Got: i={}, inputs.p_values[i]={}, prev_inputs.p_values[i]={}", + i, inputs.p_values[i], prev_inputs.p_values[i])))).into()); + } + } + if inputs.values_ptr != prev_inputs.values_ptr { + return Err(RunnerError::ModBuiltinSecurityCheck(Box::new((self.name(), format!("inputs.values_ptr != prev_inputs.values_ptr. Got: inputs.values_ptr={}, prev_inputs.values_ptr={}", + inputs.values_ptr, prev_inputs.values_ptr)))).into()); + } + if inputs.offsets_ptr + != (prev_inputs.offsets_ptr + (3 * self.instance_def.batch_size))? + { + return Err(RunnerError::ModBuiltinSecurityCheck(Box::new((self.name(), format!("inputs.offsets_ptr != prev_inputs.offsets_ptr + 3 * batch_size. Got: inputs.offsets_ptr={}, prev_inputs.offsets_ptr={}, batch_size={}", + inputs.values_ptr, prev_inputs.values_ptr, self.instance_def.batch_size)))).into()); + } + if inputs.n != prev_inputs.n.saturating_sub(self.instance_def.batch_size) { + return Err(RunnerError::ModBuiltinSecurityCheck(Box::new((self.name(), format!("inputs.n != prev_inputs.n - batch_size. Got: inputs.n={}, prev_inputs.n={}, batch_size={}", + inputs.n, prev_inputs.n, self.instance_def.batch_size)))).into()); + } + } + for index_in_batch in 0..self.instance_def.batch_size { + let (a, b, c) = self.read_memory_vars( + &vm.segments.memory, + inputs.values_ptr, + inputs.offsets_ptr, + index_in_batch, + )?; + let op = match self.builtin_type { + ModBuiltinType::Add => Operation::Add, + ModBuiltinType::Mul => Operation::Mul, + }; + let a_op_b = apply_op(&a, &b, &op)?.mod_floor(&inputs.p); + if a_op_b != c.mod_floor(&inputs.p) { + // Build error string + let p = inputs.p; + let error_string = format!("Expected a {op} b == c (mod p). Got: instance={instance}, batch={index_in_batch}, p={p}, a={a}, b={b}, c={c}."); + return Err(RunnerError::ModBuiltinSecurityCheck(Box::new(( + self.name(), + error_string, + ))) + .into()); + } + } + prev_inputs = inputs; + } + if !n_instances.is_zero() && prev_inputs.n != self.instance_def.batch_size { + return Err(RunnerError::ModBuiltinSecurityCheck(Box::new(( + self.name(), + format!( + "prev_inputs.n != batch_size Got: prev_inputs.n={}, batch_size={}", + prev_inputs.n, self.instance_def.batch_size + ), + ))) + .into()); + } + Ok(()) + } + + #[cfg(test)] + #[cfg(feature = "mod_builtin")] + // Testing method used to test programs that use parameters which are not included in any layout + // For example, programs with large batch size + pub(crate) fn override_layout_params(&mut self, batch_size: usize, word_bit_len: u32) { + self.instance_def.batch_size = batch_size; + self.instance_def.word_bit_len = word_bit_len; + self.shift = BigUint::one().shl(word_bit_len); + self.shift_powers = core::array::from_fn(|i| self.shift.pow(i as u32)); + self.zero_segment_size = core::cmp::max(N_WORDS, batch_size * 3); + } +} + +fn apply_op(lhs: &BigUint, rhs: &BigUint, op: &Operation) -> Result { + Ok(match op { + Operation::Mul => lhs * rhs, + Operation::Add => lhs + rhs, + Operation::Sub => lhs - rhs, + Operation::DivMod(ref p) => div_mod_unsigned(lhs, rhs, p)?, + }) +} + +#[cfg(test)] +mod tests { + + #[test] + #[cfg(feature = "mod_builtin")] + fn test_air_private_input_small_batch_size() { + use super::*; + use crate::{ + air_private_input::{ModInput, ModInputInstance, ModInputMemoryVars, PrivateInput}, + hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor, + utils::test_utils::Program, + vm::runners::{ + builtin_runner::{BuiltinRunner, ADD_MOD_BUILTIN_NAME, MUL_MOD_BUILTIN_NAME}, + cairo_runner::CairoRunner, + }, + Felt252, + }; + + let program_data = include_bytes!( + "../../../../../cairo_programs/mod_builtin_feature/proof/mod_builtin.json" + ); + + let mut hint_processor = BuiltinHintProcessor::new_empty(); + let program = Program::from_bytes(program_data, Some("main")).unwrap(); + let mut runner = CairoRunner::new(&program, "all_cairo", true).unwrap(); + + let mut vm = VirtualMachine::new(false); + let end = runner.initialize(&mut vm, false).unwrap(); + // Modify add_mod & mul_mod params + for runner in vm.get_builtin_runners_as_mut() { + if let BuiltinRunner::Mod(runner) = runner { + runner.override_layout_params(1, 3) + } + } + + runner + .run_until_pc(end, &mut vm, &mut hint_processor) + .unwrap(); + runner + .run_for_steps(1, &mut vm, &mut hint_processor) + .unwrap(); + runner + .end_run(false, false, &mut vm, &mut hint_processor) + .unwrap(); + runner.read_return_values(&mut vm, false).unwrap(); + runner.finalize_segments(&mut vm).unwrap(); + + let air_private_input = runner.get_air_private_input(&vm); + assert_eq!( + air_private_input.0.get(ADD_MOD_BUILTIN_NAME).unwrap()[0], + PrivateInput::Mod(ModInput { + instances: vec![ + ModInputInstance { + index: 0, + p0: Felt252::ONE, + p1: Felt252::ONE, + p2: Felt252::ZERO, + p3: Felt252::ZERO, + values_ptr: 23023, + offsets_ptr: 23055, + n: 2, + batch: BTreeMap::from([( + 0, + ModInputMemoryVars { + a_offset: 0, + a0: Felt252::ONE, + a1: Felt252::ZERO, + a2: Felt252::ZERO, + a3: Felt252::ZERO, + b_offset: 12, + b0: Felt252::ZERO, + b1: Felt252::ZERO, + b2: Felt252::ZERO, + b3: Felt252::ZERO, + c_offset: 4, + c0: Felt252::TWO, + c1: Felt252::ONE, + c2: Felt252::ZERO, + c3: Felt252::ZERO + } + ),]) + }, + ModInputInstance { + index: 1, + p0: Felt252::ONE, + p1: Felt252::ONE, + p2: Felt252::ZERO, + p3: Felt252::ZERO, + values_ptr: 23023, + offsets_ptr: 23058, + n: 1, + batch: BTreeMap::from([( + 0, + ModInputMemoryVars { + a_offset: 16, + a0: Felt252::ZERO, + a1: Felt252::ZERO, + a2: Felt252::ZERO, + a3: Felt252::ZERO, + b_offset: 20, + b0: Felt252::TWO, + b1: Felt252::ZERO, + b2: Felt252::ZERO, + b3: Felt252::ZERO, + c_offset: 24, + c0: Felt252::TWO, + c1: Felt252::ZERO, + c2: Felt252::ZERO, + c3: Felt252::ZERO + } + ),]) + } + ], + zero_value_address: 22123 + }) + ); + assert_eq!( + air_private_input.0.get(MUL_MOD_BUILTIN_NAME).unwrap()[0], + PrivateInput::Mod(ModInput { + instances: vec![ + ModInputInstance { + index: 0, + p0: Felt252::ONE, + p1: Felt252::ONE, + p2: Felt252::ZERO, + p3: Felt252::ZERO, + values_ptr: 23023, + offsets_ptr: 23061, + n: 3, + batch: BTreeMap::from([( + 0, + ModInputMemoryVars { + a_offset: 12, + a0: Felt252::ZERO, + a1: Felt252::ZERO, + a2: Felt252::ZERO, + a3: Felt252::ZERO, + b_offset: 8, + b0: Felt252::TWO, + b1: Felt252::ZERO, + b2: Felt252::ZERO, + b3: Felt252::ZERO, + c_offset: 16, + c0: Felt252::ZERO, + c1: Felt252::ZERO, + c2: Felt252::ZERO, + c3: Felt252::ZERO + } + ),]) + }, + ModInputInstance { + index: 1, + p0: Felt252::ONE, + p1: Felt252::ONE, + p2: Felt252::ZERO, + p3: Felt252::ZERO, + values_ptr: 23023, + offsets_ptr: 23064, + n: 2, + batch: BTreeMap::from([( + 0, + ModInputMemoryVars { + a_offset: 0, + a0: Felt252::ONE, + a1: Felt252::ZERO, + a2: Felt252::ZERO, + a3: Felt252::ZERO, + b_offset: 8, + b0: Felt252::TWO, + b1: Felt252::ZERO, + b2: Felt252::ZERO, + b3: Felt252::ZERO, + c_offset: 20, + c0: Felt252::TWO, + c1: Felt252::ZERO, + c2: Felt252::ZERO, + c3: Felt252::ZERO + } + ),]) + }, + ModInputInstance { + index: 2, + p0: Felt252::ONE, + p1: Felt252::ONE, + p2: Felt252::ZERO, + p3: Felt252::ZERO, + values_ptr: 23023, + offsets_ptr: 23067, + n: 1, + batch: BTreeMap::from([( + 0, + ModInputMemoryVars { + a_offset: 8, + a0: Felt252::TWO, + a1: Felt252::ZERO, + a2: Felt252::ZERO, + a3: Felt252::ZERO, + b_offset: 28, + b0: Felt252::ONE, + b1: Felt252::ZERO, + b2: Felt252::ZERO, + b3: Felt252::ZERO, + c_offset: 24, + c0: Felt252::TWO, + c1: Felt252::ZERO, + c2: Felt252::ZERO, + c3: Felt252::ZERO + } + ),]) + } + ], + zero_value_address: 22123 + }) + ) + } +} diff --git a/vm/src/vm/runners/builtin_runner/output.rs b/vm/src/vm/runners/builtin_runner/output.rs index 1e3bfe3ad4..c6283d3756 100644 --- a/vm/src/vm/runners/builtin_runner/output.rs +++ b/vm/src/vm/runners/builtin_runner/output.rs @@ -2,16 +2,26 @@ use crate::stdlib::{collections::HashMap, prelude::*}; use crate::types::relocatable::{MaybeRelocatable, Relocatable}; use crate::vm::errors::memory_errors::MemoryError; use crate::vm::errors::runner_errors::RunnerError; -use crate::vm::runners::cairo_pie::{BuiltinAdditionalData, OutputBuiltinAdditionalData}; +use crate::vm::runners::cairo_pie::{ + Attributes, BuiltinAdditionalData, OutputBuiltinAdditionalData, Pages, PublicMemoryPage, +}; use crate::vm::vm_core::VirtualMachine; -use crate::vm::vm_memory::memory::Memory; use crate::vm::vm_memory::memory_segments::MemorySegmentManager; use super::OUTPUT_BUILTIN_NAME; +#[derive(Debug, Clone, PartialEq)] +pub struct OutputBuiltinState { + pub base: usize, + pub pages: Pages, + pub attributes: Attributes, +} + #[derive(Debug, Clone)] pub struct OutputBuiltinRunner { base: usize, + pub(crate) pages: Pages, + pub(crate) attributes: Attributes, pub(crate) stop_ptr: Option, pub(crate) included: bool, } @@ -20,11 +30,21 @@ impl OutputBuiltinRunner { pub fn new(included: bool) -> OutputBuiltinRunner { OutputBuiltinRunner { base: 0, + pages: HashMap::default(), + attributes: HashMap::default(), stop_ptr: None, included, } } + pub fn new_state(&mut self, base: usize, included: bool) { + self.base = base; + self.pages = HashMap::default(); + self.attributes = HashMap::default(); + self.stop_ptr = None; + self.included = included; + } + pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) { self.base = segments.add().segment_index as usize // segments.add() always returns a positive index } @@ -41,24 +61,10 @@ impl OutputBuiltinRunner { self.base } - pub fn add_validation_rule(&self, _memory: &mut Memory) {} - - pub fn deduce_memory_cell( - &self, - _address: Relocatable, - _memory: &Memory, - ) -> Result, RunnerError> { - Ok(None) - } - pub fn get_allocated_memory_units(&self, _vm: &VirtualMachine) -> Result { Ok(0) } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base) @@ -108,12 +114,71 @@ impl OutputBuiltinRunner { } } + pub fn add_attribute(&mut self, name: String, value: Vec) { + self.attributes.insert(name, value); + } + pub fn get_additional_data(&self) -> BuiltinAdditionalData { BuiltinAdditionalData::Output(OutputBuiltinAdditionalData { - pages: HashMap::default(), - attributes: HashMap::default(), + pages: self.pages.clone(), + attributes: self.attributes.clone(), }) } + + pub(crate) fn set_stop_ptr_offset(&mut self, offset: usize) { + self.stop_ptr = Some(offset) + } + + pub fn set_state(&mut self, new_state: OutputBuiltinState) { + self.base = new_state.base; + self.pages = new_state.pages; + self.attributes = new_state.attributes; + } + + pub fn get_state(&mut self) -> OutputBuiltinState { + OutputBuiltinState { + base: self.base, + pages: self.pages.clone(), + attributes: self.attributes.clone(), + } + } + + pub fn add_page( + &mut self, + page_id: usize, + page_start: Relocatable, + page_size: usize, + ) -> Result<(), RunnerError> { + if page_start.segment_index as usize != self.base { + return Err(RunnerError::PageNotOnSegment(page_start, self.base)); + } + + self.pages.insert( + page_id, + PublicMemoryPage { + start: page_start.offset, + size: page_size, + }, + ); + + Ok(()) + } + + pub fn get_public_memory( + &self, + segments: &MemorySegmentManager, + ) -> Result, RunnerError> { + let size = self.get_used_cells(segments)?; + + let mut public_memory: Vec<(usize, usize)> = (0..size).map(|i| (i, 0)).collect(); + for (page_id, page) in self.pages.iter() { + for index in 0..page.size { + public_memory[page.start + index].1 = *page_id; + } + } + + Ok(public_memory) + } } impl Default for OutputBuiltinRunner { @@ -297,54 +362,6 @@ mod tests { assert_eq!(initial_stack.len(), 1); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = OutputBuiltinRunner::new(true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None),); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true)); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = BuiltinRunner::Output(OutputBuiltinRunner::new(true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { @@ -425,7 +442,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_add_validation_rule() { - let builtin = OutputBuiltinRunner::new(true); + let builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into(); let mut vm = vm!(); vm.segments = segments![ @@ -456,7 +473,131 @@ mod tests { fn get_air_private_input() { let builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into(); - let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((0, 3), 3)]; - assert!(builtin.air_private_input(&memory).is_empty()); + let segments = segments![((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((0, 3), 3)]; + assert!(builtin.air_private_input(&segments).is_empty()); + } + + #[test] + fn set_state() { + let mut builtin = OutputBuiltinRunner::new(true); + assert_eq!(builtin.base, 0); + + let new_state = OutputBuiltinState { + base: 10, + pages: HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), + attributes: HashMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), + }; + builtin.set_state(new_state.clone()); + + assert_eq!(builtin.base, new_state.base); + assert_eq!(builtin.pages, new_state.pages); + assert_eq!(builtin.attributes, new_state.attributes); + + let state = builtin.get_state(); + assert_eq!(state, new_state); + } + + #[test] + fn new_state() { + let mut builtin = OutputBuiltinRunner { + base: 10, + pages: HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 })]), + attributes: HashMap::from([("gps_fact_topology".to_string(), vec![0, 2, 0])]), + stop_ptr: Some(10), + included: true, + }; + + let new_base = 11; + let new_included = false; + builtin.new_state(new_base, new_included); + + assert_eq!(builtin.base, new_base); + assert!(builtin.pages.is_empty()); + assert!(builtin.attributes.is_empty()); + assert_eq!(builtin.stop_ptr, None); + assert_eq!(builtin.included, new_included); + } + + #[test] + fn add_page() { + let mut builtin = OutputBuiltinRunner::new(true); + assert_eq!( + builtin.add_page( + 1, + Relocatable { + segment_index: builtin.base() as isize, + offset: 0 + }, + 3 + ), + Ok(()) + ); + + assert_eq!( + builtin.pages, + HashMap::from([(1, PublicMemoryPage { start: 0, size: 3 }),]) + ) + } + + #[test] + fn add_page_wrong_segment() { + let mut builtin = OutputBuiltinRunner::new(true); + let page_start = Relocatable { + segment_index: 18, + offset: 0, + }; + + let result = builtin.add_page(1, page_start, 3); + assert!( + matches!(result, Err(RunnerError::PageNotOnSegment(relocatable, base)) if relocatable == page_start && base == builtin.base()) + ) + } + + #[test] + pub fn add_attribute() { + let mut builtin = OutputBuiltinRunner::new(true); + assert!(builtin.attributes.is_empty()); + + let name = "gps_fact_topology".to_string(); + let values = vec![0, 12, 30]; + builtin.add_attribute(name.clone(), values.clone()); + + assert_eq!(builtin.attributes, HashMap::from([(name, values)])); + } + + #[test] + fn get_public_memory() { + let mut builtin = OutputBuiltinRunner::new(true); + + builtin + .add_page( + 1, + Relocatable { + segment_index: builtin.base() as isize, + offset: 2, + }, + 2, + ) + .unwrap(); + + builtin + .add_page( + 2, + Relocatable { + segment_index: builtin.base() as isize, + offset: 4, + }, + 3, + ) + .unwrap(); + + let mut segments = MemorySegmentManager::new(); + segments.segment_used_sizes = Some(vec![7]); + + let public_memory = builtin.get_public_memory(&segments).unwrap(); + assert_eq!( + public_memory, + vec![(0, 0), (1, 0), (2, 1), (3, 1), (4, 2), (5, 2), (6, 2)] + ); } } diff --git a/vm/src/vm/runners/builtin_runner/poseidon.rs b/vm/src/vm/runners/builtin_runner/poseidon.rs index a668ba324b..51b12cc73b 100644 --- a/vm/src/vm/runners/builtin_runner/poseidon.rs +++ b/vm/src/vm/runners/builtin_runner/poseidon.rs @@ -19,12 +19,9 @@ use super::POSEIDON_BUILTIN_NAME; pub struct PoseidonBuiltinRunner { pub base: usize, ratio: Option, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, pub(crate) stop_ptr: Option, pub(crate) included: bool, cache: RefCell>, - pub(crate) instances_per_component: u32, } impl PoseidonBuiltinRunner { @@ -32,12 +29,9 @@ impl PoseidonBuiltinRunner { PoseidonBuiltinRunner { base: 0, ratio, - cells_per_instance: CELLS_PER_POSEIDON, - n_input_cells: INPUT_CELLS_PER_POSEIDON, stop_ptr: None, included, cache: RefCell::new(HashMap::new()), - instances_per_component: 1, } } @@ -68,19 +62,19 @@ impl PoseidonBuiltinRunner { address: Relocatable, memory: &Memory, ) -> Result, RunnerError> { - let index = address.offset % self.cells_per_instance as usize; - if index < self.n_input_cells as usize { + let index = address.offset % CELLS_PER_POSEIDON as usize; + if index < INPUT_CELLS_PER_POSEIDON as usize { return Ok(None); } if let Some(felt) = self.cache.borrow().get(&address) { return Ok(Some(felt.into())); } let first_input_addr = (address - index)?; - let first_output_addr = (first_input_addr + self.n_input_cells as usize)?; + let first_output_addr = (first_input_addr + INPUT_CELLS_PER_POSEIDON as usize)?; let mut input_felts = vec![]; - for i in 0..self.n_input_cells as usize { + for i in 0..INPUT_CELLS_PER_POSEIDON as usize { let m_index = (first_input_addr + i)?; let val = match memory.get(&m_index) { Some(value) => { @@ -110,10 +104,6 @@ impl PoseidonBuiltinRunner { Ok(self.cache.borrow().get(&address).map(|x| x.into())) } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base()) @@ -125,44 +115,7 @@ impl PoseidonBuiltinRunner { segments: &MemorySegmentManager, ) -> Result { let used_cells = self.get_used_cells(segments)?; - Ok(div_ceil(used_cells, self.cells_per_instance as usize)) - } - - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(POSEIDON_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(POSEIDON_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - POSEIDON_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - POSEIDON_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } + Ok(div_ceil(used_cells, CELLS_PER_POSEIDON as usize)) } pub fn air_private_input(&self, memory: &Memory) -> Vec { @@ -231,7 +184,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = PoseidonBuiltinRunner::new(Some(10), true); + let mut builtin: BuiltinRunner = PoseidonBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -255,7 +208,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = PoseidonBuiltinRunner::new(Some(10), true); + let mut builtin: BuiltinRunner = PoseidonBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -283,7 +236,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_when_not_included() { - let mut builtin = PoseidonBuiltinRunner::new(Some(10), false); + let mut builtin: BuiltinRunner = PoseidonBuiltinRunner::new(Some(10), false).into(); let mut vm = vm!(); @@ -307,7 +260,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = PoseidonBuiltinRunner::new(Some(10), true); + let mut builtin: BuiltinRunner = PoseidonBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); @@ -365,7 +318,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -409,7 +362,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -443,7 +396,7 @@ mod tests { fn get_air_private_input() { let builtin: BuiltinRunner = PoseidonBuiltinRunner::new(None, true).into(); - let memory = memory![ + let segments = segments![ ((0, 0), 0), ((0, 1), 1), ((0, 2), 2), @@ -458,7 +411,7 @@ mod tests { ((0, 11), 11) ]; assert_eq!( - builtin.air_private_input(&memory), + builtin.air_private_input(&segments), (vec![ PrivateInput::PoseidonState(PrivateInputPoseidonState { index: 0, diff --git a/vm/src/vm/runners/builtin_runner/range_check.rs b/vm/src/vm/runners/builtin_runner/range_check.rs index ba07f6f253..b9b49992ce 100644 --- a/vm/src/vm/runners/builtin_runner/range_check.rs +++ b/vm/src/vm/runners/builtin_runner/range_check.rs @@ -8,12 +8,9 @@ use crate::{ use crate::Felt252; use crate::{ - types::{ - instance_definitions::range_check_instance_def::CELLS_PER_RANGE_CHECK, - relocatable::{MaybeRelocatable, Relocatable}, - }, + types::relocatable::{MaybeRelocatable, Relocatable}, vm::{ - errors::{memory_errors::MemoryError, runner_errors::RunnerError}, + errors::memory_errors::MemoryError, vm_memory::{ memory::{Memory, ValidationRule}, memory_segments::MemorySegmentManager, @@ -21,50 +18,37 @@ use crate::{ }, }; -use num_traits::Zero; +use lazy_static::lazy_static; -use super::RANGE_CHECK_BUILTIN_NAME; +use super::{RANGE_CHECK_96_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME}; -// NOTE: the current implementation is based on the bound 0x10000 -const _INNER_RC_BOUND: u64 = 1u64 << INNER_RC_BOUND_SHIFT; const INNER_RC_BOUND_SHIFT: u64 = 16; const INNER_RC_BOUND_MASK: u64 = u16::MAX as u64; -// TODO: use constant instead of receiving as false parameter -const N_PARTS: u64 = 8; +pub const RC_N_PARTS_STANDARD: u64 = 8; +pub const RC_N_PARTS_96: u64 = 6; + +lazy_static! { + pub static ref BOUND_STANDARD: Felt252 = + Felt252::TWO.pow(INNER_RC_BOUND_SHIFT * RC_N_PARTS_STANDARD); + pub static ref BOUND_96: Felt252 = Felt252::TWO.pow(INNER_RC_BOUND_SHIFT * RC_N_PARTS_96); +} #[derive(Debug, Clone)] -pub struct RangeCheckBuiltinRunner { +pub struct RangeCheckBuiltinRunner { ratio: Option, base: usize, pub(crate) stop_ptr: Option, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, - pub _bound: Option, pub(crate) included: bool, - pub(crate) n_parts: u32, - pub(crate) instances_per_component: u32, } -impl RangeCheckBuiltinRunner { - pub fn new(ratio: Option, n_parts: u32, included: bool) -> RangeCheckBuiltinRunner { - let bound = Felt252::TWO.pow(16 * n_parts as u128); - let _bound = if n_parts != 0 && bound.is_zero() { - None - } else { - Some(bound) - }; - +impl RangeCheckBuiltinRunner { + pub fn new(ratio: Option, included: bool) -> RangeCheckBuiltinRunner { RangeCheckBuiltinRunner { ratio, base: 0, stop_ptr: None, - cells_per_instance: CELLS_PER_RANGE_CHECK, - n_input_cells: CELLS_PER_RANGE_CHECK, - _bound, included, - n_parts, - instances_per_component: 1, } } @@ -88,8 +72,26 @@ impl RangeCheckBuiltinRunner { self.ratio } + pub fn name(&self) -> &'static str { + match N_PARTS { + RC_N_PARTS_96 => RANGE_CHECK_96_BUILTIN_NAME, + _ => RANGE_CHECK_BUILTIN_NAME, + } + } + + pub fn n_parts(&self) -> u64 { + N_PARTS + } + + pub fn bound(&self) -> &'static Felt252 { + match N_PARTS { + RC_N_PARTS_96 => &BOUND_96, + _ => &BOUND_STANDARD, + } + } + pub fn add_validation_rule(&self, memory: &mut Memory) { - let rule: ValidationRule = ValidationRule(Box::new( + let rule = ValidationRule(Box::new( |memory: &Memory, address: Relocatable| -> Result, MemoryError> { let num = memory .get_integer(address) @@ -107,18 +109,6 @@ impl RangeCheckBuiltinRunner { memory.add_validation_rule(self.base, rule); } - pub fn deduce_memory_cell( - &self, - _address: Relocatable, - _memory: &Memory, - ) -> Result, RunnerError> { - Ok(None) - } - - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base) @@ -144,7 +134,7 @@ impl RangeCheckBuiltinRunner { .rev() .map(move |i| ((digit >> (i * INNER_RC_BOUND_SHIFT)) & INNER_RC_BOUND_MASK)) }) - .take(self.n_parts as usize) + .take(N_PARTS as usize) .fold(rc_bounds, |mm, x| { (min(mm.0, x as usize), max(mm.1, x as usize)) }); @@ -159,43 +149,6 @@ impl RangeCheckBuiltinRunner { self.get_used_cells(segments) } - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(RANGE_CHECK_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(RANGE_CHECK_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - RANGE_CHECK_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - RANGE_CHECK_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } - } - pub fn air_private_input(&self, memory: &Memory) -> Vec { let mut private_inputs = vec![]; if let Some(segment) = memory.data.get(self.base) { @@ -214,7 +167,8 @@ mod tests { use super::*; use crate::relocatable; use crate::serde::deserialize_program::BuiltinName; - use crate::stdlib::collections::HashMap; + use crate::vm::errors::runner_errors::RunnerError; + use crate::vm::runners::builtin_runner::RANGE_CHECK_BUILTIN_NAME; use crate::vm::vm_memory::memory::Memory; use crate::{ hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor, @@ -232,7 +186,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_instances() { - let builtin = RangeCheckBuiltinRunner::new(Some(10), 12, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(10), true); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![1]); @@ -243,7 +197,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(10), 12, true); + let mut builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(10), true).into(); let mut vm = vm!(); @@ -267,7 +222,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(10), 12, true); + let mut builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(10), true).into(); let mut vm = vm!(); @@ -295,7 +251,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_when_notincluded() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(10), 12, false); + let mut builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(10), false).into(); let mut vm = vm!(); @@ -319,7 +276,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(10), 12, true); + let mut builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(10), true).into(); let mut vm = vm!(); @@ -345,7 +303,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_and_allocated_size_test() { - let builtin: BuiltinRunner = RangeCheckBuiltinRunner::new(Some(10), 12, true).into(); + let builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(10), true).into(); let mut vm = vm!(); @@ -379,7 +338,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -391,7 +350,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_units() { - let builtin: BuiltinRunner = RangeCheckBuiltinRunner::new(Some(10), 12, true).into(); + let builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(10), true).into(); let mut vm = vm!(); @@ -423,7 +383,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); - let address = cairo_runner.initialize(&mut vm).unwrap(); + let address = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(address, &mut vm, &mut hint_processor) @@ -435,7 +395,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_segments_for_range_check() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let mut builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let mut segments = MemorySegmentManager::new(); builtin.initialize_segments(&mut segments); assert_eq!(builtin.base, 0); @@ -444,7 +404,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_initial_stack_for_range_check_with_base() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let mut builtin = RangeCheckBuiltinRunner::::new(Some(8), true); builtin.base = 1; let initial_stack = builtin.initial_stack(); assert_eq!( @@ -454,72 +414,26 @@ mod tests { assert_eq!(initial_stack.len(), 1); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None),); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(256), 8, true)); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(256), 8, true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(256), 8, true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_base() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(8), true); assert_eq!(builtin.base(), 0); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_ratio() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(8), true); assert_eq!(builtin.ratio(), Some(8)); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(256), 8, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(256), true), + ); let vm = vm!(); assert_eq!( @@ -531,7 +445,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_empty() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(256), 8, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(256), true), + ); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); @@ -541,7 +457,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells() { - let builtin = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(Some(256), 8, true)); + let builtin = BuiltinRunner::RangeCheck( + RangeCheckBuiltinRunner::::new(Some(256), true), + ); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); @@ -551,7 +469,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_usage_succesful_a() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3), ((0, 3), 4)]; assert_eq!(builtin.get_range_check_usage(&memory), Some((0, 4))); } @@ -559,7 +477,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_usage_succesful_b() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let memory = memory![ ((0, 0), 1465218365), ((0, 1), 2134570341), @@ -572,7 +490,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_usage_succesful_c() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let memory = memory![ ((0, 0), 634834751465218365_i64), ((0, 1), 42876922134570341_i64), @@ -587,7 +505,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_range_check_empty_memory() { - let builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let memory = Memory::new(); assert_eq!(builtin.get_range_check_usage(&memory), None); } @@ -596,7 +514,8 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_perm_range_check_units() { - let builtin_runner: BuiltinRunner = RangeCheckBuiltinRunner::new(Some(8), 8, true).into(); + let builtin_runner: BuiltinRunner = + RangeCheckBuiltinRunner::::new(Some(8), true).into(); let mut vm = vm!(); vm.current_step = 8; @@ -607,11 +526,12 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_air_private_input() { - let builtin: BuiltinRunner = RangeCheckBuiltinRunner::new(None, 4, true).into(); + let builtin: BuiltinRunner = + RangeCheckBuiltinRunner::::new(None, true).into(); - let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 2)]; + let segments = segments![((0, 0), 0), ((0, 1), 1), ((0, 2), 2)]; assert_eq!( - builtin.air_private_input(&memory), + builtin.air_private_input(&segments), (vec![ PrivateInput::Value(PrivateInputValue { index: 0, diff --git a/vm/src/vm/runners/builtin_runner/segment_arena.rs b/vm/src/vm/runners/builtin_runner/segment_arena.rs index 82c9e72aea..5cc61fb706 100644 --- a/vm/src/vm/runners/builtin_runner/segment_arena.rs +++ b/vm/src/vm/runners/builtin_runner/segment_arena.rs @@ -1,7 +1,4 @@ -use crate::stdlib::boxed::Box; use crate::vm::errors::memory_errors::MemoryError; -use crate::vm::errors::runner_errors::RunnerError; -use crate::vm::vm_memory::memory::Memory; use crate::{ types::relocatable::{MaybeRelocatable, Relocatable}, vm::vm_memory::memory_segments::MemorySegmentManager, @@ -9,19 +6,16 @@ use crate::{ #[cfg(not(feature = "std"))] use alloc::vec::Vec; +use num_integer::div_ceil; -use super::SEGMENT_ARENA_BUILTIN_NAME; - -const ARENA_BUILTIN_SIZE: u32 = 3; +pub(crate) const ARENA_BUILTIN_SIZE: u32 = 3; // The size of the builtin segment at the time of its creation. const INITIAL_SEGMENT_SIZE: usize = ARENA_BUILTIN_SIZE as usize; #[derive(Debug, Clone)] pub struct SegmentArenaBuiltinRunner { base: Relocatable, - included: bool, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells_per_instance: u32, + pub(crate) included: bool, pub(crate) stop_ptr: Option, } @@ -30,8 +24,6 @@ impl SegmentArenaBuiltinRunner { SegmentArenaBuiltinRunner { base: Relocatable::from((0, 0)), included, - cells_per_instance: ARENA_BUILTIN_SIZE, - n_input_cells_per_instance: ARENA_BUILTIN_SIZE, stop_ptr: None, } } @@ -65,60 +57,14 @@ impl SegmentArenaBuiltinRunner { } } - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(SEGMENT_ARENA_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(SEGMENT_ARENA_BUILTIN_NAME)))?; - if self.base.segment_index != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - SEGMENT_ARENA_BUILTIN_NAME, - stop_pointer, - self.base.segment_index as usize, - )))); - } - let used = self.get_used_cells(segments).map_err(RunnerError::Memory)?; - if stop_pointer != (self.base + used)? { - return Err(RunnerError::InvalidStopPointer(Box::new(( - SEGMENT_ARENA_BUILTIN_NAME, - (self.base + used)?, - stop_pointer, - )))); - } - self.stop_ptr = Some(stop_pointer.offset); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(self.base.offset); - Ok(pointer) - } - } - pub fn get_used_instances( &self, segments: &MemorySegmentManager, ) -> Result { - self.get_used_cells(segments) - } - - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base.segment_index as usize, self.stop_ptr) - } - - pub fn add_validation_rule(&self, _memory: &mut Memory) {} - - pub fn deduce_memory_cell( - &self, - _address: Relocatable, - _memory: &Memory, - ) -> Result, RunnerError> { - Ok(None) + Ok(div_ceil( + self.get_used_cells(segments)?, + ARENA_BUILTIN_SIZE as usize, + )) } pub fn base(&self) -> usize { @@ -142,9 +88,12 @@ fn gen_arg(segments: &mut MemorySegmentManager, data: &[MaybeRelocatable; 3]) -> #[cfg(test)] mod tests { use super::*; - use crate::stdlib::collections::HashMap; + use crate::vm::errors::runner_errors::RunnerError; + use crate::vm::runners::builtin_runner::SEGMENT_ARENA_BUILTIN_NAME; use crate::vm::vm_core::VirtualMachine; use crate::{relocatable, utils::test_utils::*, vm::runners::builtin_runner::BuiltinRunner}; + #[cfg(not(feature = "std"))] + use alloc::boxed::Box; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -187,7 +136,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = SegmentArenaBuiltinRunner::new(true); + let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into(); let mut vm = vm!(); @@ -214,7 +163,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_valid() { - let mut builtin = SegmentArenaBuiltinRunner::new(false); + let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(false).into(); let mut vm = vm!(); @@ -262,7 +211,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = SegmentArenaBuiltinRunner::new(true); + let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into(); let mut vm = vm!(); @@ -322,43 +271,6 @@ mod tests { assert_eq!(initial_stack.len(), 1); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = SegmentArenaBuiltinRunner::new(true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None),); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true)); - let vm = vm!(); - - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![]),); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true)); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![]),); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { @@ -412,8 +324,8 @@ mod tests { let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true)); let mut memory_segment_manager = MemorySegmentManager::new(); memory_segment_manager.segment_used_sizes = Some(vec![6]); - - assert_eq!(builtin.get_used_instances(&memory_segment_manager), Ok(3)); + // (SIZE(6) - INITIAL_SIZE(3)) / CELLS_PER_INSTANCE(3) + assert_eq!(builtin.get_used_instances(&memory_segment_manager), Ok(1)); } #[test] @@ -437,14 +349,6 @@ mod tests { ); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_add_validation_rule() { - let builtin = SegmentArenaBuiltinRunner::new(true); - let mut vm = vm!(); - builtin.add_validation_rule(&mut vm.segments.memory); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initial_stackincluded_test() { @@ -502,7 +406,7 @@ mod tests { fn get_air_private_input() { let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into(); - let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((0, 3), 3)]; - assert!(builtin.air_private_input(&memory).is_empty()); + let segments = segments![((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((0, 3), 3)]; + assert!(builtin.air_private_input(&segments).is_empty()); } } diff --git a/vm/src/vm/runners/builtin_runner/signature.rs b/vm/src/vm/runners/builtin_runner/signature.rs index d854afa05a..9520ebcc63 100644 --- a/vm/src/vm/runners/builtin_runner/signature.rs +++ b/vm/src/vm/runners/builtin_runner/signature.rs @@ -7,12 +7,9 @@ use crate::types::instance_definitions::ecdsa_instance_def::CELLS_PER_SIGNATURE; use crate::vm::runners::cairo_pie::BuiltinAdditionalData; use crate::Felt252; use crate::{ - types::{ - instance_definitions::ecdsa_instance_def::EcdsaInstanceDef, - relocatable::{MaybeRelocatable, Relocatable}, - }, + types::relocatable::{MaybeRelocatable, Relocatable}, vm::{ - errors::{memory_errors::MemoryError, runner_errors::RunnerError}, + errors::memory_errors::MemoryError, vm_memory::{ memory::{Memory, ValidationRule}, memory_segments::MemorySegmentManager, @@ -33,32 +30,22 @@ lazy_static! { .unwrap(); } -use super::SIGNATURE_BUILTIN_NAME; - #[derive(Debug, Clone)] pub struct SignatureBuiltinRunner { pub(crate) included: bool, ratio: Option, base: usize, - pub(crate) cells_per_instance: u32, - pub(crate) n_input_cells: u32, - _total_n_bits: u32, pub(crate) stop_ptr: Option, - pub(crate) instances_per_component: u32, signatures: Rc>>, } impl SignatureBuiltinRunner { - pub(crate) fn new(instance_def: &EcdsaInstanceDef, included: bool) -> Self { + pub(crate) fn new(ratio: Option, included: bool) -> Self { SignatureBuiltinRunner { base: 0, included, - ratio: instance_def.ratio, - cells_per_instance: 2, - n_input_cells: 2, - _total_n_bits: 251, + ratio, stop_ptr: None, - instances_per_component: 1, signatures: Rc::new(RefCell::new(HashMap::new())), } } @@ -106,7 +93,7 @@ impl SignatureBuiltinRunner { self.base } pub fn add_validation_rule(&self, memory: &mut Memory) { - let cells_per_instance = self.cells_per_instance; + let cells_per_instance = CELLS_PER_SIGNATURE; let signatures = Rc::clone(&self.signatures); let rule: ValidationRule = ValidationRule(Box::new( move |memory: &Memory, addr: Relocatable| -> Result, MemoryError> { @@ -156,22 +143,10 @@ impl SignatureBuiltinRunner { memory.add_validation_rule(self.base, rule); } - pub fn deduce_memory_cell( - &self, - _address: Relocatable, - _memory: &Memory, - ) -> Result, RunnerError> { - Ok(None) - } - pub fn ratio(&self) -> Option { self.ratio } - pub fn get_memory_segment_addresses(&self) -> (usize, Option) { - (self.base, self.stop_ptr) - } - pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { segments .get_segment_used_size(self.base) @@ -183,44 +158,7 @@ impl SignatureBuiltinRunner { segments: &MemorySegmentManager, ) -> Result { let used_cells = self.get_used_cells(segments)?; - Ok(div_ceil(used_cells, self.cells_per_instance as usize)) - } - - pub fn final_stack( - &mut self, - segments: &MemorySegmentManager, - pointer: Relocatable, - ) -> Result { - if self.included { - let stop_pointer_addr = (pointer - 1) - .map_err(|_| RunnerError::NoStopPointer(Box::new(SIGNATURE_BUILTIN_NAME)))?; - let stop_pointer = segments - .memory - .get_relocatable(stop_pointer_addr) - .map_err(|_| RunnerError::NoStopPointer(Box::new(SIGNATURE_BUILTIN_NAME)))?; - if self.base as isize != stop_pointer.segment_index { - return Err(RunnerError::InvalidStopPointerIndex(Box::new(( - SIGNATURE_BUILTIN_NAME, - stop_pointer, - self.base, - )))); - } - let stop_ptr = stop_pointer.offset; - let num_instances = self.get_used_instances(segments)?; - let used = num_instances * self.cells_per_instance as usize; - if stop_ptr != used { - return Err(RunnerError::InvalidStopPointer(Box::new(( - SIGNATURE_BUILTIN_NAME, - Relocatable::from((self.base as isize, used)), - Relocatable::from((self.base as isize, stop_ptr)), - )))); - } - self.stop_ptr = Some(stop_ptr); - Ok(stop_pointer_addr) - } else { - self.stop_ptr = Some(0); - Ok(pointer) - } + Ok(div_ceil(used_cells, CELLS_PER_SIGNATURE as usize)) } pub fn get_additional_data(&self) -> BuiltinAdditionalData { @@ -278,11 +216,13 @@ mod tests { use super::*; use crate::{ relocatable, - types::instance_definitions::ecdsa_instance_def::EcdsaInstanceDef, utils::test_utils::*, vm::{ - errors::memory_errors::{InsufficientAllocatedCellsError, MemoryError}, - runners::builtin_runner::BuiltinRunner, + errors::{ + memory_errors::{InsufficientAllocatedCellsError, MemoryError}, + runner_errors::RunnerError, + }, + runners::builtin_runner::{BuiltinRunner, SIGNATURE_BUILTIN_NAME}, vm_core::VirtualMachine, vm_memory::{memory::Memory, memory_segments::MemorySegmentManager}, }, @@ -294,8 +234,7 @@ mod tests { #[test] fn get_used_cells_and_allocated_size_valid() { - let builtin: BuiltinRunner = - SignatureBuiltinRunner::new(&EcdsaInstanceDef::new(Some(10)), true).into(); + let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(10), true).into(); let mut vm = vm!(); vm.current_step = 110; vm.segments.segment_used_sizes = Some(vec![1]); @@ -305,7 +244,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_segments_for_ecdsa() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(Some(512), true); let mut segments = MemorySegmentManager::new(); builtin.initialize_segments(&mut segments); assert_eq!(builtin.base, 0); @@ -314,8 +253,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_instances() { - let builtin: BuiltinRunner = - SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![1]); @@ -326,7 +264,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); @@ -350,7 +288,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_stop_pointer() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); @@ -378,7 +316,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_error_non_relocatable() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); @@ -399,70 +337,10 @@ mod tests { ); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_segment_addresses() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None)); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_missing_segment_used_sizes() { - let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), - true, - )); - let vm = vm!(); - - assert_eq!( - builtin.get_memory_accesses(&vm), - Err(MemoryError::MissingSegmentUsedSizes), - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses_empty() { - let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), - true, - )); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_memory_accesses(&vm), Ok(vec![])); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn get_memory_accesses() { - let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), - true, - )); - let mut vm = vm!(); - - vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!( - builtin.get_memory_accesses(&vm), - Ok(vec![ - (builtin.base() as isize, 0).into(), - (builtin.base() as isize, 1).into(), - (builtin.base() as isize, 2).into(), - (builtin.base() as isize, 3).into(), - ]), - ); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_missing_segment_used_sizes() { - let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), true)); let vm = vm!(); assert_eq!( @@ -474,10 +352,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_empty() { - let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), true)); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); @@ -487,10 +362,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells() { - let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new( - &EcdsaInstanceDef::default(), - true, - )); + let builtin = BuiltinRunner::Signature(SignatureBuiltinRunner::new(Some(512), true)); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); @@ -500,7 +372,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_initial_stack_for_range_check_with_base() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(Some(512), true); builtin.base = 1; let initial_stack = builtin.initial_stack(); assert_eq!( @@ -513,7 +385,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initial_stack_not_included_test() { - let ecdsa_builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), false); + let ecdsa_builtin = SignatureBuiltinRunner::new(Some(512), false); assert_eq!(ecdsa_builtin.initial_stack(), Vec::new()) } @@ -521,7 +393,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_test() { let memory = Memory::new(); - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory); assert_eq!(result, Ok(None)); } @@ -529,39 +401,21 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_ratio() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let builtin = SignatureBuiltinRunner::new(Some(512), true); assert_eq!(builtin.ratio(), Some(512)); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_base() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let builtin = SignatureBuiltinRunner::new(Some(512), true); assert_eq!(builtin.base(), 0); } - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_get_memory_segment_addresses() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); - - assert_eq!(builtin.get_memory_segment_addresses(), (0, None)); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn deduce_memory_cell() { - let memory = Memory::new(); - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); - let result = builtin.deduce_memory_cell(Relocatable::from((0, 5)), &memory); - assert_eq!(result, Ok(None)); - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_allocated_memory_min_step_not_reached() { - let builtin: BuiltinRunner = - SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); vm.current_step = 500; assert_eq!( @@ -578,8 +432,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_used_cells_and_allocated_size_insufficient_allocated() { - let builtin: BuiltinRunner = - SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true).into(); + let builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![50]); vm.current_step = 512; @@ -598,7 +451,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_invalid_stop_pointer() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); vm.segments = segments![((0, 0), (1, 0))]; assert_eq!( @@ -614,7 +467,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn final_stack_no_used_instances() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin: BuiltinRunner = SignatureBuiltinRunner::new(Some(512), true).into(); let mut vm = vm!(); vm.segments = segments![((0, 0), (0, 0))]; assert_eq!( @@ -625,7 +478,7 @@ mod tests { #[test] fn get_additional_info() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(Some(512), true); let signatures = HashMap::from([( Relocatable::from((4, 0)), Signature { diff --git a/vm/src/vm/runners/cairo_pie.rs b/vm/src/vm/runners/cairo_pie.rs index a768893d02..16bcb80d41 100644 --- a/vm/src/vm/runners/cairo_pie.rs +++ b/vm/src/vm/runners/cairo_pie.rs @@ -84,6 +84,7 @@ pub struct CairoPieMetadata { pub execution_segment: SegmentInfo, pub ret_fp_segment: SegmentInfo, pub ret_pc_segment: SegmentInfo, + #[serde(serialize_with = "serde_impl::serialize_builtin_segments")] pub builtin_segments: HashMap, pub extra_segments: Vec, } @@ -113,7 +114,7 @@ impl CairoPie { let file = File::create(file_path)?; let mut zip_writer = ZipWriter::new(file); let options = - zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Stored); + zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated); zip_writer.start_file("version.json", options)?; zip_writer.write_all(serde_json::to_string(&self.version)?.as_bytes())?; zip_writer.start_file("metadata.json", options)?; @@ -132,8 +133,9 @@ impl CairoPie { mod serde_impl { use crate::stdlib::collections::HashMap; use num_traits::Num; + use serde::ser::SerializeMap; - use super::{CairoPieMemory, CAIRO_PIE_VERSION}; + use super::{CairoPieMemory, SegmentInfo, CAIRO_PIE_VERSION}; use crate::stdlib::prelude::{String, Vec}; use crate::{ types::relocatable::{MaybeRelocatable, Relocatable}, @@ -223,12 +225,11 @@ mod serde_impl { }; } - serializer.serialize_str( - res.iter() - .map(|b| format!("{:02x}", b)) - .collect::() - .as_str(), - ) + let string = res + .iter() + .fold(String::new(), |string, b| string + &format!("{:02x}", b)); + + serializer.serialize_str(&string) } impl CairoPieMemory { @@ -320,6 +321,33 @@ mod serde_impl { seq_serializer.end() } + + pub fn serialize_builtin_segments( + values: &HashMap, + serializer: S, + ) -> Result + where + S: Serializer, + { + let mut map_serializer = serializer.serialize_map(Some(values.len()))?; + const BUILTIN_ORDERED_LIST: &[&str] = &[ + "output", + "pedersen", + "range_check", + "ecdsa", + "bitwise", + "ec_op", + "keccak", + "poseidon", + ]; + + for name in BUILTIN_ORDERED_LIST { + if let Some(info) = values.get(*name) { + map_serializer.serialize_entry(name, info)? + } + } + map_serializer.end() + } } #[cfg(test)] diff --git a/vm/src/vm/runners/cairo_runner.rs b/vm/src/vm/runners/cairo_runner.rs index 82fa3bcb30..c61c39b071 100644 --- a/vm/src/vm/runners/cairo_runner.rs +++ b/vm/src/vm/runners/cairo_runner.rs @@ -7,7 +7,7 @@ use crate::{ ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}, prelude::*, }, - types::instance_definitions::keccak_instance_def::KeccakInstanceDef, + types::layout::MEMORY_UNITS_PER_STEP, vm::{ runners::builtin_runner::SegmentArenaBuiltinRunner, trace::trace_entry::{relocate_trace_register, RelocatedTraceEntry}, @@ -22,10 +22,6 @@ use crate::{ types::{ errors::{math_errors::MathError, program_errors::ProgramError}, exec_scope::ExecutionScopes, - instance_definitions::{ - bitwise_instance_def::BitwiseInstanceDef, ec_op_instance_def::EcOpInstanceDef, - ecdsa_instance_def::EcdsaInstanceDef, - }, layout::CairoLayout, program::Program, relocatable::{relocate_address, relocate_value, MaybeRelocatable, Relocatable}, @@ -54,10 +50,14 @@ use num_integer::div_rem; use num_traits::{ToPrimitive, Zero}; use serde::{Deserialize, Serialize}; +use super::builtin_runner::ModBuiltinRunner; use super::{ - builtin_runner::{KeccakBuiltinRunner, PoseidonBuiltinRunner, OUTPUT_BUILTIN_NAME}, + builtin_runner::{ + KeccakBuiltinRunner, PoseidonBuiltinRunner, RC_N_PARTS_96, RC_N_PARTS_STANDARD, + }, cairo_pie::{self, CairoPie, CairoPieMetadata, CairoPieVersion}, }; +use crate::types::instance_definitions::mod_instance_def::ModInstanceDef; #[derive(Clone, Debug, Eq, PartialEq)] pub enum CairoArg { @@ -179,6 +179,7 @@ impl CairoRunner { "plain" => CairoLayout::plain_instance(), "small" => CairoLayout::small_instance(), "dex" => CairoLayout::dex_instance(), + "recursive" => CairoLayout::recursive_instance(), "starknet" => CairoLayout::starknet_instance(), "starknet_with_keccak" => CairoLayout::starknet_with_keccak_instance(), "recursive_large_output" => CairoLayout::recursive_large_output_instance(), @@ -228,15 +229,27 @@ impl CairoRunner { } } - pub fn initialize(&mut self, vm: &mut VirtualMachine) -> Result { - self.initialize_builtins(vm)?; + pub fn initialize( + &mut self, + vm: &mut VirtualMachine, + allow_missing_builtins: bool, + ) -> Result { + self.initialize_builtins(vm, allow_missing_builtins)?; self.initialize_segments(vm, None); let end = self.initialize_main_entrypoint(vm)?; self.initialize_vm(vm)?; Ok(end) } - pub fn initialize_builtins(&self, vm: &mut VirtualMachine) -> Result<(), RunnerError> { + /// Creates the builtin runners according to the builtins used by the program and the selected layout + /// When running in proof_mode, all builtins in the layout will be created, and only those in the program will be included + /// When not running in proof_mode, only program builtins will be created and included + /// Unless `allow_missing_builtins` is set to true, an error will be returned if a builtin is included in the program but not on the layout + pub fn initialize_builtins( + &self, + vm: &mut VirtualMachine, + allow_missing_builtins: bool, + ) -> Result<(), RunnerError> { let builtin_ordered_list = vec![ BuiltinName::output, BuiltinName::pedersen, @@ -246,6 +259,9 @@ impl CairoRunner { BuiltinName::ec_op, BuiltinName::keccak, BuiltinName::poseidon, + BuiltinName::range_check96, + BuiltinName::add_mod, + BuiltinName::mul_mod, ]; if !is_subsequence(&self.program.builtins, &builtin_ordered_list) { return Err(RunnerError::DisorderedBuiltins); @@ -271,9 +287,8 @@ impl CairoRunner { let included = program_builtins.remove(&BuiltinName::range_check); if included || self.is_proof_mode() { builtin_runners.push( - RangeCheckBuiltinRunner::new( + RangeCheckBuiltinRunner::::new( instance_def.ratio, - instance_def.n_parts, included, ) .into(), @@ -284,28 +299,30 @@ impl CairoRunner { if let Some(instance_def) = self.layout.builtins.ecdsa.as_ref() { let included = program_builtins.remove(&BuiltinName::ecdsa); if included || self.is_proof_mode() { - builtin_runners.push(SignatureBuiltinRunner::new(instance_def, included).into()); + builtin_runners + .push(SignatureBuiltinRunner::new(instance_def.ratio, included).into()); } } if let Some(instance_def) = self.layout.builtins.bitwise.as_ref() { let included = program_builtins.remove(&BuiltinName::bitwise); if included || self.is_proof_mode() { - builtin_runners.push(BitwiseBuiltinRunner::new(instance_def, included).into()); + builtin_runners + .push(BitwiseBuiltinRunner::new(instance_def.ratio, included).into()); } } if let Some(instance_def) = self.layout.builtins.ec_op.as_ref() { let included = program_builtins.remove(&BuiltinName::ec_op); if included || self.is_proof_mode() { - builtin_runners.push(EcOpBuiltinRunner::new(instance_def, included).into()); + builtin_runners.push(EcOpBuiltinRunner::new(instance_def.ratio, included).into()); } } if let Some(instance_def) = self.layout.builtins.keccak.as_ref() { let included = program_builtins.remove(&BuiltinName::keccak); if included || self.is_proof_mode() { - builtin_runners.push(KeccakBuiltinRunner::new(instance_def, included).into()); + builtin_runners.push(KeccakBuiltinRunner::new(instance_def.ratio, included).into()); } } @@ -316,10 +333,32 @@ impl CairoRunner { .push(PoseidonBuiltinRunner::new(instance_def.ratio, included).into()); } } - if !program_builtins.is_empty() { + + if let Some(instance_def) = self.layout.builtins.range_check96.as_ref() { + let included = program_builtins.remove(&BuiltinName::range_check96); + if included || self.is_proof_mode() { + builtin_runners.push( + RangeCheckBuiltinRunner::::new(instance_def.ratio, included) + .into(), + ); + } + } + if let Some(instance_def) = self.layout.builtins.add_mod.as_ref() { + let included = program_builtins.remove(&BuiltinName::add_mod); + if included || self.is_proof_mode() { + builtin_runners.push(ModBuiltinRunner::new_add_mod(instance_def, included).into()); + } + } + if let Some(instance_def) = self.layout.builtins.mul_mod.as_ref() { + let included = program_builtins.remove(&BuiltinName::mul_mod); + if included || self.is_proof_mode() { + builtin_runners.push(ModBuiltinRunner::new_mul_mod(instance_def, included).into()); + } + } + if !program_builtins.is_empty() && !allow_missing_builtins { return Err(RunnerError::NoBuiltinForInstance(Box::new(( program_builtins.iter().map(|n| n.name()).collect(), - self.layout._name.clone(), + self.layout.name.clone(), )))); } @@ -359,25 +398,24 @@ impl CairoRunner { BuiltinName::pedersen => vm .builtin_runners .push(HashBuiltinRunner::new(Some(32), true).into()), - BuiltinName::range_check => vm - .builtin_runners - .push(RangeCheckBuiltinRunner::new(Some(1), 8, true).into()), + BuiltinName::range_check => vm.builtin_runners.push( + RangeCheckBuiltinRunner::::new(Some(1), true).into(), + ), BuiltinName::output => vm .builtin_runners .push(OutputBuiltinRunner::new(true).into()), - BuiltinName::ecdsa => vm.builtin_runners.push( - SignatureBuiltinRunner::new(&EcdsaInstanceDef::new(Some(1)), true).into(), - ), - BuiltinName::bitwise => vm.builtin_runners.push( - BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(Some(1)), true).into(), - ), + BuiltinName::ecdsa => vm + .builtin_runners + .push(SignatureBuiltinRunner::new(Some(1), true).into()), + BuiltinName::bitwise => vm + .builtin_runners + .push(BitwiseBuiltinRunner::new(Some(1), true).into()), BuiltinName::ec_op => vm .builtin_runners - .push(EcOpBuiltinRunner::new(&EcOpInstanceDef::new(Some(1)), true).into()), - BuiltinName::keccak => vm.builtin_runners.push( - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(Some(1), vec![200; 8]), true) - .into(), - ), + .push(EcOpBuiltinRunner::new(Some(1), true).into()), + BuiltinName::keccak => vm + .builtin_runners + .push(KeccakBuiltinRunner::new(Some(1), true).into()), BuiltinName::poseidon => vm .builtin_runners .push(PoseidonBuiltinRunner::new(Some(1), true).into()), @@ -387,6 +425,17 @@ impl CairoRunner { .push(SegmentArenaBuiltinRunner::new(true).into()) } } + BuiltinName::range_check96 => vm + .builtin_runners + .push(RangeCheckBuiltinRunner::::new(Some(1), true).into()), + BuiltinName::add_mod => vm.builtin_runners.push( + ModBuiltinRunner::new_add_mod(&ModInstanceDef::new(Some(1), 1, 96), true) + .into(), + ), + BuiltinName::mul_mod => vm.builtin_runners.push( + ModBuiltinRunner::new_mul_mod(&ModInstanceDef::new(Some(1), 1, 96), true) + .into(), + ), } } @@ -423,31 +472,19 @@ impl CairoRunner { entrypoint: usize, stack: Vec, ) -> Result<(), RunnerError> { - if let Some(prog_base) = self.program_base { - let initial_pc = Relocatable { - segment_index: prog_base.segment_index, - offset: prog_base.offset + entrypoint, - }; - self.initial_pc = Some(initial_pc); - vm.segments - .load_data(prog_base, &self.program.shared_program_data.data) - .map_err(RunnerError::MemoryInitializationError)?; - - // Mark all addresses from the program segment as accessed - let base = self - .program_base - .unwrap_or_else(|| Relocatable::from((0, 0))); - for i in 0..self.program.shared_program_data.data.len() { - vm.segments.memory.mark_as_accessed((base + i)?); - } - } - if let Some(exec_base) = self.execution_base { - vm.segments - .load_data(exec_base, &stack) - .map_err(RunnerError::MemoryInitializationError)?; - } else { - return Err(RunnerError::NoProgBase); + let prog_base = self.program_base.ok_or(RunnerError::NoProgBase)?; + let exec_base = self.execution_base.ok_or(RunnerError::NoExecBase)?; + self.initial_pc = Some((prog_base + entrypoint)?); + vm.load_data(prog_base, &self.program.shared_program_data.data) + .map_err(RunnerError::MemoryInitializationError)?; + + // Mark all addresses from the program segment as accessed + for i in 0..self.program.shared_program_data.data.len() { + vm.segments.memory.mark_as_accessed((prog_base + i)?); } + vm.segments + .load_data(exec_base, &stack) + .map_err(RunnerError::MemoryInitializationError)?; Ok(()) } @@ -485,9 +522,19 @@ impl CairoRunner { vm: &mut VirtualMachine, ) -> Result { let mut stack = Vec::new(); - - for builtin_runner in vm.builtin_runners.iter() { - stack.append(&mut builtin_runner.initial_stack()); + { + let builtin_runners = vm + .builtin_runners + .iter() + .map(|b| (b.identifier(), b)) + .collect::>(); + for builtin_id in &self.program.builtins { + if let Some(builtin_runner) = builtin_runners.get(builtin_id) { + stack.append(&mut builtin_runner.initial_stack()); + } else { + stack.push(Felt252::ZERO.into()) + } + } } if self.is_proof_mode() { @@ -1079,8 +1126,8 @@ impl CairoRunner { let (_, size) = builtin_runner .get_used_cells_and_allocated_size(vm) .map_err(RunnerError::FinalizeSegements)?; - if builtin_runner.name() == OUTPUT_BUILTIN_NAME { - let public_memory = (0..size).map(|i| (i, 0)).collect(); + if let BuiltinRunner::Output(output_builtin) = builtin_runner { + let public_memory = output_builtin.get_public_memory(&vm.segments)?; vm.segments .finalize(Some(size), builtin_runner.base(), Some(&public_memory)) } else { @@ -1088,6 +1135,7 @@ impl CairoRunner { .finalize(Some(size), builtin_runner.base(), None) } } + vm.segments.finalize_zero_segment(); self.segments_finalized = true; Ok(()) } @@ -1156,13 +1204,13 @@ impl CairoRunner { // Out of the memory units available per step, a fraction is used for public memory, and // four are used for the instruction. - let total_memory_units = instance._memory_units_per_step * vm_current_step_u32; + let total_memory_units = MEMORY_UNITS_PER_STEP * vm_current_step_u32; let (public_memory_units, rem) = - div_rem(total_memory_units, instance._public_memory_fraction); + div_rem(total_memory_units, instance.public_memory_fraction); if rem != 0 { return Err(MathError::SafeDivFailU32( total_memory_units, - instance._public_memory_fraction, + instance.public_memory_fraction, ) .into()); } @@ -1227,14 +1275,33 @@ impl CairoRunner { Ok(()) } - pub fn read_return_values(&mut self, vm: &mut VirtualMachine) -> Result<(), RunnerError> { + pub fn read_return_values( + &mut self, + vm: &mut VirtualMachine, + allow_missing_builtins: bool, + ) -> Result<(), RunnerError> { if !self.run_ended { return Err(RunnerError::ReadReturnValuesNoEndRun); } let mut pointer = vm.get_ap(); - for builtin_runner in vm.builtin_runners.iter_mut().rev() { - let new_pointer = builtin_runner.final_stack(&vm.segments, pointer)?; - pointer = new_pointer; + for builtin_id in self.program.builtins.iter().rev() { + if let Some(builtin_runner) = vm + .builtin_runners + .iter_mut() + .find(|b| b.identifier() == *builtin_id) + { + let new_pointer = builtin_runner.final_stack(&vm.segments, pointer)?; + pointer = new_pointer; + } else { + if !allow_missing_builtins { + return Err(RunnerError::MissingBuiltin(builtin_id.name())); + } + pointer.offset = pointer.offset.saturating_sub(1); + + if !vm.get_integer(pointer)?.is_zero() { + return Err(RunnerError::MissingBuiltinStopPtrNotZero(builtin_id.name())); + } + } } if self.segments_finalized { return Err(RunnerError::FailedAddingReturnValues); @@ -1255,22 +1322,6 @@ impl CairoRunner { Ok(()) } - //NOTE: No longer needed in 0.11 - /// Add (or replace if already present) a custom hash builtin. Returns a Relocatable - /// with the new builtin base as the segment index. - pub fn add_additional_hash_builtin(&self, vm: &mut VirtualMachine) -> Relocatable { - // Create, initialize and insert the new custom hash runner. - let mut builtin: BuiltinRunner = HashBuiltinRunner::new(Some(32), true).into(); - builtin.initialize_segments(&mut vm.segments); - let segment_index = builtin.base() as isize; - vm.builtin_runners.push(builtin); - - Relocatable { - segment_index, - offset: 0, - } - } - // Iterates over the program builtins in reverse, calling BuiltinRunner::final_stack on each of them and returns the final pointer // This method is used by cairo-vm-py to replace starknet functionality pub fn get_builtins_final_stack( @@ -1405,7 +1456,7 @@ impl CairoRunner { &self, vm: &VirtualMachine, ) -> Result { - let layout_name = self.get_layout()._name.as_str(); + let layout_name = self.get_layout().name.as_str(); let dyn_layout = match layout_name { "dynamic" => Some(self.get_layout()), _ => None, @@ -1416,7 +1467,7 @@ impl CairoRunner { layout_name, dyn_layout, &vm.get_public_memory_addresses()?, - vm.get_memory_segment_addresses()?, + self.get_memory_segment_addresses(vm)?, self.relocated_trace .as_ref() .ok_or(PublicInputError::EmptyTrace)?, @@ -1428,13 +1479,45 @@ impl CairoRunner { pub fn get_air_private_input(&self, vm: &VirtualMachine) -> AirPrivateInput { let mut private_inputs = HashMap::new(); for builtin in vm.builtin_runners.iter() { - private_inputs.insert( - builtin.name(), - builtin.air_private_input(&vm.segments.memory), - ); + private_inputs.insert(builtin.name(), builtin.air_private_input(&vm.segments)); } AirPrivateInput(private_inputs) } + + pub fn get_memory_segment_addresses( + &self, + vm: &VirtualMachine, + ) -> Result, VirtualMachineError> { + let relocation_table = vm + .relocation_table + .as_ref() + .ok_or(MemoryError::UnrelocatedMemory)?; + + let relocate = |segment: (usize, usize)| -> Result<(usize, usize), VirtualMachineError> { + let (index, stop_ptr_offset) = segment; + let base = relocation_table + .get(index) + .ok_or(VirtualMachineError::RelocationNotFound(index))?; + Ok((*base, base + stop_ptr_offset)) + }; + + vm.builtin_runners + .iter() + .map(|builtin| -> Result<_, VirtualMachineError> { + let (base, stop_ptr) = builtin.get_memory_segment_addresses(); + let stop_ptr = if self.program.builtins.contains(&builtin.identifier()) { + stop_ptr.ok_or_else(|| RunnerError::NoStopPointer(Box::new(builtin.name())))? + } else { + stop_ptr.unwrap_or_default() + }; + + Ok(( + builtin.name().strip_suffix("_builtin").unwrap_or_default(), + relocate((base, stop_ptr))?, + )) + }) + .collect() + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -1552,7 +1635,6 @@ mod tests { hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor, relocatable, serde::deserialize_program::{Identifier, ReferenceManager}, - types::instance_definitions::bitwise_instance_def::BitwiseInstanceDef, utils::test_utils::*, vm::trace::trace_entry::TraceEntry, }; @@ -1564,7 +1646,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn check_memory_usage_ok_case() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::range_check, BuiltinName::output]; let cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1600,26 +1681,36 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_builtins_with_disordered_builtins() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::range_check, BuiltinName::output]; - let cairo_runner = cairo_runner!(program); + let cairo_runner = cairo_runner!(program, "plain"); + let mut vm = vm!(); + assert!(cairo_runner.initialize_builtins(&mut vm, false).is_err()); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn initialize_builtins_missing_builtins_no_allow_missing() { + let program = program![BuiltinName::output, BuiltinName::ecdsa]; + let cairo_runner = cairo_runner!(program, "plain"); let mut vm = vm!(); - assert!(cairo_runner.initialize_builtins(&mut vm).is_err()); + assert_matches!( + cairo_runner.initialize_builtins(&mut vm, false), + Err(RunnerError::NoBuiltinForInstance(_)) + ) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn create_cairo_runner_with_ordered_but_missing_builtins() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined + fn initialize_builtins_missing_builtins_allow_missing() { let program = program![BuiltinName::output, BuiltinName::ecdsa]; - //We only check that the creation doesnt panic - let _cairo_runner = cairo_runner!(program); + let cairo_runner = cairo_runner!(program); + let mut vm = vm!(); + assert!(cairo_runner.initialize_builtins(&mut vm, true).is_ok()) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_segments_with_base() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1628,7 +1719,7 @@ mod tests { offset: 9, }); add_segments!(vm, 6); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, program_base); assert_eq!( cairo_runner.program_base, @@ -1653,11 +1744,10 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_segments_no_base() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); assert_eq!( cairo_runner.program_base, @@ -1682,14 +1772,13 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_state_empty_data_and_stack() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); cairo_runner.program_base = Some(relocatable!(1, 0)); cairo_runner.execution_base = Some(relocatable!(2, 0)); let stack = Vec::new(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_state(&mut vm, 1, stack).unwrap(); assert_eq!( cairo_runner.initial_pc, @@ -1703,7 +1792,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_state_some_data_empty_stack() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program!( builtins = vec![BuiltinName::output], data = vec_data!((4), (6)), @@ -1726,7 +1814,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_state_empty_data_some_stack() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1743,7 +1830,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_state_no_program_base() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1764,7 +1850,6 @@ mod tests { #[test] #[should_panic] fn initialize_state_no_execution_base() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1782,7 +1867,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_function_entrypoint_empty_stack() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1804,7 +1888,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_function_entrypoint_some_stack() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1831,7 +1914,6 @@ mod tests { #[test] #[should_panic] fn initialize_function_entrypoint_no_execution_base() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1845,7 +1927,6 @@ mod tests { #[test] #[should_panic] fn initialize_main_entrypoint_no_main() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1855,7 +1936,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_main_entrypoint() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program!(main = Some(1),); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1880,7 +1960,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize(&mut vm).unwrap(); + cairo_runner.initialize(&mut vm, false).unwrap(); assert_eq!( vm.segments .memory @@ -1892,7 +1972,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_vm_no_builtins() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program!(main = Some(1),); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -1909,14 +1988,13 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_vm_with_range_check_valid() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program!(builtins = vec![BuiltinName::range_check], main = Some(1),); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); cairo_runner.initial_pc = Some(relocatable!(0, 1)); cairo_runner.initial_ap = Some(relocatable!(1, 2)); cairo_runner.initial_fp = Some(relocatable!(1, 2)); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); vm.segments = segments![((2, 0), 23), ((2, 1), 233)]; assert_eq!(vm.builtin_runners[0].name(), RANGE_CHECK_BUILTIN_NAME); @@ -1938,14 +2016,13 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn initialize_vm_with_range_check_invalid() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program!(builtins = vec![BuiltinName::range_check], main = Some(1),); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); cairo_runner.initial_pc = Some(relocatable!(0, 1)); cairo_runner.initial_ap = Some(relocatable!(1, 2)); cairo_runner.initial_fp = Some(relocatable!(1, 2)); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); vm.segments = segments![((2, 1), 23), ((2, 4), (-1))]; @@ -2069,7 +2146,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -2158,7 +2235,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -2323,7 +2400,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -2438,7 +2515,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -2577,7 +2654,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -2815,7 +2892,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -2954,7 +3031,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -3074,7 +3151,7 @@ mod tests { let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); assert_eq!(vm.builtin_runners[0].name(), OUTPUT_BUILTIN_NAME); assert_eq!(vm.builtin_runners[0].base(), 2); @@ -3129,7 +3206,7 @@ mod tests { ); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -3170,7 +3247,7 @@ mod tests { ); let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); @@ -3192,7 +3269,7 @@ mod tests { let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); assert_eq!(vm.builtin_runners[0].name(), OUTPUT_BUILTIN_NAME); assert_eq!(vm.builtin_runners[0].base(), 2); @@ -3246,11 +3323,12 @@ mod tests { let mut vm = vm!(); cairo_runner - .initialize_builtins(&mut vm) + .initialize_builtins(&mut vm, false) .expect("Couldn't initialize builtins."); // Swap the first and second builtins (first should be `output`). vm.builtin_runners.swap(0, 1); + cairo_runner.program.builtins.swap(0, 1); cairo_runner.initialize_segments(&mut vm, None); @@ -3284,7 +3362,7 @@ mod tests { ]; let cairo_runner = cairo_runner!(program); let mut vm = vm!(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); assert_eq!(vm.builtin_runners[0].name(), OUTPUT_BUILTIN_NAME); assert_eq!(vm.builtin_runners[1].name(), HASH_BUILTIN_NAME); assert_eq!(vm.builtin_runners[2].name(), RANGE_CHECK_BUILTIN_NAME); @@ -3342,7 +3420,7 @@ mod tests { let mut cairo_runner = cairo_runner!(&program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); @@ -3366,7 +3444,7 @@ mod tests { let mut cairo_runner = cairo_runner!(&program); let mut vm = vm!(true); assert_matches!( - cairo_runner.initialize(&mut vm), + cairo_runner.initialize(&mut vm, false), Err(RunnerError::MissingMain) ); } @@ -3421,7 +3499,7 @@ mod tests { let mut cairo_runner = cairo_runner!(&program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); @@ -3494,7 +3572,7 @@ mod tests { let mut cairo_runner = cairo_runner!(&program); let mut vm = vm!(true); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); @@ -3707,8 +3785,7 @@ mod tests { let mut vm = vm!(); vm.current_step = 8192; - vm.builtin_runners = - vec![BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into()]; + vm.builtin_runners = vec![BitwiseBuiltinRunner::new(Some(256), true).into()]; assert_matches!(cairo_runner.check_diluted_check_usage(&vm), Ok(())); } @@ -3766,7 +3843,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program, "all_cairo", true); let mut vm = vm!(true); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .expect("Call to `CairoRunner::run_until_pc()` failed."); @@ -4095,7 +4172,8 @@ mod tests { vm.segments.memory.data = vec![vec![Some(MemoryCell::new(mayberelocatable!( 0x80FF_8000_0530u64 )))]]; - vm.builtin_runners = vec![RangeCheckBuiltinRunner::new(Some(12), 5, true).into()]; + vm.builtin_runners = + vec![RangeCheckBuiltinRunner::::new(Some(12), true).into()]; assert_matches!( cairo_runner.get_perm_range_check_limits(&vm), @@ -4149,7 +4227,8 @@ mod tests { let cairo_runner = cairo_runner!(program); let mut vm = vm!(); - vm.builtin_runners = vec![RangeCheckBuiltinRunner::new(Some(8), 8, true).into()]; + vm.builtin_runners = + vec![RangeCheckBuiltinRunner::::new(Some(8), true).into()]; vm.segments.memory.data = vec![vec![Some(MemoryCell::new(mayberelocatable!( 0x80FF_8000_0530u64 )))]]; @@ -4181,7 +4260,6 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn get_initial_fp_can_be_obtained() { - //This test works with basic Program definition, will later be updated to use Program::new() when fully defined let program = program![BuiltinName::output]; let mut cairo_runner = cairo_runner!(program); let mut vm = vm!(); @@ -4217,7 +4295,8 @@ mod tests { let cairo_runner = cairo_runner!(program); let mut vm = vm!(); - vm.builtin_runners = vec![RangeCheckBuiltinRunner::new(Some(8), 8, true).into()]; + vm.builtin_runners = + vec![RangeCheckBuiltinRunner::::new(Some(8), true).into()]; vm.segments.memory.data = vec![vec![Some(MemoryCell::new(mayberelocatable!( 0x80FF_8000_0530u64 )))]]; @@ -4447,7 +4526,7 @@ mod tests { let mut vm = vm!(); let cairo_runner = cairo_runner!(program, "plain"); assert_eq!( - cairo_runner.initialize_builtins(&mut vm), + cairo_runner.initialize_builtins(&mut vm, false), Err(RunnerError::NoBuiltinForInstance(Box::new(( HashSet::from([BuiltinName::output.name()]), String::from("plain") @@ -4462,7 +4541,7 @@ mod tests { let mut vm = vm!(); let cairo_runner = cairo_runner!(program, "plain"); assert_eq!( - cairo_runner.initialize_builtins(&mut vm), + cairo_runner.initialize_builtins(&mut vm, false), Err(RunnerError::NoBuiltinForInstance(Box::new(( HashSet::from([BuiltinName::output.name(), HASH_BUILTIN_NAME]), String::from("plain") @@ -4477,7 +4556,7 @@ mod tests { let mut vm = vm!(); let cairo_runner = cairo_runner!(program, "small"); assert_eq!( - cairo_runner.initialize_builtins(&mut vm), + cairo_runner.initialize_builtins(&mut vm, false), Err(RunnerError::NoBuiltinForInstance(Box::new(( HashSet::from([BuiltinName::bitwise.name()]), String::from("small") @@ -4515,7 +4594,7 @@ mod tests { let mut runner = cairo_runner!(program); runner.runner_mode = RunnerMode::ProofModeCanonical; let mut vm = vm!(); - runner.initialize_builtins(&mut vm).unwrap(); + runner.initialize_builtins(&mut vm, false).unwrap(); runner.initialize_segments(&mut vm, None); assert_eq!(runner.execution_base, Some(Relocatable::from((1, 0)))); assert_eq!(runner.program_base, Some(Relocatable::from((0, 0)))); @@ -4652,7 +4731,7 @@ mod tests { let mut vm = vm!(); //Check values written by first call to segments.finalize() - assert_eq!(cairo_runner.read_return_values(&mut vm), Ok(())); + assert_eq!(cairo_runner.read_return_values(&mut vm, false), Ok(())); assert_eq!( cairo_runner .execution_public_memory @@ -4674,7 +4753,7 @@ mod tests { cairo_runner.run_ended = false; let mut vm = vm!(); assert_eq!( - cairo_runner.read_return_values(&mut vm), + cairo_runner.read_return_values(&mut vm, false), Err(RunnerError::ReadReturnValuesNoEndRun) ); } @@ -4693,7 +4772,7 @@ mod tests { cairo_runner.segments_finalized = true; let mut vm = vm!(); assert_eq!( - cairo_runner.read_return_values(&mut vm), + cairo_runner.read_return_values(&mut vm, false), Err(RunnerError::FailedAddingReturnValues) ); } @@ -4721,7 +4800,7 @@ mod tests { vm.set_ap(1); vm.segments.segment_used_sizes = Some(vec![0, 1, 0]); //Check values written by first call to segments.finalize() - assert_eq!(cairo_runner.read_return_values(&mut vm), Ok(())); + assert_eq!(cairo_runner.read_return_values(&mut vm, false), Ok(())); let output_builtin = match &vm.builtin_runners[0] { BuiltinRunner::Output(runner) => runner, _ => unreachable!(), @@ -4752,7 +4831,7 @@ mod tests { vm.set_ap(1); vm.segments.segment_used_sizes = Some(vec![1, 1, 0]); //Check values written by first call to segments.finalize() - assert_eq!(cairo_runner.read_return_values(&mut vm), Ok(())); + assert_eq!(cairo_runner.read_return_values(&mut vm, false), Ok(())); let output_builtin = match &vm.builtin_runners[0] { BuiltinRunner::Output(runner) => runner, _ => unreachable!(), @@ -4774,7 +4853,7 @@ mod tests { cairo_runner.segments_finalized = false; let mut vm = vm!(); let output_builtin = OutputBuiltinRunner::new(true); - let bitwise_builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true); vm.builtin_runners.push(output_builtin.into()); vm.builtin_runners.push(bitwise_builtin.into()); cairo_runner.initialize_segments(&mut vm, None); @@ -4790,13 +4869,13 @@ mod tests { // We use 5 as bitwise builtin's segment size as a bitwise instance is 5 cells vm.segments.segment_used_sizes = Some(vec![0, 2, 0, 5]); //Check values written by first call to segments.finalize() - assert_eq!(cairo_runner.read_return_values(&mut vm), Ok(())); + assert_eq!(cairo_runner.read_return_values(&mut vm, false), Ok(())); let output_builtin = match &vm.builtin_runners[0] { BuiltinRunner::Output(runner) => runner, _ => unreachable!(), }; assert_eq!(output_builtin.stop_ptr, Some(0)); - assert_eq!(cairo_runner.read_return_values(&mut vm), Ok(())); + assert_eq!(cairo_runner.read_return_values(&mut vm, false), Ok(())); let bitwise_builtin = match &vm.builtin_runners[1] { BuiltinRunner::Bitwise(runner) => runner, _ => unreachable!(), @@ -4804,32 +4883,6 @@ mod tests { assert_eq!(bitwise_builtin.stop_ptr, Some(5)); } - /// Test that add_additional_hash_builtin() creates an additional builtin. - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn add_additional_hash_builtin() { - let program = program!(); - let cairo_runner = cairo_runner!(program); - let mut vm = vm!(); - - let num_builtins = vm.builtin_runners.len(); - cairo_runner.add_additional_hash_builtin(&mut vm); - assert_eq!(vm.builtin_runners.len(), num_builtins + 1); - - let builtin = vm - .builtin_runners - .last() - .expect("missing last builtin runner"); - match builtin { - BuiltinRunner::Hash(builtin) => { - assert_eq!(builtin.base(), 0); - assert_eq!(builtin.ratio(), Some(32)); - assert!(builtin.included); - } - _ => unreachable!(), - } - } - #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_from_entrypoint_custom_program_test() { @@ -4851,7 +4904,7 @@ mod tests { .pc .unwrap(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); assert_matches!( cairo_runner.run_from_entrypoint( @@ -4872,7 +4925,9 @@ mod tests { let mut new_vm = vm!(true); //this true expression dictates that the trace is enabled let mut hint_processor = BuiltinHintProcessor::new_empty(); - new_cairo_runner.initialize_builtins(&mut new_vm).unwrap(); + new_cairo_runner + .initialize_builtins(&mut new_vm, false) + .unwrap(); new_cairo_runner.initialize_segments(&mut new_vm, None); let fib_entrypoint = program @@ -5039,7 +5094,7 @@ mod tests { .pc .unwrap(); - cairo_runner.initialize_builtins(&mut vm).unwrap(); + cairo_runner.initialize_builtins(&mut vm, false).unwrap(); cairo_runner.initialize_segments(&mut vm, None); let result = cairo_runner.run_from_entrypoint( @@ -5072,7 +5127,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); runner .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) .unwrap(); @@ -5095,7 +5150,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); runner .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) .unwrap(); @@ -5118,7 +5173,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); runner .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) .unwrap(); @@ -5142,7 +5197,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); runner .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) .unwrap(); @@ -5230,7 +5285,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); // program takes 80 steps assert_matches!( @@ -5249,7 +5304,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(81)); // program takes 81 steps assert_matches!( @@ -5270,7 +5325,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(80)); // program takes 80 steps assert_matches!( @@ -5291,7 +5346,7 @@ mod tests { .unwrap(); let mut runner = cairo_runner!(program); let mut vm = vm!(); - let end = runner.initialize(&mut vm).unwrap(); + let end = runner.initialize(&mut vm, false).unwrap(); let mut hint_processor = BuiltinHintProcessor::new(HashMap::new(), RunResources::new(9)); // program takes 9 steps assert_matches!( diff --git a/vm/src/vm/security.rs b/vm/src/vm/security.rs index a18e43421a..45440cfd76 100644 --- a/vm/src/vm/security.rs +++ b/vm/src/vm/security.rs @@ -87,7 +87,6 @@ mod test { use super::*; use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; use crate::serde::deserialize_program::BuiltinName; - use crate::stdlib::collections::HashMap; use crate::types::relocatable::Relocatable; @@ -120,7 +119,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.segments.compute_effective_sizes(); assert_matches!(verify_secure_runner(&runner, true, None, &mut vm), Ok(())); } @@ -133,7 +132,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.segments = segments![((0, 0), 100)]; vm.segments.segment_used_sizes = Some(vec![1]); @@ -152,7 +151,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.segments = segments![((0, 0), 100)]; vm.segments.segment_used_sizes = Some(vec![1]); @@ -170,7 +169,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.builtin_runners[0].set_stop_ptr(0); vm.segments.memory = memory![((2, 0), 1)]; vm.segments.segment_used_sizes = Some(vec![0, 0, 0, 0]); @@ -188,7 +187,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); let mut hint_processor = BuiltinHintProcessor::new_empty(); runner .end_run(false, false, &mut vm, &mut hint_processor) @@ -217,7 +216,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.segments.memory = memory![ ((0, 0), (1, 0)), ((0, 1), (2, 1)), @@ -245,7 +244,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.segments.memory = memory![ ((0, 1), (1, 0)), ((0, 2), (2, 1)), @@ -273,7 +272,7 @@ mod test { let mut runner = cairo_runner!(program); let mut vm = vm!(); - runner.initialize(&mut vm).unwrap(); + runner.initialize(&mut vm, false).unwrap(); vm.segments.memory = memory![ ((0, 0), (1, 0)), ((0, 1), (2, 1)), diff --git a/vm/src/vm/trace/mod.rs b/vm/src/vm/trace/mod.rs index 838bfe9d39..5a9f683570 100644 --- a/vm/src/vm/trace/mod.rs +++ b/vm/src/vm/trace/mod.rs @@ -10,7 +10,7 @@ pub mod trace_entry { ///A trace entry for every instruction that was executed. ///Holds the register values before the instruction was executed. ///Register values for ap & fp are represented as their offsets, as their indexes will always be 1 - #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] + #[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)] pub struct TraceEntry { pub pc: Relocatable, pub ap: usize, diff --git a/vm/src/vm/vm_core.rs b/vm/src/vm/vm_core.rs index 38be9b1281..42a02b80fb 100644 --- a/vm/src/vm/vm_core.rs +++ b/vm/src/vm/vm_core.rs @@ -19,7 +19,9 @@ use crate::{ exec_scope_errors::ExecScopeError, memory_errors::MemoryError, vm_errors::VirtualMachineError, }, - runners::builtin_runner::{BuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner}, + runners::builtin_runner::{ + BuiltinRunner, OutputBuiltinRunner, RangeCheckBuiltinRunner, SignatureBuiltinRunner, + }, trace::trace_entry::TraceEntry, vm_memory::memory_segments::MemorySegmentManager, }, @@ -32,7 +34,10 @@ use core::num::NonZeroUsize; use num_traits::{ToPrimitive, Zero}; use super::errors::runner_errors::RunnerError; -use super::runners::builtin_runner::OUTPUT_BUILTIN_NAME; +use super::runners::builtin_runner::{ + ModBuiltinRunner, ADD_MOD_BUILTIN_NAME, MUL_MOD_BUILTIN_NAME, OUTPUT_BUILTIN_NAME, + RC_N_PARTS_STANDARD, +}; const MAX_TRACEBACK_ENTRIES: u32 = 20; @@ -922,7 +927,9 @@ impl VirtualMachine { self.segments.memory.get_integer_range(addr, size) } - pub fn get_range_check_builtin(&self) -> Result<&RangeCheckBuiltinRunner, VirtualMachineError> { + pub fn get_range_check_builtin( + &self, + ) -> Result<&RangeCheckBuiltinRunner, VirtualMachineError> { for builtin in &self.builtin_runners { if let BuiltinRunner::RangeCheck(range_check_builtin) = builtin { return Ok(range_check_builtin); @@ -942,8 +949,22 @@ impl VirtualMachine { Err(VirtualMachineError::NoSignatureBuiltin) } - pub fn disable_trace(&mut self) { - self.trace = None + + pub fn get_output_builtin_mut( + &mut self, + ) -> Result<&mut OutputBuiltinRunner, VirtualMachineError> { + for builtin in self.get_builtin_runners_as_mut() { + if let BuiltinRunner::Output(output_builtin) = builtin { + return Ok(output_builtin); + }; + } + + Err(VirtualMachineError::NoOutputBuiltin) + } + + #[cfg(feature = "tracer")] + pub fn relocate_segments(&self) -> Result, MemoryError> { + self.segments.relocate_segments() } #[doc(hidden)] @@ -1013,7 +1034,6 @@ impl VirtualMachine { let segment_used_sizes = self.segments.compute_effective_sizes(); let segment_index = builtin.base(); - #[allow(deprecated)] for i in 0..segment_used_sizes[segment_index] { let formatted_value = match self .segments @@ -1044,46 +1064,16 @@ impl VirtualMachine { } } - pub fn get_memory_segment_addresses( - &self, - ) -> Result, VirtualMachineError> { - let relocation_table = self - .relocation_table - .as_ref() - .ok_or(MemoryError::UnrelocatedMemory)?; - - let relocate = |segment: (usize, usize)| -> Result<(usize, usize), VirtualMachineError> { - let (index, stop_ptr_offset) = segment; - let base = relocation_table - .get(index) - .ok_or(VirtualMachineError::RelocationNotFound(index))?; - Ok((*base, base + stop_ptr_offset)) - }; - - self.builtin_runners - .iter() - .map(|builtin| -> Result<_, VirtualMachineError> { - let addresses = - if let (base, Some(stop_ptr)) = builtin.get_memory_segment_addresses() { - (base, stop_ptr) - } else { - return Err(RunnerError::NoStopPointer(Box::new(builtin.name())).into()); - }; - - Ok(( - builtin.name().strip_suffix("_builtin").unwrap_or_default(), - relocate(addresses)?, - )) - }) - .collect() - } - #[doc(hidden)] pub fn builtins_final_stack_from_stack_pointer_dict( &mut self, builtin_name_to_stack_pointer: &HashMap<&'static str, Relocatable>, + skip_output: bool, ) -> Result<(), RunnerError> { for builtin in self.builtin_runners.iter_mut() { + if matches!(builtin, BuiltinRunner::Output(_)) && skip_output { + continue; + } builtin.final_stack( &self.segments, builtin_name_to_stack_pointer @@ -1094,6 +1084,63 @@ impl VirtualMachine { } Ok(()) } + + #[doc(hidden)] + pub fn set_output_stop_ptr_offset(&mut self, offset: usize) { + if let Some(BuiltinRunner::Output(builtin)) = self.builtin_runners.first_mut() { + builtin.set_stop_ptr_offset(offset); + if let Some(segment_used_sizes) = &mut self.segments.segment_used_sizes { + segment_used_sizes[builtin.base()] = offset; + } + } + } + + /// Fetches add_mod & mul_mod builtins according to the optional arguments and executes `fill_memory` + /// Returns an error if either of this optional parameters is true but the corresponding builtin is not present + /// Verifies that both builtin's (if present) batch sizes match the batch_size arg if set + // This method is needed as running `fill_memory` direclty from outside the vm struct would require cloning the builtin runners to avoid double borrowing + pub fn mod_builtin_fill_memory( + &mut self, + add_mod_ptr_n: Option<(Relocatable, usize)>, + mul_mod_ptr_n: Option<(Relocatable, usize)>, + batch_size: Option, + ) -> Result<(), VirtualMachineError> { + let fetch_builtin_params = |mod_params: Option<(Relocatable, usize)>, + mod_name: &'static str| + -> Result< + Option<(Relocatable, &ModBuiltinRunner, usize)>, + VirtualMachineError, + > { + if let Some((ptr, n)) = mod_params { + let mod_builtin = self + .builtin_runners + .iter() + .find_map(|b| match b { + BuiltinRunner::Mod(b) if b.name() == mod_name => Some(b), + _ => None, + }) + .ok_or_else(|| VirtualMachineError::NoModBuiltin(mod_name))?; + if let Some(batch_size) = batch_size { + if mod_builtin.batch_size() != batch_size { + return Err(VirtualMachineError::ModBuiltinBatchSize(Box::new(( + mod_builtin.name(), + batch_size, + )))); + } + } + Ok(Some((ptr, mod_builtin, n))) + } else { + Ok(None) + } + }; + + ModBuiltinRunner::fill_memory( + &mut self.segments.memory, + fetch_builtin_params(add_mod_ptr_n, ADD_MOD_BUILTIN_NAME)?, + fetch_builtin_params(mul_mod_ptr_n, MUL_MOD_BUILTIN_NAME)?, + ) + .map_err(VirtualMachineError::RunnerError) + } } pub struct VirtualMachineBuilder { @@ -1202,7 +1249,6 @@ mod tests { use crate::vm::runners::builtin_runner::{ BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, }; - use crate::vm::vm_memory::memory::Memory; use crate::{ any_box, hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{ @@ -1210,9 +1256,6 @@ mod tests { }, relocatable, types::{ - instance_definitions::{ - bitwise_instance_def::BitwiseInstanceDef, ec_op_instance_def::EcOpInstanceDef, - }, instruction::{Op1Addr, Register}, relocatable::Relocatable, }, @@ -3334,7 +3377,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_bitwise_builtin_valid_and() { let mut vm = vm!(); - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let builtin = BitwiseBuiltinRunner::new(Some(256), true); vm.builtin_runners.push(builtin.into()); vm.segments = segments![((0, 5), 10), ((0, 6), 12), ((0, 7), 0)]; assert_matches!( @@ -3372,7 +3415,7 @@ mod tests { opcode: Opcode::AssertEq, }; - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let mut builtin = BitwiseBuiltinRunner::new(Some(256), true); builtin.base = 2; let mut vm = vm!(); @@ -3413,7 +3456,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn deduce_memory_cell_ec_op_builtin_valid() { let mut vm = vm!(); - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let builtin = EcOpBuiltinRunner::new(Some(256), true); vm.builtin_runners.push(builtin.into()); vm.segments = segments![ @@ -3482,7 +3525,7 @@ mod tests { end */ fn verify_auto_deductions_for_ec_op_builtin_valid() { - let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let mut builtin = EcOpBuiltinRunner::new(Some(256), true); builtin.base = 3; let mut vm = vm!(); vm.builtin_runners.push(builtin.into()); @@ -3530,7 +3573,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn verify_auto_deductions_for_ec_op_builtin_valid_points_invalid_result() { - let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); + let mut builtin = EcOpBuiltinRunner::new(Some(256), true); builtin.base = 3; let mut vm = vm!(); vm.builtin_runners.push(builtin.into()); @@ -3601,7 +3644,7 @@ mod tests { end */ fn verify_auto_deductions_bitwise() { - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let mut builtin = BitwiseBuiltinRunner::new(Some(256), true); builtin.base = 2; let mut vm = vm!(); vm.builtin_runners.push(builtin.into()); @@ -3624,7 +3667,7 @@ mod tests { end */ fn verify_auto_deductions_for_addr_bitwise() { - let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let mut builtin = BitwiseBuiltinRunner::new(Some(256), true); builtin.base = 2; let builtin: BuiltinRunner = builtin.into(); let mut vm = vm!(); @@ -3814,7 +3857,7 @@ mod tests { fn test_get_builtin_runners() { let mut vm = vm!(); let hash_builtin = HashBuiltinRunner::new(Some(8), true); - let bitwise_builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true); + let bitwise_builtin = BitwiseBuiltinRunner::new(Some(256), true); vm.builtin_runners.push(hash_builtin.into()); vm.builtin_runners.push(bitwise_builtin.into()); @@ -3826,11 +3869,26 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn disable_trace() { - let mut vm = VirtualMachine::new(true); - assert!(vm.trace.is_some()); - vm.disable_trace(); - assert!(vm.trace.is_none()); + fn test_get_output_builtin_mut() { + let mut vm = vm!(); + + assert_matches!( + vm.get_output_builtin_mut(), + Err(VirtualMachineError::NoOutputBuiltin) + ); + + let output_builtin = OutputBuiltinRunner::new(true); + vm.builtin_runners.push(output_builtin.clone().into()); + + let vm_output_builtin = vm + .get_output_builtin_mut() + .expect("Output builtin should be returned"); + + assert_eq!(vm_output_builtin.base(), output_builtin.base()); + assert_eq!(vm_output_builtin.pages, output_builtin.pages); + assert_eq!(vm_output_builtin.attributes, output_builtin.attributes); + assert_eq!(vm_output_builtin.stop_ptr, output_builtin.stop_ptr); + assert_eq!(vm_output_builtin.included, output_builtin.included); } #[test] @@ -4255,7 +4313,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -4280,7 +4338,7 @@ mod tests { let mut cairo_runner = cairo_runner!(program, "all_cairo", false); let mut vm = vm!(); - let end = cairo_runner.initialize(&mut vm).unwrap(); + let end = cairo_runner.initialize(&mut vm, false).unwrap(); assert!(cairo_runner .run_until_pc(end, &mut vm, &mut hint_processor) .is_err()); @@ -4302,11 +4360,10 @@ mod tests { ap: 18, fp: 0, }) - .segments(MemorySegmentManager { - segment_sizes: HashMap::new(), - segment_used_sizes: Some(vec![1]), - public_memory_offsets: HashMap::new(), - memory: Memory::new(), + .segments({ + let mut segments = MemorySegmentManager::new(); + segments.segment_used_sizes = Some(vec![1]); + segments }) .skip_instruction_execution(true) .trace(Some(vec![TraceEntry { @@ -4367,7 +4424,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); let mut cairo_runner = cairo_runner!(program); let end = cairo_runner - .initialize(&mut virtual_machine_from_builder) + .initialize(&mut virtual_machine_from_builder, false) .unwrap(); assert!(cairo_runner diff --git a/vm/src/vm/vm_memory/memory.rs b/vm/src/vm/vm_memory/memory.rs index 6a3db35086..2ea342573b 100644 --- a/vm/src/vm/vm_memory/memory.rs +++ b/vm/src/vm/vm_memory/memory.rs @@ -1,5 +1,6 @@ use crate::stdlib::{borrow::Cow, collections::HashMap, fmt, prelude::*}; +use crate::types::errors::math_errors::MathError; use crate::vm::runners::cairo_pie::CairoPieMemory; use crate::Felt252; use crate::{ @@ -284,6 +285,14 @@ impl Memory { } } + /// Gets the value from memory address as a usize. + /// Returns an Error if the value at the memory address is missing not a Felt252, or can't be converted to usize. + pub fn get_usize(&self, key: Relocatable) -> Result { + let felt = self.get_integer(key)?.into_owned(); + felt.to_usize() + .ok_or_else(|| MemoryError::Math(MathError::Felt252ToUsizeConversion(Box::new(felt)))) + } + /// Gets the value from memory address as a Relocatable value. /// Returns an Error if the value at the memory address is missing or not a Relocatable. pub fn get_relocatable(&self, key: Relocatable) -> Result { @@ -516,6 +525,21 @@ impl Memory { .count(), ) } + + // Inserts a value into memory & inmediately marks it as accessed if insertion was succesful + // Used by ModBuiltinRunner, as it accesses memory outside of it's segment when operating + pub(crate) fn insert_as_accessed( + &mut self, + key: Relocatable, + val: V, + ) -> Result<(), MemoryError> + where + MaybeRelocatable: From, + { + self.insert(key, val)?; + self.mark_as_accessed(key); + Ok(()) + } } impl From<&Memory> for CairoPieMemory { @@ -551,7 +575,7 @@ impl fmt::Display for Memory { } } } - writeln!(f, "}}") + Ok(()) } } @@ -605,10 +629,11 @@ mod memory_tests { use super::*; use crate::{ felt_hex, relocatable, - types::instance_definitions::ecdsa_instance_def::EcdsaInstanceDef, utils::test_utils::*, vm::{ - runners::builtin_runner::{RangeCheckBuiltinRunner, SignatureBuiltinRunner}, + runners::builtin_runner::{ + RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_STANDARD, + }, vm_memory::memory_segments::MemorySegmentManager, }, }; @@ -779,7 +804,7 @@ mod memory_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn validate_existing_memory_for_range_check_within_bounds() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let mut builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let mut segments = MemorySegmentManager::new(); builtin.initialize_segments(&mut segments); builtin.add_validation_rule(&mut segments.memory); @@ -804,7 +829,7 @@ mod memory_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn validate_existing_memory_for_range_check_outside_bounds() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let mut builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let mut segments = MemorySegmentManager::new(); segments.add(); builtin.initialize_segments(&mut segments); @@ -829,7 +854,7 @@ mod memory_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn validate_existing_memory_for_invalid_signature() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(Some(512), true); let mut segments = MemorySegmentManager::new(); builtin.initialize_segments(&mut segments); segments.memory = memory![ @@ -859,7 +884,7 @@ mod memory_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn validate_existing_memory_for_valid_signature() { - let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(Some(512), true); let signature_r = felt_hex!("0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20"); @@ -895,7 +920,7 @@ mod memory_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn validate_existing_memory_for_range_check_relocatable_value() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let mut builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let mut segments = MemorySegmentManager::new(); builtin.initialize_segments(&mut segments); segments.memory = memory![((0, 0), (0, 4))]; @@ -912,7 +937,7 @@ mod memory_tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn validate_existing_memory_for_range_check_out_of_bounds_diff_segment() { - let mut builtin = RangeCheckBuiltinRunner::new(Some(8), 8, true); + let mut builtin = RangeCheckBuiltinRunner::::new(Some(8), true); let mut segments = MemorySegmentManager::new(); segments.memory = Memory::new(); segments.add(); @@ -1424,7 +1449,7 @@ mod memory_tests { assert_eq!( format!("{}", memory), - "(-1,0) : -1:0\n(-1,1) : 8\n(-1,2) : 9\n(0,0) : 1\n(0,1) : -1:0\n(0,2) : 3\n(1,0) : -1:1\n(1,1) : 5\n(1,2) : -1:2\n}\n"); + "(-1,0) : -1:0\n(-1,1) : 8\n(-1,2) : 9\n(0,0) : 1\n(0,1) : -1:0\n(0,2) : 3\n(1,0) : -1:1\n(1,1) : 5\n(1,2) : -1:2\n"); } #[test] diff --git a/vm/src/vm/vm_memory/memory_segments.rs b/vm/src/vm/vm_memory/memory_segments.rs index 58e65589c1..f9886da1a5 100644 --- a/vm/src/vm/vm_memory/memory_segments.rs +++ b/vm/src/vm/vm_memory/memory_segments.rs @@ -1,3 +1,9 @@ +use core::cmp::max; +use core::fmt; + +use crate::Felt252; +use num_traits::Zero; + use crate::stdlib::prelude::*; use crate::stdlib::{any::Any, collections::HashMap}; use crate::vm::runners::cairo_runner::CairoArg; @@ -10,6 +16,8 @@ use crate::{ }, }; +use super::memory::MemoryCell; + pub struct MemorySegmentManager { pub segment_sizes: HashMap, pub segment_used_sizes: Option>, @@ -17,6 +25,11 @@ pub struct MemorySegmentManager { // A map from segment index to a list of pairs (offset, page_id) that constitute the // public memory. Note that the offset is absolute (not based on the page_id). pub public_memory_offsets: HashMap>, + // Segment index of the zero segment index, a memory segment filled with zeroes, used exclusively by builtin runners + // This segment will never have index 0 so we use 0 to represent uninitialized value + zero_segment_index: usize, + // Segment size of the zero segment index + zero_segment_size: usize, } impl MemorySegmentManager { @@ -69,6 +82,8 @@ impl MemorySegmentManager { segment_used_sizes: None, public_memory_offsets: HashMap::new(), memory: Memory::new(), + zero_segment_index: 0, + zero_segment_size: 0, } } @@ -204,11 +219,16 @@ impl MemorySegmentManager { if i > builtin_segments_start && i <= builtin_segments_end { continue; } - let accessed_amount = match self.memory.get_amount_of_accessed_addresses_for_segment(i) - { - Some(accessed_amount) if accessed_amount > 0 => accessed_amount, - _ => continue, - }; + let accessed_amount = + // Instead of marking the values in the zero segment until zero_segment_size as accessed we use zero_segment_size as accessed_amount + if !self.zero_segment_index.is_zero() && i == self.zero_segment_index { + self.zero_segment_size + } else { + match self.memory.get_amount_of_accessed_addresses_for_segment(i) { + Some(accessed_amount) if accessed_amount > 0 => accessed_amount, + _ => continue, + } + }; let segment_size = self .get_segment_size(i) .ok_or(MemoryError::MissingSegmentUsedSizes)?; @@ -261,6 +281,33 @@ impl MemorySegmentManager { self.public_memory_offsets .insert(segment_index, public_memory.cloned().unwrap_or_default()); } + + // Creates the zero segment if it wasn't previously created + // Fills the segment with the value 0 until size is reached + // Returns the index of the zero segment + pub(crate) fn add_zero_segment(&mut self, size: usize) -> usize { + if self.zero_segment_index.is_zero() { + self.zero_segment_index = self.add().segment_index as usize; + } + // Fil zero segment with zero values until size is reached + for _ in 0..self.zero_segment_size.saturating_sub(size) { + // As zero_segment_index is only accessible to the segment manager + // we can asume that it is always valid and index direcly into it + self.memory.data[self.zero_segment_index] + .push(Some(MemoryCell::new(Felt252::ZERO.into()))) + } + self.zero_segment_size = max(self.zero_segment_size, size); + self.zero_segment_index + } + + // Finalizes the zero segment and clears it's tracking data from the manager + pub(crate) fn finalize_zero_segment(&mut self) { + if !self.zero_segment_index.is_zero() { + self.finalize(Some(self.zero_segment_size), self.zero_segment_index, None); + self.zero_segment_index = 0; + self.zero_segment_size = 0; + } + } } impl Default for MemorySegmentManager { @@ -269,6 +316,28 @@ impl Default for MemorySegmentManager { } } +impl fmt::Display for MemorySegmentManager { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Memory:\n{}", self.memory)?; + if let Some(used_sizes) = &self.segment_used_sizes { + writeln!(f, "Segment Info:")?; + for (index, used_size) in used_sizes.iter().enumerate() { + writeln!( + f, + "Segment Number: {}, Used Size: {}, Size {}", + index, + used_size, + self.segment_sizes + .get(&index) + .map(|n| n.to_string()) + .unwrap_or(String::from("None")) + )?; + } + } + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*;