diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ec6c7a0e..a7993bcb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -157,6 +157,7 @@ jobs: run: make test-ci - name: test-cairo run: make test-cairo + test_macos: name: Test (macOS, Apple silicon) runs-on: macos-14 @@ -179,7 +180,7 @@ jobs: - name: Install scarb uses: software-mansion/setup-scarb@v1 with: - scarb-version: "2.6.4" + scarb-version: "2.7.1" - name: Install deps run: make deps - name: Build cairo-native-runtime library. @@ -192,6 +193,18 @@ jobs: coverage: name: coverage runs-on: ubuntu-latest + strategy: + matrix: + partition: [1, 2, 3, 4] + include: + - partition: 1 + output: lcov-1.info + - partition: 2 + output: lcov-2.info + - partition: 3 + output: lcov-3.info + - partition: 4 + output: lcov-4.info env: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse MLIR_SYS_180_PREFIX: /usr/lib/llvm-18/ @@ -231,37 +244,80 @@ jobs: keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key - name: Install LLVM run: sudo apt-get install llvm-18 llvm-18-dev llvm-18-runtime clang-18 clang-tools-18 lld-18 libpolly-18-dev libmlir-18-dev mlir-18-tools - - name: Install cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov + - name: Install testing tools + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest,cargo-llvm-cov - name: Install scarb uses: software-mansion/setup-scarb@v1 with: - scarb-version: "2.6.4" + scarb-version: "2.7.1" - name: Install deps - run: make deps + run: make deps + - name: Build runtime and alexandria + run: make runtime && make check-llvm && make needs-cairo2 && make build-alexandria - name: Build cairo-native-runtime library. - run: cargo build --profile=ci --package=cairo-native-runtime - - name: test and generate coverage - run: make coverage - - name: save coverage data + run: export PATH=$HOME/.rustup/toolchains/stable-aarch64-apple-darwin/bin:$PATH && cargo build --profile=ci --package=cairo-native-runtime + + - name: Run tests and generate coverage partition ${{ matrix.partition }} + run: cargo llvm-cov nextest --verbose --all-features --workspace --lcov --output-path ${{ matrix.output }} --partition count:${{ matrix.partition }}/4 + + - name: test and generate coverage corelib + if: ${{ matrix.partition == '1' }} + run: cargo llvm-cov nextest --verbose --all-features --lcov --output-path lcov-test.info run --bin cairo-native-test -- corelib + + - name: save coverage data with corelib + if: ${{ matrix.partition == '1' }} uses: actions/upload-artifact@v4 with: - name: coverage_data + name: coverage-data-1 path: | - ./lcov.info + ./${{ matrix.output }} ./lcov-test.info + - name: save coverage data + if: ${{ matrix.partition != '1' }} + uses: actions/upload-artifact@v4 + with: + name: coverage-data-${{ matrix.partition }} + path: ./${{ matrix.output }} + + upload-coverage: name: Upload Coverage runs-on: ubuntu-latest needs: [coverage] steps: + - name: Setup rust env + uses: dtolnay/rust-toolchain@1.80.0 + - name: Retreive cached dependencies + uses: Swatinem/rust-cache@v2 + - name: Install testing tools + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest,cargo-llvm-cov - name: Checkout uses: actions/checkout@v4 - - name: Download artifacts + - name: Download artifacts partition 1 + uses: actions/download-artifact@v4 + with: + name: coverage-data-1 + - name: Download artifacts partition 2 + uses: actions/download-artifact@v4 + with: + name: coverage-data-2 + - name: Download artifacts partition 3 + uses: actions/download-artifact@v4 + with: + name: coverage-data-3 + - name: Download artifacts partition 4 uses: actions/download-artifact@v4 with: - name: coverage_data + name: coverage-data-4 + - name: Install lcov + run: sudo apt-get update && sudo apt-get install -y lcov + - name: Merge the reports + run: lcov -a lcov-1.info -a lcov-2.info -a lcov-3.info -a lcov-4.info -o lcov.info - name: Upload coverage uses: codecov/codecov-action@v4 with: diff --git a/Cargo.lock b/Cargo.lock index 9951087b3..8f3d1d702 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aes" @@ -54,9 +54,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -69,33 +69,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -237,9 +237,9 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii-canvas" @@ -302,7 +302,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.68", + "syn 2.0.75", "which", ] @@ -354,6 +354,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -393,24 +403,11 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cairo-felt" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae932292b9ba497a4e892b56aa4e0c6f329a455180fdbdc132700dfe68d9b153" -dependencies = [ - "lazy_static", - "num-bigint", - "num-integer", - "num-traits 0.2.19", - "serde", -] - [[package]] name = "cairo-lang-casm" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6296d5748288d9fb97175d31aff9f68ea3f602456923895e512b078e9a2210a0" +checksum = "e4425280959f189d8a5ebf1f5363c10663bc9f843a4819253e6be87d183b583e" dependencies = [ "cairo-lang-utils", "indoc", @@ -422,9 +419,9 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7be5083c3328dad2248a94f0a24b3520c588e7d3bd5891770e4c91d3facade3" +checksum = "2698e2ca73db964e6d496a648fcbb2ace5559941b5179ab3310c9a0b6872b348" dependencies = [ "anyhow", "cairo-lang-defs", @@ -438,25 +435,27 @@ dependencies = [ "cairo-lang-sierra-generator", "cairo-lang-syntax", "cairo-lang-utils", + "indoc", "salsa", + "semver", "smol_str", "thiserror", ] [[package]] name = "cairo-lang-debug" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3cbf67fd766cb7ed48b72e6abf7041857518c9b9fd42475a60c138671c6603" +checksum = "6ac7332f2b041ca28b24b0311a0b4a35f426bb52836a2d268a8374ea262e9e6b" dependencies = [ "cairo-lang-utils", ] [[package]] name = "cairo-lang-defs" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b284e41dfc158dfbdc02612dbfdb27a55547d23063bdc53105eeec41d8df006" +checksum = "079a34b560a82b463cd12ae62022d70981e8ab56b6505f9499348ebeaf460de8" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -464,28 +463,28 @@ dependencies = [ "cairo-lang-parser", "cairo-lang-syntax", "cairo-lang-utils", - "itertools 0.11.0", + "itertools 0.12.1", "salsa", "smol_str", ] [[package]] name = "cairo-lang-diagnostics" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6314b24901af8be75cd0e1363e3ff1a8020066372501f4cfc9161726b06ec2a" +checksum = "c29625349297ad791942377763f5b04c779ea694f436488dc6ad194720b89487" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", "cairo-lang-utils", - "itertools 0.11.0", + "itertools 0.12.1", ] [[package]] name = "cairo-lang-eq-solver" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f95f5c8f7ea75580d164b5304251022e3d47f43fc1c778a01381b55ca9f268c" +checksum = "9cb26cd75126db6eaf94d5dffe0ce750d030ac879a88de5a621551969e9b59e3" dependencies = [ "cairo-lang-utils", "good_lp", @@ -493,23 +492,45 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e58b80f0b413ef1320358fde1a0877fc3fbf740f5cead0de3e947a1bc3bfd4" +checksum = "651012f2956bea884c7a3ab9df21dc76112d7edd3f403b37ca5be62fc3f41b09" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", "path-clean", "salsa", + "semver", + "serde", + "smol_str", +] + +[[package]] +name = "cairo-lang-formatter" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d09ffb9498368cf4e95d0b28662596331aef1677e4f759ab5e609d27dfcb587" +dependencies = [ + "anyhow", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-parser", + "cairo-lang-syntax", + "cairo-lang-utils", + "diffy", + "ignore", + "itertools 0.12.1", + "salsa", "serde", "smol_str", + "thiserror", ] [[package]] name = "cairo-lang-lowering" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe6d604a06ea96c05b3666f2e8fac63cb8709e13667de272912f81db004a16b" +checksum = "da4ffe6c197c35dec665029fcf695422f02c55b5118b4da1142e182b9fe77f87" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -521,7 +542,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "id-arena", - "itertools 0.11.0", + "itertools 0.12.1", "log", "num-bigint", "num-traits 0.2.19", @@ -532,9 +553,9 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf1c279de47a77422f81b8a98023cd523cf0ae79f7153d60c4cf8b62b8ece2f" +checksum = "f262ad5f1110ff70c93deb81cce024cf160f4a4518762e7deb2047fe73846789" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -542,7 +563,7 @@ dependencies = [ "cairo-lang-syntax-codegen", "cairo-lang-utils", "colored", - "itertools 0.11.0", + "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", "salsa", @@ -552,9 +573,9 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1177a07498bdf45cba62f0c727388ff7433072847dbf701c58fa3c3e358154e" +checksum = "18024b44b5edbc1f378ba85c1a4ff04e880ea465a33251053aec507f08250668" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -564,27 +585,27 @@ dependencies = [ "cairo-lang-utils", "indent", "indoc", - "itertools 0.11.0", + "itertools 0.12.1", "salsa", "smol_str", ] [[package]] name = "cairo-lang-proc-macros" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c90d812ec983c5a8e3173aca3fc55036b9739201c89f30271ee14a4c1189379" +checksum = "124402d8fad2a033bb36910dd7d0651f3100845c63dce679c58797a8cb0448c2" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] name = "cairo-lang-project" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3985495d7e9dc481e97135d7139cfa098024351fb51d5feef8366b5fbc104807" +checksum = "1f37dba9653eabf4dcb43a5e1436cd6bc093b5ad6f28ff42eaaef12549014213" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -596,15 +617,13 @@ dependencies = [ [[package]] name = "cairo-lang-runner" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc7c5969d107d24dbd7612ab7afec65d25475fe51d4bb708e3c773f2346c92b" +checksum = "18df87ee986ca0e02e2ea63483875b791602809873c908bbf7b3d592e3833a3a" dependencies = [ "ark-ff", "ark-secp256k1", "ark-secp256r1", - "ark-std", - "cairo-felt", "cairo-lang-casm", "cairo-lang-lowering", "cairo-lang-sierra", @@ -614,22 +633,24 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm 0.9.3", - "itertools 0.11.0", + "cairo-vm", + "itertools 0.12.1", "keccak", "num-bigint", "num-integer", "num-traits 0.2.19", + "rand", + "sha2", "smol_str", - "starknet-crypto", + "starknet-types-core", "thiserror", ] [[package]] name = "cairo-lang-semantic" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5cfadbb9ca3479a6b5c02c0a125a5747835ba57a2de9c4e9764f42d85abe059" +checksum = "a1612476b548e9ab8ae89ee38a73d9875339f62f2f59d9ce8a719bc1761c54c3" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -643,7 +664,7 @@ dependencies = [ "cairo-lang-utils", "id-arena", "indoc", - "itertools 0.11.0", + "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", "once_cell", @@ -654,65 +675,69 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a57492267a5a8891866b6e48cdefa508b5f05931a5f8eaf004b9de15b1ffd6" +checksum = "8209be8cf22263bf8a55df334a642b74fe563beecbbbefa55cda39fa4b131a61" dependencies = [ "anyhow", - "cairo-felt", "cairo-lang-utils", "const-fnv1a-hash", "convert_case", "derivative", - "itertools 0.11.0", + "itertools 0.12.1", "lalrpop", "lalrpop-util", "num-bigint", + "num-integer", "num-traits 0.2.19", + "once_cell", "regex", "salsa", "serde", "serde_json", "sha3", "smol_str", + "starknet-types-core", "thiserror", ] [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fdbb4bd95477123653b9200bd4e9dceae95a914f6fe85b2bed83b223e36fb5a" +checksum = "1c9d1350366c23e4a9f6e18ea95939f18df52df455f06c0e3d7889f80ce18a94" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "itertools 0.11.0", + "itertools 0.12.1", + "num-bigint", "num-traits 0.2.19", "thiserror", ] [[package]] name = "cairo-lang-sierra-gas" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882cb178f1b79aabf70acce1d87b08d569d8a4b0ce8b1d8f538a02cdb36789db" +checksum = "9fe1ff15052b173537360b7dca5f9b2ccb10392b2a1c11af99add35d42632115" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "itertools 0.11.0", + "itertools 0.12.1", + "num-bigint", "num-traits 0.2.19", "thiserror", ] [[package]] name = "cairo-lang-sierra-generator" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d80c9d29e6d3f4ab60e698ebe2de84dcf90570c3dd1cfa7b01bd5c42470331c" +checksum = "2d3802e7b6722fabc9cc0a61c86e7ad53138f6f41880aca80a60f889739fbf55" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -724,21 +749,22 @@ dependencies = [ "cairo-lang-sierra", "cairo-lang-syntax", "cairo-lang-utils", - "itertools 0.11.0", + "itertools 0.12.1", "num-traits 0.2.19", "once_cell", "salsa", + "serde", + "serde_json", "smol_str", ] [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac02c90be2630ae861db6af226090da92741020519768332dd2c07e24d94c75" +checksum = "355bde3b0a835bac2457af133a9042a7d039c934e678905b843bb6b420884428" dependencies = [ "assert_matches", - "cairo-felt", "cairo-lang-casm", "cairo-lang-sierra", "cairo-lang-sierra-ap-change", @@ -746,17 +772,18 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-utils", "indoc", - "itertools 0.11.0", + "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", + "starknet-types-core", "thiserror", ] [[package]] name = "cairo-lang-sierra-type-size" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d102b10989f9637b1c916dd950cbd1bd8bb1b6a7aaa1a3035390be0683b92d85" +checksum = "7ddddaacc814e0ffda9f176c913fb2a9cd74fe6594dea789e8281eef10cac201" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -764,12 +791,11 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27921a2bf82d191d28afd570b913341080c8fc25c83bf870dbf1252570b1b41" +checksum = "10be5fd5fe78db232b032e25e4be786f8061606be4ab26371c869c5ab267699c" dependencies = [ "anyhow", - "cairo-felt", "cairo-lang-compiler", "cairo-lang-defs", "cairo-lang-diagnostics", @@ -785,27 +811,27 @@ dependencies = [ "const_format", "indent", "indoc", - "itertools 0.11.0", + "itertools 0.12.1", "once_cell", "serde", "serde_json", "smol_str", + "starknet-types-core", "thiserror", ] [[package]] name = "cairo-lang-starknet-classes" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8623b076ef3569e4262da5da270a84658b1ff242fe0c9624fbe432e7a937d101" +checksum = "b7bf919d0919fce727c6d53ee5cb37459c9db35c258521284523c53f5f907c07" dependencies = [ - "cairo-felt", "cairo-lang-casm", "cairo-lang-sierra", "cairo-lang-sierra-to-casm", "cairo-lang-utils", "convert_case", - "itertools 0.11.0", + "itertools 0.12.1", "num-bigint", "num-integer", "num-traits 0.2.19", @@ -814,15 +840,15 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "starknet-crypto", + "starknet-types-core", "thiserror", ] [[package]] name = "cairo-lang-syntax" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c62f5bd74e249636e7c48d8b95e6cc0ee991206d4a6cbe5c2624184a828e70b" +checksum = "b2a376f88d815b63505be54a6afa93d75b67cfd65835922ec648cfcbb0a5e4b4" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -836,9 +862,9 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a744747e9ab03b65480265304490f3e29d99e4cb297e39d0e6fdb047c1bc86a7" +checksum = "01f276bc28f6302fc63032046a12b60d18498906e65f646acb963244eed97f7c" dependencies = [ "genco", "xshell", @@ -846,12 +872,11 @@ dependencies = [ [[package]] name = "cairo-lang-test-plugin" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592e7e5f875d69428aae446e299d3c4618c7fb326adafc5d3a83bd8a5a916111" +checksum = "e4cc569e35642d48ba2c75ba500397887a54fa5ead441e005b59968445851b99" dependencies = [ "anyhow", - "cairo-felt", "cairo-lang-compiler", "cairo-lang-debug", "cairo-lang-defs", @@ -866,18 +891,20 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "indoc", - "itertools 0.11.0", + "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", "serde", + "starknet-types-core", ] [[package]] name = "cairo-lang-test-utils" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0787123191d9275b748e0b8f601e332642c409e863e72a634719090e044b2b" +checksum = "21e90b6236439e19077ec913351a17a33c7be199dcafdacd8389c4c5199400d6" dependencies = [ + "cairo-lang-formatter", "cairo-lang-utils", "colored", "log", @@ -886,13 +913,13 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f98e8769412907ceb106c21c70907cc0c87ca0a2a44c82b6229a695a6f9b48" +checksum = "55a394e545f1500bea093d01be40895d3234faaa24d9585d08a509c514cabd88" dependencies = [ "hashbrown 0.14.5", - "indexmap 2.2.6", - "itertools 0.11.0", + "indexmap 2.4.0", + "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", "schemars", @@ -905,7 +932,6 @@ version = "0.2.0" dependencies = [ "anyhow", "bumpalo", - "cairo-felt", "cairo-lang-compiler", "cairo-lang-defs", "cairo-lang-diagnostics", @@ -922,7 +948,7 @@ dependencies = [ "cairo-lang-test-plugin", "cairo-lang-utils", "cairo-native-runtime", - "cairo-vm 1.0.0-rc3", + "cairo-vm", "cc", "clap", "colored", @@ -932,7 +958,7 @@ dependencies = [ "itertools 0.13.0", "k256", "keccak", - "lambdaworks-math", + "lambdaworks-math 0.9.0", "lazy_static", "libc", "libloading", @@ -951,6 +977,7 @@ dependencies = [ "sec1", "serde", "serde_json", + "sha2", "starknet-types-core", "stats_alloc", "tempfile", @@ -965,52 +992,20 @@ dependencies = [ name = "cairo-native-runtime" version = "0.2.0" dependencies = [ - "cairo-lang-runner", "cairo-lang-sierra-gas", "lazy_static", "libc", - "starknet-crypto", - "starknet-curve", - "starknet-types-core", -] - -[[package]] -name = "cairo-vm" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90d260c5b0c0812f02fcbdc21eb0d5908fcecdca888fb779b54c3967f7f88bf" -dependencies = [ - "anyhow", - "bincode", - "bitvec", - "cairo-felt", - "generic-array", - "hashbrown 0.14.5", - "hex", - "keccak", - "lazy_static", - "mimalloc", - "nom", - "num-bigint", - "num-integer", - "num-prime", - "num-traits 0.2.19", "rand", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "sha3", - "starknet-crypto", - "starknet-curve", - "thiserror-no-std", + "starknet-crypto 0.7.1", + "starknet-curve 0.5.0", + "starknet-types-core", ] [[package]] name = "cairo-vm" -version = "1.0.0-rc3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0fa4c74b86c0f17b58ced4fdab5c1da0a41fb12725ad7601e12bb27d8d90435" +checksum = "58363ad8065ed891e3b14a8191b707677c7c7cb5b9d10030822506786d8d8108" dependencies = [ "anyhow", "ark-ff", @@ -1031,11 +1026,12 @@ dependencies = [ "num-prime", "num-traits 0.2.19", "rand", + "rust_decimal", "serde", "serde_json", "sha2", "sha3", - "starknet-crypto", + "starknet-crypto 0.6.2", "starknet-types-core", "thiserror-no-std", "zip", @@ -1043,9 +1039,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -1058,13 +1054,13 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.101" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" +checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -1132,9 +1128,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.7" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -1142,9 +1138,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -1154,27 +1150,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -1264,9 +1260,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -1371,9 +1367,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -1381,27 +1377,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1479,7 +1475,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1489,7 +1485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1504,6 +1500,15 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "diffy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e616e59155c92257e84970156f506287853355f58cd4a6eb167385722c32b790" +dependencies = [ + "nu-ansi-term", +] + [[package]] name = "digest" version = "0.10.7" @@ -1566,7 +1571,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1633,7 +1638,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1676,9 +1681,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" dependencies = [ "crc32fast", "miniz_oxide", @@ -1752,7 +1757,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1810,7 +1815,7 @@ checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -1843,6 +1848,19 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + [[package]] name = "good_lp" version = "1.8.1" @@ -1917,9 +1935,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "hex" @@ -1966,6 +1984,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "ignore" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.7", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -1996,9 +2030,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -2044,9 +2078,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ "hermit-abi", "libc", @@ -2055,9 +2089,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -2103,18 +2137,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -2179,7 +2213,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb5d4f22241504f7c7b8d2c3a7d7835d7c07117f10bff2a7d96a9ef6ef217c3" dependencies = [ - "lambdaworks-math", + "lambdaworks-math 0.7.0", "serde", "sha2", "sha3", @@ -2190,6 +2224,16 @@ name = "lambdaworks-math" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "358e172628e713b80a530a59654154bfc45783a6ed70ea284839800cebdf8f97" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "lambdaworks-math" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030a60407d8b7bfef27f591acd5c570a7729d81f99531e992f6d61189b89e72d" dependencies = [ "rayon", "serde", @@ -2213,18 +2257,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2233,16 +2277,6 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "libmimalloc-sys" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "libredox" version = "0.1.3" @@ -2261,9 +2295,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "llvm-sys" -version = "181.1.0" +version = "181.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890e59e3db86b787af9d9b53c6accc0193e9b698293dda178c0821dbc3fb6217" +checksum = "1d255b36907416971229095a8465c0b69f5f1c6fb8421b6dcdbb64eb47e1be90" dependencies = [ "anyhow", "cc", @@ -2285,15 +2319,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ "hashbrown 0.14.5", ] @@ -2340,7 +2374,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.68", + "syn 2.0.75", "tblgen-alt", "unindent", ] @@ -2351,15 +2385,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "mimalloc" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" -dependencies = [ - "libmimalloc-sys", -] - [[package]] name = "minilp" version = "0.2.2" @@ -2378,11 +2403,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -2435,9 +2460,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits 0.2.19", @@ -2530,9 +2555,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "ordered-float" @@ -2630,9 +2655,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2686,7 +2711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.4.0", ] [[package]] @@ -2762,9 +2787,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "powerfmt" @@ -2774,9 +2799,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -2811,7 +2839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -2869,9 +2897,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2958,18 +2986,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -2978,9 +3006,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -3044,9 +3072,9 @@ dependencies = [ [[package]] name = "rstest" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afd55a67069d6e434a95161415f5beeada95a01c7b815508a82dcb0e1593682" +checksum = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936" dependencies = [ "futures", "futures-timer", @@ -3056,9 +3084,9 @@ dependencies = [ [[package]] name = "rstest_macros" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4165dfae59a39dd41d8dec720d3cbfbc71f69744efb480a3920f5d4e0cc6798d" +checksum = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42" dependencies = [ "cfg-if", "glob", @@ -3068,15 +3096,15 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.68", + "syn 2.0.75", "unicode-ident", ] [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "num-traits 0.2.19", @@ -3174,8 +3202,8 @@ dependencies = [ [[package]] name = "scarb-metadata" -version = "1.11.1" -source = "git+https://github.com/software-mansion/scarb.git?rev=v2.6.4#c4c7c0bac3a30c23a4e2f1db145b967371b0e3c2" +version = "1.12.0" +source = "git+https://github.com/software-mansion/scarb.git?rev=v2.7.1#e288874ba65f228ce3ae9aa55eef9f169824e998" dependencies = [ "camino", "semver", @@ -3186,8 +3214,8 @@ dependencies = [ [[package]] name = "scarb-ui" -version = "0.1.3" -source = "git+https://github.com/software-mansion/scarb.git?rev=v2.6.4#c4c7c0bac3a30c23a4e2f1db145b967371b0e3c2" +version = "0.1.5" +source = "git+https://github.com/software-mansion/scarb.git?rev=v2.7.1#e288874ba65f228ce3ae9aa55eef9f169824e998" dependencies = [ "anyhow", "camino", @@ -3197,6 +3225,7 @@ dependencies = [ "scarb-metadata", "serde", "serde_json", + "tracing-core", ] [[package]] @@ -3221,7 +3250,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -3255,22 +3284,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -3281,25 +3310,26 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] name = "serde_json" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -3378,9 +3408,9 @@ dependencies = [ [[package]] name = "slug" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" dependencies = [ "deunicode", "wasm-bindgen", @@ -3442,21 +3472,52 @@ dependencies = [ "num-traits 0.2.19", "rfc6979", "sha2", - "starknet-crypto-codegen", - "starknet-curve", + "starknet-crypto-codegen 0.3.3", + "starknet-curve 0.4.2", "starknet-ff", "zeroize", ] +[[package]] +name = "starknet-crypto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2a821ad8d98c6c3e4d0e5097f3fe6e2ed120ada9d32be87cd1330c7923a2f0" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits 0.2.19", + "rfc6979", + "sha2", + "starknet-crypto-codegen 0.4.0", + "starknet-curve 0.5.0", + "starknet-types-core", + "zeroize", +] + [[package]] name = "starknet-crypto-codegen" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" dependencies = [ - "starknet-curve", + "starknet-curve 0.4.2", "starknet-ff", - "syn 2.0.68", + "syn 2.0.75", +] + +[[package]] +name = "starknet-crypto-codegen" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e179dedc3fa6da064e56811d3e05d446aa2f7459e4eb0e3e49378a337235437" +dependencies = [ + "starknet-curve 0.5.0", + "starknet-types-core", + "syn 2.0.75", ] [[package]] @@ -3468,6 +3529,15 @@ dependencies = [ "starknet-ff", ] +[[package]] +name = "starknet-curve" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56935b306dcf0b8f14bb2a1257164b8478bb8be4801dfae0923f5b266d1b457c" +dependencies = [ + "starknet-types-core", +] + [[package]] name = "starknet-ff" version = "0.3.7" @@ -3482,12 +3552,13 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4098ac4ad57621cc7ec133b80fe72814d2cc4bee63ca8e7be4450ba6f42a07e8" +checksum = "ce6bacf0ba19bc721e518bc4bf389ff13daa8a7c5db5fd320600473b8aa9fcbd" dependencies = [ "lambdaworks-crypto", - "lambdaworks-math", + "lambdaworks-math 0.7.0", + "lazy_static", "num-bigint", "num-integer", "num-traits 0.2.19", @@ -3538,9 +3609,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" dependencies = [ "proc-macro2", "quote", @@ -3567,14 +3638,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3606,7 +3678,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -3617,28 +3689,28 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", "test-case-core", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -3711,21 +3783,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.14", + "toml_edit 0.22.20", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -3736,22 +3808,22 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.4.0", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.13", + "winnow 0.6.18", ] [[package]] @@ -3773,7 +3845,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -3848,9 +3920,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unescaper" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adf6ad32eb5b3cadff915f7b770faaac8f7ff0476633aa29eb0d9584d889d34" +checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" dependencies = [ "thiserror", ] @@ -3875,9 +3947,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unicode_categories" @@ -3911,9 +3983,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -3942,34 +4014,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3977,28 +4050,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -4034,11 +4107,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4062,7 +4135,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -4082,18 +4164,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -4104,9 +4186,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4116,9 +4198,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4128,15 +4210,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -4146,9 +4228,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4158,9 +4240,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4170,9 +4252,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4182,9 +4264,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -4197,9 +4279,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -4236,22 +4318,23 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -4271,7 +4354,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.75", ] [[package]] @@ -4315,9 +4398,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.11+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75652c55c0b6f3e6f12eb786fe1bc960396bf05a1eb3bf1f3691c3610ac2e6d4" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index ae5e9609d..b734ff3ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,13 +39,12 @@ required-features = ["scarb"] [features] default = ["build-cli", "with-runtime"] build-cli = [ - "dep:clap", - "dep:tracing-subscriber", - "dep:anyhow", - "dep:cairo-lang-test-plugin", - "dep:cairo-lang-runner", - "dep:colored", - "dep:cairo-felt", + "dep:clap", + "dep:tracing-subscriber", + "dep:anyhow", + "dep:cairo-lang-test-plugin", + "dep:cairo-lang-runner", + "dep:colored", ] scarb = ["build-cli", "dep:scarb-ui", "dep:scarb-metadata", "dep:serde_json"] with-debug-utils = [] @@ -55,14 +54,14 @@ with-cheatcode = [] [dependencies] bumpalo = "3.16.0" -cairo-lang-compiler = "2.6.4" -cairo-lang-defs = "2.6.4" -cairo-lang-diagnostics = "2.6.4" -cairo-lang-filesystem = "2.6.4" -cairo-lang-lowering = "2.6.4" -cairo-lang-semantic = "2.6.4" -cairo-lang-sierra = "2.6.4" -cairo-lang-sierra-generator = "2.6.4" +cairo-lang-compiler = "2.7.1" +cairo-lang-defs = "2.7.1" +cairo-lang-diagnostics = "2.7.1" +cairo-lang-filesystem = "2.7.1" +cairo-lang-lowering = "2.7.1" +cairo-lang-semantic = "2.7.1" +cairo-lang-sierra = "2.7.1" +cairo-lang-sierra-generator = "2.7.1" educe = "0.5.11" # can't update until https://github.com/magiclen/educe/issues/27 id-arena = "2.2" itertools = "0.13.0" @@ -73,8 +72,10 @@ melior = { version = "0.18.4", features = ["ods-dialects"] } mlir-sys = "0.2.2" num-bigint = "0.4.4" num-traits = "0.2" -starknet-types-core = { version = "=0.1.2", default-features = false, features = [ - "std", "serde", "num-traits" +starknet-types-core = { version = "0.1.5", default-features = false, features = [ + "std", + "serde", + "num-traits", ] } tempfile = "3.6" thiserror = "1.0.59" @@ -82,48 +83,51 @@ tracing = "0.1" # CLI dependencies -cairo-lang-sierra-ap-change = "2.6.4" -cairo-lang-sierra-gas = "2.6.4" -cairo-lang-starknet = "2.6.4" -cairo-lang-utils = "2.6.4" -cairo-lang-starknet-classes = "2.6.4" +cairo-lang-sierra-ap-change = "2.7.1" +cairo-lang-sierra-gas = "2.7.1" +cairo-lang-starknet = "2.7.1" +cairo-lang-utils = "2.7.1" +cairo-lang-starknet-classes = "2.7.1" cairo-native-runtime = { version = "0.2.0", path = "runtime", optional = true } clap = { version = "4.5", features = ["derive"], optional = true } libloading = "0.8.3" -tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry"] , optional = true } +tracing-subscriber = { version = "0.3.18", features = [ + "env-filter", + "json", + "registry", +], optional = true } serde = { version = "1.0", features = ["derive"], optional = true } anyhow = { version = "1.0", optional = true } -cairo-lang-test-plugin = { version = "2.6.4", optional = true } -cairo-lang-runner = { version = "2.6.4", optional = true } +cairo-lang-test-plugin = { version = "2.7.1", optional = true } +cairo-lang-runner = { version = "2.7.1", optional = true } colored = { version = "2.1.0", optional = true } # needed to interface with cairo-lang-* -cairo-felt = { version = "0.9.1", optional = true } -keccak = "0.1.3" +keccak = "0.1.5" k256 = "0.13.3" p256 = "0.13.2" -scarb-metadata = { git = "https://github.com/software-mansion/scarb.git", rev = "v2.6.4", optional = true } -scarb-ui = { git = "https://github.com/software-mansion/scarb.git", rev = "v2.6.4", optional = true } +sha2 = "0.10.8" # needed for the syscall handler stub +scarb-metadata = { git = "https://github.com/software-mansion/scarb.git", rev = "v2.7.1", optional = true } +scarb-ui = { git = "https://github.com/software-mansion/scarb.git", rev = "v2.7.1", optional = true } sec1 = "0.7.3" -serde_json = { version = "1.0.117", optional = true } +serde_json = { version = "1.0.125", optional = true } stats_alloc = "0.1.10" [dev-dependencies] -cairo-vm = { version = "1.0.0-rc3", features = ["cairo-1-hints"] } -cairo-felt = "0.9.1" -cairo-lang-runner = "2.6.4" -cairo-lang-semantic = { version = "2.6.4", features = ["testing"] } +cairo-vm = { version = "1.0.1", features = ["cairo-1-hints"] } +cairo-lang-runner = "2.7.1" +cairo-lang-semantic = { version = "2.7.1", features = ["testing"] } criterion = { version = "0.5.1", features = ["html_reports"] } -lambdaworks-math = "0.7.0" +lambdaworks-math = "0.9.0" pretty_assertions_sorted = "1.2.3" proptest = "1.4.0" -rstest = "0.21.0" +rstest = "0.22.0" test-case = "3.3" walkdir = "2.5.0" serde_json = { version = "1.0.117" } salsa = "0.16.1" [build-dependencies] -cc = "1.0.96" +cc = "1.1.14" [profile.optimized-dev] inherits = "dev" diff --git a/Makefile b/Makefile index 2021bbe2b..361342e64 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ # UNAME := $(shell uname) -CAIRO_2_VERSION=2.6.4 +CAIRO_2_VERSION=2.7.1 check-llvm: ifndef MLIR_SYS_180_PREFIX @@ -136,7 +136,7 @@ cairo-%-macos.tar: cairo-%.tar: curl -L -o "$@" "https://github.com/starkware-libs/cairo/releases/download/v$*/release-x86_64-unknown-linux-musl.tar.gz" -SCARB_VERSION = 2.6.4 +SCARB_VERSION = 2.7.1 install-scarb: curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh| sh -s -- --no-modify-path --version $(SCARB_VERSION) diff --git a/README.md b/README.md index 60c03eef4..856cf81b5 100644 --- a/README.md +++ b/README.md @@ -717,7 +717,7 @@ For more examples, check out the `examples/` directory. ### Requirements - [hyperfine](https://github.com/sharkdp/hyperfine): `cargo install hyperfine` -- [cairo 2.6.4](https://github.com/starkware-libs/cairo) +- [cairo 2.7.1](https://github.com/starkware-libs/cairo) - Cairo Corelibs - LLVM 18 with MLIR diff --git a/benches/benches.rs b/benches/benches.rs index 85fd7e17d..bc9a4bc4f 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -134,7 +134,7 @@ fn criterion_benchmark(c: &mut Criterion) { fn load_contract(path: impl AsRef) -> Program { let mut db = RootDatabase::builder().detect_corelib().build().unwrap(); let main_crate_ids = setup_project(&mut db, path.as_ref()).unwrap(); - compile_prepared_db( + let sirrra_program = compile_prepared_db( &mut db, main_crate_ids, CompilerConfig { @@ -142,7 +142,9 @@ fn load_contract(path: impl AsRef) -> Program { ..Default::default() }, ) - .unwrap() + .unwrap(); + + sirrra_program.program } criterion_group!(benches, criterion_benchmark); diff --git a/docs/gas.md b/docs/gas.md index 53c03a455..a61669aab 100644 --- a/docs/gas.md +++ b/docs/gas.md @@ -18,7 +18,7 @@ The process of calculating gas begins at the very outset of the compilation proc The action of withdrawing gas can be split in two steps: -- **Calculating Total Gas Cost**: Using the previously constructed HashMap, we iterate over the various cost tokens (including steps, built-in usage, and memory holes) for the statement, convert them into a [common gas unit](https://github.com/starkware-libs/cairo/blob/v2.7.0-dev.0/crates/cairo-lang-runner/src/lib.rs#L136), and sum them up to get the total gas cost for the statement. +- **Calculating Total Gas Cost**: Using the previously constructed HashMap, we iterate over the various cost tokens (including steps, built-in usage, and memory holes) for the statement, convert them into a [common gas unit](https://github.com/starkware-libs/cairo/blob/v2.7.1/crates/cairo-lang-runner/src/lib.rs#L136), and sum them up to get the total gas cost for the statement. - **Executing Gas Withdrawal**: The previously calculated gas cost is used when the current statement is a `withdraw_gas` libfunc call. The `withdraw_gas` libfunc takes the current leftover gas as input and uses the calculated gas cost for the statement to deduct the appropriate amount from the gas builtin. In the compiled IR, gas withdrawal appears as the total gas being reduced by a predefined constant. Additionally, the libfunc branches based on whether the remaining gas is greater than or equal to the amount being withdrawn. diff --git a/examples/erc20.rs b/examples/erc20.rs index 401a5435d..bb272bdc4 100644 --- a/examples/erc20.rs +++ b/examples/erc20.rs @@ -265,6 +265,19 @@ impl StarknetSyscallHandler for SyscallHandler { ) -> SyscallResult<(U256, U256)> { unimplemented!() } + + fn sha256_process_block( + &mut self, + _prev_state: &[u32; 8], + _current_block: &[u32; 16], + _remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]> { + unimplemented!() + } + + fn cheatcode(&mut self, _selector: Felt, _input: &[Felt]) -> Vec { + unimplemented!(); + } } fn main() { diff --git a/examples/starknet.rs b/examples/starknet.rs index 9d111934f..516da48aa 100644 --- a/examples/starknet.rs +++ b/examples/starknet.rs @@ -396,6 +396,15 @@ impl StarknetSyscallHandler for SyscallHandler { _ => vec![], } } + + fn sha256_process_block( + &mut self, + _prev_state: &[u32; 8], + _current_block: &[u32; 16], + _remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]> { + unimplemented!() + } } fn main() { diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index e915cb15c..1c6a9f9dd 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -9,12 +9,12 @@ license = "Apache-2.0" crate-type = ["rlib", "cdylib", "staticlib"] [dependencies] -starknet-types-core = { version = "=0.1.2", default-features = false, features = [ - "std", "serde", +starknet-types-core = { version = "0.1.5", default-features = false, features = [ + "std", "serde", ] } -cairo-lang-runner = "2.6.4" -cairo-lang-sierra-gas = "2.6.4" -libc = "0.2.155" -starknet-crypto = "0.6.2" -starknet-curve = "0.4.2" -lazy_static = "1.4.0" +cairo-lang-sierra-gas = "2.7.1" +libc = "0.2.158" +starknet-crypto = "0.7.1" +starknet-curve = "0.5.0" +lazy_static = "1.5.0" +rand = "0.8.5" diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index cc41b324f..93ea7f81f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -4,13 +4,17 @@ use cairo_lang_sierra_gas::core_libfunc_cost::{ DICT_SQUASH_REPEATED_ACCESS_COST, DICT_SQUASH_UNIQUE_KEY_COST, }; use lazy_static::lazy_static; -use starknet_crypto::FieldElement; -use starknet_curve::AffinePoint; -use starknet_types_core::felt::Felt; +use rand::Rng; +use starknet_curve::curve_params::BETA; +use starknet_types_core::{ + curve::{AffinePoint, ProjectivePoint}, + felt::Felt, +}; +use std::ops::Mul; use std::{collections::HashMap, fs::File, io::Write, os::fd::FromRawFd, ptr::NonNull, slice}; lazy_static! { - pub static ref HALF_PRIME: FieldElement = FieldElement::from_dec_str( + pub static ref HALF_PRIME: Felt = Felt::from_dec_str( "1809251394333065606848661391547535052811553607665798349986546028067936010240" ) .unwrap(); @@ -102,12 +106,12 @@ pub unsafe extern "C" fn cairo_native__libfunc__pedersen( let rhs = slice::from_raw_parts(rhs, 32); // Convert to FieldElement. - let lhs = FieldElement::from_byte_slice_be(lhs).unwrap(); - let rhs = FieldElement::from_byte_slice_be(rhs).unwrap(); + let lhs = Felt::from_bytes_le_slice(lhs); + let rhs = Felt::from_bytes_le_slice(rhs); // Compute pedersen hash and copy the result into `dst`. let res = starknet_crypto::pedersen_hash(&lhs, &rhs); - dst.copy_from_slice(&res.to_bytes_be()); + dst.copy_from_slice(&res.to_bytes_le()); } /// Compute `hades_permutation(op0, op1, op2)` and replace the operands with the results. @@ -135,18 +139,18 @@ pub unsafe extern "C" fn cairo_native__libfunc__hades_permutation( // Convert to FieldElement. let mut state = [ - FieldElement::from_byte_slice_be(op0).unwrap(), - FieldElement::from_byte_slice_be(op1).unwrap(), - FieldElement::from_byte_slice_be(op2).unwrap(), + Felt::from_bytes_le_slice(op0), + Felt::from_bytes_le_slice(op1), + Felt::from_bytes_le_slice(op2), ]; // Compute Poseidon permutation. starknet_crypto::poseidon_permute_comp(&mut state); // Write back the results. - op0.copy_from_slice(&state[0].to_bytes_be()); - op1.copy_from_slice(&state[1].to_bytes_be()); - op2.copy_from_slice(&state[2].to_bytes_be()); + op0.copy_from_slice(&state[0].to_bytes_le()); + op1.copy_from_slice(&state[1].to_bytes_le()); + op2.copy_from_slice(&state[2].to_bytes_le()); } /// Felt252 type used in cairo native runtime @@ -286,25 +290,22 @@ pub unsafe extern "C" fn cairo_native__dict_gas_refund(ptr: *const FeltDict) -> pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_from_x_nz( mut point_ptr: NonNull<[[u8; 32]; 2]>, ) -> bool { - let x = FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(); + let x = Felt::from_bytes_le(&point_ptr.as_ref()[0]); - match AffinePoint::from_x(x) { - Some(mut point) => { - // If y > PRIME/ 2 use PRIME - y - if point.y >= *HALF_PRIME { - point.y = -point.y - } - point_ptr.as_mut()[1].copy_from_slice(&point.y.to_bytes_be()); - point_ptr.as_mut()[1].reverse(); + // https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-sierra-to-casm/src/invocations/ec.rs#L63 + + let x2 = x * x; + let x3 = x2 * x; + let alpha_x_plus_beta = x + BETA; + let rhs = x3 + alpha_x_plus_beta; + let y = rhs.sqrt().unwrap_or_else(|| Felt::from(3) * rhs); + match AffinePoint::new(x, y) { + Ok(point) => { + point_ptr.as_mut()[1].copy_from_slice(&point.y().to_bytes_le()); true } - None => false, + Err(_) => false, } } @@ -320,22 +321,49 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_from_x_nz( /// definitely unsafe to use manually. #[no_mangle] pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_point_try_new_nz( - point_ptr: NonNull<[[u8; 32]; 2]>, + mut point_ptr: NonNull<[[u8; 32]; 2]>, ) -> bool { - let x = FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(); - let y = FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[1]; - data.reverse(); - data - }) - .unwrap(); + let x = Felt::from_bytes_le(&point_ptr.as_ref()[0]); + let y = Felt::from_bytes_le(&point_ptr.as_ref()[1]); - AffinePoint::from_x(x).is_some_and(|point| y == point.y || y == -point.y) + match AffinePoint::new(x, y) { + Ok(point) => { + point_ptr.as_mut()[0].copy_from_slice(&point.x().to_bytes_le()); + point_ptr.as_mut()[1].copy_from_slice(&point.y().to_bytes_le()); + true + } + Err(_) => false, + } +} + +/// Compute `ec_state_init()` and store the state back. +/// +/// # Safety +/// +/// This function is intended to be called from MLIR, deals with pointers, and is therefore +/// definitely unsafe to use manually. +#[no_mangle] +pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_init( + mut state_ptr: NonNull<[[u8; 32]; 4]>, +) { + // https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-runner/src/casm_run/mod.rs#L1802 + let mut rng = rand::thread_rng(); + let (random_x, random_y) = loop { + // Randominzing 31 bytes to make sure is in range. + let x_bytes: [u8; 31] = rng.gen(); + let random_x = Felt::from_bytes_be_slice(&x_bytes); + let random_y_squared = random_x * random_x * random_x + random_x + BETA; + if let Some(random_y) = random_y_squared.sqrt() { + break (random_x, random_y); + } + }; + + let state = AffinePoint::new(random_x, random_y).unwrap(); + + state_ptr.as_mut()[0].copy_from_slice(&state.x().to_bytes_le()); + state_ptr.as_mut()[1].copy_from_slice(&state.y().to_bytes_le()); + state_ptr.as_mut()[2].copy_from_slice(&state.x().to_bytes_le()); + state_ptr.as_mut()[3].copy_from_slice(&state.y().to_bytes_le()); } /// Compute `ec_state_add(state, point)` and store the state back. @@ -353,44 +381,22 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_add( mut state_ptr: NonNull<[[u8; 32]; 4]>, point_ptr: NonNull<[[u8; 32]; 2]>, ) { - let mut state = AffinePoint { - x: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(), - y: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[1]; - data.reverse(); - data - }) - .unwrap(), - infinity: false, - }; - let point = AffinePoint { - x: FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(), - y: FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[1]; - data.reverse(); - data - }) - .unwrap(), - infinity: false, - }; + let mut state = ProjectivePoint::from_affine( + Felt::from_bytes_le(&state_ptr.as_ref()[0]), + Felt::from_bytes_le(&state_ptr.as_ref()[1]), + ) + .unwrap(); + let point = AffinePoint::new( + Felt::from_bytes_le(&point_ptr.as_ref()[0]), + Felt::from_bytes_le(&point_ptr.as_ref()[1]), + ) + .unwrap(); state += &point; + let state = state.to_affine().unwrap(); - state_ptr.as_mut()[0].copy_from_slice(&state.x.to_bytes_be()); - state_ptr.as_mut()[1].copy_from_slice(&state.y.to_bytes_be()); - - state_ptr.as_mut()[0].reverse(); - state_ptr.as_mut()[1].reverse(); + state_ptr.as_mut()[0].copy_from_slice(&state.x().to_bytes_le()); + state_ptr.as_mut()[1].copy_from_slice(&state.y().to_bytes_le()); } /// Compute `ec_state_add_mul(state, scalar, point)` and store the state back. @@ -409,50 +415,23 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_add_mul( scalar_ptr: NonNull<[u8; 32]>, point_ptr: NonNull<[[u8; 32]; 2]>, ) { - let mut state = AffinePoint { - x: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(), - y: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[1]; - data.reverse(); - data - }) - .unwrap(), - infinity: false, - }; - let scalar = FieldElement::from_bytes_be(&{ - let mut data = *scalar_ptr.as_ref(); - data.reverse(); - data - }) + let mut state = ProjectivePoint::from_affine( + Felt::from_bytes_le(&state_ptr.as_ref()[0]), + Felt::from_bytes_le(&state_ptr.as_ref()[1]), + ) .unwrap(); - let point = AffinePoint { - x: FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(), - y: FieldElement::from_bytes_be(&{ - let mut data = point_ptr.as_ref()[1]; - data.reverse(); - data - }) - .unwrap(), - infinity: false, - }; - - state += &(&point * &scalar.to_bits_le()); + let point = ProjectivePoint::from_affine( + Felt::from_bytes_le(&point_ptr.as_ref()[0]), + Felt::from_bytes_le(&point_ptr.as_ref()[1]), + ) + .unwrap(); + let scalar = Felt::from_bytes_le(scalar_ptr.as_ref()); - state_ptr.as_mut()[0].copy_from_slice(&state.x.to_bytes_be()); - state_ptr.as_mut()[1].copy_from_slice(&state.y.to_bytes_be()); + state += &point.mul(scalar); + let state = state.to_affine().unwrap(); - state_ptr.as_mut()[0].reverse(); - state_ptr.as_mut()[1].reverse(); + state_ptr.as_mut()[0].copy_from_slice(&state.x().to_bytes_le()); + state_ptr.as_mut()[1].copy_from_slice(&state.y().to_bytes_le()); } /// Compute `ec_state_try_finalize_nz(state)` and store the result. @@ -470,47 +449,25 @@ pub unsafe extern "C" fn cairo_native__libfunc__ec__ec_state_try_finalize_nz( mut point_ptr: NonNull<[[u8; 32]; 2]>, state_ptr: NonNull<[[u8; 32]; 4]>, ) -> bool { - let state = AffinePoint { - x: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[0]; - data.reverse(); - data - }) - .unwrap(), - y: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[1]; - data.reverse(); - data - }) - .unwrap(), - infinity: false, - }; - let random = AffinePoint { - x: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[2]; - data.reverse(); - data - }) - .unwrap(), - y: FieldElement::from_bytes_be(&{ - let mut data = state_ptr.as_ref()[3]; - data.reverse(); - data - }) - .unwrap(), - infinity: false, - }; + let state = ProjectivePoint::from_affine( + Felt::from_bytes_le(&state_ptr.as_ref()[0]), + Felt::from_bytes_le(&state_ptr.as_ref()[1]), + ) + .unwrap(); + let random = ProjectivePoint::from_affine( + Felt::from_bytes_le(&state_ptr.as_ref()[2]), + Felt::from_bytes_le(&state_ptr.as_ref()[3]), + ) + .unwrap(); - if state.x == random.x && state.y == random.y { + if state.x() == random.x() && state.y() == random.y() { false } else { let point = &state - &random; + let point = point.to_affine().unwrap(); - point_ptr.as_mut()[0].copy_from_slice(&point.x.to_bytes_be()); - point_ptr.as_mut()[1].copy_from_slice(&point.y.to_bytes_be()); - - point_ptr.as_mut()[0].reverse(); - point_ptr.as_mut()[1].reverse(); + point_ptr.as_mut()[0].copy_from_slice(&point.x().to_bytes_le()); + point_ptr.as_mut()[1].copy_from_slice(&point.y().to_bytes_le()); true } diff --git a/src/bin/cairo-native-dump.rs b/src/bin/cairo-native-dump.rs index 71c070828..fa79c65bb 100644 --- a/src/bin/cairo-native-dump.rs +++ b/src/bin/cairo-native-dump.rs @@ -64,6 +64,7 @@ fn load_program(path: &Path, is_contract: bool) -> Result { // mimics cairo_lang_starknet::contract_class::compile_path diff --git a/src/bin/cairo-native-run.rs b/src/bin/cairo-native-run.rs index 96f2ab8e0..f8747d61e 100644 --- a/src/bin/cairo-native-run.rs +++ b/src/bin/cairo-native-run.rs @@ -2,24 +2,21 @@ mod utils; use anyhow::Context; use cairo_lang_compiler::{ + compile_prepared_db, db::RootDatabase, diagnostics::DiagnosticsReporter, project::{check_compiler_path, setup_project}, + CompilerConfig, }; -use cairo_lang_diagnostics::ToOption; use cairo_lang_runner::short_string::as_cairo_short_string; -use cairo_lang_sierra_generator::{ - db::SierraGenGroup, - replace_ids::{DebugReplacer, SierraIdReplacer}, -}; -use cairo_lang_starknet::contract::get_contracts_info; use cairo_native::{ context::NativeContext, executor::{AotNativeExecutor, JitNativeExecutor, NativeExecutor}, metadata::gas::{GasMetadata, MetadataComputationConfig}, + starknet_stub::StubSyscallHandler, }; use clap::{Parser, ValueEnum}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use tracing_subscriber::{EnvFilter, FmtSubscriber}; use utils::{find_function, result_to_runresult}; @@ -66,32 +63,37 @@ fn main() -> anyhow::Result<()> { // Check if args.path is a file or a directory. check_compiler_path(args.single_file, &args.path)?; - let db = &mut RootDatabase::builder().detect_corelib().build()?; + let mut db_builder = RootDatabase::builder(); + db_builder.detect_corelib(); + if args.available_gas.is_none() { + db_builder.skip_auto_withdraw_gas(); + } + let mut db = db_builder.build()?; - let main_crate_ids = setup_project(db, Path::new(&args.path))?; + let main_crate_ids = setup_project(&mut db, &args.path)?; let mut reporter = DiagnosticsReporter::stderr(); if args.allow_warnings { reporter = reporter.allow_warnings(); } - if reporter.check(db) { + if reporter.check(&db) { anyhow::bail!("failed to compile: {}", args.path.display()); } - let sierra_program = db - .get_sierra_program(main_crate_ids.clone()) - .to_option() - .with_context(|| "Compilation failed without any diagnostics.")? - .program - .clone(); - let replacer = DebugReplacer { db }; + let sierra_program = compile_prepared_db( + &mut db, + main_crate_ids, + CompilerConfig { + replace_ids: true, + ..Default::default() + }, + )? + .program; + if args.available_gas.is_none() && sierra_program.requires_gas_counter() { anyhow::bail!("Program requires gas counter, please provide `--available-gas` argument."); } - let _contracts_info = get_contracts_info(db, main_crate_ids, &replacer)?; - let sierra_program = replacer.apply(&sierra_program); - let native_context = NativeContext::new(); // Compile the sierra program into a MLIR module. @@ -115,8 +117,10 @@ fn main() -> anyhow::Result<()> { .get_initial_available_gas(&func.id, args.available_gas.map(|x| x.try_into().unwrap())) .with_context(|| "not enough gas to run")?; + let mut syscall_handler = StubSyscallHandler::default(); + let result = native_executor - .invoke_dynamic(&func.id, &[], Some(initial_gas)) + .invoke_dynamic_with_syscall_handler(&func.id, &[], Some(initial_gas), &mut syscall_handler) .with_context(|| "Failed to run the function.")?; let run_result = result_to_runresult(&result)?; diff --git a/src/bin/cairo-native-test.rs b/src/bin/cairo-native-test.rs index ba42532f8..0c86a195c 100644 --- a/src/bin/cairo-native-test.rs +++ b/src/bin/cairo-native-test.rs @@ -8,10 +8,10 @@ use cairo_lang_compiler::{ }; use cairo_lang_filesystem::cfg::{Cfg, CfgSet}; use cairo_lang_starknet::starknet_plugin_suite; -use cairo_lang_test_plugin::{compile_test_prepared_db, test_plugin_suite}; +use cairo_lang_test_plugin::{compile_test_prepared_db, test_plugin_suite, TestsCompilationConfig}; use clap::Parser; use colored::Colorize; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use tracing_subscriber::{EnvFilter, FmtSubscriber}; use utils::{ test::{display_tests_summary, filter_test_cases, run_tests}, @@ -76,7 +76,7 @@ fn main() -> anyhow::Result<()> { b.build()? }; - let main_crate_ids = setup_project(db, Path::new(&args.path))?; + let main_crate_ids = setup_project(db, &args.path)?; let mut reporter = DiagnosticsReporter::stderr().with_crates(&main_crate_ids); if args.allow_warnings { reporter = reporter.allow_warnings(); @@ -87,10 +87,14 @@ fn main() -> anyhow::Result<()> { let db = db.snapshot(); let test_crate_ids = main_crate_ids.clone(); + let test_config = TestsCompilationConfig { + starknet: args.starknet, + add_statements_functions: false, + }; let build_test_compilation = compile_test_prepared_db( &db, - args.starknet, + test_config, main_crate_ids.clone(), test_crate_ids.clone(), )?; @@ -103,9 +107,9 @@ fn main() -> anyhow::Result<()> { ); let summary = run_tests( - compiled.named_tests, - compiled.sierra_program, - compiled.function_set_costs, + compiled.metadata.named_tests, + compiled.sierra_program.program, + compiled.metadata.function_set_costs, RunArgs { run_mode: args.run_mode.clone(), opt_level: args.opt_level, diff --git a/src/bin/scarb-native-test.rs b/src/bin/scarb-native-test.rs index bbdeb299b..d980287b2 100644 --- a/src/bin/scarb-native-test.rs +++ b/src/bin/scarb-native-test.rs @@ -81,9 +81,9 @@ fn main() -> anyhow::Result<()> { ); let summary = run_tests( - compiled.named_tests, - compiled.sierra_program, - compiled.function_set_costs, + compiled.metadata.named_tests, + compiled.sierra_program.program, + compiled.metadata.function_set_costs, RunArgs { run_mode: args.run_mode.clone(), opt_level: args.opt_level, diff --git a/src/bin/utils/mod.rs b/src/bin/utils/mod.rs index 7d42267c2..8fd4b3c8a 100644 --- a/src/bin/utils/mod.rs +++ b/src/bin/utils/mod.rs @@ -4,7 +4,6 @@ pub mod test; use anyhow::bail; -use cairo_felt::Felt252; use cairo_lang_runner::{casm_run::format_next_item, RunResultValue}; use cairo_lang_sierra::program::{Function, Program}; use cairo_native::{execution_result::ExecutionResult, values::JitValue}; @@ -43,7 +42,7 @@ pub fn find_function<'a>( } /// Formats the given felts as a panic string. -pub fn format_for_panic(mut felts: IntoIter) -> String { +pub fn format_for_panic(mut felts: IntoIter) -> String { let mut items = Vec::new(); while let Some(item) = format_next_item(&mut felts) { items.push(item.quote_if_string()); @@ -67,10 +66,9 @@ pub fn result_to_runresult(result: &ExecutionResult) -> anyhow::Result { - if debug_name - .as_ref() - .expect("missing debug name") - .starts_with("core::panics::PanicResult::") + let debug_name = debug_name.as_ref().expect("missing debug name"); + if debug_name.starts_with("core::panics::PanicResult::") + || debug_name.starts_with("Enum Vec { #[cfg(test)] mod tests { use super::*; - use cairo_felt::Felt252; use cairo_lang_sierra::ProgramParser; use std::collections::HashMap; @@ -228,10 +225,10 @@ mod tests { }) .unwrap(), RunResultValue::Success(vec![ - Felt252::from(34), - Felt252::from(42), - Felt252::from(100), - Felt252::from(1000) + Felt::from(34), + Felt::from(42), + Felt::from(100), + Felt::from(1000) ]) ); } @@ -250,7 +247,7 @@ mod tests { builtin_stats: Default::default(), }) .unwrap(), - RunResultValue::Success(vec![Felt252::from(24)]) + RunResultValue::Success(vec![Felt::from(24)]) ); } @@ -308,11 +305,7 @@ mod tests { builtin_stats: Default::default(), }) .unwrap(), - RunResultValue::Panic(vec![ - Felt252::from(42), - Felt252::from(100), - Felt252::from(1000) - ]) + RunResultValue::Panic(vec![Felt::from(42), Felt::from(100), Felt::from(1000)]) ); } @@ -326,7 +319,7 @@ mod tests { builtin_stats: Default::default(), }) .unwrap(), - RunResultValue::Success(vec![Felt252::from(10)]) + RunResultValue::Success(vec![Felt::from(10)]) ); } diff --git a/src/bin/utils/test.rs b/src/bin/utils/test.rs index 44d3ff678..29e7ab5c8 100644 --- a/src/bin/utils/test.rs +++ b/src/bin/utils/test.rs @@ -3,11 +3,11 @@ use anyhow::Context; use cairo_lang_runner::RunResultValue; use cairo_lang_sierra::program::Program; use cairo_lang_sierra::{extensions::gas::CostTokenType, ids::FunctionId}; -use cairo_lang_test_plugin::TestCompilation; use cairo_lang_test_plugin::{ test_config::{PanicExpectation, TestExpectation}, TestConfig, }; +use cairo_lang_test_plugin::{TestCompilation, TestCompilationMetadata}; use cairo_lang_utils::casts::IntoOrPanic; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use cairo_native::starknet_stub::StubSyscallHandler; @@ -70,8 +70,9 @@ pub fn filter_test_cases( ignored: bool, filter: String, ) -> (TestCompilation, usize) { - let total_tests_count = compiled.named_tests.len(); + let total_tests_count = compiled.metadata.named_tests.len(); let named_tests = compiled + .metadata .named_tests .into_iter() // Filtering unignored tests in `ignored` mode @@ -87,7 +88,10 @@ pub fn filter_test_cases( .collect_vec(); let filtered_out = total_tests_count - named_tests.len(); let tests = TestCompilation { - named_tests, + metadata: TestCompilationMetadata { + named_tests, + ..compiled.metadata + }, ..compiled }; (tests, filtered_out) diff --git a/src/compiler.rs b/src/compiler.rs index b178ca949..61b399569 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -72,6 +72,7 @@ use cairo_lang_sierra::{ program::{Function, Invocation, Program, Statement, StatementIdx}, program_registry::ProgramRegistry, }; +use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use itertools::Itertools; use melior::{ dialect::{ @@ -355,7 +356,7 @@ fn compile_func( ), ); - let initial_state = edit_state::put_results(HashMap::<_, Value>::new(), { + let initial_state = edit_state::put_results(OrderedHashMap::<_, Value>::default(), { let mut values = Vec::new(); let mut count = 0; @@ -428,7 +429,7 @@ fn compile_func( tracing::trace!("Implementing the statement {statement_idx}'s landing block."); state = edit_state::put_results( - HashMap::default(), + OrderedHashMap::default(), state .keys() .sorted_by_key(|x| x.id) @@ -849,7 +850,7 @@ fn generate_function_structure<'c, 'a>( sierra_stmt_start_offset: usize, ) -> Result<(BlockRef<'c, 'a>, BlockStorage<'c, 'a>), Error> { let initial_state = edit_state::put_results::( - HashMap::new(), + OrderedHashMap::default(), function .params .iter() @@ -936,7 +937,10 @@ fn generate_function_structure<'c, 'a>( Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert((state.clone(), 0)), }; - assert_eq!(prev_state, &state, "Branch target states do not match."); + assert!( + prev_state.eq_unordered(&state), + "Branch target states do not match." + ); *pred_count += 1; Ok(state) @@ -1126,7 +1130,7 @@ fn generate_branching_targets<'ctx, 'this, 'a>( statements: &'this [Statement], statement_idx: StatementIdx, invocation: &'this Invocation, - state: &HashMap>, + state: &OrderedHashMap>, ) -> Vec<(&'this Block<'ctx>, Vec>)> where 'this: 'ctx, diff --git a/src/context.rs b/src/context.rs index 4bff5fb19..dcf5f24d9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -186,7 +186,7 @@ impl NativeContext { std::fs::write( "dump-prepass-debug-pretty.mlir", module.as_operation().to_string_with_flags( - OperationPrintingFlags::new().enable_debug_info(true, true), + OperationPrintingFlags::new().enable_debug_info(true, false), )?, ) .expect("failed to writedump-prepass-debug-pretty.mlir"); @@ -206,7 +206,7 @@ impl NativeContext { std::fs::write( "dump-debug-pretty.mlir", module.as_operation().to_string_with_flags( - OperationPrintingFlags::new().enable_debug_info(true, true), + OperationPrintingFlags::new().enable_debug_info(true, false), )?, ) .expect("failed to write dump-debug-pretty.mlir"); diff --git a/src/debug.rs b/src/debug.rs index 488bebcf3..93c0555b4 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,9 +1,11 @@ use cairo_lang_sierra::extensions::{ array::ArrayConcreteLibfunc, boolean::BoolConcreteLibfunc, + bounded_int::BoundedIntConcreteLibfunc, boxing::BoxConcreteLibfunc, bytes31::Bytes31ConcreteLibfunc, casts::CastConcreteLibfunc, + circuit::CircuitConcreteLibfunc, const_type::ConstConcreteLibfunc, core::CoreConcreteLibfunc, coupon::CouponConcreteLibfunc, @@ -54,6 +56,9 @@ pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str { ArrayConcreteLibfunc::Len(_) => "array_len", ArrayConcreteLibfunc::SnapshotPopFront(_) => "array_snapshot_pop_front", ArrayConcreteLibfunc::SnapshotPopBack(_) => "array_snapshot_pop_back", + ArrayConcreteLibfunc::TupleFromSpan(_) => "array_tuple_from_span", + ArrayConcreteLibfunc::SnapshotMultiPopFront(_) => "array_snapshot_multi_pop_front", + ArrayConcreteLibfunc::SnapshotMultiPopBack(_) => "array_snapshot_multi_pop_back", }, CoreConcreteLibfunc::BranchAlign(_) => "branch_align", CoreConcreteLibfunc::Bool(value) => match value { @@ -363,6 +368,9 @@ pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str { Secp256OpConcreteLibfunc::GetXy(_) => "secp256r1_get_xy", }, }, + StarkNetConcreteLibfunc::Sha256ProcessBlock(_) => "sha256_process_block", + StarkNetConcreteLibfunc::Sha256StateHandleInit(_) => "sha256_state_handle_init", + StarkNetConcreteLibfunc::Sha256StateHandleDigest(_) => "sha256_state_handle_digest", }, CoreConcreteLibfunc::Debug(value) => match value { DebugConcreteLibfunc::Print(_) => "debug_print", @@ -373,5 +381,31 @@ pub fn libfunc_to_name(value: &CoreConcreteLibfunc) -> &'static str { Bytes31ConcreteLibfunc::ToFelt252(_) => "bytes31_to_felt252", Bytes31ConcreteLibfunc::TryFromFelt252(_) => "bytes31_try_from_felt252", }, + CoreConcreteLibfunc::Circuit(selector) => match selector { + CircuitConcreteLibfunc::AddInput(_) => "circuit_add_input", + CircuitConcreteLibfunc::Eval(_) => "circuit_eval", + CircuitConcreteLibfunc::GetDescriptor(_) => "circuit_get_descriptor", + CircuitConcreteLibfunc::InitCircuitData(_) => "circuit_init_circuit_data", + CircuitConcreteLibfunc::GetOutput(_) => "circuit_get_output", + CircuitConcreteLibfunc::TryIntoCircuitModulus(_) => "circuit_try_into_circuit_modulus", + CircuitConcreteLibfunc::FailureGuaranteeVerify(_) => "circuit_failure_guarantee_verify", + CircuitConcreteLibfunc::IntoU96Guarantee(_) => "circuit_into_u96_guarantee", + CircuitConcreteLibfunc::U96GuaranteeVerify(_) => "circuit_u96_guarantee_verify", + CircuitConcreteLibfunc::U96LimbsLessThanGuaranteeVerify(_) => { + "circuit_u96_limbs_less_than_guarantee_verify" + } + CircuitConcreteLibfunc::U96SingleLimbLessThanGuaranteeVerify(_) => { + "circuit_u96_single_limb_less_than_guarantee_verify" + } + }, + CoreConcreteLibfunc::BoundedInt(selector) => match selector { + BoundedIntConcreteLibfunc::Add(_) => "bounded_int_add", + BoundedIntConcreteLibfunc::Sub(_) => "bounded_int_sub", + BoundedIntConcreteLibfunc::Mul(_) => "bounded_int_mul", + BoundedIntConcreteLibfunc::DivRem(_) => "bounded_int_div_rem", + BoundedIntConcreteLibfunc::Constrain(_) => "bounded_int_constrain", + BoundedIntConcreteLibfunc::IsZero(_) => "bounded_int_is_zero", + BoundedIntConcreteLibfunc::WrapNonZero(_) => "bounded_int_wrap_non_zero", + }, } } diff --git a/src/error.rs b/src/error.rs index f4d3ecea4..c8130108f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,7 +43,7 @@ pub enum Error { MissingMetadata, #[error(transparent)] - SierraAssert(SierraAssertError), + SierraAssert(#[from] SierraAssertError), #[error(transparent)] Compiler(#[from] CompilerError), @@ -78,6 +78,12 @@ pub enum SierraAssertError { Cast, #[error("range should always intersect, from {:?} to {:?}", ranges.0, ranges.1)] Range { ranges: Box<(Range, Range)> }, + #[error("type {:?} should never be initialized", .0)] + BadTypeInit(ConcreteTypeId), + #[error("expected type information was missing")] + BadTypeInfo, + #[error("circuit cannot be evaluated")] + ImpossibleCircuit, } #[derive(Error, Debug)] diff --git a/src/executor.rs b/src/executor.rs index e91432cd0..4f221a6ab 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -10,19 +10,24 @@ use crate::{ execution_result::{BuiltinStats, ContractExecutionResult, ExecutionResult}, starknet::{handler::StarknetSyscallHandlerCallbacks, StarknetSyscallHandler}, types::TypeBuilder, + utils::RangeExt, values::JitValue, }; use bumpalo::Bump; use cairo_lang_sierra::{ extensions::{ + circuit::CircuitTypeConcrete, core::{CoreLibfunc, CoreType, CoreTypeConcrete}, starknet::StarkNetTypeConcrete, + ConcreteType, }, ids::{ConcreteTypeId, FunctionId}, program::FunctionSignature, program_registry::ProgramRegistry, }; use libc::c_void; +use num_bigint::BigInt; +use num_traits::One; use starknet_types_core::felt::Felt; use std::{ alloc::Layout, @@ -320,6 +325,12 @@ fn invoke_dynamic( CoreTypeConcrete::Pedersen(_) => builtin_stats.pedersen = value, CoreTypeConcrete::Poseidon(_) => builtin_stats.poseidon = value, CoreTypeConcrete::SegmentArena(_) => builtin_stats.segment_arena = value, + // todo: add RangeCheck96 to builtin_stats? + CoreTypeConcrete::RangeCheck96(_) => (), + // todo: add AddMod to builtin_stats? + CoreTypeConcrete::Circuit(CircuitTypeConcrete::AddMod(_)) => (), + // todo: add MulMod to builtin_stats? + CoreTypeConcrete::Circuit(CircuitTypeConcrete::MulMod(_)) => (), _ => unreachable!("{type_id:?}"), } } @@ -363,6 +374,7 @@ fn parse_result( #[cfg(target_arch = "aarch64")] mut ret_registers: [u64; 4], ) -> Result { let type_info = registry.get_type(type_id).unwrap(); + let debug_name = type_info.info().long_id.to_string(); // Align the pointer to the actual return value. if let Some(return_ptr) = &mut return_ptr { @@ -430,6 +442,24 @@ fn parse_result( })) } }, + CoreTypeConcrete::BoundedInt(info) => match return_ptr { + Some(return_ptr) => Ok(JitValue::from_jit(return_ptr, type_id, registry)), + None => { + let mut data = if info.range.offset_bit_width() <= 64 { + BigInt::from(ret_registers[0]) + } else { + BigInt::from(((ret_registers[1] as u128) << 64) | ret_registers[0] as u128) + }; + + data &= (BigInt::one() << info.range.offset_bit_width()) - BigInt::one(); + data += &info.range.lower; + + Ok(JitValue::BoundedInt { + value: data.into(), + range: info.range.clone(), + }) + } + }, CoreTypeConcrete::Uint8(_) => match return_ptr { Some(return_ptr) => Ok(JitValue::Uint8(unsafe { *return_ptr.cast().as_ref() })), None => Ok(JitValue::Uint8(ret_registers[0] as u8)), @@ -551,14 +581,14 @@ fn parse_result( Ok(JitValue::Enum { tag, value, - debug_name: type_id.debug_name.as_deref().map(ToString::to_string), + debug_name: Some(debug_name), }) } CoreTypeConcrete::Struct(info) => { if info.members.is_empty() { Ok(JitValue::Struct { fields: Vec::new(), - debug_name: type_id.debug_name.as_deref().map(ToString::to_string), + debug_name: Some(debug_name), }) } else { Ok(JitValue::from_jit(return_ptr.unwrap(), type_id, registry)) @@ -591,10 +621,11 @@ fn parse_result( CoreTypeConcrete::Felt252DictEntry(_) | CoreTypeConcrete::Span(_) - | CoreTypeConcrete::BoundedInt(_) | CoreTypeConcrete::Uninitialized(_) | CoreTypeConcrete::Coupon(_) | CoreTypeConcrete::StarkNet(_) - | CoreTypeConcrete::Uint128MulGuarantee(_) => todo!(), + | CoreTypeConcrete::Uint128MulGuarantee(_) + | CoreTypeConcrete::Circuit(_) + | CoreTypeConcrete::RangeCheck96(_) => todo!(), } } diff --git a/src/libfuncs.rs b/src/libfuncs.rs index 099aaed9d..7fe0a8d69 100644 --- a/src/libfuncs.rs +++ b/src/libfuncs.rs @@ -15,16 +15,19 @@ use melior::{ ir::{Block, BlockRef, Location, Module, Operation, Region, Value, ValueLike}, Context, }; +use num_bigint::BigInt; use std::{borrow::Cow, cell::Cell, error::Error, ops::Deref}; pub mod ap_tracking; pub mod array; pub mod bitwise; pub mod r#bool; +pub mod bounded_int; pub mod r#box; pub mod branch_align; pub mod bytes31; pub mod cast; +pub mod circuit; pub mod r#const; pub mod coupon; pub mod debug; @@ -221,6 +224,12 @@ impl LibfuncBuilder for CoreConcreteLibfunc { Self::CouponCall(info) => self::function_call::build( context, registry, entry, location, helper, metadata, info, ), + Self::Circuit(info) => { + self::circuit::build(context, registry, entry, location, helper, metadata, info) + } + Self::BoundedInt(info) => { + self::bounded_int::build(context, registry, entry, location, helper, metadata, info) + } } } @@ -501,10 +510,20 @@ pub fn increment_builtin_counter<'ctx: 'a, 'a>( block: &'ctx Block<'ctx>, location: Location<'ctx>, value: Value<'ctx, '_>, +) -> crate::error::Result> { + increment_builtin_counter_by(context, block, location, value, 1) +} + +pub fn increment_builtin_counter_by<'ctx: 'a, 'a>( + context: &'ctx Context, + block: &'ctx Block<'ctx>, + location: Location<'ctx>, + value: Value<'ctx, '_>, + amount: impl Into, ) -> crate::error::Result> { block.append_op_result(arith::addi( value, - block.const_int(context, location, 1, 64)?, + block.const_int(context, location, amount, 64)?, location, )) } diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index baa32a522..c28c6ff0f 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -3,6 +3,8 @@ // TODO: A future possible improvement would be to put the array behind a double pointer and a // reference counter, to avoid unnecessary clones. +use std::ops::Deref; + use super::LibfuncHelper; use crate::{ block_ext::BlockExt, @@ -13,7 +15,7 @@ use crate::{ }; use cairo_lang_sierra::{ extensions::{ - array::ArrayConcreteLibfunc, + array::{ArrayConcreteLibfunc, ConcreteMultiPopLibfunc}, core::{CoreLibfunc, CoreType}, lib_func::{SignatureAndTypeConcreteLibfunc, SignatureOnlyConcreteLibfunc}, ConcreteLibfunc, @@ -25,12 +27,12 @@ use melior::{ arith::{self, CmpiPredicate}, cf, llvm::{self, r#type::pointer}, - ods, + ods, scf, }, ir::{ attribute::{DenseI32ArrayAttribute, IntegerAttribute}, r#type::IntegerType, - Block, Location, Value, ValueLike, + Block, Location, Region, Value, ValueLike, }, Context, }; @@ -76,6 +78,15 @@ pub fn build<'ctx, 'this>( ArrayConcreteLibfunc::SpanFromTuple(info) => { build_span_from_tuple(context, registry, entry, location, helper, metadata, info) } + ArrayConcreteLibfunc::TupleFromSpan(info) => { + build_tuple_from_span(context, registry, entry, location, helper, metadata, info) + } + ArrayConcreteLibfunc::SnapshotMultiPopFront(info) => build_snapshot_multi_pop_front( + context, registry, entry, location, helper, metadata, info, + ), + ArrayConcreteLibfunc::SnapshotMultiPopBack(info) => build_snapshot_multi_pop_back( + context, registry, entry, location, helper, metadata, info, + ), } } @@ -715,6 +726,258 @@ pub fn build_snapshot_pop_back<'ctx, 'this>( Ok(()) } +pub fn build_snapshot_multi_pop_front<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &ConcreteMultiPopLibfunc, +) -> Result<()> { + if metadata.get::().is_none() { + metadata.insert(ReallocBindingsMeta::new(context, helper)); + } + + let range_check = entry.argument(0)?.into(); + + // Get type information + + let array_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.param_signatures()[1].ty, + )?; + + let popped_cty = registry.get_type(&info.popped_ty)?; + let popped_size = popped_cty.layout(registry)?.size(); + let popped_size_value = entry.const_int(context, location, popped_size, 64)?; + + let popped_ctys = popped_cty + .fields() + .expect("popped type should be a tuple (ergo, has fields)"); + let popped_len = popped_ctys.len(); + + let array_ptr_ty = crate::ffi::get_struct_field_type_at(&array_ty, 0); + let array_start_ty = crate::ffi::get_struct_field_type_at(&array_ty, 1); + let array_end_ty = crate::ffi::get_struct_field_type_at(&array_ty, 2); + + // Get array information + + let array = entry.argument(1)?.into(); + let array_ptr = entry.extract_value(context, location, array, array_ptr_ty, 0)?; + let array_start = entry.extract_value(context, location, array, array_start_ty, 1)?; + let array_end = entry.extract_value(context, location, array, array_end_ty, 2)?; + + // Check if operation is valid: + // if array.end - array.start < popped_len { + // return + // } + + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + let popped_len_value = entry.const_int(context, location, popped_len, 32)?; + let is_valid = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Uge, + array_len, + popped_len_value, + location, + ))?; + + let valid_block = helper.append_block(Block::new(&[])); + let invalid_block = helper.append_block(Block::new(&[])); + + entry.append_operation(cf::cond_br( + context, + is_valid, + valid_block, + invalid_block, + &[], + &[], + location, + )); + + { + // Get pointer to first element to pop + + let popped_ptr = { + let single_popped_ty = + registry.build_type(context, helper, registry, metadata, &popped_ctys[0])?; + + valid_block.append_op_result(llvm::get_element_ptr_dynamic( + context, + array_ptr, + &[array_start], + single_popped_ty, + llvm::r#type::pointer(context, 0), + location, + ))? + }; + + // Allocate memory for return array + + let return_ptr = { + let null_ptr = valid_block.append_op_result( + ods::llvm::mlir_zero(context, pointer(context, 0), location).into(), + )?; + valid_block.append_op_result(ReallocBindingsMeta::realloc( + context, + null_ptr, + popped_size_value, + location, + ))? + }; + + valid_block.memcpy(context, location, popped_ptr, return_ptr, popped_size_value); + + // Update array start (removing popped elements) + + let array = { + let new_array_start = valid_block.append_op_result(arith::addi( + array_start, + popped_len_value, + location, + ))?; + + valid_block.insert_value(context, location, array, new_array_start, 1)? + }; + + valid_block.append_operation(helper.br(0, &[range_check, array, return_ptr], location)); + } + + invalid_block.append_operation(helper.br(1, &[range_check, array], location)); + + Ok(()) +} + +pub fn build_snapshot_multi_pop_back<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &ConcreteMultiPopLibfunc, +) -> Result<()> { + if metadata.get::().is_none() { + metadata.insert(ReallocBindingsMeta::new(context, helper)); + } + + let range_check = entry.argument(0)?.into(); + + // Get type information + + let array_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.param_signatures()[1].ty, + )?; + + let popped_cty = registry.get_type(&info.popped_ty)?; + let popped_size = popped_cty.layout(registry)?.size(); + let popped_size_value = entry.const_int(context, location, popped_size, 64)?; + + let popped_ctys = popped_cty + .fields() + .expect("popped type should be a tuple (ergo, has fields)"); + let popped_len = popped_ctys.len(); + + let array_ptr_ty = crate::ffi::get_struct_field_type_at(&array_ty, 0); + let array_start_ty = crate::ffi::get_struct_field_type_at(&array_ty, 1); + let array_end_ty = crate::ffi::get_struct_field_type_at(&array_ty, 2); + + // Get array information + + let array = entry.argument(1)?.into(); + let array_ptr = entry.extract_value(context, location, array, array_ptr_ty, 0)?; + let array_start = entry.extract_value(context, location, array, array_start_ty, 1)?; + let array_end = entry.extract_value(context, location, array, array_end_ty, 2)?; + + // Check if operation is valid: + // if array.end - array.start < popped_len { + // return + // } + + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + let popped_len_value = entry.const_int(context, location, popped_len, 32)?; + let is_valid = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Uge, + array_len, + popped_len_value, + location, + ))?; + + let valid_block = helper.append_block(Block::new(&[])); + let invalid_block = helper.append_block(Block::new(&[])); + + entry.append_operation(cf::cond_br( + context, + is_valid, + valid_block, + invalid_block, + &[], + &[], + location, + )); + + { + // Get pointer to first element to pop + + let popped_ptr = { + let single_popped_ty = + registry.build_type(context, helper, registry, metadata, &popped_ctys[0])?; + + let popped_start = + valid_block.append_op_result(arith::subi(array_end, popped_len_value, location))?; + + valid_block.append_op_result(llvm::get_element_ptr_dynamic( + context, + array_ptr, + &[popped_start], + single_popped_ty, + llvm::r#type::pointer(context, 0), + location, + ))? + }; + + // Allocate memory for return array + + let return_ptr = { + let null_ptr = valid_block.append_op_result( + ods::llvm::mlir_zero(context, pointer(context, 0), location).into(), + )?; + valid_block.append_op_result(ReallocBindingsMeta::realloc( + context, + null_ptr, + popped_size_value, + location, + ))? + }; + + valid_block.memcpy(context, location, popped_ptr, return_ptr, popped_size_value); + + // Update array end (removing popped elements) + + let array = { + let new_array_end = + valid_block.append_op_result(arith::subi(array_end, popped_len_value, location))?; + + valid_block.insert_value(context, location, array, new_array_end, 2)? + }; + + valid_block.append_operation(helper.br(0, &[range_check, array, return_ptr], location)); + } + + invalid_block.append_operation(helper.br(1, &[range_check, array], location)); + + Ok(()) +} + /// Generate MLIR operations for the `array_slice` libfunc. pub fn build_slice<'ctx, 'this>( context: &'ctx Context, @@ -961,6 +1224,178 @@ fn assert_nonnull<'ctx, 'this>( Ok(()) } +pub fn build_tuple_from_span<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + // Libfunc Signature: + // + // (Snapshot>) -> Box> + + if metadata.get::().is_none() { + metadata.insert(ReallocBindingsMeta::new(context, helper)); + } + + // Get type information + + let elem_core_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; + let elem_layout = elem_core_ty.layout(registry)?; + let elem_stride = elem_layout.pad_to_align().size(); + let tuple_len = registry + .get_type(&info.ty)? + .fields() + .expect("should be a struct (ergo, has fields)") + .len(); + + let u32_ty = IntegerType::new(context, 32).into(); + + // Get array information + + let array_value = entry.argument(0)?.into(); + let array_ptr = entry.extract_value(context, location, array_value, pointer(context, 0), 0)?; + let array_start = entry.extract_value(context, location, array_value, u32_ty, 1)?; + let array_end = entry.extract_value(context, location, array_value, u32_ty, 2)?; + let array_capacity = entry.extract_value(context, location, array_value, u32_ty, 3)?; + + // Check if conversion is valid + // + // if array.end - array.start != tuple_len { + // return err; + // } + + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + let tuple_len_value = entry.const_int(context, location, tuple_len, 32)?; + let array_len_matches = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Eq, + array_len, + tuple_len_value, + location, + ))?; + + let block_ok = helper.append_block(Block::new(&[])); + let block_err = helper.append_block(Block::new(&[])); + entry.append_operation(cf::cond_br( + context, + array_len_matches, + block_ok, + block_err, + &[], + &[], + location, + )); + + // Check if pointer can be passed through, that is + // if array.start == 0 && array.capacity == tuple_len + + let is_pointer_passthrough = { + let k0 = block_ok.const_int(context, location, 0, 32)?; + let array_since_is_zero = block_ok.append_op_result(arith::cmpi( + context, + CmpiPredicate::Eq, + array_start, + k0, + location, + ))?; + let array_cap_matches = block_ok.append_op_result(arith::cmpi( + context, + CmpiPredicate::Eq, + array_capacity, + tuple_len_value, + location, + ))?; + + block_ok.append_op_result(arith::andi( + array_since_is_zero, + array_cap_matches, + location, + ))? + }; + + let box_ptr = block_ok.append_op_result(scf::r#if( + is_pointer_passthrough, + &[llvm::r#type::pointer(context, 0)], + { + let region = Region::new(); + let block = region.append_block(Block::new(&[])); + + // If can be passed through, just return the array ptr + + block.append_operation(scf::r#yield(&[array_ptr], location)); + + region + }, + { + let region = Region::new(); + let block = region.append_block(Block::new(&[])); + + // Otherwise, alloc memory for the returned tuple and clone it + + let tuple_len_value = block.const_int(context, location, tuple_len, 64)?; + let elem_stride_value = block.const_int(context, location, elem_stride, 64)?; + let tuple_len_bytes = block.append_op_result(arith::muli( + tuple_len_value, + elem_stride_value, + location, + ))?; + + let tuple_ptr = { + let null_ptr = block + .append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; + let tuple_ptr = block.append_op_result(ReallocBindingsMeta::realloc( + context, + null_ptr, + tuple_len_bytes, + location, + ))?; + + assert_nonnull( + context, + block.deref(), + location, + tuple_ptr, + "realloc returned null", + )?; + + tuple_ptr + }; + + let array_start = block.append_op_result(arith::extui( + array_start, + IntegerType::new(context, 64).into(), + location, + ))?; + let array_start_offset = + block.append_op_result(arith::muli(elem_stride_value, array_start, location))?; + + let src_ptr = block.append_op_result(llvm::get_element_ptr_dynamic( + context, + array_ptr, + &[array_start_offset], + IntegerType::new(context, 8).into(), + llvm::r#type::pointer(context, 0), + location, + ))?; + block.memcpy(context, location, src_ptr, tuple_ptr, tuple_len_bytes); + + block.append_operation(scf::r#yield(&[tuple_ptr], location)); + + region + }, + location, + ))?; + + block_ok.append_operation(helper.br(0, &[box_ptr], location)); + block_err.append_operation(helper.br(1, &[], location)); + + Ok(()) +} + #[cfg(test)] mod test { use crate::{ @@ -1663,4 +2098,251 @@ mod test { JitValue::Array(vec![1u64.into(), 2u64.into()]), ); } + + #[test] + fn tuple_from_span() { + let program = load_cairo! { + use core::array::{tuple_from_span, FixedSizedArrayInfoImpl}; + + fn run_test(x: Array) -> [felt252; 3] { + (*tuple_from_span::<[felt252; 3], FixedSizedArrayInfoImpl>(@x).unwrap()).unbox() + } + }; + + assert_eq!( + run_program( + &program, + "run_test", + &[JitValue::Array(vec![ + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + JitValue::Felt252(3.into()), + ])], + ) + .return_value, + JitValue::Enum { + tag: 0, + value: Box::new(JitValue::Struct { + fields: vec![JitValue::Struct { + fields: vec![ + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + JitValue::Felt252(3.into()), + ], + debug_name: None + }], + debug_name: None + }), + debug_name: None + } + ); + } + + #[test] + fn tuple_from_span_failed() { + let program = load_cairo! { + use core::array::{tuple_from_span, FixedSizedArrayInfoImpl}; + + fn run_test(x: Array) -> Option<@Box<[core::felt252; 3]>> { + tuple_from_span::<[felt252; 3], FixedSizedArrayInfoImpl>(@x) + } + }; + + assert_eq!( + run_program( + &program, + "run_test", + &[JitValue::Array(vec![ + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + ])], + ) + .return_value, + jit_enum!(1, jit_struct!()) + ); + } + + #[test] + fn snapshot_multi_pop_front() { + let program = load_cairo!( + use array::ArrayTrait; + + fn run_test() -> (Span, @Box<[felt252; 3]>) { + let mut numbers = array![1, 2, 3, 4, 5, 6].span(); + let popped = numbers.multi_pop_front::<3>().unwrap(); + + (numbers, popped) + } + ); + let result = run_program(&program, "run_test", &[]).return_value; + + assert_eq!( + result, + // Panic result + jit_enum!( + 0, + jit_struct!( + // Tuple + jit_struct!( + // Span of original array + jit_struct!(JitValue::Array(vec![ + JitValue::Felt252(4.into()), + JitValue::Felt252(5.into()), + JitValue::Felt252(6.into()), + ])), + // Box of fixed array + jit_struct!( + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + JitValue::Felt252(3.into()) + ), + ) + ) + ) + ); + } + + #[test] + fn snapshot_failed_multi_pop_front() { + let program = load_cairo!( + use array::ArrayTrait; + + fn run_test() -> Span { + let mut numbers = array![1, 2].span(); + + // should fail (return none) + assert!(numbers.multi_pop_front::<3>().is_none()); + + numbers + } + ); + + let result = run_program(&program, "run_test", &[]).return_value; + + assert_eq!( + result, + // Panic result + jit_enum!( + 0, + jit_struct!( + // Span of original array + jit_struct!(JitValue::Array(vec![ + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + ]),) + ) + ) + ); + } + + #[test] + fn snapshot_multi_pop_back() { + let program = load_cairo!( + use array::ArrayTrait; + + fn run_test() -> (Span, @Box<[felt252; 3]>) { + let mut numbers = array![1, 2, 3, 4, 5, 6].span(); + let popped = numbers.multi_pop_back::<3>().unwrap(); + + (numbers, popped) + } + ); + let result = run_program(&program, "run_test", &[]).return_value; + + assert_eq!( + result, + // Panic result + jit_enum!( + 0, + jit_struct!( + // Tuple + jit_struct!( + // Span of original array + jit_struct!(JitValue::Array(vec![ + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + JitValue::Felt252(3.into()), + ])), + // Box of fixed array + jit_struct!( + JitValue::Felt252(4.into()), + JitValue::Felt252(5.into()), + JitValue::Felt252(6.into()) + ), + ) + ) + ) + ); + } + + #[test] + fn snapshot_failed_multi_pop_back() { + let program = load_cairo!( + use array::ArrayTrait; + + fn run_test() -> Span { + let mut numbers = array![1, 2].span(); + + // should fail (return none) + assert!(numbers.multi_pop_back::<3>().is_none()); + + numbers + } + ); + + let result = run_program(&program, "run_test", &[]).return_value; + + assert_eq!( + result, + // Panic result + jit_enum!( + 0, + jit_struct!( + // Span of original array + jit_struct!(JitValue::Array(vec![ + JitValue::Felt252(1.into()), + JitValue::Felt252(2.into()), + ]),) + ) + ) + ); + } + + #[test] + fn snapshot_multi_pop_back_front() { + let program = load_cairo!( + use array::ArrayTrait; + + fn run_test() -> (Span, @Box<[felt252; 2]>, @Box<[felt252; 2]>) { + let mut numbers = array![1, 2, 3, 4, 5, 6].span(); + let popped_front = numbers.multi_pop_front::<2>().unwrap(); + let popped_back = numbers.multi_pop_back::<2>().unwrap(); + + (numbers, popped_front, popped_back) + } + ); + let result = run_program(&program, "run_test", &[]).return_value; + + assert_eq!( + result, + // Panic result + jit_enum!( + 0, + jit_struct!( + // Tuple + jit_struct!( + // Span of original array + jit_struct!(JitValue::Array(vec![ + JitValue::Felt252(3.into()), + JitValue::Felt252(4.into()), + ])), + // Box of fixed array + jit_struct!(JitValue::Felt252(1.into()), JitValue::Felt252(2.into()),), + // Box of fixed array + jit_struct!(JitValue::Felt252(5.into()), JitValue::Felt252(6.into())), + ) + ) + ) + ); + } } diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs new file mode 100644 index 000000000..68b30d7d3 --- /dev/null +++ b/src/libfuncs/bounded_int.rs @@ -0,0 +1,739 @@ +//! # Bounded int libfuncs + +use super::LibfuncHelper; +use crate::{ + block_ext::BlockExt, error::Result, metadata::MetadataStorage, types::TypeBuilder, + utils::RangeExt, +}; +use cairo_lang_sierra::{ + extensions::{ + bounded_int::{ + BoundedIntConcreteLibfunc, BoundedIntConstrainConcreteLibfunc, + BoundedIntDivRemConcreteLibfunc, + }, + core::{CoreLibfunc, CoreType}, + lib_func::SignatureOnlyConcreteLibfunc, + utils::Range, + ConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use melior::{ + dialect::{ + arith::{self, CmpiPredicate}, + cf, + }, + ir::{r#type::IntegerType, Block, Location, Value, ValueLike}, + Context, +}; +use num_bigint::{BigInt, Sign}; + +/// Select and call the correct libfunc builder function from the selector. +pub fn build<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + selector: &BoundedIntConcreteLibfunc, +) -> Result<()> { + match selector { + BoundedIntConcreteLibfunc::Add(info) => { + build_add(context, registry, entry, location, helper, metadata, info) + } + BoundedIntConcreteLibfunc::Sub(info) => { + build_sub(context, registry, entry, location, helper, metadata, info) + } + BoundedIntConcreteLibfunc::Mul(info) => { + build_mul(context, registry, entry, location, helper, metadata, info) + } + BoundedIntConcreteLibfunc::DivRem(info) => { + build_divrem(context, registry, entry, location, helper, metadata, info) + } + BoundedIntConcreteLibfunc::Constrain(info) => { + build_constrain(context, registry, entry, location, helper, metadata, info) + } + BoundedIntConcreteLibfunc::IsZero(info) => { + build_is_zero(context, registry, entry, location, helper, metadata, info) + } + BoundedIntConcreteLibfunc::WrapNonZero(info) => { + build_wrap_non_zero(context, registry, entry, location, helper, metadata, info) + } + } +} + +/// Generate MLIR operations for the `bounded_int_add` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_add<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let lhs_value = entry.argument(0)?.into(); + let rhs_value = entry.argument(1)?.into(); + + // Extract the ranges for the operands and the result type. + let lhs_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; + let rhs_ty = registry.get_type(&info.signature.param_signatures[1].ty)?; + + let lhs_range = lhs_ty.integer_range(registry).unwrap(); + let rhs_range = rhs_ty.integer_range(registry).unwrap(); + let dst_range = registry + .get_type(&info.signature.branch_signatures[0].vars[0].ty)? + .integer_range(registry) + .unwrap(); + + let lhs_width = if lhs_ty.is_bounded_int(registry) { + lhs_range.offset_bit_width() + } else { + lhs_range.zero_based_bit_width() + }; + let rhs_width = if rhs_ty.is_bounded_int(registry) { + rhs_range.offset_bit_width() + } else { + rhs_range.zero_based_bit_width() + }; + + // Calculate the computation range. + let compute_range = Range { + lower: (&lhs_range.lower) + .min(&rhs_range.lower) + .min(&dst_range.lower) + .clone(), + upper: (&lhs_range.upper) + .max(&rhs_range.upper) + .max(&dst_range.upper) + .clone(), + }; + let compute_ty = IntegerType::new(context, compute_range.offset_bit_width()).into(); + + // Zero-extend operands into the computation range. + assert!(compute_range.offset_bit_width() >= lhs_width); + assert!(compute_range.offset_bit_width() >= rhs_width); + let lhs_value = if compute_range.offset_bit_width() > lhs_width { + if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(lhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(lhs_value, compute_ty, location))? + } + } else { + lhs_value + }; + let rhs_value = if compute_range.offset_bit_width() > rhs_width { + if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(rhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(rhs_value, compute_ty, location))? + } + } else { + rhs_value + }; + + // Offset the operands so that they are compatible. + let lhs_offset = if lhs_ty.is_bounded_int(registry) { + &lhs_range.lower - &compute_range.lower + } else { + lhs_range.lower.clone() + }; + let lhs_value = if lhs_offset != BigInt::ZERO { + let lhs_offset = entry.const_int_from_type(context, location, lhs_offset, compute_ty)?; + entry.append_op_result(arith::addi(lhs_value, lhs_offset, location))? + } else { + lhs_value + }; + + let rhs_offset = if rhs_ty.is_bounded_int(registry) { + &rhs_range.lower - &compute_range.lower + } else { + rhs_range.lower.clone() + }; + let rhs_value = if rhs_offset != BigInt::ZERO { + let rhs_offset = entry.const_int_from_type(context, location, rhs_offset, compute_ty)?; + entry.append_op_result(arith::addi(rhs_value, rhs_offset, location))? + } else { + rhs_value + }; + + // Compute the operation. + let res_value = entry.append_op_result(arith::addi(lhs_value, rhs_value, location))?; + + // Offset and truncate the result to the output type. + let res_offset = &dst_range.lower - &compute_range.lower; + let res_value = if res_offset != BigInt::ZERO { + let res_offset = entry.const_int_from_type(context, location, res_offset, compute_ty)?; + entry.append_op_result(arith::subi(res_value, res_offset, location))? + } else { + res_value + }; + + let res_value = if dst_range.offset_bit_width() < compute_range.offset_bit_width() { + entry.append_op_result(arith::trunci( + res_value, + IntegerType::new(context, dst_range.offset_bit_width()).into(), + location, + ))? + } else { + res_value + }; + + entry.append_operation(helper.br(0, &[res_value], location)); + Ok(()) +} + +/// Generate MLIR operations for the `bounded_int_sub` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_sub<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let lhs_value = entry.argument(0)?.into(); + let rhs_value = entry.argument(1)?.into(); + + // Extract the ranges for the operands and the result type. + let lhs_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; + let rhs_ty = registry.get_type(&info.signature.param_signatures[1].ty)?; + + let lhs_range = lhs_ty.integer_range(registry).unwrap(); + let rhs_range = rhs_ty.integer_range(registry).unwrap(); + let dst_range = registry + .get_type(&info.signature.branch_signatures[0].vars[0].ty)? + .integer_range(registry) + .unwrap(); + + let lhs_width = if lhs_ty.is_bounded_int(registry) { + lhs_range.offset_bit_width() + } else { + lhs_range.zero_based_bit_width() + }; + let rhs_width = if rhs_ty.is_bounded_int(registry) { + rhs_range.offset_bit_width() + } else { + rhs_range.zero_based_bit_width() + }; + + // Calculate the computation range. + let compute_range = Range { + lower: (&lhs_range.lower) + .min(&rhs_range.lower) + .min(&dst_range.lower) + .clone(), + upper: (&lhs_range.upper) + .max(&rhs_range.upper) + .max(&dst_range.upper) + .clone(), + }; + let compute_ty = IntegerType::new(context, compute_range.offset_bit_width()).into(); + + // Zero-extend operands into the computation range. + assert!(compute_range.offset_bit_width() >= lhs_width); + assert!(compute_range.offset_bit_width() >= rhs_width); + let lhs_value = if compute_range.offset_bit_width() > lhs_width { + if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(lhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(lhs_value, compute_ty, location))? + } + } else { + lhs_value + }; + let rhs_value = if compute_range.offset_bit_width() > rhs_width { + if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(rhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(rhs_value, compute_ty, location))? + } + } else { + rhs_value + }; + + // Offset the operands so that they are compatible. + let lhs_offset = if lhs_ty.is_bounded_int(registry) { + &lhs_range.lower - &compute_range.lower + } else { + lhs_range.lower.clone() + }; + let lhs_value = if lhs_offset != BigInt::ZERO { + let lhs_offset = entry.const_int_from_type(context, location, lhs_offset, compute_ty)?; + entry.append_op_result(arith::addi(lhs_value, lhs_offset, location))? + } else { + lhs_value + }; + + let rhs_offset = if rhs_ty.is_bounded_int(registry) { + &rhs_range.lower - &compute_range.lower + } else { + rhs_range.lower.clone() + }; + let rhs_value = if rhs_offset != BigInt::ZERO { + let rhs_offset = entry.const_int_from_type(context, location, rhs_offset, compute_ty)?; + entry.append_op_result(arith::addi(rhs_value, rhs_offset, location))? + } else { + rhs_value + }; + + // Compute the operation. + let res_value = entry.append_op_result(arith::subi(lhs_value, rhs_value, location))?; + + // Offset and truncate the result to the output type. + let res_offset = dst_range.lower.clone(); + let res_value = if res_offset != BigInt::ZERO { + let res_offset = entry.const_int_from_type(context, location, res_offset, compute_ty)?; + entry.append_op_result(arith::subi(res_value, res_offset, location))? + } else { + res_value + }; + + let res_value = if dst_range.offset_bit_width() < compute_range.offset_bit_width() { + entry.append_op_result(arith::trunci( + res_value, + IntegerType::new(context, dst_range.offset_bit_width()).into(), + location, + ))? + } else { + res_value + }; + + entry.append_operation(helper.br(0, &[res_value], location)); + Ok(()) +} + +/// Generate MLIR operations for the `bounded_int_mul` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_mul<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let lhs_value = entry.argument(0)?.into(); + let rhs_value = entry.argument(1)?.into(); + + // Extract the ranges for the operands and the result type. + let lhs_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; + let rhs_ty = registry.get_type(&info.signature.param_signatures[1].ty)?; + + let lhs_range = lhs_ty.integer_range(registry).unwrap(); + let rhs_range = rhs_ty.integer_range(registry).unwrap(); + let dst_range = registry + .get_type(&info.signature.branch_signatures[0].vars[0].ty)? + .integer_range(registry) + .unwrap(); + + let lhs_width = if lhs_ty.is_bounded_int(registry) { + lhs_range.offset_bit_width() + } else { + lhs_range.zero_based_bit_width() + }; + let rhs_width = if rhs_ty.is_bounded_int(registry) { + rhs_range.offset_bit_width() + } else { + rhs_range.zero_based_bit_width() + }; + + // Calculate the computation range. + let compute_range = Range { + lower: (&lhs_range.lower) + .min(&rhs_range.lower) + .min(&dst_range.lower) + .min(&BigInt::ZERO) + .clone(), + upper: (&lhs_range.upper) + .max(&rhs_range.upper) + .max(&dst_range.upper) + .clone(), + }; + let compute_ty = IntegerType::new(context, compute_range.zero_based_bit_width()).into(); + + // Zero-extend operands into the computation range. + assert!(compute_range.zero_based_bit_width() >= lhs_width); + assert!(compute_range.zero_based_bit_width() >= rhs_width); + let lhs_value = if compute_range.zero_based_bit_width() > lhs_width { + if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(lhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(lhs_value, compute_ty, location))? + } + } else { + lhs_value + }; + let rhs_value = if compute_range.zero_based_bit_width() > rhs_width { + if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(rhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(rhs_value, compute_ty, location))? + } + } else { + rhs_value + }; + + // Offset the operands so that they are compatible with the operation. + let lhs_value = if lhs_ty.is_bounded_int(registry) && lhs_range.lower != BigInt::ZERO { + let lhs_offset = + entry.const_int_from_type(context, location, lhs_range.lower.clone(), compute_ty)?; + entry.append_op_result(arith::addi(lhs_value, lhs_offset, location))? + } else { + lhs_value + }; + let rhs_value = if rhs_ty.is_bounded_int(registry) && rhs_range.lower != BigInt::ZERO { + let rhs_offset = + entry.const_int_from_type(context, location, rhs_range.lower.clone(), compute_ty)?; + entry.append_op_result(arith::addi(rhs_value, rhs_offset, location))? + } else { + rhs_value + }; + + // Compute the operation. + let res_value = entry.append_op_result(arith::muli(lhs_value, rhs_value, location))?; + + // Offset and truncate the result to the output type. + let res_offset = (&dst_range.lower).max(&compute_range.lower).clone(); + let res_value = if res_offset != BigInt::ZERO { + let res_offset = entry.const_int_from_type(context, location, res_offset, compute_ty)?; + entry.append_op_result(arith::subi(res_value, res_offset, location))? + } else { + res_value + }; + + let res_value = if dst_range.offset_bit_width() < compute_range.zero_based_bit_width() { + entry.append_op_result(arith::trunci( + res_value, + IntegerType::new(context, dst_range.offset_bit_width()).into(), + location, + ))? + } else { + res_value + }; + + entry.append_operation(helper.br(0, &[res_value], location)); + Ok(()) +} + +/// Generate MLIR operations for the `bounded_int_divrem` libfunc. +/// Libfunc for dividing two non negative BoundedInts and getting the quotient and remainder. +fn build_divrem<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &BoundedIntDivRemConcreteLibfunc, +) -> Result<()> { + let range_check = + super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + + let lhs_value = entry.argument(1)?.into(); + let rhs_value = entry.argument(2)?.into(); + + // Extract the ranges for the operands and the result type. + let lhs_ty = registry.get_type(&info.param_signatures()[1].ty)?; + let rhs_ty = registry.get_type(&info.param_signatures()[2].ty)?; + + let lhs_range = lhs_ty.integer_range(registry).unwrap(); + let rhs_range = rhs_ty.integer_range(registry).unwrap(); + let div_range = registry + .get_type(&info.branch_signatures()[0].vars[1].ty)? + .integer_range(registry) + .unwrap(); + let rem_range = registry + .get_type(&info.branch_signatures()[0].vars[2].ty)? + .integer_range(registry) + .unwrap(); + + let lhs_width = if lhs_ty.is_bounded_int(registry) { + lhs_range.offset_bit_width() + } else { + lhs_range.zero_based_bit_width() + }; + let rhs_width = if rhs_ty.is_bounded_int(registry) { + rhs_range.offset_bit_width() + } else { + rhs_range.zero_based_bit_width() + }; + + // Calculate the computation range. + let compute_range = Range { + lower: (&lhs_range.lower) + .min(&rhs_range.lower) + .min(&div_range.lower) + .min(&rem_range.lower) + .min(&BigInt::ZERO) + .clone(), + upper: (&lhs_range.upper) + .max(&rhs_range.upper) + .max(&div_range.upper) + .max(&rem_range.upper) + .clone(), + }; + let compute_ty = IntegerType::new(context, compute_range.zero_based_bit_width()).into(); + + // Zero-extend operands into the computation range. + assert!(compute_range.zero_based_bit_width() >= lhs_width); + assert!(compute_range.zero_based_bit_width() >= rhs_width); + let lhs_value = if compute_range.zero_based_bit_width() > lhs_width { + if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(lhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(lhs_value, compute_ty, location))? + } + } else { + lhs_value + }; + let rhs_value = if compute_range.zero_based_bit_width() > rhs_width { + if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extui(rhs_value, compute_ty, location))? + } else { + entry.append_op_result(arith::extsi(rhs_value, compute_ty, location))? + } + } else { + rhs_value + }; + + // Offset the operands so that they are compatible with the operation. + let lhs_value = if lhs_ty.is_bounded_int(registry) && lhs_range.lower != BigInt::ZERO { + let lhs_offset = + entry.const_int_from_type(context, location, lhs_range.lower.clone(), compute_ty)?; + entry.append_op_result(arith::addi(lhs_value, lhs_offset, location))? + } else { + lhs_value + }; + let rhs_value = if rhs_ty.is_bounded_int(registry) && rhs_range.lower != BigInt::ZERO { + let rhs_offset = + entry.const_int_from_type(context, location, rhs_range.lower.clone(), compute_ty)?; + entry.append_op_result(arith::addi(rhs_value, rhs_offset, location))? + } else { + rhs_value + }; + + // Compute the operation. + let div_value = entry.append_op_result(arith::divui(lhs_value, rhs_value, location))?; + let rem_value = entry.append_op_result(arith::remui(lhs_value, rhs_value, location))?; + + // Offset and truncate the result to the output type. + let div_offset = (&div_range.lower).max(&compute_range.lower).clone(); + let rem_offset = (&rem_range.lower).max(&compute_range.lower).clone(); + + let div_value = if div_offset != BigInt::ZERO { + let div_offset = entry.const_int_from_type(context, location, div_offset, compute_ty)?; + entry.append_op_result(arith::subi(div_value, div_offset, location))? + } else { + div_value + }; + let rem_value = if rem_offset != BigInt::ZERO { + let rem_offset = entry.const_int_from_type(context, location, rem_offset, compute_ty)?; + entry.append_op_result(arith::subi(rem_value, rem_offset, location))? + } else { + rem_value + }; + + let div_value = if div_range.offset_bit_width() < compute_range.zero_based_bit_width() { + entry.append_op_result(arith::trunci( + div_value, + IntegerType::new(context, div_range.offset_bit_width()).into(), + location, + ))? + } else { + div_value + }; + let rem_value = if rem_range.offset_bit_width() < compute_range.zero_based_bit_width() { + entry.append_op_result(arith::trunci( + rem_value, + IntegerType::new(context, rem_range.offset_bit_width()).into(), + location, + ))? + } else { + rem_value + }; + + entry.append_operation(helper.br(0, &[range_check, div_value, rem_value], location)); + Ok(()) +} + +/// Generate MLIR operations for the `bounded_int_constrain` libfunc. +fn build_constrain<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &BoundedIntConstrainConcreteLibfunc, +) -> Result<()> { + let range_check = + super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + let src_value: Value = entry.argument(1)?.into(); + + let src_ty = registry.get_type(&info.param_signatures()[1].ty)?; + let src_range = src_ty.integer_range(registry).unwrap(); + + let src_width = if src_ty.is_bounded_int(registry) { + src_range.offset_bit_width() + } else { + src_range.zero_based_bit_width() + }; + + let lower_range = registry + .get_type(&info.branch_signatures()[0].vars[1].ty)? + .integer_range(registry) + .unwrap(); + let upper_range = registry + .get_type(&info.branch_signatures()[1].vars[1].ty)? + .integer_range(registry) + .unwrap(); + + let boundary = + entry.const_int_from_type(context, location, info.boundary.clone(), src_value.r#type())?; + let is_lower = entry.append_op_result(arith::cmpi( + context, + if src_range.lower.sign() == Sign::Minus { + CmpiPredicate::Slt + } else { + CmpiPredicate::Ult + }, + src_value, + boundary, + location, + ))?; + + let lower_block = helper.append_block(Block::new(&[])); + let upper_block = helper.append_block(Block::new(&[])); + entry.append_operation(cf::cond_br( + context, + is_lower, + lower_block, + upper_block, + &[], + &[], + location, + )); + + { + let res_value = if src_range.lower != lower_range.lower { + let lower_offset = &lower_range.lower - &src_range.lower; + let lower_offset = lower_block.const_int_from_type( + context, + location, + lower_offset, + src_value.r#type(), + )?; + lower_block.append_op_result(arith::subi(src_value, lower_offset, location))? + } else { + src_value + }; + + let res_value = if src_width > lower_range.offset_bit_width() { + lower_block.append_op_result(arith::trunci( + res_value, + IntegerType::new(context, lower_range.offset_bit_width()).into(), + location, + ))? + } else { + res_value + }; + + lower_block.append_operation(helper.br(0, &[range_check, res_value], location)); + } + + { + let res_value = if src_range.lower != upper_range.lower { + let upper_offset = &upper_range.lower - &src_range.lower; + let upper_offset = upper_block.const_int_from_type( + context, + location, + upper_offset, + src_value.r#type(), + )?; + upper_block.append_op_result(arith::subi(src_value, upper_offset, location))? + } else { + src_value + }; + + let res_value = if src_width > upper_range.offset_bit_width() { + upper_block.append_op_result(arith::trunci( + res_value, + IntegerType::new(context, upper_range.offset_bit_width()).into(), + location, + ))? + } else { + res_value + }; + + upper_block.append_operation(helper.br(1, &[range_check, res_value], location)); + } + + Ok(()) +} + +/// Generate MLIR operations for the `bounded_int_is_zero` libfunc. +fn build_is_zero<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let src_value: Value = entry.argument(0)?.into(); + + let src_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; + let src_range = src_ty.integer_range(registry).unwrap(); + + assert!( + src_range.lower <= BigInt::ZERO && BigInt::ZERO < src_range.upper, + "value can never be zero" + ); + + let k0 = entry.const_int_from_type(context, location, 0, src_value.r#type())?; + let src_is_zero = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Eq, + src_value, + k0, + location, + ))?; + + entry.append_operation(helper.cond_br( + context, + src_is_zero, + [0, 1], + [&[], &[src_value]], + location, + )); + Ok(()) +} + +/// Generate MLIR operations for the `bounded_int_wrap_non_zero` libfunc. +fn build_wrap_non_zero<'ctx, 'this>( + _context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let src_value = entry.argument(0)?.into(); + + let src_range = registry + .get_type(&info.signature.param_signatures[0].ty)? + .integer_range(registry) + .unwrap(); + assert!(src_range.lower > BigInt::ZERO || BigInt::ZERO >= src_range.upper); + + entry.append_operation(helper.br(0, &[src_value], location)); + Ok(()) +} diff --git a/src/libfuncs/cast.rs b/src/libfuncs/cast.rs index 6594811c4..74fdbb112 100644 --- a/src/libfuncs/cast.rs +++ b/src/libfuncs/cast.rs @@ -1,34 +1,32 @@ //! # Casting libfuncs -use std::ops::Shr; - use super::LibfuncHelper; use crate::{ block_ext::BlockExt, - error::{Error, Result, SierraAssertError}, - metadata::{prime_modulo::PrimeModuloMeta, MetadataStorage}, - types::TypeBuilder, + error::Result, + metadata::MetadataStorage, + types::{ + felt252::{HALF_PRIME, PRIME}, + TypeBuilder, + }, + utils::RangeExt, }; use cairo_lang_sierra::{ extensions::{ casts::{CastConcreteLibfunc, DowncastConcreteLibfunc}, - core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + core::{CoreLibfunc, CoreType}, lib_func::SignatureOnlyConcreteLibfunc, - ConcreteLibfunc, + utils::Range, }, program_registry::ProgramRegistry, }; use melior::{ - dialect::{ - arith::{self, CmpiPredicate}, - cf, - }, - ir::{r#type::IntegerType, Block, Location}, + dialect::arith::{self, CmpiPredicate}, + ir::{r#type::IntegerType, Block, Location, Value, ValueLike}, Context, }; -use num_bigint::{BigInt, ToBigInt}; -use num_traits::Euclid; -use starknet_types_core::felt::Felt; +use num_bigint::{BigInt, Sign}; +use num_traits::One; /// Select and call the correct libfunc builder function from the selector. pub fn build<'ctx, 'this>( @@ -57,200 +55,205 @@ pub fn build_downcast<'ctx, 'this>( entry: &'this Block<'ctx>, location: Location<'ctx>, helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, + _metadata: &mut MetadataStorage, info: &DowncastConcreteLibfunc, ) -> Result<()> { let range_check = super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + let src_value: Value = entry.argument(1)?.into(); - let src_type = registry.get_type(&info.from_ty)?; - let dst_type = registry.get_type(&info.to_ty)?; - let src_width = src_type - .integer_width() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; - let dst_width = dst_type - .integer_width() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; + if info.signature.param_signatures[1].ty == info.signature.branch_signatures[0].vars[1].ty { + let k0 = entry.const_int(context, location, 0, 1)?; + entry.append_operation(helper.cond_br( + context, + k0, + [0, 1], + [&[range_check, src_value], &[range_check]], + location, + )); + return Ok(()); + } - let src_ty = src_type.build(context, helper, registry, metadata, &info.from_ty)?; - let dst_ty = dst_type.build(context, helper, registry, metadata, &info.to_ty)?; + let src_ty = registry.get_type(&info.signature.param_signatures[1].ty)?; + let dst_ty = registry.get_type(&info.signature.branch_signatures[0].vars[1].ty)?; - let location = Location::name( - context, - &format!("downcast<{:?}, {:?}>", src_ty, dst_ty), - location, + let dst_range = dst_ty.integer_range(registry).unwrap(); + let src_range = if src_ty.is_felt252(registry) && dst_range.lower.sign() == Sign::Minus { + if dst_range.upper.sign() != Sign::Plus { + Range { + lower: BigInt::from_biguint(Sign::Minus, PRIME.clone()) + 1, + upper: BigInt::one(), + } + } else { + Range { + lower: -HALF_PRIME.clone(), + upper: HALF_PRIME.clone() + BigInt::one(), + } + } + } else { + src_ty.integer_range(registry).unwrap() + }; + assert!( + dst_range.lower > src_range.lower || dst_range.upper < src_range.upper, + "invalid downcast `{}` into `{}`: target range contains the source range", + info.signature.param_signatures[1].ty, + info.signature.branch_signatures[0].vars[1].ty ); - let src_is_signed = src_type - .is_integer_signed() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; - let dst_is_signed = dst_type - .is_integer_signed() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; - let any_is_signed = src_is_signed | dst_is_signed; - let src_is_felt = matches!( - src_type, - CoreTypeConcrete::Felt252(_) | CoreTypeConcrete::BoundedInt(_) - ); - let dst_is_felt = matches!( - dst_type, - CoreTypeConcrete::Felt252(_) | CoreTypeConcrete::BoundedInt(_) - ); - let src_value: melior::ir::Value = entry.argument(1)?.into(); + let src_width = if src_ty.is_bounded_int(registry) { + src_range.offset_bit_width() + } else { + src_ty + .integer_range(registry) + .unwrap() + .zero_based_bit_width() + }; + let dst_width = if dst_ty.is_bounded_int(registry) { + dst_range.offset_bit_width() + } else { + dst_range.zero_based_bit_width() + }; + + let compute_width = src_range + .zero_based_bit_width() + .max(dst_range.zero_based_bit_width()); - let mut block = entry; + let is_signed = src_range.lower.sign() == Sign::Minus; - let (is_in_range, result) = if info.from_ty == info.to_ty { - // can't cast to the same type - let k0 = block.const_int(context, location, 0, 1)?; - (k0, src_value) + let src_value = if compute_width > src_width { + if is_signed && !src_ty.is_bounded_int(registry) && !src_ty.is_felt252(registry) { + entry.append_op_result(arith::extsi( + src_value, + IntegerType::new(context, compute_width).into(), + location, + ))? + } else { + entry.append_op_result(arith::extui( + src_value, + IntegerType::new(context, compute_width).into(), + location, + ))? + } } else { - // make unsigned felt into signed felt - // felt > half prime = negative - let felt_to_int = src_is_felt && !dst_is_felt; - let src_value = if felt_to_int { - let attr_halfprime_i252 = metadata - .get::>() - .ok_or(Error::MissingMetadata)? - .prime() - .shr(1); - - let half_prime = - block.const_int_from_type(context, location, attr_halfprime_i252, src_ty)?; - - let is_felt_neg = block.append_op_result(arith::cmpi( + src_value + }; + + let src_value = if is_signed && src_ty.is_felt252(registry) { + if src_range.upper.is_one() { + let adj_offset = + entry.const_int_from_type(context, location, PRIME.clone(), src_value.r#type())?; + entry.append_op_result(arith::subi(src_value, adj_offset, location))? + } else { + let adj_offset = entry.const_int_from_type( + context, + location, + HALF_PRIME.clone(), + src_value.r#type(), + )?; + let is_negative = entry.append_op_result(arith::cmpi( context, CmpiPredicate::Ugt, src_value, - half_prime, + adj_offset, location, ))?; - let is_neg_block = helper.append_block(Block::new(&[])); - let is_not_neg_block = helper.append_block(Block::new(&[])); - let final_block = helper.append_block(Block::new(&[(src_ty, location)])); - - block.append_operation(cf::cond_br( - context, - is_felt_neg, - is_neg_block, - is_not_neg_block, - &[], - &[], - location, - )); - - { - let value = metadata - .get::>() - .ok_or(Error::MissingMetadata)? - .prime(); - let prime = is_neg_block.const_int_from_type( - context, - location, - value.to_bigint().unwrap(), - src_ty, - )?; - - let mut src_value_is_neg = - is_neg_block.append_op_result(arith::subi(prime, src_value, location))?; - - let kneg1 = is_neg_block.const_int_from_type(context, location, -1, src_ty)?; - - src_value_is_neg = is_neg_block.append_op_result(arith::muli( - src_value_is_neg, - kneg1, - location, - ))?; - - is_neg_block.append_operation(cf::br(final_block, &[src_value_is_neg], location)); - } - - is_not_neg_block.append_operation(cf::br(final_block, &[src_value], location)); - block = final_block; + let k_prime = + entry.const_int_from_type(context, location, PRIME.clone(), src_value.r#type())?; + let adj_value = entry.append_op_result(arith::subi(src_value, k_prime, location))?; - block.argument(0)?.into() - } else { - src_value - }; - - let result = if src_width > dst_width { - block.append_op_result(arith::trunci(src_value, dst_ty, location))? - } else if src_is_signed { - block.append_op_result(arith::extsi(src_value, dst_ty, location))? - } else { - block.append_op_result(arith::extui(src_value, dst_ty, location))? - }; - - let (compare_value, compare_ty) = if src_width > dst_width { - (src_value, src_ty) - } else { - (result, dst_ty) - }; - - let info_range = info - .to_range - .intersection(&info.from_range) - .ok_or_else(|| { - Error::SierraAssert(SierraAssertError::Range { - ranges: Box::new((info.from_range.clone(), info.to_range.clone())), - }) - })?; - - let mut int_max_value: BigInt = info_range.upper - 1; - - let mut int_min_value = info_range.lower; - - if dst_is_felt { - let prime = &metadata - .get::>() - .ok_or(Error::MissingMetadata)? - .prime() - .to_bigint() - .expect("biguint should be casted to bigint"); - - int_min_value = int_min_value.rem_euclid(prime); - int_max_value = int_max_value.rem_euclid(prime); + entry.append_op_result(arith::select(is_negative, adj_value, src_value, location))? } + } else if src_ty.is_bounded_int(registry) && src_range.lower != BigInt::ZERO { + let dst_offset = entry.const_int_from_type( + context, + location, + src_range.lower.clone(), + src_value.r#type(), + )?; + entry.append_op_result(arith::addi(src_value, dst_offset, location))? + } else { + src_value + }; - let max_value = block.const_int_from_type(context, location, int_max_value, compare_ty)?; - let min_value = block.const_int_from_type(context, location, int_min_value, compare_ty)?; - - let is_in_range_upper = block.append_op_result(arith::cmpi( + let lower_check = if dst_range.lower > src_range.lower { + let dst_lower = entry.const_int_from_type( + context, + location, + dst_range.lower.clone(), + src_value.r#type(), + )?; + Some(entry.append_op_result(arith::cmpi( context, - if any_is_signed { - CmpiPredicate::Sle + if !is_signed { + CmpiPredicate::Uge } else { - CmpiPredicate::Ule + CmpiPredicate::Sge }, - compare_value, - max_value, + src_value, + dst_lower, location, - ))?; - - let is_in_range_lower = block.append_op_result(arith::cmpi( + ))?) + } else { + None + }; + let upper_check = if dst_range.upper < src_range.upper { + let dst_upper = entry.const_int_from_type( context, - if any_is_signed { - CmpiPredicate::Sge + location, + dst_range.upper.clone(), + src_value.r#type(), + )?; + Some(entry.append_op_result(arith::cmpi( + context, + if !is_signed { + CmpiPredicate::Ult } else { - CmpiPredicate::Uge + CmpiPredicate::Slt }, - compare_value, - min_value, + src_value, + dst_upper, location, - ))?; + ))?) + } else { + None + }; - let is_in_range = - block.append_op_result(arith::andi(is_in_range_upper, is_in_range_lower, location))?; + let is_in_bounds = match (lower_check, upper_check) { + (Some(lower_check), Some(upper_check)) => { + entry.append_op_result(arith::andi(lower_check, upper_check, location))? + } + (Some(lower_check), None) => lower_check, + (None, Some(upper_check)) => upper_check, + (None, None) => unreachable!(), + }; - (is_in_range, result) + let dst_value = if dst_ty.is_bounded_int(registry) && dst_range.lower != BigInt::ZERO { + let dst_offset = entry.const_int_from_type( + context, + location, + dst_range.lower.clone(), + src_value.r#type(), + )?; + entry.append_op_result(arith::subi(src_value, dst_offset, location))? + } else { + src_value }; - block.append_operation(helper.cond_br( + let dst_value = if dst_width < compute_width { + entry.append_op_result(arith::trunci( + dst_value, + IntegerType::new(context, dst_width).into(), + location, + ))? + } else { + dst_value + }; + entry.append_operation(helper.cond_br( context, - is_in_range, + is_in_bounds, [0, 1], - [&[range_check, result], &[range_check]], + [&[range_check, dst_value], &[range_check]], location, )); @@ -264,131 +267,110 @@ pub fn build_upcast<'ctx, 'this>( entry: &'this Block<'ctx>, location: Location<'ctx>, helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, + _metadata: &mut MetadataStorage, info: &SignatureOnlyConcreteLibfunc, ) -> Result<()> { - let src_ty = registry.get_type(&info.param_signatures()[0].ty)?; - let dst_ty = registry.get_type(&info.branch_signatures()[0].vars[0].ty)?; - let src_type = src_ty.build( - context, - helper, - registry, - metadata, - &info.param_signatures()[0].ty, - )?; - let dst_type = dst_ty.build( - context, - helper, - registry, - metadata, - &info.branch_signatures()[0].vars[0].ty, - )?; - - let location = Location::name( - context, - &format!("upcast<{:?}, {:?}>", src_type, dst_type), - location, - ); - - let src_width = src_ty - .integer_width() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; - let dst_width = dst_ty - .integer_width() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; - assert!(src_width <= dst_width); - - let is_signed = src_ty - .is_integer_signed() - .ok_or_else(|| Error::SierraAssert(SierraAssertError::Cast))?; - - let is_felt = matches!(dst_ty, CoreTypeConcrete::Felt252(_)); - - let block = entry; - - let result = if src_width == dst_width { - block.argument(0)?.into() - } else if is_signed || is_felt { - if is_felt { - let result = block.append_op_result(arith::extsi( - block.argument(0)?.into(), - IntegerType::new(context, dst_width.try_into()?).into(), - location, - ))?; - - let kzero = block.const_int_from_type(context, location, 0, dst_type)?; - - let is_neg = block.append_op_result(arith::cmpi( - context, - CmpiPredicate::Slt, - result, - kzero, - location, - ))?; + let src_value = entry.argument(0)?.into(); - let is_neg_block = helper.append_block(Block::new(&[])); - let is_not_neg_block = helper.append_block(Block::new(&[])); - let final_block = helper.append_block(Block::new(&[(dst_type, location)])); - - block.append_operation(cf::cond_br( - context, - is_neg, - is_neg_block, - is_not_neg_block, - &[], - &[], - location, - )); - - { - let result = is_not_neg_block.append_op_result(arith::extui( - entry.argument(0)?.into(), - IntegerType::new(context, dst_width.try_into()?).into(), - location, - ))?; + if info.signature.param_signatures[0].ty == info.signature.branch_signatures[0].vars[0].ty { + entry.append_operation(helper.br(0, &[src_value], location)); + return Ok(()); + } - is_not_neg_block.append_operation(cf::br(final_block, &[result], location)); - } + let src_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; + let dst_ty = registry.get_type(&info.signature.branch_signatures[0].vars[0].ty)?; - { - let mut result = is_neg_block.append_op_result(arith::extsi( - entry.argument(0)?.into(), - IntegerType::new(context, dst_width.try_into()?).into(), - location, - ))?; + let src_range = src_ty.integer_range(registry).unwrap(); + let dst_range = dst_ty.integer_range(registry).unwrap(); + assert!( + if dst_ty.is_felt252(registry) { + let alt_range = Range { + lower: -HALF_PRIME.clone(), + upper: HALF_PRIME.clone() + BigInt::one(), + }; - let value = metadata - .get::>() - .ok_or(Error::MissingMetadata)? - .prime() - .to_bigint() - .unwrap(); + (dst_range.lower <= src_range.lower && dst_range.upper >= src_range.upper) + || (alt_range.lower <= src_range.lower && alt_range.upper >= src_range.upper) + } else { + dst_range.lower <= src_range.lower && dst_range.upper >= src_range.upper + }, + "invalid upcast `{:?}` into `{:?}`: target range doesn't contain the source range", + info.signature.param_signatures[0].ty, + info.signature.branch_signatures[0].vars[0].ty + ); - let prime = is_neg_block.const_int_from_type(context, location, value, dst_type)?; + let src_width = if src_ty.is_bounded_int(registry) { + src_range.offset_bit_width() + } else { + src_range.zero_based_bit_width() + }; + let dst_width = if dst_ty.is_bounded_int(registry) { + dst_range.offset_bit_width() + } else { + dst_range.zero_based_bit_width() + }; - result = is_neg_block.append_op_result(arith::addi(result, prime, location))?; - is_neg_block.append_operation(cf::br(final_block, &[result], location)); - } + // If the source can be negative, the target type must also contain negatives when upcasting. + assert!( + src_range.lower.sign() != Sign::Minus + || dst_ty.is_felt252(registry) + || dst_range.lower.sign() == Sign::Minus + ); + let is_signed = src_range.lower.sign() == Sign::Minus; - let result = final_block.argument(0)?.into(); - final_block.append_operation(helper.br(0, &[result], location)); - return Ok(()); + let dst_value = if dst_width > src_width { + if is_signed && !src_ty.is_bounded_int(registry) { + entry.append_op_result(arith::extsi( + src_value, + IntegerType::new(context, dst_width).into(), + location, + ))? } else { - block.append_op_result(arith::extsi( - entry.argument(0)?.into(), - IntegerType::new(context, dst_width.try_into()?).into(), + entry.append_op_result(arith::extui( + src_value, + IntegerType::new(context, dst_width).into(), location, ))? } } else { - block.append_op_result(arith::extui( - block.argument(0)?.into(), - IntegerType::new(context, dst_width.try_into()?).into(), + src_value + }; + + let dst_value = if src_ty.is_bounded_int(registry) && src_range.lower != BigInt::ZERO { + let dst_offset = entry.const_int_from_type( + context, location, - ))? + if dst_ty.is_bounded_int(registry) { + &src_range.lower - &dst_range.lower + } else { + src_range.lower.clone() + }, + dst_value.r#type(), + )?; + entry.append_op_result(arith::addi(dst_value, dst_offset, location))? + } else { + dst_value + }; + + let dst_value = if dst_ty.is_felt252(registry) && src_range.lower.sign() == Sign::Minus { + let k0 = entry.const_int(context, location, 0, 252)?; + let is_negative = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Slt, + dst_value, + k0, + location, + ))?; + + let k_prime = entry.const_int(context, location, PRIME.clone(), 252)?; + let adj_value = entry.append_op_result(arith::addi(dst_value, k_prime, location))?; + + entry.append_op_result(arith::select(is_negative, adj_value, dst_value, location))? + } else { + dst_value }; - block.append_operation(helper.br(0, &[result], location)); + entry.append_operation(helper.br(0, &[dst_value], location)); Ok(()) } diff --git a/src/libfuncs/circuit.rs b/src/libfuncs/circuit.rs new file mode 100644 index 000000000..05eff5af2 --- /dev/null +++ b/src/libfuncs/circuit.rs @@ -0,0 +1,1407 @@ +//! # Circuit libfuncs + +use super::{increment_builtin_counter, increment_builtin_counter_by, LibfuncHelper}; +use crate::{ + block_ext::BlockExt, + error::{Result, SierraAssertError}, + libfuncs::r#struct::build_struct_value, + metadata::MetadataStorage, + types::TypeBuilder, + utils::{get_integer_layout, layout_repeat, ProgramRegistryExt}, +}; +use cairo_lang_sierra::{ + extensions::{ + circuit::{ + self, CircuitConcreteLibfunc, CircuitTypeConcrete, ConcreteGetOutputLibFunc, + ConcreteU96LimbsLessThanGuaranteeVerifyLibfunc, + }, + core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + lib_func::{SignatureAndTypeConcreteLibfunc, SignatureOnlyConcreteLibfunc}, + ConcreteLibfunc, + }, + program_registry::ProgramRegistry, +}; +use melior::{ + dialect::{ + arith::{self, CmpiPredicate}, + cf, llvm, + }, + ir::{ + attribute::DenseI32ArrayAttribute, r#type::IntegerType, Block, Location, Value, ValueLike, + }, + Context, +}; + +/// Select and call the correct libfunc builder function from the selector. +pub fn build<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + selector: &CircuitConcreteLibfunc, +) -> Result<()> { + match selector { + CircuitConcreteLibfunc::AddInput(info) => { + build_add_input(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::Eval(info) => { + build_eval(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::GetDescriptor(info) => { + build_get_descriptor(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::InitCircuitData(info) => { + build_init_circuit_data(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::GetOutput(info) => { + build_get_output(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::TryIntoCircuitModulus(info) => build_try_into_circuit_modulus( + context, registry, entry, location, helper, metadata, info, + ), + CircuitConcreteLibfunc::FailureGuaranteeVerify(info) => build_failure_guarantee_verify( + context, registry, entry, location, helper, metadata, info, + ), + CircuitConcreteLibfunc::IntoU96Guarantee(info) => { + build_into_u96_guarantee(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::U96GuaranteeVerify(info) => { + build_u96_guarantee_verify(context, registry, entry, location, helper, metadata, info) + } + CircuitConcreteLibfunc::U96LimbsLessThanGuaranteeVerify(info) => { + build_u96_limbs_less_than_guarantee_verify( + context, registry, entry, location, helper, metadata, info, + ) + } + CircuitConcreteLibfunc::U96SingleLimbLessThanGuaranteeVerify(info) => { + build_u96_single_limb_less_than_guarantee_verify( + context, registry, entry, location, helper, metadata, info, + ) + } + } +} + +/// Generate MLIR operations for the `init_circuit_data` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_init_circuit_data<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let rc_usage = match registry.get_type(&info.ty)? { + CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => { + info.circuit_info.rc96_usage() + } + _ => return Err(SierraAssertError::BadTypeInfo.into()), + }; + let rc = increment_builtin_counter_by( + context, + entry, + location, + entry.argument(0)?.into(), + rc_usage, + )?; + + let k0 = entry.const_int(context, location, 0, 64)?; + let accumulator_ty = &info.branch_signatures()[0].vars[1].ty; + let accumulator = build_struct_value( + context, + registry, + entry, + location, + helper, + metadata, + accumulator_ty, + &[k0], + )?; + + entry.append_operation(helper.br(0, &[rc, accumulator], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `into_u96_guarantee` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_into_u96_guarantee<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + // input is a BoundedInt<0, 79228162514264337593543950335> + let input: Value = entry.argument(0)?.into(); + // output is a U96Guarantee + let output_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.branch_signatures()[0].vars[0].ty, + )?; + // they have the same type (i96) + debug_assert_eq!(input.r#type(), output_ty); + + entry.append_operation(helper.br(0, &[input], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `add_circuit_input` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_add_input<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let n_inputs = match registry.get_type(&info.ty)? { + CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => info.circuit_info.n_inputs, + _ => return Err(SierraAssertError::BadTypeInfo.into()), + }; + let accumulator_type_id = &info.param_signatures()[0].ty; + let accumulator_ctype = registry.get_type(accumulator_type_id)?; + let accumulator_layout = accumulator_ctype.layout(registry)?; + + let accumulator: Value = entry.argument(0)?.into(); + + // Get accumulator current length + let current_length = entry.extract_value( + context, + location, + accumulator, + IntegerType::new(context, 64).into(), + 0, + )?; + + // Check if last_insert: current_length == number_of_inputs - 1 + let n_inputs_minus_1 = entry.const_int(context, location, n_inputs - 1, 64)?; + let last_insert = entry.append_op_result(arith::cmpi( + context, + arith::CmpiPredicate::Eq, + current_length, + n_inputs_minus_1, + location, + ))?; + + let middle_insert_block = helper.append_block(Block::new(&[])); + let last_insert_block = helper.append_block(Block::new(&[])); + entry.append_operation(cf::cond_br( + context, + last_insert, + last_insert_block, + middle_insert_block, + &[], + &[], + location, + )); + + // If not last insert, then: + { + // Calculate next length: next_length = current_length + 1 + let k1 = middle_insert_block.const_int(context, location, 1, 64)?; + let next_length = + middle_insert_block.append_op_result(arith::addi(current_length, k1, location))?; + + // Insert next_length into accumulator + let accumulator = + middle_insert_block.insert_value(context, location, accumulator, next_length, 0)?; + + // Get pointer to accumulator with alloc and store + let accumulator_ptr = middle_insert_block.alloca1( + context, + location, + accumulator.r#type(), + accumulator_layout.align(), + )?; + middle_insert_block.store(context, location, accumulator_ptr, accumulator)?; + + // Get pointer to next input to insert + let k0 = middle_insert_block.const_int(context, location, 0, 64)?; + let next_input_ptr = + middle_insert_block.append_op_result(llvm::get_element_ptr_dynamic( + context, + accumulator_ptr, + &[k0, k1, current_length], + accumulator.r#type(), + llvm::r#type::pointer(context, 0), + location, + ))?; + + // Interpret u384 struct (input) as u384 integer + let u384_struct = entry.argument(1)?.into(); + let new_input = + u384_struct_to_integer(context, middle_insert_block, location, u384_struct)?; + + // Store the u384 into next input pointer + middle_insert_block.store(context, location, next_input_ptr, new_input)?; + + // Load accumulator from pointer + let accumulator = + middle_insert_block.load(context, location, accumulator_ptr, accumulator.r#type())?; + + middle_insert_block.append_operation(helper.br(1, &[accumulator], location)); + } + + // If is last insert, then: + { + let data_type_id = &info.branch_signatures()[0].vars[0].ty; + let (data_type, data_layout) = + registry.build_type_with_layout(context, helper, registry, metadata, data_type_id)?; + + // Alloc return data + let data_ptr = + last_insert_block.alloca1(context, location, data_type, data_layout.align())?; + + // Get pointer to accumulator with alloc and store + let accumulator_ptr = last_insert_block.alloca1( + context, + location, + accumulator.r#type(), + accumulator_layout.align(), + )?; + last_insert_block.store(context, location, accumulator_ptr, accumulator)?; + + // Get pointer to accumulator input + let k0 = last_insert_block.const_int(context, location, 0, 64)?; + let k1 = last_insert_block.const_int(context, location, 1, 64)?; + let accumulator_input_ptr = + last_insert_block.append_op_result(llvm::get_element_ptr_dynamic( + context, + accumulator_ptr, + &[k0, k1], + accumulator.r#type(), + llvm::r#type::pointer(context, 0), + location, + ))?; + + // Copy accumulator input into return data + let accumulator_input_length = last_insert_block.const_int( + context, + location, + layout_repeat(&get_integer_layout(384), n_inputs - 1)? + .0 + .size(), + 64, + )?; + last_insert_block.memcpy( + context, + location, + accumulator_input_ptr, + data_ptr, + accumulator_input_length, + ); + + // Interpret u384 struct (input) as u384 integer + let u384_struct = entry.argument(1)?.into(); + let new_input = u384_struct_to_integer(context, last_insert_block, location, u384_struct)?; + + // Get pointer to data end + let data_end_ptr = last_insert_block.append_op_result(llvm::get_element_ptr( + context, + data_ptr, + DenseI32ArrayAttribute::new(context, &[0, n_inputs as i32 - 1]), + data_type, + llvm::r#type::pointer(context, 0), + location, + ))?; + + // Store the u384 into next input pointer + last_insert_block.store(context, location, data_end_ptr, new_input)?; + + // Load data from pointer + let data = last_insert_block.load(context, location, data_ptr, data_type)?; + + last_insert_block.append_operation(helper.br(0, &[data], location)); + } + + Ok(()) +} + +/// Generate MLIR operations for the `try_into_circuit_modulus` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_try_into_circuit_modulus<'ctx, 'this>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let modulus = u384_struct_to_integer(context, entry, location, entry.argument(0)?.into())?; + let k1 = entry.const_int(context, location, 1, 384)?; + + let is_valid = entry.append_op_result(arith::cmpi( + context, + arith::CmpiPredicate::Ugt, + modulus, + k1, + location, + ))?; + + entry.append_operation(helper.cond_br(context, is_valid, [0, 1], [&[modulus], &[]], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `get_circuit_descriptor` libfunc. +/// NOOP +#[allow(clippy::too_many_arguments)] +fn build_get_descriptor<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let descriptor_type_id = &info.branch_signatures()[0].vars[0].ty; + let descriptor_type = + registry.build_type(context, helper, registry, metadata, descriptor_type_id)?; + + let unit = entry.append_op_result(llvm::undef(descriptor_type, location))?; + + entry.append_operation(helper.br(0, &[unit], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `eval_circuit` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_eval<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let circuit_info = match registry.get_type(&info.ty)? { + CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info, + _ => return Err(SierraAssertError::BadTypeInfo.into()), + }; + let add_mod = entry.argument(0)?.into(); + let mul_mod = entry.argument(1)?.into(); + let circuit_data = entry.argument(3)?.into(); + let circuit_modulus = entry.argument(4)?.into(); + + // arguments 5 and 6 are used to build the gate 0 (with constant value 1) + // let zero = entry.argument(5)?; + // let one = entry.argument(6)?; + + // We multiply the amount of gates evaluated by 4 (the amount of u96s in each gate) + let add_mod = increment_builtin_counter_by( + context, + entry, + location, + add_mod, + circuit_info.add_offsets.len() * 4, + )?; + + let ([ok_block, err_block], gates) = build_gate_evaluation( + context, + entry, + location, + helper, + circuit_info, + circuit_data, + circuit_modulus, + )?; + + // Ok case + { + let mul_mod = increment_builtin_counter_by( + context, + ok_block, + location, + mul_mod, + circuit_info.mul_offsets.len() * 4, + )?; + + // Build output struct + let outputs_type_id = &info.branch_signatures()[0].vars[2].ty; + let outputs = build_struct_value( + context, + registry, + ok_block, + location, + helper, + metadata, + outputs_type_id, + &gates, + )?; + + ok_block.append_operation(helper.br(0, &[add_mod, mul_mod, outputs], location)); + } + + // Error case + { + // We only consider mul gates evaluated before failure + let mul_mod = { + let mul_mod_usage = err_block.append_op_result(arith::muli( + err_block.argument(0)?.into(), + err_block.const_int(context, location, 4, 64)?, + location, + ))?; + err_block.append_op_result(arith::addi(mul_mod, mul_mod_usage, location)) + }?; + + let partial_type_id = &info.branch_signatures()[1].vars[2].ty; + let partial = err_block.append_op_result(llvm::undef( + registry.build_type(context, helper, registry, metadata, partial_type_id)?, + location, + ))?; + let failure_type_id = &info.branch_signatures()[1].vars[3].ty; + let failure = err_block.append_op_result(llvm::undef( + registry.build_type(context, helper, registry, metadata, failure_type_id)?, + location, + ))?; + err_block.append_operation(helper.br(1, &[add_mod, mul_mod, partial, failure], location)); + } + + Ok(()) +} + +/// Builds the evaluation of all circuit gates, returning: +/// - An array of two branches, the success block and the error block respectively. +/// - The error block contains the index of the first failure as argument. +/// - A vector of the gate values. In case of failure, not all values are guaranteed to be computed. +/// +/// The original Cairo hint evaluates all gates, even in case of failure. This implementation exits on first error, as there is no need for the partial outputs yet. +fn build_gate_evaluation<'ctx, 'this>( + context: &'this Context, + mut block: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + circuit_info: &circuit::CircuitInfo, + circuit_data: Value<'ctx, 'ctx>, + circuit_modulus: Value<'ctx, 'ctx>, +) -> Result<([&'this Block<'ctx>; 2], Vec>)> { + // Throughout the evaluation of the circuit we maintain an array of known gate values + // Initially, it only contains the inputs of the circuit. + // Unknown values are represented as None + + let mut values = vec![None; 1 + circuit_info.n_inputs + circuit_info.values.len()]; + values[0] = Some(block.const_int(context, location, 1, 384)?); + for i in 0..circuit_info.n_inputs { + values[i + 1] = Some(block.extract_value( + context, + location, + circuit_data, + IntegerType::new(context, 384).into(), + i, + )?); + } + + let err_block = helper.append_block(Block::new(&[( + IntegerType::new(context, 64).into(), + location, + )])); + + let mut add_offsets = circuit_info.add_offsets.iter().peekable(); + let mut mul_offsets = circuit_info.mul_offsets.iter().enumerate(); + + // We loop until all gates have been solved + loop { + // We iterate the add gate offsets as long as we can + while let Some(&add_gate_offset) = add_offsets.peek() { + let lhs_value = values[add_gate_offset.lhs].to_owned(); + let rhs_value = values[add_gate_offset.rhs].to_owned(); + let output_value = values[add_gate_offset.output].to_owned(); + + // Depending on the values known at the time, we can deduce if we are dealing with an ADD gate or a SUB gate. + match (lhs_value, rhs_value, output_value) { + // ADD: lhs + rhs = out + (Some(lhs_value), Some(rhs_value), None) => { + // Extend to avoid overflow + let lhs_value = block.append_op_result(arith::extui( + lhs_value, + IntegerType::new(context, 384 + 1).into(), + location, + ))?; + let rhs_value = block.append_op_result(arith::extui( + rhs_value, + IntegerType::new(context, 384 + 1).into(), + location, + ))?; + let circuit_modulus = block.append_op_result(arith::extui( + circuit_modulus, + IntegerType::new(context, 384 + 1).into(), + location, + ))?; + // value = (lhs_value + rhs_value) % circuit_modulus + let value = + block.append_op_result(arith::addi(lhs_value, rhs_value, location))?; + let value = + block.append_op_result(arith::remui(value, circuit_modulus, location))?; + // Truncate back + let value = block.append_op_result(arith::trunci( + value, + IntegerType::new(context, 384).into(), + location, + ))?; + values[add_gate_offset.output] = Some(value); + } + // SUB: lhs = out - rhs + (None, Some(rhs_value), Some(output_value)) => { + // Extend to avoid overflow + let rhs_value = block.append_op_result(arith::extui( + rhs_value, + IntegerType::new(context, 384 + 1).into(), + location, + ))?; + let output_value = block.append_op_result(arith::extui( + output_value, + IntegerType::new(context, 384 + 1).into(), + location, + ))?; + let circuit_modulus = block.append_op_result(arith::extui( + circuit_modulus, + IntegerType::new(context, 384 + 1).into(), + location, + ))?; + // value = (output_value + circuit_modulus - rhs_value) % circuit_modulus + let value = block.append_op_result(arith::addi( + output_value, + circuit_modulus, + location, + ))?; + let value = block.append_op_result(arith::subi(value, rhs_value, location))?; + let value = + block.append_op_result(arith::remui(value, circuit_modulus, location))?; + // Truncate back + let value = block.append_op_result(arith::trunci( + value, + IntegerType::new(context, 384).into(), + location, + ))?; + values[add_gate_offset.lhs] = Some(value); + } + // We can't solve this add gate yet, so we break from the loop + _ => break, + } + + add_offsets.next(); + } + + // If we can't advance any more with add gate offsets, then we solve the next mul gate offset and go back to the start of the loop (solving add gate offsets). + if let Some((gate_offset_idx, &circuit::GateOffsets { lhs, rhs, output })) = + mul_offsets.next() + { + let lhs_value = values[lhs].to_owned(); + let rhs_value = values[rhs].to_owned(); + let output_value = values[output].to_owned(); + + // Depending on the values known at the time, we can deduce if we are dealing with an MUL gate or a INV gate. + match (lhs_value, rhs_value, output_value) { + // MUL: lhs * rhs = out + (Some(lhs_value), Some(rhs_value), None) => { + // Extend to avoid overflow + let lhs_value = block.append_op_result(arith::extui( + lhs_value, + IntegerType::new(context, 384 * 2).into(), + location, + ))?; + let rhs_value = block.append_op_result(arith::extui( + rhs_value, + IntegerType::new(context, 384 * 2).into(), + location, + ))?; + let circuit_modulus = block.append_op_result(arith::extui( + circuit_modulus, + IntegerType::new(context, 384 * 2).into(), + location, + ))?; + // value = (lhs_value * rhs_value) % circuit_modulus + let value = + block.append_op_result(arith::muli(lhs_value, rhs_value, location))?; + let value = + block.append_op_result(arith::remui(value, circuit_modulus, location))?; + // Truncate back + let value = block.append_op_result(arith::trunci( + value, + IntegerType::new(context, 384).into(), + location, + ))?; + values[output] = Some(value) + } + // INV: lhs = 1 / rhs + (None, Some(rhs_value), Some(_)) => { + // Extend to avoid overflow + let rhs_value = block.append_op_result(arith::extui( + rhs_value, + IntegerType::new(context, 384 * 2).into(), + location, + ))?; + let circuit_modulus = block.append_op_result(arith::extui( + circuit_modulus, + IntegerType::new(context, 384 * 2).into(), + location, + ))?; + let integer_type = rhs_value.r#type(); + + // Apply egcd to find gcd and inverse + let egcd_result_block = build_euclidean_algorithm( + context, + block, + location, + helper, + rhs_value, + circuit_modulus, + )?; + let gcd = egcd_result_block.argument(0)?.into(); + let inverse = egcd_result_block.argument(1)?.into(); + block = egcd_result_block; + + // if the gcd is not 1, then fail (a and b are not coprimes) + let one = block.const_int_from_type(context, location, 1, integer_type)?; + let gate_offset_idx_value = block.const_int_from_type( + context, + location, + gate_offset_idx, + IntegerType::new(context, 64).into(), + )?; + let has_inverse = block.append_op_result(arith::cmpi( + context, + CmpiPredicate::Eq, + gcd, + one, + location, + ))?; + let has_inverse_block = helper.append_block(Block::new(&[])); + block.append_operation(cf::cond_br( + context, + has_inverse, + has_inverse_block, + err_block, + &[], + &[gate_offset_idx_value], + location, + )); + block = has_inverse_block; + + // if the inverse is negative, then add modulus + let zero = block.const_int_from_type(context, location, 0, integer_type)?; + let is_negative = block + .append_operation(arith::cmpi( + context, + CmpiPredicate::Slt, + inverse, + zero, + location, + )) + .result(0)? + .into(); + let wrapped_inverse = + block.append_op_result(arith::addi(inverse, circuit_modulus, location))?; + let inverse = block.append_op_result(arith::select( + is_negative, + wrapped_inverse, + inverse, + location, + ))?; + + // Truncate back + let inverse = block.append_op_result(arith::trunci( + inverse, + IntegerType::new(context, 384).into(), + location, + ))?; + + values[lhs] = Some(inverse); + } + // The imposibility to solve this mul gate offset would render the circuit unsolvable + _ => return Err(SierraAssertError::ImpossibleCircuit.into()), + } + } else { + // If there are no mul gate offsets left, then we have the finished evaluation. + break; + } + } + + // Validate all values have been calculated + // Should only fail if the circuit is not solvable (bad form) + let values = values + .into_iter() + .skip(1 + circuit_info.n_inputs) + .collect::>>() + .ok_or(SierraAssertError::ImpossibleCircuit)?; + + Ok(([block, err_block], values)) +} + +/// Generate MLIR operations for the `circuit_failure_guarantee_verify` libfunc. +/// NOOP +#[allow(clippy::too_many_arguments)] +fn build_failure_guarantee_verify<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let rc = entry.argument(0)?.into(); + let mul_mod = entry.argument(1)?.into(); + let rc = increment_builtin_counter_by(context, entry, location, rc, 4)?; + + let mul_mod = increment_builtin_counter_by(context, entry, location, mul_mod, 4)?; + + let guarantee_type_id = &info.branch_signatures()[0].vars[2].ty; + let guarantee_type = + registry.build_type(context, helper, registry, metadata, guarantee_type_id)?; + + let guarantee = entry.append_op_result(llvm::undef(guarantee_type, location))?; + + entry.append_operation(helper.br(0, &[rc, mul_mod, guarantee], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `u96_limbs_less_than_guarantee_verify` libfunc. +/// NOOP +#[allow(clippy::too_many_arguments)] +fn build_u96_limbs_less_than_guarantee_verify<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &ConcreteU96LimbsLessThanGuaranteeVerifyLibfunc, +) -> Result<()> { + let guarantee_type_id = &info.branch_signatures()[0].vars[0].ty; + let guarantee_type = + registry.build_type(context, helper, registry, metadata, guarantee_type_id)?; + + let guarantee = entry.append_op_result(llvm::undef(guarantee_type, location))?; + + let u96_type_id = &info.branch_signatures()[1].vars[0].ty; + let u96_type = registry.build_type(context, helper, registry, metadata, u96_type_id)?; + + let u96 = entry.append_op_result(llvm::undef(u96_type, location))?; + + let kfalse = entry.const_int(context, location, 0, 64)?; + entry.append_operation(helper.cond_br( + context, + kfalse, + [0, 1], + [&[guarantee], &[u96]], + location, + )); + + Ok(()) +} + +/// Generate MLIR operations for the `u96_guarantee_verify` libfunc. +/// NOOP +#[allow(clippy::too_many_arguments)] +fn build_u96_guarantee_verify<'ctx, 'this>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let rc = entry.argument(0)?.into(); + let rc = increment_builtin_counter(context, entry, location, rc)?; + + entry.append_operation(helper.br(0, &[rc], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `u96_single_limb_less_than_guarantee_verify` libfunc. +/// NOOP +#[allow(clippy::too_many_arguments)] +fn build_u96_single_limb_less_than_guarantee_verify<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let u96_type_id = &info.branch_signatures()[0].vars[0].ty; + let u96_type = registry.build_type(context, helper, registry, metadata, u96_type_id)?; + let u96 = entry.append_op_result(llvm::undef(u96_type, location))?; + + entry.append_operation(helper.br(0, &[u96], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `get_circuit_output` libfunc. +#[allow(clippy::too_many_arguments)] +fn build_get_output<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &ConcreteGetOutputLibFunc, +) -> Result<()> { + let circuit_info = match registry.get_type(&info.circuit_ty)? { + CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info, + _ => return Err(SierraAssertError::BadTypeInfo.into()), + }; + let output_type_id = &info.output_ty; + + let output_offset_idx = *circuit_info + .values + .get(output_type_id) + .ok_or(SierraAssertError::BadTypeInfo)?; + + let output_idx = output_offset_idx - circuit_info.n_inputs - 1; + + let outputs = entry.argument(0)?.into(); + let output_integer = entry.extract_value( + context, + location, + outputs, + IntegerType::new(context, 384).into(), + output_idx, + )?; + let output_struct = u384_integer_to_struct(context, entry, location, output_integer)?; + + let guarantee_type_id = &info.branch_signatures()[0].vars[1].ty; + let guarantee_type = + registry.build_type(context, helper, registry, metadata, guarantee_type_id)?; + let guarantee = entry.append_op_result(llvm::undef(guarantee_type, location))?; + + entry.append_operation(helper.br(0, &[output_struct, guarantee], location)); + + Ok(()) +} + +fn u384_struct_to_integer<'a>( + context: &'a Context, + block: &'a Block<'a>, + location: Location<'a>, + u384_struct: Value<'a, 'a>, +) -> Result> { + let u96_type = IntegerType::new(context, 96).into(); + + let limb1 = block.append_op_result(arith::extui( + block.extract_value(context, location, u384_struct, u96_type, 0)?, + IntegerType::new(context, 384).into(), + location, + ))?; + + let limb2 = { + let limb = block.append_op_result(arith::extui( + block.extract_value(context, location, u384_struct, u96_type, 1)?, + IntegerType::new(context, 384).into(), + location, + ))?; + let k96 = block.const_int(context, location, 96, 384)?; + block.append_op_result(arith::shli(limb, k96, location))? + }; + + let limb3 = { + let limb = block.append_op_result(arith::extui( + block.extract_value(context, location, u384_struct, u96_type, 2)?, + IntegerType::new(context, 384).into(), + location, + ))?; + let k192 = block.const_int(context, location, 96 * 2, 384)?; + block.append_op_result(arith::shli(limb, k192, location))? + }; + + let limb4 = { + let limb = block.append_op_result(arith::extui( + block.extract_value(context, location, u384_struct, u96_type, 3)?, + IntegerType::new(context, 384).into(), + location, + ))?; + let k288 = block.const_int(context, location, 96 * 3, 384)?; + block.append_op_result(arith::shli(limb, k288, location))? + }; + + let value = block.append_op_result(arith::ori(limb1, limb2, location))?; + let value = block.append_op_result(arith::ori(value, limb3, location))?; + let value = block.append_op_result(arith::ori(value, limb4, location))?; + + Ok(value) +} + +fn u384_integer_to_struct<'a>( + context: &'a Context, + block: &'a Block<'a>, + location: Location<'a>, + integer: Value<'a, 'a>, +) -> Result> { + let u96_type = IntegerType::new(context, 96).into(); + + let limb1 = block.append_op_result(arith::trunci( + integer, + IntegerType::new(context, 96).into(), + location, + ))?; + let limb2 = { + let k96 = block.const_int(context, location, 96, 384)?; + let limb = block.append_op_result(arith::shrui(integer, k96, location))?; + block.append_op_result(arith::trunci(limb, u96_type, location))? + }; + let limb3 = { + let k192 = block.const_int(context, location, 96 * 2, 384)?; + let limb = block.append_op_result(arith::shrui(integer, k192, location))?; + block.append_op_result(arith::trunci(limb, u96_type, location))? + }; + let limb4 = { + let k288 = block.const_int(context, location, 96 * 3, 384)?; + let limb = block.append_op_result(arith::shrui(integer, k288, location))?; + block.append_op_result(arith::trunci(limb, u96_type, location))? + }; + + let struct_type = llvm::r#type::r#struct( + context, + &[ + IntegerType::new(context, 96).into(), + IntegerType::new(context, 96).into(), + IntegerType::new(context, 96).into(), + IntegerType::new(context, 96).into(), + ], + false, + ); + let struct_value = block.append_op_result(llvm::undef(struct_type, location))?; + + block.insert_values( + context, + location, + struct_value, + &[limb1, limb2, limb3, limb4], + ) +} + +/// The extended euclidean algorithm calculates the greatest common divisor (gcd) of two integers a and b, +/// as well as the bezout coefficients x and y such that ax+by=gcd(a,b) +/// if gcd(a,b) = 1, then x is the modular multiplicative inverse of a modulo b. +/// See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm +/// +/// Given two numbers a, b. It returns a block with gcd(a, b) and the bezout coefficient x. +fn build_euclidean_algorithm<'ctx, 'this>( + context: &'ctx Context, + block: &'ctx Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + a: Value<'ctx, 'ctx>, + b: Value<'ctx, 'ctx>, +) -> Result<&'this Block<'ctx>> { + let integer_type = a.r#type(); + + let loop_block = helper.append_block(Block::new(&[ + (integer_type, location), + (integer_type, location), + (integer_type, location), + (integer_type, location), + ])); + let end_block = helper.append_block(Block::new(&[ + (integer_type, location), + (integer_type, location), + ])); + + // The algorithm egcd works by calculating a series of remainders, each the remainder of dividing the previous two + // For the initial setup, r0 = b, r1 = a + // This order is chosen because if we reverse them, then the first iteration will just swap them + let prev_remainder = b; + let remainder = a; + // Similarly we'll calculate another series which starts 0,1,... and from which we will retrieve the modular inverse of a + let prev_inverse = block.const_int_from_type(context, location, 0, integer_type)?; + let inverse = block.const_int_from_type(context, location, 1, integer_type)?; + block.append_operation(cf::br( + loop_block, + &[prev_remainder, remainder, prev_inverse, inverse], + location, + )); + + // -- Loop body -- + // Arguments are rem_(i-1), rem, inv_(i-1), inv + let prev_remainder = loop_block.argument(0)?.into(); + let remainder = loop_block.argument(1)?.into(); + let prev_inverse = loop_block.argument(2)?.into(); + let inverse = loop_block.argument(3)?.into(); + + // First calculate q = rem_(i-1)/rem_i, rounded down + let quotient = + loop_block.append_op_result(arith::divui(prev_remainder, remainder, location))?; + + // Then r_(i+1) = r_(i-1) - q * r_i, and inv_(i+1) = inv_(i-1) - q * inv_i + let rem_times_quo = loop_block.append_op_result(arith::muli(remainder, quotient, location))?; + let inv_times_quo = loop_block.append_op_result(arith::muli(inverse, quotient, location))?; + let next_remainder = + loop_block.append_op_result(arith::subi(prev_remainder, rem_times_quo, location))?; + let next_inverse = + loop_block.append_op_result(arith::subi(prev_inverse, inv_times_quo, location))?; + + // Check if r_(i+1) is 0 + // If true, then: + // - r_i is the gcd of a and b + // - inv_i is the bezout coefficient x + + let zero = loop_block.const_int_from_type(context, location, 0, integer_type)?; + let next_remainder_eq_zero = loop_block.append_op_result(arith::cmpi( + context, + CmpiPredicate::Eq, + next_remainder, + zero, + location, + ))?; + loop_block.append_operation(cf::cond_br( + context, + next_remainder_eq_zero, + end_block, + loop_block, + &[remainder, inverse], + &[remainder, next_remainder, inverse, next_inverse], + location, + )); + + Ok(end_block) +} + +#[cfg(test)] +mod test { + + use crate::{ + utils::test::{jit_enum, jit_panic, jit_struct, load_cairo, run_program_assert_output}, + values::JitValue, + }; + use cairo_lang_sierra::extensions::utils::Range; + use num_bigint::BigUint; + use num_traits::Num; + use starknet_types_core::felt::Felt; + + fn u384(limbs: [&str; 4]) -> JitValue { + fn u96_range() -> Range { + Range { + lower: BigUint::from_str_radix("0", 16).unwrap().into(), + upper: BigUint::from_str_radix("79228162514264337593543950336", 10) + .unwrap() + .into(), + } + } + + JitValue::Struct { + fields: vec![ + JitValue::BoundedInt { + value: Felt::from_hex_unchecked(limbs[0]), + range: u96_range(), + }, + JitValue::BoundedInt { + value: Felt::from_hex_unchecked(limbs[1]), + range: u96_range(), + }, + JitValue::BoundedInt { + value: Felt::from_hex_unchecked(limbs[2]), + range: u96_range(), + }, + JitValue::BoundedInt { + value: Felt::from_hex_unchecked(limbs[3]), + range: u96_range(), + }, + ], + debug_name: None, + } + } + + #[test] + fn run_add_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let in2 = CircuitElement::> {}; + let add = circuit_add(in1, in2); + + let modulus = TryInto::<_, CircuitModulus>::try_into([12, 12, 12, 12]).unwrap(); + + let outputs = (add,) + .new_inputs() + .next([3, 3, 3, 3]) + .next([6, 6, 6, 6]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(add) + } + ); + + run_program_assert_output( + &program, + "main", + &[], + jit_enum!(0, jit_struct!(u384(["0x9", "0x9", "0x9", "0x9"]))), + ); + } + + #[test] + fn run_sub_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let in2 = CircuitElement::> {}; + let mul = circuit_sub(in1, in2); + + let modulus = TryInto::<_, CircuitModulus>::try_into([12, 12, 12, 12]).unwrap(); + + let outputs = (mul,) + .new_inputs() + .next([6, 6, 6, 6]) + .next([3, 3, 3, 3]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(mul) + } + ); + + run_program_assert_output( + &program, + "main", + &[], + jit_enum!(0, jit_struct!(u384(["0x3", "0x3", "0x3", "0x3"]))), + ); + } + + #[test] + fn run_mul_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let in2 = CircuitElement::> {}; + let mul = circuit_mul(in1, in2); + + let modulus = TryInto::<_, CircuitModulus>::try_into([12, 12, 12, 12]).unwrap(); + + let outputs = (mul,) + .new_inputs() + .next([3, 0, 0, 0]) + .next([3, 3, 3, 3]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(mul) + } + ); + + run_program_assert_output( + &program, + "main", + &[], + jit_enum!(0, jit_struct!(u384(["0x9", "0x9", "0x9", "0x9"]))), + ); + } + + #[test] + fn run_inverse_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let inv = circuit_inverse(in1); + + let modulus = TryInto::<_, CircuitModulus>::try_into([11, 0, 0, 0]).unwrap(); + + let outputs = (inv,) + .new_inputs() + .next([2, 0, 0, 0]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(inv) + } + ); + + run_program_assert_output( + &program, + "main", + &[], + jit_enum!(0, jit_struct!(u384(["0x6", "0x0", "0x0", "0x0"]))), + ); + } + + #[test] + fn run_no_coprime_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let inv = circuit_inverse(in1); + + let modulus = TryInto::<_, CircuitModulus>::try_into([12, 0, 0, 0]).unwrap(); + + let outputs = (inv,) + .new_inputs() + .next([3, 0, 0, 0]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(inv) + } + ); + + run_program_assert_output( + &program, + "main", + &[], + jit_panic!(JitValue::felt_str( + "30828113188794245257250221355944970489240709081949230" + )), + ); + } + + #[test] + fn run_mul_overflow_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let in2 = CircuitElement::> {}; + let mul = circuit_mul(in1, in2); + + let modulus = TryInto::<_, CircuitModulus>::try_into([ + 0xffffffffffffffffffffffff, + 0xffffffffffffffffffffffff, + 0xffffffffffffffffffffffff, + 0xffffffffffffffffffffffff, + ]) + .unwrap(); + + let outputs = (mul,) + .new_inputs() + .next([0, 0, 0, 0xffffffffffffffffffffffff]) + .next([16, 0, 0, 0]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(mul) + } + ); + + run_program_assert_output( + &program, + "main", + &[], + jit_enum!( + 0, + jit_struct!(u384(["0xf", "0x0", "0x0", "0xfffffffffffffffffffffff0"])) + ), + ); + } + + #[test] + fn run_full_circuit() { + let program = load_cairo!( + use core::circuit::{ + RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, + circuit_sub, circuit_mul, circuit_inverse, EvalCircuitTrait, u384, + CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs, + }; + + fn main() -> u384 { + let in1 = CircuitElement::> {}; + let in2 = CircuitElement::> {}; + let add1 = circuit_add(in1, in2); + let mul1 = circuit_mul(add1, in1); + let mul2 = circuit_mul(mul1, add1); + let inv1 = circuit_inverse(mul2); + let sub1 = circuit_sub(inv1, in2); + let sub2 = circuit_sub(sub1, mul2); + let inv2 = circuit_inverse(sub2); + let add2 = circuit_add(inv2, inv2); + + let modulus = TryInto::<_, CircuitModulus>::try_into([17, 14, 14, 14]).unwrap(); + + let outputs = (add2,) + .new_inputs() + .next([9, 2, 9, 3]) + .next([5, 7, 0, 8]) + .done() + .eval(modulus) + .unwrap(); + + outputs.get_output(add2) + } + ); + + dbg!(Felt::from_raw([ + 576460752303419696, + 18446744073709551615, + 18446744073709551615, + 18446744073709551393 + ])); + + run_program_assert_output( + &program, + "main", + &[], + jit_enum!( + 0, + jit_struct!(u384([ + "0x76956587ccb74125e760fdf3", + "0xe8c82ede90011c6adc4b5cfa", + "0xaf4bed7eef975ff1941fdf3d", + "0x7" + ])) + ), + ); + } +} diff --git a/src/libfuncs/const.rs b/src/libfuncs/const.rs index fc23b710f..198600a2c 100644 --- a/src/libfuncs/const.rs +++ b/src/libfuncs/const.rs @@ -2,15 +2,16 @@ use super::LibfuncHelper; use crate::block_ext::BlockExt; +use crate::types::felt252::PRIME; +use crate::utils::RangeExt; use crate::{ error::{Error, Result}, libfuncs::{r#enum::build_enum_value, r#struct::build_struct_value}, - metadata::{ - prime_modulo::PrimeModuloMeta, realloc_bindings::ReallocBindingsMeta, MetadataStorage, - }, + metadata::{realloc_bindings::ReallocBindingsMeta, MetadataStorage}, types::TypeBuilder, utils::ProgramRegistryExt, }; +use cairo_lang_sierra::extensions::bounded_int::BoundedIntConcreteType; use cairo_lang_sierra::{ extensions::{ const_type::{ @@ -23,15 +24,11 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use melior::{ - dialect::{ - arith, - llvm::{self, r#type::pointer}, - }, - ir::{Attribute, Block, Location, Value}, + dialect::llvm::{self, r#type::pointer}, + ir::{Block, Location, Value}, Context, }; -use num_bigint::ToBigInt; -use starknet_types_core::felt::Felt; +use num_bigint::Sign; /// Select and call the correct libfunc builder function from the selector. pub fn build<'ctx, 'this>( @@ -237,40 +234,56 @@ pub fn build_const_type_value<'ctx, 'this>( } _ => Err(Error::ConstDataMismatch), }, - inner_type => match &info.inner_data[..] { - [GenericArg::Value(value)] => { - let mlir_value: Value = match inner_type { - CoreTypeConcrete::Felt252(_) => { - let value = if value.sign() == num_bigint::Sign::Minus { - let prime = metadata - .get::>() - .ok_or(Error::MissingMetadata)? - .prime(); - - value + prime.to_bigint().expect("Prime to BigInt shouldn't fail") - } else { - value.clone() - }; + CoreTypeConcrete::BoundedInt(BoundedIntConcreteType { range, .. }) => { + let value = match &info.inner_data.as_slice() { + [GenericArg::Value(value)] => value.clone(), + _ => return Err(Error::ConstDataMismatch), + }; - entry.append_op_result(arith::constant( - context, - Attribute::parse(context, &format!("{} : {}", value, inner_ty)) - .unwrap(), - location, - ))? - } - // any other int type - _ => entry.append_op_result(arith::constant( - context, - Attribute::parse(context, &format!("{} : {}", value, inner_ty)).unwrap(), - location, - ))?, - }; + // Offset the value so that 0 matches with lower. + let value = &value - &range.lower; - Ok(mlir_value) + entry.const_int( + context, + location, + value, + inner_type + .integer_range(registry) + .unwrap() + .offset_bit_width(), + ) + } + CoreTypeConcrete::Felt252(_) => { + let value = match &info.inner_data.as_slice() { + [GenericArg::Value(value)] => value.clone(), + _ => return Err(Error::ConstDataMismatch), + }; + + let (sign, value) = value.into_parts(); + let value = match sign { + Sign::Minus => PRIME.clone() - value, + _ => value, + }; + + entry.const_int_from_type(context, location, value.clone(), inner_ty) + } + CoreTypeConcrete::Uint8(_) + | CoreTypeConcrete::Uint16(_) + | CoreTypeConcrete::Uint32(_) + | CoreTypeConcrete::Uint64(_) + | CoreTypeConcrete::Uint128(_) + | CoreTypeConcrete::Sint8(_) + | CoreTypeConcrete::Sint16(_) + | CoreTypeConcrete::Sint32(_) + | CoreTypeConcrete::Sint64(_) + | CoreTypeConcrete::Sint128(_) + | CoreTypeConcrete::Bytes31(_) => match &info.inner_data.as_slice() { + [GenericArg::Value(value)] => { + entry.const_int_from_type(context, location, value.clone(), inner_ty) } _ => Err(Error::ConstDataMismatch), }, + _ => todo!("const for type {}", info.inner_ty), } } diff --git a/src/libfuncs/ec.rs b/src/libfuncs/ec.rs index 229605b9a..cccbd44c3 100644 --- a/src/libfuncs/ec.rs +++ b/src/libfuncs/ec.rs @@ -27,7 +27,7 @@ use melior::{ ir::{operation::OperationBuilder, r#type::IntegerType, Block, Location}, Context, }; -use num_bigint::{BigInt, ToBigInt}; +use num_bigint::ToBigInt; use starknet_types_core::felt::Felt; /// Select and call the correct libfunc builder function from the selector. @@ -84,13 +84,8 @@ pub fn build_is_zero<'ctx, 'this>( _metadata: &mut MetadataStorage, _info: &SignatureOnlyConcreteLibfunc, ) -> Result<()> { - let x = entry.extract_value( - context, - location, - entry.argument(0)?.into(), - IntegerType::new(context, 252).into(), - 0, - )?; + // To check whether `(x, y) = (0, 0)` (the zero point), it is enough to check + // whether `y = 0`, since there is no point on the curve with y = 0. let y = entry.extract_value( context, location, @@ -100,17 +95,12 @@ pub fn build_is_zero<'ctx, 'this>( )?; let k0 = entry.const_int(context, location, 0, 252)?; - - let x_is_zero = - entry.append_op_result(arith::cmpi(context, CmpiPredicate::Eq, x, k0, location))?; let y_is_zero = entry.append_op_result(arith::cmpi(context, CmpiPredicate::Eq, y, k0, location))?; - let point_is_zero = entry.append_op_result(arith::andi(x_is_zero, y_is_zero, location))?; - entry.append_operation(helper.cond_br( context, - point_is_zero, + y_is_zero, [0, 1], [&[], &[entry.argument(0)?.into()]], location, @@ -377,7 +367,7 @@ pub fn build_state_init<'ctx, 'this>( entry: &'this Block<'ctx>, location: Location<'ctx>, helper: &LibfuncHelper<'ctx, 'this>, - _metadata: &mut MetadataStorage, + metadata: &mut MetadataStorage, _info: &SignatureOnlyConcreteLibfunc, ) -> Result<()> { let ec_state_ty = llvm::r#type::r#struct( @@ -391,31 +381,21 @@ pub fn build_state_init<'ctx, 'this>( false, ); - let point = entry.append_op_result(llvm::undef(ec_state_ty, location))?; - - let value = BigInt::parse_bytes( - b"3151312365169595090315724863753927489909436624354740709748557281394568342450", - 10, - ) - .unwrap(); - let x = entry.const_int(context, location, value, 252)?; - - let value = BigInt::parse_bytes( - b"2835232394579952276045648147338966184268723952674536708929458753792035266179", - 10, - ) - .unwrap(); - let y = entry.const_int(context, location, value, 252)?; - - let point = entry.insert_value(context, location, point, x, 0)?; - - let point = entry.insert_value(context, location, point, y, 1)?; + let state_ptr = helper.init_block().alloca1( + context, + location, + ec_state_ty, + get_integer_layout(252).align(), + )?; - let point = entry.insert_value(context, location, point, x, 2)?; + metadata + .get_mut::() + .ok_or(Error::MissingMetadata)? + .libfunc_ec_state_init(context, helper, entry, state_ptr, location)?; - let point = entry.insert_value(context, location, point, y, 3)?; + let state = entry.load(context, location, state_ptr, ec_state_ty)?; - entry.append_operation(helper.br(0, &[point], location)); + entry.append_operation(helper.br(0, &[state], location)); Ok(()) } @@ -636,10 +616,7 @@ mod test { r(0.into(), 1.into()), jit_enum!(1, JitValue::EcPoint(0.into(), 1.into())) ); - assert_eq!( - r(1.into(), 0.into()), - jit_enum!(1, JitValue::EcPoint(1.into(), 0.into())) - ); + assert_eq!(r(1.into(), 0.into()), jit_enum!(0, jit_struct!())); assert_eq!( r(1.into(), 1.into()), jit_enum!(1, JitValue::EcPoint(1.into(), 1.into())) @@ -784,29 +761,9 @@ mod test { #[test] fn ec_state_init() { - run_program_assert_output( - &EC_STATE_INIT, - "run_test", - &[], - JitValue::EcState( - Felt::from_dec_str( - "3151312365169595090315724863753927489909436624354740709748557281394568342450", - ) - .unwrap(), - Felt::from_dec_str( - "2835232394579952276045648147338966184268723952674536708929458753792035266179", - ) - .unwrap(), - Felt::from_dec_str( - "3151312365169595090315724863753927489909436624354740709748557281394568342450", - ) - .unwrap(), - Felt::from_dec_str( - "2835232394579952276045648147338966184268723952674536708929458753792035266179", - ) - .unwrap(), - ), - ); + let result = run_program(&EC_STATE_INIT, "run_test", &[]); + // cant match the values because the state init is a random point + assert!(matches!(result.return_value, JitValue::EcState(_, _, _, _))); } #[test] diff --git a/src/libfuncs/felt252.rs b/src/libfuncs/felt252.rs index 2c7ef09bf..e834a109b 100644 --- a/src/libfuncs/felt252.rs +++ b/src/libfuncs/felt252.rs @@ -691,14 +691,11 @@ pub mod test { }; // Helper function to assert that a division panics. - let assert_panics = |lhs, rhs| match run_test(lhs, rhs) { - JitValue::Enum { debug_name, .. } => { - assert_eq!( - debug_name, - Some("core::panics::PanicResult::<(core::felt252,)>".into()) - ); - } - _ => panic!("division by 0 is expected to panic"), + let assert_panics = |lhs, rhs| { + assert!( + matches!(run_test(lhs, rhs), JitValue::Enum { tag, .. } if tag == 1), + "division by 0 is expected to panic", + ) }; // Division by zero is expected to panic. diff --git a/src/libfuncs/gas.rs b/src/libfuncs/gas.rs index 14a6aea8a..da21dbf5b 100644 --- a/src/libfuncs/gas.rs +++ b/src/libfuncs/gas.rs @@ -216,7 +216,7 @@ mod test { let result = run_program(&program, "run_test", &[]); assert_eq!( result.remaining_gas, - Some(340282366920938463463374607431768204835), + Some(340282366920938463463374607431768205035), ); } } diff --git a/src/libfuncs/pedersen.rs b/src/libfuncs/pedersen.rs index b09f6960b..b69b9640f 100644 --- a/src/libfuncs/pedersen.rs +++ b/src/libfuncs/pedersen.rs @@ -18,7 +18,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use melior::{ - dialect::{arith, ods}, + dialect::arith, ir::{r#type::IntegerType, Block, Location}, Context, }; @@ -85,13 +85,8 @@ pub fn build_pedersen<'ctx>( let lhs_i256 = entry.append_op_result(arith::extui(lhs, i256_ty, location))?; let rhs_i256 = entry.append_op_result(arith::extui(rhs, i256_ty, location))?; - let lhs_be = - entry.append_op_result(ods::llvm::intr_bswap(context, lhs_i256, location).into())?; - let rhs_be = - entry.append_op_result(ods::llvm::intr_bswap(context, rhs_i256, location).into())?; - - entry.store(context, location, lhs_ptr, lhs_be)?; - entry.store(context, location, rhs_ptr, rhs_be)?; + entry.store(context, location, lhs_ptr, lhs_i256)?; + entry.store(context, location, rhs_ptr, rhs_i256)?; let runtime_bindings = metadata .get_mut::() @@ -100,9 +95,8 @@ pub fn build_pedersen<'ctx>( runtime_bindings .libfunc_pedersen(context, helper, entry, dst_ptr, lhs_ptr, rhs_ptr, location)?; - let result_be = entry.load(context, location, dst_ptr, i256_ty)?; - let op = entry.append_op_result(ods::llvm::intr_bswap(context, result_be, location).into())?; - let result = entry.append_op_result(arith::trunci(op, felt252_ty, location))?; + let result = entry.load(context, location, dst_ptr, i256_ty)?; + let result = entry.append_op_result(arith::trunci(result, felt252_ty, location))?; entry.append_operation(helper.br(0, &[pedersen_builtin, result], location)); Ok(()) diff --git a/src/libfuncs/poseidon.rs b/src/libfuncs/poseidon.rs index a9926caf9..9d5ad0766 100644 --- a/src/libfuncs/poseidon.rs +++ b/src/libfuncs/poseidon.rs @@ -18,7 +18,7 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use melior::{ - dialect::{arith, llvm, ods}, + dialect::{arith, ods}, ir::{r#type::IntegerType, Block, Location}, Context, }; @@ -91,13 +91,9 @@ pub fn build_hades_permutation<'ctx>( let op2_i256 = entry.append_op_result(ods::arith::extui(context, i256_ty, op2, location).into())?; - let op0_be = entry.append_op_result(llvm::intr_bswap(op0_i256, i256_ty, location))?; - let op1_be = entry.append_op_result(llvm::intr_bswap(op1_i256, i256_ty, location))?; - let op2_be = entry.append_op_result(llvm::intr_bswap(op2_i256, i256_ty, location))?; - - entry.store(context, location, op0_ptr, op0_be)?; - entry.store(context, location, op1_ptr, op1_be)?; - entry.store(context, location, op2_ptr, op2_be)?; + entry.store(context, location, op0_ptr, op0_i256)?; + entry.store(context, location, op1_ptr, op1_i256)?; + entry.store(context, location, op2_ptr, op2_i256)?; let runtime_bindings = metadata .get_mut::() @@ -106,13 +102,9 @@ pub fn build_hades_permutation<'ctx>( runtime_bindings .libfunc_hades_permutation(context, helper, entry, op0_ptr, op1_ptr, op2_ptr, location)?; - let op0_be = entry.load(context, location, op0_ptr, i256_ty)?; - let op1_be = entry.load(context, location, op1_ptr, i256_ty)?; - let op2_be = entry.load(context, location, op2_ptr, i256_ty)?; - - let op0_i256 = entry.append_op_result(llvm::intr_bswap(op0_be, i256_ty, location))?; - let op1_i256 = entry.append_op_result(llvm::intr_bswap(op1_be, i256_ty, location))?; - let op2_i256 = entry.append_op_result(llvm::intr_bswap(op2_be, i256_ty, location))?; + let op0_i256 = entry.load(context, location, op0_ptr, i256_ty)?; + let op1_i256 = entry.load(context, location, op1_ptr, i256_ty)?; + let op2_i256 = entry.load(context, location, op2_ptr, i256_ty)?; let op0 = entry.append_op_result(arith::trunci(op0_i256, felt252_ty, location))?; let op1 = entry.append_op_result(arith::trunci(op1_i256, felt252_ty, location))?; diff --git a/src/libfuncs/sint16.rs b/src/libfuncs/sint16.rs index bca217957..e29c853f4 100644 --- a/src/libfuncs/sint16.rs +++ b/src/libfuncs/sint16.rs @@ -496,9 +496,9 @@ mod test { } }; static ref I16_WIDEMUL: (String, Program) = load_cairo! { - use integer::i16_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: i16, rhs: i16) -> i32 { - i16_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/sint32.rs b/src/libfuncs/sint32.rs index 26619a824..0544d5c85 100644 --- a/src/libfuncs/sint32.rs +++ b/src/libfuncs/sint32.rs @@ -496,9 +496,9 @@ mod test { } }; static ref I32_WIDEMUL: (String, Program) = load_cairo! { - use integer::i32_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: i32, rhs: i32) -> i64 { - i32_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/sint64.rs b/src/libfuncs/sint64.rs index df918dc0a..2927b9dd6 100644 --- a/src/libfuncs/sint64.rs +++ b/src/libfuncs/sint64.rs @@ -496,9 +496,9 @@ mod test { } }; static ref I64_WIDEMUL: (String, Program) = load_cairo! { - use integer::i64_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: i64, rhs: i64) -> i128 { - i64_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/sint8.rs b/src/libfuncs/sint8.rs index 75eb4994d..da48ee886 100644 --- a/src/libfuncs/sint8.rs +++ b/src/libfuncs/sint8.rs @@ -498,9 +498,9 @@ mod test { } }; static ref I8_WIDEMUL: (String, Program) = load_cairo! { - use integer::i8_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: i8, rhs: i8) -> i16 { - i8_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/starknet.rs b/src/libfuncs/starknet.rs index e005aa5a0..34b4d469c 100644 --- a/src/libfuncs/starknet.rs +++ b/src/libfuncs/starknet.rs @@ -141,6 +141,15 @@ pub fn build<'ctx, 'this>( StarkNetConcreteLibfunc::Secp256(selector) => self::secp256::build( context, registry, entry, location, helper, metadata, selector, ), + StarkNetConcreteLibfunc::Sha256ProcessBlock(info) => build_sha256_process_block_syscall( + context, registry, entry, location, helper, metadata, info, + ), + StarkNetConcreteLibfunc::Sha256StateHandleInit(info) => build_sha256_state_handle_init( + context, registry, entry, location, helper, metadata, info, + ), + StarkNetConcreteLibfunc::Sha256StateHandleDigest(info) => build_sha256_state_handle_digest( + context, registry, entry, location, helper, metadata, info, + ), #[cfg(feature = "with-cheatcode")] StarkNetConcreteLibfunc::Testing(TestingConcreteLibfunc::Cheatcode(info)) => { self::testing::build(context, registry, entry, location, helper, metadata, info) @@ -3946,6 +3955,308 @@ pub fn build_send_message_to_l1<'ctx, 'this>( Ok(()) } +/// +/// From the corelib +/// ```text, no_run +/// // Initializes a new SHA-256 state handle. +/// extern fn sha256_state_handle_init(state: Box<[u32; 8]>) -> Sha256StateHandle nopanic; +/// ``` +pub fn build_sha256_state_handle_init<'ctx, 'this>( + _context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let value = entry.argument(0)?.into(); + entry.append_operation(helper.br(0, &[value], location)); + Ok(()) +} + +/// +/// From the corelib +/// ```text, no_run +/// // Initializes a new SHA-256 state handle. +/// extern fn sha256_state_handle_digest(state: Sha256StateHandle) -> Box<[u32; 8]> nopanic; +/// ``` +pub fn build_sha256_state_handle_digest<'ctx, 'this>( + _context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _metadata: &mut MetadataStorage, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + let value = entry.argument(0)?.into(); + entry.append_operation(helper.br(0, &[value], location)); + Ok(()) +} + +pub fn build_sha256_process_block_syscall<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> { + // todo: do + // Extract self pointer. + let ptr = entry + .append_operation(llvm::load( + context, + entry.argument(1)?.into(), + llvm::r#type::pointer(context, 0), + location, + LoadStoreOptions::default(), + )) + .result(0)? + .into(); + + // Allocate space for the return value. + let (result_layout, (result_tag_ty, result_tag_layout), variant_tys) = + crate::types::r#enum::get_type_for_variants( + context, + helper, + registry, + metadata, + &[ + info.branch_signatures()[0].vars[2].ty.clone(), + info.branch_signatures()[1].vars[2].ty.clone(), + ], + )?; + + let k1 = helper + .init_block() + .append_operation(arith::constant( + context, + IntegerAttribute::new(IntegerType::new(context, 64).into(), 1).into(), + location, + )) + .result(0)? + .into(); + let result_ptr = helper + .init_block() + .append_operation( + OperationBuilder::new("llvm.alloca", location) + .add_attributes(&[ + ( + Identifier::new(context, "alignment"), + IntegerAttribute::new( + IntegerType::new(context, 64).into(), + result_layout.align().try_into()?, + ) + .into(), + ), + ( + Identifier::new(context, "elem_type"), + TypeAttribute::new(llvm::r#type::r#struct( + context, + &[ + result_tag_ty, + llvm::r#type::array( + IntegerType::new(context, 8).into(), + (result_layout.size() - 1).try_into()?, + ), + ], + false, + )) + .into(), + ), + ]) + .add_operands(&[k1]) + .add_results(&[llvm::r#type::pointer(context, 0)]) + .build()?, + ) + .result(0)? + .into(); + + // Allocate space and write the current gas. + let gas_builtin_ptr = helper.init_block().alloca1( + context, + location, + IntegerType::new(context, 128).into(), + get_integer_layout(128).align(), + )?; + entry.append_operation(llvm::store( + context, + entry.argument(0)?.into(), + gas_builtin_ptr, + location, + LoadStoreOptions::default(), + )); + + let sha256_prev_state_ptr = entry.argument(2)?.into(); + let sha256_current_block_ptr = entry.argument(3)?.into(); + + let fn_ptr = entry + .append_operation(llvm::get_element_ptr( + context, + entry.argument(1)?.into(), + DenseI32ArrayAttribute::new( + context, + &[StarknetSyscallHandlerCallbacks::<()>::SHA256_PROCESS_BLOCK.try_into()?], + ), + llvm::r#type::pointer(context, 0), + llvm::r#type::pointer(context, 0), + location, + )) + .result(0)? + .into(); + let fn_ptr = entry + .append_operation(llvm::load( + context, + fn_ptr, + llvm::r#type::pointer(context, 0), + location, + LoadStoreOptions::default(), + )) + .result(0)? + .into(); + + entry.append_operation( + OperationBuilder::new("llvm.call", location) + .add_operands(&[ + fn_ptr, + result_ptr, + ptr, + gas_builtin_ptr, + sha256_prev_state_ptr, + sha256_current_block_ptr, + ]) + .build()?, + ); + + let result = entry + .append_operation(llvm::load( + context, + result_ptr, + llvm::r#type::r#struct( + context, + &[ + result_tag_ty, + llvm::r#type::array( + IntegerType::new(context, 8).into(), + (result_layout.size() - 1).try_into()?, + ), + ], + false, + ), + location, + LoadStoreOptions::default(), + )) + .result(0)? + .into(); + let result_tag = entry + .append_operation(llvm::extract_value( + context, + result, + DenseI64ArrayAttribute::new(context, &[0]), + IntegerType::new(context, 1).into(), + location, + )) + .result(0)? + .into(); + + let payload_ok = { + let ptr = entry + .append_operation( + OperationBuilder::new("llvm.getelementptr", location) + .add_attributes(&[ + ( + Identifier::new(context, "rawConstantIndices"), + DenseI32ArrayAttribute::new( + context, + &[result_tag_layout.extend(variant_tys[0].1)?.1.try_into()?], + ) + .into(), + ), + ( + Identifier::new(context, "elem_type"), + TypeAttribute::new(IntegerType::new(context, 8).into()).into(), + ), + ]) + .add_operands(&[result_ptr]) + .add_results(&[llvm::r#type::pointer(context, 0)]) + .build()?, + ) + .result(0)? + .into(); + entry + .append_operation(llvm::load( + context, + ptr, + variant_tys[0].0, + location, + LoadStoreOptions::default(), + )) + .result(0)? + .into() + }; + let payload_err = { + let ptr = entry + .append_operation( + OperationBuilder::new("llvm.getelementptr", location) + .add_attributes(&[ + ( + Identifier::new(context, "rawConstantIndices"), + DenseI32ArrayAttribute::new( + context, + &[result_tag_layout.extend(variant_tys[1].1)?.1.try_into()?], + ) + .into(), + ), + ( + Identifier::new(context, "elem_type"), + TypeAttribute::new(IntegerType::new(context, 8).into()).into(), + ), + ]) + .add_operands(&[result_ptr]) + .add_results(&[llvm::r#type::pointer(context, 0)]) + .build()?, + ) + .result(0)? + .into(); + entry + .append_operation(llvm::load( + context, + ptr, + variant_tys[1].0, + location, + LoadStoreOptions::default(), + )) + .result(0)? + .into() + }; + + let remaining_gas = entry + .append_operation(llvm::load( + context, + gas_builtin_ptr, + IntegerType::new(context, 128).into(), + location, + LoadStoreOptions::default(), + )) + .result(0)? + .into(); + + entry.append_operation(helper.cond_br( + context, + result_tag, + [1, 0], + [ + &[remaining_gas, entry.argument(1)?.into(), payload_err], + &[remaining_gas, entry.argument(1)?.into(), payload_ok], + ], + location, + )); + Ok(()) +} + #[cfg(test)] mod test { use crate::utils::test::{jit_enum, jit_struct, load_cairo, run_program_assert_output}; diff --git a/src/libfuncs/uint128.rs b/src/libfuncs/uint128.rs index 49aa1fc4f..e50823f00 100644 --- a/src/libfuncs/uint128.rs +++ b/src/libfuncs/uint128.rs @@ -632,9 +632,9 @@ mod test { } }; static ref U128_WIDEMUL: (String, Program) = load_cairo! { - use integer::u128_wide_mul; - fn run_test(lhs: u128, rhs: u128) -> (u128, u128) { - u128_wide_mul(lhs, rhs) + use core::num::traits::WideMul; + fn run_test(lhs: u128, rhs: u128) -> u256 { + WideMul::wide_mul(lhs,rhs) } }; static ref U128_TO_FELT252: (String, Program) = load_cairo! { @@ -645,14 +645,21 @@ mod test { } }; static ref U128_SQRT: (String, Program) = load_cairo! { - use core::integer::u128_sqrt; - + use core::num::traits::Sqrt; fn run_test(value: u128) -> u64 { - u128_sqrt(value) + value.sqrt() } }; } + fn u256(value: BigUint) -> JitValue { + assert!(value.bits() <= 256); + jit_struct!( + JitValue::Uint128((&value & &u128::MAX.into()).try_into().unwrap()), + JitValue::Uint128(((&value >> 128u32) & &u128::MAX.into()).try_into().unwrap()), + ) + } + #[test] fn u128_byte_reverse() { run_program_assert_output( @@ -969,31 +976,31 @@ mod test { program, "run_test", &[0u128.into(), 0u128.into()], - jit_struct!(0u128.into(), 0u128.into()), + u256(0u32.into()), ); run_program_assert_output( program, "run_test", &[0u128.into(), 1u128.into()], - jit_struct!(0u128.into(), 0u128.into()), + u256(0u32.into()), ); run_program_assert_output( program, "run_test", &[1u128.into(), 0u128.into()], - jit_struct!(0u128.into(), 0u128.into()), + u256(0u32.into()), ); run_program_assert_output( program, "run_test", &[1u128.into(), 1u128.into()], - jit_struct!(0u128.into(), 1u128.into()), + u256(1u32.into()), ); run_program_assert_output( program, "run_test", &[u128::MAX.into(), u128::MAX.into()], - jit_struct!((u128::MAX - 1).into(), 1u128.into()), + u256(BigUint::from(u128::MAX) * BigUint::from(u128::MAX)), ); } } diff --git a/src/libfuncs/uint16.rs b/src/libfuncs/uint16.rs index 61ebe2712..89aac52a9 100644 --- a/src/libfuncs/uint16.rs +++ b/src/libfuncs/uint16.rs @@ -595,16 +595,15 @@ mod test { } }; static ref U16_SQRT: (String, Program) = load_cairo! { - use core::integer::u16_sqrt; - + use core::num::traits::Sqrt; fn run_test(value: u16) -> u8 { - u16_sqrt(value) + value.sqrt() } }; static ref U16_WIDEMUL: (String, Program) = load_cairo! { - use integer::u16_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: u16, rhs: u16) -> u32 { - u16_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/uint256.rs b/src/libfuncs/uint256.rs index 4e2e077f4..2a96bb512 100644 --- a/src/libfuncs/uint256.rs +++ b/src/libfuncs/uint256.rs @@ -1021,10 +1021,10 @@ mod test { } }; static ref U256_SQRT: (String, Program) = load_cairo! { - use core::integer::u256_sqrt; + use core::num::traits::Sqrt; fn run_test(value: u256) -> u128 { - u256_sqrt(value) + value.sqrt() } }; static ref U256_INV_MOD_N: (String, Program) = load_cairo! { diff --git a/src/libfuncs/uint32.rs b/src/libfuncs/uint32.rs index ebc3f7a73..b33b58025 100644 --- a/src/libfuncs/uint32.rs +++ b/src/libfuncs/uint32.rs @@ -563,16 +563,16 @@ mod test { } }; static ref U32_SQRT: (String, Program) = load_cairo! { - use core::integer::u32_sqrt; + use core::num::traits::Sqrt; fn run_test(value: u32) -> u16 { - u32_sqrt(value) + value.sqrt() } }; static ref U32_WIDEMUL: (String, Program) = load_cairo! { - use integer::u32_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: u32, rhs: u32) -> u64 { - u32_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/uint64.rs b/src/libfuncs/uint64.rs index 6164bf564..52598b86c 100644 --- a/src/libfuncs/uint64.rs +++ b/src/libfuncs/uint64.rs @@ -563,16 +563,16 @@ mod test { } }; static ref U64_SQRT: (String, Program) = load_cairo! { - use core::integer::u64_sqrt; + use core::num::traits::Sqrt; fn run_test(value: u64) -> u32 { - u64_sqrt(value) + value.sqrt() } }; static ref U64_WIDEMUL: (String, Program) = load_cairo! { - use integer::u64_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: u64, rhs: u64) -> u128 { - u64_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/libfuncs/uint8.rs b/src/libfuncs/uint8.rs index 6424d3e7d..c3b127c08 100644 --- a/src/libfuncs/uint8.rs +++ b/src/libfuncs/uint8.rs @@ -560,16 +560,15 @@ mod test { } }; static ref U8_SQRT: (String, Program) = load_cairo! { - use core::integer::u8_sqrt; - + use core::num::traits::Sqrt; fn run_test(value: u8) -> u8 { - u8_sqrt(value) + value.sqrt() } }; static ref U8_WIDEMUL: (String, Program) = load_cairo! { - use integer::u8_wide_mul; + use core::num::traits::WideMul; fn run_test(lhs: u8, rhs: u8) -> u16 { - u8_wide_mul(lhs, rhs) + WideMul::wide_mul(lhs,rhs) } }; } diff --git a/src/metadata/runtime_bindings.rs b/src/metadata/runtime_bindings.rs index 4a487f22f..a6fa26267 100644 --- a/src/metadata/runtime_bindings.rs +++ b/src/metadata/runtime_bindings.rs @@ -21,6 +21,7 @@ enum RuntimeBinding { HadesPermutation, EcStateTryFinalizeNz, EcStateAddMul, + EcStateInit, EcStateAdd, EcPointTryNewNz, EcPointFromXNz, @@ -278,6 +279,43 @@ impl RuntimeBindingsMeta { ))) } + /// Register if necessary, then invoke the `ec_state_init()` function. + pub fn libfunc_ec_state_init<'c, 'a>( + &mut self, + context: &'c Context, + module: &Module, + block: &'a Block<'c>, + state_ptr: Value<'c, '_>, + location: Location<'c>, + ) -> Result> + where + 'c: 'a, + { + if self.active_map.insert(RuntimeBinding::EcStateInit) { + module.body().append_operation(func::func( + context, + StringAttribute::new(context, "cairo_native__libfunc__ec__ec_state_init"), + TypeAttribute::new( + FunctionType::new(context, &[llvm::r#type::pointer(context, 0)], &[]).into(), + ), + Region::new(), + &[( + Identifier::new(context, "sym_visibility"), + StringAttribute::new(context, "private").into(), + )], + Location::unknown(context), + )); + } + + Ok(block.append_operation(func::call( + context, + FlatSymbolRefAttribute::new(context, "cairo_native__libfunc__ec__ec_state_init"), + &[state_ptr], + &[], + location, + ))) + } + /// Register if necessary, then invoke the `ec_state_add()` function. pub fn libfunc_ec_state_add<'c, 'a>( &mut self, diff --git a/src/starknet.rs b/src/starknet.rs index 671235fc4..7339f913b 100644 --- a/src/starknet.rs +++ b/src/starknet.rs @@ -242,6 +242,13 @@ pub trait StarknetSyscallHandler { remaining_gas: &mut u128, ) -> SyscallResult<(U256, U256)>; + fn sha256_process_block( + &mut self, + prev_state: &[u32; 8], + current_block: &[u32; 16], + remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]>; + #[cfg(feature = "with-cheatcode")] fn cheatcode(&mut self, _selector: Felt, _input: &[Felt]) -> Vec { unimplemented!(); @@ -433,6 +440,15 @@ impl StarknetSyscallHandler for DummySyscallHandler { ) -> SyscallResult<(U256, U256)> { unimplemented!() } + + fn sha256_process_block( + &mut self, + _prev_state: &[u32; 8], + _current_block: &[u32; 16], + _remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]> { + unimplemented!() + } } // TODO: Move to the correct place or remove if unused. @@ -700,6 +716,13 @@ pub(crate) mod handler { gas: &mut u128, p: &Secp256r1Point, ), + sha256_process_block: extern "C" fn( + result_ptr: &mut SyscallResultAbi<*mut [u32; 8]>, + ptr: &mut T, + gas: &mut u128, + prev_state: &[u32; 8], + current_block: &[u32; 16], + ), // testing syscalls #[cfg(feature = "with-cheatcode")] pub cheatcode: extern "C" fn( @@ -740,6 +763,7 @@ pub(crate) mod handler { pub const SECP256R1_GET_POINT_FROM_X: usize = field_offset!(Self, secp256r1_get_point_from_x) >> 3; pub const SECP256R1_GET_XY: usize = field_offset!(Self, secp256r1_get_xy) >> 3; + pub const SHA256_PROCESS_BLOCK: usize = field_offset!(Self, sha256_process_block) >> 3; } #[allow(unused_variables)] @@ -772,6 +796,7 @@ pub(crate) mod handler { secp256r1_mul: Self::wrap_secp256r1_mul, secp256r1_get_point_from_x: Self::wrap_secp256r1_get_point_from_x, secp256r1_get_xy: Self::wrap_secp256r1_get_xy, + sha256_process_block: Self::wrap_sha256_process_block, #[cfg(feature = "with-cheatcode")] cheatcode: Self::wrap_cheatcode, } @@ -1644,6 +1669,36 @@ pub(crate) mod handler { Err(e) => Self::wrap_error(&e), }; } + + extern "C" fn wrap_sha256_process_block( + result_ptr: &mut SyscallResultAbi<*mut [u32; 8]>, + ptr: &mut T, + gas: &mut u128, + prev_state: &[u32; 8], + current_block: &[u32; 16], + ) { + let result = ptr.sha256_process_block(prev_state, current_block, gas); + + *result_ptr = match result { + Ok(x) => SyscallResultAbi { + ok: ManuallyDrop::new(SyscallResultAbiOk { + tag: 0u8, + payload: ManuallyDrop::new({ + unsafe { + let data = libc::malloc(std::mem::size_of_val(&x)).cast(); + std::ptr::copy_nonoverlapping::( + x.as_ptr().cast(), + data, + x.len(), + ); + data.cast() + } + }), + }), + }, + Err(e) => Self::wrap_error(&e), + }; + } } } diff --git a/src/starknet_stub.rs b/src/starknet_stub.rs index 9d5361912..82b6a860d 100644 --- a/src/starknet_stub.rs +++ b/src/starknet_stub.rs @@ -819,6 +819,23 @@ impl StarknetSyscallHandler for &mut StubSyscallHandler { _ => vec![], } } + + fn sha256_process_block( + &mut self, + prev_state: &[u32; 8], + current_block: &[u32; 16], + _remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]> { + // reference impl + // https://github.com/starkware-libs/cairo/blob/ba3f82b4a09972b6a24bf791e344cabce579bf69/crates/cairo-lang-runner/src/casm_run/mod.rs#L1292 + let mut state = *prev_state; + let data_as_bytes = sha2::digest::generic_array::GenericArray::from_exact_iter( + current_block.iter().flat_map(|x| x.to_be_bytes()), + ) + .unwrap(); + sha2::compress256(&mut state, &[data_as_bytes]); + Ok(state) + } } #[cfg(test)] diff --git a/src/types.rs b/src/types.rs index fbcb334c5..e57998db4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,6 +3,7 @@ //! Contains type generation stuff (aka. conversion from Sierra to MLIR types). use crate::block_ext::BlockExt; +use crate::utils::RangeExt; use crate::{ error::Error as CoreTypeBuilderError, libfuncs::LibfuncHelper, @@ -12,6 +13,8 @@ use crate::{ }, utils::{get_integer_layout, layout_repeat, ProgramRegistryExt}, }; +use cairo_lang_sierra::extensions::circuit::CircuitTypeConcrete; +use cairo_lang_sierra::extensions::utils::Range; use cairo_lang_sierra::{ extensions::{ core::{CoreLibfunc, CoreType, CoreTypeConcrete}, @@ -21,6 +24,7 @@ use cairo_lang_sierra::{ program::GenericArg, program_registry::ProgramRegistry, }; +use felt252::PRIME; use melior::{ dialect::{ llvm::{self, r#type::pointer}, @@ -29,7 +33,8 @@ use melior::{ ir::{r#type::IntegerType, Block, Location, Module, Type, Value}, Context, }; -use num_traits::Signed; +use num_bigint::{BigInt, ToBigInt}; +use num_traits::{Bounded, One}; use std::{alloc::Layout, error::Error, ops::Deref, sync::OnceLock}; pub mod array; @@ -38,6 +43,7 @@ pub mod bounded_int; pub mod r#box; pub mod builtin_costs; pub mod bytes31; +pub mod circuit; pub mod coupon; pub mod ec_op; pub mod ec_point; @@ -102,13 +108,15 @@ pub trait TypeBuilder { /// a function invocation argument or return value. fn is_memory_allocated(&self, registry: &ProgramRegistry) -> bool; - /// If the type is an integer type, return its width in bits. - /// - /// TODO: How is it used? - fn integer_width(&self) -> Option; + /// If the type is an integer, return its value range. + fn integer_range(&self, registry: &ProgramRegistry) -> Option; - /// If the type is an integer type, return if its signed. - fn is_integer_signed(&self) -> Option; + /// Return whether the type is a `BoundedInt<>`, either directly or indirectly (ex. through + /// `NonZero>`). + fn is_bounded_int(&self, registry: &ProgramRegistry) -> bool; + /// Return whether the type is a `felt252`, either directly or indirectly (ex. through + /// `NonZero>`). + fn is_felt252(&self, registry: &ProgramRegistry) -> bool; /// If the type is a enum type, return all possible variants. /// @@ -283,6 +291,13 @@ impl TypeBuilder for CoreTypeConcrete { metadata, WithSelf::new(self_ty, info), ), + Self::RangeCheck96(info) => self::range_check::build( + context, + module, + registry, + metadata, + WithSelf::new(self_ty, info), + ), Self::SegmentArena(info) => self::segment_arena::build( context, module, @@ -410,6 +425,13 @@ impl TypeBuilder for CoreTypeConcrete { metadata, WithSelf::new(self_ty, info), ), + CoreTypeConcrete::Circuit(info) => self::circuit::build( + context, + module, + registry, + metadata, + WithSelf::new(self_ty, info), + ), } } @@ -421,11 +443,14 @@ impl TypeBuilder for CoreTypeConcrete { | CoreTypeConcrete::GasBuiltin(_) | CoreTypeConcrete::BuiltinCosts(_) | CoreTypeConcrete::RangeCheck(_) + | CoreTypeConcrete::RangeCheck96(_) | CoreTypeConcrete::Pedersen(_) | CoreTypeConcrete::Poseidon(_) | CoreTypeConcrete::Coupon(_) | CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::System(_)) | CoreTypeConcrete::SegmentArena(_) + | CoreTypeConcrete::Circuit(CircuitTypeConcrete::AddMod(_)) + | CoreTypeConcrete::Circuit(CircuitTypeConcrete::MulMod(_)) ) } @@ -439,6 +464,7 @@ impl TypeBuilder for CoreTypeConcrete { | CoreTypeConcrete::RangeCheck(_) | CoreTypeConcrete::Pedersen(_) | CoreTypeConcrete::Poseidon(_) + | CoreTypeConcrete::RangeCheck96(_) | CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::System(_)) // u64 is not complex | CoreTypeConcrete::SegmentArena(_) => false, @@ -491,11 +517,22 @@ impl TypeBuilder for CoreTypeConcrete { }, CoreTypeConcrete::Struct(_) => true, - CoreTypeConcrete::BoundedInt(_) => todo!(), + CoreTypeConcrete::BoundedInt(_info) => { + #[cfg(target_arch = "x86_64")] + let value = _info.range.offset_bit_width() > 128; + + #[cfg(target_arch = "aarch64")] + let value = false; + + value + }, CoreTypeConcrete::Const(_) => todo!(), CoreTypeConcrete::Span(_) => todo!(), - CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::Secp256Point(_)) => todo!(), + CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::Secp256Point(_)) + | CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::Sha256StateHandle(_)) => todo!(), CoreTypeConcrete::Coupon(_) => false, + + CoreTypeConcrete::Circuit(info) => circuit::is_complex(info) } } @@ -507,6 +544,7 @@ impl TypeBuilder for CoreTypeConcrete { | CoreTypeConcrete::RangeCheck(_) | CoreTypeConcrete::Pedersen(_) | CoreTypeConcrete::Poseidon(_) + | CoreTypeConcrete::RangeCheck96(_) | CoreTypeConcrete::SegmentArena(_) => false, // Other builtins: CoreTypeConcrete::BuiltinCosts(_) @@ -565,6 +603,7 @@ impl TypeBuilder for CoreTypeConcrete { type_info.is_zst(registry) } CoreTypeConcrete::Span(_) => todo!(), + CoreTypeConcrete::Circuit(info) => circuit::is_zst(info), } } @@ -653,6 +692,7 @@ impl TypeBuilder for CoreTypeConcrete { .unwrap() .0 } + StarkNetTypeConcrete::Sha256StateHandle(_) => Layout::new::<*mut ()>(), }, CoreTypeConcrete::SegmentArena(_) => Layout::new::(), CoreTypeConcrete::Snapshot(info) => registry.get_type(&info.ty)?.layout(registry)?, @@ -662,15 +702,14 @@ impl TypeBuilder for CoreTypeConcrete { CoreTypeConcrete::Sint64(_) => get_integer_layout(64), CoreTypeConcrete::Sint128(_) => get_integer_layout(128), CoreTypeConcrete::Bytes31(_) => get_integer_layout(248), - CoreTypeConcrete::BoundedInt(info) => get_integer_layout( - (info.range.lower.bits().max(info.range.upper.bits()) + 1) - .try_into() - .expect("should always fit u32"), - ), + CoreTypeConcrete::BoundedInt(info) => get_integer_layout(info.range.offset_bit_width()), + CoreTypeConcrete::Const(const_type) => { registry.get_type(&const_type.inner_ty)?.layout(registry)? } CoreTypeConcrete::Coupon(_) => Layout::new::<()>(), + CoreTypeConcrete::RangeCheck96(_) => get_integer_layout(64), + CoreTypeConcrete::Circuit(info) => circuit::layout(registry, info)?, } .pad_to_align()) } @@ -702,6 +741,7 @@ impl TypeBuilder for CoreTypeConcrete { CoreTypeConcrete::NonZero(_) => false, CoreTypeConcrete::Nullable(_) => false, CoreTypeConcrete::RangeCheck(_) => false, + CoreTypeConcrete::RangeCheck96(_) => false, CoreTypeConcrete::Uninitialized(_) => false, CoreTypeConcrete::Enum(info) => { // Enums are memory-allocated if either: @@ -746,52 +786,76 @@ impl TypeBuilder for CoreTypeConcrete { .unwrap() .is_memory_allocated(registry), CoreTypeConcrete::Coupon(_) => false, + CoreTypeConcrete::Circuit(_) => false, } } - fn integer_width(&self) -> Option { + fn integer_range(&self, registry: &ProgramRegistry) -> Option { + fn range_of() -> Range + where + T: Bounded + Into, + { + Range { + lower: T::min_value().into(), + upper: T::max_value().into() + BigInt::one(), + } + } + + Some(match self { + Self::Uint8(_) => range_of::(), + Self::Uint16(_) => range_of::(), + Self::Uint32(_) => range_of::(), + Self::Uint64(_) => range_of::(), + Self::Uint128(_) => range_of::(), + Self::Felt252(_) => Range { + lower: BigInt::ZERO, + upper: PRIME.to_bigint().unwrap(), + }, + Self::Sint8(_) => range_of::(), + Self::Sint16(_) => range_of::(), + Self::Sint32(_) => range_of::(), + Self::Sint64(_) => range_of::(), + Self::Sint128(_) => range_of::(), + + Self::BoundedInt(info) => info.range.clone(), + Self::Bytes31(_) => Range { + lower: BigInt::ZERO, + upper: BigInt::one() << 248, + }, + Self::Const(info) => { + return registry + .get_type(&info.inner_ty) + .unwrap() + .integer_range(registry) + } + Self::NonZero(info) => { + return registry.get_type(&info.ty).unwrap().integer_range(registry) + } + + _ => return None, + }) + } + + fn is_bounded_int(&self, registry: &ProgramRegistry) -> bool { match self { - Self::Uint8(_) => Some(8), - Self::Uint16(_) => Some(16), - Self::Uint32(_) => Some(32), - Self::Uint64(_) => Some(64), - Self::Uint128(_) => Some(128), - Self::Felt252(_) => Some(252), - Self::Sint8(_) => Some(8), - Self::Sint16(_) => Some(16), - Self::Sint32(_) => Some(32), - Self::Sint64(_) => Some(64), - Self::Sint128(_) => Some(128), - - CoreTypeConcrete::BoundedInt(_) => Some(252), - CoreTypeConcrete::Bytes31(_) => Some(248), - CoreTypeConcrete::Const(_) => todo!(), + CoreTypeConcrete::BoundedInt(_) => true, + CoreTypeConcrete::NonZero(info) => registry + .get_type(&info.ty) + .unwrap() + .is_bounded_int(registry), - _ => None, + _ => false, } } - fn is_integer_signed(&self) -> Option { + fn is_felt252(&self, registry: &ProgramRegistry) -> bool { match self { - Self::Uint8(_) => Some(false), - Self::Uint16(_) => Some(false), - Self::Uint32(_) => Some(false), - Self::Uint64(_) => Some(false), - Self::Uint128(_) => Some(false), - Self::Felt252(_) => Some(true), - Self::Sint8(_) => Some(true), - Self::Sint16(_) => Some(true), - Self::Sint32(_) => Some(true), - Self::Sint64(_) => Some(true), - Self::Sint128(_) => Some(true), - - CoreTypeConcrete::BoundedInt(info) => { - Some(info.range.lower.is_negative() || info.range.upper.is_negative()) + CoreTypeConcrete::Felt252(_) => true, + CoreTypeConcrete::NonZero(info) => { + registry.get_type(&info.ty).unwrap().is_felt252(registry) } - CoreTypeConcrete::Bytes31(_) => Some(false), - CoreTypeConcrete::Const(_) => todo!(), - _ => None, + _ => false, } } diff --git a/src/types/bounded_int.rs b/src/types/bounded_int.rs index 73d6a1874..f2c34f537 100644 --- a/src/types/bounded_int.rs +++ b/src/types/bounded_int.rs @@ -1,41 +1,36 @@ //! # `BoundedInt` type //! //! A `BoundedInt` is a int with a lower and high bound. +//! +//! It's represented as the offseted range using the minimal number of bits. For example: +//! - 10 as `BoundedInt<10, 20>` is represented as `0 : i4`. +//! - 15 as `BoundedInt<10, 20>` is represented as `5 : i4`. +//! - 1 as `BoundedInt<1, 1>` is represented as `0 : i0`. -use crate::{error::Result, metadata::MetadataStorage}; +use super::WithSelf; +use crate::{error::Result, metadata::MetadataStorage, utils::RangeExt}; use cairo_lang_sierra::{ extensions::{ bounded_int::BoundedIntConcreteType, core::{CoreLibfunc, CoreType}, - types::InfoOnlyConcreteType, }, program_registry::ProgramRegistry, }; use melior::{ - ir::{Module, Type}, + ir::{r#type::IntegerType, Module, Type}, Context, }; -use super::WithSelf; - /// Build the MLIR type. /// /// Check out [the module](self) for more info. pub fn build<'ctx>( context: &'ctx Context, - module: &Module<'ctx>, - registry: &ProgramRegistry, - metadata: &mut MetadataStorage, + _module: &Module<'ctx>, + _registry: &ProgramRegistry, + _metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { - // todo: possible optimization, we may be able to use less bits depending on the possible values within the range. - - let info = WithSelf { - self_ty: info.self_ty, - inner: &InfoOnlyConcreteType { - info: info.info.clone(), - }, - }; - - super::felt252::build(context, module, registry, metadata, info) + let n_bits = info.range.offset_bit_width(); + Ok(IntegerType::new(context, n_bits).into()) } diff --git a/src/types/circuit.rs b/src/types/circuit.rs new file mode 100644 index 000000000..02db15468 --- /dev/null +++ b/src/types/circuit.rs @@ -0,0 +1,288 @@ +//! # `Circuit` type + +use std::alloc::Layout; + +use super::WithSelf; +use crate::{ + error::{Result, SierraAssertError}, + metadata::MetadataStorage, + utils::{get_integer_layout, layout_repeat}, +}; +use cairo_lang_sierra::{ + extensions::{ + circuit::CircuitTypeConcrete, + core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + types::InfoOnlyConcreteType, + }, + program::GenericArg, + program_registry::ProgramRegistry, +}; +use melior::{ + dialect::llvm, + ir::{r#type::IntegerType, Module, Type}, + Context, +}; + +pub const CIRCUIT_INPUT_SIZE: usize = 384; + +/// Build the MLIR type. +/// +/// Check out [the module](self) for more info. +pub fn build<'ctx>( + context: &'ctx Context, + module: &Module<'ctx>, + registry: &ProgramRegistry, + metadata: &mut MetadataStorage, + selector: WithSelf, +) -> Result> { + match &*selector { + CircuitTypeConcrete::CircuitModulus(_) => Ok(IntegerType::new(context, 384).into()), + CircuitTypeConcrete::U96Guarantee(_) => Ok(IntegerType::new(context, 96).into()), + CircuitTypeConcrete::CircuitInputAccumulator(info) => build_circuit_accumulator( + context, + module, + registry, + metadata, + WithSelf::new(selector.self_ty(), info), + ), + CircuitTypeConcrete::CircuitData(info) => build_circuit_data( + context, + module, + registry, + metadata, + WithSelf::new(selector.self_ty(), info), + ), + CircuitTypeConcrete::CircuitOutputs(info) => build_circuit_outputs( + context, + module, + registry, + metadata, + WithSelf::new(selector.self_ty(), info), + ), + // builtins + CircuitTypeConcrete::AddMod(_) + | CircuitTypeConcrete::U96LimbsLessThanGuarantee(_) + | CircuitTypeConcrete::MulMod(_) => Ok(IntegerType::new(context, 64).into()), + // noops + CircuitTypeConcrete::CircuitDescriptor(_) + | CircuitTypeConcrete::CircuitFailureGuarantee(_) + | CircuitTypeConcrete::CircuitPartialOutputs(_) => { + Ok(llvm::r#type::array(IntegerType::new(context, 8).into(), 0)) + } + // phantoms + CircuitTypeConcrete::Circuit(_) + | CircuitTypeConcrete::AddModGate(_) + | CircuitTypeConcrete::SubModGate(_) + | CircuitTypeConcrete::MulModGate(_) + | CircuitTypeConcrete::InverseGate(_) + | CircuitTypeConcrete::CircuitInput(_) => { + Err(SierraAssertError::BadTypeInit(selector.self_ty.clone()))? + } + } +} + +pub fn build_circuit_accumulator<'ctx>( + context: &'ctx Context, + _module: &Module<'ctx>, + registry: &ProgramRegistry, + _metadata: &mut MetadataStorage, + info: WithSelf, +) -> Result> { + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = + registry.get_type(circuit_type_id)? + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + + let n_inputs = circuit.circuit_info.n_inputs; + + let fields = vec![ + IntegerType::new(context, 64).into(), + llvm::r#type::array(IntegerType::new(context, 384).into(), n_inputs as u32 - 1), + ]; + + Ok(llvm::r#type::r#struct(context, &fields, false)) +} + +pub fn build_circuit_data<'ctx>( + context: &'ctx Context, + _module: &Module<'ctx>, + registry: &ProgramRegistry, + _metadata: &mut MetadataStorage, + info: WithSelf, +) -> Result> { + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = + registry.get_type(circuit_type_id)? + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + + let n_inputs = circuit.circuit_info.n_inputs; + + Ok(llvm::r#type::array( + IntegerType::new(context, 384).into(), + n_inputs as u32, + )) +} + +pub fn build_circuit_outputs<'ctx>( + context: &'ctx Context, + _module: &Module<'ctx>, + registry: &ProgramRegistry, + _metadata: &mut MetadataStorage, + info: WithSelf, +) -> Result> { + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = + registry.get_type(circuit_type_id)? + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + + let n_gates = circuit.circuit_info.values.len(); + + Ok(llvm::r#type::array( + IntegerType::new(context, 384).into(), + n_gates as u32, + )) +} + +pub fn is_complex(info: &CircuitTypeConcrete) -> bool { + match *info { + CircuitTypeConcrete::AddMod(_) + | CircuitTypeConcrete::MulMod(_) + | CircuitTypeConcrete::AddModGate(_) + | CircuitTypeConcrete::SubModGate(_) + | CircuitTypeConcrete::MulModGate(_) + | CircuitTypeConcrete::U96Guarantee(_) + | CircuitTypeConcrete::InverseGate(_) + | CircuitTypeConcrete::U96LimbsLessThanGuarantee(_) + | CircuitTypeConcrete::CircuitModulus(_) + | CircuitTypeConcrete::CircuitInput(_) + | CircuitTypeConcrete::Circuit(_) + | CircuitTypeConcrete::CircuitDescriptor(_) + | CircuitTypeConcrete::CircuitFailureGuarantee(_) => false, + + CircuitTypeConcrete::CircuitInputAccumulator(_) + | CircuitTypeConcrete::CircuitPartialOutputs(_) + | CircuitTypeConcrete::CircuitData(_) + | CircuitTypeConcrete::CircuitOutputs(_) => true, + } +} + +pub fn is_zst(info: &CircuitTypeConcrete) -> bool { + match *info { + CircuitTypeConcrete::AddModGate(_) + | CircuitTypeConcrete::SubModGate(_) + | CircuitTypeConcrete::MulModGate(_) + | CircuitTypeConcrete::CircuitInput(_) + | CircuitTypeConcrete::InverseGate(_) + | CircuitTypeConcrete::U96LimbsLessThanGuarantee(_) + | CircuitTypeConcrete::Circuit(_) + | CircuitTypeConcrete::CircuitDescriptor(_) + | CircuitTypeConcrete::CircuitFailureGuarantee(_) => true, + + CircuitTypeConcrete::AddMod(_) + | CircuitTypeConcrete::CircuitModulus(_) + | CircuitTypeConcrete::U96Guarantee(_) + | CircuitTypeConcrete::MulMod(_) + | CircuitTypeConcrete::CircuitInputAccumulator(_) + | CircuitTypeConcrete::CircuitPartialOutputs(_) + | CircuitTypeConcrete::CircuitData(_) + | CircuitTypeConcrete::CircuitOutputs(_) => false, + } +} + +pub fn layout( + registry: &ProgramRegistry, + info: &CircuitTypeConcrete, +) -> Result { + match info { + CircuitTypeConcrete::AddMod(_) | CircuitTypeConcrete::MulMod(_) => { + Ok(get_integer_layout(64)) + } + CircuitTypeConcrete::CircuitModulus(_) => Ok(get_integer_layout(384)), + CircuitTypeConcrete::U96Guarantee(_) => Ok(get_integer_layout(96)), + + CircuitTypeConcrete::AddModGate(_) + | CircuitTypeConcrete::SubModGate(_) + | CircuitTypeConcrete::MulModGate(_) + | CircuitTypeConcrete::CircuitInput(_) + | CircuitTypeConcrete::InverseGate(_) + | CircuitTypeConcrete::U96LimbsLessThanGuarantee(_) + | CircuitTypeConcrete::Circuit(_) + | CircuitTypeConcrete::CircuitDescriptor(_) + | CircuitTypeConcrete::CircuitFailureGuarantee(_) => Ok(Layout::new::<()>()), + + CircuitTypeConcrete::CircuitData(info) => { + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = + registry.get_type(circuit_type_id)? + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + + let n_inputs = circuit.circuit_info.n_inputs; + + let u384_layout = get_integer_layout(384); + + let layout = layout_repeat(&u384_layout, n_inputs)?.0; + + Ok(layout) + } + CircuitTypeConcrete::CircuitOutputs(info) => { + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = + registry.get_type(circuit_type_id)? + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + + let n_gates = circuit.circuit_info.values.len(); + + let u384_layout = get_integer_layout(384); + + let layout = layout_repeat(&u384_layout, n_gates)?.0; + + Ok(layout) + } + CircuitTypeConcrete::CircuitInputAccumulator(info) => { + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = + registry.get_type(circuit_type_id)? + else { + return Err(SierraAssertError::BadTypeInfo.into()); + }; + + let n_inputs = circuit.circuit_info.n_inputs; + + let length_layout = get_integer_layout(64); + + let u384_layout = get_integer_layout(384); + let inputs_layout = layout_repeat(&u384_layout, n_inputs - 1)?.0; + let layout = length_layout.extend(inputs_layout)?.0; + + Ok(layout) + } + CircuitTypeConcrete::CircuitPartialOutputs(_) => { + todo!("CircuitPartialOutputs is noop for now") + } + } +} diff --git a/src/types/starknet.rs b/src/types/starknet.rs index 5d5ded10e..231b8ec5d 100644 --- a/src/types/starknet.rs +++ b/src/types/starknet.rs @@ -90,6 +90,13 @@ pub fn build<'ctx>( metadata, WithSelf::new(selector.self_ty(), info), ), + StarkNetTypeConcrete::Sha256StateHandle(info) => build_sha256_state_handle( + context, + module, + registry, + metadata, + WithSelf::new(selector.self_ty(), info), + ), } } @@ -177,3 +184,14 @@ pub fn build_secp256_point<'ctx>( false, )) } + +pub fn build_sha256_state_handle<'ctx>( + context: &'ctx Context, + _module: &Module<'ctx>, + _registry: &ProgramRegistry, + _metadata: &mut MetadataStorage, + _info: WithSelf, +) -> Result> { + // A ptr to a heap (realloc) allocated [u32; 8] + Ok(llvm::r#type::pointer(context, 0)) +} diff --git a/src/utils.rs b/src/utils.rs index cdd0390ed..8e38e8140 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,7 +7,10 @@ use crate::{ }; use cairo_lang_compiler::CompilerConfig; use cairo_lang_sierra::{ - extensions::core::{CoreLibfunc, CoreType}, + extensions::{ + core::{CoreLibfunc, CoreType}, + utils::Range, + }, ids::{ConcreteTypeId, FunctionId}, program::{GenFunction, Program, StatementIdx}, program_registry::ProgramRegistry, @@ -18,6 +21,7 @@ use melior::{ Context, Error, ExecutionEngine, }; use num_bigint::{BigInt, BigUint, Sign}; +use num_traits::One; use std::{ alloc::Layout, borrow::Cow, @@ -73,8 +77,8 @@ pub fn get_integer_layout(width: u32) -> Layout { Layout::new::().align_to(16).unwrap() } } else { - let width = (width as usize).next_multiple_of(8).next_power_of_two(); - Layout::from_size_align(width >> 3, (width >> 3).min(16)).unwrap() + let width = (width as usize).next_multiple_of(8); + Layout::from_size_align(width >> 3, 16).expect("align should be power of two") } } @@ -247,6 +251,12 @@ pub fn register_runtime_symbols(engine: &ExecutionEngine) { as *mut (), ); + engine.register_symbol( + "cairo_native__libfunc__ec__ec_state_init", + cairo_native_runtime::cairo_native__libfunc__ec__ec_state_init + as *const fn(*mut [[u8; 32]; 4]) as *mut (), + ); + engine.register_symbol( "cairo_native__libfunc__ec__ec_state_add_mul", cairo_native_runtime::cairo_native__libfunc__ec__ec_state_add_mul @@ -491,6 +501,49 @@ impl ProgramRegistryExt for ProgramRegistry { } } +pub trait RangeExt { + /// Width in bits when the offset is zero (aka. the natural representation). + fn zero_based_bit_width(&self) -> u32; + /// Width in bits when the offset is not necessarily zero (aka. the compact representation). + fn offset_bit_width(&self) -> u32; +} + +impl RangeExt for Range { + fn zero_based_bit_width(&self) -> u32 { + // Formula for unsigned integers: + // x.bits() + // + // Formula for signed values: + // - Positive: (x.magnitude() + BigUint::one()).bits() + // - Negative: (x.magnitude() - BigUint::one()).bits() + 1 + // - Zero: 0 + + let width = if self.lower.sign() == Sign::Minus { + let lower_width = (self.lower.magnitude() - BigUint::one()).bits() + 1; + let upper_width = { + let upper = &self.upper - &BigInt::one(); + match upper.sign() { + Sign::Minus => (upper.magnitude() - BigUint::one()).bits() + 1, + Sign::NoSign => 0, + Sign::Plus => (upper.magnitude() + BigUint::one()).bits(), + } + }; + + lower_width.max(upper_width) as u32 + } else { + (&self.upper - &BigInt::one()).bits() as u32 + }; + + // FIXME: Workaround for segfault in canonicalization (including LLVM 19). + width.max(1) + } + + fn offset_bit_width(&self) -> u32 { + // FIXME: Workaround for segfault in canonicalization (including LLVM 19). + ((self.size() - BigInt::one()).bits() as u32).max(1) + } +} + #[cfg(test)] pub mod test { use crate::{ @@ -527,9 +580,9 @@ pub mod test { // Helper macros for faster testing. macro_rules! jit_struct { - ( $($x:expr),* $(,)? ) => { + ($($y:expr),* $(,)? ) => { crate::values::JitValue::Struct { - fields: vec![$($x), *], + fields: vec![$($y), *], debug_name: None } }; @@ -595,7 +648,7 @@ pub mod test { Path::new(&var("CARGO_MANIFEST_DIR").unwrap()).join("corelib/src"), ); let main_crate_ids = setup_project(&mut db, program_file.path()).unwrap(); - let program = compile_prepared_db( + let sierra_program_with_dbg = compile_prepared_db( &mut db, main_crate_ids, CompilerConfig { @@ -608,7 +661,7 @@ pub mod test { let module_name = program_file.path().with_extension(""); let module_name = module_name.file_name().unwrap().to_str().unwrap(); - (module_name.to_string(), program) + (module_name.to_string(), sierra_program_with_dbg.program) } pub fn run_program( diff --git a/src/values.rs b/src/values.rs index edadb2015..49f4fcd00 100644 --- a/src/values.rs +++ b/src/values.rs @@ -3,10 +3,9 @@ //! A Rusty interface to provide parameters to JIT calls. use crate::{ - error::CompilerError, - error::Error, + error::{CompilerError, Error}, types::{felt252::PRIME, TypeBuilder}, - utils::{felt252_bigint, get_integer_layout, layout_repeat, next_multiple_of_usize}, + utils::{felt252_bigint, get_integer_layout, layout_repeat, next_multiple_of_usize, RangeExt}, }; use bumpalo::Bump; use cairo_lang_sierra::{ @@ -20,10 +19,10 @@ use cairo_lang_sierra::{ }; use cairo_native_runtime::FeltDict; use educe::Educe; -use num_bigint::{BigInt, Sign, ToBigInt}; -use num_traits::Euclid; +use num_bigint::{BigInt, BigUint, Sign, ToBigInt}; +use num_traits::{Euclid, One}; use starknet_types_core::felt::Felt; -use std::{alloc::Layout, collections::HashMap, ops::Neg, ptr::NonNull}; +use std::{alloc::Layout, collections::HashMap, ops::Neg, ptr::NonNull, slice}; /// A JitValue is a value that can be passed to the JIT engine as an argument or received as a result. /// @@ -761,6 +760,7 @@ impl JitValue { Secp256PointTypeConcrete::R1(_) => JitValue::Secp256R1Point { x, y }, } } + StarkNetTypeConcrete::Sha256StateHandle(_) => todo!(), }, CoreTypeConcrete::Span(_) => todo!("implement span from_jit"), CoreTypeConcrete::Snapshot(info) => Self::from_jit(ptr, &info.ty, registry), @@ -771,14 +771,24 @@ impl JitValue { CoreTypeConcrete::Const(_) => todo!(), CoreTypeConcrete::BoundedInt(info) => { - let data = ptr.cast::<[u8; 32]>().as_ref(); - let data = Felt::from_bytes_le(data); + let mut data = BigUint::from_bytes_le(slice::from_raw_parts( + ptr.cast::().as_ptr(), + (info.range.offset_bit_width().next_multiple_of(8) >> 3) as usize, + )) + .to_bigint() + .unwrap(); + + data &= (BigInt::one() << info.range.offset_bit_width()) - BigInt::one(); + data += &info.range.lower; + Self::BoundedInt { - value: data, + value: data.into(), range: info.range.clone(), } } - CoreTypeConcrete::Coupon(_) => todo!(), + CoreTypeConcrete::Coupon(_) + | CoreTypeConcrete::Circuit(_) + | CoreTypeConcrete::RangeCheck96(_) => todo!(), } } } @@ -957,8 +967,11 @@ mod test { let registry = ProgramRegistry::::new(&program).unwrap(); assert_eq!( - JitValue::resolve_type(&ty, ®istry).integer_width(), - Some(128) + JitValue::resolve_type(&ty, ®istry).integer_range(®istry), + Some(Range { + lower: BigInt::from(u128::MIN), + upper: BigInt::from(u128::MAX) + BigInt::one(), + }) ); } diff --git a/tests/alexandria/Scarb.lock b/tests/alexandria/Scarb.lock index 7fcef9621..5802fb43c 100644 --- a/tests/alexandria/Scarb.lock +++ b/tests/alexandria/Scarb.lock @@ -13,7 +13,7 @@ dependencies = [ [[package]] name = "alexandria_bytes" version = "0.1.0" -source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bbc010b922d9ca6f807ef01b0b255e34331b5eac#bbc010b922d9ca6f807ef01b0b255e34331b5eac" +source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2#7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2" dependencies = [ "alexandria_data_structures", "alexandria_math", @@ -22,7 +22,7 @@ dependencies = [ [[package]] name = "alexandria_data_structures" version = "0.2.0" -source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bbc010b922d9ca6f807ef01b0b255e34331b5eac#bbc010b922d9ca6f807ef01b0b255e34331b5eac" +source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2#7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2" dependencies = [ "alexandria_encoding", ] @@ -30,7 +30,7 @@ dependencies = [ [[package]] name = "alexandria_encoding" version = "0.1.0" -source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bbc010b922d9ca6f807ef01b0b255e34331b5eac#bbc010b922d9ca6f807ef01b0b255e34331b5eac" +source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2#7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2" dependencies = [ "alexandria_bytes", "alexandria_math", @@ -39,16 +39,13 @@ dependencies = [ [[package]] name = "alexandria_math" -version = "0.2.0" -source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bbc010b922d9ca6f807ef01b0b255e34331b5eac#bbc010b922d9ca6f807ef01b0b255e34331b5eac" -dependencies = [ - "alexandria_data_structures", -] +version = "0.2.1" +source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2#7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2" [[package]] name = "alexandria_numeric" version = "0.1.0" -source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bbc010b922d9ca6f807ef01b0b255e34331b5eac#bbc010b922d9ca6f807ef01b0b255e34331b5eac" +source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2#7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2" dependencies = [ "alexandria_math", "alexandria_searching", @@ -57,7 +54,7 @@ dependencies = [ [[package]] name = "alexandria_searching" version = "0.1.0" -source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bbc010b922d9ca6f807ef01b0b255e34331b5eac#bbc010b922d9ca6f807ef01b0b255e34331b5eac" +source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2#7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2" dependencies = [ "alexandria_data_structures", ] diff --git a/tests/alexandria/Scarb.toml b/tests/alexandria/Scarb.toml index a44d33aaf..bd7283a2d 100644 --- a/tests/alexandria/Scarb.toml +++ b/tests/alexandria/Scarb.toml @@ -1,11 +1,11 @@ [package] name = "alexandria" version = "0.1.0" -cairo-version = "2.6.3" +cairo-version = "2.7.1" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html [dependencies] -alexandria_math = { rev = "bbc010b922d9ca6f807ef01b0b255e34331b5eac", git = "https://github.com/keep-starknet-strange/alexandria.git" } -alexandria_data_structures = { rev = "bbc010b922d9ca6f807ef01b0b255e34331b5eac", git = "https://github.com/keep-starknet-strange/alexandria.git" } -alexandria_encoding = { rev = "bbc010b922d9ca6f807ef01b0b255e34331b5eac", git = "https://github.com/keep-starknet-strange/alexandria.git" } +alexandria_math = { rev = "7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2", git = "https://github.com/keep-starknet-strange/alexandria.git" } +alexandria_data_structures = { rev = "7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2", git = "https://github.com/keep-starknet-strange/alexandria.git" } +alexandria_encoding = { rev = "7c19379ab6cf0f8b48be3c5b118ffddd7e26a4d2", git = "https://github.com/keep-starknet-strange/alexandria.git" } diff --git a/tests/alexandria/src/lib.cairo b/tests/alexandria/src/lib.cairo index 257c3084a..5449ea597 100644 --- a/tests/alexandria/src/lib.cairo +++ b/tests/alexandria/src/lib.cairo @@ -1,7 +1,10 @@ mod alexandria { // Alexandria Math + use alexandria_encoding::reversible::ReversibleBytes; + use alexandria_encoding::reversible::ReversibleBits; use core::option::OptionTrait; + fn fib() -> felt252 { alexandria_math::fibonacci::fib(16, 10, 1) } @@ -85,30 +88,23 @@ mod alexandria { (encoded, decoded) } - use alexandria_encoding::reversible::{ - U16ReversibleBits, U32ReversibleBits, U64ReversibleBits, U128ReversibleBits, - U256ReversibleBits - }; fn reverse_bits() -> (u16, u32, u64, u128, u256) { ( - U16ReversibleBits::reverse_bits(@333), - U32ReversibleBits::reverse_bits(@3333333), - U64ReversibleBits::reverse_bits(@3333333333333), - U128ReversibleBits::reverse_bits(@333333333333333333333), - U256ReversibleBits::reverse_bits(@33333333333333333333333333), + 333_u16.reverse_bits(), + 3333333_u32.reverse_bits(), + 3333333333333_u64.reverse_bits(), + 333333333333333333333_u128.reverse_bits(), + 33333333333333333333333333_u256.reverse_bits(), ) } - use alexandria_encoding::reversible::{ - U16Reversible, U32Reversible, U64Reversible, U128Reversible, U256Reversible - }; fn reverse_bytes() -> (u16, u32, u64, u128, u256) { ( - U16Reversible::reverse_bytes(@333), - U32Reversible::reverse_bytes(@3333333), - U64Reversible::reverse_bytes(@3333333333333), - U128Reversible::reverse_bytes(@333333333333333333333), - U256Reversible::reverse_bytes(@33333333333333333333333333), + 333_u16.reverse_bytes(), + 3333333_u32.reverse_bytes(), + 3333333333333_u64.reverse_bytes(), + 333333333333333333333_u128.reverse_bytes(), + 33333333333333333333333333_u256.reverse_bytes(), ) } } diff --git a/tests/cases/brainfuck.cairo b/tests/cases/brainfuck.cairo index d015de00d..8d7c0b40d 100644 --- a/tests/cases/brainfuck.cairo +++ b/tests/cases/brainfuck.cairo @@ -1,7 +1,8 @@ use core::{ traits::Default, array::{ArrayTrait, SpanTrait}, debug::PrintTrait, dict::Felt252DictTrait, - integer::{u8_wrapping_add, u8_wrapping_sub}, option::OptionTrait, traits::Into, + option::OptionTrait, traits::Into, + num::traits::{WrappingAdd, WrappingSub}, }; fn generate_jump_table(program: @Array) -> Felt252Dict { @@ -50,9 +51,9 @@ fn run_program(program: @Array, input: Option>) { } else if op_code == '<' { mp -= 1; } else if op_code == '+' { - memory.insert(mp, u8_wrapping_add(memory.get(mp), 1)); + memory.insert(mp, memory.get(mp).wrapping_add(1)); } else if op_code == '-' { - memory.insert(mp, u8_wrapping_sub(memory.get(mp), 1)); + memory.insert(mp, memory.get(mp).wrapping_sub(1)); } else if op_code == '.' { memory.get(mp).print(); } else if op_code == ',' { diff --git a/tests/cases/cairo_vm/contracts/alloc_segment.cairo b/tests/cases/cairo_vm/contracts/alloc_segment.cairo index 5fef14266..bc5c9a0d5 100644 --- a/tests/cases/cairo_vm/contracts/alloc_segment.cairo +++ b/tests/cases/cairo_vm/contracts/alloc_segment.cairo @@ -1,7 +1,7 @@ #[starknet::contract] mod AllocSegment { use dict::{Felt252DictTrait, Felt252DictEntryTrait}; - use traits::Index; + use core::ops::index::Index; use array::{ArrayTrait, SpanTrait}; #[storage] diff --git a/tests/cases/cairo_vm/contracts/dict_test.cairo b/tests/cases/cairo_vm/contracts/dict_test.cairo index 2bb9c8f46..34a43811b 100644 --- a/tests/cases/cairo_vm/contracts/dict_test.cairo +++ b/tests/cases/cairo_vm/contracts/dict_test.cairo @@ -1,7 +1,7 @@ #[starknet::contract] mod DictTest { use dict::Felt252DictTrait; - use traits::Index; + use core::ops::index::Index; const KEY1: felt252 = 10; const KEY2: felt252 = 21; @@ -27,12 +27,12 @@ mod DictTest { dict.insert(KEY4, 4); dict.insert(KEY5, 5); - assert(dict.index(KEY1) == 1, 'KEY1'); - assert(dict.index(KEY2) == 2, 'KEY2'); - assert(dict.index(KEY3) == 3, 'KEY3'); - assert(dict.index(KEY4) == 4, 'KEY4'); - assert(dict.index(KEY5) == 5, 'KEY5'); + assert(dict[KEY1] == 1, 'KEY1'); + assert(dict[KEY2] == 2, 'KEY2'); + assert(dict[KEY3] == 3, 'KEY3'); + assert(dict[KEY4] == 4, 'KEY4'); + assert(dict[KEY5] == 5, 'KEY5'); - return dict.index(KEY5); + return dict[KEY5]; } } diff --git a/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo b/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo index 69e14f0cc..9d97cde95 100644 --- a/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo +++ b/tests/cases/cairo_vm/contracts/felt252_dict_entry_init.cairo @@ -1,7 +1,7 @@ #[starknet::contract] mod DictEntryInitTest { use dict::{Felt252DictTrait, Felt252DictEntryTrait}; - use traits::Index; + use core::ops::index::Index; use array::{ArrayTrait, SpanTrait}; #[storage] @@ -14,8 +14,8 @@ mod DictEntryInitTest { // Generates hint Felt252DictEntryInit by creating a new dict entry dict.insert(10, 110); dict.insert(11, 111); - let val10 = dict.index(10); - let val11 = dict.index(11); + let val10 = dict[10]; + let val11 = dict[11]; assert(val10 == 110, 'dict[10] == 110'); assert(val11 == 111, 'dict[11] == 111'); diff --git a/tests/cases/cairo_vm/contracts/init_squash_data.cairo b/tests/cases/cairo_vm/contracts/init_squash_data.cairo index a9fcabe82..09b8d339e 100644 --- a/tests/cases/cairo_vm/contracts/init_squash_data.cairo +++ b/tests/cases/cairo_vm/contracts/init_squash_data.cairo @@ -5,7 +5,7 @@ mod TestDict { use dict::Felt252DictTrait; use nullable::NullableTrait; - use traits::Index; + use core::ops::index::Index; #[external(v0)] fn test_dict_init(self: @ContractState, test_value: felt252) -> felt252 { diff --git a/tests/cases/cairo_vm/contracts/u128_sqrt.cairo b/tests/cases/cairo_vm/contracts/u128_sqrt.cairo index 35e2dc089..602489ccc 100644 --- a/tests/cases/cairo_vm/contracts/u128_sqrt.cairo +++ b/tests/cases/cairo_vm/contracts/u128_sqrt.cairo @@ -3,7 +3,7 @@ mod U128Sqrt { #[storage] struct Storage {} - use integer::u128_sqrt; + use core::num::traits::Sqrt; use core::traits::Into; use traits::TryInto; use option::OptionTrait; @@ -12,7 +12,7 @@ mod U128Sqrt { #[external(v0)] fn sqrt(self: @ContractState, num: felt252) -> felt252 { let num_in_u128: u128 = num.try_into().unwrap(); - let a: u64 = u128_sqrt(num_in_u128); + let a: u64 = num_in_u128.sqrt(); let to_return: felt252 = a.into(); to_return } diff --git a/tests/cases/cairo_vm/contracts/u16_sqrt.cairo b/tests/cases/cairo_vm/contracts/u16_sqrt.cairo index 582df5167..4911af4b4 100644 --- a/tests/cases/cairo_vm/contracts/u16_sqrt.cairo +++ b/tests/cases/cairo_vm/contracts/u16_sqrt.cairo @@ -3,7 +3,7 @@ mod U16Sqrt { #[storage] struct Storage {} - use integer::u16_sqrt; + use core::num::traits::Sqrt; use core::traits::Into; use traits::TryInto; use option::OptionTrait; @@ -12,7 +12,7 @@ mod U16Sqrt { #[external(v0)] fn sqrt(self: @ContractState, num: felt252) -> felt252 { let num_in_u16: u16 = num.try_into().unwrap(); - let a: u8 = u16_sqrt(num_in_u16); + let a: u8 = num_in_u16.sqrt(); let to_return: felt252 = a.into(); to_return } diff --git a/tests/cases/cairo_vm/contracts/u256_sqrt.cairo b/tests/cases/cairo_vm/contracts/u256_sqrt.cairo index 5bb704260..3bab5cebf 100644 --- a/tests/cases/cairo_vm/contracts/u256_sqrt.cairo +++ b/tests/cases/cairo_vm/contracts/u256_sqrt.cairo @@ -3,11 +3,11 @@ mod U256Sqrt { #[storage] struct Storage {} - use integer::u256_sqrt; + use core::num::traits::Sqrt; use core::traits::Into; use traits::TryInto; - use option::OptionTrait; - use integer::BoundedInt; + use option::OptionTrait; + use core::num::traits::Bounded; fn as_u256(a: u128, b: u128) -> u256{ u256{ @@ -20,7 +20,7 @@ mod U256Sqrt { fn sqrt(self: @ContractState, num: felt252) -> felt252 { let num_in_u128: u128 = num.try_into().unwrap(); let num_in_u256: u256 = as_u256(num_in_u128, 0); - let a: u128 = u256_sqrt(num_in_u256); + let a: u128 = num_in_u256.sqrt(); let to_return: felt252 = a.into(); to_return } diff --git a/tests/cases/cairo_vm/contracts/u32_sqrt.cairo b/tests/cases/cairo_vm/contracts/u32_sqrt.cairo index 1778c6ed7..9a3a7b9c5 100644 --- a/tests/cases/cairo_vm/contracts/u32_sqrt.cairo +++ b/tests/cases/cairo_vm/contracts/u32_sqrt.cairo @@ -3,7 +3,7 @@ mod U32Sqrt { #[storage] struct Storage {} - use integer::u32_sqrt; + use core::num::traits::Sqrt; use core::traits::Into; use traits::TryInto; use option::OptionTrait; @@ -12,7 +12,7 @@ mod U32Sqrt { #[external(v0)] fn sqrt(self: @ContractState, num: felt252) -> felt252 { let num_in_u32: u32 = num.try_into().unwrap(); - let a: u16 = u32_sqrt(num_in_u32); + let a: u16 = num_in_u32.sqrt(); let to_return: felt252 = a.into(); to_return } diff --git a/tests/cases/cairo_vm/contracts/u64_sqrt.cairo b/tests/cases/cairo_vm/contracts/u64_sqrt.cairo index fbceac225..a9302cec9 100644 --- a/tests/cases/cairo_vm/contracts/u64_sqrt.cairo +++ b/tests/cases/cairo_vm/contracts/u64_sqrt.cairo @@ -3,7 +3,7 @@ mod U64Sqrt { #[storage] struct Storage {} - use integer::u64_sqrt; + use core::num::traits::Sqrt; use core::traits::Into; use traits::TryInto; use option::OptionTrait; @@ -12,7 +12,7 @@ mod U64Sqrt { #[external(v0)] fn sqrt(self: @ContractState, num: felt252) -> felt252 { let num_in_u64: u64 = num.try_into().unwrap(); - let a: u32 = u64_sqrt(num_in_u64); + let a: u32 = num_in_u64.sqrt(); let to_return: felt252 = a.into(); to_return } diff --git a/tests/cases/cairo_vm/contracts/u8_sqrt.cairo b/tests/cases/cairo_vm/contracts/u8_sqrt.cairo index ec083041e..73f2fee7c 100644 --- a/tests/cases/cairo_vm/contracts/u8_sqrt.cairo +++ b/tests/cases/cairo_vm/contracts/u8_sqrt.cairo @@ -3,7 +3,7 @@ mod U8Sqrt { #[storage] struct Storage {} - use integer::u8_sqrt; + use core::num::traits::Sqrt; use core::traits::Into; use traits::TryInto; use option::OptionTrait; @@ -12,7 +12,7 @@ mod U8Sqrt { #[external(v0)] fn sqrt(self: @ContractState, num: felt252) -> felt252 { let num_in_u8: u8 = num.try_into().unwrap(); - let a: u8 = u8_sqrt(num_in_u8); + let a: u8 = num_in_u8.sqrt(); let to_return: felt252 = a.into(); to_return } diff --git a/tests/cases/sint/i16_wide_mul.cairo b/tests/cases/sint/i16_wide_mul.cairo index 998d41f85..fb32216ba 100644 --- a/tests/cases/sint/i16_wide_mul.cairo +++ b/tests/cases/sint/i16_wide_mul.cairo @@ -1,4 +1,4 @@ -use integer::i16_wide_mul; +use core::num::traits::WideMul; fn main() -> ( i32, i32, i32, @@ -7,18 +7,18 @@ fn main() -> ( i32, i32, i32, ) { ( - i16_wide_mul(0_i16, 0_i16), - i16_wide_mul(0_i16, 10_i16), - i16_wide_mul(0_i16, 255_i16), - i16_wide_mul(10_i16, 0_i16), - i16_wide_mul(10_i16, 10_i16), - i16_wide_mul(10_i16, 255_i16), - i16_wide_mul(255_i16, 0_i16), - i16_wide_mul(255_i16, 10_i16), - i16_wide_mul(255_i16, 255_i16), - i16_wide_mul(10_i16, -10_i16), - i16_wide_mul(10_i16, -255_i16), - i16_wide_mul(-255_i16, -255_i16), + WideMul::wide_mul(0_i16, 0_i16), + WideMul::wide_mul(0_i16, 10_i16), + WideMul::wide_mul(0_i16, 255_i16), + WideMul::wide_mul(10_i16, 0_i16), + WideMul::wide_mul(10_i16, 10_i16), + WideMul::wide_mul(10_i16, 255_i16), + WideMul::wide_mul(255_i16, 0_i16), + WideMul::wide_mul(255_i16, 10_i16), + WideMul::wide_mul(255_i16, 255_i16), + WideMul::wide_mul(10_i16, -10_i16), + WideMul::wide_mul(10_i16, -255_i16), + WideMul::wide_mul(-255_i16, -255_i16), ) } diff --git a/tests/cases/sint/i32_wide_mul.cairo b/tests/cases/sint/i32_wide_mul.cairo index 716715977..a80b78a1d 100644 --- a/tests/cases/sint/i32_wide_mul.cairo +++ b/tests/cases/sint/i32_wide_mul.cairo @@ -1,4 +1,4 @@ -use integer::i32_wide_mul; +use core::num::traits::WideMul; fn main() -> ( i64, i64, i64, @@ -7,18 +7,18 @@ fn main() -> ( i64, i64, i64, ) { ( - i32_wide_mul(0_i32, 0_i32), - i32_wide_mul(0_i32, 10_i32), - i32_wide_mul(0_i32, 2147483647_i32), - i32_wide_mul(10_i32, 0_i32), - i32_wide_mul(10_i32, 10_i32), - i32_wide_mul(10_i32, 2147483647_i32), - i32_wide_mul(2147483647_i32, 0_i32), - i32_wide_mul(2147483647_i32, 10_i32), - i32_wide_mul(2147483647_i32, 2147483647_i32), - i32_wide_mul(10_i32, -10_i32), - i32_wide_mul(10_i32, -2147483647_i32), - i32_wide_mul(-2147483647_i32, -2147483647_i32), + WideMul::wide_mul(0_i32, 0_i32), + WideMul::wide_mul(0_i32, 10_i32), + WideMul::wide_mul(0_i32, 2147483647_i32), + WideMul::wide_mul(10_i32, 0_i32), + WideMul::wide_mul(10_i32, 10_i32), + WideMul::wide_mul(10_i32, 2147483647_i32), + WideMul::wide_mul(2147483647_i32, 0_i32), + WideMul::wide_mul(2147483647_i32, 10_i32), + WideMul::wide_mul(2147483647_i32, 2147483647_i32), + WideMul::wide_mul(10_i32, -10_i32), + WideMul::wide_mul(10_i32, -2147483647_i32), + WideMul::wide_mul(-2147483647_i32, -2147483647_i32), ) } diff --git a/tests/cases/sint/i64_wide_mul.cairo b/tests/cases/sint/i64_wide_mul.cairo index 0da94b309..795a96a26 100644 --- a/tests/cases/sint/i64_wide_mul.cairo +++ b/tests/cases/sint/i64_wide_mul.cairo @@ -1,4 +1,4 @@ -use integer::i64_wide_mul; +use core::num::traits::WideMul; fn main() -> ( i128, i128, i128, @@ -7,18 +7,18 @@ fn main() -> ( i128, i128, i128, ) { ( - i64_wide_mul(0_i64, 0_i64), - i64_wide_mul(0_i64, 10_i64), - i64_wide_mul(0_i64, 9223372036854775807_i64), - i64_wide_mul(10_i64, 0_i64), - i64_wide_mul(10_i64, 10_i64), - i64_wide_mul(10_i64, 9223372036854775807_i64), - i64_wide_mul(9223372036854775807_i64, 0_i64), - i64_wide_mul(9223372036854775807_i64, 10_i64), - i64_wide_mul(9223372036854775807_i64, 9223372036854775807_i64), - i64_wide_mul(10_i64, -10_i64), - i64_wide_mul(10_i64, -9223372036854775807_i64), - i64_wide_mul(-9223372036854775807_i64, -9223372036854775807_i64), + WideMul::wide_mul(0_i64, 0_i64), + WideMul::wide_mul(0_i64, 10_i64), + WideMul::wide_mul(0_i64, 9223372036854775807_i64), + WideMul::wide_mul(10_i64, 0_i64), + WideMul::wide_mul(10_i64, 10_i64), + WideMul::wide_mul(10_i64, 9223372036854775807_i64), + WideMul::wide_mul(9223372036854775807_i64, 0_i64), + WideMul::wide_mul(9223372036854775807_i64, 10_i64), + WideMul::wide_mul(9223372036854775807_i64, 9223372036854775807_i64), + WideMul::wide_mul(10_i64, -10_i64), + WideMul::wide_mul(10_i64, -9223372036854775807_i64), + WideMul::wide_mul(-9223372036854775807_i64, -9223372036854775807_i64), ) } diff --git a/tests/cases/sint/i8_wide_mul.cairo b/tests/cases/sint/i8_wide_mul.cairo index b47a73d82..fd5dff9e7 100644 --- a/tests/cases/sint/i8_wide_mul.cairo +++ b/tests/cases/sint/i8_wide_mul.cairo @@ -1,4 +1,4 @@ -use integer::i8_wide_mul; +use core::num::traits::WideMul; fn main() -> ( i16, i16, i16, @@ -7,18 +7,18 @@ fn main() -> ( i16, i16, i16, ) { ( - i8_wide_mul(0_i8, 0_i8), - i8_wide_mul(0_i8, 10_i8), - i8_wide_mul(0_i8, 127_i8), - i8_wide_mul(10_i8, 0_i8), - i8_wide_mul(10_i8, 10_i8), - i8_wide_mul(10_i8, 127_i8), - i8_wide_mul(127_i8, 0_i8), - i8_wide_mul(127_i8, 10_i8), - i8_wide_mul(127_i8, 127_i8), - i8_wide_mul(10_i8, -10_i8), - i8_wide_mul(10_i8, -127_i8), - i8_wide_mul(-127_i8, -127_i8), + WideMul::wide_mul(0_i8, 0_i8), + WideMul::wide_mul(0_i8, 10_i8), + WideMul::wide_mul(0_i8, 127_i8), + WideMul::wide_mul(10_i8, 0_i8), + WideMul::wide_mul(10_i8, 10_i8), + WideMul::wide_mul(10_i8, 127_i8), + WideMul::wide_mul(127_i8, 0_i8), + WideMul::wide_mul(127_i8, 10_i8), + WideMul::wide_mul(127_i8, 127_i8), + WideMul::wide_mul(10_i8, -10_i8), + WideMul::wide_mul(10_i8, -127_i8), + WideMul::wide_mul(-127_i8, -127_i8), ) } diff --git a/tests/cases/uint/uint_addition.cairo b/tests/cases/uint/uint_addition.cairo index bba205693..5441635de 100644 --- a/tests/cases/uint/uint_addition.cairo +++ b/tests/cases/uint/uint_addition.cairo @@ -1,7 +1,4 @@ -use integer::u16_wrapping_add; -use integer::u32_wrapping_add; -use integer::u64_wrapping_add; -use integer::u128_wrapping_add; +use core::num::traits::WrappingAdd; fn main() -> ( (u16, u16, u16), @@ -12,22 +9,22 @@ fn main() -> ( ( ( 4_u16 + 6_u16, - u16_wrapping_add(60000_u16, 20000_u16), + 60000_u16.wrapping_add(20000_u16), 50_u16 + 2_u16, ), ( 4_u32 + 6_u32, - u32_wrapping_add(4294967293_u32, 10_u32), + 4294967293_u32.wrapping_add(10_u32), 50_u32 + 2_u32, ), ( 4_u64 + 6_u64, - u64_wrapping_add(18446744073709551613_u64, 10_u64), + 18446744073709551613_u64.wrapping_add(10_u64), 50_u64 + 2_u64, ), ( 4_u128 + 6_u128, - u128_wrapping_add(340282366920938463463374607431768211453_u128, 10_u128), + 340282366920938463463374607431768211453_u128.wrapping_add(10_u128), 50_u128 + 2_u128, ), ) diff --git a/tests/cases/uint/uint_subtraction.cairo b/tests/cases/uint/uint_subtraction.cairo index 32b465462..20a3a81bc 100644 --- a/tests/cases/uint/uint_subtraction.cairo +++ b/tests/cases/uint/uint_subtraction.cairo @@ -1,6 +1,4 @@ -use integer::u16_wrapping_sub; -use integer::u32_wrapping_sub; -use integer::u64_wrapping_sub; +use core::num::traits::WrappingSub; fn main() -> ( (u16, u16, u16), @@ -11,17 +9,17 @@ fn main() -> ( ( ( 6_u16 - 4_u16, - u16_wrapping_sub(0_u16, 2_u16), + 0_u16.wrapping_sub(2_u16), 50_u16 - 2_u16, ), ( 6_u32 - 4_u32, - u32_wrapping_sub(0_u32, 2_u32), + 0_u32.wrapping_sub(2_u32), 50_u32 - 2_u32, ), ( 6_u64 - 4_u64, - u64_wrapping_sub(0_u64, 2_u64), + 0_u64.wrapping_sub(2_u64), 50_u64 - 2_u64, ), ( diff --git a/tests/cases/uint/wide_mul.cairo b/tests/cases/uint/wide_mul.cairo index 6ed3116d6..f06b2590b 100644 --- a/tests/cases/uint/wide_mul.cairo +++ b/tests/cases/uint/wide_mul.cairo @@ -1,8 +1,4 @@ -use integer::u8_wide_mul; -use integer::u16_wide_mul; -use integer::u32_wide_mul; -use integer::u64_wide_mul; -use integer::u128_wide_mul; +use core::num::traits::WideMul; fn main() -> ( u16, u16, u16, @@ -21,59 +17,59 @@ fn main() -> ( u128, u128, u128, u128, u128, u128, - (u128, u128), (u128, u128), (u128, u128), - (u128, u128), (u128, u128), (u128, u128), - (u128, u128), (u128, u128), (u128, u128), + u256, u256, u256, + u256, u256, u256, + u256, u256, u256, ) { ( - u8_wide_mul(0_u8, 0_u8), - u8_wide_mul(0_u8, 10_u8), - u8_wide_mul(0_u8, 255_u8), - u8_wide_mul(10_u8, 0_u8), - u8_wide_mul(10_u8, 10_u8), - u8_wide_mul(10_u8, 255_u8), - u8_wide_mul(255_u8, 0_u8), - u8_wide_mul(255_u8, 10_u8), - u8_wide_mul(255_u8, 255_u8), + WideMul::wide_mul(0_u8, 0_u8), + WideMul::wide_mul(0_u8, 10_u8), + WideMul::wide_mul(0_u8, 255_u8), + WideMul::wide_mul(10_u8, 0_u8), + WideMul::wide_mul(10_u8, 10_u8), + WideMul::wide_mul(10_u8, 255_u8), + WideMul::wide_mul(255_u8, 0_u8), + WideMul::wide_mul(255_u8, 10_u8), + WideMul::wide_mul(255_u8, 255_u8), - u16_wide_mul(0_u16, 0_u16), - u16_wide_mul(0_u16, 1000_u16), - u16_wide_mul(0_u16, 65535_u16), - u16_wide_mul(1000_u16, 0_u16), - u16_wide_mul(1000_u16, 1000_u16), - u16_wide_mul(1000_u16, 65535_u16), - u16_wide_mul(65535_u16, 0_u16), - u16_wide_mul(65535_u16, 10_u16), - u16_wide_mul(65535_u16, 65535_u16), + WideMul::wide_mul(0_u16, 0_u16), + WideMul::wide_mul(0_u16, 1000_u16), + WideMul::wide_mul(0_u16, 65535_u16), + WideMul::wide_mul(1000_u16, 0_u16), + WideMul::wide_mul(1000_u16, 1000_u16), + WideMul::wide_mul(1000_u16, 65535_u16), + WideMul::wide_mul(65535_u16, 0_u16), + WideMul::wide_mul(65535_u16, 10_u16), + WideMul::wide_mul(65535_u16, 65535_u16), - u32_wide_mul(0_u32, 0_u32), - u32_wide_mul(0_u32, 100000_u32), - u32_wide_mul(0_u32, 4294967295_u32), - u32_wide_mul(100000_u32, 0_u32), - u32_wide_mul(100000_u32, 100000_u32), - u32_wide_mul(100000_u32, 4294967295_u32), - u32_wide_mul(4294967295_u32, 0_u32), - u32_wide_mul(4294967295_u32, 10_u32), - u32_wide_mul(4294967295_u32, 4294967295_u32), + WideMul::wide_mul(0_u32, 0_u32), + WideMul::wide_mul(0_u32, 100000_u32), + WideMul::wide_mul(0_u32, 4294967295_u32), + WideMul::wide_mul(100000_u32, 0_u32), + WideMul::wide_mul(100000_u32, 100000_u32), + WideMul::wide_mul(100000_u32, 4294967295_u32), + WideMul::wide_mul(4294967295_u32, 0_u32), + WideMul::wide_mul(4294967295_u32, 10_u32), + WideMul::wide_mul(4294967295_u32, 4294967295_u32), - u64_wide_mul(0_u64, 0_u64), - u64_wide_mul(0_u64, 10000000000_u64), - u64_wide_mul(0_u64, 18446744073709551615_u64), - u64_wide_mul(10000000000_u64, 0_u64), - u64_wide_mul(10000000000_u64, 10000000000_u64), - u64_wide_mul(10000000000_u64, 18446744073709551615_u64), - u64_wide_mul(18446744073709551615_u64, 0_u64), - u64_wide_mul(18446744073709551615_u64, 10_u64), - u64_wide_mul(18446744073709551615_u64, 18446744073709551615_u64), + WideMul::wide_mul(0_u64, 0_u64), + WideMul::wide_mul(0_u64, 10000000000_u64), + WideMul::wide_mul(0_u64, 18446744073709551615_u64), + WideMul::wide_mul(10000000000_u64, 0_u64), + WideMul::wide_mul(10000000000_u64, 10000000000_u64), + WideMul::wide_mul(10000000000_u64, 18446744073709551615_u64), + WideMul::wide_mul(18446744073709551615_u64, 0_u64), + WideMul::wide_mul(18446744073709551615_u64, 10_u64), + WideMul::wide_mul(18446744073709551615_u64, 18446744073709551615_u64), - u128_wide_mul(0_u128, 0_u128), - u128_wide_mul(0_u128, 100000000000000000000_u128), - u128_wide_mul(0_u128, 340282366920938463463374607431768211455_u128), - u128_wide_mul(100000000000000000000_u128, 0_u128), - u128_wide_mul(100000000000000000000_u128, 100000000000000000000_u128), - u128_wide_mul(100000000000000000000_u128, 340282366920938463463374607431768211455_u128), - u128_wide_mul(340282366920938463463374607431768211455_u128, 0_u128), - u128_wide_mul(340282366920938463463374607431768211455_u128, 10_u128), - u128_wide_mul(340282366920938463463374607431768211455_u128, 340282366920938463463374607431768211455_u128), + WideMul::wide_mul(0_u128, 0_u128), + WideMul::wide_mul(0_u128, 100000000000000000000_u128), + WideMul::wide_mul(0_u128, 340282366920938463463374607431768211455_u128), + WideMul::wide_mul(100000000000000000000_u128, 0_u128), + WideMul::wide_mul(100000000000000000000_u128, 100000000000000000000_u128), + WideMul::wide_mul(100000000000000000000_u128, 340282366920938463463374607431768211455_u128), + WideMul::wide_mul(340282366920938463463374607431768211455_u128, 0_u128), + WideMul::wide_mul(340282366920938463463374607431768211455_u128, 10_u128), + WideMul::wide_mul(340282366920938463463374607431768211455_u128, 340282366920938463463374607431768211455_u128), ) } diff --git a/tests/common.rs b/tests/common.rs index ee217e2ae..0e2ca9a28 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -63,7 +63,6 @@ macro_rules! load_cairo { }; } -use cairo_felt::Felt252; #[allow(unused_imports)] pub(crate) use load_cairo; use num_traits::ToPrimitive; @@ -123,7 +122,7 @@ pub fn load_cairo_str(program_str: &str) -> (String, Program, SierraCasmRunner) Path::new(&var("CARGO_MANIFEST_DIR").unwrap()).join("corelib/src"), ); let main_crate_ids = setup_project(&mut db, program_file.path()).unwrap(); - let program = compile_prepared_db( + let sierra_program_with_dbg = compile_prepared_db( &mut db, main_crate_ids.clone(), CompilerConfig { @@ -132,6 +131,7 @@ pub fn load_cairo_str(program_str: &str) -> (String, Program, SierraCasmRunner) }, ) .unwrap(); + let program = sierra_program_with_dbg.program; let module_name = program_file.path().with_extension(""); let module_name = module_name.file_name().unwrap().to_str().unwrap(); @@ -159,7 +159,7 @@ pub fn load_cairo_path(program_path: &str) -> (String, Program, SierraCasmRunner Path::new(&var("CARGO_MANIFEST_DIR").unwrap()).join("corelib/src"), ); let main_crate_ids = setup_project(&mut db, program_file).unwrap(); - let program = compile_prepared_db( + let sierra_program_with_dbg = compile_prepared_db( &mut db, main_crate_ids.clone(), CompilerConfig { @@ -168,6 +168,7 @@ pub fn load_cairo_path(program_path: &str) -> (String, Program, SierraCasmRunner }, ) .unwrap(); + let program = sierra_program_with_dbg.program; let module_name = program_file.with_extension(""); let module_name = module_name.file_name().unwrap().to_str().unwrap(); @@ -357,7 +358,8 @@ pub fn run_vm_contract( let entrypoint_args: Vec<&CairoArg> = entrypoint_args.iter().collect(); // Run contract entrypoint - let mut hint_processor = Cairo1HintProcessor::new(&contract.hints, RunResources::default()); + let mut hint_processor = + Cairo1HintProcessor::new(&contract.hints, RunResources::default(), false); runner .run_from_entrypoint( entrypoint, @@ -503,8 +505,8 @@ pub fn compare_outputs( fn map_vm_values( size_cache: &mut HashMap, registry: &ProgramRegistry, - memory: &[Option], - mut values: &[Felt252], + memory: &[Option], + mut values: &[Felt], ty: &ConcreteTypeId, ) -> JitValue { match registry.get_type(ty).unwrap() { @@ -526,7 +528,7 @@ pub fn compare_outputs( ) } CoreTypeConcrete::Felt252(_) => { - JitValue::Felt252(Felt::from_bytes_le(&values[0].to_le_bytes())) + JitValue::Felt252(Felt::from_bytes_le(&values[0].to_bytes_le())) } CoreTypeConcrete::Uint128(_) => JitValue::Uint128(values[0].to_u128().unwrap()), CoreTypeConcrete::Uint64(_) => JitValue::Uint64(values[0].to_u64().unwrap()), @@ -613,13 +615,13 @@ pub fn compare_outputs( .step_by(3) .map(|index| { ( - Felt::from_bytes_le(&memory[index].clone().unwrap().to_le_bytes()), + Felt::from_bytes_le(&memory[index].unwrap().to_bytes_le()), match &info.info.long_id.generic_args[0] { cairo_lang_sierra::program::GenericArg::Type(ty) => map_vm_values( size_cache, registry, memory, - &[memory[index + 2].clone().unwrap()], + &[memory[index + 2].unwrap()], ty, ), _ => unimplemented!("unsupported dict value type"), @@ -684,22 +686,22 @@ pub fn compare_outputs( assert_eq!(values.len(), 2); JitValue::EcPoint( - Felt::from_bytes_le(&values[0].to_le_bytes()), - Felt::from_bytes_le(&values[1].to_le_bytes()), + Felt::from_bytes_le(&values[0].to_bytes_le()), + Felt::from_bytes_le(&values[1].to_bytes_le()), ) } CoreTypeConcrete::EcState(_) => { assert_eq!(values.len(), 4); JitValue::EcState( - Felt::from_bytes_le(&values[0].to_le_bytes()), - Felt::from_bytes_le(&values[1].to_le_bytes()), - Felt::from_bytes_le(&values[2].to_le_bytes()), - Felt::from_bytes_le(&values[3].to_le_bytes()), + Felt::from_bytes_le(&values[0].to_bytes_le()), + Felt::from_bytes_le(&values[1].to_bytes_le()), + Felt::from_bytes_le(&values[2].to_bytes_le()), + Felt::from_bytes_le(&values[3].to_bytes_le()), ) } CoreTypeConcrete::Bytes31(_) => { - let mut bytes = values[0].to_le_bytes().to_vec(); + let mut bytes = values[0].to_bytes_le().to_vec(); bytes.pop(); JitValue::Bytes31(bytes.try_into().unwrap()) } @@ -730,11 +732,8 @@ pub fn compare_outputs( .unwrap_or(false) }); assert_eq!( - vm_result - .gas_counter - .clone() - .unwrap_or_else(|| Felt252::from(0)), - Felt252::from(native_result.remaining_gas.unwrap_or(0)), + vm_result.gas_counter.unwrap_or_else(|| Felt::from(0)), + Felt::from(native_result.remaining_gas.unwrap_or(0)), ); let vm_result = match &vm_result.value { @@ -781,7 +780,7 @@ pub fn compare_outputs( JitValue::Array( values .iter() - .map(|value| Felt::from_bytes_le(&value.to_le_bytes())) + .map(|value| Felt::from_bytes_le(&value.to_bytes_le())) .map(JitValue::Felt252) .collect(), ), diff --git a/tests/tests/arrays.rs b/tests/tests/arrays.rs index 29e2e653a..89893afbf 100644 --- a/tests/tests/arrays.rs +++ b/tests/tests/arrays.rs @@ -1,12 +1,12 @@ use crate::common::{any_felt, load_cairo, run_native_program, run_vm_program}; use crate::common::{compare_outputs, DEFAULT_GAS}; -use cairo_felt::Felt252 as DeprecatedFelt; use cairo_lang_runner::{Arg, SierraCasmRunner}; use cairo_lang_sierra::program::Program; use cairo_native::starknet::DummySyscallHandler; use cairo_native::values::JitValue; use lazy_static::lazy_static; use proptest::prelude::*; +use starknet_types_core::felt::Felt; lazy_static! { static ref ARRAY_GET: (String, Program, SierraCasmRunner) = load_cairo! { @@ -55,10 +55,7 @@ fn array_get_test() { let result_vm = run_vm_program( program, "run_test", - &[ - Arg::Value(DeprecatedFelt::from(10)), - Arg::Value(DeprecatedFelt::from(5)), - ], + &[Arg::Value(Felt::from(10)), Arg::Value(Felt::from(5))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -84,8 +81,8 @@ proptest! { fn array_get_test_proptest(value in any_felt(), idx in 0u32..26) { let program = &ARRAY_GET; let result_vm = run_vm_program(program, "run_test", &[ - Arg::Value(DeprecatedFelt::from_bytes_be(&value.to_bytes_be())), - Arg::Value(DeprecatedFelt::from(idx)) + Arg::Value(Felt::from_bytes_be(&value.to_bytes_be())), + Arg::Value(Felt::from(idx)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, diff --git a/tests/tests/boolean.rs b/tests/tests/boolean.rs index 54a801fc1..0deeff58f 100644 --- a/tests/tests/boolean.rs +++ b/tests/tests/boolean.rs @@ -1,10 +1,10 @@ use crate::common::{compare_outputs, load_cairo, run_native_program, run_vm_program, DEFAULT_GAS}; -use cairo_felt::Felt252 as DeprecatedFelt; use cairo_lang_runner::{Arg, SierraCasmRunner}; use cairo_lang_sierra::program::Program; use cairo_native::{starknet::DummySyscallHandler, values::JitValue}; use lazy_static::lazy_static; use proptest::prelude::*; +use starknet_types_core::felt::Felt; lazy_static! { static ref FELT252_TO_BOOL: (String, Program, SierraCasmRunner) = load_cairo! { @@ -115,7 +115,7 @@ fn felt252_to_bool_bug() { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from(a))], + &[Arg::Value(Felt::from(a))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -139,7 +139,7 @@ fn felt252_to_bool_bug() { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from(a))], + &[Arg::Value(Felt::from(a))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -165,7 +165,7 @@ proptest! { fn bool_to_felt252_proptest(a: bool) { let program = &BOOL_TO_FELT252; let result_vm = run_vm_program(program, "run_test", &[ - Arg::Value(DeprecatedFelt::from(a)), + Arg::Value(Felt::from(a)), ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -188,7 +188,7 @@ proptest! { fn bool_not_proptest(a: bool) { let program = &BOOL_NOT; let result_vm = run_vm_program(program, "run_test", &[ - Arg::Value(DeprecatedFelt::from(a)), + Arg::Value(Felt::from(a)), ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -211,8 +211,8 @@ proptest! { fn bool_and_proptest(a: bool, b: bool) { let program = &BOOL_AND; let result_vm = run_vm_program(program, "run_test", &[ - Arg::Value(DeprecatedFelt::from(a)), - Arg::Value(DeprecatedFelt::from(b)) + Arg::Value(Felt::from(a)), + Arg::Value(Felt::from(b)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -235,8 +235,8 @@ proptest! { fn bool_or_proptest(a: bool, b: bool) { let program = &BOOL_OR; let result_vm = run_vm_program(program, "run_test", &[ - Arg::Value(DeprecatedFelt::from(a)), - Arg::Value(DeprecatedFelt::from(b)) + Arg::Value(Felt::from(a)), + Arg::Value(Felt::from(b)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -259,8 +259,8 @@ proptest! { fn bool_xor_proptest(a: bool, b: bool) { let program = &BOOL_XOR; let result_vm = run_vm_program(program, "run_test", &[ - Arg::Value(DeprecatedFelt::from(a)), - Arg::Value(DeprecatedFelt::from(b)) + Arg::Value(Felt::from(a)), + Arg::Value(Felt::from(b)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, diff --git a/tests/tests/dict.rs b/tests/tests/dict.rs index 3b9d32682..6735890be 100644 --- a/tests/tests/dict.rs +++ b/tests/tests/dict.rs @@ -1,12 +1,12 @@ use crate::common::{ any_felt, compare_outputs, load_cairo, run_native_program, run_vm_program, DEFAULT_GAS, }; -use cairo_felt::Felt252 as DeprecatedFelt; use cairo_lang_runner::{Arg, SierraCasmRunner}; use cairo_lang_sierra::program::Program; use cairo_native::{starknet::DummySyscallHandler, values::JitValue}; use lazy_static::lazy_static; use proptest::prelude::*; +use starknet_types_core::felt::Felt; lazy_static! { static ref DICT_GET_INSERT: (String, Program, SierraCasmRunner) = load_cairo! { @@ -28,7 +28,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/ec.rs b/tests/tests/ec.rs index c8178eaac..b0668ee32 100644 --- a/tests/tests/ec.rs +++ b/tests/tests/ec.rs @@ -1,7 +1,6 @@ use crate::common::{ any_felt, compare_outputs, load_cairo, run_native_program, run_vm_program, DEFAULT_GAS, }; -use cairo_felt::Felt252 as DeprecatedFelt; use cairo_lang_runner::{Arg, SierraCasmRunner}; use cairo_lang_sierra::program::Program; use cairo_native::{starknet::DummySyscallHandler, values::JitValue}; @@ -60,7 +59,7 @@ fn ec_point_zero() { #[test] fn ec_point_from_x_big() { - let x = DeprecatedFelt::new( + let x = Felt::from( BigUint::from_str( "10503791839462130483045092717244804953879649418761481950933471772092536173", ) @@ -70,14 +69,14 @@ fn ec_point_from_x_big() { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(x.clone())], + &[Arg::Value(x)], Some(DEFAULT_GAS as usize), ) .unwrap(); let result_native = run_native_program( program, "run_test", - &[JitValue::Felt252(Felt::from_bytes_be(&x.to_be_bytes()))], + &[JitValue::Felt252(Felt::from_bytes_be(&x.to_bytes_be()))], Some(DEFAULT_GAS as u128), Option::::None, ); @@ -93,19 +92,19 @@ fn ec_point_from_x_big() { #[test] fn ec_point_from_x_small() { - let x = DeprecatedFelt::new(BigUint::from_str("1234").unwrap()); + let x = Felt::from(BigUint::from_str("1234").unwrap()); let program = &EC_POINT_FROM_X; let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(x.clone())], + &[Arg::Value(x)], Some(DEFAULT_GAS as usize), ) .unwrap(); let result_native = run_native_program( program, "run_test", - &[JitValue::Felt252(Felt::from_bytes_be(&x.to_be_bytes()))], + &[JitValue::Felt252(Felt::from_bytes_be(&x.to_bytes_be()))], Some(DEFAULT_GAS as u128), Option::::None, ); @@ -126,7 +125,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -152,7 +151,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/felt252.rs b/tests/tests/felt252.rs index d14ff053d..d9216517f 100644 --- a/tests/tests/felt252.rs +++ b/tests/tests/felt252.rs @@ -2,12 +2,12 @@ use crate::common::{ any_felt, compare_outputs, load_cairo, nonzero_felt, run_native_program, run_vm_program, DEFAULT_GAS, }; -use cairo_felt::Felt252 as DeprecatedFelt; use cairo_lang_runner::{Arg, SierraCasmRunner}; use cairo_lang_sierra::program::Program; use cairo_native::{starknet::DummySyscallHandler, values::JitValue}; use lazy_static::lazy_static; use proptest::prelude::*; +use starknet_types_core::felt::Felt; lazy_static! { @@ -63,7 +63,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -89,7 +89,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -115,7 +115,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -141,7 +141,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/programs.rs b/tests/tests/programs.rs index c0c587b9f..558c52ed9 100644 --- a/tests/tests/programs.rs +++ b/tests/tests/programs.rs @@ -1,13 +1,12 @@ use crate::common::{any_felt, load_cairo, run_native_program, run_vm_program}; use crate::common::{compare_outputs, DEFAULT_GAS}; -use cairo_felt::Felt252 as DeprecatedFelt; use cairo_lang_runner::{Arg, SierraCasmRunner}; use cairo_lang_sierra::program::Program; use cairo_native::starknet::DummySyscallHandler; use cairo_native::values::JitValue; use lazy_static::lazy_static; -use num_traits::Num; use proptest::prelude::*; +use starknet_types_core::felt::Felt; lazy_static! { pub static ref FACTORIAL: (String, Program, SierraCasmRunner) = load_cairo! { @@ -118,7 +117,7 @@ fn fib() { let result_vm = run_vm_program( &FIB, "run_test", - &[Arg::Value(DeprecatedFelt::from(10))], + &[Arg::Value(Felt::from(10))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -144,7 +143,7 @@ fn logistic_map() { let result_vm = run_vm_program( &LOGISTIC_MAP, "run_test", - &[Arg::Value(DeprecatedFelt::from(1000))], + &[Arg::Value(Felt::from(1000))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -172,16 +171,14 @@ fn pedersen() { "run_test", &[ Arg::Value( - DeprecatedFelt::from_str_radix( + Felt::from_dec_str( "2163739901324492107409690946633517860331020929182861814098856895601180685", - 10, ) .unwrap(), ), Arg::Value( - DeprecatedFelt::from_str_radix( + Felt::from_dec_str( "2392090257937917229310563411601744459500735555884672871108624696010915493156", - 10, ) .unwrap(), ), @@ -218,7 +215,7 @@ fn factorial() { let result_vm = run_vm_program( &FACTORIAL, "run_test", - &[Arg::Value(DeprecatedFelt::from(13))], + &[Arg::Value(Felt::from(13))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -245,7 +242,7 @@ proptest! { let result_vm = run_vm_program( &FIB, "run_test", - &[Arg::Value(DeprecatedFelt::from(n))], + &[Arg::Value(Felt::from(n))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -270,7 +267,7 @@ proptest! { let result_vm = run_vm_program( &LOGISTIC_MAP, "run_test", - &[Arg::Value(DeprecatedFelt::from(n))], + &[Arg::Value(Felt::from(n))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -295,7 +292,7 @@ proptest! { let result_vm = run_vm_program( &FACTORIAL, "run_test", - &[Arg::Value(DeprecatedFelt::from(n))], + &[Arg::Value(Felt::from(n))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -320,7 +317,7 @@ proptest! { let result_vm = run_vm_program( &PEDERSEN, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -346,9 +343,9 @@ proptest! { let result_vm = run_vm_program( &POSEIDON, "run_test", - &[Arg::Value(DeprecatedFelt::from_bytes_be(&a.clone().to_bytes_be())), - Arg::Value(DeprecatedFelt::from_bytes_be(&b.clone().to_bytes_be())), - Arg::Value(DeprecatedFelt::from_bytes_be(&c.clone().to_bytes_be()))], + &[Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), + Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be())), + Arg::Value(Felt::from_bytes_be(&c.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/starknet/keccak.rs b/tests/tests/starknet/keccak.rs index 73f30ed65..9c9830110 100644 --- a/tests/tests/starknet/keccak.rs +++ b/tests/tests/starknet/keccak.rs @@ -38,7 +38,7 @@ fn keccak_test() { assert!(!result.failure_flag); assert_eq!( result.remaining_gas, - 340282366920938463463374607431767962275 + 340282366920938463463374607431767963515 ); assert_eq!(result.return_values, vec![1.into()]); } diff --git a/tests/tests/starknet/programs/syscalls.cairo b/tests/tests/starknet/programs/syscalls.cairo index 33284009d..c57362bc4 100644 --- a/tests/tests/starknet/programs/syscalls.cairo +++ b/tests/tests/starknet/programs/syscalls.cairo @@ -8,6 +8,9 @@ use core::starknet::{ }; use core::starknet::syscalls::get_execution_info_syscall; use core::starknet::syscalls::get_execution_info_v2_syscall; +use core::sha256::{sha256_state_handle_init, sha256_state_handle_digest, SHA256_INITIAL_STATE}; +use core::box::BoxTrait; +use core::starknet::SyscallResultTrait; fn get_block_hash() -> SyscallResult { get_block_hash_syscall(0) @@ -112,3 +115,12 @@ fn pop_log(log: felt252) -> Span { fn pop_l2_to_l1_message(message: felt252) -> Span { return cheatcode::<'pop_l2_to_l1_message'>(array![message].span()); } + +fn sha256_process() -> [u32; 8] { + let mut state = sha256_state_handle_init(BoxTrait::new(SHA256_INITIAL_STATE)); + let chunk = BoxTrait::new([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xd, 0xe, 0xf, 0x10, 0x11]); + + state = starknet::syscalls::sha256_process_block_syscall(state, chunk).unwrap_syscall(); + + sha256_state_handle_digest(state).unbox() +} diff --git a/tests/tests/starknet/secp256.rs b/tests/tests/starknet/secp256.rs index 65364997e..2be6062a0 100644 --- a/tests/tests/starknet/secp256.rs +++ b/tests/tests/starknet/secp256.rs @@ -247,6 +247,15 @@ impl StarknetSyscallHandler for &mut SyscallHandler { args.push_back(p); Ok(rets.pop_front().unwrap()) } + + fn sha256_process_block( + &mut self, + _prev_state: &[u32; 8], + _current_block: &[u32; 16], + _remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]> { + unimplemented!() + } } lazy_static! { diff --git a/tests/tests/starknet/syscalls.rs b/tests/tests/starknet/syscalls.rs index c4a542750..005fd0cd2 100644 --- a/tests/tests/starknet/syscalls.rs +++ b/tests/tests/starknet/syscalls.rs @@ -494,6 +494,15 @@ impl StarknetSyscallHandler for SyscallHandler { _ => vec![], } } + + fn sha256_process_block( + &mut self, + prev_state: &[u32; 8], + _current_block: &[u32; 16], + _remaining_gas: &mut u128, + ) -> SyscallResult<[u32; 8]> { + Ok(*prev_state) + } } lazy_static! { @@ -1157,3 +1166,38 @@ fn pop_l2_to_l1_message() { .events .is_empty()); } + +#[test] +fn sha256_process() { + let result = run_native_program( + &SYSCALLS_PROGRAM, + "sha256_process", + &[], + Some(u128::MAX), + Some(SyscallHandler::new()), + ); + + assert_eq_sorted!( + result.return_value, + JitValue::Enum { + tag: 0, + value: Box::new(JitValue::Struct { + fields: vec![JitValue::Struct { + fields: vec![ + 1779033703_u32.into(), + 3144134277_u32.into(), + 1013904242_u32.into(), + 2773480762_u32.into(), + 1359893119_u32.into(), + 2600822924_u32.into(), + 528734635_u32.into(), + 1541459225_u32.into(), + ], + debug_name: None + }], + debug_name: None + }), + debug_name: None, + }, + ); +}