From 7c7e6269505f2ad844984a55c43a2b5f6a2fde51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Fri, 13 Sep 2024 18:19:09 +0200 Subject: [PATCH] WIP: need to fix or remove calls to cairo1 helper --- .env.example | 1 + .gitignore | 8 + .python-version | 1 + .trunk/trunk.yaml | 49 +- .vscode/settings.json | 5 +- cairo/.python-version | 1 + cairo/README.md | 0 cairo/pyproject.toml | 24 + cairo/src/__init__.py | 0 cairo/src/account.cairo | 486 ++++ cairo/src/constants.cairo | 1562 +++++++++++ cairo/src/errors.cairo | 773 ++++++ cairo/src/evm.cairo | 337 +++ cairo/src/gas.cairo | 206 ++ .../src/instructions/block_information.cairo | 176 ++ .../instructions/duplication_operations.cairo | 29 + .../environmental_information.cairo | 474 ++++ .../instructions/exchange_operations.cairo | 30 + .../src/instructions/logging_operations.cairo | 76 + .../src/instructions/memory_operations.cairo | 503 ++++ cairo/src/instructions/push_operations.cairo | 39 + cairo/src/instructions/sha3.cairo | 64 + .../stop_and_math_operations.cairo | 562 ++++ .../src/instructions/system_operations.cairo | 1258 +++++++++ cairo/src/interfaces/interfaces.cairo | 26 + cairo/src/interpreter.cairo | 1087 ++++++++ cairo/src/memory.cairo | 298 +++ cairo/src/model.cairo | 223 ++ cairo/src/precompiles/blake2f.cairo | 521 ++++ cairo/src/precompiles/datacopy.cairo | 28 + cairo/src/precompiles/ec_recover.cairo | 102 + cairo/src/precompiles/ecadd.cairo | 47 + cairo/src/precompiles/ecmul.cairo | 44 + .../src/precompiles/kakarot_precompiles.cairo | 64 + cairo/src/precompiles/modexp.cairo | 50 + cairo/src/precompiles/p256verify.cairo | 51 + cairo/src/precompiles/precompiles.cairo | 196 ++ .../src/precompiles/precompiles_helpers.cairo | 36 + cairo/src/precompiles/ripemd160.cairo | 965 +++++++ cairo/src/precompiles/sha256.cairo | 454 ++++ cairo/src/stack.cairo | 155 ++ cairo/src/state.cairo | 478 ++++ cairo/src/utils/alt_bn128/alt_bn128_def.cairo | 18 + .../src/utils/alt_bn128/alt_bn128_field.cairo | 552 ++++ cairo/src/utils/alt_bn128/alt_bn128_g1.cairo | 334 +++ cairo/src/utils/alt_bn128/bigint.cairo | 57 + cairo/src/utils/array.cairo | 121 + cairo/src/utils/bytes.cairo | 312 +++ .../src/utils/compile_keth.py | 5 +- cairo/src/utils/constants.py | 14 + cairo/src/utils/dict.cairo | 134 + cairo/src/utils/eth_transaction.cairo | 386 +++ cairo/src/utils/maths.cairo | 34 + cairo/src/utils/modexp/modexp_utils.cairo | 338 +++ cairo/src/utils/rlp.cairo | 129 + cairo/src/utils/sha_256/packed_sha256.cairo | 288 ++ cairo/src/utils/signature.cairo | 34 + cairo/src/utils/uint256.cairo | 394 +++ cairo/src/utils/uint256.py | 8 + cairo/src/utils/utils.cairo | 1031 ++++++++ cairo/tests/__init__.py | 0 cairo/tests/conftest.py | 78 + cairo/tests/src/__init__.py | 0 cairo/tests/src/conftest.py | 292 +++ .../test_duplication_operations.cairo | 39 + .../test_duplication_operations.py | 9 + .../test_environmental_information.cairo | 292 +++ .../test_environmental_information.py | 126 + .../test_exchange_operations.cairo | 43 + .../instructions/test_exchange_operations.py | 10 + .../instructions/test_memory_operations.cairo | 231 ++ .../instructions/test_memory_operations.py | 148 ++ .../instructions/test_push_operations.cairo | 34 + .../src/instructions/test_push_operations.py | 13 + .../test_stop_and_math_operations.cairo | 63 + .../test_stop_and_math_operations.py | 132 + .../tests/src/precompiles/test_datacopy.cairo | 31 + cairo/tests/src/precompiles/test_datacopy.py | 9 + cairo/tests/src/precompiles/test_ec_add.cairo | 61 + cairo/tests/src/precompiles/test_ec_add.py | 11 + cairo/tests/src/precompiles/test_ec_mul.cairo | 53 + cairo/tests/src/precompiles/test_ec_mul.py | 8 + .../src/precompiles/test_ec_recover.cairo | 23 + .../tests/src/precompiles/test_ec_recover.py | 70 + cairo/tests/src/precompiles/test_modexp.cairo | 27 + cairo/tests/src/precompiles/test_modexp.py | 32 + .../src/precompiles/test_precompiles.cairo | 50 + .../tests/src/precompiles/test_precompiles.py | 106 + .../src/precompiles/test_ripemd160.cairo | 24 + cairo/tests/src/precompiles/test_ripemd160.py | 19 + cairo/tests/src/precompiles/test_sha256.cairo | 27 + cairo/tests/src/precompiles/test_sha256.py | 20 + cairo/tests/src/test_account.cairo | 195 ++ cairo/tests/src/test_account.py | 61 + cairo/tests/src/test_evm.cairo | 69 + cairo/tests/src/test_evm.py | 38 + cairo/tests/src/test_gas.cairo | 85 + cairo/tests/src/test_gas.py | 102 + cairo/tests/src/test_memory.cairo | 81 + cairo/tests/src/test_memory.py | 36 + cairo/tests/src/test_stack.cairo | 147 ++ cairo/tests/src/test_stack.py | 27 + cairo/tests/src/test_state.cairo | 288 ++ cairo/tests/src/test_state.py | 12 + cairo/tests/src/utils/test_array.cairo | 81 + cairo/tests/src/utils/test_array.py | 74 + cairo/tests/src/utils/test_bytes.cairo | 103 + cairo/tests/src/utils/test_bytes.py | 124 + cairo/tests/src/utils/test_dict.cairo | 120 + cairo/tests/src/utils/test_dict.py | 13 + .../src/utils/test_eth_transaction.cairo | 65 + cairo/tests/src/utils/test_eth_transaction.py | 148 ++ cairo/tests/src/utils/test_rlp.cairo | 54 + cairo/tests/src/utils/test_rlp.py | 82 + cairo/tests/src/utils/test_uint256.cairo | 51 + cairo/tests/src/utils/test_uint256.py | 38 + cairo/tests/src/utils/test_utils.cairo | 231 ++ cairo/tests/src/utils/test_utils.py | 236 ++ cairo/tests/utils/constants.py | 349 +++ cairo/tests/utils/coverage.py | 128 + cairo/tests/utils/debug.cairo | 61 + cairo/tests/utils/errors.py | 18 + cairo/tests/utils/helpers.cairo | 206 ++ cairo/tests/utils/helpers.py | 167 ++ cairo/tests/utils/hints.py | 55 + cairo/tests/utils/interface_id.py | 25 + cairo/tests/utils/reporting.py | 80 + cairo/tests/utils/serde.py | 303 +++ cairo_programs/fibonacci.cairo | 18 - cairo_programs/fibonacci.json | 260 -- cairo_programs/syscalls.cairo | 9 - cairo_programs/syscalls.json | 977 ------- cairo_programs/transaction_hash.cairo | 7 - cairo_programs/transaction_hash.json | 70 - poetry.lock | 2305 ----------------- pyproject.toml | 143 +- uv.lock | 2167 ++++++++++++++++ 137 files changed, 24003 insertions(+), 3665 deletions(-) create mode 100644 .env.example create mode 100644 .python-version create mode 100644 cairo/.python-version create mode 100644 cairo/README.md create mode 100644 cairo/pyproject.toml create mode 100644 cairo/src/__init__.py create mode 100644 cairo/src/account.cairo create mode 100644 cairo/src/constants.cairo create mode 100644 cairo/src/errors.cairo create mode 100644 cairo/src/evm.cairo create mode 100644 cairo/src/gas.cairo create mode 100644 cairo/src/instructions/block_information.cairo create mode 100644 cairo/src/instructions/duplication_operations.cairo create mode 100644 cairo/src/instructions/environmental_information.cairo create mode 100644 cairo/src/instructions/exchange_operations.cairo create mode 100644 cairo/src/instructions/logging_operations.cairo create mode 100644 cairo/src/instructions/memory_operations.cairo create mode 100644 cairo/src/instructions/push_operations.cairo create mode 100644 cairo/src/instructions/sha3.cairo create mode 100644 cairo/src/instructions/stop_and_math_operations.cairo create mode 100644 cairo/src/instructions/system_operations.cairo create mode 100644 cairo/src/interfaces/interfaces.cairo create mode 100644 cairo/src/interpreter.cairo create mode 100644 cairo/src/memory.cairo create mode 100644 cairo/src/model.cairo create mode 100644 cairo/src/precompiles/blake2f.cairo create mode 100644 cairo/src/precompiles/datacopy.cairo create mode 100644 cairo/src/precompiles/ec_recover.cairo create mode 100644 cairo/src/precompiles/ecadd.cairo create mode 100644 cairo/src/precompiles/ecmul.cairo create mode 100644 cairo/src/precompiles/kakarot_precompiles.cairo create mode 100644 cairo/src/precompiles/modexp.cairo create mode 100644 cairo/src/precompiles/p256verify.cairo create mode 100644 cairo/src/precompiles/precompiles.cairo create mode 100644 cairo/src/precompiles/precompiles_helpers.cairo create mode 100644 cairo/src/precompiles/ripemd160.cairo create mode 100644 cairo/src/precompiles/sha256.cairo create mode 100644 cairo/src/stack.cairo create mode 100644 cairo/src/state.cairo create mode 100644 cairo/src/utils/alt_bn128/alt_bn128_def.cairo create mode 100644 cairo/src/utils/alt_bn128/alt_bn128_field.cairo create mode 100644 cairo/src/utils/alt_bn128/alt_bn128_g1.cairo create mode 100644 cairo/src/utils/alt_bn128/bigint.cairo create mode 100644 cairo/src/utils/array.cairo create mode 100644 cairo/src/utils/bytes.cairo rename cairo_programs/compile_cairo.py => cairo/src/utils/compile_keth.py (93%) create mode 100644 cairo/src/utils/constants.py create mode 100644 cairo/src/utils/dict.cairo create mode 100644 cairo/src/utils/eth_transaction.cairo create mode 100644 cairo/src/utils/maths.cairo create mode 100644 cairo/src/utils/modexp/modexp_utils.cairo create mode 100644 cairo/src/utils/rlp.cairo create mode 100644 cairo/src/utils/sha_256/packed_sha256.cairo create mode 100644 cairo/src/utils/signature.cairo create mode 100644 cairo/src/utils/uint256.cairo create mode 100644 cairo/src/utils/uint256.py create mode 100644 cairo/src/utils/utils.cairo create mode 100644 cairo/tests/__init__.py create mode 100644 cairo/tests/conftest.py create mode 100644 cairo/tests/src/__init__.py create mode 100644 cairo/tests/src/conftest.py create mode 100644 cairo/tests/src/instructions/test_duplication_operations.cairo create mode 100644 cairo/tests/src/instructions/test_duplication_operations.py create mode 100644 cairo/tests/src/instructions/test_environmental_information.cairo create mode 100644 cairo/tests/src/instructions/test_environmental_information.py create mode 100644 cairo/tests/src/instructions/test_exchange_operations.cairo create mode 100644 cairo/tests/src/instructions/test_exchange_operations.py create mode 100644 cairo/tests/src/instructions/test_memory_operations.cairo create mode 100644 cairo/tests/src/instructions/test_memory_operations.py create mode 100644 cairo/tests/src/instructions/test_push_operations.cairo create mode 100644 cairo/tests/src/instructions/test_push_operations.py create mode 100644 cairo/tests/src/instructions/test_stop_and_math_operations.cairo create mode 100644 cairo/tests/src/instructions/test_stop_and_math_operations.py create mode 100644 cairo/tests/src/precompiles/test_datacopy.cairo create mode 100644 cairo/tests/src/precompiles/test_datacopy.py create mode 100644 cairo/tests/src/precompiles/test_ec_add.cairo create mode 100644 cairo/tests/src/precompiles/test_ec_add.py create mode 100644 cairo/tests/src/precompiles/test_ec_mul.cairo create mode 100644 cairo/tests/src/precompiles/test_ec_mul.py create mode 100644 cairo/tests/src/precompiles/test_ec_recover.cairo create mode 100644 cairo/tests/src/precompiles/test_ec_recover.py create mode 100644 cairo/tests/src/precompiles/test_modexp.cairo create mode 100644 cairo/tests/src/precompiles/test_modexp.py create mode 100644 cairo/tests/src/precompiles/test_precompiles.cairo create mode 100644 cairo/tests/src/precompiles/test_precompiles.py create mode 100644 cairo/tests/src/precompiles/test_ripemd160.cairo create mode 100644 cairo/tests/src/precompiles/test_ripemd160.py create mode 100644 cairo/tests/src/precompiles/test_sha256.cairo create mode 100644 cairo/tests/src/precompiles/test_sha256.py create mode 100644 cairo/tests/src/test_account.cairo create mode 100644 cairo/tests/src/test_account.py create mode 100644 cairo/tests/src/test_evm.cairo create mode 100644 cairo/tests/src/test_evm.py create mode 100644 cairo/tests/src/test_gas.cairo create mode 100644 cairo/tests/src/test_gas.py create mode 100644 cairo/tests/src/test_memory.cairo create mode 100644 cairo/tests/src/test_memory.py create mode 100644 cairo/tests/src/test_stack.cairo create mode 100644 cairo/tests/src/test_stack.py create mode 100644 cairo/tests/src/test_state.cairo create mode 100644 cairo/tests/src/test_state.py create mode 100644 cairo/tests/src/utils/test_array.cairo create mode 100644 cairo/tests/src/utils/test_array.py create mode 100644 cairo/tests/src/utils/test_bytes.cairo create mode 100644 cairo/tests/src/utils/test_bytes.py create mode 100644 cairo/tests/src/utils/test_dict.cairo create mode 100644 cairo/tests/src/utils/test_dict.py create mode 100644 cairo/tests/src/utils/test_eth_transaction.cairo create mode 100644 cairo/tests/src/utils/test_eth_transaction.py create mode 100644 cairo/tests/src/utils/test_rlp.cairo create mode 100644 cairo/tests/src/utils/test_rlp.py create mode 100644 cairo/tests/src/utils/test_uint256.cairo create mode 100644 cairo/tests/src/utils/test_uint256.py create mode 100644 cairo/tests/src/utils/test_utils.cairo create mode 100644 cairo/tests/src/utils/test_utils.py create mode 100644 cairo/tests/utils/constants.py create mode 100644 cairo/tests/utils/coverage.py create mode 100644 cairo/tests/utils/debug.cairo create mode 100644 cairo/tests/utils/errors.py create mode 100644 cairo/tests/utils/helpers.cairo create mode 100644 cairo/tests/utils/helpers.py create mode 100644 cairo/tests/utils/hints.py create mode 100644 cairo/tests/utils/interface_id.py create mode 100644 cairo/tests/utils/reporting.py create mode 100644 cairo/tests/utils/serde.py delete mode 100644 cairo_programs/fibonacci.cairo delete mode 100644 cairo_programs/fibonacci.json delete mode 100644 cairo_programs/syscalls.cairo delete mode 100644 cairo_programs/syscalls.json delete mode 100644 cairo_programs/transaction_hash.cairo delete mode 100644 cairo_programs/transaction_hash.json delete mode 100644 poetry.lock create mode 100644 uv.lock diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..7b3e13f7 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +HYPOTHESIS_PROFILE=dev diff --git a/.gitignore b/.gitignore index 9325aba4..6c6065df 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,11 @@ target/ # Ignore database files **/*.db + +# Cairo project files +*.pyc +*.pb.gz +.env +build +coverage +.hypothesis diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..9919bf8c --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.10.13 diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 3f336df0..9689a3c6 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -2,7 +2,7 @@ # To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml version: 0.1 cli: - version: 1.22.3 + version: 1.22.5 # Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) plugins: sources: @@ -12,6 +12,7 @@ plugins: # Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) runtimes: enabled: + - go@1.21.0 - node@18.12.1 - python@3.10.8 definitions: @@ -19,6 +20,13 @@ runtimes: system_version: allowed # This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) lint: + files: + - name: cairo + extensions: + - cairo + - name: solidity + extensions: + - sol definitions: - name: clippy commands: @@ -26,18 +34,49 @@ lint: run: cargo clippy --message-format json --locked --all-targets --all-features -- --cap-lints=warn --no-deps + - name: cairo + files: [cairo] + commands: + - output: rewrite + success_codes: [0] + formatter: true + run: cairo-format ${target} + read_output_from: stdout + run_linter_from: workspace + - name: solidity + files: [solidity] + commands: + - output: rewrite + success_codes: [0, 1] + formatter: true + run: forge fmt ${target} --check -r + read_output_from: stdout + run_linter_from: workspace enabled: + - dotenv-linter@3.3.0 - actionlint@1.7.1 - - checkov@3.2.238 + - black@24.8.0 + - cairo@SYSTEM + - checkov@3.2.253 - clippy@SYSTEM - - rustfmt@SYSTEM + - codespell@2.3.0 - git-diff-check + - hadolint@2.12.0 + - isort@5.13.2 - markdownlint@0.41.0 - - osv-scanner@1.8.4 + - osv-scanner@1.8.5 + - oxipng@9.1.2 - prettier@3.3.3 + - ruff@0.6.4 + - rustfmt@SYSTEM + - shellcheck@0.10.0 + - shfmt@3.6.0 + - solidity@SYSTEM - taplo@0.9.3 - - trufflehog@3.81.9 + - trivy@0.55.1 + - trufflehog@3.82.1 - yamllint@1.35.1 + actions: disabled: - trunk-announce diff --git a/.vscode/settings.json b/.vscode/settings.json index 84c784c0..2148a7a5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,8 @@ "ommers", "recv", "Risc" - ] + ], + "python.testing.pytestArgs": ["cairo"], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true } diff --git a/cairo/.python-version b/cairo/.python-version new file mode 100644 index 00000000..c8cfe395 --- /dev/null +++ b/cairo/.python-version @@ -0,0 +1 @@ +3.10 diff --git a/cairo/README.md b/cairo/README.md new file mode 100644 index 00000000..e69de29b diff --git a/cairo/pyproject.toml b/cairo/pyproject.toml new file mode 100644 index 00000000..bd1f1c57 --- /dev/null +++ b/cairo/pyproject.toml @@ -0,0 +1,24 @@ +[project] +name = "cairo" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.10" + +dependencies = ["cairo-lang>=0.13.2", "ethereum", "python-dotenv>=1.0.1"] + +[tool.uv] +dev-dependencies = [ + "eth-abi>=5.1.0", + "eth-account>=0.13.3", + "eth-keys>=0.5.1", + "eth-utils>=5.0.0", + "hypothesis>=6.112.1", + "ipykernel>=6.29.5", + "protobuf>=5.28.1", + "pytest-xdist>=3.6.1", + "pytest>=8.3.3", +] + +[tool.uv.sources] +ethereum = { git = "https://github.com/ethereum/execution-specs.git" } diff --git a/cairo/src/__init__.py b/cairo/src/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cairo/src/account.cairo b/cairo/src/account.cairo new file mode 100644 index 00000000..05eacc9e --- /dev/null +++ b/cairo/src/account.cairo @@ -0,0 +1,486 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE, TRUE +from starkware.cairo.common.cairo_builtins import HashBuiltin, KeccakBuiltin, BitwiseBuiltin +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.dict import dict_read, dict_write +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.hash import hash2 +from starkware.cairo.common.math_cmp import is_not_zero +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.hash_state import ( + hash_finalize, + hash_init, + hash_update, + hash_update_single, + hash_update_with_hashchain, +) +from starkware.cairo.lang.compiler.lib.registers import get_ap +from starkware.cairo.common.find_element import find_element + +from src.interfaces.interfaces import ICairo1Helpers +from src.model import model +from src.utils.dict import default_dict_copy +from src.utils.utils import Helpers +from src.utils.bytes import keccak + +namespace Account { + // @notice Create a new account + // @dev New contract accounts start at nonce=1. + // @param address The address (starknet,evm) of the account + // @param code_len The length of the code + // @param code The pointer to the code + // @param nonce The initial nonce + // @return The updated state + // @return The account + func init( + address: model.Address*, + code_len: felt, + code: felt*, + code_hash: Uint256*, + nonce: felt, + balance: Uint256*, + ) -> model.Account* { + let (storage_start) = default_dict_new(0); + let (transient_storage_start) = default_dict_new(0); + let (valid_jumpdests_start) = default_dict_new(0); + return new model.Account( + address=address, + code_len=code_len, + code=code, + code_hash=code_hash, + storage_start=storage_start, + storage=storage_start, + transient_storage_start=transient_storage_start, + transient_storage=transient_storage_start, + valid_jumpdests_start=valid_jumpdests_start, + valid_jumpdests=valid_jumpdests_start, + nonce=nonce, + balance=balance, + selfdestruct=0, + created=0, + ); + } + + // @dev Copy the Account to safely mutate the storage + // @dev Squash dicts used internally + // @param self The pointer to the Account + func copy{range_check_ptr}(self: model.Account*) -> model.Account* { + alloc_locals; + let (storage_start, storage) = default_dict_copy(self.storage_start, self.storage); + let (transient_storage_start, transient_storage) = default_dict_copy( + self.transient_storage_start, self.transient_storage + ); + let (valid_jumpdests_start, valid_jumpdests) = default_dict_copy( + self.valid_jumpdests_start, self.valid_jumpdests + ); + return new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=storage_start, + storage=storage, + transient_storage_start=transient_storage_start, + transient_storage=transient_storage, + valid_jumpdests_start=valid_jumpdests_start, + valid_jumpdests=valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + } + + // @notice Read a given storage + // @dev Try to retrieve in the local Dict first, and returns 0 otherwise. + // @param self The pointer to the execution Account. + // @param key The pointer to the storage key + // @return The updated Account + // @return The read value + func read_storage{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, key: Uint256* + ) -> (model.Account*, Uint256*) { + alloc_locals; + let storage = self.storage; + let (local storage_addr) = Internals._storage_addr(key); + let (pointer) = dict_read{dict_ptr=storage}(key=storage_addr); + local value_ptr: Uint256*; + if (pointer != 0) { + assert value_ptr = cast(pointer, Uint256*); + } else { + assert value_ptr = new Uint256(0, 0); + } + + tempvar self = new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + return (self, value_ptr); + } + + // @notive Read the first value of a given storage slot + // @dev The storage needs to exists already, to this should be used only + // after a storage_read or storage_write has been done + func fetch_original_storage{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, key: Uint256* + ) -> Uint256 { + alloc_locals; + let storage = self.storage; + let (local storage_addr) = Internals._storage_addr(key); + + let (pointer) = dict_read{dict_ptr=storage}(key=storage_addr); + local value_ptr: Uint256*; + if (pointer != 0) { + assert value_ptr = cast(pointer, Uint256*); + } else { + assert value_ptr = new Uint256(0, 0); + } + } + + // @notice Update a storage key with the given value + // @param self The pointer to the Account. + // @param key The pointer to the Uint256 storage key + // @param value The pointer to the Uint256 value + func write_storage{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, key: Uint256*, value: Uint256* + ) -> model.Account* { + alloc_locals; + local storage: DictAccess* = self.storage; + let (storage_addr) = Internals._storage_addr(key); + dict_write{dict_ptr=storage}(key=storage_addr, new_value=cast(value, felt)); + tempvar self = new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + return self; + } + + // @notice Read a given key in the transient storage + // @param self The pointer to the execution Account. + // @param key The pointer to the storage key + // @return The updated Account + // @return The read value + func read_transient_storage{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, key: Uint256* + ) -> (model.Account*, Uint256*) { + alloc_locals; + let transient_storage = self.transient_storage; + let (local storage_addr) = Internals._storage_addr(key); + let (pointer) = dict_read{dict_ptr=transient_storage}(key=storage_addr); + local value_ptr: Uint256*; + + // Case reading from local storage + if (pointer != 0) { + assert value_ptr = cast(pointer, Uint256*); + } else { + assert value_ptr = new Uint256(0, 0); + } + tempvar self = new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + return (self, value_ptr); + } + + // @notice Updates a transient storage key with the given value + // @param self The pointer to the Account. + // @param key The pointer to the Uint256 storage key + // @param value The pointer to the Uint256 value + func write_transient_storage{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, key: Uint256*, value: Uint256* + ) -> model.Account* { + alloc_locals; + local transient_storage: DictAccess* = self.transient_storage; + let (storage_addr) = Internals._storage_addr(key); + dict_write{dict_ptr=transient_storage}(key=storage_addr, new_value=cast(value, felt)); + tempvar self = new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + return self; + } + + // @notice Set the account's bytecode, valid jumpdests and mark it as created during this + // transaction. + // @dev The only reason to set code after creation is in create/deploy operations where + // the account exists from the beginning for setting storages, but the + // deployed bytecode is known at the end (the return_data of the operation). + // @param self The pointer to the Account. + // @param code_len The len of the code + // @param code The code array + // @return The updated Account with the code and valid jumpdests set + func set_code{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, code_len: felt, code: felt* + ) -> model.Account* { + alloc_locals; + compute_code_hash(code_len, code); + let (ap_val) = get_ap(); + let code_hash = cast(ap_val - 2, Uint256*); + let (valid_jumpdests_start, valid_jumpdests) = Helpers.initialize_jumpdests(code_len, code); + return new model.Account( + address=self.address, + code_len=code_len, + code=code, + code_hash=code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=valid_jumpdests_start, + valid_jumpdests=valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=1, + ); + } + + // @notice Set the nonce of the Account + // @param self The pointer to the Account + // @param nonce The new nonce + func set_nonce(self: model.Account*, nonce: felt) -> model.Account* { + return new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + } + + // @notice Sets an account as created + func set_created(self: model.Account*, is_created: felt) -> model.Account* { + return new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=is_created, + ); + } + + // @notice Set the balance of the Account + // @param self The pointer to the Account + // @param balance The new balance + func set_balance(self: model.Account*, balance: Uint256*) -> model.Account* { + return new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + } + + // @notice Register an account for SELFDESTRUCT + // @dev True means that the account will be erased at the end of the transaction + // @return The pointer to the updated Account + func selfdestruct(self: model.Account*) -> model.Account* { + return new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=self.storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=1, + created=self.created, + ); + } + + // @notice Tells if an account has code_len > 0 or nonce > 0 + // @dev See https://github.com/ethereum/execution-specs/blob/3fe6514f2d9d234e760d11af883a47c1263eff51/src/ethereum/shanghai/state.py#L352 + // @param self The pointer to the Account + // @return TRUE is either nonce > 0 or code_len > 0, FALSE otherwise + func has_code_or_nonce(self: model.Account*) -> felt { + if (self.nonce + self.code_len != 0) { + return TRUE; + } + return FALSE; + } + + func is_storage_warm{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, key: Uint256* + ) -> (model.Account*, felt) { + alloc_locals; + local storage: DictAccess* = self.storage; + let (local storage_addr) = Internals._storage_addr(key); + let (pointer) = dict_read{dict_ptr=storage}(key=storage_addr); + + tempvar account = new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=storage, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + + if (pointer != 0) { + return (account, TRUE); + } + return (account, FALSE); + } + + // @notice Caches the given storage keys by creating an entry in the storage dict of the account. + // @dev This is used for access list transactions that provide a list of preaccessed keys + // @param storage_keys_len The number of storage keys to cache. + // @param storage_keys The pointer to the first storage key. + func cache_storage_keys{pedersen_ptr: HashBuiltin*, range_check_ptr}( + self: model.Account*, storage_keys_len: felt, storage_keys: Uint256* + ) -> model.Account* { + alloc_locals; + let storage_ptr = self.storage; + with storage_ptr { + Internals._cache_storage_keys(self.address.evm, storage_keys_len, storage_keys); + } + tempvar self = new model.Account( + address=self.address, + code_len=self.code_len, + code=self.code, + code_hash=self.code_hash, + storage_start=self.storage_start, + storage=storage_ptr, + transient_storage_start=self.transient_storage_start, + transient_storage=self.transient_storage, + valid_jumpdests_start=self.valid_jumpdests_start, + valid_jumpdests=self.valid_jumpdests, + nonce=self.nonce, + balance=self.balance, + selfdestruct=self.selfdestruct, + created=self.created, + ); + return self; + } + + func compute_code_hash{ + range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* + }(code_len: felt, code: felt*) -> Uint256 { + alloc_locals; + if (code_len == 0) { + // see https://eips.ethereum.org/EIPS/eip-1052 + let empty_code_hash = Uint256( + 304396909071904405792975023732328604784, 262949717399590921288928019264691438528 + ); + return empty_code_hash; + } + let code_hash = keccak(code_len, code); + return code_hash; + } +} + +namespace Internals { + // @notice Compute the storage address of the given key + // @dev Just the hash of low and high to get a unique random felt key + func _storage_addr{pedersen_ptr: HashBuiltin*, range_check_ptr}(key: Uint256*) -> (res: felt) { + let (res) = hash2{hash_ptr=pedersen_ptr}(key.low, key.high); + return (res=res); + } + + // TODO: fixme value shouldn't be always 0 + func _cache_storage_keys{pedersen_ptr: HashBuiltin*, range_check_ptr, storage_ptr: DictAccess*}( + evm_address: felt, storage_keys_len: felt, storage_keys: Uint256* + ) { + alloc_locals; + if (storage_keys_len == 0) { + return (); + } + + let key = storage_keys; + let (local storage_addr) = Internals._storage_addr(key); + tempvar value_ptr = new Uint256(0, 0); + dict_write{dict_ptr=storage_ptr}(key=storage_addr, new_value=cast(value_ptr, felt)); + + return _cache_storage_keys(evm_address, storage_keys_len - 1, storage_keys + Uint256.SIZE); + } +} diff --git a/cairo/src/constants.cairo b/cairo/src/constants.cairo new file mode 100644 index 00000000..29d72217 --- /dev/null +++ b/cairo/src/constants.cairo @@ -0,0 +1,1562 @@ +// SPDX-License-Identifier: MIT + +from src.gas import Gas + +// @title Constants file. +// @notice This file contains global constants. +namespace Constants { + const UINT128_MAX = 0xffffffffffffffffffffffffffffffff; + + // STACK + const STACK_MAX_DEPTH = 1024; + + // ACCOUNTS + const MAX_NONCE = 2 ** 64 - 1; + const MAX_CODE_SIZE = 0x6000; + + const BURN_ADDRESS = 0xdead; +} + +// See model.Opcode: +// number +// gas. Some opcodes have a zero fixed gas cost, only depending on dynamic gas cost. (e.g. warm/cold costs). +// stack_input +// stack_size_min +// stack_size_diff +opcodes_label: +// STOP +dw 0x00; +dw 0; +dw 0; +dw 0; +dw 0; +// ADD +dw 0x01; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// MUL +dw 0x02; +dw Gas.LOW; +dw 2; +dw 2; +dw -1; +// SUB +dw 0x03; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// DIV +dw 0x04; +dw Gas.LOW; +dw 2; +dw 2; +dw -1; +// SDIV +dw 0x05; +dw Gas.LOW; +dw 2; +dw 2; +dw -1; +// MOD +dw 0x06; +dw Gas.LOW; +dw 2; +dw 2; +dw -1; +// SMOD +dw 0x07; +dw Gas.LOW; +dw 2; +dw 2; +dw -1; +// ADDMOD +dw 0x08; +dw Gas.MID; +dw 3; +dw 3; +dw -1; +// MULMOD +dw 0x09; +dw Gas.MID; +dw 3; +dw 3; +dw -1; +// EXP +dw 0x0a; +dw Gas.EXPONENTIATION; +dw 2; +dw 2; +dw -1; +// SIGNEXTEND +dw 0x0b; +dw Gas.LOW; +dw 2; +dw 2; +dw -1; +// INVALID +dw 0x0c; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x0d; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x0e; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x0f; +dw 0; +dw 0; +dw 0; +dw 0; +// LT +dw 0x10; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// GT +dw 0x11; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// SLT +dw 0x12; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// SGT +dw 0x13; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// EQ +dw 0x14; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// ISZERO +dw 0x15; +dw Gas.VERY_LOW; +dw 1; +dw 1; +dw 0; +// AND +dw 0x16; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// OR +dw 0x17; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// XOR +dw 0x18; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// NOT +dw 0x19; +dw Gas.VERY_LOW; +dw 1; +dw 1; +dw -1; +// BYTE +dw 0x1a; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// SHL +dw 0x1b; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// SHR +dw 0x1c; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// SAR +dw 0x1d; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -1; +// INVALID +dw 0x1e; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x1f; +dw 0; +dw 0; +dw 0; +dw 0; +// SHA3 +dw 0x20; +dw Gas.KECCAK256; +dw 2; +dw 2; +dw -1; +// INVALID +dw 0x21; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x22; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x23; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x24; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x25; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x26; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x27; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x28; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x29; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x2a; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x2b; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x2c; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x2d; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x2e; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x2f; +dw 0; +dw 0; +dw 0; +dw 0; +// ADDRESS +dw 0x30; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// BALANCE +dw 0x31; +dw 0; +dw 1; +dw 1; +dw 0; +// ORIGIN +dw 0x32; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// CALLER +dw 0x33; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// CALLVALUE +dw 0x34; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// CALLDATALOAD +dw 0x35; +dw Gas.VERY_LOW; +dw 1; +dw 1; +dw 0; +// CALLDATASIZE +dw 0x36; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// CALLDATACOPY +dw 0x37; +dw Gas.VERY_LOW; +dw 3; +dw 3; +dw 0; +// CODESIZE +dw 0x38; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// CODECOPY +dw 0x39; +dw Gas.VERY_LOW; +dw 3; +dw 3; +dw 0; +// GASPRICE +dw 0x3a; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// EXTCODESIZE +dw 0x3b; +dw 0; +dw 1; +dw 1; +dw 0; +// EXTCODECOPY +dw 0x3c; +dw 0; +dw 4; +dw 4; +dw 0; +// RETURNDATASIZE +dw 0x3d; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// RETURNDATACOPY +dw 0x3e; +dw Gas.VERY_LOW; +dw 3; +dw 3; +dw 0; +// EXTCODEHASH +dw 0x3f; +dw 0; +dw 1; +dw 1; +dw 0; +// BLOCKHASH +dw 0x40; +dw Gas.BLOCK_HASH; +dw 1; +dw 1; +dw 0; +// COINBASE +dw 0x41; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// TIMESTAMP +dw 0x42; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// NUMBER +dw 0x43; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// PREVRANDAO +dw 0x44; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// GASLIMIT +dw 0x45; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// CHAINID +dw 0x46; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// SELFBALANCE +dw 0x47; +dw Gas.FAST_STEP; +dw 0; +dw 0; +dw 1; +// BASEFEE +dw 0x48; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// BLOBHASH +dw 0x49; +dw Gas.BLOBHASH; +dw 1; +dw 1; +dw 0; +// BLOBBASEFEE +dw 0x4a; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// INVALID +dw 0x4b; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x4c; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x4d; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x4e; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0x4f; +dw 0; +dw 0; +dw 0; +dw 0; +// POP +dw 0x50; +dw Gas.BASE; +dw 1; +dw 1; +dw -1; +// MLOAD +dw 0x51; +dw Gas.VERY_LOW; +dw 1; +dw 1; +dw 0; +// MSTORE +dw 0x52; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -2; +// MSTORE8 +dw 0x53; +dw Gas.VERY_LOW; +dw 2; +dw 2; +dw -2; +// SLOAD +dw 0x54; +dw 0; // gas cost is dynamic +dw 1; +dw 1; +dw 0; +// SSTORE +dw 0x55; +dw 0; +dw 2; +dw 2; +dw -2; +// JUMP +dw 0x56; +dw Gas.MID; +dw 1; +dw 1; +dw -1; +// JUMPI +dw 0x57; +dw Gas.HIGH; +dw 2; +dw 2; +dw -2; +// PC +dw 0x58; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// MSIZE +dw 0x59; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// GAS +dw 0x5a; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// JUMPDEST +dw 0x5b; +dw Gas.JUMPDEST; +dw 0; +dw 0; +dw 0; +// TLOAD +dw 0x5c; +dw 0; // gas cost is dynamic +dw 1; +dw 1; +dw 0; +// TSTORE +dw 0x5d; +dw 0; // gas cost is dynamic +dw 2; +dw 2; +dw -2; +// MCOPY +dw 0x5e; +dw Gas.VERY_LOW; // + Dynamic gas +dw 3; +dw 3; +dw -3; +// PUSH0 +dw 0x5f; +dw Gas.BASE; +dw 0; +dw 0; +dw 1; +// PUSH1 +dw 0x60; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH2 +dw 0x61; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH3 +dw 0x62; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH4 +dw 0x63; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH5 +dw 0x64; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH6 +dw 0x65; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH7 +dw 0x66; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH8 +dw 0x67; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH9 +dw 0x68; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH10 +dw 0x69; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH11 +dw 0x6a; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH12 +dw 0x6b; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH13 +dw 0x6c; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH14 +dw 0x6d; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH15 +dw 0x6e; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH16 +dw 0x6f; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH17 +dw 0x70; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH18 +dw 0x71; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH19 +dw 0x72; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH20 +dw 0x73; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH21 +dw 0x74; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH22 +dw 0x75; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH23 +dw 0x76; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH24 +dw 0x77; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH25 +dw 0x78; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH26 +dw 0x79; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH27 +dw 0x7a; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH28 +dw 0x7b; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH29 +dw 0x7c; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH30 +dw 0x7d; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH31 +dw 0x7e; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// PUSH32 +dw 0x7f; +dw Gas.VERY_LOW; +dw 0; +dw 0; +dw 1; +// DUP1 +dw 0x80; +dw Gas.VERY_LOW; +dw 0; +dw 1; +dw 1; +// DUP2 +dw 0x81; +dw Gas.VERY_LOW; +dw 0; +dw 2; +dw 1; +// DUP3 +dw 0x82; +dw Gas.VERY_LOW; +dw 0; +dw 3; +dw 1; +// DUP4 +dw 0x83; +dw Gas.VERY_LOW; +dw 0; +dw 4; +dw 1; +// DUP5 +dw 0x84; +dw Gas.VERY_LOW; +dw 0; +dw 5; +dw 1; +// DUP6 +dw 0x85; +dw Gas.VERY_LOW; +dw 0; +dw 6; +dw 1; +// DUP7 +dw 0x86; +dw Gas.VERY_LOW; +dw 0; +dw 7; +dw 1; +// DUP8 +dw 0x87; +dw Gas.VERY_LOW; +dw 0; +dw 8; +dw 1; +// DUP9 +dw 0x88; +dw Gas.VERY_LOW; +dw 0; +dw 9; +dw 1; +// DUP10 +dw 0x89; +dw Gas.VERY_LOW; +dw 0; +dw 10; +dw 1; +// DUP11 +dw 0x8a; +dw Gas.VERY_LOW; +dw 0; +dw 11; +dw 1; +// DUP12 +dw 0x8b; +dw Gas.VERY_LOW; +dw 0; +dw 12; +dw 1; +// DUP13 +dw 0x8c; +dw Gas.VERY_LOW; +dw 0; +dw 13; +dw 1; +// DUP14 +dw 0x8d; +dw Gas.VERY_LOW; +dw 0; +dw 14; +dw 1; +// DUP15 +dw 0x8e; +dw Gas.VERY_LOW; +dw 0; +dw 15; +dw 1; +// DUP16 +dw 0x8f; +dw Gas.VERY_LOW; +dw 0; +dw 16; +dw 1; +// SWAP1 +dw 0x90; +dw Gas.VERY_LOW; +dw 0; +dw 2; +dw 0; +// SWAP2 +dw 0x91; +dw Gas.VERY_LOW; +dw 0; +dw 3; +dw 0; +// SWAP3 +dw 0x92; +dw Gas.VERY_LOW; +dw 0; +dw 4; +dw 0; +// SWAP4 +dw 0x93; +dw Gas.VERY_LOW; +dw 0; +dw 5; +dw 0; +// SWAP5 +dw 0x94; +dw Gas.VERY_LOW; +dw 0; +dw 6; +dw 0; +// SWAP6 +dw 0x95; +dw Gas.VERY_LOW; +dw 0; +dw 7; +dw 0; +// SWAP7 +dw 0x96; +dw Gas.VERY_LOW; +dw 0; +dw 8; +dw 0; +// SWAP8 +dw 0x97; +dw Gas.VERY_LOW; +dw 0; +dw 9; +dw 0; +// SWAP9 +dw 0x98; +dw Gas.VERY_LOW; +dw 0; +dw 10; +dw 0; +// SWAP10 +dw 0x99; +dw Gas.VERY_LOW; +dw 0; +dw 11; +dw 0; +// SWAP11 +dw 0x9a; +dw Gas.VERY_LOW; +dw 0; +dw 12; +dw 0; +// SWAP12 +dw 0x9b; +dw Gas.VERY_LOW; +dw 0; +dw 13; +dw 0; +// SWAP13 +dw 0x9c; +dw Gas.VERY_LOW; +dw 0; +dw 14; +dw 0; +// SWAP14 +dw 0x9d; +dw Gas.VERY_LOW; +dw 0; +dw 15; +dw 0; +// SWAP15 +dw 0x9e; +dw Gas.VERY_LOW; +dw 0; +dw 16; +dw 0; +// SWAP16 +dw 0x9f; +dw Gas.VERY_LOW; +dw 0; +dw 17; +dw 0; +// LOG0 +dw 0xa0; +dw Gas.LOG; +dw 2; +dw 2; +dw -2; +// LOG1 +dw 0xa1; +dw Gas.LOG; +dw 3; +dw 3; +dw -3; +// LOG2 +dw 0xa2; +dw Gas.LOG; +dw 4; +dw 4; +dw -4; +// LOG3 +dw 0xa3; +dw Gas.LOG; +dw 5; +dw 5; +dw -5; +// LOG4 +dw 0xa4; +dw Gas.LOG; +dw 6; +dw 6; +dw -6; +// INVALID +dw 0xa5; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xa6; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xa7; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xa8; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xa9; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xaa; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xab; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xac; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xad; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xae; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xaf; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb0; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb1; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb2; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb3; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb4; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb5; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb6; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb7; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb8; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xb9; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xba; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xbb; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xbc; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xbd; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xbe; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xbf; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc0; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc1; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc2; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc3; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc4; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc5; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc6; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc7; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc8; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xc9; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xca; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xcb; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xcc; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xcd; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xce; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xcf; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd0; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd1; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd2; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd3; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd4; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd5; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd6; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd7; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd8; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xd9; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xda; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xdb; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xdc; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xdd; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xde; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xdf; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe0; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe1; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe2; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe3; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe4; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe5; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe6; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe7; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe8; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xe9; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xea; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xeb; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xec; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xed; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xee; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xef; +dw 0; +dw 0; +dw 0; +dw 0; +// CREATE +dw 0xf0; +dw Gas.CREATE; +dw 3; +dw 3; +dw -2; +// CALL +dw 0xf1; +dw 0; +dw 7; +dw 7; +dw -6; +// CALLCODE +dw 0xf2; +dw 0; +dw 7; +dw 7; +dw -6; +// RETURN +dw 0xf3; +dw Gas.ZERO; +dw 2; +dw 2; +dw -2; +// DELEGATECALL +dw 0xf4; +dw 0; +dw 6; +dw 6; +dw -5; +// CREATE2 +dw 0xf5; +dw Gas.CREATE; +dw 4; +dw 4; +dw -3; +// INVALID +dw 0xf6; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xf7; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xf8; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xf9; +dw 0; +dw 0; +dw 0; +dw 0; +// STATICCALL +dw 0xfa; +dw 0; +dw 6; +dw 6; +dw -5; +// INVALID +dw 0xfb; +dw 0; +dw 0; +dw 0; +dw 0; +// INVALID +dw 0xfc; +dw 0; +dw 0; +dw 0; +dw 0; +// REVERT +dw 0xfd; +dw 0; +dw 2; +dw 2; +dw -2; +// INVALID +dw 0xfe; +dw 0; +dw 0; +dw 0; +dw 0; +// SELFDESTRUCT +dw 0xff; +dw Gas.SELF_DESTRUCT; +dw 1; +dw 1; +dw -1; diff --git a/cairo/src/errors.cairo b/cairo/src/errors.cairo new file mode 100644 index 00000000..802c02b2 --- /dev/null +++ b/cairo/src/errors.cairo @@ -0,0 +1,773 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.math_cmp import is_nn + +from src.utils.bytes import felt_to_ascii + +namespace Errors { + const REVERT = 1; + const EXCEPTIONAL_HALT = 2; + + func eth_validation_failed() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(eth_validation_failed_message); + return (30, error); + + eth_validation_failed_message: + dw 0x4b; // K + dw 0x61; // a + dw 0x6b; // k + dw 0x61; // a + dw 0x72; // r + dw 0x6f; // o + dw 0x74; // t + dw 0x3a; // : + dw 0x20; // + dw 0x65; // e + dw 0x74; // t + dw 0x68; // h + dw 0x20; // + dw 0x76; // v + dw 0x61; // a + dw 0x6c; // l + dw 0x69; // i + dw 0x64; // d + dw 0x61; // a + dw 0x74; // t + dw 0x69; // i + dw 0x6f; // o + dw 0x6e; // n + dw 0x20; // + dw 0x66; // f + dw 0x61; // a + dw 0x69; // i + dw 0x6c; // l + dw 0x65; // e + dw 0x64; // d + } + + func stateModificationError() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(state_modification_error_message); + return (31, error); + + state_modification_error_message: + dw 75; // K + dw 97; // a + dw 107; // k + dw 97; // a + dw 114; // r + dw 111; // o + dw 116; // t + dw 58; // : + dw 32; // + dw 83; // S + dw 116; // t + dw 97; // a + dw 116; // t + dw 101; // e + dw 77; // M + dw 111; // o + dw 100; // d + dw 105; // i + dw 102; // f + dw 105; // i + dw 99; // c + dw 97; // a + dw 116; // t + dw 105; // i + dw 111; // o + dw 110; // n + dw 69; // E + dw 114; // r + dw 114; // r + dw 111; // o + dw 114; // r + } + + func unknownOpcode() -> (error_len: felt, error: felt*) { + alloc_locals; + let (error) = get_label_location(unknown_opcode_error_message); + return (22, error); + + unknown_opcode_error_message: + dw 75; // K' + dw 97; // a' + dw 107; // k' + dw 97; // a' + dw 114; // r' + dw 111; // o' + dw 116; // t' + dw 58; // :' + dw 32; // ' + dw 85; // U' + dw 110; // n' + dw 107; // k' + dw 110; // n' + dw 111; // o' + dw 119; // w' + dw 110; // n' + dw 79; // O' + dw 112; // p' + dw 99; // c' + dw 111; // o' + dw 100; // d' + dw 101; // e' + } + + func invalidJumpDestError() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(invalid_jump_dest_message); + return (29, error); + + invalid_jump_dest_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'i'; + dw 'n'; + dw 'v'; + dw 'a'; + dw 'l'; + dw 'i'; + dw 'd'; + dw 'J'; + dw 'u'; + dw 'm'; + dw 'p'; + dw 'D'; + dw 'e'; + dw 's'; + dw 't'; + dw 'E'; + dw 'r'; + dw 'r'; + dw 'o'; + dw 'r'; + } + + func callerNotKakarotAccount() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(caller_non_kakarot_error_message); + return (49, error); + + caller_non_kakarot_error_message: + dw 75; // K + dw 97; // a + dw 107; // k + dw 97; // a + dw 114; // r + dw 111; // o + dw 116; // t + dw 58; // : + dw 32; // + dw 99; // c + dw 97; // a + dw 108; // l + dw 108; // l + dw 101; // e + dw 114; // r + dw 32; // + dw 99; // c + dw 111; // o + dw 110; // n + dw 116; // t + dw 114; // r + dw 97; // a + dw 99; // c + dw 116; // t + dw 32; // + dw 105; // i + dw 115; // s + dw 32; // + dw 110; // n + dw 111; // o + dw 116; // t + dw 32; // + dw 97; // a + dw 32; // + dw 75; // K + dw 97; // a + dw 107; // k + dw 97; // a + dw 114; // r + dw 111; // o + dw 116; // t + dw 32; // + dw 65; // A + dw 99; // c + dw 99; // c + dw 111; // o + dw 117; // u + dw 110; // n + dw 116; // t + } + + func onlyViewEntrypoint() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(only_view_error_message); + return (54, error); + + only_view_error_message: + dw 75; // K + dw 97; // a + dw 107; // k + dw 97; // a + dw 114; // r + dw 111; // o + dw 116; // t + dw 58; // : + dw 32; // + dw 101; // e + dw 110; // n + dw 116; // t + dw 114; // r + dw 121; // y + dw 112; // p + dw 111; // o + dw 105; // i + dw 110; // n + dw 116; // t + dw 32; // + dw 115; // s + dw 104; // h + dw 111; // o + dw 117; // u + dw 108; // l + dw 100; // d + dw 32; // + dw 111; // o + dw 110; // n + dw 108; // l + dw 121; // y + dw 32; // + dw 98; // b + dw 101; // e + dw 32; // + dw 99; // c + dw 97; // a + dw 108; // l + dw 108; // l + dw 101; // e + dw 100; // d + dw 32; // + dw 105; // i + dw 110; // n + dw 32; // + dw 118; // v + dw 105; // i + dw 101; // e + dw 119; // w + dw 32; // + dw 109; // m + dw 111; // o + dw 100; // d + dw 101; // e + } + + func stackOverflow() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(stack_overflow_error_message); + return (22, error); + + stack_overflow_error_message: + dw 75; // K + dw 97; // a + dw 107; // k + dw 97; // a + dw 114; // r + dw 111; // o + dw 116; // t + dw 58; // : + dw 32; // + dw 83; // S + dw 116; // t + dw 97; // a + dw 99; // c + dw 107; // k + dw 79; // O + dw 118; // v + dw 101; // e + dw 114; // r + dw 102; // f + dw 108; // l + dw 111; // o + dw 119; // w + } + + func stackUnderflow() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(stack_underflow_error_message); + return (23, error); + + stack_underflow_error_message: + dw 75; // K + dw 97; // a + dw 107; // k + dw 97; // a + dw 114; // r + dw 111; // o + dw 116; // t + dw 58; // : + dw 32; // + dw 83; // S + dw 116; // t + dw 97; // a + dw 99; // c + dw 107; // k + dw 85; // U + dw 110; // n + dw 100; // d + dw 101; // e + dw 114; // r + dw 102; // f + dw 108; // l + dw 111; // o + dw 119; // w + } + + func outOfBoundsRead() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(out_of_bounds_read_error_message); + return (24, error); + + out_of_bounds_read_error_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'O'; + dw 'u'; + dw 't'; + dw 'O'; + dw 'f'; + dw 'B'; + dw 'o'; + dw 'u'; + dw 'n'; + dw 'd'; + dw 's'; + dw 'R'; + dw 'e'; + dw 'a'; + dw 'd'; + } + + func unknownPrecompile(address: felt) -> (error_len: felt, error: felt*) { + alloc_locals; + let (error) = alloc(); + assert [error + 0] = 75; // K + assert [error + 1] = 97; // a + assert [error + 2] = 107; // k + assert [error + 3] = 97; // a + assert [error + 4] = 114; // r + assert [error + 5] = 111; // o + assert [error + 6] = 116; // t + assert [error + 7] = 58; // : + assert [error + 8] = 32; // + assert [error + 9] = 85; // U + assert [error + 10] = 110; // n + assert [error + 11] = 107; // k + assert [error + 12] = 110; // n + assert [error + 13] = 111; // o + assert [error + 14] = 119; // w + assert [error + 15] = 110; // n + assert [error + 16] = 80; // P + assert [error + 17] = 114; // r + assert [error + 18] = 101; // e + assert [error + 19] = 99; // c + assert [error + 20] = 111; // o + assert [error + 21] = 109; // m + assert [error + 22] = 112; // p + assert [error + 23] = 105; // i + assert [error + 24] = 108; // l + assert [error + 25] = 101; // e + assert [error + 26] = 32; // " " + assert [error + 27] = '0' + address; // convert uint address to str + return (28, error); + } + + func unauthorizedPrecompile() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(unauthorized_precompile_error_message); + return (31, error); + + unauthorized_precompile_error_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'u'; + dw 'n'; + dw 'a'; + dw 'u'; + dw 't'; + dw 'h'; + dw 'o'; + dw 'r'; + dw 'i'; + dw 'z'; + dw 'e'; + dw 'd'; + dw 'P'; + dw 'r'; + dw 'e'; + dw 'c'; + dw 'o'; + dw 'm'; + dw 'p'; + dw 'i'; + dw 'l'; + dw 'e'; + } + + func accountNotDeployed() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(account_not_deployed_error_message); + return (27, error); + + account_not_deployed_error_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'a'; + dw 'c'; + dw 'c'; + dw 'o'; + dw 'u'; + dw 'n'; + dw 't'; + dw 'N'; + dw 'o'; + dw 't'; + dw 'D'; + dw 'e'; + dw 'p'; + dw 'l'; + dw 'o'; + dw 'y'; + dw 'e'; + dw 'd'; + } + + func notImplementedPrecompile(address: felt) -> (error_len: felt, error: felt*) { + alloc_locals; + let (error) = alloc(); + assert [error + 0] = 75; // K + assert [error + 1] = 97; // a + assert [error + 2] = 107; // k + assert [error + 3] = 97; // a + assert [error + 4] = 114; // r + assert [error + 5] = 111; // o + assert [error + 6] = 116; // t + assert [error + 7] = 58; // : + assert [error + 8] = 32; // + assert [error + 9] = 78; // N + assert [error + 10] = 111; // o + assert [error + 11] = 116; // t + assert [error + 12] = 73; // I + assert [error + 13] = 109; // m + assert [error + 14] = 112; // p + assert [error + 15] = 108; // l + assert [error + 16] = 101; // e + assert [error + 17] = 109; // m + assert [error + 18] = 101; // e + assert [error + 19] = 110; // n + assert [error + 20] = 116; // t + assert [error + 21] = 101; // e + assert [error + 22] = 100; // d + assert [error + 23] = 80; // P + assert [error + 24] = 114; // r + assert [error + 25] = 101; // e + assert [error + 26] = 99; // c + assert [error + 27] = 111; // o + assert [error + 28] = 109; // m + assert [error + 29] = 112; // p + assert [error + 30] = 105; // i + assert [error + 31] = 108; // l + assert [error + 32] = 101; // e + assert [error + 33] = 32; // + + if (address == 10) { + assert [error + 34] = '1'; + assert [error + 35] = '0'; + return (36, error); + } + assert [error + 34] = '0' + address; + return (35, error); + } + + func invalidCairoSelector() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(invalid_cairo_selector_message); + return (29, error); + + invalid_cairo_selector_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'i'; + dw 'n'; + dw 'v'; + dw 'a'; + dw 'l'; + dw 'i'; + dw 'd'; + dw 'C'; + dw 'a'; + dw 'i'; + dw 'r'; + dw 'o'; + dw 'S'; + dw 'e'; + dw 'l'; + dw 'e'; + dw 'c'; + dw 't'; + dw 'o'; + dw 'r'; + } + + func balanceError() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(balance_error_message); + return (40, error); + + balance_error_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 't'; + dw 'r'; + dw 'a'; + dw 'n'; + dw 's'; + dw 'f'; + dw 'e'; + dw 'r'; + dw ' '; + dw 'a'; + dw 'm'; + dw 'o'; + dw 'u'; + dw 'n'; + dw 't'; + dw ' '; + dw 'e'; + dw 'x'; + dw 'c'; + dw 'e'; + dw 'e'; + dw 'd'; + dw 's'; + dw ' '; + dw 'b'; + dw 'a'; + dw 'l'; + dw 'a'; + dw 'n'; + dw 'c'; + dw 'e'; + } + + func addressCollision() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(address_collision_error_message); + return (25, error); + + address_collision_error_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'a'; + dw 'd'; + dw 'd'; + dw 'r'; + dw 'e'; + dw 's'; + dw 's'; + dw 'C'; + dw 'o'; + dw 'l'; + dw 'l'; + dw 'i'; + dw 's'; + dw 'i'; + dw 'o'; + dw 'n'; + } + + func outOfGas{range_check_ptr}(gas_left: felt, gas_used: felt) -> ( + error_len: felt, error: felt* + ) { + alloc_locals; + let (error: felt*) = alloc(); + + assert [error + 0] = 'K'; + assert [error + 1] = 'a'; + assert [error + 2] = 'k'; + assert [error + 3] = 'a'; + assert [error + 4] = 'r'; + assert [error + 5] = 'o'; + assert [error + 6] = 't'; + assert [error + 7] = ':'; + assert [error + 8] = ' '; + assert [error + 9] = 'o'; + assert [error + 10] = 'u'; + assert [error + 11] = 't'; + assert [error + 12] = 'O'; + assert [error + 13] = 'f'; + assert [error + 14] = 'G'; + assert [error + 15] = 'a'; + assert [error + 16] = 's'; + assert [error + 17] = ' '; + assert [error + 18] = 'l'; + assert [error + 19] = 'e'; + assert [error + 20] = 'f'; + assert [error + 21] = 't'; + assert [error + 22] = '='; + + let gas_left_in_range = is_nn(gas_left); + if (gas_left_in_range == 0) { + // Trim the useless left= part of the string + return (17, error); + } + + let gas_left_ascii_len = felt_to_ascii(error + 23, gas_left); + + assert [error + 23 + gas_left_ascii_len + 0] = ','; + assert [error + 23 + gas_left_ascii_len + 1] = ' '; + assert [error + 23 + gas_left_ascii_len + 2] = 'u'; + assert [error + 23 + gas_left_ascii_len + 3] = 's'; + assert [error + 23 + gas_left_ascii_len + 4] = 'e'; + assert [error + 23 + gas_left_ascii_len + 5] = 'd'; + assert [error + 23 + gas_left_ascii_len + 6] = '='; + + let gas_used_in_range = is_nn(gas_used); + + if (gas_used_in_range == 0) { + return (23 + gas_left_ascii_len + 7, error); + } + + let gas_used_ascii_len = felt_to_ascii(error + 23 + gas_left_ascii_len + 7, gas_used); + + return (23 + gas_left_ascii_len + 7 + gas_used_ascii_len, error); + } + + func precompileInputError() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(precompile_input_error_message); + return (27, error); + + precompile_input_error_message: + dw 'P'; + dw 'r'; + dw 'e'; + dw 'c'; + dw 'o'; + dw 'm'; + dw 'p'; + dw 'i'; + dw 'l'; + dw 'e'; + dw ':'; + dw ' '; + dw 'w'; + dw 'r'; + dw 'o'; + dw 'n'; + dw 'g'; + dw ' '; + dw 'i'; + dw 'n'; + dw 'p'; + dw 'u'; + dw 't'; + dw '_'; + dw 'l'; + dw 'e'; + dw 'n'; + } + + func precompileFlagError() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(precompile_flag_error); + return (22, error); + + precompile_flag_error: + dw 'P'; + dw 'r'; + dw 'e'; + dw 'c'; + dw 'o'; + dw 'm'; + dw 'p'; + dw 'i'; + dw 'l'; + dw 'e'; + dw ':'; + dw ' '; + dw 'f'; + dw 'l'; + dw 'a'; + dw 'g'; + dw ' '; + dw 'e'; + dw 'r'; + dw 'r'; + dw 'o'; + dw 'r'; + } + + func kakarotReentrancy() -> (error_len: felt, error: felt*) { + let (error) = get_label_location(kakarot_reentrancy_error_message); + return (19, error); + + kakarot_reentrancy_error_message: + dw 'K'; + dw 'a'; + dw 'k'; + dw 'a'; + dw 'r'; + dw 'o'; + dw 't'; + dw ':'; + dw ' '; + dw 'r'; + dw 'e'; + dw 'e'; + dw 'n'; + dw 't'; + dw 'r'; + dw 'a'; + dw 'n'; + dw 'c'; + dw 'y'; + } +} diff --git a/cairo/src/evm.cairo b/cairo/src/evm.cairo new file mode 100644 index 00000000..4a805a94 --- /dev/null +++ b/cairo/src/evm.cairo @@ -0,0 +1,337 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math_cmp import is_nn, is_le_felt, RC_BOUND +from starkware.cairo.common.math import assert_le_felt +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.dict import dict_read, dict_write, DictAccess +from starkware.cairo.common.default_dict import default_dict_finalize + +from src.errors import Errors +from src.model import model +from src.account import Account +from src.stack import Stack +from src.state import State +from src.interfaces.interfaces import IAccount + +// @title EVM related functions. +// @notice This file contains functions related to the execution context. +namespace EVM { + // @notice Initialize the execution context. + // @dev Initialize the execution context of a specific contract. + // @param message The message (see model.Message) to be executed. + // @return EVM The initialized execution context. + func init(message: model.Message*, gas_left: felt) -> model.EVM* { + let (return_data: felt*) = alloc(); + + return new model.EVM( + message=message, + return_data_len=0, + return_data=return_data, + program_counter=0, + stopped=FALSE, + gas_left=gas_left, + gas_refund=0, + reverted=FALSE, + ); + } + + func finalize{range_check_ptr, evm: model.EVM*}() { + let (squashed_start, squashed_end) = default_dict_finalize( + evm.message.valid_jumpdests_start, evm.message.valid_jumpdests, 0 + ); + tempvar message = new model.Message( + bytecode=evm.message.bytecode, + bytecode_len=evm.message.bytecode_len, + valid_jumpdests_start=squashed_start, + valid_jumpdests=squashed_end, + calldata=evm.message.calldata, + calldata_len=evm.message.calldata_len, + value=evm.message.value, + caller=evm.message.caller, + parent=evm.message.parent, + address=evm.message.address, + code_address=evm.message.code_address, + read_only=evm.message.read_only, + is_create=evm.message.is_create, + depth=evm.message.depth, + env=evm.message.env, + cairo_precompile_called=evm.message.cairo_precompile_called, + ); + + tempvar evm = new model.EVM( + message=message, + return_data_len=evm.return_data_len, + return_data=evm.return_data, + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund, + reverted=evm.reverted, + ); + + return (); + } + + // @notice Stop the current execution context. + // @dev When the execution context is stopped, no more instructions can be executed. + // @param self The pointer to the execution context. + // @param return_data_len The length of the return_data. + // @param return_data The pointer to the return_data array. + // @param reverted A code indicating whether the EVM is reverted or not. + // can be either 0 - not reverted, Errors.REVERTED or Errors.EXCEPTIONAL_HALT + // @return EVM The pointer to the updated execution context. + func stop( + self: model.EVM*, return_data_len: felt, return_data: felt*, reverted: felt + ) -> model.EVM* { + return new model.EVM( + message=self.message, + return_data_len=return_data_len, + return_data=return_data, + program_counter=self.program_counter, + stopped=TRUE, + gas_left=self.gas_left, + gas_refund=self.gas_refund, + reverted=reverted, + ); + } + + func out_of_gas{range_check_ptr}(self: model.EVM*, amount: felt) -> model.EVM* { + let (revert_reason_len, revert_reason) = Errors.outOfGas(self.gas_left, amount); + return new model.EVM( + message=self.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=self.program_counter, + stopped=TRUE, + gas_left=0, + gas_refund=self.gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + } + + // @notice Update the return data of the current execution context. + // @param self The pointer to the execution context. + // @param return_data_len The length of the return_data. + // @param return_data The pointer to the return_data array. + // @return EVM The pointer to the updated execution context. + func update_return_data( + self: model.EVM*, return_data_len: felt, return_data: felt* + ) -> model.EVM* { + return new model.EVM( + message=self.message, + return_data_len=return_data_len, + return_data=return_data, + program_counter=self.program_counter, + stopped=self.stopped, + gas_left=self.gas_left, + gas_refund=self.gas_refund, + reverted=self.reverted, + ); + } + + // @notice Increment the program counter. + // @dev The program counter is incremented by the given value. + // @param self The pointer to the execution context. + // @param inc_value The value to increment the program counter with. + // @return EVM The pointer to the updated execution context. + func increment_program_counter(self: model.EVM*, inc_value: felt) -> model.EVM* { + return new model.EVM( + message=self.message, + return_data_len=self.return_data_len, + return_data=self.return_data, + program_counter=self.program_counter + inc_value, + stopped=self.stopped, + gas_left=self.gas_left, + gas_refund=self.gas_refund, + reverted=self.reverted, + ); + } + + // @notice Subtracts `amount` from `evm.gas_left`. + // @dev The gas left is decremented by the given amount. + // Use code adapted from is_nn. + // Assumption: gas_left < 2 ** 128 + // @param self The pointer to the current execution context. + // @param amount The amount of gas the current operation requires. + // @return EVM The pointer to the updated execution context. + func charge_gas{range_check_ptr}(self: model.EVM*, amount: felt) -> model.EVM* { + // This is equivalent to is_nn(self.gas_left - amount) + tempvar a = self.gas_left - amount; // a is necessary for using the whitelisted hint + %{ memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1 %} + jmp out_of_range if [ap] != 0, ap++; + [range_check_ptr] = a; + ap += 20; + tempvar range_check_ptr = range_check_ptr + 1; + jmp enough_gas; + + out_of_range: + %{ memory[ap] = 0 if 0 <= ((-ids.a - 1) % PRIME) < range_check_builtin.bound else 1 %} + jmp need_felt_comparison if [ap] != 0, ap++; + assert [range_check_ptr] = (-a) - 1; + ap += 17; + tempvar range_check_ptr = range_check_ptr + 1; + jmp not_enough_gas; + + need_felt_comparison: + assert_le_felt(RC_BOUND, a); + jmp not_enough_gas; + + enough_gas: + let range_check_ptr = [ap - 1]; + return new model.EVM( + message=self.message, + return_data_len=self.return_data_len, + return_data=self.return_data, + program_counter=self.program_counter, + stopped=self.stopped, + gas_left=a, + gas_refund=self.gas_refund, + reverted=self.reverted, + ); + + not_enough_gas: + let range_check_ptr = [ap - 1]; + let (revert_reason_len, revert_reason) = Errors.outOfGas(self.gas_left, amount); + return new model.EVM( + message=self.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=self.program_counter, + stopped=TRUE, + gas_left=0, + gas_refund=self.gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + } + + func halt_validation_failed{range_check_ptr}(self: model.EVM*) -> model.EVM* { + let (revert_reason_len, revert_reason) = Errors.eth_validation_failed(); + return new model.EVM( + message=self.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=self.program_counter, + stopped=TRUE, + gas_left=0, + gas_refund=0, + reverted=Errors.EXCEPTIONAL_HALT, + ); + } + + // @notice Update the array of events to emit in the case of a execution context successfully running to completion (see `EVM.finalize`). + // @param self The pointer to the execution context. + // @param topics_len The length of the topics + // @param topics The topics Uint256 array + // @param data_len The length of the data + // @param data The data bytes array + func push_event{state: model.State*}( + self: model.EVM*, topics_len: felt, topics: Uint256*, data_len: felt, data: felt* + ) { + alloc_locals; + + // we add the operating evm_contract_address of the execution context + // as the first key of an event + // we track kakarot events as those emitted from the kkrt contract + // and map it to the corresponding EVM contract via this convention + // this looks a bit odd and may need to be reviewed + let (local topics_with_address: felt*) = alloc(); + assert [topics_with_address] = self.message.address.evm; + memcpy(dst=topics_with_address + 1, src=cast(topics, felt*), len=topics_len * Uint256.SIZE); + let event = model.Event( + topics_len=1 + topics_len * Uint256.SIZE, + topics=topics_with_address, + data_len=data_len, + data=data, + ); + + State.add_event(event); + + return (); + } + + // @notice Update the program counter. + // @dev The program counter is updated to a given value. This is only ever called by JUMP or JUMPI + // @param self The pointer to the execution context. + // @param new_pc_offset The value to update the program counter by. + // @return EVM The pointer to the updated execution context. + func jump{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + self: model.EVM*, new_pc_offset: felt + ) -> model.EVM* { + let out_of_range = is_nn(new_pc_offset - self.message.bytecode_len); + if (out_of_range != FALSE) { + let (revert_reason_len, revert_reason) = Errors.invalidJumpDestError(); + let evm = EVM.stop(self, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + let valid_jumpdests = self.message.valid_jumpdests; + with valid_jumpdests { + let is_valid_jumpdest = Internals.is_valid_jumpdest( + self.message.code_address, new_pc_offset + ); + } + + tempvar message = new model.Message( + bytecode=self.message.bytecode, + bytecode_len=self.message.bytecode_len, + valid_jumpdests_start=self.message.valid_jumpdests_start, + valid_jumpdests=valid_jumpdests, + calldata=self.message.calldata, + calldata_len=self.message.calldata_len, + value=self.message.value, + caller=self.message.caller, + parent=self.message.parent, + address=self.message.address, + code_address=self.message.code_address, + read_only=self.message.read_only, + is_create=self.message.is_create, + depth=self.message.depth, + env=self.message.env, + cairo_precompile_called=self.message.cairo_precompile_called, + ); + + if (is_valid_jumpdest == FALSE) { + let (revert_reason_len, revert_reason) = Errors.invalidJumpDestError(); + // stop and revert the execution context with the updated `message` + tempvar evm = new model.EVM( + message=message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=self.program_counter, + stopped=TRUE, + gas_left=self.gas_left, + gas_refund=self.gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + return evm; + } + + return new model.EVM( + message=message, + return_data_len=self.return_data_len, + return_data=self.return_data, + program_counter=new_pc_offset, + stopped=self.stopped, + gas_left=self.gas_left, + gas_refund=self.gas_refund, + reverted=self.reverted, + ); + } +} + +namespace Internals { + func is_valid_jumpdest{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + valid_jumpdests: DictAccess*, + state: model.State*, + }(code_address: model.Address*, index: felt) -> felt { + alloc_locals; + let (is_cached) = dict_read{dict_ptr=valid_jumpdests}(index); + // TODO: fix where valid_jumpdest should be stored + return is_cached; + } +} diff --git a/cairo/src/gas.cairo b/cairo/src/gas.cairo new file mode 100644 index 00000000..5343202a --- /dev/null +++ b/cairo/src/gas.cairo @@ -0,0 +1,206 @@ +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.math_cmp import is_not_zero, is_nn, is_le_felt +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.uint256 import Uint256, uint256_lt + +from src.model import model +from src.utils.uint256 import uint256_eq +from src.utils.utils import Helpers +from src.utils.maths import unsigned_div_rem + +namespace Gas { + const JUMPDEST = 1; + const BASE = 2; + const VERY_LOW = 3; + const STORAGE_SET = 20000; + const STORAGE_UPDATE = 5000; + const STORAGE_CLEAR_REFUND = 4800; + const LOW = 5; + const MID = 8; + const HIGH = 10; + const EXPONENTIATION = 10; + const EXPONENTIATION_PER_BYTE = 50; + const MEMORY = 3; + const KECCAK256 = 30; + const KECCAK256_WORD = 6; + const COPY = 3; + const BLOCK_HASH = 20; + const LOG = 375; + const LOG_DATA = 8; + const LOG_TOPIC = 375; + const CREATE = 32000; + const CODE_DEPOSIT = 200; + const ZERO = 0; + const NEW_ACCOUNT = 25000; + const CALL_VALUE = 9000; + const CALL_STIPEND = 2300; + const SELF_DESTRUCT = 5000; + const SELF_DESTRUCT_NEW_ACCOUNT = 25000; + const ECRECOVER = 3000; + const SHA256 = 60; + const SHA256_WORD = 12; + const RIPEMD160 = 600; + const RIPEMD160_WORD = 120; + const IDENTITY = 15; + const IDENTITY_WORD = 3; + const RETURN_DATA_COPY = 3; + const FAST_STEP = 5; + const BLAKE2_PER_ROUND = 1; + const COLD_SLOAD = 2100; + const COLD_ACCOUNT_ACCESS = 2600; + const WARM_ACCESS = 100; + const INIT_CODE_WORD_COST = 2; + const TX_BASE_COST = 21000; + const TX_ACCESS_LIST_ADDRESS_COST = 2400; + const TX_ACCESS_LIST_STORAGE_KEY_COST = 1900; + const BLOBHASH = 3; + const MEMORY_COST_U32 = 0x200018000000; + + // @notice Compute the cost of the memory for a given words length. + // @dev To avoid range_check overflow, we compute words_len / 512 + // instead of words_len * words_len / 512. Then we recompute the + // resulting quotient: x^2 = 512q + r becomes + // x = 512 q0 + r0 => x^2 = 512(512 q0^2 + 2 q0 r0) + r0^2 + // r0^2 = 512 q1 + r1 + // x^2 = 512(512 q0^2 + 2 * q0 r0 + q1) + r1 + // q = 512 * q0 * q0 + 2 q0 * r0 + q1 + // @param words_len The given number of words (bytes32). + // @return cost The associated gas cost. + func memory_cost{range_check_ptr}(words_len: felt) -> felt { + let (q0, r0) = unsigned_div_rem(words_len, 512); + let (q1, r1) = unsigned_div_rem(r0 * r0, 512); + + let memory_cost = 512 * q0 * q0 + 2 * q0 * r0 + q1 + (MEMORY * words_len); + return memory_cost; + } + + // @notice Compute the expansion cost of max_offset for the memory. + // @dev Assumption max_offset < 2**133 necessary for unsigned_div_rem usage. + // @param words_len The current length of the memory. + // @param max_offset The target max_offset to be applied to the given memory. + // @return cost The expansion gas cost: 0 if no expansion is triggered, and the new size of the memory + func calculate_gas_extend_memory{range_check_ptr}( + words_len: felt, max_offset: felt + ) -> model.MemoryExpansion { + alloc_locals; + let is_memory_length_not_zero = is_not_zero(words_len); + let current_memory_length = (words_len * 32 - 1) * is_memory_length_not_zero; + let memory_expansion = is_le_felt(current_memory_length, max_offset); + if (memory_expansion == FALSE) { + let expansion = model.MemoryExpansion(cost=0, new_words_len=words_len); + return expansion; + } + + let prev_cost = memory_cost(words_len); + let (new_words_len, _) = unsigned_div_rem(max_offset + 31, 32); + let new_cost = memory_cost(new_words_len); + + let expansion_cost = new_cost - prev_cost; + let expansion = model.MemoryExpansion(cost=expansion_cost, new_words_len=new_words_len); + return expansion; + } + + // @notive A saturated version of the memory_expansion_cost function + // @dev Saturation at offset + size = 2^128. + // @param words_len The current length of the memory as Uint256. + // @param offset An offset to be applied to the given memory as Uint256. + // @param size The size of the memory chunk. + // @return cost The expansion gas cost: 0 if no expansion is triggered, and the new size of the memory + func memory_expansion_cost_saturated{range_check_ptr}( + words_len: felt, offset: Uint256, size: Uint256 + ) -> model.MemoryExpansion { + let (is_zero) = uint256_eq(size, Uint256(low=0, high=0)); + if (is_zero != FALSE) { + let expansion = model.MemoryExpansion(cost=0, new_words_len=words_len); + return expansion; + } + + let (q, _) = unsigned_div_rem(offset.low + size.low, 2 ** 32); + if (offset.high == 0 and size.high == 0 and q == 0) { + return calculate_gas_extend_memory(words_len, offset.low + size.low); + } + // Hardcoded value of cost(2**32) and size of 2**32 bytes = 2**27 words of 32 bytes + // This offset would produce an OOG error in any case + let expansion = model.MemoryExpansion(cost=MEMORY_COST_U32, new_words_len=2 ** 27); + return expansion; + } + + // @notice Given two memory chunks, compute the maximum expansion cost + // based on the maximum offset reached by each chunks. + // @dev Memory expansion cost is computed over the `low` parts of + // the offsets and sizes. In the second step, we check whether the `high` + // parts are non-zero and if so, we add the cost of expanding the memory by + // 2**128 words (saturating). + // @param words_len The current length of the memory as felt252. + // @param offset_1 The offset of the first memory chunk as Uint256. + // @param size_1 The size of the first memory chunk as Uint256. + // @param offset_2 The offset of the second memory chunk as Uint256. + // @param size_2 The size of the second memory chunk as Uint256. + // @return cost The expansion gas cost for chunk who's ending offset is the largest and the new size of the memory + func max_memory_expansion_cost{range_check_ptr}( + words_len: felt, offset_1: Uint256*, size_1: Uint256*, offset_2: Uint256*, size_2: Uint256* + ) -> model.MemoryExpansion { + alloc_locals; + + let (is_zero_1) = uint256_eq([size_1], Uint256(0, 0)); + let (is_zero_2) = uint256_eq([size_2], Uint256(0, 0)); + tempvar both_zero = is_zero_1 * is_zero_2; + jmp no_expansion if both_zero != 0; + + tempvar is_not_saturated = Helpers.is_zero(offset_1.high) * Helpers.is_zero(size_1.high) * + Helpers.is_zero(offset_2.high) * Helpers.is_zero(size_2.high); + tempvar is_saturated = 1 - is_not_saturated; + tempvar range_check_ptr = range_check_ptr; + jmp expansion_cost_saturated if is_saturated != 0; + + let max_offset_1 = (1 - is_zero_1) * (offset_1.low + size_1.low); + let max_offset_2 = (1 - is_zero_2) * (offset_2.low + size_2.low); + let max_expansion_is_2 = is_le_felt(max_offset_1, max_offset_2); + let max_offset = max_offset_1 * (1 - max_expansion_is_2) + max_offset_2 * + max_expansion_is_2; + let (q, _) = unsigned_div_rem(max_offset, 2 ** 32); + tempvar range_check_ptr = range_check_ptr; + jmp expansion_cost_saturated if q != 0; + + let expansion = calculate_gas_extend_memory(words_len, max_offset); + let expansion = model.MemoryExpansion( + cost=expansion.cost, new_words_len=expansion.new_words_len + ); + return expansion; + + no_expansion: + let range_check_ptr = [fp - 8]; + let expansion = model.MemoryExpansion(cost=0, new_words_len=words_len); + return expansion; + + expansion_cost_saturated: + let range_check_ptr = [ap - 1]; + // Hardcoded value of cost(2**32) and size of 2**32 bytes = 2**27 words of 32 bytes + // This offset would produce an OOG error in any case + let expansion = model.MemoryExpansion(cost=MEMORY_COST_U32, new_words_len=2 ** 27); + return expansion; + } + + // @notice Computes the base gas of a message call. + // @dev This should be called after having withdrawn the gas relative to the + // memory expansion and eventual extra gas costs. + // @param gas_param The gas parameter of the message call, from the Stack. + // @param gas_left The gas left in the current execution frame. + // @return gas The base gas of the message call. + func compute_message_call_gas{range_check_ptr}(gas_param: Uint256, gas_left: felt) -> felt { + alloc_locals; + let (quotient, _) = unsigned_div_rem(gas_left, 64); + tempvar max_allowed_gas = gas_left - quotient; + let (max_allowed_high, max_allowed_low) = split_felt(max_allowed_gas); + tempvar max_allowed = Uint256(low=max_allowed_low, high=max_allowed_high); + let (is_gas_param_lower) = uint256_lt(gas_param, max_allowed); + + // The message gas is the minimum between the gas param and the remaining gas left. + if (is_gas_param_lower != FALSE) { + // If gas is lower, it means that it fits in a felt and this is safe + tempvar gas = gas_param.low + 2 ** 128 * gas_param.high; + return gas; + } + return max_allowed.low; + } +} diff --git a/cairo/src/instructions/block_information.cairo b/cairo/src/instructions/block_information.cairo new file mode 100644 index 00000000..daa4ce43 --- /dev/null +++ b/cairo/src/instructions/block_information.cairo @@ -0,0 +1,176 @@ +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.math_cmp import is_in_range +from starkware.cairo.common.uint256 import Uint256 + +from src.constants import Constants +from src.evm import EVM +from src.interfaces.interfaces import ICairo1Helpers +from src.model import model +from src.stack import Stack +from src.state import State +from src.utils.utils import Helpers + +// @title BlockInformation information opcodes. +// @notice This file contains the functions to execute for block information opcodes. +namespace BlockInformation { + func exec_block_information{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let opcode_number = [evm.message.bytecode + evm.program_counter]; + + tempvar offset = 2 * (opcode_number - 0x40) + 1; + + jmp rel offset; + jmp blockhash; + jmp coinbase; + jmp timestamp; + jmp number; + jmp prevrandao; + jmp gaslimit; + jmp chainid; + jmp selfbalance; + jmp basefee; + jmp blobhash; + jmp blobbasefee; + + blockhash: + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let range_check_ptr = [fp - 8]; + let stack = cast([fp - 6], model.Stack*); + let evm = cast([fp - 3], model.EVM*); + Internals.blockhash(evm); + + // Rebind unused args with fp + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let memory = cast([fp - 5], model.Memory*); + let state = cast([fp - 4], model.State*); + return evm; + + coinbase: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + let range_check_ptr = [fp - 8]; + let (coinbase_high, coinbase_low) = split_felt(evm.message.env.coinbase); + tempvar coinbase_u256 = Uint256(low=coinbase_low, high=coinbase_high); + Stack.push_uint256(coinbase_u256); + + // Rebind unused args with fp + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let memory = cast([fp - 5], model.Memory*); + let state = cast([fp - 4], model.State*); + return evm; + + timestamp: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint128(evm.message.env.block_timestamp); + jmp end; + + number: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint128(evm.message.env.block_number); + jmp end; + + prevrandao: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint256(evm.message.env.prev_randao); + jmp end; + + gaslimit: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint128(evm.message.env.block_gas_limit); + jmp end; + + chainid: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint128(evm.message.env.chain_id); + jmp end; + + selfbalance: + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let range_check_ptr = [fp - 8]; + let stack = cast([fp - 6], model.Stack*); + let state = cast([fp - 4], model.State*); + let evm = cast([fp - 3], model.EVM*); + Internals.selfbalance(evm); + + // Rebind unused args with fp + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let memory = cast([fp - 5], model.Memory*); + return evm; + + basefee: + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint128(evm.message.env.base_fee); + jmp end; + + blobhash: + let stack = cast([fp - 6], model.Stack*); + Stack.pop(); + Stack.push_uint128(0); + jmp end; + + blobbasefee: + let stack = cast([fp - 6], model.Stack*); + Stack.push_uint128(0); + jmp end; + + end: + // Rebind unused args with fp + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let range_check_ptr = [fp - 8]; + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let memory = cast([fp - 5], model.Memory*); + let state = cast([fp - 4], model.State*); + let evm = cast([fp - 3], model.EVM*); + + // Rebind used args with ap + let stack = cast([ap - 1], model.Stack*); + + return evm; + } +} + +namespace Internals { + func blockhash{}(evm: model.EVM*) { + let (block_number) = Stack.pop(); + if (block_number.high != 0) { + Stack.push_uint256(Uint256(0, 0)); + return (); + } + + let lower_bound = Helpers.saturated_sub(evm.message.env.block_number, 256); + let in_range = is_in_range(block_number.low, lower_bound, evm.message.env.block_number); + + if (in_range == FALSE) { + Stack.push_uint256(Uint256(0, 0)); + return (); + } + + let (blockhash) = ICairo1Helpers.get_block_hash(implementation, block_number.low); + let (blockhash_high, blockhash_low) = split_felt(blockhash); + Stack.push_uint256(Uint256(low=blockhash_low, high=blockhash_high)); + return (); + } + + func selfbalance{ + pedersen_ptr: HashBuiltin*, range_check_ptr, stack: model.Stack*, state: model.State* + }(evm: model.EVM*) { + let account = State.get_account(evm.message.address.evm); + Stack.push(account.balance); + return (); + } +} diff --git a/cairo/src/instructions/duplication_operations.cairo b/cairo/src/instructions/duplication_operations.cairo new file mode 100644 index 00000000..8f315e17 --- /dev/null +++ b/cairo/src/instructions/duplication_operations.cairo @@ -0,0 +1,29 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin + +from src.model import model +from src.stack import Stack +from src.state import State + +// @title Duplication operations opcodes. +namespace DuplicationOperations { + // @notice Generic DUP operation + // @dev Duplicate the top i-th stack item to the top of the stack. + // @param evm The pointer to the execution context. + // @return EVM Updated execution context. + func exec_dup{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let opcode_number = [evm.message.bytecode + evm.program_counter]; + let i = opcode_number - 0x7F; + + let (element) = Stack.peek(i - 1); + Stack.push(element); + + return evm; + } +} diff --git a/cairo/src/instructions/environmental_information.cairo b/cairo/src/instructions/environmental_information.cairo new file mode 100644 index 00000000..54d7128c --- /dev/null +++ b/cairo/src/instructions/environmental_information.cairo @@ -0,0 +1,474 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.memset import memset +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.math_cmp import is_not_zero, is_nn +from starkware.cairo.common.uint256 import Uint256, uint256_le + +from src.account import Account +from src.errors import Errors +from src.evm import EVM +from src.gas import Gas +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.state import State +from src.utils.array import slice +from src.utils.maths import unsigned_div_rem +from src.utils.uint256 import uint256_to_uint160, uint256_add, uint256_eq +from src.utils.utils import Helpers + +// @title Environmental information opcodes. +// @notice This file contains the functions to execute for environmental information opcodes. +namespace EnvironmentalInformation { + func exec_address{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let address = Helpers.to_uint256(evm.message.address.evm); + Stack.push(address); + return evm; + } + + func exec_balance{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (address_uint256) = Stack.pop(); + let evm_address = uint256_to_uint160([address_uint256]); + + // Gas + // Calling `get_account` subsequently will make the account warm for the next interaction + let is_warm = State.is_account_warm(evm_address); + tempvar gas = is_warm * Gas.WARM_ACCESS + (1 - is_warm) * Gas.COLD_ACCOUNT_ACCESS; + let evm = EVM.charge_gas(evm, gas); + if (evm.reverted != FALSE) { + return evm; + } + + let account = State.get_account(evm_address); + Stack.push(account.balance); + + return evm; + } + + func exec_origin{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let origin_address = Helpers.to_uint256(evm.message.env.origin); + + Stack.push(origin_address); + return evm; + } + + func exec_caller{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let address = Helpers.to_uint256(evm.message.caller); + Stack.push(address); + return evm; + } + + func exec_callvalue{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push(evm.message.value); + + return evm; + } + + func exec_calldataload{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (offset) = Stack.pop(); + + if (offset.high != 0) { + Stack.push_uint128(0); + return evm; + } + + let (sliced_calldata: felt*) = alloc(); + slice(sliced_calldata, evm.message.calldata_len, evm.message.calldata, offset.low, 32); + let calldata = Helpers.bytes32_to_uint256(sliced_calldata); + Stack.push_uint256(calldata); + + return evm; + } + + func exec_calldatasize{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push_uint128(evm.message.calldata_len); + return evm; + } + + func exec_returndatacopy{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + // STACK + let (popped) = Stack.pop_n(3); + let memory_offset = popped[0]; + let returndata_offset = popped[1]; + let size = popped[2]; + + // GAS + let memory_expansion = Gas.memory_expansion_cost_saturated( + memory.words_len, memory_offset, size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Any size upper than 2**128 will cause an OOG error, considering the maximum gas for a transaction. + // here with size.low = 2**128 - 1, copy_gas_cost is 0x18000000000000000000000000000000, ie is between 2**124 and 2**125 + let upper_bytes_bound = size.low + 31; + let (words, _) = unsigned_div_rem(upper_bytes_bound, 32); + let copy_gas_cost = words * Gas.COPY; + + // static cost handled in jump table + let evm = EVM.charge_gas(evm, memory_expansion.cost + copy_gas_cost); + if (evm.reverted != FALSE) { + return evm; + } + // OPERATION + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + + // Offset.high != 0 means that the sliced data is surely 0x00...00 + // And storing 0 in Memory is just doing nothing. + if (returndata_offset.high != 0) { + // We still check for OOB returndatacopy + let (max_index, carry) = uint256_add(returndata_offset, size); + let (high, low) = split_felt(evm.return_data_len); + let (is_in_bounds) = uint256_le(max_index, Uint256(low=low, high=high)); + let is_in_bounds = is_in_bounds * (1 - carry); + if (is_in_bounds == FALSE) { + let (revert_reason_len, revert_reason) = Errors.outOfBoundsRead(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + return evm; + } + + let (sliced_data: felt*) = alloc(); + tempvar is_in_bounds = is_nn(evm.return_data_len - (returndata_offset.low + size.low)); + if (is_in_bounds == FALSE) { + let (revert_reason_len, revert_reason) = Errors.outOfBoundsRead(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + slice(sliced_data, evm.return_data_len, evm.return_data, returndata_offset.low, size.low); + + Memory.store_n(size.low, sliced_data, memory_offset.low); + + return evm; + } + + func exec_copy{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + // STACK + let (popped) = Stack.pop_n(3); + let dest_offset = popped[0]; + let offset = popped[1]; + let size = popped[2]; + + // if size == 0, we can optimize by returning early + // fixed opcode cost has already been charged as both + // calldatacopy and codecopy don't have additional checks + let (is_zero) = uint256_eq(size, Uint256(low=0, high=0)); + if (is_zero != FALSE) { + return evm; + } + + // GAS + let memory_expansion = Gas.memory_expansion_cost_saturated( + memory.words_len, dest_offset, size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Any size upper than 2**128 will cause an OOG error, considering the maximum gas for a transaction. + // here with size.low = 2**128 - 1, copy_gas_cost is 0x18000000000000000000000000000000, ie is between 2**124 and 2**125 + let upper_bytes_bound = size.low + 31; + let (words, _) = unsigned_div_rem(upper_bytes_bound, 32); + let copy_gas_cost = words * Gas.COPY; + + // static cost handled in jump table + let evm = EVM.charge_gas(evm, memory_expansion.cost + copy_gas_cost); + if (evm.reverted != FALSE) { + return evm; + } + + // OPERATION + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + + let opcode_number = [evm.message.bytecode + evm.program_counter]; + + let (data_to_store: felt*) = alloc(); + // Offset.high != 0 means that the sliced data is surely 0x00...00 + // Store 0 in memory + if (offset.high != 0) { + memset(dst=data_to_store, value=0, n=size.low); + Memory.store_n(size.low, data_to_store, dest_offset.low); + return evm; + } + + // 0x37: calldatacopy + // 0x39: codecopy + local data_len; + local data: felt*; + if (opcode_number == 0x37) { + assert data_len = evm.message.calldata_len; + assert data = evm.message.calldata; + tempvar range_check_ptr = range_check_ptr; + } else { + assert data_len = evm.message.bytecode_len; + assert data = evm.message.bytecode; + tempvar range_check_ptr = range_check_ptr; + } + let range_check_ptr = [ap - 1]; + slice(data_to_store, data_len, data, offset.low, size.low); + + Memory.store_n(size.low, data_to_store, dest_offset.low); + + return evm; + } + + func exec_codesize{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push_uint128(evm.message.bytecode_len); + return evm; + } + + func exec_gasprice{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + // TODO: since gas_price is a felt, it might panic when being cast to a Uint256.low, + // Add check gas_price < 2 ** 128 + // `split_felt` might be too expensive for this if we know gas_price < 2 ** 128 + Stack.push_uint128(evm.message.env.gas_price); + + return evm; + } + + func exec_extcodesize{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (address_uint256) = Stack.pop(); + let evm_address = uint256_to_uint160([address_uint256]); + + // Gas + // Calling `get_account` subsequently will make the account warm for the next interaction + let is_warm = State.is_account_warm(evm_address); + tempvar gas = is_warm * Gas.WARM_ACCESS + (1 - is_warm) * Gas.COLD_ACCOUNT_ACCESS; + let evm = EVM.charge_gas(evm, gas); + if (evm.reverted != FALSE) { + return evm; + } + + let account = State.get_account(evm_address); + + // bytecode_len cannot be greater than 24k in the EVM + Stack.push_uint128(account.code_len); + + return evm; + } + + func exec_extcodecopy{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(4); + let evm_address = uint256_to_uint160(popped[0]); + let dest_offset = popped[1]; + let offset = popped[2]; + let size = popped[3]; + + // Gas + // Calling `get_account` subsequently will make the account warm for the next interaction + let is_warm = State.is_account_warm(evm_address); + tempvar access_gas_cost = is_warm * Gas.WARM_ACCESS + (1 - is_warm) * + Gas.COLD_ACCOUNT_ACCESS; + + // Any size upper than 2**128 will cause an OOG error, considering the maximum gas for a transaction. + // here with size.low = 2**128 - 1, copy_gas_cost is 0x18000000000000000000000000000000, ie is between 2**124 and 2**125 + let upper_bytes_bound = size.low + 31; + let (words, _) = unsigned_div_rem(upper_bytes_bound, 32); + let copy_gas_cost = words * Gas.COPY; + + let memory_expansion = Gas.memory_expansion_cost_saturated( + memory.words_len, dest_offset, size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + let evm = EVM.charge_gas(evm, access_gas_cost + copy_gas_cost + memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + + let (data_to_store: felt*) = alloc(); + // Offset.high != 0 means that the sliced data is surely 0x00...00 + // Store 0 in memory + if (offset.high != 0) { + memset(dst=data_to_store, value=0, n=size.low); + Memory.store_n(size.low, data_to_store, dest_offset.low); + return evm; + } + + let account = State.get_account(evm_address); + slice(data_to_store, account.code_len, account.code, offset.low, size.low); + + Memory.store_n(size.low, data_to_store, dest_offset.low); + + return evm; + } + + func exec_returndatasize{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push_uint128(evm.return_data_len); + return evm; + } + + func exec_extcodehash{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (address_uint256) = Stack.pop(); + let evm_address = uint256_to_uint160([address_uint256]); + + // Gas + // Calling `get_account` subsequently will make the account warm for the next interaction + let is_warm = State.is_account_warm(evm_address); + tempvar access_gas_cost = is_warm * Gas.WARM_ACCESS + (1 - is_warm) * + Gas.COLD_ACCOUNT_ACCESS; + let evm = EVM.charge_gas(evm, access_gas_cost); + if (evm.reverted != FALSE) { + return evm; + } + + let account = State.get_account(evm_address); + let has_code_or_nonce = Account.has_code_or_nonce(account); + let account_exists = has_code_or_nonce + account.balance.low + account.balance.high; + // Relevant cases: + // https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L392 + if (account_exists == FALSE) { + Stack.push_uint128(0); + return evm; + } + + Stack.push_uint256([account.code_hash]); + + return evm; + } +} diff --git a/cairo/src/instructions/exchange_operations.cairo b/cairo/src/instructions/exchange_operations.cairo new file mode 100644 index 00000000..e3d051a2 --- /dev/null +++ b/cairo/src/instructions/exchange_operations.cairo @@ -0,0 +1,30 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.bool import TRUE + +from src.model import model +from src.evm import EVM +from src.stack import Stack +from src.state import State +from src.errors import Errors + +// @title Exchange operations opcodes. +namespace ExchangeOperations { + // @notice Generic SWAP operation + // @dev Exchange 1st and i-th stack items + // @param evm The pointer to the execution context + // @return EVM Updated execution context. + func exec_swap{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let opcode_number = [evm.message.bytecode + evm.program_counter]; + let i = opcode_number - 0x8f; + Stack.swap_i(i); + + return evm; + } +} diff --git a/cairo/src/instructions/logging_operations.cairo b/cairo/src/instructions/logging_operations.cairo new file mode 100644 index 00000000..d0797a3d --- /dev/null +++ b/cairo/src/instructions/logging_operations.cairo @@ -0,0 +1,76 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE, TRUE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math_cmp import is_not_zero + +from src.errors import Errors +from src.evm import EVM +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.state import State +from src.gas import Gas +from src.utils.utils import Helpers + +// @title Logging operations opcodes. +// @notice This file contains the functions to execute for logging operations opcodes. +namespace LoggingOperations { + // @notice Generic logging operation + // @dev Append log record with n topics. + // @custom:since Frontier + // @custom:group Logging Operations + // @param evm The pointer to the execution context + // @param Topic length. + // @return EVM The pointer to the execution context. + func exec_log{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + if (evm.message.read_only != FALSE) { + let (revert_reason_len, revert_reason) = Errors.stateModificationError(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + let opcode_number = [evm.message.bytecode + evm.program_counter]; + let topics_len = opcode_number - 0xa0; + + let (popped) = Stack.pop_n(topics_len + 2); + + let offset = popped[0]; + let size = popped[1]; + + let memory_expansion = Gas.memory_expansion_cost_saturated(memory.words_len, offset, size); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + let size_cost_low = Gas.LOG_DATA * size.low; + tempvar size_cost_high = is_not_zero(size.high) * 2 ** 128; + let topics_cost = Gas.LOG_TOPIC * topics_len; + let evm = EVM.charge_gas( + evm, memory_expansion.cost + size_cost_low + size_cost_high + topics_cost + ); + if (evm.reverted != FALSE) { + return evm; + } + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + let (data: felt*) = alloc(); + Memory.load_n(size.low, data, offset.low); + EVM.push_event(evm, topics_len, popped + 4, size.low, data); + + return evm; + } +} diff --git a/cairo/src/instructions/memory_operations.cairo b/cairo/src/instructions/memory_operations.cairo new file mode 100644 index 00000000..319fd3ee --- /dev/null +++ b/cairo/src/instructions/memory_operations.cairo @@ -0,0 +1,503 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE, TRUE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.math_cmp import is_nn, is_not_zero + +from src.errors import Errors +from src.account import Account +from src.evm import EVM +from src.gas import Gas +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.state import State +from src.utils.utils import Helpers +from src.utils.uint256 import uint256_unsigned_div_rem, uint256_eq +from src.utils.maths import unsigned_div_rem + +namespace MemoryOperations { + func exec_mload{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (offset) = Stack.pop(); + + let memory_expansion = Gas.memory_expansion_cost_saturated( + memory.words_len, [offset], Uint256(32, 0) + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + let evm = EVM.charge_gas(evm, memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + + let value = Memory.load(offset.low); + Stack.push_uint256(value); + + return evm; + } + + func exec_mstore{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(2); + let offset = popped[0]; + let value = popped[1]; + + let memory_expansion = Gas.memory_expansion_cost_saturated( + memory.words_len, offset, Uint256(32, 0) + ); + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + let evm = EVM.charge_gas(evm, memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + Memory.store(value, offset.low); + + return evm; + } + + func exec_mcopy{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(3); + let dst = popped; + let src = popped + Uint256.SIZE; + let size = popped + 2 * Uint256.SIZE; + + // GAS + let memory_expansion = Gas.max_memory_expansion_cost( + memory.words_len, src, size, dst, size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Any size upper than 2**128 will cause an OOG error, considering the maximum gas for a transaction. + // here with size.low = 2**128 - 1, copy_gas_cost is 0x18000000000000000000000000000000, ie is between 2**124 and 2**125 + let upper_bytes_bound = size.low + 31; + let (words, _) = unsigned_div_rem(upper_bytes_bound, 32); + let copy_gas_cost_low = words * Gas.COPY; + + let evm = EVM.charge_gas(evm, memory_expansion.cost + copy_gas_cost_low); + if (evm.reverted != FALSE) { + return evm; + } + + // Operation + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + + let (data: felt*) = alloc(); + Memory.load_n(size.low, data, src.low); + Memory.store_n(size.low, data, dst.low); + + return evm; + } + + func exec_pc{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push_uint128(evm.program_counter); + return evm; + } + + func exec_msize{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push_uint128(memory.words_len * 32); + return evm; + } + + func exec_jump{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + let (offset) = Stack.pop(); + + if (offset.high != 0) { + let (revert_reason_len, revert_reason) = Errors.invalidJumpDestError(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + let evm = EVM.jump(evm, offset.low); + return evm; + } + + func exec_jumpi{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + let (popped) = Stack.pop_n(2); + let offset = popped[0]; + let skip_condition = popped[1]; + + // If skip_condition is 0, then don't jump + let (skip_condition_is_zero) = uint256_eq(Uint256(0, 0), skip_condition); + if (skip_condition_is_zero != FALSE) { + // Return with a PC incremented by one - as JUMP and JUMPi increments + // are skipped in the main `execute_opcode` loop + let evm = EVM.increment_program_counter(evm, 1); + return evm; + } + + if (offset.high != 0) { + let (revert_reason_len, revert_reason) = Errors.invalidJumpDestError(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + let evm = EVM.jump(evm, offset.low); + return evm; + } + + func exec_jumpdest{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + return evm; + } + + func exec_pop{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.pop(); + + return evm; + } + + func exec_mstore8{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(2); + let offset = popped[0]; + let value = popped[1]; + + let memory_expansion = Gas.memory_expansion_cost_saturated( + memory.words_len, offset, Uint256(1, 0) + ); + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + let evm = EVM.charge_gas(evm, memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + let (_, remainder) = uint256_unsigned_div_rem(value, Uint256(256, 0)); + let (value_pointer: felt*) = alloc(); + assert [value_pointer] = remainder.low; + + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + Memory.store_n(1, value_pointer, offset.low); + + return evm; + } + + func exec_sstore{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + let (popped) = Stack.pop_n(2); + let key = popped; // Uint256* + let new_value = popped + Uint256.SIZE; // Uint256* + + let is_enough_gasleft = is_nn(evm.gas_left - (Gas.CALL_STIPEND + 1)); + if (is_enough_gasleft == FALSE) { + let (revert_reason_len, revert_reason) = Errors.outOfGas( + evm.gas_left, Gas.CALL_STIPEND + ); + return new model.EVM( + message=evm.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=evm.program_counter, + stopped=TRUE, + gas_left=0, + gas_refund=evm.gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + } + + // Has to be done BEFORE fetching the current value from the state, + // otherwise it would warm up the storage slot. + let is_storage_warm = State.is_storage_warm(evm.message.address.evm, key); + local gas_cost: felt; + if (is_storage_warm == FALSE) { + assert gas_cost = Gas.COLD_SLOAD; + } else { + assert gas_cost = 0; + } + + let account = State.get_account(evm.message.address.evm); + let original_value = Account.fetch_original_storage(account, key); + let current_value = State.read_storage(evm.message.address.evm, key); + + let (is_current_original) = uint256_eq(original_value, [current_value]); + let (is_current_new) = uint256_eq([new_value], [current_value]); + let (is_original_zero) = uint256_eq(Uint256(0, 0), original_value); + + if (is_current_original * (1 - is_current_new) != FALSE) { + tempvar gas_cost = gas_cost + (is_original_zero * Gas.STORAGE_SET) + ( + (1 - is_original_zero) * (Gas.STORAGE_UPDATE - Gas.COLD_SLOAD) + ); + } else { + tempvar gas_cost = gas_cost + Gas.WARM_ACCESS; + } + + let evm = EVM.charge_gas(evm, gas_cost); + if (evm.reverted != FALSE) { + return evm; + } + + let (is_current_zero) = uint256_eq(Uint256(0, 0), [current_value]); + let (is_new_zero) = uint256_eq(Uint256(0, 0), [new_value]); + + // storage is being changed and the original value was not zero + tempvar is_storage_set_changed = (1 - is_current_new) * (1 - is_original_zero); + + // storage is being changed and the original value is the new value + let (is_new_original) = uint256_eq([new_value], original_value); + tempvar is_storage_restored = (1 - is_current_new) * is_new_original; + + tempvar gas_refund = is_storage_set_changed * Gas.STORAGE_CLEAR_REFUND * ( + (1 - is_current_zero) * is_new_zero - is_current_zero + ) + is_storage_restored * ( + is_original_zero * (Gas.STORAGE_SET - Gas.WARM_ACCESS) + + (1 - is_original_zero) * (Gas.STORAGE_UPDATE - Gas.COLD_SLOAD - Gas.WARM_ACCESS) + ); + + // Operation + if (evm.message.read_only != FALSE) { + let (revert_reason_len, revert_reason) = Errors.stateModificationError(); + return new model.EVM( + message=evm.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=evm.program_counter, + stopped=TRUE, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund + gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + } + + State.write_storage(evm.message.address.evm, key, new_value); + // Return with the updated gas refund + return new model.EVM( + message=evm.message, + return_data_len=evm.return_data_len, + return_data=evm.return_data, + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund + gas_refund, + reverted=evm.reverted, + ); + } + + func exec_sload{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (key) = Stack.pop(); + + // Has to be done BEFORE fetching the current value from the state, + // otherwise it would warm up the storage slot. + let is_storage_warm = State.is_storage_warm(evm.message.address.evm, key); + tempvar gas_cost = is_storage_warm * Gas.WARM_ACCESS + (1 - is_storage_warm) * + Gas.COLD_SLOAD; + let evm = EVM.charge_gas(evm, gas_cost); + if (evm.reverted != FALSE) { + return evm; + } + + let value = State.read_storage(evm.message.address.evm, key); + Stack.push(value); + return evm; + } + + func exec_tstore{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + let (popped) = Stack.pop_n(2); + let key = popped; // Uint256* + let new_value = popped + Uint256.SIZE; // Uint256* + + // GAS + let evm = EVM.charge_gas(evm, Gas.WARM_ACCESS); + if (evm.reverted != FALSE) { + return evm; + } + + // Operation + if (evm.message.read_only != FALSE) { + let (revert_reason_len, revert_reason) = Errors.stateModificationError(); + return new model.EVM( + message=evm.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=evm.program_counter, + stopped=TRUE, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + } + + State.write_transient_storage(evm.message.address.evm, key, new_value); + return new model.EVM( + message=evm.message, + return_data_len=evm.return_data_len, + return_data=evm.return_data, + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund, + reverted=evm.reverted, + ); + } + + func exec_tload{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (key) = Stack.pop(); + + // Gas + let evm = EVM.charge_gas(evm, Gas.WARM_ACCESS); + if (evm.reverted != FALSE) { + return evm; + } + + // Operation + let value = State.read_transient_storage(evm.message.address.evm, key); + Stack.push(value); + return evm; + } + + func exec_gas{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + Stack.push_uint128(evm.gas_left); + + return evm; + } +} diff --git a/cairo/src/instructions/push_operations.cairo b/cairo/src/instructions/push_operations.cairo new file mode 100644 index 00000000..e6d10dd6 --- /dev/null +++ b/cairo/src/instructions/push_operations.cairo @@ -0,0 +1,39 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math_cmp import is_nn + +from src.constants import Constants +from src.errors import Errors +from src.evm import EVM +from src.model import model +from src.stack import Stack +from src.state import State +from src.utils.utils import Helpers + +// @title Push operations opcodes. +namespace PushOperations { + func exec_push{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let opcode_number = [evm.message.bytecode + evm.program_counter]; + let i = opcode_number - 0x5f; + + // Copy code slice + let pc = evm.program_counter + 1; + let out_of_bounds = is_nn(pc + i - evm.message.bytecode_len); + local len = (1 - out_of_bounds) * i + out_of_bounds * (evm.message.bytecode_len - pc); + + let stack_element = Helpers.bytes_to_uint256(len, evm.message.bytecode + pc); + Stack.push_uint256(stack_element); + + let evm = EVM.increment_program_counter(evm, len); + + return evm; + } +} diff --git a/cairo/src/instructions/sha3.cairo b/cairo/src/instructions/sha3.cairo new file mode 100644 index 00000000..55269299 --- /dev/null +++ b/cairo/src/instructions/sha3.cairo @@ -0,0 +1,64 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.math_cmp import is_not_zero + +from src.evm import EVM +from src.interfaces.interfaces import ICairo1Helpers +from src.gas import Gas +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.utils.bytes import keccak +from src.utils.maths import unsigned_div_rem + +namespace Sha3 { + func exec_sha3{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(2); + let offset = popped[0]; + let size = popped[1]; + + // GAS + let memory_expansion = Gas.memory_expansion_cost_saturated(memory.words_len, offset, size); + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + let (words, _) = unsigned_div_rem(size.low + 31, 32); + let words_gas_cost_low = Gas.KECCAK256_WORD * words; + tempvar words_gas_cost_high = is_not_zero(size.high) * 2 ** 128; + let evm = EVM.charge_gas( + evm, memory_expansion.cost + words_gas_cost_low + words_gas_cost_high + ); + if (evm.reverted != FALSE) { + return evm; + } + + // OPERATION + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + words_len=memory_expansion.new_words_len, + ); + + let (bigendian_data: felt*) = alloc(); + Memory.load_n(size.low, bigendian_data, offset.low); + + let result = keccak(size.low, bigendian_data); + + Stack.push_uint256(result); + + return evm; + } +} diff --git a/cairo/src/instructions/stop_and_math_operations.cairo b/cairo/src/instructions/stop_and_math_operations.cairo new file mode 100644 index 00000000..76c7f093 --- /dev/null +++ b/cairo/src/instructions/stop_and_math_operations.cairo @@ -0,0 +1,562 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.uint256 import ( + uint256_and, + uint256_lt, + uint256_mul, + uint256_not, + uint256_or, + uint256_shl, + uint256_xor, + Uint256, + SHIFT, + ALL_ONES, +) + +from src.constants import Constants, opcodes_label +from src.model import model +from src.evm import EVM +from src.stack import Stack +from src.gas import Gas +from src.state import State +from src.errors import Errors +from src.utils.uint256 import ( + uint256_fast_exp, + uint256_signextend, + uint256_sub, + uint256_add, + uint256_unsigned_div_rem, + uint256_mul_div_mod, + uint256_signed_lt, + uint256_shr, + uint256_signed_div_rem, + uint256_eq, +) +from src.utils.utils import Helpers + +// @title Stop and Math operations opcodes. +// @notice Math operations gathers Arithmetic and Comparison operations +namespace StopAndMathOperations { + func exec_stop{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + // return_data stored the return_data for the last executed sub context + // see CALLs opcodes. When we run the STOP opcode, we stop the current + // execution context with *no* return data (unlike RETURN and REVERT). + // hence we just clear the return_data and stop. + let (return_data: felt*) = alloc(); + let evm = EVM.stop(evm, 0, return_data, FALSE); + return evm; + } + + func exec_math_operation{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + local opcode: model.Opcode*; + + // See evm.cairo, pc is increased before entering the opcode + let opcode_number = [evm.message.bytecode + evm.program_counter]; + + // To cast the codeoffset opcodes_label to a model.Opcode*, we need to use it to offset + // the current pc. We get the pc from the `get_fp_and_pc` util and assign a codeoffset (pc_label) to it. + // In short, this boilds down to: opcode = pc + offset - pc = offset + let (_, pc) = get_fp_and_pc(); + + pc_label: + assert opcode = cast( + pc + (opcodes_label - pc_label) + opcode_number * model.Opcode.SIZE, model.Opcode* + ); + + let (popped) = Stack.pop_n(opcode.stack_input); + local stack: model.Stack* = stack; + + // offset is 1 (new line) + 2 (jmp + label) per opcode + // opcode is offset from by 0x1 (index of the first opcode) + tempvar offset = 2 * (opcode_number - 0x01) + 1; + + tempvar range_check_ptr = range_check_ptr; + tempvar popped = popped; + + jmp rel offset; + + jmp ADD; // 0x1 + jmp MUL; // 0x2 + jmp SUB; // 0x3 + jmp DIV; // 0x4 + jmp SDIV; // 0x5 + jmp MOD; // 0x6 + jmp SMOD; // 0x7 + jmp ADDMOD; // 0x8 + jmp MULMOD; // 0x9 + jmp EXP; // 0xa + jmp SIGNEXTEND; // 0xb + jmp INVALID; // 0xc + jmp INVALID; // 0xd + jmp INVALID; // 0xe + jmp INVALID; // 0xf + jmp LT; // 0x10 + jmp GT; // 0x11 + jmp SLT; // 0x12 + jmp SGT; // 0x13 + jmp EQ; // 0x14 + jmp ISZERO; // 0x15 + jmp AND; // 0x16 + jmp OR; // 0x17 + jmp XOR; // 0x18 + jmp NOT; // 0x19 + jmp BYTE; // 0x1a + jmp SHL; // 0x1b + jmp SHR; // 0x1c + jmp SAR; // 0x1d + + end: + // Parse results + // All the jumps share the same return signature, which is bitwise_ptr + // and range_check_ptr in implicit args and a Uint256 for the value + let bitwise_ptr = cast([ap - 4], BitwiseBuiltin*); + let range_check_ptr = [ap - 3]; + let result = Uint256([ap - 2], [ap - 1]); + + // Rebind args with fp + // Function args are in [fp - n - 2: fp - 2] + // locals are retrieved from [fp] in the order they are defined + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let memory = cast([fp - 5], model.Memory*); + let state = cast([fp - 4], model.State*); + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp + 1], model.Stack*); + + // Finalize opcode + Stack.push_uint256(result); + return evm; + + ADD: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result, _) = uint256_add(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + MUL: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result, _) = uint256_mul(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + SUB: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_sub(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + DIV: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (quotient, _) = uint256_unsigned_div_rem(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(quotient.low, quotient.high); + jmp end; + + SDIV: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (quotient, _) = uint256_signed_div_rem(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(quotient.low, quotient.high); + jmp end; + + MOD: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (_, remainder) = uint256_unsigned_div_rem(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(remainder.low, remainder.high); + jmp end; + + SMOD: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (_, remainder) = uint256_signed_div_rem(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(remainder.low, remainder.high); + jmp end; + + ADDMOD: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + tempvar mod_is_not_zero = popped[2].low + popped[2].high; + jmp addmod_not_zero if mod_is_not_zero != 0; + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(0, 0); + jmp end; + + addmod_not_zero: + // (a + b) mod n = (a mod n + b mod n) mod n + let (_, x) = uint256_unsigned_div_rem(popped[0], popped[2]); + let (_, y) = uint256_unsigned_div_rem(popped[1], popped[2]); + // x, y in range [0, n-1] thus: + // if x + y < n then x + y mod n = x + y + // if x + y >= n then x + y mod n = x + y - n + let (sum, carry) = uint256_add(x, y); + + if (carry != 0) { + // result = (2**256) - (n - overflown_sum) + // <=> result = (2**256 - 1) - (n - overflown_sum - 1) + // as n > overflown_sum we can't have an underflow + let max_u256 = Uint256(ALL_ONES, ALL_ONES); + let (overflown_part) = uint256_sub(popped[2], sum); + let (to_remove) = uint256_sub(overflown_part, Uint256(1, 0)); + let (result) = uint256_sub(max_u256, to_remove); + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = result; + jmp end; + } + + let (is_sum_lt_n) = uint256_lt(sum, popped[2]); + if (is_sum_lt_n != 0) { + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = sum; + jmp end; + } + + let (result) = uint256_sub(sum, popped[2]); + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = result; + jmp end; + + MULMOD: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + tempvar mod_is_not_zero = popped[2].low + popped[2].high; + jmp mulmod_not_zero if mod_is_not_zero != 0; + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(0, 0); + jmp end; + + mulmod_not_zero: + let (_, _, result) = uint256_mul_div_mod(popped[0], popped[1], popped[2]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + EXP: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + let exponent = popped[1]; + + // Gas + local bytes_used: felt; + if (exponent.high == 0) { + let bytes_used_low = Helpers.bytes_used_128(exponent.low); + assert bytes_used = bytes_used_low; + tempvar range_check_ptr = range_check_ptr; + } else { + let bytes_used_high = Helpers.bytes_used_128(exponent.high); + assert bytes_used = bytes_used_high + 16; + tempvar range_check_ptr = range_check_ptr; + } + let range_check_ptr = [ap - 1]; + + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let memory = cast([fp - 5], model.Memory*); + let state = cast([fp - 4], model.State*); + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp + 1], model.Stack*); + + let evm = EVM.charge_gas(evm, Gas.EXPONENTIATION_PER_BYTE * bytes_used); + if (evm.reverted != FALSE) { + return evm; + } + + let result = uint256_fast_exp(popped[0], exponent); + + Stack.push_uint256(result); + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + return evm; + + SIGNEXTEND: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let result = uint256_signextend(popped[1], popped[0]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = result; + jmp end; + + INVALID: + let range_check_ptr = [ap - 2]; + // Rebind args with fp + // Function args are in [fp - n - 2: fp - 2] + // locals are retrieved from [fp] in the order they are defined + let pedersen_ptr = cast([fp - 9], HashBuiltin*); + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let memory = cast([fp - 5], model.Memory*); + let state = cast([fp - 4], model.State*); + let evm = cast([fp - 3], model.EVM*); + let stack = cast([fp + 1], model.Stack*); + + let (revert_reason_len, revert_reason) = Errors.unknownOpcode(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + + LT: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (res) = uint256_lt(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(res, 0); + jmp end; + + GT: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (res) = uint256_lt(popped[1], popped[0]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(res, 0); + jmp end; + + SLT: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (res) = uint256_signed_lt(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(res, 0); + jmp end; + + SGT: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (res) = uint256_signed_lt(popped[1], popped[0]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(res, 0); + jmp end; + + EQ: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (res) = uint256_eq(popped[0], popped[1]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(res, 0); + jmp end; + + ISZERO: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (res) = uint256_eq(popped[0], Uint256(0, 0)); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(res, 0); + jmp end; + + AND: + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_and(popped[0], popped[1]); + + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + OR: + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_or(popped[0], popped[1]); + + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + XOR: + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_xor(popped[0], popped[1]); + + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + BYTE: + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + // compute y = (x >> (248 - i * 8)) & 0xFF + let i = popped[0]; + let (is_inf_32) = uint256_lt(i, Uint256(32, 0)); + jmp byte_i if is_inf_32 != 0; + + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(0, 0); + jmp end; + + // here i < 32 so we can use field ops + byte_i: + let right = Uint256(248 - i.low * 8, 0); + let (shift_right) = uint256_shr(popped[1], right); + let (result) = uint256_and(shift_right, Uint256(0xFF, 0)); + + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + SHL: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_shl(popped[1], popped[0]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + SHR: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_shr(popped[1], popped[0]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + SAR: + let bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + // In C, SAR would be something like that (on a 4 bytes int): + // ``` + // int sign = -((unsigned) x >> 31); + // int sar = (sign^x) >> n ^ sign; + // ``` + // This is the cairo adaptation + let shift = popped[0]; + let value = popped[1]; + // (unsigned) x >> 31 : extract the left-most bit (i.e. the sign). + let (_sign) = uint256_shr(value, Uint256(255, 0)); + + // Declare low and high as tempvar because we can't declare a Uint256 as tempvar. + tempvar low; + tempvar high; + if (_sign.low == 0) { + // If sign is positive, set it to 0. + low = 0; + high = 0; + } else { + // If sign is negative, set the number to -1. + low = Constants.UINT128_MAX; + high = Constants.UINT128_MAX; + } + + // Rebuild the `sign` variable from `low` and `high`. + let sign = Uint256(low, high); + + // `sign ^ x` + let (step1) = uint256_xor(sign, value); + // `sign ^ x >> n` + let (step2) = uint256_shr(step1, shift); + // `sign & x >> n ^ sign` + let (result) = uint256_xor(step2, sign); + + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + + NOT: + let range_check_ptr = [ap - 2]; + let popped = cast([ap - 1], Uint256*); + + let (result) = uint256_not(popped[0]); + + tempvar bitwise_ptr = cast([fp - 7], BitwiseBuiltin*); + tempvar range_check_ptr = range_check_ptr; + tempvar result = Uint256(result.low, result.high); + jmp end; + } +} diff --git a/cairo/src/instructions/system_operations.cairo b/cairo/src/instructions/system_operations.cairo new file mode 100644 index 00000000..25a6c505 --- /dev/null +++ b/cairo/src/instructions/system_operations.cairo @@ -0,0 +1,1258 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.math_cmp import is_nn, is_not_zero +from starkware.cairo.common.uint256 import Uint256, uint256_lt, uint256_le +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.dict_access import DictAccess + +from src.account import Account +from src.interfaces.interfaces import ICairo1Helpers +from src.constants import Constants +from src.errors import Errors +from src.evm import EVM +from src.gas import Gas +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.state import State +from src.utils.utils import Helpers +from src.utils.array import slice +from src.utils.bytes import keccak, felt_to_bytes, felt_to_bytes20, uint256_to_bytes32 +from src.utils.uint256 import uint256_to_uint160, uint256_eq +from src.utils.maths import unsigned_div_rem + +using bool = felt; + +// @title System operations opcodes. +// @notice This file contains the functions to execute for system operations opcodes. +namespace SystemOperations { + func exec_create{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let opcode_number = [evm.message.bytecode + evm.program_counter]; + let is_create2 = is_not_zero(opcode_number - 0xf0); + let popped_len = 3 + is_create2; + let (popped) = Stack.pop_n(3 + is_create2); + + let value = popped; + let offset = popped[1]; + let size = popped[2]; + + // Gas + // + extend_memory.cost + // + init_code_gas + // + is_create2 * GAS_KECCAK256_WORD * call_data_words + let memory_expansion = Gas.memory_expansion_cost_saturated(memory.words_len, offset, size); + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + let (calldata_words, _) = unsigned_div_rem(size.low + 31, 32); + let init_code_gas_low = Gas.INIT_CODE_WORD_COST * calldata_words; + tempvar init_code_gas_high = is_not_zero(size.high) * 2 ** 128; + let calldata_word_gas = is_create2 * Gas.KECCAK256_WORD * calldata_words; + let evm = EVM.charge_gas( + evm, memory_expansion.cost + init_code_gas_low + init_code_gas_high + calldata_word_gas + ); + if (evm.reverted != FALSE) { + return evm; + } + + // Load bytecode + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + memory_expansion.new_words_len, + ); + let (bytecode: felt*) = alloc(); + Memory.load_n(size.low, bytecode, offset.low); + + let (return_data) = alloc(); + + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=0, + return_data=return_data, + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund, + reverted=evm.reverted, + ); + + let target_address = CreateHelper.get_evm_address( + evm.message.address.evm, popped_len, popped, size.low, bytecode + ); + + // @dev: performed before eventual subsequent early-returns of this function + // to mark the account as warm EIP-2929 + let target_account = State.get_account(target_address); + + // Get message call gas + let (gas_limit, _) = unsigned_div_rem(evm.gas_left, 64); + let gas_limit = evm.gas_left - gas_limit; + + if (evm.message.read_only != FALSE) { + let evm = EVM.charge_gas(evm, gas_limit); + let (revert_reason_len, revert_reason) = Errors.stateModificationError(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + // Check sender balance and nonce + let sender = State.get_account(evm.message.address.evm); + let is_nonce_overflow = Helpers.is_zero(Constants.MAX_NONCE - sender.nonce); + let (is_balance_overflow) = uint256_lt([sender.balance], [value]); + let stack_depth_limit = Helpers.is_zero(Constants.STACK_MAX_DEPTH - evm.message.depth); + if (is_nonce_overflow + is_balance_overflow + stack_depth_limit != 0) { + Stack.push_uint128(0); + return evm; + } + + let evm = EVM.charge_gas(evm, gas_limit); + + // Operation + // Check target account availability + let is_collision = Account.has_code_or_nonce(target_account); + if (is_collision != 0) { + let sender = Account.set_nonce(sender, sender.nonce + 1); + State.update_account(sender); + Stack.push_uint128(0); + return evm; + } + + // Check code size + let code_size_too_big = is_nn(size.low - (2 * Constants.MAX_CODE_SIZE + 1)); + if (code_size_too_big != FALSE) { + let evm = EVM.charge_gas(evm, evm.gas_left + 1); + return evm; + } + + // Increment nonce + let sender = Account.set_nonce(sender, sender.nonce + 1); + State.update_account(sender); + + // Final update of calling context + tempvar parent = new model.Parent(evm, stack, memory, state); + let stack = Stack.init(); + let memory = Memory.init(); + let state = State.copy(); + + // Create child message + let (calldata: felt*) = alloc(); + let (valid_jumpdests_start, valid_jumpdests) = Helpers.initialize_jumpdests( + bytecode_len=size.low, bytecode=bytecode + ); + tempvar address_zero = new model.Address(starknet=0, evm=0); + tempvar message = new model.Message( + bytecode=bytecode, + bytecode_len=size.low, + valid_jumpdests_start=valid_jumpdests_start, + valid_jumpdests=valid_jumpdests, + calldata=calldata, + calldata_len=0, + value=value, + caller=evm.message.address.evm, + parent=parent, + address=target_account.address, + code_address=address_zero, + read_only=FALSE, + is_create=TRUE, + depth=evm.message.depth + 1, + env=evm.message.env, + cairo_precompile_called=evm.message.cairo_precompile_called, + ); + let child_evm = EVM.init(message, gas_limit); + let stack = Stack.init(); + + let target_account = State.get_account(target_address); + let target_account = Account.set_nonce(target_account, 1); + let target_account = Account.set_created(target_account, 1); + State.update_account(target_account); + + let transfer = model.Transfer(evm.message.address, target_account.address, [value]); + let success = State.add_transfer(transfer); + if (success == 0) { + Stack.push_uint128(0); + return child_evm; + } + + return child_evm; + } + + // @notice INVALID operation. + // @dev Equivalent to REVERT (since Byzantium fork) with 0,0 as stack parameters, + // except that all the gas given to the current context is consumed. + // @custom:since Frontier + // @custom:group System Operations + // @custom:gas NaN + // @custom:stack_consumed_elements 0 + // @custom:stack_produced_elements 0 + // @param evm The pointer to the execution context + // @return EVM The pointer to the updated execution context. + func exec_invalid{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let (revert_reason: felt*) = alloc(); + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=0, + return_data=revert_reason, + program_counter=evm.program_counter, + stopped=TRUE, + gas_left=0, + gas_refund=evm.gas_refund, + reverted=Errors.EXCEPTIONAL_HALT, + ); + return evm; + } + + // @notice RETURN operation. + // @dev Halt execution returning output data + // @custom:since Frontier + // @custom:group System Operations + // @custom:gas NaN + // @custom:stack_consumed_elements 2 + // @custom:stack_produced_elements 0 + // @return EVM The pointer to the updated execution context. + func exec_return{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(2); + let offset = popped[0]; + let size = popped[1]; + + let memory_expansion = Gas.memory_expansion_cost_saturated(memory.words_len, offset, size); + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + let evm = EVM.charge_gas(evm, memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + memory_expansion.new_words_len, + ); + let (local return_data: felt*) = alloc(); + Memory.load_n(size.low, return_data, offset.low); + + let evm = EVM.stop(evm, size.low, return_data, FALSE); + + return evm; + } + + // @notice REVERT operation. + // @dev + // @custom:since Byzantium + // @custom:group System Operations + // @custom:gas 0 + dynamic gas + // @custom:stack_consumed_elements 2 + // @custom:stack_produced_elements 0 + // @return EVM The pointer to the updated execution context. + func exec_revert{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let (popped) = Stack.pop_n(2); + let offset = popped[0]; + let size = popped[1]; + + let memory_expansion = Gas.memory_expansion_cost_saturated(memory.words_len, offset, size); + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + let evm = EVM.charge_gas(evm, memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + // Load revert reason from offset + let (return_data: felt*) = alloc(); + tempvar memory = new model.Memory( + word_dict_start=memory.word_dict_start, + word_dict=memory.word_dict, + memory_expansion.new_words_len, + ); + Memory.load_n(size.low, return_data, offset.low); + + let evm = EVM.stop(evm, size.low, return_data, Errors.REVERT); + return evm; + } + + // @notice CALL operation. Message call into an account. + // @dev we don't pop the two last arguments (ret_offset and ret_size) to get + // them at the end of the CALL. These two extra stack values need to be + // cleard if the CALL early return without reverting (value > balance, stack + // too deep). + // @custom:since Frontier + // @custom:group System Operations + // @custom:gas 0 + dynamic gas + // @custom:stack_consumed_elements 7 + // @custom:stack_produced_elements 1 + // @return EVM The pointer to the sub context. + func exec_call{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + // 1. Parse args from Stack + // Note: We don't pop ret_offset and ret_size here but at the end of the sub context + // See finalize_parent + let (popped) = Stack.pop_n(5); + let gas_param = popped[0]; + let to = uint256_to_uint160(popped[1]); + let value = popped + 2 * Uint256.SIZE; + let args_offset = popped + 3 * Uint256.SIZE; + let args_size = popped + 4 * Uint256.SIZE; + let (ret_offset) = Stack.peek(0); + let (ret_size) = Stack.peek(1); + + local call_sender = evm.message.address.evm; + + // 2. Gas + // Memory expansion cost + let memory_expansion = Gas.max_memory_expansion_cost( + memory.words_len, args_offset, args_size, ret_offset, ret_size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Access gas cost. The account is marked as warm in the `generic_call` function, + // which performs a `get_account`. + let is_account_warm = State.is_account_warm(to); + tempvar access_gas_cost = is_account_warm * Gas.WARM_ACCESS + (1 - is_account_warm) * + Gas.COLD_ACCOUNT_ACCESS; + + // Create gas cost + let is_account_alive = State.is_account_alive(to); + tempvar is_value_non_zero = is_not_zero(value.low) + is_not_zero(value.high); + tempvar is_value_non_zero = is_not_zero(is_value_non_zero); + let create_gas_cost = (1 - is_account_alive) * is_value_non_zero * Gas.NEW_ACCOUNT; + + // Transfer gas cost + let transfer_gas_cost = is_value_non_zero * Gas.CALL_VALUE; + + // Charge the fixed cost of the extra_gas + memory expansion + tempvar extra_gas = access_gas_cost + create_gas_cost + transfer_gas_cost; + let evm = EVM.charge_gas(evm, extra_gas + memory_expansion.cost); + + let gas = Gas.compute_message_call_gas(gas_param, evm.gas_left); + + // Charge the fixed message call gas + let evm = EVM.charge_gas(evm, gas); + if (evm.reverted != FALSE) { + // This EVM's stack will not be used anymore, since it reverted - no need to pop the + // last remaining 2 values ret_offset and ret_size. + return evm; + } + + // Operation + tempvar memory = new model.Memory( + memory.word_dict_start, memory.word_dict, memory_expansion.new_words_len + ); + if (evm.message.read_only * is_value_non_zero != FALSE) { + // No need to pop + let (revert_reason_len, revert_reason) = Errors.stateModificationError(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + tempvar gas_with_stipend = gas + is_value_non_zero * Gas.CALL_STIPEND; + + let sender = State.get_account(call_sender); + let (sender_balance_lt_value) = uint256_lt([sender.balance], [value]); + tempvar is_max_depth_reached = Helpers.is_zero( + Constants.STACK_MAX_DEPTH - evm.message.depth + ); + tempvar is_call_invalid = sender_balance_lt_value + is_max_depth_reached; + if (is_call_invalid != FALSE) { + // Requires popping the returndata offset and size before pushing 0 + Stack.pop_n(2); + Stack.push_uint128(0); + let (return_data) = alloc(); + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=0, + return_data=return_data, + program_counter=evm.program_counter, + stopped=FALSE, + gas_left=evm.gas_left + gas_with_stipend, + gas_refund=evm.gas_refund, + reverted=FALSE, + ); + return evm; + } + + let child_evm = CallHelper.generic_call( + evm, + gas=gas_with_stipend, + value=value, + caller=call_sender, + to=to, + code_address=to, + is_staticcall=FALSE, + args_offset=args_offset, + args_size=args_size, + ret_offset=ret_offset, + ret_size=ret_size, + ); + + let transfer = model.Transfer(evm.message.address, child_evm.message.address, [value]); + let success = State.add_transfer(transfer); + if (success == 0) { + let (revert_reason_len, revert_reason) = Errors.balanceError(); + tempvar child_evm = EVM.stop( + child_evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT + ); + } else { + tempvar child_evm = child_evm; + } + + return child_evm; + } + + // @notice STATICCALL operation. + // @dev + // @custom:since Homestead + // @custom:group System Operations + // @custom:gas 0 + dynamic gas + // @custom:stack_consumed_elements 6 + // @custom:stack_produced_elements 1 + // @return EVM The pointer to the sub context. + func exec_staticcall{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + // Stack + let (popped) = Stack.pop_n(4); + let gas_param = popped[0]; + let to = uint256_to_uint160(popped[1]); + let args_offset = popped + 2 * Uint256.SIZE; + let args_size = popped + 3 * Uint256.SIZE; + let (ret_offset) = Stack.peek(0); + let (ret_size) = Stack.peek(1); + + local call_sender = evm.message.address.evm; + + // Gas + // Memory expansion cost + let memory_expansion = Gas.max_memory_expansion_cost( + memory.words_len, args_offset, args_size, ret_offset, ret_size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Access gas cost. The account is marked as warm in the `is_account_alive` instruction, + // which performs a `get_account`. + let is_account_warm = State.is_account_warm(to); + tempvar access_gas_cost = is_account_warm * Gas.WARM_ACCESS + (1 - is_account_warm) * + Gas.COLD_ACCOUNT_ACCESS; + + // Charge the fixed cost of the extra_gas + memory expansion + let evm = EVM.charge_gas(evm, access_gas_cost + memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + let gas = Gas.compute_message_call_gas(gas_param, evm.gas_left); + let evm = EVM.charge_gas(evm, gas); + if (evm.reverted != FALSE) { + return evm; + } + + // Operation + tempvar memory = new model.Memory( + memory.word_dict_start, memory.word_dict, memory_expansion.new_words_len + ); + tempvar is_max_depth_reached = Helpers.is_zero( + Constants.STACK_MAX_DEPTH - evm.message.depth + ); + + if (is_max_depth_reached != FALSE) { + // Requires popping the returndata offset and size before pushing 0 + Stack.pop_n(2); + Stack.push_uint128(0); + let (return_data) = alloc(); + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=0, + return_data=return_data, + program_counter=evm.program_counter, + stopped=FALSE, + gas_left=evm.gas_left + gas, + gas_refund=evm.gas_refund, + reverted=FALSE, + ); + return evm; + } + + tempvar zero = new Uint256(0, 0); + // Operation + let child_evm = CallHelper.generic_call( + evm, + gas, + value=zero, + caller=call_sender, + to=to, + code_address=to, + is_staticcall=TRUE, + args_offset=args_offset, + args_size=args_size, + ret_offset=ret_offset, + ret_size=ret_size, + ); + + return child_evm; + } + + // @notice CALLCODE operation. + // @dev + // @custom:since Frontier + // @custom:group System Operations + // @custom:gas 0 + dynamic gas + // @custom:stack_consumed_elements 7 + // @custom:stack_produced_elements 1 + // @return EVM The pointer to the sub context. + func exec_callcode{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + // Stack + let (popped) = Stack.pop_n(5); + let gas_param = popped[0]; + let code_address = uint256_to_uint160(popped[1]); + let value = popped + 2 * Uint256.SIZE; + let args_offset = popped + 3 * Uint256.SIZE; + let args_size = popped + 4 * Uint256.SIZE; + let (ret_offset) = Stack.peek(0); + let (ret_size) = Stack.peek(1); + + local call_sender = evm.message.address.evm; + + // Gas + let memory_expansion = Gas.max_memory_expansion_cost( + memory.words_len, args_offset, args_size, ret_offset, ret_size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Access gas cost. The account is marked as warm in the `is_account_alive` instruction, + // which performs a `get_account`. + let is_account_warm = State.is_account_warm(code_address); + tempvar access_gas_cost = is_account_warm * Gas.WARM_ACCESS + (1 - is_account_warm) * + Gas.COLD_ACCOUNT_ACCESS; + + tempvar is_value_non_zero = is_not_zero(value.low) + is_not_zero(value.high); + tempvar is_value_non_zero = is_not_zero(is_value_non_zero); + let transfer_gas_cost = is_value_non_zero * Gas.CALL_VALUE; + + let extra_gas = access_gas_cost + transfer_gas_cost; + let evm = EVM.charge_gas(evm, extra_gas + memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + let gas = Gas.compute_message_call_gas(gas_param, evm.gas_left); + let evm = EVM.charge_gas(evm, gas); + if (evm.reverted != FALSE) { + return evm; + } + tempvar gas_with_stipend = gas + is_value_non_zero * Gas.CALL_STIPEND; + + // Operation + tempvar memory = new model.Memory( + memory.word_dict_start, memory.word_dict, memory_expansion.new_words_len + ); + let sender = State.get_account(call_sender); + let (sender_balance_lt_value) = uint256_lt([sender.balance], [value]); + tempvar is_max_depth_reached = Helpers.is_zero( + Constants.STACK_MAX_DEPTH - evm.message.depth + ); + tempvar is_call_invalid = sender_balance_lt_value + is_max_depth_reached; + if (is_call_invalid != FALSE) { + // Requires popping the returndata offset and size before pushing 0 + Stack.pop_n(2); + Stack.push_uint128(0); + let (return_data) = alloc(); + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=0, + return_data=return_data, + program_counter=evm.program_counter, + stopped=FALSE, + gas_left=evm.gas_left + gas_with_stipend, + gas_refund=evm.gas_refund, + reverted=FALSE, + ); + return evm; + } + + let child_evm = CallHelper.generic_call( + evm, + gas=gas_with_stipend, + value=value, + caller=call_sender, + to=call_sender, + code_address=code_address, + is_staticcall=FALSE, + args_offset=args_offset, + args_size=args_size, + ret_offset=ret_offset, + ret_size=ret_size, + ); + + return child_evm; + } + + // @notice DELEGATECALL operation. + // @dev + // @custom:since Byzantium + // @custom:group System Operations + // @custom:gas 0 + dynamic gas + // @custom:stack_consumed_elements 6 + // @custom:stack_produced_elements 1 + // @return EVM The pointer to the sub context. + func exec_delegatecall{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + // Stack + let (popped) = Stack.pop_n(4); + let gas_param = popped[0]; + let code_address = uint256_to_uint160(popped[1]); + let args_offset = popped + 2 * Uint256.SIZE; + let args_size = popped + 3 * Uint256.SIZE; + let (ret_offset) = Stack.peek(0); + let (ret_size) = Stack.peek(1); + + let call_sender = evm.message.caller; + let to = evm.message.address.evm; + + // Gas + // Memory expansion cost + let memory_expansion = Gas.max_memory_expansion_cost( + memory.words_len, args_offset, args_size, ret_offset, ret_size + ); + + if (memory_expansion.cost == Gas.MEMORY_COST_U32) { + let evm = EVM.out_of_gas(evm, memory_expansion.cost); + return evm; + } + + // Access gas cost. The account is marked as warm in the `generic_call` function, + // which performs a `get_account`. + let is_account_warm = State.is_account_warm(code_address); + tempvar access_gas_cost = is_account_warm * Gas.WARM_ACCESS + (1 - is_account_warm) * + Gas.COLD_ACCOUNT_ACCESS; + + // Charge the fixed cost of the extra_gas + memory expansion + let extra_gas = access_gas_cost; + let evm = EVM.charge_gas(evm, extra_gas + memory_expansion.cost); + if (evm.reverted != FALSE) { + return evm; + } + + let gas = Gas.compute_message_call_gas(gas_param, evm.gas_left); + let evm = EVM.charge_gas(evm, gas); + if (evm.reverted != FALSE) { + return evm; + } + + tempvar is_max_depth_reached = Helpers.is_zero( + Constants.STACK_MAX_DEPTH - evm.message.depth + ); + if (is_max_depth_reached != FALSE) { + // Requires popping the returndata offset and size before pushing 0 + Stack.pop_n(2); + Stack.push_uint128(0); + let (return_data) = alloc(); + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=0, + return_data=return_data, + program_counter=evm.program_counter, + stopped=FALSE, + gas_left=evm.gas_left + gas, + gas_refund=evm.gas_refund, + reverted=FALSE, + ); + return evm; + } + + // Operation + tempvar memory = new model.Memory( + memory.word_dict_start, memory.word_dict, memory_expansion.new_words_len + ); + let child_evm = CallHelper.generic_call( + evm, + gas, + value=evm.message.value, + caller=call_sender, + to=to, + code_address=code_address, + is_staticcall=FALSE, + args_offset=args_offset, + args_size=args_size, + ret_offset=ret_offset, + ret_size=ret_size, + ); + + return child_evm; + } + + // @notice SELFDESTRUCT operation. + // @dev + // @custom:since Frontier + // @custom:group System Operations + // @custom:gas 3000 + dynamic gas + // @custom:stack_consumed_elements 1 + // @return EVM The pointer to the updated execution_context. + func exec_selfdestruct{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + let (popped) = Stack.pop(); + let recipient = uint256_to_uint160([popped]); + + // Gas + // Access gas cost. The account is marked as warm in the `is_account_alive` instruction, + // which performs a `get_account` and thus must be performed after the warm check. + let is_recipient_warm = State.is_account_warm(recipient); + tempvar access_gas_cost = (1 - is_recipient_warm) * Gas.COLD_ACCOUNT_ACCESS; + + let is_recipient_alive = State.is_account_alive(recipient); + let self_account = State.get_account(evm.message.address.evm); + tempvar is_self_balance_zero = Helpers.is_zero(self_account.balance.low) * Helpers.is_zero( + self_account.balance.high + ); + tempvar gas_selfdestruct_new_account = (1 - is_recipient_alive) * ( + 1 - is_self_balance_zero + ) * Gas.SELF_DESTRUCT_NEW_ACCOUNT; + + let evm = EVM.charge_gas(evm, access_gas_cost + gas_selfdestruct_new_account); + if (evm.reverted != FALSE) { + return evm; + } + + // Operation + if (evm.message.read_only != FALSE) { + let (revert_reason_len, revert_reason) = Errors.stateModificationError(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + // If the account was created in the same transaction and recipient is self, the native token is burnt + tempvar is_recipient_not_self = is_not_zero(recipient - evm.message.address.evm); + + if (self_account.created != FALSE) { + tempvar recipient = is_recipient_not_self * recipient; + } else { + tempvar recipient = recipient; + } + + let recipient_account = State.get_account(recipient); + let transfer = model.Transfer( + sender=self_account.address, + recipient=recipient_account.address, + amount=[self_account.balance], + ); + let success = State.add_transfer(transfer); + + // Marked as SELFDESTRUCT for commitment + // @dev: get_account again because add_transfer updated it + let account = State.get_account(evm.message.address.evm); + let account = Account.selfdestruct(account); + State.update_account(account); + + // Halt context + let (return_data: felt*) = alloc(); + let evm = EVM.stop(evm, 0, return_data, FALSE); + + return evm; + } +} + +namespace CallHelper { + // @notice The shared logic of the CALL, CALLCODE, STATICCALL, and DELEGATECALL ops. + // Loads the calldata from memory, constructs the child evm corresponding to the new + // execution frame of the call and returns it. + // @param evm The current EVM, which is the parent of the new EVM. + // @param gas The gas to be used by the new EVM. + // @param value The value to be transferred in the call + // @param to The address of the target account. + // @param code_address The address of the account whose code will be executed. + // @param is_staticcall A boolean indicating whether the call is a static call. + // @param args_offset The offset of the calldata in memory. + // @param args_size The size of the calldata in memory. + // @param ret_offset The offset to store the return data at. + // @param ret_size The size of the return data. + // @return EVM The pointer to the newly created sub context. + func generic_call{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }( + evm: model.EVM*, + gas: felt, + value: Uint256*, + caller: felt, + to: felt, + code_address: felt, + is_staticcall: bool, + args_offset: Uint256*, + args_size: Uint256*, + ret_offset: Uint256*, + ret_size: Uint256*, + ) -> model.EVM* { + alloc_locals; + + // 1. Calldata + let (calldata: felt*) = alloc(); + Memory.load_n(args_size.low, calldata, args_offset.low); + + // 2. Build child_evm + + let code_account = State.get_account(code_address); + local code_len: felt = code_account.code_len; + local code: felt* = code_account.code; + + tempvar to_address = new model.Address(starknet=0xdead, evm=to); + + tempvar parent = new model.Parent(evm, stack, memory, state); + let stack = Stack.init(); + let memory = Memory.init(); + + if (is_staticcall != FALSE) { + tempvar read_only = TRUE; + } else { + tempvar read_only = evm.message.read_only; + } + + tempvar message = new model.Message( + bytecode=code, + bytecode_len=code_len, + valid_jumpdests_start=code_account.valid_jumpdests_start, + valid_jumpdests=code_account.valid_jumpdests, + calldata=calldata, + calldata_len=args_size.low, + value=value, + caller=caller, + parent=parent, + address=to_address, + code_address=code_account.address, + read_only=read_only, + is_create=FALSE, + depth=evm.message.depth + 1, + env=evm.message.env, + cairo_precompile_called=evm.message.cairo_precompile_called, + ); + + let child_evm = EVM.init(message, gas); + let state = State.copy(); + return child_evm; + } + + // @return EVM The pointer to the updated calling context. + func finalize_parent{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + // Pop ret_offset and ret_size + // See call family opcodes who don't pop these + // two values, the Stack here is guaranteed to have enough items + // values are checked there as Memory expansion cost is computed there. + let (popped) = Stack.pop_n(n=2); + let ret_offset = popped[0]; + let ret_size = popped[1]; + + // Put status in stack + let is_reverted = is_not_zero(evm.reverted); + Stack.push_uint128(1 - is_reverted); + + // Restore parent state if the call has reverted + if (evm.reverted != FALSE) { + tempvar state = evm.message.parent.state; + } else { + tempvar state = state; + } + let state = cast([ap - 1], model.State*); + + let cairo_precompile_called = evm.message.cairo_precompile_called + + evm.message.parent.evm.message.cairo_precompile_called; + + tempvar message = new model.Message( + bytecode=evm.message.parent.evm.message.bytecode, + bytecode_len=evm.message.parent.evm.message.bytecode_len, + valid_jumpdests_start=evm.message.parent.evm.message.valid_jumpdests_start, + valid_jumpdests=evm.message.parent.evm.message.valid_jumpdests, + calldata=evm.message.parent.evm.message.calldata, + calldata_len=evm.message.parent.evm.message.calldata_len, + value=evm.message.parent.evm.message.value, + caller=evm.message.parent.evm.message.caller, + parent=evm.message.parent.evm.message.parent, + address=evm.message.parent.evm.message.address, + code_address=evm.message.parent.evm.message.code_address, + read_only=evm.message.parent.evm.message.read_only, + is_create=evm.message.parent.evm.message.is_create, + depth=evm.message.parent.evm.message.depth, + env=evm.message.parent.evm.message.env, + cairo_precompile_called=cairo_precompile_called, + ); + + if (evm.reverted != FALSE) { + // If a call to a cairo precompile has been made, the tx should be reverted + with_attr error_message( + "EVM tx reverted, reverting SN tx because of previous calls to cairo precompiles") { + assert cairo_precompile_called = FALSE; + } + } + + if (evm.reverted == Errors.EXCEPTIONAL_HALT) { + // If the call has halted exceptionnaly, the return_data is empty + // and nothing is copied to memory, and the gas is not returned; + tempvar evm = new model.EVM( + message=message, + return_data_len=0, + return_data=evm.return_data, + program_counter=evm.message.parent.evm.program_counter + 1, + stopped=evm.message.parent.evm.stopped, + gas_left=evm.message.parent.evm.gas_left, + gas_refund=evm.message.parent.evm.gas_refund, + reverted=evm.message.parent.evm.reverted, + ); + return evm; + } + + let actual_output_size_is_ret_size = is_nn(evm.return_data_len - ret_size.low); + let actual_output_size = actual_output_size_is_ret_size * ret_size.low + ( + 1 - actual_output_size_is_ret_size + ) * evm.return_data_len; + Memory.store_n(actual_output_size, evm.return_data, ret_offset.low); + + if (evm.reverted != FALSE) { + tempvar gas_refund = evm.message.parent.evm.gas_refund; + } else { + tempvar gas_refund = evm.message.parent.evm.gas_refund + evm.gas_refund; + } + + tempvar evm = new model.EVM( + message=message, + return_data_len=evm.return_data_len, + return_data=evm.return_data, + program_counter=evm.message.parent.evm.program_counter + 1, + stopped=evm.message.parent.evm.stopped, + gas_left=evm.message.parent.evm.gas_left + evm.gas_left, + gas_refund=gas_refund, + reverted=evm.message.parent.evm.reverted, + ); + + return evm; + } +} + +namespace CreateHelper { + // @notice Constructs an evm contract address for the create opcode + // via last twenty bytes of the keccak hash of: + // keccak256(rlp([sender_address,sender_nonce])). + // See [CREATE](https://www.evm.codes/#f0). + // @param sender_address The evm sender address. + // @param bytecode_len The length of the initialization code. + // @param nonce The nonce given to the create opcode. + // @return EVM The pointer to the updated calling context. + func get_create_address{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(sender_address: felt, nonce: felt) -> (evm_contract_address: felt) { + alloc_locals; + local message_len; + // rlp([address, nonce]) inlined to save unnecessary expensive general RLP encoding + // final bytes is either + // (0xc0 + bytes_length) + (0x80 + 20) + address + nonce + // or + // (0xc0 + bytes_length) + (0x80 + 20) + address + (0x80 + nonce_len) + nonce + let (message: felt*) = alloc(); + assert [message + 1] = 0x80 + 20; + felt_to_bytes20(message + 2, sender_address); + let encode_nonce = is_nn(nonce - 0x80); + if (encode_nonce != FALSE) { + let nonce_len = felt_to_bytes(message + 2 + 20 + 1, nonce); + assert [message + 2 + 20] = 0x80 + nonce_len; + assert message_len = 1 + 1 + 20 + 1 + nonce_len; + tempvar range_check_ptr = range_check_ptr; + } else { + let is_nonce_not_zero = is_not_zero(nonce); + let encoded_nonce = nonce * is_nonce_not_zero + (1 - is_nonce_not_zero) * 0x80; + assert [message + 2 + 20] = encoded_nonce; + assert message_len = 1 + 1 + 20 + 1; + tempvar range_check_ptr = range_check_ptr; + } + let range_check_ptr = [ap - 1]; + assert message[0] = message_len + 0xc0 - 1; + + let msg_hash = keccak(message_len, message); + + let address = uint256_to_uint160(msg_hash); + return (address,); + } + + // @notice Constructs an evm contract address for the create2 opcode + // via last twenty bytes of the keccak hash of: + // keccak256(0xff + sender_address + salt + + // keccak256(initialization_code))[12:]. + // See [CREATE2](https://www.evm.codes/#f5). + // @param sender_address The evm sender address. + // @param bytecode_len The length of the initialization code. + // @param bytecode The offset to store the element at. + // @param salt The salt given to the create2 opcode. + // @return EVM The pointer to the updated calling context. + func get_create2_address{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(sender_address: felt, bytecode_len: felt, bytecode: felt*, salt: Uint256) -> felt { + alloc_locals; + + let bytecode_hash = keccak(bytecode_len, bytecode); + + // get keccak hash of + // marker + caller_address + salt + bytecode_hash + let (local packed_bytes: felt*) = alloc(); + + // 0xff is by convention the marker involved in deterministic address creation for create2 + assert [packed_bytes] = 0xff; + felt_to_bytes20(packed_bytes + 1, sender_address); + uint256_to_bytes32(packed_bytes + 1 + 20, salt); + uint256_to_bytes32(packed_bytes + 1 + 20 + 32, bytecode_hash); + let packed_bytes_len = 1 + 20 + 32 + 32; + + let create2_hash = keccak(packed_bytes_len, packed_bytes); + let create2_address = uint256_to_uint160(create2_hash); + + return create2_address; + } + + // @notice Pre-compute the evm address of a contract account before deploying it. + func get_evm_address{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + state: model.State*, + }( + evm_address: felt, popped_len: felt, popped: Uint256*, bytecode_len: felt, bytecode: felt* + ) -> felt { + alloc_locals; + // create2 context pops 4 off the stack, create pops 3 + // so we use popped_len to derive the way we should handle + // the creation of evm addresses + if (popped_len != 4) { + let account = State.get_account(evm_address); + let (evm_contract_address) = CreateHelper.get_create_address( + evm_address, account.nonce + ); + return evm_contract_address; + } else { + let salt = popped[3]; + let evm_contract_address = CreateHelper.get_create2_address( + sender_address=evm_address, bytecode_len=bytecode_len, bytecode=bytecode, salt=salt + ); + return evm_contract_address; + } + } + + // @notice At the end of a sub-context initiated with CREATE or CREATE2, the calling context's stack is updated. + // @dev Restores the parent state if the sub-context has reverted. + // @param evm The pointer to the calling context. + // @return EVM The pointer to the updated calling context. + func finalize_parent{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + let cairo_precompile_called = evm.message.cairo_precompile_called + + evm.message.parent.evm.message.cairo_precompile_called; + + tempvar message = new model.Message( + bytecode=evm.message.parent.evm.message.bytecode, + bytecode_len=evm.message.parent.evm.message.bytecode_len, + valid_jumpdests_start=evm.message.parent.evm.message.valid_jumpdests_start, + valid_jumpdests=evm.message.parent.evm.message.valid_jumpdests, + calldata=evm.message.parent.evm.message.calldata, + calldata_len=evm.message.parent.evm.message.calldata_len, + value=evm.message.parent.evm.message.value, + caller=evm.message.parent.evm.message.caller, + parent=evm.message.parent.evm.message.parent, + address=evm.message.parent.evm.message.address, + code_address=evm.message.parent.evm.message.code_address, + read_only=evm.message.parent.evm.message.read_only, + is_create=evm.message.parent.evm.message.is_create, + depth=evm.message.parent.evm.message.depth, + env=evm.message.parent.evm.message.env, + cairo_precompile_called=cairo_precompile_called, + ); + // Reverted during execution - either REVERT or exceptional + if (evm.reverted != FALSE) { + with_attr error_message( + "EVM tx reverted, reverting SN tx because of previous calls to cairo precompiles") { + assert cairo_precompile_called = FALSE; + } + let is_exceptional_revert = is_not_zero(Errors.REVERT - evm.reverted); + let return_data_len = (1 - is_exceptional_revert) * evm.return_data_len; + let gas_left = evm.message.parent.evm.gas_left + (1 - is_exceptional_revert) * + evm.gas_left; + let gas_refund = evm.message.parent.evm.gas_refund + (1 - is_exceptional_revert) * + evm.gas_refund; + + tempvar stack_code = new Uint256(low=0, high=0); + Stack.push(stack_code); + + tempvar state = evm.message.parent.state; + + tempvar evm = new model.EVM( + message=message, + return_data_len=return_data_len, + return_data=evm.return_data, + program_counter=evm.message.parent.evm.program_counter + 1, + stopped=evm.message.parent.evm.stopped, + gas_left=gas_left, + gas_refund=gas_refund, + reverted=evm.message.parent.evm.reverted, + ); + return evm; + } + + // Charge final deposit gas + let code_size_limit = is_nn(Constants.MAX_CODE_SIZE - evm.return_data_len); + let code_deposit_cost = Gas.CODE_DEPOSIT * evm.return_data_len; + let remaining_gas = evm.gas_left - code_deposit_cost; + let enough_gas = is_nn(remaining_gas); + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3540.md + if (evm.return_data_len == 0) { + tempvar is_prefix_not_0xef = TRUE; + } else { + tempvar is_prefix_not_0xef = is_not_zero(0xef - [evm.return_data]); + } + + let success = enough_gas * code_size_limit * is_prefix_not_0xef; + + // Stack output: the address of the deployed contract, 0 if the deployment failed. + let (address_high, address_low) = split_felt(evm.message.address.evm * success); + tempvar address = new Uint256(low=address_low, high=address_high); + Stack.push(address); + + if (success == FALSE) { + tempvar state = evm.message.parent.state; + with_attr error_message( + "EVM tx reverted, reverting SN tx because of previous calls to cairo precompiles") { + assert cairo_precompile_called = FALSE; + } + + tempvar evm = new model.EVM( + message=message, + return_data_len=0, + return_data=evm.return_data, + program_counter=evm.message.parent.evm.program_counter + 1, + stopped=evm.message.parent.evm.stopped, + gas_left=evm.message.parent.evm.gas_left, + gas_refund=evm.message.parent.evm.gas_refund, + reverted=evm.message.parent.evm.reverted, + ); + return evm; + } + + // Write bytecode and valid jumpdests to Account + let account = State.get_account(evm.message.address.evm); + let account = Account.set_code(account, evm.return_data_len, evm.return_data); + + // Update local state with the updated account inner pointers. + State.update_account(account); + + tempvar evm = new model.EVM( + message=message, + return_data_len=0, + return_data=evm.return_data, + program_counter=evm.message.parent.evm.program_counter + 1, + stopped=evm.message.parent.evm.stopped, + gas_left=evm.message.parent.evm.gas_left + remaining_gas, + gas_refund=evm.message.parent.evm.gas_refund + evm.gas_refund, + reverted=evm.message.parent.evm.reverted, + ); + + return evm; + } +} diff --git a/cairo/src/interfaces/interfaces.cairo b/cairo/src/interfaces/interfaces.cairo new file mode 100644 index 00000000..0a3099e3 --- /dev/null +++ b/cairo/src/interfaces/interfaces.cairo @@ -0,0 +1,26 @@ +from starkware.cairo.common.uint256 import Uint256 + +namespace ICairo1Helpers { + func exec_precompile(address: felt, data_len: felt, data: felt*) -> ( + success: felt, gas: felt, return_data_len: felt, return_data: felt* + ) { + } + + func get_block_hash(block_number: felt) -> (hash: felt) { + } + + func recover_eth_address(msg_hash: Uint256, r: Uint256, s: Uint256, y_parity: felt) -> ( + success: felt, address: felt + ) { + } + + func verify_signature_secp256r1( + msg_hash: Uint256, r: Uint256, s: Uint256, x: Uint256, y: Uint256 + ) -> (is_valid: felt) { + } +} + +namespace IAccount { + func is_valid_jumpdest(address: felt, index: felt) -> (is_valid: felt) { + } +} diff --git a/cairo/src/interpreter.cairo b/cairo/src/interpreter.cairo new file mode 100644 index 00000000..9e9850b3 --- /dev/null +++ b/cairo/src/interpreter.cairo @@ -0,0 +1,1087 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE, TRUE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math_cmp import is_not_zero, is_nn, is_le_felt +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.dict import DictAccess +from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc, get_ap +from starkware.cairo.common.uint256 import Uint256, uint256_le + +from src.account import Account +from src.constants import opcodes_label, Constants +from src.errors import Errors +from src.evm import EVM +from src.instructions.block_information import BlockInformation +from src.instructions.duplication_operations import DuplicationOperations +from src.instructions.environmental_information import EnvironmentalInformation +from src.instructions.exchange_operations import ExchangeOperations +from src.instructions.logging_operations import LoggingOperations +from src.instructions.memory_operations import MemoryOperations +from src.instructions.push_operations import PushOperations +from src.instructions.sha3 import Sha3 +from src.instructions.stop_and_math_operations import StopAndMathOperations +from src.instructions.system_operations import CallHelper, CreateHelper, SystemOperations +from src.memory import Memory +from src.model import model +from src.precompiles.precompiles import Precompiles +from src.precompiles.precompiles_helpers import PrecompilesHelpers +from src.stack import Stack +from src.state import State +from src.gas import Gas +from src.utils.utils import Helpers +from src.utils.array import count_not_zero +from src.utils.uint256 import uint256_sub, uint256_add +from src.utils.maths import unsigned_div_rem + +// @title EVM instructions processing. +// @notice This file contains functions related to the processing of EVM instructions. +namespace Interpreter { + // @notice Decode the current opcode and execute associated function. + // @dev The function uses an internal jump table to execute the corresponding opcode + // @param evm The pointer to the execution context. + // @return EVM The pointer to the updated execution context. + func exec_opcode{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + local opcode_number; + local opcode: model.Opcode*; + + let pc = evm.program_counter; + let is_pc_ge_code_len = is_nn(pc - evm.message.bytecode_len); + if (is_pc_ge_code_len != FALSE) { + let is_precompile = PrecompilesHelpers.is_precompile(evm.message.code_address.evm); + if (is_precompile != FALSE) { + let parent_context = evm.message.parent; + let is_parent_zero = Helpers.is_zero(cast(parent_context, felt)); + if (is_parent_zero != FALSE) { + // Case A: The precompile is called straight from an EOA + tempvar caller_code_address = evm.message.caller; + } else { + // Case B: The precompile is called from a contract + tempvar caller_code_address = parent_context.evm.message.code_address.evm; + } + tempvar caller_address = evm.message.caller; + let ( + output_len, output, gas_used, precompile_reverted + ) = Precompiles.exec_precompile( + evm.message.code_address.evm, + evm.message.calldata_len, + evm.message.calldata, + caller_code_address, + caller_address, + ); + let evm = EVM.charge_gas(evm, gas_used); + let evm_reverted = is_not_zero(evm.reverted); + let success = (1 - precompile_reverted) * (1 - evm_reverted); + let evm = EVM.stop(evm, output_len, output, 1 - success); + let is_cairo_precompile_called = PrecompilesHelpers.is_kakarot_precompile( + evm.message.code_address.evm + ); + tempvar message = new model.Message( + bytecode=evm.message.bytecode, + bytecode_len=evm.message.bytecode_len, + valid_jumpdests_start=evm.message.valid_jumpdests_start, + valid_jumpdests=evm.message.valid_jumpdests, + calldata=evm.message.calldata, + calldata_len=evm.message.calldata_len, + value=evm.message.value, + caller=evm.message.caller, + parent=evm.message.parent, + address=evm.message.address, + code_address=evm.message.code_address, + read_only=evm.message.read_only, + is_create=evm.message.is_create, + depth=evm.message.depth, + env=evm.message.env, + cairo_precompile_called=is_cairo_precompile_called, + ); + tempvar evm = new model.EVM( + message=message, + return_data_len=evm.return_data_len, + return_data=evm.return_data, + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=evm.gas_left, + gas_refund=evm.gas_refund, + reverted=evm.reverted, + ); + return evm; + } else { + let (return_data: felt*) = alloc(); + let evm = EVM.stop(evm, 0, return_data, FALSE); + return evm; + } + } + assert opcode_number = [evm.message.bytecode + pc]; + + // Get the corresponding opcode data + // To cast the codeoffset opcodes_label to a model.Opcode*, we need to use it to offset + // the current pc. We get the pc from the `get_fp_and_pc` util and assign a codeoffset (pc_label) to it. + // In short, this boils down to: opcode = pc + offset - pc = offset + let (_, cairo_pc) = get_fp_and_pc(); + + pc_label: + assert opcode = cast( + cairo_pc + (opcodes_label - pc_label) + opcode_number * model.Opcode.SIZE, model.Opcode* + ); + + // Check stack over/under flow + let stack_underflow = is_nn(opcode.stack_size_min - 1 - stack.size); + if (stack_underflow != 0) { + let (revert_reason_len, revert_reason) = Errors.stackUnderflow(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + let stack_overflow = is_nn( + stack.size + opcode.stack_size_diff - (Constants.STACK_MAX_DEPTH + 1) + ); + if (stack_overflow != 0) { + let (revert_reason_len, revert_reason) = Errors.stackOverflow(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + // Update static gas + let evm = EVM.charge_gas(evm, opcode.gas); + if (evm.reverted != FALSE) { + return evm; + } + + // Compute the corresponding offset in the jump table: + // count 1 for "next line" and 4 steps per opcode: call, opcode, jmp, end + tempvar offset = 1 + 4 * opcode_number; + + // Prepare arguments + [ap] = pedersen_ptr, ap++; + [ap] = range_check_ptr, ap++; + [ap] = bitwise_ptr, ap++; + [ap] = stack, ap++; + [ap] = memory, ap++; + [ap] = state, ap++; + [ap] = evm, ap++; + + // call opcode + jmp rel offset; + call StopAndMathOperations.exec_stop; // 0x0 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x1 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x2 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x3 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x4 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x5 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x6 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x7 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x8 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x9 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0xa + jmp end; + call StopAndMathOperations.exec_math_operation; // 0xb + jmp end; + call unknown_opcode; // 0xc + jmp end; + call unknown_opcode; // 0xd + jmp end; + call unknown_opcode; // 0xe + jmp end; + call unknown_opcode; // 0xf + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x10 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x11 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x12 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x13 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x14 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x15 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x16 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x17 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x18 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x19 + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x1a + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x1b + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x1c + jmp end; + call StopAndMathOperations.exec_math_operation; // 0x1d + jmp end; + call unknown_opcode; // 0x1e + jmp end; + call unknown_opcode; // 0x1f + jmp end; + call Sha3.exec_sha3; // 0x20 + jmp end; + call unknown_opcode; // 0x21 + jmp end; + call unknown_opcode; // 0x22 + jmp end; + call unknown_opcode; // 0x23 + jmp end; + call unknown_opcode; // 0x24 + jmp end; + call unknown_opcode; // 0x25 + jmp end; + call unknown_opcode; // 0x26 + jmp end; + call unknown_opcode; // 0x27 + jmp end; + call unknown_opcode; // 0x28 + jmp end; + call unknown_opcode; // 0x29 + jmp end; + call unknown_opcode; // 0x2a + jmp end; + call unknown_opcode; // 0x2b + jmp end; + call unknown_opcode; // 0x2c + jmp end; + call unknown_opcode; // 0x2d + jmp end; + call unknown_opcode; // 0x2e + jmp end; + call unknown_opcode; // 0x2f + jmp end; + call EnvironmentalInformation.exec_address; // 0x30 + jmp end; + call EnvironmentalInformation.exec_balance; // 0x31 + jmp end; + call EnvironmentalInformation.exec_origin; // 0x32 + jmp end; + call EnvironmentalInformation.exec_caller; // 0x33 + jmp end; + call EnvironmentalInformation.exec_callvalue; // 0x34 + jmp end; + call EnvironmentalInformation.exec_calldataload; // 0x35 + jmp end; + call EnvironmentalInformation.exec_calldatasize; // 0x36 + jmp end; + call EnvironmentalInformation.exec_copy; // 0x37 + jmp end; + call EnvironmentalInformation.exec_codesize; // 0x38 + jmp end; + call EnvironmentalInformation.exec_copy; // 0x39 + jmp end; + call EnvironmentalInformation.exec_gasprice; // 0x3a + jmp end; + call EnvironmentalInformation.exec_extcodesize; // 0x3b + jmp end; + call EnvironmentalInformation.exec_extcodecopy; // 0x3c + jmp end; + call EnvironmentalInformation.exec_returndatasize; // 0x3d + jmp end; + call EnvironmentalInformation.exec_returndatacopy; // 0x3e + jmp end; + call EnvironmentalInformation.exec_extcodehash; // 0x3f + jmp end; + call BlockInformation.exec_block_information; // 0x40 + jmp end; + call BlockInformation.exec_block_information; // 0x41 + jmp end; + call BlockInformation.exec_block_information; // 0x42 + jmp end; + call BlockInformation.exec_block_information; // 0x43 + jmp end; + call BlockInformation.exec_block_information; // 0x44 + jmp end; + call BlockInformation.exec_block_information; // 0x45 + jmp end; + call BlockInformation.exec_block_information; // 0x46 + jmp end; + call BlockInformation.exec_block_information; // 0x47 + jmp end; + call BlockInformation.exec_block_information; // 0x48 + jmp end; + call BlockInformation.exec_block_information; // 0x49 + jmp end; + call BlockInformation.exec_block_information; // 0x4a + jmp end; + call unknown_opcode; // 0x4b + jmp end; + call unknown_opcode; // 0x4c + jmp end; + call unknown_opcode; // 0x4d + jmp end; + call unknown_opcode; // 0x4e + jmp end; + call unknown_opcode; // 0x4f + jmp end; + call MemoryOperations.exec_pop; // 0x50 + jmp end; + call MemoryOperations.exec_mload; // 0x51 + jmp end; + call MemoryOperations.exec_mstore; // 0x52 + jmp end; + call MemoryOperations.exec_mstore8; // 0x53 + jmp end; + call MemoryOperations.exec_sload; // 0x54 + jmp end; + call MemoryOperations.exec_sstore; // 0x55 + jmp end; + call MemoryOperations.exec_jump; // 0x56 + jmp end_no_pc_increment; + call MemoryOperations.exec_jumpi; // 0x57 + jmp end_no_pc_increment; + call MemoryOperations.exec_pc; // 0x58 + jmp end; + call MemoryOperations.exec_msize; // 0x59 + jmp end; + call MemoryOperations.exec_gas; // 0x5a + jmp end; + call MemoryOperations.exec_jumpdest; // 0x5b + jmp end; + call MemoryOperations.exec_tload; // 0x5c + jmp end; + call MemoryOperations.exec_tstore; // 0x5d + jmp end; + call MemoryOperations.exec_mcopy; // 0x5e + jmp end; + call PushOperations.exec_push; // 0x5f + jmp end; + call PushOperations.exec_push; // 0x60 + jmp end; + call PushOperations.exec_push; // 0x61 + jmp end; + call PushOperations.exec_push; // 0x62 + jmp end; + call PushOperations.exec_push; // 0x63 + jmp end; + call PushOperations.exec_push; // 0x64 + jmp end; + call PushOperations.exec_push; // 0x65 + jmp end; + call PushOperations.exec_push; // 0x66 + jmp end; + call PushOperations.exec_push; // 0x67 + jmp end; + call PushOperations.exec_push; // 0x68 + jmp end; + call PushOperations.exec_push; // 0x69 + jmp end; + call PushOperations.exec_push; // 0x6a + jmp end; + call PushOperations.exec_push; // 0x6b + jmp end; + call PushOperations.exec_push; // 0x6c + jmp end; + call PushOperations.exec_push; // 0x6d + jmp end; + call PushOperations.exec_push; // 0x6e + jmp end; + call PushOperations.exec_push; // 0x6f + jmp end; + call PushOperations.exec_push; // 0x70 + jmp end; + call PushOperations.exec_push; // 0x71 + jmp end; + call PushOperations.exec_push; // 0x72 + jmp end; + call PushOperations.exec_push; // 0x73 + jmp end; + call PushOperations.exec_push; // 0x74 + jmp end; + call PushOperations.exec_push; // 0x75 + jmp end; + call PushOperations.exec_push; // 0x76 + jmp end; + call PushOperations.exec_push; // 0x77 + jmp end; + call PushOperations.exec_push; // 0x78 + jmp end; + call PushOperations.exec_push; // 0x79 + jmp end; + call PushOperations.exec_push; // 0x7a + jmp end; + call PushOperations.exec_push; // 0x7b + jmp end; + call PushOperations.exec_push; // 0x7c + jmp end; + call PushOperations.exec_push; // 0x7d + jmp end; + call PushOperations.exec_push; // 0x7e + jmp end; + call PushOperations.exec_push; // 0x7f + jmp end; + call DuplicationOperations.exec_dup; // 0x80 + jmp end; + call DuplicationOperations.exec_dup; // 0x81 + jmp end; + call DuplicationOperations.exec_dup; // 0x82 + jmp end; + call DuplicationOperations.exec_dup; // 0x83 + jmp end; + call DuplicationOperations.exec_dup; // 0x84 + jmp end; + call DuplicationOperations.exec_dup; // 0x85 + jmp end; + call DuplicationOperations.exec_dup; // 0x86 + jmp end; + call DuplicationOperations.exec_dup; // 0x87 + jmp end; + call DuplicationOperations.exec_dup; // 0x88 + jmp end; + call DuplicationOperations.exec_dup; // 0x89 + jmp end; + call DuplicationOperations.exec_dup; // 0x8a + jmp end; + call DuplicationOperations.exec_dup; // 0x8b + jmp end; + call DuplicationOperations.exec_dup; // 0x8c + jmp end; + call DuplicationOperations.exec_dup; // 0x8d + jmp end; + call DuplicationOperations.exec_dup; // 0x8e + jmp end; + call DuplicationOperations.exec_dup; // 0x8f + jmp end; + call ExchangeOperations.exec_swap; // 0x90 + jmp end; + call ExchangeOperations.exec_swap; // 0x91 + jmp end; + call ExchangeOperations.exec_swap; // 0x92 + jmp end; + call ExchangeOperations.exec_swap; // 0x93 + jmp end; + call ExchangeOperations.exec_swap; // 0x94 + jmp end; + call ExchangeOperations.exec_swap; // 0x95 + jmp end; + call ExchangeOperations.exec_swap; // 0x96 + jmp end; + call ExchangeOperations.exec_swap; // 0x97 + jmp end; + call ExchangeOperations.exec_swap; // 0x98 + jmp end; + call ExchangeOperations.exec_swap; // 0x99 + jmp end; + call ExchangeOperations.exec_swap; // 0x9a + jmp end; + call ExchangeOperations.exec_swap; // 0x9b + jmp end; + call ExchangeOperations.exec_swap; // 0x9c + jmp end; + call ExchangeOperations.exec_swap; // 0x9d + jmp end; + call ExchangeOperations.exec_swap; // 0x9e + jmp end; + call ExchangeOperations.exec_swap; // 0x9f + jmp end; + call LoggingOperations.exec_log; // 0xa0 + jmp end; + call LoggingOperations.exec_log; // 0xa1 + jmp end; + call LoggingOperations.exec_log; // 0xa2 + jmp end; + call LoggingOperations.exec_log; // 0xa3 + jmp end; + call LoggingOperations.exec_log; // 0xa4 + jmp end; + call unknown_opcode; // 0xa5 + jmp end; + call unknown_opcode; // 0xa6 + jmp end; + call unknown_opcode; // 0xa7 + jmp end; + call unknown_opcode; // 0xa8 + jmp end; + call unknown_opcode; // 0xa9 + jmp end; + call unknown_opcode; // 0xaa + jmp end; + call unknown_opcode; // 0xab + jmp end; + call unknown_opcode; // 0xac + jmp end; + call unknown_opcode; // 0xad + jmp end; + call unknown_opcode; // 0xae + jmp end; + call unknown_opcode; // 0xaf + jmp end; + call unknown_opcode; // 0xb0 + jmp end; + call unknown_opcode; // 0xb1 + jmp end; + call unknown_opcode; // 0xb2 + jmp end; + call unknown_opcode; // 0xb3 + jmp end; + call unknown_opcode; // 0xb4 + jmp end; + call unknown_opcode; // 0xb5 + jmp end; + call unknown_opcode; // 0xb6 + jmp end; + call unknown_opcode; // 0xb7 + jmp end; + call unknown_opcode; // 0xb8 + jmp end; + call unknown_opcode; // 0xb9 + jmp end; + call unknown_opcode; // 0xba + jmp end; + call unknown_opcode; // 0xbb + jmp end; + call unknown_opcode; // 0xbc + jmp end; + call unknown_opcode; // 0xbd + jmp end; + call unknown_opcode; // 0xbe + jmp end; + call unknown_opcode; // 0xbf + jmp end; + call unknown_opcode; // 0xc0 + jmp end; + call unknown_opcode; // 0xc1 + jmp end; + call unknown_opcode; // 0xc2 + jmp end; + call unknown_opcode; // 0xc3 + jmp end; + call unknown_opcode; // 0xc4 + jmp end; + call unknown_opcode; // 0xc5 + jmp end; + call unknown_opcode; // 0xc6 + jmp end; + call unknown_opcode; // 0xc7 + jmp end; + call unknown_opcode; // 0xc8 + jmp end; + call unknown_opcode; // 0xc9 + jmp end; + call unknown_opcode; // 0xca + jmp end; + call unknown_opcode; // 0xcb + jmp end; + call unknown_opcode; // 0xcc + jmp end; + call unknown_opcode; // 0xcd + jmp end; + call unknown_opcode; // 0xce + jmp end; + call unknown_opcode; // 0xcf + jmp end; + call unknown_opcode; // 0xd0 + jmp end; + call unknown_opcode; // 0xd1 + jmp end; + call unknown_opcode; // 0xd2 + jmp end; + call unknown_opcode; // 0xd3 + jmp end; + call unknown_opcode; // 0xd4 + jmp end; + call unknown_opcode; // 0xd5 + jmp end; + call unknown_opcode; // 0xd6 + jmp end; + call unknown_opcode; // 0xd7 + jmp end; + call unknown_opcode; // 0xd8 + jmp end; + call unknown_opcode; // 0xd9 + jmp end; + call unknown_opcode; // 0xda + jmp end; + call unknown_opcode; // 0xdb + jmp end; + call unknown_opcode; // 0xdc + jmp end; + call unknown_opcode; // 0xdd + jmp end; + call unknown_opcode; // 0xde + jmp end; + call unknown_opcode; // 0xdf + jmp end; + call unknown_opcode; // 0xe0 + jmp end; + call unknown_opcode; // 0xe1 + jmp end; + call unknown_opcode; // 0xe2 + jmp end; + call unknown_opcode; // 0xe3 + jmp end; + call unknown_opcode; // 0xe4 + jmp end; + call unknown_opcode; // 0xe5 + jmp end; + call unknown_opcode; // 0xe6 + jmp end; + call unknown_opcode; // 0xe7 + jmp end; + call unknown_opcode; // 0xe8 + jmp end; + call unknown_opcode; // 0xe9 + jmp end; + call unknown_opcode; // 0xea + jmp end; + call unknown_opcode; // 0xeb + jmp end; + call unknown_opcode; // 0xec + jmp end; + call unknown_opcode; // 0xed + jmp end; + call unknown_opcode; // 0xee + jmp end; + call unknown_opcode; // 0xef + jmp end; + call SystemOperations.exec_create; // 0xf0 + jmp end; + call SystemOperations.exec_call; // 0xf1 + jmp end; + call SystemOperations.exec_callcode; // 0xf2 + jmp end; + call SystemOperations.exec_return; // 0xf3 + jmp end; + call SystemOperations.exec_delegatecall; // 0xf4 + jmp end; + call SystemOperations.exec_create; // 0xf5 + jmp end; + call unknown_opcode; // 0xf6 + jmp end; + call unknown_opcode; // 0xf7 + jmp end; + call unknown_opcode; // 0xf8 + jmp end; + call unknown_opcode; // 0xf9 + jmp end; + call SystemOperations.exec_staticcall; // 0xfa + jmp end; + call unknown_opcode; // 0xfb + jmp end; + call unknown_opcode; // 0xfc + jmp end; + call SystemOperations.exec_revert; // 0xfd + jmp end; + call SystemOperations.exec_invalid; // 0xfe + jmp end; + call SystemOperations.exec_selfdestruct; // 0xff + jmp end; + + end: + let pedersen_ptr = cast([ap - 7], HashBuiltin*); + let range_check_ptr = [ap - 6]; + let bitwise_ptr = cast([ap - 5], BitwiseBuiltin*); + let stack = cast([ap - 4], model.Stack*); + let memory = cast([ap - 3], model.Memory*); + let state = cast([ap - 2], model.State*); + let evm = cast([ap - 1], model.EVM*); + let evm_prev = cast([fp - 3], model.EVM*); + + if (evm_prev.message.depth == evm.message.depth) { + let evm = EVM.increment_program_counter(evm, 1); + return evm; + } else { + return evm; + } + + end_no_pc_increment: + let pedersen_ptr = cast([ap - 7], HashBuiltin*); + let range_check_ptr = [ap - 6]; + let bitwise_ptr = cast([ap - 5], BitwiseBuiltin*); + let stack = cast([ap - 4], model.Stack*); + let memory = cast([ap - 3], model.Memory*); + let state = cast([ap - 2], model.State*); + let evm = cast([ap - 1], model.EVM*); + + return evm; + } + + // @notice A placeholder for opcodes that don't exist + // @dev Halts execution + // @param evm The pointer to the execution context + func unknown_opcode{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + let (revert_reason_len, revert_reason) = Errors.unknownOpcode(); + let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + return evm; + } + + // @notice Iteratively decode and execute the bytecode of an EVM + // @param evm The pointer to the execution context. + // @return EVM The pointer to the updated execution context. + func run{ + pedersen_ptr: HashBuiltin*, + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + stack: model.Stack*, + memory: model.Memory*, + state: model.State*, + }(evm: model.EVM*) -> model.EVM* { + alloc_locals; + + if (evm.stopped == FALSE) { + let evm = exec_opcode(evm); + return run(evm); + } + + Memory.finalize(); + Stack.finalize(); + State.finalize(); + with evm { + EVM.finalize(); + } + + if (evm.message.depth == 0) { + if (evm.reverted != 0) { + // All REVERTS in a root ctx set the gas_refund to 0. + // Only if the execution has halted exceptionnaly, consume all gas + let is_not_exceptional_revert = Helpers.is_zero(evm.reverted - 1); + let gas_left = is_not_exceptional_revert * evm.gas_left; + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=evm.return_data_len, + return_data=evm.return_data, + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=gas_left, + gas_refund=0, + reverted=evm.reverted, + ); + return evm; + } + if (evm.message.is_create != FALSE) { + let evm = Internals._finalize_create_tx(evm); + return evm; + } + + return evm; + } + + let stack = evm.message.parent.stack; + let memory = evm.message.parent.memory; + + if (evm.message.is_create != FALSE) { + let evm = CreateHelper.finalize_parent(evm); + return run(evm); + } else { + let evm = CallHelper.finalize_parent(evm); + return run(evm); + } + } + + // @notice Run the given bytecode with the given calldata and parameters + // @param address The target account address + // @param is_deploy_tx Whether the transaction is a deploy tx or not + // @param origin The caller EVM address + // @param bytecode_len The length of the bytecode + // @param bytecode The bytecode run + // @param calldata_len The length of the calldata + // @param calldata The calldata of the execution + // @param value The value of the execution + // @param gas_limit The gas limit of the execution + // @param gas_price The gas price for the execution + // @param access_list_len The length (in number of felts) of the serialized access list + // @param access_list The access list + // @return evm The EVM post-execution + // @return state The state post-execution + // @return stack The stack post-execution + // @return memory The memory post-execution + // @return gas_used the gas used by the transaction + // @return required_gas The amount of gas required by the transaction to successfully execute. This is different + // from the gas used by the transaction as it doesn't take into account any refunds. + func execute{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + env: model.Environment*, + address: model.Address*, + is_deploy_tx: felt, + bytecode_len: felt, + bytecode: felt*, + calldata_len: felt, + calldata: felt*, + value: Uint256*, + gas_limit: felt, + access_list_len: felt, + access_list: felt*, + ) -> (model.EVM*, model.Stack*, model.Memory*, model.State*, felt, felt) { + alloc_locals; + let fp_and_pc = get_fp_and_pc(); + local __fp__: felt* = fp_and_pc.fp_val; + + // Compute intrinsic gas usage + // See https://www.evm.codes/about#gascosts + let count = count_not_zero(calldata_len, calldata); + let zeroes = calldata_len - count; + let calldata_gas = zeroes * 4 + count * 16; + let intrinsic_gas = Gas.TX_BASE_COST + calldata_gas; + + // If is_deploy_tx is TRUE, then + // bytecode is data and data is empty + // else, bytecode and data are kept as is + let bytecode_len = calldata_len * is_deploy_tx + bytecode_len * (1 - is_deploy_tx); + let calldata_len = calldata_len * (1 - is_deploy_tx); + + let tmp_bytecode = bytecode; + let tmp_calldata = calldata; + let tmp_intrinsic_gas = intrinsic_gas; + local bytecode: felt*; + local calldata: felt*; + local intrinsic_gas: felt; + local code_address: model.Address*; + if (is_deploy_tx != FALSE) { + let (empty: felt*) = alloc(); + let (init_code_words, _) = unsigned_div_rem(bytecode_len + 31, 32); + let init_code_gas = Gas.INIT_CODE_WORD_COST * init_code_words; + assert bytecode = tmp_calldata; + assert calldata = empty; + assert intrinsic_gas = tmp_intrinsic_gas + Gas.CREATE + init_code_gas; + assert code_address = new model.Address(starknet=0, evm=0); + let (valid_jumpdests_start, valid_jumpdests) = Helpers.initialize_jumpdests( + bytecode_len=bytecode_len, bytecode=bytecode + ); + tempvar range_check_ptr = range_check_ptr; + tempvar valid_jumpdests_start = valid_jumpdests_start; + tempvar valid_jumpdests = valid_jumpdests; + } else { + assert bytecode = tmp_bytecode; + assert calldata = tmp_calldata; + assert intrinsic_gas = tmp_intrinsic_gas; + assert code_address = address; + + let (new_dict) = default_dict_new(0); + tempvar range_check_ptr = range_check_ptr; + tempvar valid_jumpdests_start = new_dict; + tempvar valid_jumpdests = new_dict; + } + + let valid_jumpdests_start = cast([ap - 2], DictAccess*); + let valid_jumpdests = cast([ap - 1], DictAccess*); + + tempvar message = new model.Message( + bytecode=bytecode, + bytecode_len=bytecode_len, + valid_jumpdests_start=valid_jumpdests_start, + valid_jumpdests=valid_jumpdests, + calldata=calldata, + calldata_len=calldata_len, + value=value, + caller=env.origin, + parent=cast(0, model.Parent*), + address=address, + code_address=code_address, + read_only=FALSE, + is_create=is_deploy_tx, + depth=0, + env=env, + cairo_precompile_called=FALSE, + ); + + let stack = Stack.init(); + let memory = Memory.init(); + let state = State.init(); + + // Cache the coinbase, precompiles, caller, and target, making them warm + with state { + let coinbase = State.get_account(env.coinbase); + State.cache_precompiles(); + State.get_account(address.evm); + let access_list_cost = State.cache_access_list(access_list_len, access_list); + } + + let intrinsic_gas = intrinsic_gas + access_list_cost; + let evm = EVM.init(message, gas_limit - intrinsic_gas); + + let is_gas_limit_enough = is_le_felt(intrinsic_gas, gas_limit); + if (is_gas_limit_enough == FALSE) { + let evm = EVM.halt_validation_failed(evm); + State.finalize{state=state}(); + return (evm, stack, memory, state, 0, 0); + } + + tempvar is_initcode_invalid = is_deploy_tx * is_nn( + bytecode_len - (2 * Constants.MAX_CODE_SIZE + 1) + ); + if (is_initcode_invalid != FALSE) { + let evm = EVM.halt_validation_failed(evm); + State.finalize{state=state}(); + return (evm, stack, memory, state, 0, 0); + } + + // Charge the gas fee to the user without setting up a transfer. + // Transfers with the exact amounts will be performed post-execution. + // Note: balance > effective_fee was verified in eth_send_raw_unsigned_tx() + let max_fee = gas_limit * env.gas_price; + let (fee_high, fee_low) = split_felt(max_fee); + let max_fee_u256 = Uint256(low=fee_low, high=fee_high); + + with state { + let sender = State.get_account(env.origin); + let (local new_balance) = uint256_sub([sender.balance], max_fee_u256); + let sender = Account.set_balance(sender, &new_balance); + let sender = Account.set_nonce(sender, sender.nonce + 1); + State.update_account(sender); + + let transfer = model.Transfer(sender.address, address, [value]); + let success = State.add_transfer(transfer); + + // Check collision + let account = State.get_account(address.evm); + let code_or_nonce = Account.has_code_or_nonce(account); + let is_collision = code_or_nonce * is_deploy_tx; + // Nonce is set to 1 in case of deploy_tx and account is marked as created + let nonce = account.nonce * (1 - is_deploy_tx) + is_deploy_tx; + let account = Account.set_nonce(account, nonce); + let account = Account.set_created(account, is_deploy_tx); + State.update_account(account); + } + + if (is_collision != 0) { + let (revert_reason_len, revert_reason) = Errors.addressCollision(); + tempvar evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + } else { + tempvar evm = evm; + } + + if (success == 0) { + let (revert_reason_len, revert_reason) = Errors.balanceError(); + tempvar evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT); + } else { + tempvar evm = evm; + } + + with stack, memory, state { + let evm = run(evm); + } + + let required_gas = gas_limit - evm.gas_left; + let (max_refund, _) = unsigned_div_rem(required_gas, 5); + let is_max_refund_le_gas_refund = is_nn(evm.gas_refund - max_refund); + tempvar gas_refund = is_max_refund_le_gas_refund * max_refund + ( + 1 - is_max_refund_le_gas_refund + ) * evm.gas_refund; + + let total_gas_used = required_gas - gas_refund; + + // Reset the state if the execution has failed. + // Only the gas fee paid will be committed. + State.finalize{state=state}(); + if (evm.reverted != 0) { + with_attr error_message( + "EVM tx reverted, reverting SN tx because of previous calls to cairo precompiles") { + assert evm.message.cairo_precompile_called = FALSE; + } + tempvar state = State.init(); + } else { + tempvar state = state; + } + let is_reverted = is_not_zero(evm.reverted); + let success = 1 - is_reverted; + let paid_fee_u256 = Uint256(max_fee_u256.low * success, max_fee_u256.high * success); + + with state { + let sender = State.get_account(env.origin); + uint256_add([sender.balance], paid_fee_u256); + let (ap_val) = get_ap(); + let sender = Account.set_balance(sender, cast(ap_val - 3, Uint256*)); + let sender = Account.set_nonce(sender, sender.nonce + is_reverted); + State.update_account(sender); + } + + // So as to not burn the base_fee_per gas, we send it to the coinbase. + let actual_fee = total_gas_used * env.gas_price; + let (fee_high, fee_low) = split_felt(actual_fee); + let actual_fee_u256 = Uint256(low=fee_low, high=fee_high); + let transfer = model.Transfer(sender.address, coinbase.address, actual_fee_u256); + + with state { + State.add_transfer(transfer); + State.finalize(); + } + + return (evm, stack, memory, state, total_gas_used, required_gas); + } +} + +namespace Internals { + func _finalize_create_tx{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + evm: model.EVM* + ) -> model.EVM* { + alloc_locals; + let is_reverted = is_not_zero(evm.reverted); + if (is_reverted != 0) { + return evm; + } + + // Charge final deposit gas + let code_size_limit = is_nn(Constants.MAX_CODE_SIZE - evm.return_data_len); + let code_deposit_cost = Gas.CODE_DEPOSIT * evm.return_data_len; + let enough_gas = is_nn(evm.gas_left - code_deposit_cost); + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3540.md + if (evm.return_data_len == 0) { + tempvar is_prefix_not_0xef = TRUE; + } else { + tempvar is_prefix_not_0xef = is_not_zero(0xef - [evm.return_data]); + } + + let success = enough_gas * code_size_limit * is_prefix_not_0xef; + + if (success == 0) { + // Reverts and burn all gas + let (revert_reason_len, revert_reason) = Errors.outOfGas( + evm.gas_left, code_deposit_cost + ); + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=revert_reason_len, + return_data=revert_reason, + program_counter=evm.program_counter, + stopped=TRUE, + gas_left=0, + gas_refund=0, + reverted=Errors.EXCEPTIONAL_HALT, + ); + return evm; + } + + // Write bytecode and cache the final code valid jumpdests to Account + let account = State.get_account(evm.message.address.evm); + let account = Account.set_code(account, evm.return_data_len, evm.return_data); + + State.update_account(account); + State.finalize(); + + // Update gas and return data - we know gas_left > code_deposit_cost + tempvar evm = new model.EVM( + message=evm.message, + return_data_len=2, + return_data=cast(evm.message.address, felt*), + program_counter=evm.program_counter, + stopped=evm.stopped, + gas_left=evm.gas_left - code_deposit_cost, + gas_refund=evm.gas_refund, + reverted=evm.reverted, + ); + + return evm; + } +} diff --git a/cairo/src/memory.cairo b/cairo/src/memory.cairo new file mode 100644 index 00000000..3163203d --- /dev/null +++ b/cairo/src/memory.cairo @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: MIT + +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.default_dict import default_dict_new, default_dict_finalize +from starkware.cairo.common.dict import DictAccess, dict_read, dict_write +from starkware.cairo.common.uint256 import Uint256 + +from src.model import model +from src.utils.utils import Helpers +from src.utils.maths import unsigned_div_rem + +// @title Memory related functions. +// @notice This file contains functions related to the memory. +// @dev The memory is a region that only exists during the smart contract execution, and is accessed +// @dev with a byte offset. +// @dev While all the 32-byte address space is available and initialized to 0, the +// @dev size is counted with the highest address that was accessed. +// @dev It is generally read and written with `MLOAD` and `MSTORE` instructions, +// @dev but is also used by other instructions like `CREATE` or `EXTCODECOPY`. +// @dev The memory representation at model.Memory is a sequence of 128bit (16B) chunks, +// @dev stored as a dictionary from chunk_index to chunk_value. +// @dev Each chunk should be read as big endian representation of 16 bytes. +namespace Memory { + // @notice Initialize the memory. + // @return memory The pointer to the memory. + func init() -> model.Memory* { + let (word_dict_start: DictAccess*) = default_dict_new(0); + return new model.Memory(word_dict_start, word_dict_start, 0); + } + + // @notice Finalize the memory. + // @return summary The pointer to the memory Summary. + func finalize{range_check_ptr, memory: model.Memory*}() { + let (squashed_start, squashed_end) = default_dict_finalize( + memory.word_dict_start, memory.word_dict, 0 + ); + tempvar memory = new model.Memory(squashed_start, squashed_end, memory.words_len); + return (); + } + + // @notice Store an element into the memory. + // @param memory The pointer to the memory. + // @param element The element to push. + // @param offset The offset to store the element at. + // @return memory The new pointer to the memory. + func store{range_check_ptr, memory: model.Memory*}(element: Uint256, offset: felt) { + let word_dict = memory.word_dict; + + // Check alignment of offset to 16B chunks. + let (chunk_index, offset_in_chunk) = unsigned_div_rem(offset, 16); + + if (offset_in_chunk == 0) { + // Offset is aligned. This is the simplest and most efficient case, + // so we optimize for it. Note that no locals were allocated at all. + dict_write{dict_ptr=word_dict}(chunk_index, element.high); + dict_write{dict_ptr=word_dict}(chunk_index + 1, element.low); + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (); + } + + // Offset is misaligned. + // | W0 | W1 | w2 | + // | EL_H | EL_L | + // ^---^ + // |-- mask = 256 ** offset_in_chunk + + // Compute mask. + tempvar mask = Helpers.pow256_rev(offset_in_chunk); + let mask_c = 2 ** 128 / mask; + + // Split the 2 input 16B chunks at offset_in_chunk. + let (el_hh, el_hl) = unsigned_div_rem(element.high, mask_c); + let (el_lh, el_ll) = unsigned_div_rem(element.low, mask_c); + + // Read the words at chunk_index, chunk_index + 2. + let (w0) = dict_read{dict_ptr=word_dict}(chunk_index); + let (w2) = dict_read{dict_ptr=word_dict}(chunk_index + 2); + + // Compute the new words. + let (w0_h, _) = unsigned_div_rem(w0, mask); + let (_, w2_l) = unsigned_div_rem(w2, mask); + let new_w0 = w0_h * mask + el_hh; + let new_w1 = el_hl * mask + el_lh; + let new_w2 = el_ll * mask + w2_l; + + // Write new words. + dict_write{dict_ptr=word_dict}(chunk_index, new_w0); + dict_write{dict_ptr=word_dict}(chunk_index + 1, new_w1); + dict_write{dict_ptr=word_dict}(chunk_index + 2, new_w2); + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (); + } + + // @notice Store N bytes into the memory. + // @param memory The pointer to the memory. + // @param element_len byte length of the array to be saved on memory. + // @param element pointer to the array that will be saved on memory. + // @param offset The offset to store the element at. + // @return memory The new pointer to the memory. + func store_n{range_check_ptr, memory: model.Memory*}( + element_len: felt, element: felt*, offset: felt + ) { + alloc_locals; + if (element_len == 0) { + return (); + } + + let word_dict = memory.word_dict; + + // Check alignment of offset to 16B chunks. + let (chunk_index_i, offset_in_chunk_i) = unsigned_div_rem(offset, 16); + let (chunk_index_f, offset_in_chunk_f) = unsigned_div_rem(offset + element_len - 1, 16); + tempvar offset_in_chunk_f = offset_in_chunk_f + 1; + let mask_i = Helpers.pow256_rev(offset_in_chunk_i); + let mask_f = Helpers.pow256_rev(offset_in_chunk_f); + + // Special case: within the same word. + if (chunk_index_i == chunk_index_f) { + let (w) = dict_read{dict_ptr=word_dict}(chunk_index_i); + + let (w_h, w_l) = Helpers.div_rem(w, mask_i); + let (_, w_ll) = Helpers.div_rem(w_l, mask_f); + let x = Helpers.bytes_to_felt(element_len, element); + let new_w = w_h * mask_i + x * mask_f + w_ll; + dict_write{dict_ptr=word_dict}(chunk_index_i, new_w); + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (); + } + + // Otherwise. + // Fill first word. + let (w_i) = dict_read{dict_ptr=word_dict}(chunk_index_i); + let (w_i_h, _) = Helpers.div_rem(w_i, mask_i); + let x_i = Helpers.bytes_to_felt(16 - offset_in_chunk_i, element); + dict_write{dict_ptr=word_dict}(chunk_index_i, w_i_h * mask_i + x_i); + + // Fill last word. + let (w_f) = dict_read{dict_ptr=word_dict}(chunk_index_f); + let (_, w_f_l) = Helpers.div_rem(w_f, mask_f); + let x_f = Helpers.bytes_to_felt( + offset_in_chunk_f, element + element_len - offset_in_chunk_f + ); + dict_write{dict_ptr=word_dict}(chunk_index_f, x_f * mask_f + w_f_l); + + // Write blocks. + Internals.store_aligned_words{dict_ptr=word_dict}( + chunk_index_i + 1, chunk_index_f, element + 16 - offset_in_chunk_i + ); + + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (); + } + + // @notice Load an element from the memory. + // @param memory The pointer to the memory. + // @param offset The offset to load the element from. + // @return memory The new pointer to the memory. + // @return loaded_element The loaded element. + func load{range_check_ptr, memory: model.Memory*}(offset: felt) -> Uint256 { + let word_dict = memory.word_dict; + + // Check alignment of offset to 16B chunks. + let (chunk_index, offset_in_chunk) = unsigned_div_rem(offset, 16); + + if (offset_in_chunk == 0) { + // Offset is aligned. This is the simplest and most efficient case, + // so we optimize for it. Note that no locals were allocated at all. + let (el_h) = dict_read{dict_ptr=word_dict}(chunk_index); + let (el_l) = dict_read{dict_ptr=word_dict}(chunk_index + 1); + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (Uint256(low=el_l, high=el_h)); + } + + // Offset is misaligned. + // | W0 | W1 | w2 | + // | EL_H | EL_L | + // ^---^ + // |-- mask = 256 ** offset_in_chunk + + // Compute mask. + tempvar mask = Helpers.pow256_rev(offset_in_chunk); + tempvar mask_c = 2 ** 128 / mask; + + // Read words. + let (w0) = dict_read{dict_ptr=word_dict}(chunk_index); + let (w1) = dict_read{dict_ptr=word_dict}(chunk_index + 1); + let (w2) = dict_read{dict_ptr=word_dict}(chunk_index + 2); + + // Compute element words. + let (_, w0_l) = unsigned_div_rem(w0, mask); + let (w1_h, w1_l) = unsigned_div_rem(w1, mask); + let (w2_h, _) = unsigned_div_rem(w2, mask); + let el_h = w0_l * mask_c + w1_h; + let el_l = w1_l * mask_c + w2_h; + + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (Uint256(low=el_l, high=el_h)); + } + + // @notice Load N bytes from the memory. + // @param memory The pointer to the memory. + // @param element_len byte length of the output array. + // @param element pointer to the output array. + // @param offset The memory offset to load from. + // @return memory The new pointer to the memory. + func load_n{range_check_ptr, memory: model.Memory*}( + element_len: felt, element: felt*, offset: felt + ) { + alloc_locals; + + if (element_len == 0) { + return (); + } + + let word_dict = memory.word_dict; + + // Check alignment of offset to 16B chunks. + let (chunk_index_i, offset_in_chunk_i) = unsigned_div_rem(offset, 16); + let (chunk_index_f, offset_in_chunk_f) = unsigned_div_rem(offset + element_len - 1, 16); + tempvar offset_in_chunk_f = offset_in_chunk_f + 1; + let mask_i = Helpers.pow256_rev(offset_in_chunk_i); + let mask_f = Helpers.pow256_rev(offset_in_chunk_f); + + // Special case: within the same word. + if (chunk_index_i == chunk_index_f) { + let (w) = dict_read{dict_ptr=word_dict}(chunk_index_i); + let (_, w_l) = Helpers.div_rem(w, mask_i); + let (w_lh, _) = Helpers.div_rem(w_l, mask_f); + Helpers.split_word(w_lh, element_len, element); + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (); + } + + // Otherwise. + // Get first word. + let (w_i) = dict_read{dict_ptr=word_dict}(chunk_index_i); + let (_, w_i_l) = Helpers.div_rem(w_i, mask_i); + Helpers.split_word(w_i_l, 16 - offset_in_chunk_i, element); + + // Get last word. + let (w_f) = dict_read{dict_ptr=word_dict}(chunk_index_f); + let (w_f_h, _) = Helpers.div_rem(w_f, mask_f); + Helpers.split_word(w_f_h, offset_in_chunk_f, element + element_len - offset_in_chunk_f); + + // Get blocks. + Internals.load_aligned_words{dict_ptr=word_dict}( + chunk_index_i + 1, chunk_index_f, element + 16 - offset_in_chunk_i + ); + + tempvar memory = new model.Memory(memory.word_dict_start, word_dict, memory.words_len); + return (); + } +} + +namespace Internals { + func store_aligned_words{range_check_ptr, dict_ptr: DictAccess*}( + chunk_index: felt, chunk_index_f: felt, element: felt* + ) { + if (chunk_index == chunk_index_f) { + return (); + } + let current = ( + element[0] * 256 ** 15 + + element[1] * 256 ** 14 + + element[2] * 256 ** 13 + + element[3] * 256 ** 12 + + element[4] * 256 ** 11 + + element[5] * 256 ** 10 + + element[6] * 256 ** 9 + + element[7] * 256 ** 8 + + element[8] * 256 ** 7 + + element[9] * 256 ** 6 + + element[10] * 256 ** 5 + + element[11] * 256 ** 4 + + element[12] * 256 ** 3 + + element[13] * 256 ** 2 + + element[14] * 256 ** 1 + + element[15] * 256 ** 0 + ); + dict_write(chunk_index, current); + return store_aligned_words( + chunk_index=chunk_index + 1, chunk_index_f=chunk_index_f, element=&element[16] + ); + } + + func load_aligned_words{range_check_ptr, dict_ptr: DictAccess*}( + chunk_index: felt, chunk_index_f: felt, element: felt* + ) { + if (chunk_index == chunk_index_f) { + return (); + } + let (value) = dict_read(chunk_index); + Helpers.split_word_128(value, element); + return load_aligned_words( + chunk_index=chunk_index + 1, chunk_index_f=chunk_index_f, element=&element[16] + ); + } +} diff --git a/cairo/src/model.cairo b/cairo/src/model.cairo new file mode 100644 index 00000000..ad872920 --- /dev/null +++ b/cairo/src/model.cairo @@ -0,0 +1,223 @@ +// StarkWare dependencies +from starkware.cairo.common.dict import DictAccess +from starkware.cairo.common.uint256 import Uint256 + +namespace model { + // @notice Represents the cost and size of a memory expansion operation. + // @param cost The cost of the memory expansion operation. + // @param new_words_len The number of words in the memory post-expansion. + struct MemoryExpansion { + cost: felt, + new_words_len: felt, + } + + // @notice: Represents an optional value. + // @param is_some A boolean indicating whether the value is present. + // @param value The value (if applicable). + struct Option { + is_some: felt, + value: felt, + } + + // @notice Info: https://www.evm.codes/about#stack + // @notice Stack with a 1024 items maximum size. Each item is a 256 bits word. The stack is used by most + // @notice opcodes to consume their parameters from. + // @dev The dict stores a pointer to the word (a Uint256). + // @param size The size of the Stack. + // @param dict_ptr_start pointer to a DictAccess array used to store the stack's value at a given index. + // @param dict_ptr pointer to the end of the DictAccess array. + struct Stack { + dict_ptr_start: DictAccess*, + dict_ptr: DictAccess*, + size: felt, + } + + // @notice info: https://www.evm.codes/about#memory + // @notice Transient memory maintained by the EVM during an execution which doesn't persist + // @notice between transactions. + // @param word_dict_start pointer to a DictAccess used to store the memory's value at a given index. + // @param word_dict pointer to the end of the DictAccess array. + // @param words_len number of words (bytes32). + struct Memory { + word_dict_start: DictAccess*, + word_dict: DictAccess*, + words_len: felt, + } + + // @dev In Cairo Zero, dict are list of DictAccess, ie that they can contain only felts. For having + // dict of structs, we store in the dict pointers to the struct. List of structs are just list of + // felt with inlined structs. Hence one has eventually + // accounts := Dict + // events := List + // transfers := List + // Unlike in standard EVM, we need to store the native token transfers as well since we use the + // Starknet's ETH and can't just set the balances + struct State { + accounts_start: DictAccess*, + accounts: DictAccess*, + events_len: felt, + events: Event*, + transfers_len: felt, + transfers: Transfer*, + } + + // @notice The struct representing an EVM account. + // @dev We don't put the balance here to avoid loading the whole Account just for sending ETH + // @dev The address is a tuple (starknet, evm) for step-optimization purposes: + // we can compute the starknet only once. + struct Account { + address: model.Address*, + code_len: felt, + code: felt*, + code_hash: Uint256*, + storage_start: DictAccess*, + storage: DictAccess*, + transient_storage_start: DictAccess*, + transient_storage: DictAccess*, + valid_jumpdests_start: DictAccess*, + valid_jumpdests: DictAccess*, + nonce: felt, + balance: Uint256*, + selfdestruct: felt, + // @dev: another way of knowing if an account was just created or not is to get it's registered starknet address. + // 1. It's zero -> it was created in the same tx + // 2. It's non-zero -> We fetch it's nonce from storage, if 0 -> it was created in the same tx, otherwise it was created in a previous tx. + created: felt, + } + + // @notice The struct representing an EVM event. + // @dev The topics are indeed a first felt for the emitting EVM account, followed by a list of Uint256 + struct Event { + topics_len: felt, + topics: felt*, + data_len: felt, + data: felt*, + } + + // @dev A struct to save Starknet native ETH transfers to be made when finalizing a tx + struct Transfer { + sender: Address*, + recipient: Address*, + amount: Uint256, + } + + // @dev Though one of the two address is enough, we store both to save on steps and simplify the usage. + struct Address { + starknet: felt, + evm: felt, + } + + // @notice info: https://www.evm.codes/about#calldata + // @notice Struct storing data related to a call. + // @dev All Message fields are constant during a given call. + // @param bytecode The executed bytecode. + // @param bytecode_len The length of bytecode. + // @param calldata byte The space where the data parameter of a transaction or call is held. + // @param calldata_len The length of calldata. + // @param value The amount of native token to transfer. + // @param parent The parent context of the current execution context, can be empty. + // @param address The address of the current EVM account. Note that the bytecode may not be the one + // of the account in case of a CALLCODE or DELEGATECALL + // @param code_address The EVM address the bytecode of the message is taken from. + // @param read_only if set to true, context cannot do any state modifying instructions or send ETH in the sub context. + // @param is_create if set to true, the call context is a CREATEs or deploy execution + // @param depth The depth of the current execution context. + struct Message { + bytecode: felt*, + bytecode_len: felt, + valid_jumpdests_start: DictAccess*, + valid_jumpdests: DictAccess*, + calldata: felt*, + calldata_len: felt, + value: Uint256*, + caller: felt, + parent: Parent*, + address: Address*, + code_address: Address*, + read_only: felt, + is_create: felt, + depth: felt, + env: Environment*, + cairo_precompile_called: felt, + } + + // @dev Stores all data relevant to the current execution context. + // @param message The call context data. + // @param return_data_len The return_data length. + // @param return_data The region used to return a value after a call. + // @param program_counter The keep track of the current position in the program as it is being executed. + // @param stopped A boolean that state if the current execution is halted. + // @param gas_left The gas consumed by the current state of the execution. + // @param reverted A code indicating whether the EVM is reverted or not. + // can be either 0 - not reverted, Errors.REVERTED or Errors.EXCEPTIONAL_HALT + struct EVM { + message: Message*, + return_data_len: felt, + return_data: felt*, + program_counter: felt, + stopped: felt, + gas_left: felt, + gas_refund: felt, + reverted: felt, + } + + // @notice Store all environment data relevant to the current execution context. + // @param origin The origin of the transaction. + // @param gas_price The gas price for the call. + // @param chain_id The chain id of the current block. + // @param prev_randao The previous RANDAO value. + // @param block_number The block number of the current block. + // @param block_gas_limit The gas limit for the current block. + // @param block_timestamp The timestamp of the current block. + // @param coinbase The address of the miner of the current block. + // @param base_fee The basefee of the current block. + struct Environment { + origin: felt, + gas_price: felt, + chain_id: felt, + prev_randao: Uint256, + block_number: felt, + block_gas_limit: felt, + block_timestamp: felt, + coinbase: felt, + base_fee: felt, + } + + // @dev The parent EVM struct is used to store the parent EVM context of the current execution context. + struct Parent { + evm: EVM*, + stack: Stack*, + memory: Memory*, + state: State*, + } + + // @dev Stores the constant data of an opcode + // @param number The opcode number + // @param gas The minimum gas used by the opcode (not including possible dynamic gas) + // @param stack_input The number of inputs popped from the stack. + // @param stack_size_min The minimal size of the Stack for this opcode. + // @param stack_size_diff The difference between the stack size after and before + struct Opcode { + number: felt, + gas: felt, + stack_input: felt, + stack_size_min: felt, + stack_size_diff: felt, + } + + // @notice A normalized Ethereum transaction + // @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md + struct EthTransaction { + signer_nonce: felt, + gas_limit: felt, + max_priority_fee_per_gas: felt, + max_fee_per_gas: felt, + destination: Option, + amount: Uint256, + payload_len: felt, + payload: felt*, + access_list_len: felt, + access_list: felt*, + chain_id: Option, + } +} diff --git a/cairo/src/precompiles/blake2f.cairo b/cairo/src/precompiles/blake2f.cairo new file mode 100644 index 00000000..2c9e624d --- /dev/null +++ b/cairo/src/precompiles/blake2f.cairo @@ -0,0 +1,521 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.registers import get_fp_and_pc, get_label_location +from starkware.cairo.common.math_cmp import is_nn +from starkware.cairo.common.bool import FALSE + +from src.errors import Errors +from src.utils.utils import Helpers +from src.utils.maths import unsigned_div_rem + +// @title Blake2f Precompile related functions. +// @notice This file contains the logic required to run the blake2f precompile +// @author @greged93 +// @custom:namespace PrecompileBlake2f +namespace PrecompileBlake2f { + const PRECOMPILE_ADDRESS = 0x09; + const GAS_COST_BLAKE2F = 0; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + local rounds_bytes_len = 4; + local word_bytes_len = 8; + local h_bytes_offset = 4; + local m_bytes_offset = 68; + local t_bytes_offset = 196; + local f_bytes_offset = 212; + + // Check input length + if (input_len != 213) { + let (revert_reason_len, revert_reason) = Errors.precompileInputError(); + return (revert_reason_len, revert_reason, 0, Errors.EXCEPTIONAL_HALT); + } + + // Check the flag + tempvar f = input[f_bytes_offset]; + if (f != f * f) { + let (revert_reason_len, revert_reason) = Errors.precompileFlagError(); + return (revert_reason_len, revert_reason, 0, Errors.EXCEPTIONAL_HALT); + } + + let rounds = Helpers.bytes_to_felt(rounds_bytes_len, input); + + let (local h: felt*) = alloc(); + Helpers.load_64_bits_array(8, input + h_bytes_offset, h); + + let (m: felt*) = alloc(); + Helpers.load_64_bits_array(16, input + m_bytes_offset, m); + + let t0 = Helpers.bytes_to_64_bits_little_felt(input + t_bytes_offset); + let t1 = Helpers.bytes_to_64_bits_little_felt(input + t_bytes_offset + 8); + + // Perform Blake2f compression + let (compressed) = Blake2.F(rounds, h, m, t0, t1, f); + + let (output: felt*) = alloc(); + Helpers.split_word_little(compressed[0], word_bytes_len, output); + Helpers.split_word_little(compressed[1], word_bytes_len, output + word_bytes_len); + Helpers.split_word_little(compressed[2], word_bytes_len, output + 2 * word_bytes_len); + Helpers.split_word_little(compressed[3], word_bytes_len, output + 3 * word_bytes_len); + Helpers.split_word_little(compressed[4], word_bytes_len, output + 4 * word_bytes_len); + Helpers.split_word_little(compressed[5], word_bytes_len, output + 5 * word_bytes_len); + Helpers.split_word_little(compressed[6], word_bytes_len, output + 6 * word_bytes_len); + Helpers.split_word_little(compressed[7], word_bytes_len, output + 7 * word_bytes_len); + + return (word_bytes_len * 8, output, rounds, 0); + } +} + +namespace Blake2 { + const MASK_ONES_64 = 2 ** 64; + + // @notice Perform the blake2b compression function. + // @param rounds The number of rounds for the compression function. + // @param h The internal state of the hash. + // @param m The sixteen words of a single message. + // @param t The message byte offset. + // @param f The flag indicating the last block. + // @return output The final state of the compression. + func F{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + rounds: felt, h: felt*, m: felt*, t0: felt, t1: felt, f: felt + ) -> (output: felt*) { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + + let (local output) = alloc(); + let (sigma_address) = get_label_location(data); + local sigma: felt* = cast(sigma_address, felt*); + + // Compute state[12]. + assert bitwise_ptr[0].x = 0x510e527fade682d1; + assert bitwise_ptr[0].y = t0; + let state12 = bitwise_ptr[0].x_xor_y; + let bitwise_ptr = bitwise_ptr + BitwiseBuiltin.SIZE; + + // Compute state[13]. + assert bitwise_ptr[0].x = 0x9b05688c2b3e6c1f; + assert bitwise_ptr[0].y = t1; + let state13 = bitwise_ptr[0].x_xor_y; + let bitwise_ptr = bitwise_ptr + BitwiseBuiltin.SIZE; + + // Compute state[14]. + local state14; + if (f == FALSE) { + // 0x1f83d9abfb41bd6b ^ 0xffffffffffffffff + state14 = 0x1f83d9abfb41bd6b; + } else { + state14 = 0xe07c265404be4294; + } + + let (local initial_state: felt*) = alloc(); + assert initial_state[0] = h[0]; + assert initial_state[1] = h[1]; + assert initial_state[2] = h[2]; + assert initial_state[3] = h[3]; + assert initial_state[4] = h[4]; + assert initial_state[5] = h[5]; + assert initial_state[6] = h[6]; + assert initial_state[7] = h[7]; + assert initial_state[8] = 0x6a09e667f3bcc908; + assert initial_state[9] = 0xbb67ae8584caa73b; + assert initial_state[10] = 0x3c6ef372fe94f82b; + assert initial_state[11] = 0xa54ff53a5f1d36f1; + assert initial_state[12] = state12; + assert initial_state[13] = state13; + assert initial_state[14] = state14; + assert initial_state[15] = 0x5be0cd19137e2179; + + let (state) = blake_rounds(rounds, 0, initial_state, m, sigma); + + tempvar old_h = h; + tempvar last_state = state; + tempvar new_h = output; + tempvar bitwise_ptr = bitwise_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar pedersen_ptr = pedersen_ptr; + tempvar n = 8; + + loop: + assert bitwise_ptr[0].x = old_h[0]; + assert bitwise_ptr[0].y = last_state[0]; + assert bitwise_ptr[1].x = bitwise_ptr[0].x_xor_y; + assert bitwise_ptr[1].y = last_state[8]; + assert new_h[0] = bitwise_ptr[1].x_xor_y; + tempvar old_h = old_h + 1; + tempvar last_state = last_state + 1; + tempvar new_h = new_h + 1; + tempvar bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + tempvar range_check_ptr = range_check_ptr; + tempvar pedersen_ptr = pedersen_ptr; + tempvar n = n - 1; + jmp loop if n != 0; + + return (output=output); + + // Sigma + data: + dw 0; + dw 2; + dw 4; + dw 6; + dw 1; + dw 3; + dw 5; + dw 7; + dw 8; + dw 10; + dw 12; + dw 14; + dw 9; + dw 11; + dw 13; + dw 15; + dw 14; + dw 4; + dw 9; + dw 13; + dw 10; + dw 8; + dw 15; + dw 6; + dw 1; + dw 0; + dw 11; + dw 5; + dw 12; + dw 2; + dw 7; + dw 3; + dw 11; + dw 12; + dw 5; + dw 15; + dw 8; + dw 0; + dw 2; + dw 13; + dw 10; + dw 3; + dw 7; + dw 9; + dw 14; + dw 6; + dw 1; + dw 4; + dw 7; + dw 3; + dw 13; + dw 11; + dw 9; + dw 1; + dw 12; + dw 14; + dw 2; + dw 5; + dw 4; + dw 15; + dw 6; + dw 10; + dw 0; + dw 8; + dw 9; + dw 5; + dw 2; + dw 10; + dw 0; + dw 7; + dw 4; + dw 15; + dw 14; + dw 11; + dw 6; + dw 3; + dw 1; + dw 12; + dw 8; + dw 13; + dw 2; + dw 6; + dw 0; + dw 8; + dw 12; + dw 10; + dw 11; + dw 3; + dw 4; + dw 7; + dw 15; + dw 1; + dw 13; + dw 5; + dw 14; + dw 9; + dw 12; + dw 1; + dw 14; + dw 4; + dw 5; + dw 15; + dw 13; + dw 10; + dw 0; + dw 6; + dw 9; + dw 8; + dw 7; + dw 3; + dw 2; + dw 11; + dw 13; + dw 7; + dw 12; + dw 3; + dw 11; + dw 14; + dw 1; + dw 9; + dw 5; + dw 15; + dw 8; + dw 2; + dw 0; + dw 4; + dw 6; + dw 10; + dw 6; + dw 14; + dw 11; + dw 0; + dw 15; + dw 9; + dw 3; + dw 8; + dw 12; + dw 13; + dw 1; + dw 10; + dw 2; + dw 7; + dw 4; + dw 5; + dw 10; + dw 8; + dw 7; + dw 1; + dw 2; + dw 4; + dw 6; + dw 5; + dw 15; + dw 9; + dw 3; + dw 13; + dw 11; + dw 14; + dw 12; + dw 0; + } + + // @notice Perform all blake2b compression function rounds. + // @param rounds The number of rounds for the compression function. + // @param i The current round. + // @param h The internal state of the hash. + // @param m The sixteen words of a single message. + // @param sigma The message schedule. + // @return final_h The final hash. + func blake_rounds{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + rounds: felt, i: felt, h: felt*, m: felt*, sigma: felt* + ) -> (final_h: felt*) { + if (rounds == 0) { + return (final_h=h); + } + let (_, r) = unsigned_div_rem(i, 10); + let (h_new) = blake_round(h, m, sigma + r * 16); + + return blake_rounds(rounds - 1, i + 1, h_new, m, sigma); + } + + // @notice Perform a single round of the blake2b compression function. + // @param state The internal state of the hash. + // @param message The sixteen words of a single message. + // @param sigma The message schedule. + // @return new_state The new state of the compression function. + func blake_round{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + state: felt*, message: felt*, sigma: felt* + ) -> (new_state: felt*) { + alloc_locals; + + let (state0, state4, state8, state12) = mix_one( + state[0], state[4], state[8], state[12], message[sigma[0]] + ); + let (state1, state5, state9, state13) = mix_one( + state[1], state[5], state[9], state[13], message[sigma[1]] + ); + let (state2, state6, state10, state14) = mix_one( + state[2], state[6], state[10], state[14], message[sigma[2]] + ); + let (state3, state7, state11, state15) = mix_one( + state[3], state[7], state[11], state[15], message[sigma[3]] + ); + + let (state0, state4, state8, state12) = mix_two( + state0, state4, state8, state12, message[sigma[4]] + ); + let (state1, state5, state9, state13) = mix_two( + state1, state5, state9, state13, message[sigma[5]] + ); + let (state2, state6, state10, state14) = mix_two( + state2, state6, state10, state14, message[sigma[6]] + ); + let (state3, state7, state11, state15) = mix_two( + state3, state7, state11, state15, message[sigma[7]] + ); + + let (state0, state5, state10, state15) = mix_one( + state0, state5, state10, state15, message[sigma[8]] + ); + let (state1, state6, state11, state12) = mix_one( + state1, state6, state11, state12, message[sigma[9]] + ); + let (state2, state7, state8, state13) = mix_one( + state2, state7, state8, state13, message[sigma[10]] + ); + let (state3, state4, state9, state14) = mix_one( + state3, state4, state9, state14, message[sigma[11]] + ); + + let (state0, state5, state10, state15) = mix_two( + state0, state5, state10, state15, message[sigma[12]] + ); + let (state1, state6, state11, state12) = mix_two( + state1, state6, state11, state12, message[sigma[13]] + ); + let (state2, state7, state8, state13) = mix_two( + state2, state7, state8, state13, message[sigma[14]] + ); + let (state3, state4, state9, state14) = mix_two( + state3, state4, state9, state14, message[sigma[15]] + ); + + let (new_state: felt*) = alloc(); + assert new_state[0] = state0; + assert new_state[1] = state1; + assert new_state[2] = state2; + assert new_state[3] = state3; + assert new_state[4] = state4; + assert new_state[5] = state5; + assert new_state[6] = state6; + assert new_state[7] = state7; + assert new_state[8] = state8; + assert new_state[9] = state9; + assert new_state[10] = state10; + assert new_state[11] = state11; + assert new_state[12] = state12; + assert new_state[13] = state13; + assert new_state[14] = state14; + assert new_state[15] = state15; + + return (new_state=new_state); + } + + // @notice Perform a mixing of inputs. + // @param a The first state word. + // @param b The second state word. + // @param c The third state word. + // @param d The fourth state word. + // @param m The message word used in mixing. + // @return a The new first state word. + // @return b The new second state word. + // @return c The new third state word. + // @return d The new fourth state word. + func mix_one{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + a: felt, b: felt, c: felt, d: felt, m: felt + ) -> (a: felt, b: felt, c: felt, d: felt) { + alloc_locals; + + // a = (a + b + m) % 2**64 + let (_, a) = unsigned_div_rem(a + b + m, MASK_ONES_64); + + // d = right_rot((d ^ a), 32). + assert bitwise_ptr[0].x = a; + assert bitwise_ptr[0].y = d; + tempvar a_xor_d = bitwise_ptr[0].x_xor_y; + assert bitwise_ptr[1].x = a_xor_d; + assert bitwise_ptr[1].y = (2 ** 64 - 2 ** 32); + tempvar d = ( + (2 ** (64 - 32)) * a_xor_d + (1 / 2 ** 32 - 2 ** (64 - 32)) * bitwise_ptr[1].x_and_y + ); + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + // c = (c + d) % 2**64 + let (_, c) = unsigned_div_rem(c + d, MASK_ONES_64); + + // b = right_rot((b ^ c), 24). + assert bitwise_ptr[0].x = b; + assert bitwise_ptr[0].y = c; + tempvar b_xor_c = bitwise_ptr[0].x_xor_y; + assert bitwise_ptr[1].x = b_xor_c; + assert bitwise_ptr[1].y = (2 ** 64 - 2 ** 24); + tempvar b = ( + (2 ** (64 - 24)) * b_xor_c + (1 / 2 ** 24 - 2 ** (64 - 24)) * bitwise_ptr[1].x_and_y + ); + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + return (a, b, c, d); + } + + // @notice Perform a mixing of inputs. + // @param a The first state word. + // @param b The second state word. + // @param c The third state word. + // @param d The fourth state word. + // @param m The message word used in mixing. + // @return a The new first state word. + // @return b The new second state word. + // @return c The new third state word. + // @return d The new fourth state word. + func mix_two{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + a: felt, b: felt, c: felt, d: felt, m: felt + ) -> (a: felt, b: felt, c: felt, d: felt) { + alloc_locals; + + // a = (a + b + m) % 2**64 + let (_, a) = unsigned_div_rem(a + b + m, MASK_ONES_64); + + // d = right_rot((d ^ a), 16). + assert bitwise_ptr[0].x = d; + assert bitwise_ptr[0].y = a; + tempvar d_xor_a = bitwise_ptr[0].x_xor_y; + assert bitwise_ptr[1].x = d_xor_a; + assert bitwise_ptr[1].y = (2 ** 64 - 2 ** 16); + tempvar d = (2 ** (64 - 16)) * d_xor_a + (1 / 2 ** 16 - 2 ** (64 - 16)) * bitwise_ptr[ + 1 + ].x_and_y; + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + // c = (c + d) % 2**64 + let (_, c) = unsigned_div_rem(c + d, MASK_ONES_64); + + // b = right_rot((b ^ c), 63). + assert bitwise_ptr[0].x = b; + assert bitwise_ptr[0].y = c; + tempvar b_xor_c = bitwise_ptr[0].x_xor_y; + assert bitwise_ptr[1].x = b_xor_c; + assert bitwise_ptr[1].y = (2 ** 64 - 2 ** 63); + tempvar b = (2 ** (64 - 63)) * b_xor_c + (1 / 2 ** 63 - 2 ** (64 - 63)) * bitwise_ptr[ + 1 + ].x_and_y; + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + return (a, b, c, d); + } +} diff --git a/cairo/src/precompiles/datacopy.cairo b/cairo/src/precompiles/datacopy.cairo new file mode 100644 index 00000000..220f6df6 --- /dev/null +++ b/cairo/src/precompiles/datacopy.cairo @@ -0,0 +1,28 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin + +from src.model import model +from src.utils.utils import Helpers +from src.memory import Memory +from src.evm import EVM + +// @title DataCopy precompile +// @custom:precompile +// @custom:address 0x04 +// @notice This precompile serves as a cheaper way to copy data in memory +namespace PrecompileDataCopy { + const PRECOMPILE_ADDRESS = 0x04; + const GAS_COST_DATACOPY = 15; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + let (minimum_word_size) = Helpers.minimum_word_count(input_len); + return (input_len, input, 3 * minimum_word_size + GAS_COST_DATACOPY, 0); + } +} diff --git a/cairo/src/precompiles/ec_recover.cairo b/cairo/src/precompiles/ec_recover.cairo new file mode 100644 index 00000000..59cf1e84 --- /dev/null +++ b/cairo/src/precompiles/ec_recover.cairo @@ -0,0 +1,102 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.builtin_keccak.keccak import keccak_uint256s_bigend +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.math_cmp import RC_BOUND +from starkware.cairo.common.cairo_secp.ec import EcPoint +from starkware.cairo.common.cairo_secp.bigint import BigInt3 +from starkware.cairo.common.cairo_secp.signature import ( + recover_public_key, + public_key_point_to_eth_address, +) +from starkware.cairo.common.uint256 import Uint256, uint256_reverse_endian +from starkware.cairo.common.cairo_secp.bigint import bigint_to_uint256 +from starkware.cairo.common.memset import memset + +from src.errors import Errors +from src.interfaces.interfaces import ICairo1Helpers +from src.utils.utils import Helpers +from src.utils.array import slice +from src.utils.maths import unsigned_div_rem + +// @title EcRecover Precompile related functions. +// @notice This file contains the logic required to run the ec_recover precompile +// using Starkware's cairo_secp library +// @author @clementwalter +// @custom:namespace PrecompileEcRecover +namespace PrecompileEcRecover { + const PRECOMPILE_ADDRESS = 0x01; + const GAS_COST_EC_RECOVER = 3000; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + + let (input_padded) = alloc(); + slice(input_padded, input_len, input, 0, 4 * 32); + + let v_uint256 = Helpers.bytes32_to_uint256(input_padded + 32); + let v = Helpers.uint256_to_felt(v_uint256); + + if ((v - 27) * (v - 28) != 0) { + let (output) = alloc(); + return (0, output, GAS_COST_EC_RECOVER, 0); + } + + let msg_hash = Helpers.bytes_to_uint256(32, input_padded); + let r = Helpers.bytes_to_uint256(32, input_padded + 32 * 2); + let s = Helpers.bytes_to_uint256(32, input_padded + 32 * 3); + + // v - 27, see recover_public_key comment + let (success, recovered_address) = ICairo1Helpers.recover_eth_address( + msg_hash=msg_hash, r=r, s=s, y_parity=v - 27 + ); + + if (success == 0) { + let (output) = alloc(); + return (0, output, GAS_COST_EC_RECOVER, 0); + } + + let (output) = alloc(); + memset(output, 0, 12); + Helpers.split_word(recovered_address, 20, output + 12); + + return (32, output, GAS_COST_EC_RECOVER, 0); + } +} + +namespace EcRecoverHelpers { + func ec_point_equal(point_0: EcPoint, point_1: EcPoint) -> (is_equal: felt) { + if (point_0.x.d0 == point_1.x.d0 and point_0.y.d0 == point_1.y.d0 and + point_0.x.d1 == point_1.x.d1 and point_0.y.d1 == point_1.y.d1 and + point_0.x.d2 == point_1.x.d2 and point_0.y.d2 == point_1.y.d2) { + return (is_equal=1); + } + return (is_equal=0); + } + + // @notice Convert a public key point to the corresponding Ethereum address. + func public_key_point_to_eth_address{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(public_key_point: EcPoint) -> (eth_address: felt) { + alloc_locals; + let (local elements: Uint256*) = alloc(); + let (x_uint256: Uint256) = bigint_to_uint256(public_key_point.x); + assert elements[0] = x_uint256; + let (y_uint256: Uint256) = bigint_to_uint256(public_key_point.y); + assert elements[1] = y_uint256; + + let (point_hash) = keccak_uint256s_bigend(n_elements=2, elements=elements); + + // The Ethereum address is the 20 least significant bytes of the keccak of the public key. + let (high_high, high_low) = unsigned_div_rem(point_hash.high, 2 ** 32); + return (eth_address=point_hash.low + RC_BOUND * high_low); + } +} diff --git a/cairo/src/precompiles/ecadd.cairo b/cairo/src/precompiles/ecadd.cairo new file mode 100644 index 00000000..a436d678 --- /dev/null +++ b/cairo/src/precompiles/ecadd.cairo @@ -0,0 +1,47 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.cairo_secp.bigint import BigInt3 +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.memcpy import memcpy + +from src.utils.alt_bn128.alt_bn128_g1 import G1Point, ALT_BN128 +from src.utils.utils import Helpers + +// @title EcAdd Precompile related functions. +// @notice This file contains the logic required to run the ec_add precompile +// using alt_bn128 library +// @author @pedrobergamini +// @custom:namespace PrecompileEcAdd +namespace PrecompileEcAdd { + const PRECOMPILE_ADDRESS = 0x06; + const GAS_COST_EC_ADD = 150; + const G1POINT_BYTES_LEN = 32; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + + let x0: BigInt3 = Helpers.bytes32_to_bigint(input); + let y0: BigInt3 = Helpers.bytes32_to_bigint(input + G1POINT_BYTES_LEN); + let x1: BigInt3 = Helpers.bytes32_to_bigint(input + G1POINT_BYTES_LEN * 2); + let y1: BigInt3 = Helpers.bytes32_to_bigint(input + G1POINT_BYTES_LEN * 3); + + with_attr error_message("Kakarot: ec_add failed") { + let point0: G1Point = G1Point(x0, y0); + let point1: G1Point = G1Point(x1, y1); + let result: G1Point = ALT_BN128.ec_add(point0, point1); + } + + let (bytes_x_len, output: felt*) = Helpers.bigint_to_bytes_array(result.x); + let (bytes_y_len, bytes_y: felt*) = Helpers.bigint_to_bytes_array(result.y); + memcpy(output + bytes_x_len, bytes_y, bytes_y_len); + + return (G1POINT_BYTES_LEN * 2, output, GAS_COST_EC_ADD, 0); + } +} diff --git a/cairo/src/precompiles/ecmul.cairo b/cairo/src/precompiles/ecmul.cairo new file mode 100644 index 00000000..3b89b678 --- /dev/null +++ b/cairo/src/precompiles/ecmul.cairo @@ -0,0 +1,44 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.cairo_secp.bigint import BigInt3 +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.memcpy import memcpy + +from src.utils.alt_bn128.alt_bn128_g1 import G1Point, ALT_BN128 +from src.utils.utils import Helpers + +// @title EcMul Precompile related functions. +// @notice This file contains the logic required to run the ec_mul precompile +// using alt_bn128 library +// @author @pedrobergamini +// @custom:namespace PrecompileEcMul +namespace PrecompileEcMul { + const PRECOMPILE_ADDRESS = 0x07; + const GAS_COST_EC_MUL = 6000; + const G1POINT_BYTES_LEN = 32; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + + let x: BigInt3 = Helpers.bytes32_to_bigint(input); + let y: BigInt3 = Helpers.bytes32_to_bigint(input + G1POINT_BYTES_LEN); + let scalar: BigInt3 = Helpers.bytes32_to_bigint(input + G1POINT_BYTES_LEN * 2); + + with_attr error_message("Kakarot: ec_mul failed") { + let result: G1Point = ALT_BN128.ec_mul(G1Point(x, y), scalar); + } + + let (bytes_x_len, output: felt*) = Helpers.bigint_to_bytes_array(result.x); + let (bytes_y_len, bytes_y: felt*) = Helpers.bigint_to_bytes_array(result.y); + memcpy(output + bytes_x_len, bytes_y, bytes_y_len); + + return (G1POINT_BYTES_LEN * 2, output, GAS_COST_EC_MUL, 0); + } +} diff --git a/cairo/src/precompiles/kakarot_precompiles.cairo b/cairo/src/precompiles/kakarot_precompiles.cairo new file mode 100644 index 00000000..644c92eb --- /dev/null +++ b/cairo/src/precompiles/kakarot_precompiles.cairo @@ -0,0 +1,64 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math_cmp import is_nn +from starkware.cairo.common.math import assert_not_zero +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE, TRUE + +from src.errors import Errors +from src.account import Account +from src.utils.utils import Helpers + +const CALL_CONTRACT_SOLIDITY_SELECTOR = 0xb3eb2c1b; + +// TODO: compute acceptable EVM gas values for Cairo execution +const CAIRO_PRECOMPILE_GAS = 10000; +const CAIRO_MESSAGE_GAS = 5000; + +namespace KakarotPrecompiles { + // @notice Executes a cairo contract/class. + // @param input_len The length of the input in bytes. + // @param input The input data. + // @param caller_address The address of the caller of the precompile. Delegatecall rules apply. + func cairo_precompile{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(input_len: felt, input: felt*, caller_address: felt) -> ( + output_len: felt, output: felt*, gas_used: felt, reverted: felt + ) { + alloc_locals; + + // Input must be at least 4 + 3*32 bytes long. + let is_input_invalid = is_nn(99 - input_len); + if (is_input_invalid != 0) { + let (revert_reason_len, revert_reason) = Errors.outOfBoundsRead(); + return (revert_reason_len, revert_reason, CAIRO_PRECOMPILE_GAS, TRUE); + } + + // Input is formatted as: + // [selector: bytes4][starknet_address: bytes32][starknet_selector:bytes32][data_offset: bytes32][data_len: bytes32][data: bytes[]] + + // Load selector from first 4 bytes of input. + let selector = Helpers.bytes4_to_felt(input); + let args_ptr = input + 4; + + // Load address and cairo selector called + // Safe to assume that the 32 bytes in input do not overflow a felt (whitelisted precompiles) + let to_starknet_address = Helpers.bytes32_to_felt(args_ptr); + + let starknet_selector_ptr = args_ptr + 32; + let starknet_selector = Helpers.bytes32_to_felt(starknet_selector_ptr); + + let data_offset_ptr = args_ptr + 64; + let data_offset = Helpers.bytes32_to_felt(data_offset_ptr); + let data_len_ptr = args_ptr + data_offset; + + // Load input data by packing all + // If the input data is larger than the size of a felt, it will wrap around the felt size. + let data_words_len = Helpers.bytes32_to_felt(data_len_ptr); + let data_bytes_len = data_words_len * 32; + let data_ptr = data_len_ptr + 32; + let (data_len, data) = Helpers.load_256_bits_array(data_bytes_len, data_ptr); + + let (revert_reason_len, revert_reason) = Errors.invalidCairoSelector(); + return (revert_reason_len, revert_reason, CAIRO_PRECOMPILE_GAS, TRUE); + } +} diff --git a/cairo/src/precompiles/modexp.cairo b/cairo/src/precompiles/modexp.cairo new file mode 100644 index 00000000..a794a5b6 --- /dev/null +++ b/cairo/src/precompiles/modexp.cairo @@ -0,0 +1,50 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.alloc import alloc + +from src.utils.utils import Helpers +from src.utils.modexp.modexp_utils import ModExpHelpersUint256 +from src.utils.bytes import uint256_to_bytes + +// @title ModExpUint256 MVP Precompile related functions. +// @notice It is an MVP implementation since it only supports uint256 numbers with m_size<=16 and not bigint which requires bigint library in cairo 0.10. +// @author @dragan2234 +// @custom:namespace PrecompileModExpUint256 +namespace PrecompileModExpUint256 { + const PRECOMPILE_ADDRESS = 0x05; + const MOD_EXP_BYTES_LEN = 32; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + + let b_size: Uint256 = Helpers.bytes32_to_uint256(input); + let e_size: Uint256 = Helpers.bytes32_to_uint256(input + MOD_EXP_BYTES_LEN); + let m_size: Uint256 = Helpers.bytes32_to_uint256(input + MOD_EXP_BYTES_LEN * 2); + let b: Uint256 = Helpers.bytes_to_uint256(b_size.low, input + MOD_EXP_BYTES_LEN * 3); + let e: Uint256 = Helpers.bytes_to_uint256( + e_size.low, input + MOD_EXP_BYTES_LEN * 3 + b_size.low + ); + let m: Uint256 = Helpers.bytes_to_uint256( + m_size.low, input + MOD_EXP_BYTES_LEN * 3 + b_size.low + e_size.low + ); + with_attr error_message("Kakarot: modexp failed") { + let (result) = ModExpHelpersUint256.uint256_mod_exp(b, e, m); + } + let bytes: felt* = alloc(); + let bytes_len = uint256_to_bytes(bytes, result); + + let (gas_cost) = ModExpHelpersUint256.calculate_mod_exp_gas( + b_size, m_size, e_size, b, e, m + ); + + return (bytes_len, bytes, gas_cost, 0); + } +} diff --git a/cairo/src/precompiles/p256verify.cairo b/cairo/src/precompiles/p256verify.cairo new file mode 100644 index 00000000..0eb4b84e --- /dev/null +++ b/cairo/src/precompiles/p256verify.cairo @@ -0,0 +1,51 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.memset import memset + +from src.utils.utils import Helpers +from src.interfaces.interfaces import ICairo1Helpers + +// @title P256Verify precompile related functions. +// @notice This file contains the logic required to run the ec_recover precompile +// using Starkware's cairo_secp library +// @author @clementwalter +// @custom:namespace PrecompileEcRecover +namespace PrecompileP256Verify { + const PRECOMPILE_ADDRESS = 0x100; + const GAS_COST_P256_VERIFY = 3450; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + + let (output) = alloc(); + if (input_len != 160) { + return (0, output, GAS_COST_P256_VERIFY, 0); + } + + let msg_hash = Helpers.bytes32_to_uint256(input); + let r = Helpers.bytes32_to_uint256(input + 32); + let s = Helpers.bytes32_to_uint256(input + 64); + let x = Helpers.bytes32_to_uint256(input + 96); + let y = Helpers.bytes32_to_uint256(input + 128); + + let (is_valid) = ICairo1Helpers.verify_signature_secp256r1( + msg_hash=msg_hash, r=r, s=s, x=x, y=y + ); + + if (is_valid == 0) { + return (0, output, GAS_COST_P256_VERIFY, 0); + } + + memset(output, 0, 31); + assert output[31] = 1; + return (32, output, GAS_COST_P256_VERIFY, 0); + } +} diff --git a/cairo/src/precompiles/precompiles.cairo b/cairo/src/precompiles/precompiles.cairo new file mode 100644 index 00000000..afd525a4 --- /dev/null +++ b/cairo/src/precompiles/precompiles.cairo @@ -0,0 +1,196 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math_cmp import is_nn, is_not_zero, is_in_range +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.memcpy import memcpy + +from src.interfaces.interfaces import ICairo1Helpers +from src.errors import Errors +from src.precompiles.blake2f import PrecompileBlake2f +from src.precompiles.kakarot_precompiles import KakarotPrecompiles +from src.precompiles.datacopy import PrecompileDataCopy +from src.precompiles.ec_recover import PrecompileEcRecover +from src.precompiles.p256verify import PrecompileP256Verify +from src.precompiles.ripemd160 import PrecompileRIPEMD160 +from src.precompiles.sha256 import PrecompileSHA256 +from src.precompiles.precompiles_helpers import ( + PrecompilesHelpers, + LAST_ETHEREUM_PRECOMPILE_ADDRESS, + FIRST_ROLLUP_PRECOMPILE_ADDRESS, + FIRST_KAKAROT_PRECOMPILE_ADDRESS, +) +from src.utils.utils import Helpers + +// @title Precompile related functions. +namespace Precompiles { + // @notice Executes associated function of precompiled evm_address. + // @dev This function uses an internal jump table to execute the corresponding precompile impmentation. + // @param precompile_address The precompile evm_address. + // @param input_len The length of the input array. + // @param input The input array. + // @param caller_code_address The address of the code of the contract that calls the precompile. + // @param caller_address The address of the caller of the precompile. Delegatecall rules apply. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + // @return reverted Whether the precompile ran successfully or not + func exec_precompile{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + precompile_address: felt, + input_len: felt, + input: felt*, + caller_code_address: felt, + caller_address: felt, + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + let is_eth_precompile = is_nn(LAST_ETHEREUM_PRECOMPILE_ADDRESS - precompile_address); + tempvar pedersen_ptr = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + jmp eth_precompile if is_eth_precompile != 0; + + let is_rollup_precompile_ = PrecompilesHelpers.is_rollup_precompile(precompile_address); + tempvar pedersen_ptr = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + jmp rollup_precompile if is_rollup_precompile_ != 0; + + let is_kakarot_precompile_ = PrecompilesHelpers.is_kakarot_precompile(precompile_address); + tempvar pedersen_ptr = pedersen_ptr; + tempvar range_check_ptr = range_check_ptr; + jmp kakarot_precompile if is_kakarot_precompile_ != 0; + jmp unauthorized_call; + + eth_precompile: + tempvar index = precompile_address; + jmp call_precompile; + + rollup_precompile: + tempvar index = (LAST_ETHEREUM_PRECOMPILE_ADDRESS + 1) + ( + precompile_address - FIRST_ROLLUP_PRECOMPILE_ADDRESS + ); + jmp call_precompile; + + unauthorized_call: + // Prepare arguments if none of the above conditions are met + [ap] = pedersen_ptr, ap++; + [ap] = range_check_ptr, ap++; + [ap] = bitwise_ptr, ap++; + call unauthorized_precompile; + ret; + + call_precompile: + // Compute the corresponding offset in the jump table: + // count 1 for "next line" and 3 steps per index: call, precompile, ret + tempvar offset = 1 + 3 * index; + + // Prepare arguments + [ap] = pedersen_ptr, ap++; + [ap] = range_check_ptr, ap++; + [ap] = bitwise_ptr, ap++; + [ap] = precompile_address, ap++; + [ap] = input_len, ap++; + [ap] = input, ap++; + + // call precompile precompile_address + jmp rel offset; + call unknown_precompile; // 0x0 + ret; + call PrecompileEcRecover.run; // 0x1 + ret; + call external_precompile; // 0x2 + ret; + call PrecompileRIPEMD160.run; // 0x3 + ret; + call PrecompileDataCopy.run; // 0x4 + ret; + call external_precompile; // 0x5 + ret; + call not_implemented_precompile; // 0x6 + ret; + call not_implemented_precompile; // 0x7 + ret; + call not_implemented_precompile; // 0x8 + ret; + call PrecompileBlake2f.run; // 0x9 + ret; + call not_implemented_precompile; // 0x0a: POINT_EVALUATION_PRECOMPILE + ret; + // Rollup precompiles. Offset must have been computed appropriately, + // based on the address of the precompile and the last ethereum precompile + call PrecompileP256Verify.run; // offset 0x0b: precompile 0x100 + ret; + + kakarot_precompile: + tempvar index = precompile_address - FIRST_KAKAROT_PRECOMPILE_ADDRESS; + tempvar offset = 1 + 3 * index; + + // Prepare arguments + [ap] = pedersen_ptr, ap++; + [ap] = range_check_ptr, ap++; + [ap] = bitwise_ptr, ap++; + [ap] = input_len, ap++; + [ap] = input, ap++; + [ap] = caller_address, ap++; + + // Kakarot precompiles. Offset must have been computed appropriately, + // based on the total number of kakarot precompiles + jmp rel offset; + call KakarotPrecompiles.cairo_precompile; // offset 0x0c: precompile 0x75001 + ret; + } + + // @notice A placeholder for attempts to call a precompile without permissions + // @dev Halts execution. + // @param evm_address The evm_address. + // @param input_len The length of the input array. + // @param input The input array. + func unauthorized_precompile{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }() -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + let (revert_reason_len, revert_reason) = Errors.unauthorizedPrecompile(); + return (revert_reason_len, revert_reason, 0, Errors.REVERT); + } + + // @notice A placeholder for precompile that don't exist. + // @dev Halts execution. + // @param evm_address The evm_address. + // @param input_len The length of the input array. + // @param input The input array. + func unknown_precompile{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(evm_address: felt, input_len: felt, input: felt*) -> ( + output_len: felt, output: felt*, gas_used: felt, reverted: felt + ) { + let (revert_reason_len, revert_reason) = Errors.unknownPrecompile(evm_address); + return (revert_reason_len, revert_reason, 0, Errors.EXCEPTIONAL_HALT); + } + + // @notice A placeholder for precompile that are not implemented yet. + // @dev Halts execution. + // @param evm_address The evm_address. + // @param input_len The length of the input array. + // @param input The input array. + func not_implemented_precompile{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(evm_address: felt, input_len: felt, input: felt*) -> ( + output_len: felt, output: felt*, gas_used: felt, reverted: felt + ) { + let (revert_reason_len, revert_reason) = Errors.notImplementedPrecompile(evm_address); + return (revert_reason_len, revert_reason, 0, Errors.EXCEPTIONAL_HALT); + } + + func external_precompile{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* + }(evm_address: felt, input_len: felt, input: felt*) -> ( + output_len: felt, output: felt*, gas_used: felt, reverted: felt + ) { + alloc_locals; + + let (calldata: felt*) = alloc(); + assert [calldata] = evm_address; + assert [calldata + 1] = input_len; + memcpy(calldata + 2, input, input_len); + let (success, gas, return_data_len, return_data) = ICairo1Helpers.exec_precompile( + address=evm_address, data_len=input_len, data=input + ); + + return (return_data_len, return_data, gas, 1 - success); + } +} diff --git a/cairo/src/precompiles/precompiles_helpers.cairo b/cairo/src/precompiles/precompiles_helpers.cairo new file mode 100644 index 00000000..10b5c02d --- /dev/null +++ b/cairo/src/precompiles/precompiles_helpers.cairo @@ -0,0 +1,36 @@ +from starkware.cairo.common.math_cmp import is_nn, is_not_zero, is_in_range + +const LAST_ETHEREUM_PRECOMPILE_ADDRESS = 0x0a; +const FIRST_ROLLUP_PRECOMPILE_ADDRESS = 0x100; +const LAST_ROLLUP_PRECOMPILE_ADDRESS = 0x100; +const EXEC_PRECOMPILE_SELECTOR = 0x01e3e7ac032066525c37d0791c3c0f5fbb1c17f1cb6fe00afc206faa3fbd18e1; +const FIRST_KAKAROT_PRECOMPILE_ADDRESS = 0x75001; +const LAST_KAKAROT_PRECOMPILE_ADDRESS = 0x75002; + +namespace PrecompilesHelpers { + func is_rollup_precompile{range_check_ptr}(address: felt) -> felt { + return is_in_range( + address, FIRST_ROLLUP_PRECOMPILE_ADDRESS, LAST_ROLLUP_PRECOMPILE_ADDRESS + 1 + ); + } + + func is_kakarot_precompile{range_check_ptr}(address: felt) -> felt { + return is_in_range( + address, FIRST_KAKAROT_PRECOMPILE_ADDRESS, LAST_KAKAROT_PRECOMPILE_ADDRESS + 1 + ); + } + // @notice Return whether the address is a precompile address. + // @dev Ethereum precompiles start at address 0x01. + // @dev RIP precompiles start at address FIRST_ROLLUP_PRECOMPILE_ADDRESS. + // @dev Kakarot precompiles start at address FIRST_KAKAROT_PRECOMPILE_ADDRESS. + func is_precompile{range_check_ptr}(address: felt) -> felt { + alloc_locals; + let is_rollup_precompile_ = is_rollup_precompile(address); + let is_kakarot_precompile_ = is_kakarot_precompile(address); + return is_not_zero(address) * ( + is_nn(LAST_ETHEREUM_PRECOMPILE_ADDRESS - address) + + is_rollup_precompile_ + + is_kakarot_precompile_ + ); + } +} diff --git a/cairo/src/precompiles/ripemd160.cairo b/cairo/src/precompiles/ripemd160.cairo new file mode 100644 index 00000000..7803f058 --- /dev/null +++ b/cairo/src/precompiles/ripemd160.cairo @@ -0,0 +1,965 @@ +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin, HashBuiltin +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.math import assert_nn_le +from starkware.cairo.common.math_cmp import is_nn_le, is_nn +from starkware.cairo.common.bitwise import bitwise_and, bitwise_xor, bitwise_or +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.default_dict import default_dict_new, default_dict_finalize +from starkware.cairo.common.dict import dict_read, dict_write +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.memset import memset + +from src.model import model +from src.memory import Memory +from src.evm import EVM +from src.utils.utils import Helpers +from src.utils.maths import unsigned_div_rem + +// @title RIPEMD-160 precompile +// @custom:precompile +// @custom:address 0x03 +// @notice This precompile serves to hash data with RIPEMD-160 +// @author @TurcFort07 +// @custom:namespace PrecompileRIPEMD160 +namespace PrecompileRIPEMD160 { + const PRECOMPILE_ADDRESS = 0x03; + const GAS_COST_RIPEMD160 = 600; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + let (local buf: felt*) = alloc(); + let (local arr_x: felt*) = alloc(); + + // before starting fill arr_x with 0s to align on 32 bytes (hash length is 20bytes so 12 bytes to fill) + memset(arr_x, 0, 12); + let arr_x: felt* = arr_x + 12; + + // 1. init magic constants + init(buf, 5); + + // 2. compress data + let (x) = default_dict_new(0); + let start = x; + let (res, rsize, new_msg) = compress_data{dict_ptr=x, bitwise_ptr=bitwise_ptr}( + buf, 5, input_len, input + ); + default_dict_finalize(start, x, 0); + + // 3. finish hash + let (res, _) = finish(res, rsize, new_msg, input_len, 0); + + // 4. [optional]convert words to bytes + let (hash) = default_dict_new(0); + let h0 = hash; + buf2hash{dict_ptr=hash, bitwise_ptr=bitwise_ptr}(res, 0); + dict_to_array{dict_ptr=hash}(arr_x, 20); + default_dict_finalize(h0, hash, 0); + + // 5. return bytes hash code. + let (minimum_word_size) = Helpers.minimum_word_count(input_len); + return (32, arr_x - 12, 120 * minimum_word_size + GAS_COST_RIPEMD160, 0); + } +} + +const MAX_32_BIT = 2 ** 32; +const MAX_BYTE = 2 ** 8; + +func buf2hash{range_check_ptr, dict_ptr: DictAccess*, bitwise_ptr: BitwiseBuiltin*}( + buf: felt*, index: felt +) { + alloc_locals; + if (index == 20) { + return (); + } + + let (index_4, _) = unsigned_div_rem(index, 4); + let val_4 = buf[index_4]; + let (pow2_8) = pow2(8); + let (pow2_16) = pow2(16); + let (pow2_24) = pow2(24); + let (val_1) = uint8_div(val_4, pow2_8); + let (val_2) = uint8_div(val_4, pow2_16); + let (val_3) = uint8_div(val_4, pow2_24); + let (val_4) = uint8_div(val_4, 1); + + dict_write{dict_ptr=dict_ptr}(index, val_4); + dict_write{dict_ptr=dict_ptr}(index + 1, val_1); + dict_write{dict_ptr=dict_ptr}(index + 2, val_2); + dict_write{dict_ptr=dict_ptr}(index + 3, val_3); + + buf2hash{dict_ptr=dict_ptr, bitwise_ptr=bitwise_ptr}(buf, index + 4); + return (); +} + +func parse_msg{dict_ptr: DictAccess*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + input: felt*, index: felt +) { + if (index == 16) { + return (); + } + + let (val) = BYTES_TO_WORD(input); + dict_write{dict_ptr=dict_ptr}(index, val); + parse_msg{dict_ptr=dict_ptr, bitwise_ptr=bitwise_ptr}(input=input + 4, index=index + 1); + return (); +} + +func compress_data{dict_ptr: DictAccess*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + buf: felt*, bufsize: felt, input_len: felt, input: felt* +) -> (res: felt*, rsize: felt, new_msg: felt*) { + alloc_locals; + let len_lt_63 = is_nn(63 - input_len); + if (len_lt_63 == FALSE) { + parse_msg{dict_ptr=dict_ptr}(input, 0); + let (local arr_x: felt*) = alloc(); + dict_to_array{dict_ptr=dict_ptr}(arr_x, 16); + local dict_ptr: DictAccess* = dict_ptr; + let (res, rsize) = compress(buf, bufsize, arr_x, 16); + let new_msg = input + 64; + let (res, rsize, new_msg) = compress_data{dict_ptr=dict_ptr, bitwise_ptr=bitwise_ptr}( + res, rsize, input_len - 64, new_msg + ); + return (res=res, rsize=rsize, new_msg=new_msg); + } + return (buf, bufsize, input); +} + +func absorb_data{range_check_ptr, bitwise_ptr: BitwiseBuiltin*, dict_ptr: DictAccess*}( + data: felt*, len: felt, index: felt +) { + alloc_locals; + if (index - len == 0) { + return (); + } + + let (index_4, _) = unsigned_div_rem(index, 4); + let (index_and_3) = uint32_and(index, 3); + let (factor) = uint32_mul(8, index_and_3); + let (factor) = pow2(factor); + let (tmp) = uint32_mul([data], factor); + let (old_val) = dict_read{dict_ptr=dict_ptr}(index_4); + let (val) = uint32_xor(old_val, tmp); + dict_write{dict_ptr=dict_ptr}(index_4, val); + + absorb_data{dict_ptr=dict_ptr}(data + 1, len, index + 1); + return (); +} + +func dict_to_array{dict_ptr: DictAccess*}(arr: felt*, len) { + if (len == 0) { + return (); + } + + let index = len - 1; + let (x) = dict_read{dict_ptr=dict_ptr}(index); + assert arr[index] = x; + + dict_to_array{dict_ptr=dict_ptr}(arr, len - 1); + + return (); +} + +// init buf to magic constants. +func init(buf: felt*, size: felt) { + assert size = 5; + assert [buf + 0] = 0x67452301; + assert [buf + 1] = 0xefcdab89; + assert [buf + 2] = 0x98badcfe; + assert [buf + 3] = 0x10325476; + assert [buf + 4] = 0xc3d2e1f0; + return (); +} + +// the compression function. +// transforms buf using message bytes X[0] through X[15]. +func compress{bitwise_ptr: BitwiseBuiltin*, range_check_ptr}( + buf: felt*, bufsize: felt, x: felt*, xlen: felt +) -> (res: felt*, rsize: felt) { + alloc_locals; + + assert bufsize = 5; + assert xlen = 16; + + // all element is in [0, 2^32). + let (_, aa) = unsigned_div_rem([buf + 0], MAX_32_BIT); + let (_, bb) = unsigned_div_rem([buf + 1], MAX_32_BIT); + let (_, cc) = unsigned_div_rem([buf + 2], MAX_32_BIT); + let (_, dd) = unsigned_div_rem([buf + 3], MAX_32_BIT); + let (_, ee) = unsigned_div_rem([buf + 4], MAX_32_BIT); + local aaa = aa; + local bbb = bb; + local ccc = cc; + local ddd = dd; + local eee = ee; + + // round 1 + let (local aa, local cc) = FF(aa, bb, cc, dd, ee, [x + 0], 11); + let (local ee, local bb) = FF(ee, aa, bb, cc, dd, [x + 1], 14); + let (local dd, local aa) = FF(dd, ee, aa, bb, cc, [x + 2], 15); + let (local cc, local ee) = FF(cc, dd, ee, aa, bb, [x + 3], 12); + let (local bb, local dd) = FF(bb, cc, dd, ee, aa, [x + 4], 5); + let (local aa, local cc) = FF(aa, bb, cc, dd, ee, [x + 5], 8); + let (local ee, local bb) = FF(ee, aa, bb, cc, dd, [x + 6], 7); + let (local dd, local aa) = FF(dd, ee, aa, bb, cc, [x + 7], 9); + let (local cc, local ee) = FF(cc, dd, ee, aa, bb, [x + 8], 11); + let (local bb, local dd) = FF(bb, cc, dd, ee, aa, [x + 9], 13); + let (local aa, local cc) = FF(aa, bb, cc, dd, ee, [x + 10], 14); + let (local ee, local bb) = FF(ee, aa, bb, cc, dd, [x + 11], 15); + let (local dd, local aa) = FF(dd, ee, aa, bb, cc, [x + 12], 6); + let (local cc, local ee) = FF(cc, dd, ee, aa, bb, [x + 13], 7); + let (local bb, local dd) = FF(bb, cc, dd, ee, aa, [x + 14], 9); + let (local aa, local cc) = FF(aa, bb, cc, dd, ee, [x + 15], 8); + + // round 2 + let (local ee, local bb) = GG(ee, aa, bb, cc, dd, [x + 7], 7); + let (local dd, local aa) = GG(dd, ee, aa, bb, cc, [x + 4], 6); + let (local cc, local ee) = GG(cc, dd, ee, aa, bb, [x + 13], 8); + let (local bb, local dd) = GG(bb, cc, dd, ee, aa, [x + 1], 13); + let (local aa, local cc) = GG(aa, bb, cc, dd, ee, [x + 10], 11); + let (local ee, local bb) = GG(ee, aa, bb, cc, dd, [x + 6], 9); + let (local dd, local aa) = GG(dd, ee, aa, bb, cc, [x + 15], 7); + let (local cc, local ee) = GG(cc, dd, ee, aa, bb, [x + 3], 15); + let (local bb, local dd) = GG(bb, cc, dd, ee, aa, [x + 12], 7); + let (local aa, local cc) = GG(aa, bb, cc, dd, ee, [x + 0], 12); + let (local ee, local bb) = GG(ee, aa, bb, cc, dd, [x + 9], 15); + let (local dd, local aa) = GG(dd, ee, aa, bb, cc, [x + 5], 9); + let (local cc, local ee) = GG(cc, dd, ee, aa, bb, [x + 2], 11); + let (local bb, local dd) = GG(bb, cc, dd, ee, aa, [x + 14], 7); + let (local aa, local cc) = GG(aa, bb, cc, dd, ee, [x + 11], 13); + let (local ee, local bb) = GG(ee, aa, bb, cc, dd, [x + 8], 12); + + // round 3 + let (local dd, local aa) = HH(dd, ee, aa, bb, cc, [x + 3], 11); + let (local cc, local ee) = HH(cc, dd, ee, aa, bb, [x + 10], 13); + let (local bb, local dd) = HH(bb, cc, dd, ee, aa, [x + 14], 6); + let (local aa, local cc) = HH(aa, bb, cc, dd, ee, [x + 4], 7); + let (local ee, local bb) = HH(ee, aa, bb, cc, dd, [x + 9], 14); + let (local dd, local aa) = HH(dd, ee, aa, bb, cc, [x + 15], 9); + let (local cc, local ee) = HH(cc, dd, ee, aa, bb, [x + 8], 13); + let (local bb, local dd) = HH(bb, cc, dd, ee, aa, [x + 1], 15); + let (local aa, local cc) = HH(aa, bb, cc, dd, ee, [x + 2], 14); + let (local ee, local bb) = HH(ee, aa, bb, cc, dd, [x + 7], 8); + let (local dd, local aa) = HH(dd, ee, aa, bb, cc, [x + 0], 13); + let (local cc, local ee) = HH(cc, dd, ee, aa, bb, [x + 6], 6); + let (local bb, local dd) = HH(bb, cc, dd, ee, aa, [x + 13], 5); + let (local aa, local cc) = HH(aa, bb, cc, dd, ee, [x + 11], 12); + let (local ee, local bb) = HH(ee, aa, bb, cc, dd, [x + 5], 7); + let (local dd, local aa) = HH(dd, ee, aa, bb, cc, [x + 12], 5); + + // round 4 + let (local cc, local ee) = II(cc, dd, ee, aa, bb, [x + 1], 11); + let (local bb, local dd) = II(bb, cc, dd, ee, aa, [x + 9], 12); + let (local aa, local cc) = II(aa, bb, cc, dd, ee, [x + 11], 14); + let (local ee, local bb) = II(ee, aa, bb, cc, dd, [x + 10], 15); + let (local dd, local aa) = II(dd, ee, aa, bb, cc, [x + 0], 14); + let (local cc, local ee) = II(cc, dd, ee, aa, bb, [x + 8], 15); + let (local bb, local dd) = II(bb, cc, dd, ee, aa, [x + 12], 9); + let (local aa, local cc) = II(aa, bb, cc, dd, ee, [x + 4], 8); + let (local ee, local bb) = II(ee, aa, bb, cc, dd, [x + 13], 9); + let (local dd, local aa) = II(dd, ee, aa, bb, cc, [x + 3], 14); + let (local cc, local ee) = II(cc, dd, ee, aa, bb, [x + 7], 5); + let (local bb, local dd) = II(bb, cc, dd, ee, aa, [x + 15], 6); + let (local aa, local cc) = II(aa, bb, cc, dd, ee, [x + 14], 8); + let (local ee, local bb) = II(ee, aa, bb, cc, dd, [x + 5], 6); + let (local dd, local aa) = II(dd, ee, aa, bb, cc, [x + 6], 5); + let (local cc, local ee) = II(cc, dd, ee, aa, bb, [x + 2], 12); + + // round 5 + let (local bb, local dd) = JJ(bb, cc, dd, ee, aa, [x + 4], 9); + let (local aa, local cc) = JJ(aa, bb, cc, dd, ee, [x + 0], 15); + let (local ee, local bb) = JJ(ee, aa, bb, cc, dd, [x + 5], 5); + let (local dd, local aa) = JJ(dd, ee, aa, bb, cc, [x + 9], 11); + let (local cc, local ee) = JJ(cc, dd, ee, aa, bb, [x + 7], 6); + let (local bb, local dd) = JJ(bb, cc, dd, ee, aa, [x + 12], 8); + let (local aa, local cc) = JJ(aa, bb, cc, dd, ee, [x + 2], 13); + let (local ee, local bb) = JJ(ee, aa, bb, cc, dd, [x + 10], 12); + let (local dd, local aa) = JJ(dd, ee, aa, bb, cc, [x + 14], 5); + let (local cc, local ee) = JJ(cc, dd, ee, aa, bb, [x + 1], 12); + let (local bb, local dd) = JJ(bb, cc, dd, ee, aa, [x + 3], 13); + let (local aa, local cc) = JJ(aa, bb, cc, dd, ee, [x + 8], 14); + let (local ee, local bb) = JJ(ee, aa, bb, cc, dd, [x + 11], 11); + let (local dd, local aa) = JJ(dd, ee, aa, bb, cc, [x + 6], 8); + let (local cc, local ee) = JJ(cc, dd, ee, aa, bb, [x + 15], 5); + let (local bb, local dd) = JJ(bb, cc, dd, ee, aa, [x + 13], 6); + + // parallel round 1 + let (local aaa, local ccc) = JJJ(aaa, bbb, ccc, ddd, eee, [x + 5], 8); + let (local eee, local bbb) = JJJ(eee, aaa, bbb, ccc, ddd, [x + 14], 9); + let (local ddd, local aaa) = JJJ(ddd, eee, aaa, bbb, ccc, [x + 7], 9); + let (local ccc, local eee) = JJJ(ccc, ddd, eee, aaa, bbb, [x + 0], 11); + let (local bbb, local ddd) = JJJ(bbb, ccc, ddd, eee, aaa, [x + 9], 13); + let (local aaa, local ccc) = JJJ(aaa, bbb, ccc, ddd, eee, [x + 2], 15); + let (local eee, local bbb) = JJJ(eee, aaa, bbb, ccc, ddd, [x + 11], 15); + let (local ddd, local aaa) = JJJ(ddd, eee, aaa, bbb, ccc, [x + 4], 5); + let (local ccc, local eee) = JJJ(ccc, ddd, eee, aaa, bbb, [x + 13], 7); + let (local bbb, local ddd) = JJJ(bbb, ccc, ddd, eee, aaa, [x + 6], 7); + let (local aaa, local ccc) = JJJ(aaa, bbb, ccc, ddd, eee, [x + 15], 8); + let (local eee, local bbb) = JJJ(eee, aaa, bbb, ccc, ddd, [x + 8], 11); + let (local ddd, local aaa) = JJJ(ddd, eee, aaa, bbb, ccc, [x + 1], 14); + let (local ccc, local eee) = JJJ(ccc, ddd, eee, aaa, bbb, [x + 10], 14); + let (local bbb, local ddd) = JJJ(bbb, ccc, ddd, eee, aaa, [x + 3], 12); + let (local aaa, local ccc) = JJJ(aaa, bbb, ccc, ddd, eee, [x + 12], 6); + + // parallel round 2 + let (local eee, local bbb) = III(eee, aaa, bbb, ccc, ddd, [x + 6], 9); + let (local ddd, local aaa) = III(ddd, eee, aaa, bbb, ccc, [x + 11], 13); + let (local ccc, local eee) = III(ccc, ddd, eee, aaa, bbb, [x + 3], 15); + let (local bbb, local ddd) = III(bbb, ccc, ddd, eee, aaa, [x + 7], 7); + let (local aaa, local ccc) = III(aaa, bbb, ccc, ddd, eee, [x + 0], 12); + let (local eee, local bbb) = III(eee, aaa, bbb, ccc, ddd, [x + 13], 8); + let (local ddd, local aaa) = III(ddd, eee, aaa, bbb, ccc, [x + 5], 9); + let (local ccc, local eee) = III(ccc, ddd, eee, aaa, bbb, [x + 10], 11); + let (local bbb, local ddd) = III(bbb, ccc, ddd, eee, aaa, [x + 14], 7); + let (local aaa, local ccc) = III(aaa, bbb, ccc, ddd, eee, [x + 15], 7); + let (local eee, local bbb) = III(eee, aaa, bbb, ccc, ddd, [x + 8], 12); + let (local ddd, local aaa) = III(ddd, eee, aaa, bbb, ccc, [x + 12], 7); + let (local ccc, local eee) = III(ccc, ddd, eee, aaa, bbb, [x + 4], 6); + let (local bbb, local ddd) = III(bbb, ccc, ddd, eee, aaa, [x + 9], 15); + let (local aaa, local ccc) = III(aaa, bbb, ccc, ddd, eee, [x + 1], 13); + let (local eee, local bbb) = III(eee, aaa, bbb, ccc, ddd, [x + 2], 11); + + // parallel round 3 + let (local ddd, local aaa) = HHH(ddd, eee, aaa, bbb, ccc, [x + 15], 9); + let (local ccc, local eee) = HHH(ccc, ddd, eee, aaa, bbb, [x + 5], 7); + let (local bbb, local ddd) = HHH(bbb, ccc, ddd, eee, aaa, [x + 1], 15); + let (local aaa, local ccc) = HHH(aaa, bbb, ccc, ddd, eee, [x + 3], 11); + let (local eee, local bbb) = HHH(eee, aaa, bbb, ccc, ddd, [x + 7], 8); + let (local ddd, local aaa) = HHH(ddd, eee, aaa, bbb, ccc, [x + 14], 6); + let (local ccc, local eee) = HHH(ccc, ddd, eee, aaa, bbb, [x + 6], 6); + let (local bbb, local ddd) = HHH(bbb, ccc, ddd, eee, aaa, [x + 9], 14); + let (local aaa, local ccc) = HHH(aaa, bbb, ccc, ddd, eee, [x + 11], 12); + let (local eee, local bbb) = HHH(eee, aaa, bbb, ccc, ddd, [x + 8], 13); + let (local ddd, local aaa) = HHH(ddd, eee, aaa, bbb, ccc, [x + 12], 5); + let (local ccc, local eee) = HHH(ccc, ddd, eee, aaa, bbb, [x + 2], 14); + let (local bbb, local ddd) = HHH(bbb, ccc, ddd, eee, aaa, [x + 10], 13); + let (local aaa, local ccc) = HHH(aaa, bbb, ccc, ddd, eee, [x + 0], 13); + let (local eee, local bbb) = HHH(eee, aaa, bbb, ccc, ddd, [x + 4], 7); + let (local ddd, local aaa) = HHH(ddd, eee, aaa, bbb, ccc, [x + 13], 5); + + // parallel round 4 + let (local ccc, local eee) = GGG(ccc, ddd, eee, aaa, bbb, [x + 8], 15); + let (local bbb, local ddd) = GGG(bbb, ccc, ddd, eee, aaa, [x + 6], 5); + let (local aaa, local ccc) = GGG(aaa, bbb, ccc, ddd, eee, [x + 4], 8); + let (local eee, local bbb) = GGG(eee, aaa, bbb, ccc, ddd, [x + 1], 11); + let (local ddd, local aaa) = GGG(ddd, eee, aaa, bbb, ccc, [x + 3], 14); + let (local ccc, local eee) = GGG(ccc, ddd, eee, aaa, bbb, [x + 11], 14); + let (local bbb, local ddd) = GGG(bbb, ccc, ddd, eee, aaa, [x + 15], 6); + let (local aaa, local ccc) = GGG(aaa, bbb, ccc, ddd, eee, [x + 0], 14); + let (local eee, local bbb) = GGG(eee, aaa, bbb, ccc, ddd, [x + 5], 6); + let (local ddd, local aaa) = GGG(ddd, eee, aaa, bbb, ccc, [x + 12], 9); + let (local ccc, local eee) = GGG(ccc, ddd, eee, aaa, bbb, [x + 2], 12); + let (local bbb, local ddd) = GGG(bbb, ccc, ddd, eee, aaa, [x + 13], 9); + let (local aaa, local ccc) = GGG(aaa, bbb, ccc, ddd, eee, [x + 9], 12); + let (local eee, local bbb) = GGG(eee, aaa, bbb, ccc, ddd, [x + 7], 5); + let (local ddd, local aaa) = GGG(ddd, eee, aaa, bbb, ccc, [x + 10], 15); + let (local ccc, local eee) = GGG(ccc, ddd, eee, aaa, bbb, [x + 14], 8); + + // parallel round 5 + let (local bbb, local ddd) = FFF(bbb, ccc, ddd, eee, aaa, [x + 12], 8); + let (local aaa, local ccc) = FFF(aaa, bbb, ccc, ddd, eee, [x + 15], 5); + let (local eee, local bbb) = FFF(eee, aaa, bbb, ccc, ddd, [x + 10], 12); + let (local ddd, local aaa) = FFF(ddd, eee, aaa, bbb, ccc, [x + 4], 9); + let (local ccc, local eee) = FFF(ccc, ddd, eee, aaa, bbb, [x + 1], 12); + let (local bbb, local ddd) = FFF(bbb, ccc, ddd, eee, aaa, [x + 5], 5); + let (local aaa, local ccc) = FFF(aaa, bbb, ccc, ddd, eee, [x + 8], 14); + let (local eee, local bbb) = FFF(eee, aaa, bbb, ccc, ddd, [x + 7], 6); + let (local ddd, local aaa) = FFF(ddd, eee, aaa, bbb, ccc, [x + 6], 8); + let (local ccc, local eee) = FFF(ccc, ddd, eee, aaa, bbb, [x + 2], 13); + let (local bbb, local ddd) = FFF(bbb, ccc, ddd, eee, aaa, [x + 13], 6); + let (local aaa, local ccc) = FFF(aaa, bbb, ccc, ddd, eee, [x + 14], 5); + let (local eee, local bbb) = FFF(eee, aaa, bbb, ccc, ddd, [x + 0], 15); + let (local ddd, local aaa) = FFF(ddd, eee, aaa, bbb, ccc, [x + 3], 13); + let (local ccc, local eee) = FFF(ccc, ddd, eee, aaa, bbb, [x + 9], 11); + let (local bbb, local ddd) = FFF(bbb, ccc, ddd, eee, aaa, [x + 11], 11); + + // combine results + let (local res: felt*) = alloc(); + + let (res0) = uint32_add([buf + 1], cc); + let (res0) = uint32_add(res0, ddd); + + let (res1) = uint32_add([buf + 2], dd); + let (res1) = uint32_add(res1, eee); + + let (res2) = uint32_add([buf + 3], ee); + let (res2) = uint32_add(res2, aaa); + + let (res3) = uint32_add([buf + 4], aa); + let (res3) = uint32_add(res3, bbb); + + let (res4) = uint32_add([buf + 0], bb); + let (res4) = uint32_add(res4, ccc); + + assert res[0] = res0; + assert res[1] = res1; + assert res[2] = res2; + assert res[3] = res3; + assert res[4] = res4; + + return (res=res, rsize=5); +} + +// puts bytes from data into X and pad out; appends length +// and finally, compresses the last block(s) +// note: length in bits == 8 * (dsize + 2^32 mswlen). +// note: there are (dsize mod 64) bytes left in data. +func finish{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + buf: felt*, bufsize: felt, data: felt*, dsize: felt, mswlen: felt +) -> (res: felt*, rsize: felt) { + alloc_locals; + let (x) = default_dict_new(0); + tempvar start = x; + + // put data into x. + let (local len) = uint32_and(dsize, 63); + absorb_data{dict_ptr=x}(data, len, 0); + + // append the bit m_n == 1. + let (index_4, _) = unsigned_div_rem(dsize, 4); + let (local index) = uint32_and(index_4, 15); + let (old_val) = dict_read{dict_ptr=x}(index); + let (local ba_3) = uint32_and(dsize, 3); + let (factor) = uint32_add(8 * ba_3, 7); + let (tmp) = pow2(factor); + let (local val) = uint32_xor(old_val, tmp); + dict_write{dict_ptr=x}(index, val); + + // length goes to next block. + let (val) = uint32_mul(dsize, 8); + let (pow2_29) = pow2(29); + let (factor, _) = unsigned_div_rem(dsize, pow2_29); + let len_8 = mswlen * 8; + let (val_15) = uint32_or(factor, len_8); + + let next_block = is_nn_le(55, len); + if (next_block == FALSE) { + dict_write{dict_ptr=x}(14, val); + dict_write{dict_ptr=x}(15, val_15); + + let (local arr_x: felt*) = alloc(); + dict_to_array{dict_ptr=x}(arr_x, 16); + default_dict_finalize(start, x, 0); + let (res, rsize) = compress(buf, bufsize, arr_x, 16); + return (res=res, rsize=rsize); + } + let (local arr_x: felt*) = alloc(); + dict_to_array{dict_ptr=x}(arr_x, 16); + let (buf, bufsize) = compress(buf, bufsize, arr_x, 16); + // reset dict to all 0. + let (x) = default_dict_new(0); + + dict_write{dict_ptr=x}(14, val); + dict_write{dict_ptr=x}(15, val_15); + + let (local arr_x: felt*) = alloc(); + dict_to_array{dict_ptr=x}(arr_x, 16); + default_dict_finalize(start, x, 0); + let (res, rsize) = compress(buf, bufsize, arr_x, 16); + return (res=res, rsize=rsize); +} + +func uint8_div{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y) -> (z: felt) { + let (z, _) = unsigned_div_rem(x, y); + let (_, z) = unsigned_div_rem(z, MAX_BYTE); + return (z=z); +} + +func uint32_add{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y) -> (z: felt) { + let (_, z) = unsigned_div_rem(x + y, MAX_32_BIT); + return (z=z); +} + +func uint32_mul{range_check_ptr}(x, y) -> (z: felt) { + let (_, z) = unsigned_div_rem(x * y, MAX_32_BIT); + return (z=z); +} + +func uint32_and{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y) -> (z: felt) { + let (z) = bitwise_and(x, y); + let (_, z) = unsigned_div_rem(z, MAX_32_BIT); + return (z=z); +} + +func uint32_or{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y) -> (z: felt) { + let (z) = bitwise_or(x, y); + let (_, z) = unsigned_div_rem(z, MAX_32_BIT); + return (z=z); +} + +func uint32_not{range_check_ptr}(x: felt) -> (not_x: felt) { + let not_x = MAX_32_BIT - 1 - x; + let (_, not_x) = unsigned_div_rem(not_x, MAX_32_BIT); + return (not_x=not_x); +} + +func uint32_xor{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y) -> (z: felt) { + let (z) = bitwise_xor(x, y); + let (_, z) = unsigned_div_rem(z, MAX_32_BIT); + return (z=z); +} + +// collect four bytes into one word. +func BYTES_TO_WORD{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x: felt*) -> (res: felt) { + alloc_locals; + let (factor_3) = pow2(24); + let (factor_2) = pow2(16); + let (factor_1) = pow2(8); + let (l1) = uint32_mul([x + 3], factor_3); + let (l2) = uint32_mul([x + 2], factor_2); + let (l3) = uint32_mul([x + 1], factor_1); + let (l1_or_l2) = uint32_or(l1, l2); + let (l1_or_l2_or_l3) = uint32_or(l1_or_l2, l3); + let (res) = uint32_or(l1_or_l2_or_l3, [x]); + return (res=res); +} + +// ROL(x, n) cyclically rotates x over n bits to the left +// x must be mod of an unsigned 32 bits type and 0 <= n < 32. +func ROL{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, n) -> (res: felt) { + alloc_locals; + assert_nn_le(x, 2 ** 32 - 1); + assert_nn_le(n, 31); + + let (factor_n) = pow2(n); + let (factor_diff) = pow2(32 - n); + let (x_left_shift) = uint32_mul(x, factor_n); + let (x_right_shift, _) = unsigned_div_rem(x, factor_diff); + let (res) = uint32_or(x_left_shift, x_right_shift); + return (res=res); +} + +// the five basic functions F(), G(), H(), I(), J(). +func F{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y, z) -> (res: felt) { + let (x_xor_y) = uint32_xor(x, y); + let (res) = uint32_xor(x_xor_y, z); + return (res=res); +} + +func G{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y, z) -> (res: felt) { + let (x_and_y) = uint32_and(x, y); + let (not_x) = uint32_not(x); + let (not_x_and_z) = uint32_and(not_x, z); + let (res) = uint32_or(x_and_y, not_x_and_z); + return (res=res); +} + +func H{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y, z) -> (res: felt) { + let (not_y) = uint32_not(y); + let (x_or_not_y) = uint32_or(x, not_y); + let (res) = uint32_xor(x_or_not_y, z); + return (res=res); +} + +func I{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y, z) -> (res: felt) { + let (x_and_z) = uint32_and(x, z); + let (not_z) = uint32_not(z); + let (y_and_not_z) = uint32_and(y, not_z); + let (res) = uint32_or(x_and_z, y_and_not_z); + return (res=res); +} + +func J{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x, y, z) -> (res: felt) { + let (not_z) = uint32_not(z); + let (y_or_not_z) = uint32_or(y, not_z); + let (res) = uint32_xor(x, y_or_not_z); + return (res=res); +} + +// the ten basic operations FF() through JJJ(). +func ROLASE{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, s, e) -> (res: felt) { + let (rol_a_s) = ROL(a, s); + let (res) = uint32_add(rol_a_s, e); + return (res=res); +} + +func FF{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + + let (f_bcd) = F(b, c, d); + let (a) = uint32_add(a, f_bcd); + let (a) = uint32_add(a, x); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func GG{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (g_bcd) = G(b, c, d); + let (a) = uint32_add(a, g_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x5a827999); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func HH{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (h_bcd) = H(b, c, d); + let (a) = uint32_add(a, h_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x6ed9eba1); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func II{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (i_bcd) = I(b, c, d); + let (a) = uint32_add(a, i_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x8f1bbcdc); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func JJ{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (j_bcd) = J(b, c, d); + let (a) = uint32_add(a, j_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0xa953fd4e); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func FFF{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + let (res1: felt, res2: felt) = FF(a, b, c, d, e, x, s); + return (res1=res1, res2=res2); +} + +func GGG{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (g_bcd) = G(b, c, d); + let (a) = uint32_add(a, g_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x7a6d76e9); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func HHH{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (h_bcd) = H(b, c, d); + let (a) = uint32_add(a, h_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x6d703ef3); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func III{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (i_bcd) = I(b, c, d); + let (a) = uint32_add(a, i_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x5c4dd124); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +func JJJ{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(a, b, c, d, e, x, s) -> ( + res1: felt, res2: felt +) { + alloc_locals; + let (j_bcd) = J(b, c, d); + let (a) = uint32_add(a, j_bcd); + let (a) = uint32_add(a, x); + let (a) = uint32_add(a, 0x50a28be6); + let (res1) = ROLASE(a, s, e); + let (res2) = ROL(c, 10); + return (res1=res1, res2=res2); +} + +// This is taken from https://github.com/greenlucid/chess-cairo. +func pow2(i: felt) -> (res: felt) { + let (data_address) = get_label_location(data); + return (res=[data_address + i]); + + data: + dw 1; + dw 2; + dw 4; + dw 8; + dw 16; + dw 32; + dw 64; + dw 128; + dw 256; + dw 512; + dw 1024; + dw 2048; + dw 4096; + dw 8192; + dw 16384; + dw 32768; + dw 65536; + dw 131072; + dw 262144; + dw 524288; + dw 1048576; + dw 2097152; + dw 4194304; + dw 8388608; + dw 16777216; + dw 33554432; + dw 67108864; + dw 134217728; + dw 268435456; + dw 536870912; + dw 1073741824; + dw 2147483648; + dw 4294967296; + dw 8589934592; + dw 17179869184; + dw 34359738368; + dw 68719476736; + dw 137438953472; + dw 274877906944; + dw 549755813888; + dw 1099511627776; + dw 2199023255552; + dw 4398046511104; + dw 8796093022208; + dw 17592186044416; + dw 35184372088832; + dw 70368744177664; + dw 140737488355328; + dw 281474976710656; + dw 562949953421312; + dw 1125899906842624; + dw 2251799813685248; + dw 4503599627370496; + dw 9007199254740992; + dw 18014398509481984; + dw 36028797018963968; + dw 72057594037927936; + dw 144115188075855872; + dw 288230376151711744; + dw 576460752303423488; + dw 1152921504606846976; + dw 2305843009213693952; + dw 4611686018427387904; + dw 9223372036854775808; + dw 18446744073709551616; + dw 36893488147419103232; + dw 73786976294838206464; + dw 147573952589676412928; + dw 295147905179352825856; + dw 590295810358705651712; + dw 1180591620717411303424; + dw 2361183241434822606848; + dw 4722366482869645213696; + dw 9444732965739290427392; + dw 18889465931478580854784; + dw 37778931862957161709568; + dw 75557863725914323419136; + dw 151115727451828646838272; + dw 302231454903657293676544; + dw 604462909807314587353088; + dw 1208925819614629174706176; + dw 2417851639229258349412352; + dw 4835703278458516698824704; + dw 9671406556917033397649408; + dw 19342813113834066795298816; + dw 38685626227668133590597632; + dw 77371252455336267181195264; + dw 154742504910672534362390528; + dw 309485009821345068724781056; + dw 618970019642690137449562112; + dw 1237940039285380274899124224; + dw 2475880078570760549798248448; + dw 4951760157141521099596496896; + dw 9903520314283042199192993792; + dw 19807040628566084398385987584; + dw 39614081257132168796771975168; + dw 79228162514264337593543950336; + dw 158456325028528675187087900672; + dw 316912650057057350374175801344; + dw 633825300114114700748351602688; + dw 1267650600228229401496703205376; + dw 2535301200456458802993406410752; + dw 5070602400912917605986812821504; + dw 10141204801825835211973625643008; + dw 20282409603651670423947251286016; + dw 40564819207303340847894502572032; + dw 81129638414606681695789005144064; + dw 162259276829213363391578010288128; + dw 324518553658426726783156020576256; + dw 649037107316853453566312041152512; + dw 1298074214633706907132624082305024; + dw 2596148429267413814265248164610048; + dw 5192296858534827628530496329220096; + dw 10384593717069655257060992658440192; + dw 20769187434139310514121985316880384; + dw 41538374868278621028243970633760768; + dw 83076749736557242056487941267521536; + dw 166153499473114484112975882535043072; + dw 332306998946228968225951765070086144; + dw 664613997892457936451903530140172288; + dw 1329227995784915872903807060280344576; + dw 2658455991569831745807614120560689152; + dw 5316911983139663491615228241121378304; + dw 10633823966279326983230456482242756608; + dw 21267647932558653966460912964485513216; + dw 42535295865117307932921825928971026432; + dw 85070591730234615865843651857942052864; + dw 170141183460469231731687303715884105728; + dw 340282366920938463463374607431768211456; + dw 680564733841876926926749214863536422912; + dw 1361129467683753853853498429727072845824; + dw 2722258935367507707706996859454145691648; + dw 5444517870735015415413993718908291383296; + dw 10889035741470030830827987437816582766592; + dw 21778071482940061661655974875633165533184; + dw 43556142965880123323311949751266331066368; + dw 87112285931760246646623899502532662132736; + dw 174224571863520493293247799005065324265472; + dw 348449143727040986586495598010130648530944; + dw 696898287454081973172991196020261297061888; + dw 1393796574908163946345982392040522594123776; + dw 2787593149816327892691964784081045188247552; + dw 5575186299632655785383929568162090376495104; + dw 11150372599265311570767859136324180752990208; + dw 22300745198530623141535718272648361505980416; + dw 44601490397061246283071436545296723011960832; + dw 89202980794122492566142873090593446023921664; + dw 178405961588244985132285746181186892047843328; + dw 356811923176489970264571492362373784095686656; + dw 713623846352979940529142984724747568191373312; + dw 1427247692705959881058285969449495136382746624; + dw 2854495385411919762116571938898990272765493248; + dw 5708990770823839524233143877797980545530986496; + dw 11417981541647679048466287755595961091061972992; + dw 22835963083295358096932575511191922182123945984; + dw 45671926166590716193865151022383844364247891968; + dw 91343852333181432387730302044767688728495783936; + dw 182687704666362864775460604089535377456991567872; + dw 365375409332725729550921208179070754913983135744; + dw 730750818665451459101842416358141509827966271488; + dw 1461501637330902918203684832716283019655932542976; + dw 2923003274661805836407369665432566039311865085952; + dw 5846006549323611672814739330865132078623730171904; + dw 11692013098647223345629478661730264157247460343808; + dw 23384026197294446691258957323460528314494920687616; + dw 46768052394588893382517914646921056628989841375232; + dw 93536104789177786765035829293842113257979682750464; + dw 187072209578355573530071658587684226515959365500928; + dw 374144419156711147060143317175368453031918731001856; + dw 748288838313422294120286634350736906063837462003712; + dw 1496577676626844588240573268701473812127674924007424; + dw 2993155353253689176481146537402947624255349848014848; + dw 5986310706507378352962293074805895248510699696029696; + dw 11972621413014756705924586149611790497021399392059392; + dw 23945242826029513411849172299223580994042798784118784; + dw 47890485652059026823698344598447161988085597568237568; + dw 95780971304118053647396689196894323976171195136475136; + dw 191561942608236107294793378393788647952342390272950272; + dw 383123885216472214589586756787577295904684780545900544; + dw 766247770432944429179173513575154591809369561091801088; + dw 1532495540865888858358347027150309183618739122183602176; + dw 3064991081731777716716694054300618367237478244367204352; + dw 6129982163463555433433388108601236734474956488734408704; + dw 12259964326927110866866776217202473468949912977468817408; + dw 24519928653854221733733552434404946937899825954937634816; + dw 49039857307708443467467104868809893875799651909875269632; + dw 98079714615416886934934209737619787751599303819750539264; + dw 196159429230833773869868419475239575503198607639501078528; + dw 392318858461667547739736838950479151006397215279002157056; + dw 784637716923335095479473677900958302012794430558004314112; + dw 1569275433846670190958947355801916604025588861116008628224; + dw 3138550867693340381917894711603833208051177722232017256448; + dw 6277101735386680763835789423207666416102355444464034512896; + dw 12554203470773361527671578846415332832204710888928069025792; + dw 25108406941546723055343157692830665664409421777856138051584; + dw 50216813883093446110686315385661331328818843555712276103168; + dw 100433627766186892221372630771322662657637687111424552206336; + dw 200867255532373784442745261542645325315275374222849104412672; + dw 401734511064747568885490523085290650630550748445698208825344; + dw 803469022129495137770981046170581301261101496891396417650688; + dw 1606938044258990275541962092341162602522202993782792835301376; + dw 3213876088517980551083924184682325205044405987565585670602752; + dw 6427752177035961102167848369364650410088811975131171341205504; + dw 12855504354071922204335696738729300820177623950262342682411008; + dw 25711008708143844408671393477458601640355247900524685364822016; + dw 51422017416287688817342786954917203280710495801049370729644032; + dw 102844034832575377634685573909834406561420991602098741459288064; + dw 205688069665150755269371147819668813122841983204197482918576128; + dw 411376139330301510538742295639337626245683966408394965837152256; + dw 822752278660603021077484591278675252491367932816789931674304512; + dw 1645504557321206042154969182557350504982735865633579863348609024; + dw 3291009114642412084309938365114701009965471731267159726697218048; + dw 6582018229284824168619876730229402019930943462534319453394436096; + dw 13164036458569648337239753460458804039861886925068638906788872192; + dw 26328072917139296674479506920917608079723773850137277813577744384; + dw 52656145834278593348959013841835216159447547700274555627155488768; + dw 105312291668557186697918027683670432318895095400549111254310977536; + dw 210624583337114373395836055367340864637790190801098222508621955072; + dw 421249166674228746791672110734681729275580381602196445017243910144; + dw 842498333348457493583344221469363458551160763204392890034487820288; + dw 1684996666696914987166688442938726917102321526408785780068975640576; + dw 3369993333393829974333376885877453834204643052817571560137951281152; + dw 6739986666787659948666753771754907668409286105635143120275902562304; + dw 13479973333575319897333507543509815336818572211270286240551805124608; + dw 26959946667150639794667015087019630673637144422540572481103610249216; + dw 53919893334301279589334030174039261347274288845081144962207220498432; + dw 107839786668602559178668060348078522694548577690162289924414440996864; + dw 215679573337205118357336120696157045389097155380324579848828881993728; + dw 431359146674410236714672241392314090778194310760649159697657763987456; + dw 862718293348820473429344482784628181556388621521298319395315527974912; + dw 1725436586697640946858688965569256363112777243042596638790631055949824; + dw 3450873173395281893717377931138512726225554486085193277581262111899648; + dw 6901746346790563787434755862277025452451108972170386555162524223799296; + dw 13803492693581127574869511724554050904902217944340773110325048447598592; + dw 27606985387162255149739023449108101809804435888681546220650096895197184; + dw 55213970774324510299478046898216203619608871777363092441300193790394368; + dw 110427941548649020598956093796432407239217743554726184882600387580788736; + dw 220855883097298041197912187592864814478435487109452369765200775161577472; + dw 441711766194596082395824375185729628956870974218904739530401550323154944; + dw 883423532389192164791648750371459257913741948437809479060803100646309888; + dw 1766847064778384329583297500742918515827483896875618958121606201292619776; + dw 3533694129556768659166595001485837031654967793751237916243212402585239552; + dw 7067388259113537318333190002971674063309935587502475832486424805170479104; + dw 14134776518227074636666380005943348126619871175004951664972849610340958208; + dw 28269553036454149273332760011886696253239742350009903329945699220681916416; + dw 56539106072908298546665520023773392506479484700019806659891398441363832832; + dw 113078212145816597093331040047546785012958969400039613319782796882727665664; + dw 226156424291633194186662080095093570025917938800079226639565593765455331328; + dw 452312848583266388373324160190187140051835877600158453279131187530910662656; + dw 904625697166532776746648320380374280103671755200316906558262375061821325312; + dw 1809251394333065553493296640760748560207343510400633813116524750123642650624; +} diff --git a/cairo/src/precompiles/sha256.cairo b/cairo/src/precompiles/sha256.cairo new file mode 100644 index 00000000..76220116 --- /dev/null +++ b/cairo/src/precompiles/sha256.cairo @@ -0,0 +1,454 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math import assert_nn_le +from starkware.cairo.common.math_cmp import is_le_felt +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.memset import memset +from starkware.cairo.common.pow import pow +from starkware.cairo.common.bool import FALSE + +from src.utils.sha_256.packed_sha256 import ( + BLOCK_SIZE, + compute_message_schedule, + sha2_compress, + get_round_constants, +) +from src.utils.utils import Helpers +from src.utils.maths import unsigned_div_rem + +// @title SHA2-256 Precompile related functions. +// @notice This file contains the logic required to run the SHA2-256 precompile +// @author @ftupas +// @custom:namespace PrecompileSHA256 +namespace PrecompileSHA256 { + const PRECOMPILE_ADDRESS = 0x02; + const GAS_COST_SHA256 = 60; + + // @notice Run the precompile. + // @param input_len The length of input array. + // @param input The input array. + // @return output_len The output length. + // @return output The output array. + // @return gas_used The gas usage of precompile. + func run{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + _address: felt, input_len: felt, input: felt* + ) -> (output_len: felt, output: felt*, gas_used: felt, reverted: felt) { + alloc_locals; + + // Copy input array + let (arr: felt*) = alloc(); + memcpy(arr, input, input_len); + + // Zero-pad bytes array + // ex. 'rld\x00' + let (q: felt, r: felt) = unsigned_div_rem(input_len, 4); + if (r != 0) { + // Append zero elements at the end of array + memset(arr + input_len, 0, 4 - r); + tempvar arr_len = (q + 1) * 4; + } else { + tempvar arr_len = q * 4; + } + + // Prepare input bytes array to words of 32 bits (big endian). + let (prepared_input: felt*) = alloc(); + let (prepared_input_len, prepared_input: felt*) = Helpers.bytes_to_bytes4_array( + arr_len, arr, 0, prepared_input + ); + + // Compute hash, use input_len for number of bytes + let (local sha256_ptr: felt*) = alloc(); + let sha256_ptr_start = sha256_ptr; + let (hash) = SHA256.sha256{sha256_ptr=sha256_ptr}(prepared_input, input_len); + + // Finalize hash + SHA256.finalize_sha256(sha256_ptr_start=sha256_ptr_start, sha256_ptr_end=sha256_ptr); + + // Split words and return bytes hash code. + let (hash_bytes_array: felt*) = alloc(); + let (_, hash_bytes_array: felt*) = Helpers.bytes4_array_to_bytes( + 8, hash, 0, hash_bytes_array + ); + let (minimum_word_size) = Helpers.minimum_word_count(input_len); + return (32, hash_bytes_array, 12 * minimum_word_size + GAS_COST_SHA256, 0); + } +} + +namespace SHA256 { + const SHA256_INPUT_CHUNK_SIZE_FELTS = 16; + const SHA256_INPUT_CHUNK_SIZE_BYTES = 64; + const SHA256_STATE_SIZE_FELTS = 8; + // Each instance consists of 16 words of message, 8 words for the input state and 8 words + // for the output state. + const SHA256_INSTANCE_SIZE = SHA256_INPUT_CHUNK_SIZE_FELTS + 2 * SHA256_STATE_SIZE_FELTS; + + // Computes SHA256 of 'input'. Inputs of arbitrary length are supported. + // To use this function, split the input into (up to) 14 words of 32 bits (big endian). + // For example, to compute sha256('Hello world'), use: + // input = [1214606444, 1864398703, 1919706112] + // where: + // 1214606444 == int.from_bytes(b'Hell', 'big') + // 1864398703 == int.from_bytes(b'o wo', 'big') + // 1919706112 == int.from_bytes(b'rld\x00', 'big') # Note the '\x00' padding. + // + // block layout: + // 0 - 15: Message + // 16 - 23: Input State + // 24 - 32: Output + // + // output is an array of 8 32-bit words (big endian). + // + // Note: You must call finalize_sha2() at the end of the program. Otherwise, this function + // is not sound and a malicious prover may return a wrong result. + // Note: the interface of this function may change in the future. + func sha256{range_check_ptr, sha256_ptr: felt*}(data: felt*, n_bytes: felt) -> (output: felt*) { + alloc_locals; + + // Set the initial input state to IV. + assert sha256_ptr[16] = 0x6A09E667; + assert sha256_ptr[17] = 0xBB67AE85; + assert sha256_ptr[18] = 0x3C6EF372; + assert sha256_ptr[19] = 0xA54FF53A; + assert sha256_ptr[20] = 0x510E527F; + assert sha256_ptr[21] = 0x9B05688C; + assert sha256_ptr[22] = 0x1F83D9AB; + assert sha256_ptr[23] = 0x5BE0CD19; + + sha256_inner(data=data, n_bytes=n_bytes, total_bytes=n_bytes); + + // Set `output` to the start of the final state. + let output = sha256_ptr; + // Set `sha256_ptr` to the end of the output state. + let sha256_ptr = sha256_ptr + SHA256_STATE_SIZE_FELTS; + return (output,); + } + + // Computes the sha256 hash of the input chunk from `message` to `message + SHA256_INPUT_CHUNK_SIZE_FELTS` + func _sha256_chunk{range_check_ptr, sha256_start: felt*, state: felt*, output: felt*}() { + %{ + from starkware.cairo.common.cairo_sha256.sha256_utils import ( + compute_message_schedule, sha2_compress_function) + + _sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS) + assert 0 <= _sha256_input_chunk_size_felts < 100 + _sha256_state_size_felts = int(ids.SHA256_STATE_SIZE_FELTS) + assert 0 <= _sha256_state_size_felts < 100 + w = compute_message_schedule(memory.get_range( + ids.sha256_start, _sha256_input_chunk_size_felts)) + new_state = sha2_compress_function(memory.get_range(ids.state, _sha256_state_size_felts), w) + segments.write_arg(ids.output, new_state) + %} + return (); + } + + // Inner loop for sha256. `sha256_ptr` points to the start of the block. + func sha256_inner{range_check_ptr, sha256_ptr: felt*}( + data: felt*, n_bytes: felt, total_bytes: felt + ) { + alloc_locals; + + let message = sha256_ptr; + let state = sha256_ptr + SHA256_INPUT_CHUNK_SIZE_FELTS; + let output = state + SHA256_STATE_SIZE_FELTS; + + let zero_bytes = is_le_felt(n_bytes, 0); + let zero_total_bytes = is_le_felt(total_bytes, 0); + + // If the previous message block was full we are still missing "1" at the end of the message + let (_, r_div_by_64) = unsigned_div_rem(total_bytes, 64); + let missing_bit_one = is_le_felt(r_div_by_64, 0); + + // This works for 0 total bytes too, because zero_chunk will be -1 and, therefore, not 0. + let zero_chunk = zero_bytes - zero_total_bytes - missing_bit_one; + + let is_last_block = is_le_felt(n_bytes, 55); + if (is_last_block == FALSE) { + let (q, r) = unsigned_div_rem(n_bytes, SHA256_INPUT_CHUNK_SIZE_BYTES); + let is_remainder_block = is_le_felt(q, 0); + if (is_remainder_block == FALSE) { + _sha256_input( + data, SHA256_INPUT_CHUNK_SIZE_BYTES, SHA256_INPUT_CHUNK_SIZE_FELTS, 0 + ); + _sha256_chunk{sha256_start=message, state=state, output=output}(); + + let sha256_ptr = sha256_ptr + SHA256_STATE_SIZE_FELTS; + memcpy( + output + SHA256_STATE_SIZE_FELTS + SHA256_INPUT_CHUNK_SIZE_FELTS, + output, + SHA256_STATE_SIZE_FELTS, + ); + let sha256_ptr = sha256_ptr + SHA256_STATE_SIZE_FELTS; + + return sha256_inner( + data=data + SHA256_INPUT_CHUNK_SIZE_FELTS, + n_bytes=n_bytes - SHA256_INPUT_CHUNK_SIZE_BYTES, + total_bytes=total_bytes, + ); + } else { + _sha256_input(data, r, SHA256_INPUT_CHUNK_SIZE_FELTS, 0); + _sha256_chunk{sha256_start=message, state=state, output=output}(); + + let sha256_ptr = sha256_ptr + SHA256_STATE_SIZE_FELTS; + memcpy( + output + SHA256_STATE_SIZE_FELTS + SHA256_INPUT_CHUNK_SIZE_FELTS, + output, + SHA256_STATE_SIZE_FELTS, + ); + let sha256_ptr = sha256_ptr + SHA256_STATE_SIZE_FELTS; + + return sha256_inner(data=data, n_bytes=n_bytes - r, total_bytes=total_bytes); + } + } + + _sha256_input(data, n_bytes, SHA256_INPUT_CHUNK_SIZE_FELTS - 2, zero_chunk); + // Append the original message length at the end of the message block as a 64-bit big-endian integer. + assert sha256_ptr[0] = 0; + assert sha256_ptr[1] = total_bytes * 8; + let sha256_ptr = sha256_ptr + 2; + _sha256_chunk{sha256_start=message, state=state, output=output}(); + let sha256_ptr = sha256_ptr + SHA256_STATE_SIZE_FELTS; + + return (); + } + + // 1. Encode the input to binary using UTF-8 and append a single '1' to it. + // 2. Prepend that binary to the message block. + func _sha256_input{range_check_ptr, sha256_ptr: felt*}( + input: felt*, n_bytes: felt, n_words: felt, pad_chunk: felt + ) { + alloc_locals; + + local full_word; + %{ ids.full_word = int(ids.n_bytes >= 4) %} + + if (full_word != 0) { + assert sha256_ptr[0] = input[0]; + let sha256_ptr = sha256_ptr + 1; + return _sha256_input( + input=input + 1, n_bytes=n_bytes - 4, n_words=n_words - 1, pad_chunk=pad_chunk + ); + } + + if (n_words == 0) { + return (); + } + + if (n_bytes == 0 and pad_chunk == 1) { + // Add zeros between the encoded message and the length integer so that the message block is a multiple of 512. + memset(dst=sha256_ptr, value=0, n=n_words); + let sha256_ptr = sha256_ptr + n_words; + return (); + } + + if (n_bytes == 0) { + // This is the last input word, so we should add a byte '0x80' at the end and fill the rest with zeros. + assert sha256_ptr[0] = 0x80000000; + // Add zeros between the encoded message and the length integer so that the message block is a multiple of 512. + memset(dst=sha256_ptr + 1, value=0, n=n_words - 1); + let sha256_ptr = sha256_ptr + n_words; + return (); + } + + assert_nn_le(n_bytes, 3); + let (padding) = pow(256, 3 - n_bytes); + local range_check_ptr = range_check_ptr; + + assert sha256_ptr[0] = input[0] + padding * 0x80; + + memset(dst=sha256_ptr + 1, value=0, n=n_words - 1); + let sha256_ptr = sha256_ptr + n_words; + return (); + } + + // Handles n blocks of BLOCK_SIZE SHA256 instances. + // Taken from: https://github.com/starkware-libs/cairo-examples/blob/0d88b41bffe3de112d98986b8b0afa795f9d67a0/sha256/sha256.cairo#L102 + func _finalize_sha256_inner{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + sha256_ptr: felt*, n: felt, round_constants: felt* + ) { + if (n == 0) { + return (); + } + + alloc_locals; + + local MAX_VALUE = 2 ** 32 - 1; + + let sha256_start = sha256_ptr; + + let (local message_start: felt*) = alloc(); + let (local input_state_start: felt*) = alloc(); + + // Handle message. + + tempvar message = message_start; + tempvar sha256_ptr = sha256_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar m = SHA256_INPUT_CHUNK_SIZE_FELTS; + + message_loop: + tempvar x0 = sha256_ptr[0 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 0] = x0; + assert [range_check_ptr + 1] = MAX_VALUE - x0; + tempvar x1 = sha256_ptr[1 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 2] = x1; + assert [range_check_ptr + 3] = MAX_VALUE - x1; + tempvar x2 = sha256_ptr[2 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 4] = x2; + assert [range_check_ptr + 5] = MAX_VALUE - x2; + tempvar x3 = sha256_ptr[3 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 6] = x3; + assert [range_check_ptr + 7] = MAX_VALUE - x3; + tempvar x4 = sha256_ptr[4 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 8] = x4; + assert [range_check_ptr + 9] = MAX_VALUE - x4; + tempvar x5 = sha256_ptr[5 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 10] = x5; + assert [range_check_ptr + 11] = MAX_VALUE - x5; + tempvar x6 = sha256_ptr[6 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 12] = x6; + assert [range_check_ptr + 13] = MAX_VALUE - x6; + assert message[0] = x0 + 2 ** 35 * x1 + 2 ** (35 * 2) * x2 + 2 ** (35 * 3) * x3 + 2 ** ( + 35 * 4 + ) * x4 + 2 ** (35 * 5) * x5 + 2 ** (35 * 6) * x6; + + tempvar message = message + 1; + tempvar sha256_ptr = sha256_ptr + 1; + tempvar range_check_ptr = range_check_ptr + 14; + tempvar m = m - 1; + jmp message_loop if m != 0; + + // Handle input state. + + tempvar input_state = input_state_start; + tempvar sha256_ptr = sha256_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar m = SHA256_STATE_SIZE_FELTS; + + input_state_loop: + tempvar x0 = sha256_ptr[0 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 0] = x0; + assert [range_check_ptr + 1] = MAX_VALUE - x0; + tempvar x1 = sha256_ptr[1 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 2] = x1; + assert [range_check_ptr + 3] = MAX_VALUE - x1; + tempvar x2 = sha256_ptr[2 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 4] = x2; + assert [range_check_ptr + 5] = MAX_VALUE - x2; + tempvar x3 = sha256_ptr[3 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 6] = x3; + assert [range_check_ptr + 7] = MAX_VALUE - x3; + tempvar x4 = sha256_ptr[4 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 8] = x4; + assert [range_check_ptr + 9] = MAX_VALUE - x4; + tempvar x5 = sha256_ptr[5 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 10] = x5; + assert [range_check_ptr + 11] = MAX_VALUE - x5; + tempvar x6 = sha256_ptr[6 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 12] = x6; + assert [range_check_ptr + 13] = MAX_VALUE - x6; + assert input_state[0] = x0 + 2 ** 35 * x1 + 2 ** (35 * 2) * x2 + 2 ** (35 * 3) * x3 + 2 ** ( + 35 * 4 + ) * x4 + 2 ** (35 * 5) * x5 + 2 ** (35 * 6) * x6; + + tempvar input_state = input_state + 1; + tempvar sha256_ptr = sha256_ptr + 1; + tempvar range_check_ptr = range_check_ptr + 14; + tempvar m = m - 1; + jmp input_state_loop if m != 0; + + // Run sha256 on the 7 instances. + + local sha256_ptr: felt* = sha256_ptr; + local range_check_ptr = range_check_ptr; + compute_message_schedule(message_start); + let (outputs) = sha2_compress(input_state_start, message_start, round_constants); + local bitwise_ptr: BitwiseBuiltin* = bitwise_ptr; + + // Handle outputs. + + tempvar outputs = outputs; + tempvar sha256_ptr = sha256_ptr; + tempvar range_check_ptr = range_check_ptr; + tempvar m = SHA256_STATE_SIZE_FELTS; + + output_loop: + tempvar x0 = sha256_ptr[0 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr] = x0; + assert [range_check_ptr + 1] = MAX_VALUE - x0; + tempvar x1 = sha256_ptr[1 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 2] = x1; + assert [range_check_ptr + 3] = MAX_VALUE - x1; + tempvar x2 = sha256_ptr[2 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 4] = x2; + assert [range_check_ptr + 5] = MAX_VALUE - x2; + tempvar x3 = sha256_ptr[3 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 6] = x3; + assert [range_check_ptr + 7] = MAX_VALUE - x3; + tempvar x4 = sha256_ptr[4 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 8] = x4; + assert [range_check_ptr + 9] = MAX_VALUE - x4; + tempvar x5 = sha256_ptr[5 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 10] = x5; + assert [range_check_ptr + 11] = MAX_VALUE - x5; + tempvar x6 = sha256_ptr[6 * SHA256_INSTANCE_SIZE]; + assert [range_check_ptr + 12] = x6; + assert [range_check_ptr + 13] = MAX_VALUE - x6; + + assert outputs[0] = x0 + 2 ** 35 * x1 + 2 ** (35 * 2) * x2 + 2 ** (35 * 3) * x3 + 2 ** ( + 35 * 4 + ) * x4 + 2 ** (35 * 5) * x5 + 2 ** (35 * 6) * x6; + + tempvar outputs = outputs + 1; + tempvar sha256_ptr = sha256_ptr + 1; + tempvar range_check_ptr = range_check_ptr + 14; + tempvar m = m - 1; + jmp output_loop if m != 0; + + return _finalize_sha256_inner( + sha256_ptr=sha256_start + SHA256_INSTANCE_SIZE * BLOCK_SIZE, + n=n - 1, + round_constants=round_constants, + ); + } + + // Verifies that the results of sha256() are valid. + // Taken from: https://github.com/starkware-libs/cairo-examples/blob/0d88b41bffe3de112d98986b8b0afa795f9d67a0/sha256/sha256.cairo#L246 + func finalize_sha256{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + sha256_ptr_start: felt*, sha256_ptr_end: felt* + ) { + alloc_locals; + + let (__fp__, _) = get_fp_and_pc(); + + let (round_constants) = get_round_constants(); + + // We reuse the output state of the previous chunk as input to the next. + tempvar n = (sha256_ptr_end - sha256_ptr_start) / SHA256_INSTANCE_SIZE; + if (n == 0) { + return (); + } + + %{ + # Add dummy pairs of input and output. + from starkware.cairo.common.cairo_sha256.sha256_utils import ( + IV, compute_message_schedule, sha2_compress_function) + + _block_size = int(ids.BLOCK_SIZE) + assert 0 <= _block_size < 20 + _sha256_input_chunk_size_felts = int(ids.SHA256_INPUT_CHUNK_SIZE_FELTS) + assert 0 <= _sha256_input_chunk_size_felts < 100 + + message = [0] * _sha256_input_chunk_size_felts + w = compute_message_schedule(message) + output = sha2_compress_function(IV, w) + padding = (message + IV + output) * (_block_size - 1) + segments.write_arg(ids.sha256_ptr_end, padding) + %} + + // Compute the amount of blocks (rounded up). + let (local q, r) = unsigned_div_rem(n + BLOCK_SIZE - 1, BLOCK_SIZE); + _finalize_sha256_inner(sha256_ptr_start, n=q, round_constants=round_constants); + return (); + } +} diff --git a/cairo/src/stack.cairo b/cairo/src/stack.cairo new file mode 100644 index 00000000..39dc868c --- /dev/null +++ b/cairo/src/stack.cairo @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import FALSE, TRUE +from starkware.cairo.common.default_dict import default_dict_new, default_dict_finalize +from starkware.cairo.common.dict import DictAccess, dict_read, dict_write +from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc +from starkware.cairo.common.uint256 import Uint256 + +from src.constants import Constants +from src.model import model +from src.utils.utils import Helpers + +// @title Stack related functions. +namespace Stack { + // @notice Initialize the stack. + // @return The pointer to the stack. + func init() -> model.Stack* { + let (dict_ptr_start: DictAccess*) = default_dict_new(0); + return new model.Stack(dict_ptr_start, dict_ptr_start, 0); + } + + // @notice Finalizes the stack. + // @param stack The pointer to the stack. + func finalize{range_check_ptr, stack: model.Stack*}() { + let (squashed_start, squashed_end) = default_dict_finalize( + stack.dict_ptr_start, stack.dict_ptr, 0 + ); + tempvar stack = new model.Stack(squashed_start, squashed_end, stack.size); + return (); + } + + // @notice Store an element into the stack. + // @param stack The pointer to the stack. + // @param element The element to push. + // @return stack The new pointer to the stack. + func push{stack: model.Stack*}(element: Uint256*) { + let dict_ptr = stack.dict_ptr; + with dict_ptr { + dict_write(stack.size, cast(element, felt)); + } + + tempvar stack = new model.Stack(stack.dict_ptr_start, dict_ptr, stack.size + 1); + return (); + } + + // @notice Store a uint128 into the stack. + // @param stack The pointer to the stack. + // @param element The element to push. + // @return stack The new pointer to the stack. + func push_uint128{stack: model.Stack*}(element: felt) { + tempvar item = new Uint256(element, 0); + push(item); + return (); + } + + // @notice Store a uint128 into the stack. + // @param stack The pointer to the stack. + // @param element The element to push. + // @return stack The new pointer to the stack. + func push_uint256{stack: model.Stack*}(element: Uint256) { + alloc_locals; + let fp_and_pc = get_fp_and_pc(); + local __fp__: felt* = fp_and_pc.fp_val; + push(&element); + return (); + } + + // @notice Pop N elements from the stack. + // @param stack The pointer to the stack. + // @param n The len of elements to pop. + // @return stack The new pointer to the stack. + // @return elements The pointer to the first popped element. + func pop_n{stack: model.Stack*}(n: felt) -> (elements: Uint256*) { + alloc_locals; + let dict_ptr = stack.dict_ptr; + + let (local items: felt*) = alloc(); + with dict_ptr { + Internals._read_n(index=stack.size - 1, n=n, output=items); + } + + tempvar stack = new model.Stack(stack.dict_ptr_start, dict_ptr, stack.size - n); + return (cast(items, Uint256*),); + } + + // @notice Pop an element from the stack. + // @param stack The pointer to the stack. + // @return stack The new pointer to the stack. + // @return element The popped element. + func pop{stack: model.Stack*}() -> (element: Uint256*) { + let dict_ptr = stack.dict_ptr; + + with dict_ptr { + let (pointer) = dict_read(stack.size - 1); + } + + tempvar stack = new model.Stack(stack.dict_ptr_start, dict_ptr, stack.size - 1); + return (cast(pointer, Uint256*),); + } + + // @notice Return a value from the stack at a given stack index. + // @dev stack_index is 0-based, 0 is the top of the stack. + // @param stack The pointer to the stack. + // @param stack_index The index of the element to return. + // @return stack The new pointer to the stack. + // @return value The element at the given index. + func peek{stack: model.Stack*}(stack_index: felt) -> (value: Uint256*) { + let dict_ptr = stack.dict_ptr; + + with dict_ptr { + let (pointer) = dict_read(stack.size - 1 - stack_index); + } + + tempvar stack = new model.Stack(stack.dict_ptr_start, dict_ptr, stack.size); + + return (cast(pointer, Uint256*),); + } + + // @notice Swap two elements in the stack. + // @dev i is 0-based, 0 is the top of the stack. + // @param stack The pointer to the stack. + // @param i The index of the second element to swap. + // @return stack The new pointer to the stack. + func swap_i{stack: model.Stack*}(i: felt) { + let dict_ptr = stack.dict_ptr; + + with dict_ptr { + let (pointer_top) = dict_read(stack.size - 1); + let (pointer_i) = dict_read(stack.size - 1 - i); + + dict_write(stack.size - 1, pointer_i); + dict_write(stack.size - 1 - i, pointer_top); + } + + tempvar stack = new model.Stack(stack.dict_ptr_start, dict_ptr, stack.size); + + return (); + } +} + +namespace Internals { + func _read_n{dict_ptr: DictAccess*}(index: felt, n: felt, output: felt*) { + if (n == 0) { + return (); + } + + let (pointer) = dict_read(index); + let item = cast(pointer, felt*); + assert [output] = [item]; + assert [output + 1] = [item + 1]; + + return _read_n(index - 1, n - 1, output + 2); + } +} diff --git a/cairo/src/state.cairo b/cairo/src/state.cairo new file mode 100644 index 00000000..4e0c6375 --- /dev/null +++ b/cairo/src/state.cairo @@ -0,0 +1,478 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.default_dict import default_dict_new, default_dict_finalize +from starkware.cairo.common.dict import dict_read, dict_write +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.uint256 import Uint256, uint256_le +from starkware.cairo.common.bool import FALSE, TRUE + +from src.account import Account +from src.model import model +from src.gas import Gas +from src.utils.dict import default_dict_copy +from src.utils.utils import Helpers +from src.utils.uint256 import uint256_add, uint256_sub, uint256_eq + +namespace State { + // @dev Create a new empty State + func init() -> model.State* { + let (accounts_start) = default_dict_new(0); + let (events: model.Event*) = alloc(); + let (transfers: model.Transfer*) = alloc(); + return new model.State( + accounts_start=accounts_start, + accounts=accounts_start, + events_len=0, + events=events, + transfers_len=0, + transfers=transfers, + ); + } + + // @dev Deep copy of the state, creating new memory segments + // @param self The pointer to the State + func copy{range_check_ptr, state: model.State*}() -> model.State* { + alloc_locals; + // accounts are a new memory segment + let (accounts_start, accounts) = default_dict_copy(state.accounts_start, state.accounts); + // for each account, storage is a new memory segment + Internals._copy_accounts{accounts=accounts}(accounts_start, accounts); + + let (local events: felt*) = alloc(); + memcpy(dst=events, src=state.events, len=state.events_len * model.Event.SIZE); + + let (local transfers: felt*) = alloc(); + memcpy(dst=transfers, src=state.transfers, len=state.transfers_len * model.Transfer.SIZE); + + tempvar state_copy = new model.State( + accounts_start=accounts_start, + accounts=accounts, + events_len=state.events_len, + events=cast(events, model.Event*), + transfers_len=state.transfers_len, + transfers=cast(transfers, model.Transfer*), + ); + return state_copy; + } + + // @dev Squash dicts used internally + func finalize{range_check_ptr, state: model.State*}() { + alloc_locals; + // First squash to get only one account per key + let (local accounts_start, accounts_end) = default_dict_finalize( + state.accounts_start, state.accounts, 0 + ); + + let (local accounts_copy: DictAccess*) = default_dict_new(0); + tempvar accounts_copy_start = accounts_copy; + // Squashes the storage dicts of accounts, and copy the result to a new memory segment. + Internals._copy_accounts{accounts=accounts_copy}(accounts_start, accounts_end); + + tempvar state = new model.State( + accounts_start=accounts_copy_start, + accounts=accounts_copy, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + return (); + } + + // @notice Get a given EVM Account + // @param evm_address The evm address of the Account + // @return The updated state + // @return The account + func get_account{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + evm_address: felt + ) -> model.Account* { + alloc_locals; + local accounts: DictAccess* = state.accounts; + let (pointer) = dict_read{dict_ptr=accounts}(key=evm_address); + + let account = cast(pointer, model.Account*); + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + return account; + } + + // @notice Cache precompiles accounts in the state, making them warm. + func cache_precompiles{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}() { + alloc_locals; + tempvar accounts_ptr = state.accounts; + with accounts_ptr { + Internals._cache_precompile(1); + Internals._cache_precompile(2); + Internals._cache_precompile(3); + Internals._cache_precompile(4); + Internals._cache_precompile(5); + Internals._cache_precompile(6); + Internals._cache_precompile(7); + Internals._cache_precompile(8); + Internals._cache_precompile(9); + Internals._cache_precompile(10); + } + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts_ptr, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + + return (); + } + + // @notice Cache the addresses and storage keys from the access list + // in the state, making them warm. + // @param access_list_len The length of the access list. Denotes the total number of `felts` in + // the access list. + // @param access_list The pointer to the access list. + // @return The gas cost of caching the access list. + func cache_access_list{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + access_list_len: felt, access_list: felt* + ) -> felt { + alloc_locals; + tempvar accounts_ptr = state.accounts; + with accounts_ptr { + let gas_cost = Internals._cache_access_list(access_list_len, access_list); + } + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts_ptr, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + + return gas_cost; + } + + // @notice Checks if an address is warm (has been accessed before or in access list). + // @dev This also warms up the account if it's not already warm. + // @param address The address to check. + // @return A boolean indicating whether the address is warm. + func is_account_warm{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + address: felt + ) -> felt { + alloc_locals; + let accounts = state.accounts; + let (pointer) = dict_read{dict_ptr=accounts}(key=address); + + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + + if (pointer != 0) { + return TRUE; + } else { + return FALSE; + } + } + + // @notice Checks if a storage slot is warm (has been accessed before) in an account. + // @dev Since this is only called in SSTORE/SLOAD opcodes, + // we consider that account and storage will be warmed up during the execution of the opcode. + // @param self The account to check. + // @param key The key of the storage slot to check. + // @return A boolean indicating whether the storage slot is warm. + func is_storage_warm{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + address: felt, key: Uint256* + ) -> felt { + alloc_locals; + + // Get the account + let accounts = state.accounts; + let (pointer) = dict_read{dict_ptr=accounts}(key=address); + if (pointer == 0) { + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + return FALSE; + } + + let (account, res) = Account.is_storage_warm(cast(pointer, model.Account*), key); + dict_write{dict_ptr=accounts}(key=account.address.evm, new_value=cast(account, felt)); + + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + return res; + } + + // @notice Updates the given account in the state. + // @param account The new account + func update_account{state: model.State*}(account: model.Account*) { + let accounts = state.accounts; + dict_write{dict_ptr=accounts}(key=account.address.evm, new_value=cast(account, felt)); + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + return (); + } + + // @notice Read a given storage + // @dev Try to retrieve in the local Dict first, if not already here + // read the contract storage and cache the result. + // @param evm_address The evm address of the account to read storage from. + // @param key The pointer to the storage key + func read_storage{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + evm_address: felt, key: Uint256* + ) -> Uint256* { + alloc_locals; + let account = get_account(evm_address); + let (account, value) = Account.read_storage(account, key); + update_account(account); + return value; + } + + // @notice Update a storage key with the given value + // @param evm_address The evm address of the account to write storage to. + // @param key The pointer to the Uint256 storage key + // @param value The pointer to the Uint256 value + func write_storage{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + evm_address: felt, key: Uint256*, value: Uint256* + ) { + alloc_locals; + let account = get_account(evm_address); + let account = Account.write_storage(account, key, value); + update_account(account); + return (); + } + + // @notice Reads the transient storage of an account at the given key. + // @param evm_address The EVM address of the account to read. + // @param key The key of the storage slot to read. + // @return The value of the storage slot. + func read_transient_storage{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + evm_address: felt, key: Uint256* + ) -> Uint256* { + alloc_locals; + let account = get_account(evm_address); + let (account, value) = Account.read_transient_storage(account, key); + update_account(account); + return value; + } + + // @notice Updates the transient storage of an account at the given key with the given value. + // @param evm_address The EVM address of the account to update. + // @param key The key of the storage slot to update. + // @param value The new value of the storage slot. + func write_transient_storage{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + evm_address: felt, key: Uint256*, value: Uint256* + ) { + alloc_locals; + let account = get_account(evm_address); + let account = Account.write_transient_storage(account, key, value); + update_account(account); + return (); + } + + // @notice Add an event to the Event* array + // @param event The pointer to the Event + // @return The updated State + func add_event{state: model.State*}(event: model.Event) { + assert state.events[state.events_len] = event; + + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=state.accounts, + events_len=state.events_len + 1, + events=state.events, + transfers_len=state.transfers_len, + transfers=state.transfers, + ); + return (); + } + + // @notice Add a transfer to the Transfer* array + // @param event The pointer to the Transfer + // @return The updated State + // @return The status of the transfer + func add_transfer{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + transfer: model.Transfer + ) -> felt { + alloc_locals; + // See https://docs.cairo-lang.org/0.12.0/how_cairo_works/functions.html#retrieving-registers + let fp_and_pc = get_fp_and_pc(); + local __fp__: felt* = fp_and_pc.fp_val; + + if (transfer.sender.evm == transfer.recipient.evm) { + return 1; + } + + let (null_transfer) = uint256_eq(transfer.amount, Uint256(0, 0)); + if (null_transfer != 0) { + return 1; + } + + let sender = get_account(transfer.sender.evm); + let (success) = uint256_le(transfer.amount, [sender.balance]); + + if (success == 0) { + return success; + } + + let recipient = get_account(transfer.recipient.evm); + + let (local sender_balance_new) = uint256_sub([sender.balance], transfer.amount); + let (local recipient_balance_new, carry) = uint256_add( + [recipient.balance], transfer.amount + ); + + let sender = Account.set_balance(sender, &sender_balance_new); + let recipient = Account.set_balance(recipient, &recipient_balance_new); + + let accounts = state.accounts; + dict_write{dict_ptr=accounts}(key=transfer.sender.evm, new_value=cast(sender, felt)); + dict_write{dict_ptr=accounts}(key=transfer.recipient.evm, new_value=cast(recipient, felt)); + assert state.transfers[state.transfers_len] = transfer; + + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=accounts, + events_len=state.events_len, + events=state.events, + transfers_len=state.transfers_len + 1, + transfers=state.transfers, + ); + return success; + } + + // @notice Check whether an account is both in the state and non empty. + // @param address EVM Address of the account that needs to be checked. + // @return is_alive TRUE if the account is alive. + func is_account_alive{pedersen_ptr: HashBuiltin*, range_check_ptr, state: model.State*}( + address: felt + ) -> felt { + alloc_locals; + // We can get from the state without disturbing the warm/cold status + // as this is always called after already checking the warm status. + let account = get_account(address); + + let nonce = account.nonce; + let code_len = account.code_len; + let balance = account.balance; + + // an account is alive if it has nonce, code or balance + if (nonce + code_len + balance.low + balance.high != 0) { + return TRUE; + } + + return FALSE; + } +} + +namespace Internals { + // @notice Iterate through the accounts dict and copy them + // @dev Should be applied on a squashed dict + // @param accounts_start The dict start pointer + // @param accounts_end The dict end pointer + func _copy_accounts{range_check_ptr, accounts: DictAccess*}( + accounts_start: DictAccess*, accounts_end: DictAccess* + ) { + if (accounts_start == accounts_end) { + return (); + } + + if (accounts_start.new_value == 0) { + // If we do a dict_read on an unexisting account, `prev_value` and `new_value` are set to 0. + // However we expected pointers to model.Account, and casting 0 to model.Account* will + // cause a "Memory address must be relocatable" error. + return _copy_accounts(accounts_start + DictAccess.SIZE, accounts_end); + } + + let account = cast(accounts_start.new_value, model.Account*); + let account = Account.copy(account); + dict_write{dict_ptr=accounts}(key=accounts_start.key, new_value=cast(account, felt)); + + return _copy_accounts(accounts_start + DictAccess.SIZE, accounts_end); + } + + func _cache_precompile{pedersen_ptr: HashBuiltin*, range_check_ptr, accounts_ptr: DictAccess*}( + evm_address: felt + ) { + alloc_locals; + tempvar address = new model.Address(starknet=0xdead, evm=evm_address); + // TODO: precompiles can have balance + tempvar balance_ptr = new Uint256(0, 0); + let (bytecode) = alloc(); + // empty code hash see https://eips.ethereum.org/EIPS/eip-1052 + tempvar code_hash_ptr = new Uint256( + 304396909071904405792975023732328604784, 262949717399590921288928019264691438528 + ); + let account = Account.init( + address=address, + code_len=0, + code=bytecode, + code_hash=code_hash_ptr, + nonce=0, + balance=balance_ptr, + ); + dict_write{dict_ptr=accounts_ptr}(key=address.evm, new_value=cast(account, felt)); + return (); + } + + func _cache_access_list{pedersen_ptr: HashBuiltin*, range_check_ptr, accounts_ptr: DictAccess*}( + access_list_len: felt, access_list: felt* + ) -> felt { + alloc_locals; + + if (access_list_len == 0) { + return 0; + } + + let address = [access_list]; + let storage_keys_len = [access_list + 1]; + // Access list can contain several entries for the same account, so the account + // may already be in the state. If not, we need to fetch it from the contract storage. + let (account_ptr) = dict_read{dict_ptr=accounts_ptr}(key=address); + tempvar account = cast(account_ptr, model.Account*); + + let pedersen_ptr = cast([ap - 3], HashBuiltin*); + let range_check_ptr = [ap - 2]; + let account = cast([ap - 1], model.Account*); + + let account = Account.cache_storage_keys( + account, storage_keys_len, cast(access_list + 2, Uint256*) + ); + dict_write{dict_ptr=accounts_ptr}(key=address, new_value=cast(account, felt)); + + // storage_keys_len tracks the count of storage keys (of Uint256 type). + // Each storage key takes 2 felt each + tempvar item_len = 2 + storage_keys_len * Uint256.SIZE; + let cum_gas_cost = _cache_access_list(access_list_len - item_len, access_list + item_len); + return cum_gas_cost + Gas.TX_ACCESS_LIST_ADDRESS_COST + storage_keys_len * + Gas.TX_ACCESS_LIST_STORAGE_KEY_COST; + } +} diff --git a/cairo/src/utils/alt_bn128/alt_bn128_def.cairo b/cairo/src/utils/alt_bn128/alt_bn128_def.cairo new file mode 100644 index 00000000..ec2e396d --- /dev/null +++ b/cairo/src/utils/alt_bn128/alt_bn128_def.cairo @@ -0,0 +1,18 @@ +// Library copied from https://github.com/tekkac/cairo-alt_bn128 + +// Basic definitions for the alt_bn128 elliptic curve. +// The curve is given by the equation +// y^2 = x^3 + 3 +// over the field Z/p for +// p = p(u) = 36u^4 + 36u^3 + 24u^2 + 6u + 1 +// const p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 +const P0 = 0x31ca8d3c208c16d87cfd47; +const P1 = 0x16da060561765e05aa45a1; +const P2 = 0x30644e72e131a029b8504; + +// The following constants represent the size of the curve: +// n = n(u) = 36u^4 + 36u^3 + 18u^2 + 6u + 1 +// const n = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +const N0 = 0x39709143e1f593f0000001; +const N1 = 0x16da06056174a0cfa121e6; +const N2 = 0x30644e72e131a029b8504; diff --git a/cairo/src/utils/alt_bn128/alt_bn128_field.cairo b/cairo/src/utils/alt_bn128/alt_bn128_field.cairo new file mode 100644 index 00000000..2019db0f --- /dev/null +++ b/cairo/src/utils/alt_bn128/alt_bn128_field.cairo @@ -0,0 +1,552 @@ +// Library copied from https://github.com/tekkac/cairo-alt_bn128 + +// Starkware dependencies +from starkware.cairo.common.bitwise import bitwise_and +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin + +// Internal dependencies +from src.utils.alt_bn128.bigint import ( + BASE, + BigInt3, + UnreducedBigInt3, + UnreducedBigInt5, + nondet_bigint3, + bigint_mul, +) +from src.utils.alt_bn128.alt_bn128_def import P0, P1, P2 + +// FIELD STRUCTURES +struct FQ2 { + e0: BigInt3, + e1: BigInt3, +} + +struct FQ12 { + e0: BigInt3, + e1: BigInt3, + e2: BigInt3, + e3: BigInt3, + e4: BigInt3, + e5: BigInt3, + e6: BigInt3, + e7: BigInt3, + e8: BigInt3, + e9: BigInt3, + eA: BigInt3, + eB: BigInt3, +} + +struct unreducedFQ12 { + e0: UnreducedBigInt5, + e1: UnreducedBigInt5, + e2: UnreducedBigInt5, + e3: UnreducedBigInt5, + e4: UnreducedBigInt5, + e5: UnreducedBigInt5, + e6: UnreducedBigInt5, + e7: UnreducedBigInt5, + e8: UnreducedBigInt5, + e9: UnreducedBigInt5, + eA: UnreducedBigInt5, + eB: UnreducedBigInt5, +} + +// FIELD CONSTANTS +func fq_zero() -> (res: BigInt3) { + return (BigInt3(0, 0, 0),); +} + +func fq2_zero() -> (res: FQ2) { + return (FQ2(e0=BigInt3(0, 0, 0), e1=BigInt3(0, 0, 0)),); +} + +func fq12_zero() -> (res: FQ12) { + return ( + FQ12( + e0=BigInt3(0, 0, 0), + e1=BigInt3(0, 0, 0), + e2=BigInt3(0, 0, 0), + e3=BigInt3(0, 0, 0), + e4=BigInt3(0, 0, 0), + e5=BigInt3(0, 0, 0), + e6=BigInt3(0, 0, 0), + e7=BigInt3(0, 0, 0), + e8=BigInt3(0, 0, 0), + e9=BigInt3(0, 0, 0), + eA=BigInt3(0, 0, 0), + eB=BigInt3(0, 0, 0), + ), + ); +} + +func fq12_one() -> (res: FQ12) { + return ( + FQ12( + e0=BigInt3(1, 0, 0), + e1=BigInt3(0, 0, 0), + e2=BigInt3(0, 0, 0), + e3=BigInt3(0, 0, 0), + e4=BigInt3(0, 0, 0), + e5=BigInt3(0, 0, 0), + e6=BigInt3(0, 0, 0), + e7=BigInt3(0, 0, 0), + e8=BigInt3(0, 0, 0), + e9=BigInt3(0, 0, 0), + eA=BigInt3(0, 0, 0), + eB=BigInt3(0, 0, 0), + ), + ); +} + +func verify_zero3{range_check_ptr}(val: BigInt3) { + alloc_locals; + local flag; + local q; + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.cairo.common.math_utils import as_int + + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + + v = pack(ids.val, PRIME) + q, r = divmod(v, P) + assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." + + ids.flag = 1 if q > 0 else 0 + q = q if q > 0 else 0-q + ids.q = q % PRIME + %} + assert [range_check_ptr] = q + 2 ** 127; + + tempvar carry1 = ((2 * flag - 1) * q * P0 - val.d0) / BASE; + assert [range_check_ptr + 1] = carry1 + 2 ** 127; + + tempvar carry2 = ((2 * flag - 1) * q * P1 - val.d1 + carry1) / BASE; + assert [range_check_ptr + 2] = carry2 + 2 ** 127; + + assert (2 * flag - 1) * q * P2 - val.d2 + carry2 = 0; + + let range_check_ptr = range_check_ptr + 3; + + return (); +} + +func verify_zero5{range_check_ptr}(val: UnreducedBigInt5) { + alloc_locals; + local flag; + local q1; + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.cairo.common.math_utils import as_int + + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + + v3 = as_int(ids.val.d3, PRIME) + v4 = as_int(ids.val.d4, PRIME) + v = pack(ids.val, PRIME) + v3*2**258 + v4*2**344 + + q, r = divmod(v, P) + assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2, ids.val.d3, ids.val.d4}." + + # Since q usually doesn't fit BigInt3, divide it again + ids.flag = 1 if q > 0 else 0 + q = q if q > 0 else 0-q + q1, q2 = divmod(q, P) + ids.q1 = q1 + value = k = q2 + %} + let (k) = nondet_bigint3(); + let fullk = BigInt3(q1 * P0 + k.d0, q1 * P1 + k.d1, q1 * P2 + k.d2); + let P = BigInt3(P0, P1, P2); + let (k_n) = bigint_mul(fullk, P); + + // val mod n = 0, so val = k_n + tempvar carry1 = ((2 * flag - 1) * k_n.d0 - val.d0) / BASE; + assert [range_check_ptr + 0] = carry1 + 2 ** 127; + + tempvar carry2 = ((2 * flag - 1) * k_n.d1 - val.d1 + carry1) / BASE; + assert [range_check_ptr + 1] = carry2 + 2 ** 127; + + tempvar carry3 = ((2 * flag - 1) * k_n.d2 - val.d2 + carry2) / BASE; + assert [range_check_ptr + 2] = carry3 + 2 ** 127; + + tempvar carry4 = ((2 * flag - 1) * k_n.d3 - val.d3 + carry3) / BASE; + assert [range_check_ptr + 3] = carry4 + 2 ** 127; + + assert (2 * flag - 1) * k_n.d4 - val.d4 + carry4 = 0; + + let range_check_ptr = range_check_ptr + 4; + + return (); +} + +// returns 1 if x ==0 mod alt_bn128 prime +func is_zero{range_check_ptr}(x: BigInt3) -> (res: felt) { + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + x = pack(ids.x, PRIME) % P + %} + if (nondet %{ x == 0 %} != 0) { + verify_zero3(x); + // verify_zero5(UnreducedBigInt5(d0=x.d0, d1=x.d1, d2=x.d2, d3=0, d4=0)) + return (res=1); + } + + %{ + from starkware.python.math_utils import div_mod + value = x_inv = div_mod(1, x, P) + %} + let (x_inv) = nondet_bigint3(); + let (x_x_inv) = bigint_mul(x, x_inv); + + // Check that x * x_inv = 1 to verify that x != 0. + verify_zero5( + UnreducedBigInt5( + d0=x_x_inv.d0 - 1, d1=x_x_inv.d1, d2=x_x_inv.d2, d3=x_x_inv.d3, d4=x_x_inv.d4 + ), + ); + return (res=0); +} + +// FQ12 verify + +func verify_zero_fq12{range_check_ptr}(x: FQ12) { + verify_zero3(x.e0); + verify_zero3(x.e1); + verify_zero3(x.e2); + verify_zero3(x.e3); + verify_zero3(x.e4); + verify_zero3(x.e5); + verify_zero3(x.e6); + verify_zero3(x.e7); + verify_zero3(x.e8); + verify_zero3(x.e9); + verify_zero3(x.eA); + verify_zero3(x.eB); + return (); +} + +func fq_eq_zero(x: BigInt3) -> (res: felt) { + if (x.d0 != 0) { + return (res=0); + } + if (x.d1 != 0) { + return (res=0); + } + if (x.d2 != 0) { + return (res=0); + } + return (res=1); +} + +func fq12_eq_zero(x: FQ12) -> (res: felt) { + let (e0_is_zero) = fq_eq_zero(x.e0); + if (e0_is_zero == 0) { + return (res=0); + } + let (e1_is_zero) = fq_eq_zero(x.e1); + if (e1_is_zero == 0) { + return (res=0); + } + let (e2_is_zero) = fq_eq_zero(x.e2); + if (e2_is_zero == 0) { + return (res=0); + } + let (e3_is_zero) = fq_eq_zero(x.e3); + if (e3_is_zero == 0) { + return (res=0); + } + let (e4_is_zero) = fq_eq_zero(x.e4); + if (e4_is_zero == 0) { + return (res=0); + } + let (e5_is_zero) = fq_eq_zero(x.e5); + if (e5_is_zero == 0) { + return (res=0); + } + let (e6_is_zero) = fq_eq_zero(x.e6); + if (e6_is_zero == 0) { + return (res=0); + } + let (e7_is_zero) = fq_eq_zero(x.e7); + if (e7_is_zero == 0) { + return (res=0); + } + let (e8_is_zero) = fq_eq_zero(x.e8); + if (e8_is_zero == 0) { + return (res=0); + } + let (e9_is_zero) = fq_eq_zero(x.e9); + if (e9_is_zero == 0) { + return (res=0); + } + let (eA_is_zero) = fq_eq_zero(x.eA); + if (eA_is_zero == 0) { + return (res=0); + } + let (eB_is_zero) = fq_eq_zero(x.eB); + if (eB_is_zero == 0) { + return (res=0); + } + return (res=1); +} + +func fq12_is_zero{range_check_ptr}(x: FQ12) -> (res: felt) { + %{ + import sys, os + cwd = os.getcwd() + sys.path.append(cwd) + + from utils.bn128_field import FQ, FQ12 + from utils.bn128_utils import parse_fq12 + + val = list(map(FQ, parse_fq12(ids.x))) + + if FQ12(val) == FQ12([0]*12): + x = 0 + else: + x = 1 + %} + if (nondet %{ x == 0 %} != 0) { + verify_zero_fq12(x); + return (res=1); + } + + %{ + val = list(map(FQ, parse_fq12(ids.x))) + val = FQ12(val).inv() + value = list(map(lambda x: x.n, val.coeffs)) + %} + let (x_inv) = nondet_fq12(); + + // TODO VERIF x * x_inv - 1 = 0 + return (res=0); +} + +// Difference of two FQ12, resulting FQ12 BigInt3 limbs can be negative +func fq12_diff(x: FQ12, y: FQ12) -> (res: FQ12) { + return ( + res=FQ12( + BigInt3(d0=x.e0.d0 - y.e0.d0, d1=x.e0.d1 - y.e0.d1, d2=x.e0.d2 - y.e0.d2), + BigInt3(d0=x.e1.d0 - y.e1.d0, d1=x.e1.d1 - y.e1.d1, d2=x.e1.d2 - y.e1.d2), + BigInt3(d0=x.e2.d0 - y.e2.d0, d1=x.e2.d1 - y.e2.d1, d2=x.e2.d2 - y.e2.d2), + BigInt3(d0=x.e3.d0 - y.e3.d0, d1=x.e3.d1 - y.e3.d1, d2=x.e3.d2 - y.e3.d2), + BigInt3(d0=x.e4.d0 - y.e4.d0, d1=x.e4.d1 - y.e4.d1, d2=x.e4.d2 - y.e4.d2), + BigInt3(d0=x.e5.d0 - y.e5.d0, d1=x.e5.d1 - y.e5.d1, d2=x.e5.d2 - y.e5.d2), + BigInt3(d0=x.e6.d0 - y.e6.d0, d1=x.e6.d1 - y.e6.d1, d2=x.e6.d2 - y.e6.d2), + BigInt3(d0=x.e7.d0 - y.e7.d0, d1=x.e7.d1 - y.e7.d1, d2=x.e7.d2 - y.e7.d2), + BigInt3(d0=x.e8.d0 - y.e8.d0, d1=x.e8.d1 - y.e8.d1, d2=x.e8.d2 - y.e8.d2), + BigInt3(d0=x.e9.d0 - y.e9.d0, d1=x.e9.d1 - y.e9.d1, d2=x.e9.d2 - y.e9.d2), + BigInt3(d0=x.eA.d0 - y.eA.d0, d1=x.eA.d1 - y.eA.d1, d2=x.eA.d2 - y.eA.d2), + BigInt3(d0=x.eB.d0 - y.eB.d0, d1=x.eB.d1 - y.eB.d1, d2=x.eB.d2 - y.eB.d2), + ), + ); +} + +func fq12_sum(x: FQ12, y: FQ12) -> (res: FQ12) { + return ( + res=FQ12( + BigInt3(d0=x.e0.d0 + y.e0.d0, d1=x.e0.d1 + y.e0.d1, d2=x.e0.d2 + y.e0.d2), + BigInt3(d0=x.e1.d0 + y.e1.d0, d1=x.e1.d1 + y.e1.d1, d2=x.e1.d2 + y.e1.d2), + BigInt3(d0=x.e2.d0 + y.e2.d0, d1=x.e2.d1 + y.e2.d1, d2=x.e2.d2 + y.e2.d2), + BigInt3(d0=x.e3.d0 + y.e3.d0, d1=x.e3.d1 + y.e3.d1, d2=x.e3.d2 + y.e3.d2), + BigInt3(d0=x.e4.d0 + y.e4.d0, d1=x.e4.d1 + y.e4.d1, d2=x.e4.d2 + y.e4.d2), + BigInt3(d0=x.e5.d0 + y.e5.d0, d1=x.e5.d1 + y.e5.d1, d2=x.e5.d2 + y.e5.d2), + BigInt3(d0=x.e6.d0 + y.e6.d0, d1=x.e6.d1 + y.e6.d1, d2=x.e6.d2 + y.e6.d2), + BigInt3(d0=x.e7.d0 + y.e7.d0, d1=x.e7.d1 + y.e7.d1, d2=x.e7.d2 + y.e7.d2), + BigInt3(d0=x.e8.d0 + y.e8.d0, d1=x.e8.d1 + y.e8.d1, d2=x.e8.d2 + y.e8.d2), + BigInt3(d0=x.e9.d0 + y.e9.d0, d1=x.e9.d1 + y.e9.d1, d2=x.e9.d2 + y.e9.d2), + BigInt3(d0=x.eA.d0 + y.eA.d0, d1=x.eA.d1 + y.eA.d1, d2=x.eA.d2 + y.eA.d2), + BigInt3(d0=x.eB.d0 + y.eB.d0, d1=x.eB.d1 + y.eB.d1, d2=x.eB.d2 + y.eB.d2), + ), + ); +} + +// TODO + +// FIELD MULTIPLICATION + +// func ufq12_mul{range_check_ptr}(a : FQ12, b : FQ12) -> (res : unreducedFQ12): +// let ab_e0 = bigint_mul(a.e0, b.d0) +// let ab_e0 = bigint_mul(a.e0, b.d0) +// return ( +// unreducedFQ12( +// e0= + +// end + +// TODO deterministic (unreduced FQ12?) +func fq12_mul{range_check_ptr}(a: FQ12, b: FQ12) -> (res: FQ12) { + %{ + import sys, os + cwd = os.getcwd() + sys.path.append(cwd) + from utils.bn128_field import FQ, FQ12 + from utils.bn128_utils import parse_fq12, print_g12 + a = FQ12(list(map(FQ, parse_fq12(ids.a)))) + b = FQ12(list(map(FQ, parse_fq12(ids.b)))) + value = res = list(map(lambda x: x.n, (a*b).coeffs)) + # print("a*b =", value) + %} + let (res) = nondet_fq12(); + // TODO CHECKS + return (res=res); +} + +func fq12_pow_inner{range_check_ptr}(x: FQ12, n: felt, m: felt) -> (pow2: FQ12, res: FQ12) { + if (m == 0) { + assert n = 0; + let (one) = fq12_one(); + return (pow2=x, res=one); + } + + alloc_locals; + let (x_sqr) = fq12_mul(x, x); + + %{ memory[ap] = (ids.n % PRIME) % 2 %} + jmp odd if [ap] != 0, ap++; + return fq12_pow_inner(x=x_sqr, n=n / 2, m=m - 1); + + odd: + let (inner_pow, inner_res) = fq12_pow_inner(x=x_sqr, n=(n - 1) / 2, m=m - 1); + let (res) = fq12_mul(inner_res, x); + return (inner_pow, res); +} + +func fq12_pow_3{range_check_ptr}(x: FQ12, n: BigInt3) -> (pow2: FQ12, res: FQ12) { + alloc_locals; + let (pow2_0: FQ12, local res0: FQ12) = fq12_pow_inner(x, n.d0, 86); + let (pow2_1: FQ12, local res1: FQ12) = fq12_pow_inner(pow2_0, n.d1, 86); + let (pow2_2, local res2: FQ12) = fq12_pow_inner(pow2_1, n.d2, 86); + let (res: FQ12) = fq12_mul(res0, res1); + let (res: FQ12) = fq12_mul(res, res2); + return (pow2_2, res); +} + +func fq12_pow_12{range_check_ptr}(x: FQ12, n: FQ12) -> (res: FQ12) { + alloc_locals; + let (pow2_0: FQ12, local res0: FQ12) = fq12_pow_3(x, n.e0); + let (pow2_1: FQ12, local res1: FQ12) = fq12_pow_3(pow2_0, n.e1); + let (pow2_2: FQ12, local res2: FQ12) = fq12_pow_3(pow2_1, n.e2); + let (pow2_3: FQ12, local res3: FQ12) = fq12_pow_3(pow2_2, n.e3); + let (pow2_4: FQ12, local res4: FQ12) = fq12_pow_3(pow2_3, n.e4); + let (pow2_5: FQ12, local res5: FQ12) = fq12_pow_3(pow2_4, n.e5); + let (pow2_6: FQ12, local res6: FQ12) = fq12_pow_3(pow2_5, n.e6); + let (pow2_7: FQ12, local res7: FQ12) = fq12_pow_3(pow2_6, n.e7); + let (pow2_8: FQ12, local res8: FQ12) = fq12_pow_3(pow2_7, n.e8); + let (pow2_9: FQ12, local res9: FQ12) = fq12_pow_3(pow2_8, n.e9); + let (pow2_A: FQ12, local resA: FQ12) = fq12_pow_3(pow2_9, n.eA); + // Simplifications since eB = 0 + // let (pow2_B : FQ12, local resB : FQ12) = fq12_pow_3(pow2_A, n.eB) + let (local res01: FQ12) = fq12_mul(res0, res1); + let (local res23: FQ12) = fq12_mul(res2, res3); + let (local res45: FQ12) = fq12_mul(res4, res5); + let (local res67: FQ12) = fq12_mul(res6, res7); + let (local res89: FQ12) = fq12_mul(res8, res9); + // let (local resAB : FQ12) = fq12_mul(resA, resB) + let (local res0123: FQ12) = fq12_mul(res01, res23); + let (local res4567: FQ12) = fq12_mul(res45, res67); + // let (local res89AB : FQ12) = fq12_mul(res89, resAB) + let (local res89A: FQ12) = fq12_mul(res89, resA); + let (local res0123: FQ12) = fq12_mul(res01, res23); + let (local res0__7: FQ12) = fq12_mul(res0123, res4567); + let (res: FQ12) = fq12_mul(res0__7, res89A); + return (res,); +} + +// Hint argument: value +// a 12 element list of field elements +func nondet_fq12{range_check_ptr}() -> (res: FQ12) { + let res: FQ12 = [cast(ap + 38, FQ12*)]; + %{ + from starkware.cairo.common.cairo_secp.secp_utils import split + + r = ids.res + var_list = [r.e0, r.e1, r.e2, r.e3, r.e4, r.e5, + r.e6, r.e7, r.e8, r.e9, r.eA, r.eB] + #segments.write_arg(ids.res.e0.address_, split(val[0])) + for (var, val) in zip(var_list, value): + segments.write_arg(var.address_, split(val)) + %} + const MAX_SUM = 12 * 3 * (2 ** 86 - 1); + // TODO RANGE CHECKS? (WHY THE ASSERT LIKE THIS BTW?) + assert [range_check_ptr] = MAX_SUM - ( + res.e0.d0 + + res.e0.d1 + + res.e0.d2 + + res.e1.d0 + + res.e1.d1 + + res.e1.d2 + + res.e2.d0 + + res.e2.d1 + + res.e2.d2 + + res.e3.d0 + + res.e3.d1 + + res.e3.d2 + + res.e4.d0 + + res.e4.d1 + + res.e4.d2 + + res.e5.d0 + + res.e5.d1 + + res.e5.d2 + + res.e6.d0 + + res.e6.d1 + + res.e6.d2 + + res.e7.d0 + + res.e7.d1 + + res.e7.d2 + + res.e8.d0 + + res.e8.d1 + + res.e8.d2 + + res.e9.d0 + + res.e9.d1 + + res.e9.d2 + + res.eA.d0 + + res.eA.d1 + + res.eA.d2 + + res.eB.d0 + + res.eB.d1 + + res.eB.d2 + ); + + tempvar range_check_ptr = range_check_ptr + 37; + [range_check_ptr - 1] = res.e0.d0, ap++; + [range_check_ptr - 2] = res.e0.d1, ap++; + [range_check_ptr - 3] = res.e0.d2, ap++; + [range_check_ptr - 4] = res.e1.d0, ap++; + [range_check_ptr - 5] = res.e1.d1, ap++; + [range_check_ptr - 6] = res.e1.d2, ap++; + [range_check_ptr - 7] = res.e2.d0, ap++; + [range_check_ptr - 8] = res.e2.d1, ap++; + [range_check_ptr - 9] = res.e2.d2, ap++; + [range_check_ptr - 10] = res.e3.d0, ap++; + [range_check_ptr - 11] = res.e3.d1, ap++; + [range_check_ptr - 12] = res.e3.d2, ap++; + [range_check_ptr - 13] = res.e4.d0, ap++; + [range_check_ptr - 14] = res.e4.d1, ap++; + [range_check_ptr - 15] = res.e4.d2, ap++; + [range_check_ptr - 16] = res.e5.d0, ap++; + [range_check_ptr - 17] = res.e5.d1, ap++; + [range_check_ptr - 18] = res.e5.d2, ap++; + [range_check_ptr - 19] = res.e6.d0, ap++; + [range_check_ptr - 20] = res.e6.d1, ap++; + [range_check_ptr - 21] = res.e6.d2, ap++; + [range_check_ptr - 22] = res.e7.d0, ap++; + [range_check_ptr - 23] = res.e7.d1, ap++; + [range_check_ptr - 24] = res.e7.d2, ap++; + [range_check_ptr - 25] = res.e8.d0, ap++; + [range_check_ptr - 26] = res.e8.d1, ap++; + [range_check_ptr - 27] = res.e8.d2, ap++; + [range_check_ptr - 28] = res.e9.d0, ap++; + [range_check_ptr - 29] = res.e9.d1, ap++; + [range_check_ptr - 30] = res.e9.d2, ap++; + [range_check_ptr - 31] = res.eA.d0, ap++; + [range_check_ptr - 32] = res.eA.d1, ap++; + [range_check_ptr - 33] = res.eA.d2, ap++; + [range_check_ptr - 34] = res.eB.d0, ap++; + [range_check_ptr - 35] = res.eB.d1, ap++; + [range_check_ptr - 36] = res.eB.d2, ap++; + static_assert &res + FQ12.SIZE == ap; + return (res=res); +} diff --git a/cairo/src/utils/alt_bn128/alt_bn128_g1.cairo b/cairo/src/utils/alt_bn128/alt_bn128_g1.cairo new file mode 100644 index 00000000..2cee41fc --- /dev/null +++ b/cairo/src/utils/alt_bn128/alt_bn128_g1.cairo @@ -0,0 +1,334 @@ +// Library copied from https://github.com/tekkac/cairo-alt_bn128 + +// Starkware dependencies +from starkware.cairo.common.cairo_secp.bigint import UnreducedBigInt3, BigInt3 + +// Internal dependencies +from src.utils.alt_bn128.bigint import nondet_bigint3, UnreducedBigInt5, bigint_mul +from src.utils.alt_bn128.alt_bn128_field import is_zero, verify_zero5 +from src.utils.alt_bn128.alt_bn128_def import P0, P1, P2 + +// Represents a point on the elliptic curve. +// The zero point is represented using pt.x=0, as there is no point on the curve with this x value. +struct G1Point { + x: BigInt3, + y: BigInt3, +} + +namespace ALT_BN128 { + // Returns the slope of the elliptic curve at the given point. + // The slope is used to compute pt + pt. + // Assumption: pt != 0. + func compute_doubling_slope{range_check_ptr}(pt: G1Point) -> (slope: BigInt3) { + // Note that y cannot be zero: assume that it is, then pt = -pt, so 2 * pt = 0, which + // contradicts the fact that the size of the curve is odd. + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import div_mod + + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + + # Compute the slope. + x = pack(ids.pt.x, PRIME) + y = pack(ids.pt.y, PRIME) + value = slope = div_mod(3 * x ** 2, 2 * y, P) + %} + let (slope: BigInt3) = nondet_bigint3(); + + let (x_sqr: UnreducedBigInt5) = bigint_mul(pt.x, pt.x); + let (slope_y: UnreducedBigInt5) = bigint_mul(slope, pt.y); + + verify_zero5( + UnreducedBigInt5( + d0=3 * x_sqr.d0 - 2 * slope_y.d0, + d1=3 * x_sqr.d1 - 2 * slope_y.d1, + d2=3 * x_sqr.d2 - 2 * slope_y.d2, + d3=3 * x_sqr.d3 - 2 * slope_y.d3, + d4=3 * x_sqr.d4 - 2 * slope_y.d4, + ), + ); + + return (slope=slope); + } + + // Returns the slope of the line connecting the two given points. + // The slope is used to compute pt0 + pt1. + // Assumption: pt0.x != pt1.x (mod field prime). + func compute_slope{range_check_ptr}(pt0: G1Point, pt1: G1Point) -> (slope: BigInt3) { + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import div_mod + + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + # Compute the slope. + x0 = pack(ids.pt0.x, PRIME) + y0 = pack(ids.pt0.y, PRIME) + x1 = pack(ids.pt1.x, PRIME) + y1 = pack(ids.pt1.y, PRIME) + value = slope = div_mod(y0 - y1, x0 - x1, P) + %} + let (slope) = nondet_bigint3(); + + let x_diff = BigInt3( + d0=pt0.x.d0 - pt1.x.d0, d1=pt0.x.d1 - pt1.x.d1, d2=pt0.x.d2 - pt1.x.d2 + ); + let (x_diff_slope: UnreducedBigInt5) = bigint_mul(x_diff, slope); + + verify_zero5( + UnreducedBigInt5( + d0=x_diff_slope.d0 - pt0.y.d0 + pt1.y.d0, + d1=x_diff_slope.d1 - pt0.y.d1 + pt1.y.d1, + d2=x_diff_slope.d2 - pt0.y.d2 + pt1.y.d2, + d3=x_diff_slope.d3, + d4=x_diff_slope.d4, + ), + ); + + return (slope,); + } + + // Given a point 'pt' on the elliptic curve, computes pt + pt. + func ec_double{range_check_ptr}(pt: G1Point) -> (res: G1Point) { + if (pt.x.d0 == 0) { + if (pt.x.d1 == 0) { + if (pt.x.d2 == 0) { + return (pt,); + } + } + } + + let (slope: BigInt3) = compute_doubling_slope(pt); + let (slope_sqr: UnreducedBigInt5) = bigint_mul(slope, slope); + + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + slope = pack(ids.slope, PRIME) + x = pack(ids.pt.x, PRIME) + y = pack(ids.pt.y, PRIME) + + value = new_x = (pow(slope, 2, P) - 2 * x) % P + %} + let (new_x: BigInt3) = nondet_bigint3(); + + %{ value = new_y = (slope * (x - new_x) - y) % P %} + let (new_y: BigInt3) = nondet_bigint3(); + + verify_zero5( + UnreducedBigInt5( + d0=slope_sqr.d0 - new_x.d0 - 2 * pt.x.d0, + d1=slope_sqr.d1 - new_x.d1 - 2 * pt.x.d1, + d2=slope_sqr.d2 - new_x.d2 - 2 * pt.x.d2, + d3=slope_sqr.d3, + d4=slope_sqr.d4, + ), + ); + + let (x_diff_slope: UnreducedBigInt5) = bigint_mul( + BigInt3(d0=pt.x.d0 - new_x.d0, d1=pt.x.d1 - new_x.d1, d2=pt.x.d2 - new_x.d2), slope + ); + + verify_zero5( + UnreducedBigInt5( + d0=x_diff_slope.d0 - pt.y.d0 - new_y.d0, + d1=x_diff_slope.d1 - pt.y.d1 - new_y.d1, + d2=x_diff_slope.d2 - pt.y.d2 - new_y.d2, + d3=x_diff_slope.d3, + d4=x_diff_slope.d4, + ), + ); + + return (G1Point(new_x, new_y),); + } + + // Adds two points on the elliptic curve. + // Assumption: pt0.x != pt1.x (however, pt0 = pt1 = 0 is allowed). + // Note that this means that the function cannot be used if pt0 = pt1 + // (use ec_double() in this case) or pt0 = -pt1 (the result is 0 in this case). + func fast_ec_add{range_check_ptr}(pt0: G1Point, pt1: G1Point) -> (res: G1Point) { + if (pt0.x.d0 == 0) { + if (pt0.x.d1 == 0) { + if (pt0.x.d2 == 0) { + return (pt1,); + } + } + } + if (pt1.x.d0 == 0) { + if (pt1.x.d1 == 0) { + if (pt1.x.d2 == 0) { + return (pt0,); + } + } + } + + let (slope: BigInt3) = compute_slope(pt0, pt1); + let (slope_sqr: UnreducedBigInt5) = bigint_mul(slope, slope); + + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + + P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + slope = pack(ids.slope, PRIME) + x0 = pack(ids.pt0.x, PRIME) + x1 = pack(ids.pt1.x, PRIME) + y0 = pack(ids.pt0.y, PRIME) + + value = new_x = (pow(slope, 2, P) - x0 - x1) % P + %} + let (new_x: BigInt3) = nondet_bigint3(); + + %{ value = new_y = (slope * (x0 - new_x) - y0) % P %} + let (new_y: BigInt3) = nondet_bigint3(); + + verify_zero5( + UnreducedBigInt5( + d0=slope_sqr.d0 - new_x.d0 - pt0.x.d0 - pt1.x.d0, + d1=slope_sqr.d1 - new_x.d1 - pt0.x.d1 - pt1.x.d1, + d2=slope_sqr.d2 - new_x.d2 - pt0.x.d2 - pt1.x.d2, + d3=slope_sqr.d3, + d4=slope_sqr.d4, + ), + ); + + let (x_diff_slope: UnreducedBigInt5) = bigint_mul( + BigInt3(d0=pt0.x.d0 - new_x.d0, d1=pt0.x.d1 - new_x.d1, d2=pt0.x.d2 - new_x.d2), slope + ); + + verify_zero5( + UnreducedBigInt5( + d0=x_diff_slope.d0 - pt0.y.d0 - new_y.d0, + d1=x_diff_slope.d1 - pt0.y.d1 - new_y.d1, + d2=x_diff_slope.d2 - pt0.y.d2 - new_y.d2, + d3=x_diff_slope.d3, + d4=x_diff_slope.d4, + ), + ); + + return (G1Point(new_x, new_y),); + } + + // Same as fast_ec_add, except that the cases pt0 = ±pt1 are supported. + func ec_add{range_check_ptr}(pt0: G1Point, pt1: G1Point) -> (res: G1Point) { + let x_diff = BigInt3( + d0=pt0.x.d0 - pt1.x.d0, d1=pt0.x.d1 - pt1.x.d1, d2=pt0.x.d2 - pt1.x.d2 + ); + let (same_x: felt) = is_zero(x_diff); + if (same_x == 0) { + // pt0.x != pt1.x so we can use fast_ec_add. + return fast_ec_add(pt0, pt1); + } + + // We have pt0.x = pt1.x. This implies pt0.y = ±pt1.y. + // Check whether pt0.y = -pt1.y. + let y_sum = BigInt3(d0=pt0.y.d0 + pt1.y.d0, d1=pt0.y.d1 + pt1.y.d1, d2=pt0.y.d2 + pt1.y.d2); + let (opposite_y: felt) = is_zero(y_sum); + if (opposite_y != 0) { + // pt0.y = -pt1.y. + // Note that the case pt0 = pt1 = 0 falls into this branch as well. + let ZERO_POINT = G1Point(BigInt3(0, 0, 0), BigInt3(0, 0, 0)); + return (ZERO_POINT,); + } else { + // pt0.y = pt1.y. + return ec_double(pt0); + } + } + + // Given 0 <= m < 250, a scalar and a point on the elliptic curve, pt, + // verifies that 0 <= scalar < 2**m and returns (2**m * pt, scalar * pt). + func ec_mul_inner{range_check_ptr}(pt: G1Point, scalar: felt, m: felt) -> ( + pow2: G1Point, res: G1Point + ) { + if (m == 0) { + assert scalar = 0; + let ZERO_POINT = G1Point(BigInt3(0, 0, 0), BigInt3(0, 0, 0)); + return (pow2=pt, res=ZERO_POINT); + } + + alloc_locals; + let (double_pt: G1Point) = ec_double(pt); + %{ memory[ap] = (ids.scalar % PRIME) % 2 %} + jmp odd if [ap] != 0, ap++; + return ec_mul_inner(pt=double_pt, scalar=scalar / 2, m=m - 1); + + odd: + let (local inner_pow2: G1Point, inner_res: G1Point) = ec_mul_inner( + pt=double_pt, scalar=(scalar - 1) / 2, m=m - 1 + ); + // Here inner_res = (scalar - 1) / 2 * double_pt = (scalar - 1) * pt. + // Assume pt != 0 and that inner_res = ±pt. We obtain (scalar - 1) * pt = ±pt => + // scalar - 1 = ±1 (mod N) => scalar = 0 or 2. + // In both cases (scalar - 1) / 2 cannot be in the range [0, 2**(m-1)), so we get a + // contradiction. + let (res: G1Point) = fast_ec_add(pt0=pt, pt1=inner_res); + return (pow2=inner_pow2, res=res); + } + + func ec_mul{range_check_ptr}(pt: G1Point, scalar: BigInt3) -> (res: G1Point) { + alloc_locals; + let (pow2_0: G1Point, local res0: G1Point) = ec_mul_inner(pt, scalar.d0, 86); + let (pow2_1: G1Point, local res1: G1Point) = ec_mul_inner(pow2_0, scalar.d1, 86); + let (_, local res2: G1Point) = ec_mul_inner(pow2_1, scalar.d2, 84); + let (res: G1Point) = ec_add(res0, res1); + let (res: G1Point) = ec_add(res, res2); + return (res,); + } + + // CONSTANTS + func g1() -> (res: G1Point) { + return (res=G1Point(BigInt3(1, 0, 0), BigInt3(2, 0, 0))); + } + + func g1_two() -> (res: G1Point) { + return ( + G1Point( + BigInt3(0x71ca8d3c208c16d87cfd3, 0x116da060561765e05aa45a, 0x30644e72e131a029b850), + BigInt3( + 0x138fc7ff3ebf7a5a18a2c4, 0x3e5acaba7029a29a91278d, 0x15ed738c0e0a7c92e7845 + ), + ), + ); + } + + func g1_three() -> (res: G1Point) { + return ( + G1Point( + BigInt3(0x38e679f2d355961915abf0, 0xaf2c6daf4564c57611c56, 0x769bf9ac56bea3ff4023), + BigInt3( + 0x1c5b57cdf1ff3dd9fe2261, 0x2df2342191d4c6798ed02e, 0x2ab799bee0489429554fd + ), + ), + ); + } + + func g1_negone() -> (res: G1Point) { + return ( + G1Point( + BigInt3(0x1, 0x0, 0x0), + BigInt3( + 0x31ca8d3c208c16d87cfd45, 0x16da060561765e05aa45a1, 0x30644e72e131a029b8504 + ), + ), + ); + } + + func g1_negtwo() -> (res: G1Point) { + return ( + G1Point( + BigInt3(0x71ca8d3c208c16d87cfd3, 0x116da060561765e05aa45a, 0x30644e72e131a029b850), + BigInt3( + 0x1e3ac53ce1cc9c7e645a83, 0x187f3b4af14cbb6b191e14, 0x1a76dae6d3272396d0cbe + ), + ), + ); + } + + func g1_negthree() -> (res: G1Point) { + return ( + G1Point( + BigInt3(0x38e679f2d355961915abf0, 0xaf2c6daf4564c57611c56, 0x769bf9ac56bea3ff4023), + BigInt3(0x156f356e2e8cd8fe7edae6, 0x28e7d1e3cfa1978c1b7573, 0x5acb4b400e90c0063006), + ), + ); + } +} diff --git a/cairo/src/utils/alt_bn128/bigint.cairo b/cairo/src/utils/alt_bn128/bigint.cairo new file mode 100644 index 00000000..a7b23bb1 --- /dev/null +++ b/cairo/src/utils/alt_bn128/bigint.cairo @@ -0,0 +1,57 @@ +// Library copied from https://github.com/tekkac/cairo-alt_bn128 + +// Starkware dependencies +from starkware.cairo.common.cairo_secp.bigint import UnreducedBigInt3, BigInt3 + +// The base of the representation. +const BASE = 2 ** 86; + +// Represents a big integer: sum_i(BASE**i * d_i). +// Note that the limbs (d_i) are NOT restricted to the range [0, BASE) and in particular they +// can be negative. +struct UnreducedBigInt5 { + d0: felt, + d1: felt, + d2: felt, + d3: felt, + d4: felt, +} + +func bigint_mul(x: BigInt3, y: BigInt3) -> (res: UnreducedBigInt5) { + return ( + UnreducedBigInt5( + d0=x.d0 * y.d0, + d1=x.d0 * y.d1 + x.d1 * y.d0, + d2=x.d0 * y.d2 + x.d1 * y.d1 + x.d2 * y.d0, + d3=x.d1 * y.d2 + x.d2 * y.d1, + d4=x.d2 * y.d2, + ), + ); +} + +// Returns a BigInt3 instance whose value is controlled by a prover hint. +// +// Soundness guarantee: each limb is in the range [0, 3 * BASE). +// Completeness guarantee (honest prover): the value is in reduced form and in particular, +// each limb is in the range [0, BASE). +// +// Hint arguments: value. +func nondet_bigint3{range_check_ptr}() -> (res: BigInt3) { + // The result should be at the end of the stack after the function returns. + let res: BigInt3 = [cast(ap + 5, BigInt3*)]; + %{ + from starkware.cairo.common.cairo_secp.secp_utils import split + segments.write_arg(ids.res.address_, split(value)) + %} + // The maximal possible sum of the limbs, assuming each of them is in the range [0, BASE). + const MAX_SUM = 3 * (BASE - 1); + assert [range_check_ptr] = MAX_SUM - (res.d0 + res.d1 + res.d2); + + // Prepare the result at the end of the stack. + tempvar range_check_ptr = range_check_ptr + 4; + [range_check_ptr - 3] = res.d0, ap++; + [range_check_ptr - 2] = res.d1, ap++; + [range_check_ptr - 1] = res.d2, ap++; + static_assert &res + BigInt3.SIZE == ap; + return (res=res); +} diff --git a/cairo/src/utils/array.cairo b/cairo/src/utils/array.cairo new file mode 100644 index 00000000..543025c4 --- /dev/null +++ b/cairo/src/utils/array.cairo @@ -0,0 +1,121 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.memset import memset +from starkware.cairo.common.math_cmp import is_not_zero, is_nn +from starkware.cairo.common.bool import FALSE, TRUE + +func reverse(dst: felt*, arr_len: felt, arr: felt*) { + alloc_locals; + + if (arr_len == 0) { + return (); + } + + tempvar i = arr_len; + + body: + let arr_len = [fp - 4]; + let arr = cast([fp - 3], felt*); + let dst = cast([fp - 5], felt*); + let i = [ap - 1]; + + assert [dst + i - 1] = [arr + arr_len - i]; + tempvar i = i - 1; + + jmp body if i != 0; + + return (); +} + +func count_not_zero(arr_len: felt, arr: felt*) -> felt { + if (arr_len == 0) { + return 0; + } + + tempvar len = arr_len; + tempvar count = 0; + tempvar arr = arr; + + body: + let len = [ap - 3]; + let count = [ap - 2]; + let arr = cast([ap - 1], felt*); + let not_zero = is_not_zero([arr]); + + tempvar len = len - 1; + tempvar count = count + not_zero; + tempvar arr = arr + 1; + + jmp body if len != 0; + + let count = [ap - 2]; + + return count; +} + +// @notice Fills slice with a slice of data. +// @dev If the slice is out of bounds, the function pads with zeros. +func slice{range_check_ptr}(dst: felt*, data_len: felt, data: felt*, offset: felt, size: felt) { + alloc_locals; + + if (size == 0) { + return (); + } + + let overlap = is_nn(data_len - offset); + if (overlap == FALSE) { + memset(dst=dst, value=0, n=size); + return (); + } + + let max_len = (data_len - offset); + let is_within_bound = is_nn(max_len - size); + if (is_within_bound != FALSE) { + memcpy(dst=dst, src=data + offset, len=size); + return (); + } + + memcpy(dst=dst, src=data + offset, len=max_len); + memset(dst=dst + max_len, value=0, n=size - max_len); + return (); +} + +func contains{range_check_ptr}(arr_len: felt, arr: felt*, value: felt) -> felt { + alloc_locals; + + if (arr_len == 0) { + return FALSE; + } + + tempvar i = 0; + + body: + let arr_len = [fp - 5]; + let arr = cast([fp - 4], felt*); + let value = [fp - 3]; + let i = [ap - 1]; + + tempvar check_value = [arr + i] - value; + tempvar check_bound = arr_len - (i + 1); + tempvar checks = check_value * check_bound; + + tempvar i = i + 1; + static_assert i == [ap - 1]; + jmp body if checks != 0; + + if (check_value == 0) { + return TRUE; + } + return FALSE; +} + +func pad_end{range_check_ptr}(arr_len, arr: felt*, size: felt) { + alloc_locals; + let size_to_fill = size - arr_len; + let is_within_bound = is_nn(size_to_fill); + if (is_within_bound == FALSE) { + return (); + } + memset(arr + arr_len, 0, size_to_fill); + return (); +} diff --git a/cairo/src/utils/bytes.cairo b/cairo/src/utils/bytes.cairo new file mode 100644 index 00000000..ebc48198 --- /dev/null +++ b/cairo/src/utils/bytes.cairo @@ -0,0 +1,312 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, KeccakBuiltin, BitwiseBuiltin +from starkware.cairo.common.builtin_keccak.keccak import keccak_bigend +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.math import split_int, split_felt, assert_le_felt, assert_nn_le +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.memset import memset +from starkware.cairo.common.registers import get_label_location + +from src.utils.array import reverse +from src.utils.maths import unsigned_div_rem + +func felt_to_ascii{range_check_ptr}(dst: felt*, n: felt) -> felt { + alloc_locals; + let (local ascii: felt*) = alloc(); + + tempvar range_check_ptr = range_check_ptr; + tempvar n = n; + tempvar ascii_len = 0; + + body: + let ascii = cast([fp], felt*); + let range_check_ptr = [ap - 3]; + let n = [ap - 2]; + let ascii_len = [ap - 1]; + + let (n, chunk) = unsigned_div_rem(n, 10); + assert [ascii + ascii_len] = chunk + '0'; + + tempvar range_check_ptr = range_check_ptr; + tempvar n = n; + tempvar ascii_len = ascii_len + 1; + + jmp body if n != 0; + + let range_check_ptr = [ap - 3]; + let ascii_len = [ap - 1]; + let ascii = cast([fp], felt*); + + reverse(dst, ascii_len, ascii); + + return ascii_len; +} + +// @notice Split a felt into an array of bytes little endian +// @dev Use a hint from split_int: the value must be lower than 248 bits +// as the prover assumption is n_bytes**256 < PRIME +func felt_to_bytes_little{range_check_ptr}(dst: felt*, value: felt) -> felt { + alloc_locals; + + with_attr error_message("felt_to_bytes_little: value >= 2**248") { + assert_le_felt(value, 2 ** 248 - 1); + } + + tempvar range_check_ptr = range_check_ptr; + tempvar value = value; + tempvar bytes_len = 0; + + body: + let range_check_ptr = [ap - 3]; + let value = [ap - 2]; + let bytes_len = [ap - 1]; + let bytes = cast([fp - 4], felt*); + let output = bytes + bytes_len; + let base = 2 ** 8; + let bound = base; + + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + let byte = [output]; + with_attr error_message("felt_to_bytes_little: byte value is too big") { + assert_nn_le(byte, bound - 1); + } + tempvar value = (value - byte) / base; + + tempvar range_check_ptr = range_check_ptr; + tempvar value = value; + tempvar bytes_len = bytes_len + 1; + + jmp body if value != 0; + + let range_check_ptr = [ap - 3]; + let value = [ap - 2]; + let bytes_len = [ap - 1]; + assert value = 0; + + let (pow256_address) = get_label_location(pow256_table); + if (bytes_len == 1) { + tempvar lower_bound = 0; + } else { + let lower_bound_ = pow256_address[bytes_len - 1]; + tempvar lower_bound = lower_bound_; + } + + // Assert that the `bytes_len` found is the minimal one possible to represent the value. + let initial_value = [fp - 3]; + let lower_bound = [ap - 1]; + let upper_bound = pow256_address[bytes_len]; + with_attr error_message("bytes_len is not the minimal possible") { + assert_le_felt(lower_bound, initial_value); + assert_le_felt(initial_value, upper_bound - 1); + } + return bytes_len; + + pow256_table: + dw 256 ** 0; + dw 256 ** 1; + dw 256 ** 2; + dw 256 ** 3; + dw 256 ** 4; + dw 256 ** 5; + dw 256 ** 6; + dw 256 ** 7; + dw 256 ** 8; + dw 256 ** 9; + dw 256 ** 10; + dw 256 ** 11; + dw 256 ** 12; + dw 256 ** 13; + dw 256 ** 14; + dw 256 ** 15; + dw 256 ** 16; + dw 256 ** 17; + dw 256 ** 18; + dw 256 ** 19; + dw 256 ** 20; + dw 256 ** 21; + dw 256 ** 22; + dw 256 ** 23; + dw 256 ** 24; + dw 256 ** 25; + dw 256 ** 26; + dw 256 ** 27; + dw 256 ** 28; + dw 256 ** 29; + dw 256 ** 30; + dw 256 ** 31; +} + +// @notice Split a felt into an array of bytes +// @dev Use felt_to_bytes_little: the value must be lower than 248 bits +// as the prover assumption is n_bytes**256 < PRIME +func felt_to_bytes{range_check_ptr}(dst: felt*, value: felt) -> felt { + alloc_locals; + let (local bytes: felt*) = alloc(); + let bytes_len = felt_to_bytes_little(bytes, value); + reverse(dst, bytes_len, bytes); + + return bytes_len; +} + +// @notice Split a felt into an array of 20 bytes, big endian +// @dev Truncate the high 12 bytes +func felt_to_bytes20{range_check_ptr}(dst: felt*, value: felt) { + alloc_locals; + let (bytes20: felt*) = alloc(); + let (high, low) = split_felt(value); + let (_, high) = unsigned_div_rem(high, 2 ** 32); + split_int(low, 16, 256, 256, bytes20); + split_int(high, 4, 256, 256, bytes20 + 16); + reverse(dst, 20, bytes20); + return (); +} + +func felt_to_bytes32{range_check_ptr}(dst: felt*, value: felt) { + alloc_locals; + let (bytes32: felt*) = alloc(); + let (high, low) = split_felt(value); + split_int(low, 16, 256, 256, bytes32); + split_int(high, 16, 256, 256, bytes32 + 16); + reverse(dst, 32, bytes32); + return (); +} + +func uint256_to_bytes_little{range_check_ptr}(dst: felt*, n: Uint256) -> felt { + alloc_locals; + let (local highest_byte, safe_high) = unsigned_div_rem(n.high, 2 ** 120); + local range_check_ptr = range_check_ptr; + + let value = n.low + safe_high * 2 ** 128; + let len = felt_to_bytes_little(dst, value); + if (highest_byte != 0) { + memset(dst + len, 0, 31 - len); + assert [dst + 31] = highest_byte; + tempvar bytes_len = 32; + } else { + tempvar bytes_len = len; + } + + return bytes_len; +} + +func uint256_to_bytes{range_check_ptr}(dst: felt*, n: Uint256) -> felt { + alloc_locals; + let (bytes: felt*) = alloc(); + let bytes_len = uint256_to_bytes_little(bytes, n); + reverse(dst, bytes_len, bytes); + return bytes_len; +} + +func uint256_to_bytes32{range_check_ptr}(dst: felt*, n: Uint256) { + alloc_locals; + let (bytes: felt*) = alloc(); + let bytes_len = uint256_to_bytes_little(bytes, n); + memset(dst, 0, 32 - bytes_len); + reverse(dst + 32 - bytes_len, bytes_len, bytes); + return (); +} + +// @notice Converts an array of bytes to an array of bytes8, little endian +// @dev The individual bytes are packed into 8-byte words, little endian. +// The last word is returned separately, along with the number of used bytes +// as it may be incomplete. +// @param dst The destination array. +// @param bytes_len The number of bytes in the input array. +// @param bytes The input array. +// @return The number of bytes written to the destination array. +// @return The last word. +// @return The number of bytes used in the last word +func bytes_to_bytes8_little_endian{range_check_ptr}(dst: felt*, bytes_len: felt, bytes: felt*) -> ( + ) { + alloc_locals; + + if (bytes_len == 0) { + return (); + } + + let (local pow256) = get_label_location(pow256_table); + let (full_u64_word_count, local last_input_num_bytes) = unsigned_div_rem(bytes_len, 8); + local range_check_ptr = range_check_ptr; + + tempvar dst_index = 0; + tempvar bytes_index = bytes_len - 1; + tempvar bytes8 = 0; + tempvar bytes8_index = 7; + + body: + let dst_index = [ap - 4]; + let bytes_index = [ap - 3]; + let bytes8 = [ap - 2]; + let bytes8_index = [ap - 1]; + + let bytes_len = [fp - 4]; + let bytes = cast([fp - 3], felt*); + let pow256 = cast([fp], felt*); + let current_byte = bytes[bytes_len - 1 - bytes_index]; + let current_pow = pow256[bytes8_index]; + + tempvar bytes8 = bytes8 + current_byte * current_pow; + + jmp next if bytes_index != 0; + jmp end_word_not_full if bytes8_index != 0; + + let last_input_num_bytes = [fp + 1]; + assert [dst + dst_index] = bytes8; + let range_check_ptr = [fp + 2]; + return (); + + next: + jmp regular if bytes8_index != 0; + + assert [dst + dst_index] = bytes8; + + tempvar dst_index = dst_index + 1; + tempvar bytes_index = bytes_index - 1; + tempvar bytes8 = 0; + tempvar bytes8_index = 7; + static_assert dst_index == [ap - 4]; + static_assert bytes_index == [ap - 3]; + static_assert bytes8 == [ap - 2]; + static_assert bytes8_index == [ap - 1]; + jmp body; + + regular: + tempvar dst_index = dst_index; + tempvar bytes_index = bytes_index - 1; + tempvar bytes8 = bytes8; + tempvar bytes8_index = bytes8_index - 1; + static_assert dst_index == [ap - 4]; + static_assert bytes_index == [ap - 3]; + static_assert bytes8 == [ap - 2]; + static_assert bytes8_index == [ap - 1]; + jmp body; + + end_word_not_full: + assert [dst + dst_index] = bytes8; + let range_check_ptr = [fp + 2]; + return (); + + pow256_table: + dw 256 ** 7; + dw 256 ** 6; + dw 256 ** 5; + dw 256 ** 4; + dw 256 ** 3; + dw 256 ** 2; + dw 256 ** 1; + dw 256 ** 0; +} + +func keccak{range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin*}( + code_len: felt, code: felt* +) -> Uint256 { + alloc_locals; + let (local dst: felt*) = alloc(); + bytes_to_bytes8_little_endian(dst, code_len, code); + + let (code_hash) = keccak_bigend(dst, code_len); + return code_hash; +} diff --git a/cairo_programs/compile_cairo.py b/cairo/src/utils/compile_keth.py similarity index 93% rename from cairo_programs/compile_cairo.py rename to cairo/src/utils/compile_keth.py index 3a6eb11e..09fc82c0 100644 --- a/cairo_programs/compile_cairo.py +++ b/cairo/src/utils/compile_keth.py @@ -1,6 +1,7 @@ import logging import subprocess import sys +from pathlib import Path # Configure the logger logging.basicConfig( @@ -10,8 +11,6 @@ def compile_cairo(file_name): - from pathlib import Path - input_path = Path(file_name) output_path = input_path.with_suffix(".json") @@ -23,7 +22,7 @@ def compile_cairo(file_name): "--proof_mode", "--no_debug_info", "--cairo_path", - "cairo_programs", + str(Path(__file__).parents[2]), ] result = subprocess.run(command, capture_output=True, text=True) diff --git a/cairo/src/utils/constants.py b/cairo/src/utils/constants.py new file mode 100644 index 00000000..15aa7bfa --- /dev/null +++ b/cairo/src/utils/constants.py @@ -0,0 +1,14 @@ +import logging +from pathlib import Path + +from dotenv import load_dotenv + +logging.basicConfig() +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) +load_dotenv() + +CAIRO_DIR = Path("src") +TESTS_DIR = Path("tests") +BUILD_DIR = Path("build") +BUILD_DIR.mkdir(exist_ok=True, parents=True) diff --git a/cairo/src/utils/dict.cairo b/cairo/src/utils/dict.cairo new file mode 100644 index 00000000..ca0f4e66 --- /dev/null +++ b/cairo/src/utils/dict.cairo @@ -0,0 +1,134 @@ +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.dict import dict_write, dict_squash +from starkware.cairo.common.math_cmp import is_not_zero +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.uint256 import Uint256 + +from src.utils.maths import unsigned_div_rem + +func dict_keys{range_check_ptr}(dict_start: DictAccess*, dict_end: DictAccess*) -> ( + keys_len: felt, keys: felt* +) { + alloc_locals; + let (local keys_start: felt*) = alloc(); + let dict_len = dict_end - dict_start; + let (local keys_len, _) = unsigned_div_rem(dict_len, DictAccess.SIZE); + local range_check_ptr = range_check_ptr; + + if (dict_len == 0) { + return (keys_len, keys_start); + } + + tempvar keys = keys_start; + tempvar len = keys_len; + tempvar dict = dict_start; + + loop: + let keys = cast([ap - 3], felt*); + let len = [ap - 2]; + let dict = cast([ap - 1], DictAccess*); + + assert [keys] = dict.key; + tempvar keys = keys + 1; + tempvar len = len - 1; + tempvar dict = dict + DictAccess.SIZE; + + static_assert keys == [ap - 3]; + static_assert len == [ap - 2]; + static_assert dict == [ap - 1]; + + jmp loop if len != 0; + + return (keys_len, keys_start); +} + +func dict_values{range_check_ptr}(dict_start: DictAccess*, dict_end: DictAccess*) -> ( + values_len: felt, values: Uint256* +) { + alloc_locals; + let (local values: Uint256*) = alloc(); + let dict_len = dict_end - dict_start; + let (local values_len, _) = unsigned_div_rem(dict_len, DictAccess.SIZE); + local range_check_ptr = range_check_ptr; + + if (dict_len == 0) { + return (values_len, values); + } + + tempvar index = 0; + tempvar len = values_len; + tempvar dict = dict_start; + + loop: + let index = [ap - 3]; + let len = [ap - 2]; + let dict = cast([ap - 1], DictAccess*); + + let pointer = cast(dict.new_value, Uint256*); + assert values[index] = pointer[0]; + + tempvar index = index + 1; + tempvar len = len - 1; + tempvar dict = dict + DictAccess.SIZE; + + static_assert index == [ap - 3]; + static_assert len == [ap - 2]; + static_assert dict == [ap - 1]; + + jmp loop if len != 0; + + return (values_len, values); +} + +func default_dict_copy{range_check_ptr}(start: DictAccess*, end: DictAccess*) -> ( + DictAccess*, DictAccess* +) { + alloc_locals; + let (squashed_start, squashed_end) = dict_squash(start, end); + local range_check_ptr = range_check_ptr; + let dict_len = squashed_end - squashed_start; + + local default_value; + if (dict_len == 0) { + assert default_value = 0; + } else { + assert default_value = squashed_start.prev_value; + } + + let (local new_start) = default_dict_new(default_value); + let new_ptr = new_start; + + if (dict_len == 0) { + return (new_start, new_ptr); + } + + tempvar squashed_start = squashed_start; + tempvar dict_len = dict_len; + tempvar new_ptr = new_ptr; + + loop: + let squashed_start = cast([ap - 3], DictAccess*); + let dict_len = [ap - 2]; + let new_ptr = cast([ap - 1], DictAccess*); + let default_value = [fp + 1]; + + let key = [squashed_start].key; + let prev_value = [squashed_start].prev_value; + assert prev_value = default_value; + let new_value = [squashed_start].new_value; + + dict_write{dict_ptr=new_ptr}(key=key, new_value=new_value); + + tempvar squashed_start = squashed_start + DictAccess.SIZE; + tempvar dict_len = dict_len - DictAccess.SIZE; + tempvar new_ptr = new_ptr; + + static_assert squashed_start == [ap - 3]; + static_assert dict_len == [ap - 2]; + static_assert new_ptr == [ap - 1]; + + jmp loop if dict_len != 0; + + return (new_start, new_ptr); +} diff --git a/cairo/src/utils/eth_transaction.cairo b/cairo/src/utils/eth_transaction.cairo new file mode 100644 index 00000000..27f91749 --- /dev/null +++ b/cairo/src/utils/eth_transaction.cairo @@ -0,0 +1,386 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin, HashBuiltin, KeccakBuiltin +from starkware.cairo.common.math_cmp import is_not_zero, is_nn +from starkware.cairo.common.math import assert_not_zero, assert_nn +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.uint256 import Uint256 + +from src.model import model +from src.constants import Constants +from src.utils.rlp import RLP +from src.utils.utils import Helpers +from src.utils.bytes import keccak +from src.utils.signature import Signature + +// @title EthTransaction utils +// @notice This file contains utils for decoding eth transactions +// @custom:namespace EthTransaction +namespace EthTransaction { + // @notice Decode a legacy Ethereum transaction + // @dev This function decodes a legacy Ethereum transaction in accordance with EIP-155. + // It returns transaction details including nonce, gas price, gas limit, destination address, amount, payload, + // transaction hash, and signature (v, r, s). The transaction hash is computed by keccak hashing the signed + // transaction data, which includes the chain ID in accordance with EIP-155. + // @param tx_data_len The length of the raw transaction data + // @param tx_data The raw transaction data + func decode_legacy_tx{bitwise_ptr: BitwiseBuiltin*, range_check_ptr}( + tx_data_len: felt, tx_data: felt* + ) -> model.EthTransaction* { + // see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + alloc_locals; + let (tx_items: RLP.Item*) = alloc(); + RLP.decode(tx_items, tx_data_len, tx_data); + + assert [tx_items].is_list = TRUE; + let items_len = [tx_items].data_len; + let items = cast([tx_items].data, RLP.Item*); + + // Pre eip-155 txs have 6 fields, post eip-155 txs have 9 fields + // We check for both cases here, and do the remaining ones in the next if block + assert items[0].is_list = FALSE; + assert items[1].is_list = FALSE; + assert items[2].is_list = FALSE; + assert items[3].is_list = FALSE; + assert items[4].is_list = FALSE; + assert items[5].is_list = FALSE; + + assert_nn(31 - items[0].data_len); + let nonce = Helpers.bytes_to_felt(items[0].data_len, items[0].data); + assert_nn(31 - items[1].data_len); + let gas_price = Helpers.bytes_to_felt(items[1].data_len, items[1].data); + assert_nn(31 - items[2].data_len); + let gas_limit = Helpers.bytes_to_felt(items[2].data_len, items[2].data); + let destination = Helpers.try_parse_destination_from_bytes( + items[3].data_len, items[3].data + ); + assert_nn(32 - items[4].data_len); + let amount = Helpers.bytes_to_uint256(items[4].data_len, items[4].data); + let payload_len = items[5].data_len; + let payload = items[5].data; + + // pre eip-155 txs have 6 fields, post eip-155 txs have 9 fields + if (items_len == 6) { + tempvar is_some = 0; + tempvar chain_id = 0; + } else { + assert items_len = 9; + assert items[6].is_list = FALSE; + assert items[7].is_list = FALSE; + assert items[8].is_list = FALSE; + let chain_id = Helpers.bytes_to_felt(items[6].data_len, items[6].data); + + tempvar is_some = 1; + tempvar chain_id = chain_id; + } + let is_some = [ap - 2]; + let chain_id = [ap - 1]; + + tempvar tx = new model.EthTransaction( + signer_nonce=nonce, + gas_limit=gas_limit, + max_priority_fee_per_gas=gas_price, + max_fee_per_gas=gas_price, + destination=destination, + amount=amount, + payload_len=payload_len, + payload=payload, + access_list_len=0, + access_list=cast(0, felt*), + chain_id=model.Option(is_some=is_some, value=chain_id), + ); + return tx; + } + + // @notice Decode an Ethereum transaction with optional access list + // @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2930.md + // @param tx_data_len The length of the raw transaction data + // @param tx_data The raw transaction data + func decode_2930{bitwise_ptr: BitwiseBuiltin*, range_check_ptr}( + tx_data_len: felt, tx_data: felt* + ) -> model.EthTransaction* { + alloc_locals; + + let (tx_items: RLP.Item*) = alloc(); + RLP.decode(tx_items, tx_data_len - 1, tx_data + 1); + + assert [tx_items].is_list = TRUE; + let items_len = [tx_items].data_len; + let items = cast([tx_items].data, RLP.Item*); + + assert items_len = 8; + assert items[0].is_list = FALSE; + assert items[1].is_list = FALSE; + assert items[2].is_list = FALSE; + assert items[3].is_list = FALSE; + assert items[4].is_list = FALSE; + assert items[5].is_list = FALSE; + assert items[6].is_list = FALSE; + assert items[7].is_list = TRUE; + + assert_nn(31 - items[0].data_len); + let chain_id = Helpers.bytes_to_felt(items[0].data_len, items[0].data); + assert_nn(31 - items[1].data_len); + let nonce = Helpers.bytes_to_felt(items[1].data_len, items[1].data); + assert_nn(31 - items[2].data_len); + let gas_price = Helpers.bytes_to_felt(items[2].data_len, items[2].data); + assert_nn(31 - items[3].data_len); + let gas_limit = Helpers.bytes_to_felt(items[3].data_len, items[3].data); + let destination = Helpers.try_parse_destination_from_bytes( + items[4].data_len, items[4].data + ); + assert_nn(32 - items[5].data_len); + let amount = Helpers.bytes_to_uint256(items[5].data_len, items[5].data); + let payload_len = items[6].data_len; + let payload = items[6].data; + + let (access_list: felt*) = alloc(); + let access_list_len = parse_access_list( + access_list, items[7].data_len, cast(items[7].data, RLP.Item*) + ); + tempvar tx = new model.EthTransaction( + signer_nonce=nonce, + gas_limit=gas_limit, + max_priority_fee_per_gas=gas_price, + max_fee_per_gas=gas_price, + destination=destination, + amount=amount, + payload_len=payload_len, + payload=payload, + access_list_len=access_list_len, + access_list=access_list, + chain_id=model.Option(is_some=1, value=chain_id), + ); + return tx; + } + + // @notice Decode an Ethereum transaction with fee market + // @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md + // @param tx_data_len The length of the raw transaction data + // @param tx_data The raw transaction data + func decode_1559{bitwise_ptr: BitwiseBuiltin*, range_check_ptr}( + tx_data_len: felt, tx_data: felt* + ) -> model.EthTransaction* { + alloc_locals; + + let (tx_items: RLP.Item*) = alloc(); + RLP.decode(tx_items, tx_data_len - 1, tx_data + 1); + + assert [tx_items].is_list = TRUE; + let items_len = [tx_items].data_len; + let items = cast([tx_items].data, RLP.Item*); + + assert items_len = 9; + assert items[0].is_list = FALSE; + assert items[1].is_list = FALSE; + assert items[2].is_list = FALSE; + assert items[3].is_list = FALSE; + assert items[4].is_list = FALSE; + assert items[5].is_list = FALSE; + assert items[6].is_list = FALSE; + assert items[7].is_list = FALSE; + assert items[8].is_list = TRUE; + + assert_nn(31 - items[0].data_len); + let chain_id = Helpers.bytes_to_felt(items[0].data_len, items[0].data); + assert_nn(31 - items[1].data_len); + let nonce = Helpers.bytes_to_felt(items[1].data_len, items[1].data); + assert_nn(31 - items[2].data_len); + let max_priority_fee_per_gas = Helpers.bytes_to_felt(items[2].data_len, items[2].data); + assert_nn(31 - items[3].data_len); + let max_fee_per_gas = Helpers.bytes_to_felt(items[3].data_len, items[3].data); + assert_nn(31 - items[4].data_len); + let gas_limit = Helpers.bytes_to_felt(items[4].data_len, items[4].data); + let destination = Helpers.try_parse_destination_from_bytes( + items[5].data_len, items[5].data + ); + assert_nn(32 - items[6].data_len); + let amount = Helpers.bytes_to_uint256(items[6].data_len, items[6].data); + let payload_len = items[7].data_len; + let payload = items[7].data; + let (access_list: felt*) = alloc(); + let access_list_len = parse_access_list( + access_list, items[8].data_len, cast(items[8].data, RLP.Item*) + ); + tempvar tx = new model.EthTransaction( + signer_nonce=nonce, + gas_limit=gas_limit, + max_priority_fee_per_gas=max_priority_fee_per_gas, + max_fee_per_gas=max_fee_per_gas, + destination=destination, + amount=amount, + payload_len=payload_len, + payload=payload, + access_list_len=access_list_len, + access_list=access_list, + chain_id=model.Option(is_some=1, value=chain_id), + ); + return tx; + } + + // @notice Returns the type of a tx, considering that legacy tx are type 0. + // @dev This function checks if a raw transaction is a legacy Ethereum transaction by checking the transaction type + // according to EIP-2718. If the transaction type is greater than or equal to 0xc0, it's a legacy transaction. + // See https://eips.ethereum.org/EIPS/eip-2718#transactiontype-only-goes-up-to-0x7f + // @param tx_data_len The len of the raw transaction data + // @param tx_data The raw transaction data + func get_tx_type{range_check_ptr}(tx_data_len: felt, tx_data: felt*) -> felt { + with_attr error_message("tx_data_len is zero") { + assert_not_zero(tx_data_len); + } + + let type = [tx_data]; + let is_legacy = is_nn(type - 0xc0); + if (is_legacy != FALSE) { + return 0; + } + return type; + } + + // @notice Decode a raw Ethereum transaction + // @param tx_data_len The length of the raw transaction data + // @param tx_data The raw transaction data + func decode{bitwise_ptr: BitwiseBuiltin*, range_check_ptr}( + tx_data_len: felt, tx_data: felt* + ) -> model.EthTransaction* { + let tx_type = get_tx_type(tx_data_len, tx_data); + let is_supported = is_nn(2 - tx_type); + with_attr error_message("Kakarot: transaction type not supported") { + assert is_supported = TRUE; + } + tempvar offset = 1 + 3 * tx_type; + + [ap] = bitwise_ptr, ap++; + [ap] = range_check_ptr, ap++; + [ap] = tx_data_len, ap++; + [ap] = tx_data, ap++; + jmp rel offset; + call decode_legacy_tx; + ret; + call decode_2930; + ret; + call decode_1559; + ret; + } + + // @notice Recursively parses the RLP-decoded access list. + // @dev the parsed format is [address, storage_keys_len, *[storage_keys], address, storage_keys_len, *[storage_keys]] + // where keys_len is the number of storage keys, and each storage key takes 2 felts. + // @param parsed_list The pointer to the next free cell in the parsed access list. + // @param list_len The remaining length of the RLP-decoded access list to parse. + // @param list_items The pointer to the current RLP-decoded access list item to parse. + // @return The length of the serialized access list, expressed in total amount of felts in the list. + func parse_access_list{range_check_ptr}( + parsed_list: felt*, access_list_len: felt, access_list: RLP.Item* + ) -> felt { + alloc_locals; + if (access_list_len == 0) { + return 0; + } + + // Address + let address_item = cast(access_list.data, RLP.Item*); + let address = Helpers.bytes20_to_felt(address_item.data); + + // List + let keys_item = cast(access_list.data + RLP.Item.SIZE, RLP.Item*); + let keys_len = keys_item.data_len; + assert [parsed_list] = address; + assert [parsed_list + 1] = keys_len; + + let keys = cast(keys_item.data, RLP.Item*); + parse_storage_keys(parsed_list + 2, keys_len, keys); + + let serialized_len = parse_access_list( + parsed_list + 2 + keys_len * Uint256.SIZE, + access_list_len - 1, + access_list + RLP.Item.SIZE, + ); + return serialized_len + 2 + keys_len * Uint256.SIZE; + } + + // @notice Recursively parses the RLP-decoded storage keys list of an address + // and returns an array containing the parsed storage keys. + // @dev the keys are stored in the parsed format [key_low, key_high, key_low, key_high] + // @param parsed_keys The pointer to the next free cell in the parsed access list array. + // @param keys_list_len The remaining length of the RLP-decoded storage keys list to parse. + // @param keys_list The pointer to the current RLP-decoded storage keys list item to parse. + func parse_storage_keys{range_check_ptr}( + parsed_keys: felt*, keys_list_len: felt, keys_list: RLP.Item* + ) { + alloc_locals; + if (keys_list_len == 0) { + return (); + } + + let key = Helpers.bytes32_to_uint256(keys_list.data); + assert [parsed_keys] = key.low; + assert [parsed_keys + 1] = key.high; + + parse_storage_keys( + parsed_keys + Uint256.SIZE, keys_list_len - 1, keys_list + RLP.Item.SIZE + ); + return (); + } + + // @notice Validate an Ethereum transaction and execute it. + // @dev This function validates the transaction by checking its signature, + // chain_id, nonce and gas. It then sends it to Kakarot. + // @param tx_data_len The length of tx data + // @param tx_data The tx data. + // @param signature_len The length of tx signature. + // @param signature The tx signature. + // @param chain_id The expected chain id of the tx + func validate{pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr}( + tx_data_len: felt, + tx_data: felt*, + signature_len: felt, + signature: felt*, + chain_id: felt, + address: felt, + ) { + alloc_locals; + + with_attr error_message("Incorrect signature length") { + assert signature_len = 5; + } + + with_attr error_message("Signatures values not in range") { + assert [range_check_ptr] = signature[0]; + assert [range_check_ptr + 1] = signature[1]; + assert [range_check_ptr + 2] = signature[2]; + assert [range_check_ptr + 3] = signature[3]; + assert [range_check_ptr + 4] = signature[4]; + let range_check_ptr = range_check_ptr + 5; + } + + let r = Uint256(signature[0], signature[1]); + let s = Uint256(signature[2], signature[3]); + let v = signature[4]; + + let tx_type = EthTransaction.get_tx_type(tx_data_len, tx_data); + local y_parity: felt; + local pre_eip155_tx: felt; + if (tx_type == 0) { + let is_eip155_tx = is_nn(28 - v); + assert pre_eip155_tx = is_eip155_tx; + if (is_eip155_tx != FALSE) { + assert y_parity = v - 27; + } else { + assert y_parity = (v - 2 * chain_id - 35); + } + tempvar range_check_ptr = range_check_ptr; + } else { + assert pre_eip155_tx = FALSE; + assert y_parity = v; + tempvar range_check_ptr = range_check_ptr; + } + let range_check_ptr = [ap - 1]; + + let msg_hash = keccak(tx_data_len, tx_data); + + Signature.verify_eth_signature_uint256( + msg_hash=msg_hash, r=r, s=s, v=y_parity, eth_address=address + ); + } +} diff --git a/cairo/src/utils/maths.cairo b/cairo/src/utils/maths.cairo new file mode 100644 index 00000000..3de054c9 --- /dev/null +++ b/cairo/src/utils/maths.cairo @@ -0,0 +1,34 @@ +// @dev Inlined version of unsigned_div_rem +// Returns q and r such that: +// 0 <= q < rc_bound, 0 <= r < div and value = q * div + r. +// +// Assumption: 0 < div <= PRIME / rc_bound. +// Prover assumption: value / div < rc_bound. +// +// The value of div is restricted to make sure there is no overflow. +// q * div + r < (q + 1) * div <= rc_bound * (PRIME / rc_bound) = PRIME. +func unsigned_div_rem{range_check_ptr}(value, div) -> (q: felt, r: felt) { + let r = [range_check_ptr]; + let q = [range_check_ptr + 1]; + let range_check_ptr = range_check_ptr + 2; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.div) + assert 0 < ids.div <= PRIME // range_check_builtin.bound, \ + f'div={hex(ids.div)} is out of the valid range.' + ids.q, ids.r = divmod(ids.value, ids.div) + %} + + // equivalent to assert_le(r, div - 1); + tempvar a = div - 1 - r; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.' + %} + a = [range_check_ptr]; + let range_check_ptr = range_check_ptr + 1; + + assert value = q * div + r; + return (q, r); +} diff --git a/cairo/src/utils/modexp/modexp_utils.cairo b/cairo/src/utils/modexp/modexp_utils.cairo new file mode 100644 index 00000000..72b1b41b --- /dev/null +++ b/cairo/src/utils/modexp/modexp_utils.cairo @@ -0,0 +1,338 @@ +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256, uint256_mul, uint256_lt +from starkware.cairo.common.bitwise import bitwise_and +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.bool import FALSE + +from src.utils.uint256 import ( + uint256_sub, + uint256_add, + uint256_unsigned_div_rem, + uint256_mul_div_mod, + uint256_eq, +) + +// @title ModExpHelpersUint256 Functions +// @notice This file contains a selection of helper functions for modular exponentiation and gas cost calculation. +// @author @dragan2234 +// @custom:namespace ModExpHelpersUint256 +namespace ModExpHelpersUint256 { + const GAS_COST_MOD_EXP = 200; + + // @title Modular exponentiation calculation + // @author dragan2234 + // @dev Computes x ** y % p for Uint256 numbers via fast modular exponentiation algorithm. + // Time complexity is log_2(y). + // Loop is implemented via uint256_mod_exp_recursive_call() function. + func uint256_mod_exp{range_check_ptr: felt}(x: Uint256, y: Uint256, p: Uint256) -> ( + remainder: Uint256 + ) { + alloc_locals; + let res = Uint256(low=1, high=0); + let (r_x, r_y, r_res) = uint256_mod_exp_recursive_call(x, y, res, p); + let (quotient, remainder) = uint256_unsigned_div_rem(r_res, p); + return (remainder=remainder); + } + + func uint256_mod_exp_recursive_call{range_check_ptr: felt}( + x: Uint256, y: Uint256, res: Uint256, p: Uint256 + ) -> (r_x: Uint256, r_y: Uint256, r_res: Uint256) { + alloc_locals; + let (is_greater_than_zero) = uint256_lt(Uint256(low=0, high=0), y); + if (is_greater_than_zero == FALSE) { + return (r_x=x, r_y=y, r_res=res); + } + + let (quotient, remainder) = uint256_unsigned_div_rem(y, Uint256(low=2, high=0)); + let (is_equal_to_one) = uint256_eq(remainder, Uint256(low=1, high=0)); + if (is_equal_to_one == FALSE) { + let (x_res_quotient, x_res_quotient_high, x_res_remainder) = uint256_mul_div_mod( + x, x, p + ); + return uint256_mod_exp_recursive_call(x=x_res_remainder, y=quotient, res=res, p=p); + } else { + let ( + x_res_res_quotient, x_res_res_quotient_high, x_res_res_remainder + ) = uint256_mul_div_mod(res, x, p); + let (x_res_quotient, x_res_quotient_high, x_res_remainder) = uint256_mul_div_mod( + x, x, p + ); + return uint256_mod_exp_recursive_call( + x=x_res_remainder, y=quotient, res=x_res_res_remainder, p=p + ); + } + } + + func calculate_mod_exp_gas{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}( + b_size: Uint256, e_size: Uint256, m_size: Uint256, b: Uint256, e: Uint256, m: Uint256 + ) -> (gas_cost: felt) { + alloc_locals; + + let (is_less_than) = uint256_lt(b_size, m_size); + + if (is_less_than == FALSE) { + tempvar max_length = b_size; + } else { + tempvar max_length = m_size; + } + + let (words_step_1, _) = uint256_add(max_length, Uint256(low=7, high=0)); + let (words, _) = uint256_unsigned_div_rem(words_step_1, Uint256(low=8, high=0)); + let (multiplication_complexity, carry) = uint256_mul(words, words); + assert carry = Uint256(0, 0); + + let (is_less_than_33) = uint256_lt(e_size, Uint256(low=33, high=0)); + if (is_less_than_33 == FALSE) { + let sub_step: Uint256 = uint256_sub(e_size, Uint256(low=32, high=0)); + + let (local result, local carry) = uint256_mul(Uint256(low=8, high=0), sub_step); + assert carry = Uint256(low=0, high=0); + + let (bitwise_high) = bitwise_and(e.high, 2 ** 128 - 1); + let (bitwise_low) = bitwise_and(e.low, 2 ** 128 - 1); + let e_bit_length = get_u256_bitlength(Uint256(low=bitwise_low, high=bitwise_high)); + + let e_bit_length_uint256 = Uint256(low=e_bit_length, high=0); + let (subtracted_e_bit_length) = uint256_sub( + e_bit_length_uint256, Uint256(low=1, high=0) + ); + + let (addition, _) = uint256_add(result, subtracted_e_bit_length); + + tempvar iteration_count_res = addition; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr = bitwise_ptr; + } else { + let (is_zero) = uint256_eq(e, Uint256(low=0, high=0)); + if (is_zero == FALSE) { + let u256_l = get_u256_bitlength(e); + let inner_step = u256_l - 1; + tempvar iteration_count = Uint256(low=inner_step, high=0); + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr = bitwise_ptr; + } else { + tempvar iteration_count = Uint256(low=0, high=0); + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr = bitwise_ptr; + } + tempvar iteration_count_res = iteration_count; + tempvar range_check_ptr = range_check_ptr; + tempvar bitwise_ptr = bitwise_ptr; + } + tempvar bitwise_ptr = bitwise_ptr; + let another_var = iteration_count_res; + let (mci, carry) = uint256_mul(multiplication_complexity, another_var); + assert carry = Uint256(low=0, high=0); + + let (division_mci, _) = uint256_unsigned_div_rem(mci, Uint256(low=3, high=0)); + + let (gas_is_greater_than) = uint256_lt(Uint256(low=200, high=0), division_mci); + + if (gas_is_greater_than == FALSE) { + tempvar gas_cost = Uint256(low=GAS_COST_MOD_EXP, high=0); + } else { + tempvar gas_cost = division_mci; + } + let res = gas_cost.low; + return (gas_cost=res); + } + // @author feltroidprime + // Returns the number of bits in x. + // Params: + // - x: felt - Input value. + // Assumptions for the caller: + // - 0 <= x < 2^128 + // Returns: + // - bit_length: felt - Number of bits in x. + func get_felt_bitlength{range_check_ptr}(x: felt) -> felt { + if (x == 0) { + return 0; + } + alloc_locals; + local bit_length; + + %{ + x = ids.x + ids.bit_length = x.bit_length() + %} + if (bit_length == 128) { + assert [range_check_ptr] = x - 2 ** 127; + tempvar range_check_ptr = range_check_ptr + 1; + return bit_length; + } else { + // Computes N=2^bit_length and n=2^(bit_length-1) + // x is supposed to verify n = 2^(b-1) <= x < N = 2^bit_length <=> x has bit_length bits + let N = pow2(bit_length); + let n = pow2(bit_length - 1); + assert [range_check_ptr] = bit_length; + assert [range_check_ptr + 1] = 128 - bit_length; + assert [range_check_ptr + 2] = N - x - 1; + assert [range_check_ptr + 3] = x - n; + tempvar range_check_ptr = range_check_ptr + 4; + return bit_length; + } + } + // @author feltroidprime + // Returns 2**i for i in [0, 128] + // Assumptions: i is in [0, 128]. + func pow2(i: felt) -> felt { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let data = pc + (powers - pc_label); + + let res = [data + i]; + + return res; + + powers: + dw 0x1; + dw 0x2; + dw 0x4; + dw 0x8; + dw 0x10; + dw 0x20; + dw 0x40; + dw 0x80; + dw 0x100; + dw 0x200; + dw 0x400; + dw 0x800; + dw 0x1000; + dw 0x2000; + dw 0x4000; + dw 0x8000; + dw 0x10000; + dw 0x20000; + dw 0x40000; + dw 0x80000; + dw 0x100000; + dw 0x200000; + dw 0x400000; + dw 0x800000; + dw 0x1000000; + dw 0x2000000; + dw 0x4000000; + dw 0x8000000; + dw 0x10000000; + dw 0x20000000; + dw 0x40000000; + dw 0x80000000; + dw 0x100000000; + dw 0x200000000; + dw 0x400000000; + dw 0x800000000; + dw 0x1000000000; + dw 0x2000000000; + dw 0x4000000000; + dw 0x8000000000; + dw 0x10000000000; + dw 0x20000000000; + dw 0x40000000000; + dw 0x80000000000; + dw 0x100000000000; + dw 0x200000000000; + dw 0x400000000000; + dw 0x800000000000; + dw 0x1000000000000; + dw 0x2000000000000; + dw 0x4000000000000; + dw 0x8000000000000; + dw 0x10000000000000; + dw 0x20000000000000; + dw 0x40000000000000; + dw 0x80000000000000; + dw 0x100000000000000; + dw 0x200000000000000; + dw 0x400000000000000; + dw 0x800000000000000; + dw 0x1000000000000000; + dw 0x2000000000000000; + dw 0x4000000000000000; + dw 0x8000000000000000; + dw 0x10000000000000000; + dw 0x20000000000000000; + dw 0x40000000000000000; + dw 0x80000000000000000; + dw 0x100000000000000000; + dw 0x200000000000000000; + dw 0x400000000000000000; + dw 0x800000000000000000; + dw 0x1000000000000000000; + dw 0x2000000000000000000; + dw 0x4000000000000000000; + dw 0x8000000000000000000; + dw 0x10000000000000000000; + dw 0x20000000000000000000; + dw 0x40000000000000000000; + dw 0x80000000000000000000; + dw 0x100000000000000000000; + dw 0x200000000000000000000; + dw 0x400000000000000000000; + dw 0x800000000000000000000; + dw 0x1000000000000000000000; + dw 0x2000000000000000000000; + dw 0x4000000000000000000000; + dw 0x8000000000000000000000; + dw 0x10000000000000000000000; + dw 0x20000000000000000000000; + dw 0x40000000000000000000000; + dw 0x80000000000000000000000; + dw 0x100000000000000000000000; + dw 0x200000000000000000000000; + dw 0x400000000000000000000000; + dw 0x800000000000000000000000; + dw 0x1000000000000000000000000; + dw 0x2000000000000000000000000; + dw 0x4000000000000000000000000; + dw 0x8000000000000000000000000; + dw 0x10000000000000000000000000; + dw 0x20000000000000000000000000; + dw 0x40000000000000000000000000; + dw 0x80000000000000000000000000; + dw 0x100000000000000000000000000; + dw 0x200000000000000000000000000; + dw 0x400000000000000000000000000; + dw 0x800000000000000000000000000; + dw 0x1000000000000000000000000000; + dw 0x2000000000000000000000000000; + dw 0x4000000000000000000000000000; + dw 0x8000000000000000000000000000; + dw 0x10000000000000000000000000000; + dw 0x20000000000000000000000000000; + dw 0x40000000000000000000000000000; + dw 0x80000000000000000000000000000; + dw 0x100000000000000000000000000000; + dw 0x200000000000000000000000000000; + dw 0x400000000000000000000000000000; + dw 0x800000000000000000000000000000; + dw 0x1000000000000000000000000000000; + dw 0x2000000000000000000000000000000; + dw 0x4000000000000000000000000000000; + dw 0x8000000000000000000000000000000; + dw 0x10000000000000000000000000000000; + dw 0x20000000000000000000000000000000; + dw 0x40000000000000000000000000000000; + dw 0x80000000000000000000000000000000; + dw 0x100000000000000000000000000000000; + } + // @credits feltroidprime + // Returns the total number of bits in the uint256 number. + // Assumptions : + // - 0 <= x < 2^256 + // Returns: + // - nbits: felt - Total number of bits in the uint256 number. + func get_u256_bitlength{range_check_ptr}(x: Uint256) -> felt { + if (x.high != 0) { + let x_bit_high = get_felt_bitlength(x.high); + return 128 + x_bit_high; + } else { + if (x.low != 0) { + let x_bit_low = get_felt_bitlength(x.low); + return x_bit_low; + } else { + return 0; + } + } + } +} diff --git a/cairo/src/utils/rlp.cairo b/cairo/src/utils/rlp.cairo new file mode 100644 index 00000000..291b4959 --- /dev/null +++ b/cairo/src/utils/rlp.cairo @@ -0,0 +1,129 @@ +from starkware.cairo.common.bool import FALSE, TRUE +from starkware.cairo.common.math_cmp import is_nn +from starkware.cairo.common.math import assert_not_zero, assert_nn +from starkware.cairo.common.alloc import alloc + +from src.utils.utils import Helpers + +// The namespace handling all RLP computation +namespace RLP { + const TYPE_STRING = 0; + const TYPE_LIST = 1; + + // The type returned when data is RLP decoded + // An RLP Item is either a byte array or a list of other RLP Items. + // The data is either a pointer to the first byte in the array or a pointer to the first Item in the list. + // If the data is a list then the data_len is the number of items in the list. + // and the `data` field can be casted to a `Item*` to access the bytes. + // If the data is a byte array then the data_len is the length of the array. + struct Item { + data_len: felt, + data: felt*, + is_list: felt, + } + + // @notive Decode the type of an RLP item. + // @dev Unsafe function, does not check if the data is long enough (can be exploited by a malicious prover). + // Always check afterwards that outputs are compatible with the associated data_len. + // @param data The RLP encoded data. + // @return rlp_type The type of the RLP data (string or list). + // @return offset The offset of the data in the RLP encoded data. + // @return len The length of the data. + func decode_type_unsafe{range_check_ptr}(data: felt*) -> ( + rlp_type: felt, offset: felt, len: felt + ) { + alloc_locals; + + let prefix = [data]; + + // Char + let is_le_127 = is_nn(0x7f - prefix); + if (is_le_127 != FALSE) { + return (TYPE_STRING, 0, 1); + } + + let is_le_183 = is_nn(0xb7 - prefix); // a max 55 bytes long string + if (is_le_183 != FALSE) { + return (TYPE_STRING, 1, prefix - 0x80); + } + + let is_le_191 = is_nn(0xbf - prefix); // string longer than 55 bytes + if (is_le_191 != FALSE) { + local len_bytes_count = prefix - 0xb7; + let string_len = Helpers.bytes_to_felt(len_bytes_count, data + 1); + assert [range_check_ptr] = string_len; + let range_check_ptr = range_check_ptr + 1; + return (TYPE_STRING, 1 + len_bytes_count, string_len); + } + + let is_le_247 = is_nn(0xf7 - prefix); // list 0-55 bytes long + if (is_le_247 != FALSE) { + local list_len = prefix - 0xc0; + return (TYPE_LIST, 1, list_len); + } + + local len_bytes_count = prefix - 0xf7; + let list_len = Helpers.bytes_to_felt(len_bytes_count, data + 1); + tempvar offset = 1 + len_bytes_count; + assert [range_check_ptr] = offset; + assert [range_check_ptr + 1] = list_len; + let range_check_ptr = range_check_ptr + 2; + return (TYPE_LIST, offset, list_len); + } + + // @notice Decodes a Recursive Length Prefix (RLP) encoded data. + // @notice This function decodes the RLP encoded data into a list of items. + // Each item is a struct containing the length of the data, the data itself, and a flag indicating whether the data is a list. + // The function first determines the type of the RLP data (string or list) and then processes it accordingly. + // If the data is a string, it is simply added to the items. + // If the data is a list, it is recursively decoded. + // After processing the first item, the function checks if there is more data to decode and if so, + // it recursively decodes the remaining data and adds the decoded items to the list of items. + // @param data_len The length of the data to decode. + // @param data The RLP encoded data. + // @param items The pointer to the next free cell in the list of items decoded. + // @return items_len The number of items decoded. + func decode_raw{range_check_ptr}(items: Item*, data_len: felt, data: felt*) -> felt { + alloc_locals; + + if (data_len == 0) { + return 0; + } + + with_attr error_message("RLP data too short for declared length") { + let (rlp_type, offset, len) = decode_type_unsafe(data); + assert [range_check_ptr] = offset + len; + local remaining_data_len = data_len - [range_check_ptr]; + let range_check_ptr = range_check_ptr + 1; + assert_nn(remaining_data_len); + } + + if (rlp_type == TYPE_LIST) { + let (sub_items: Item*) = alloc(); + let sub_items_len = decode_raw(items=sub_items, data_len=len, data=data + offset); + assert [items] = Item(sub_items_len, cast(sub_items, felt*), TRUE); + tempvar range_check_ptr = range_check_ptr; + } else { + assert [items] = Item(data_len=len, data=data + offset, is_list=FALSE); + tempvar range_check_ptr = range_check_ptr; + } + tempvar items = items + Item.SIZE; + + let items_len = decode_raw( + items=items, data_len=remaining_data_len, data=data + offset + len + ); + return 1 + items_len; + } + + func decode{range_check_ptr}(items: Item*, data_len: felt, data: felt*) { + alloc_locals; + let (rlp_type, offset, len) = decode_type_unsafe(data); + local extra_bytes = data_len - offset - len; + with_attr error_message("RLP string ends with {extra_bytes} superfluous bytes") { + assert extra_bytes = 0; + } + let items_len = decode_raw(items=items, data_len=data_len, data=data); + assert items_len = 1; + return (); + } +} diff --git a/cairo/src/utils/sha_256/packed_sha256.cairo b/cairo/src/utils/sha_256/packed_sha256.cairo new file mode 100644 index 00000000..2fc0e40c --- /dev/null +++ b/cairo/src/utils/sha_256/packed_sha256.cairo @@ -0,0 +1,288 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.registers import get_fp_and_pc + +const BLOCK_SIZE = 7; +const ALL_ONES = 2 ** 251 - 1; +// Pack the different instances with offsets of 35 bits. This is the maximal possible offset for +// 7 32-bit words and it allows space for carry bits in integer addition operations (up to +// 8 summands). +const SHIFTS = 1 + 2 ** 35 + 2 ** (35 * 2) + 2 ** (35 * 3) + 2 ** (35 * 4) + 2 ** (35 * 5) + 2 ** ( + 35 * 6 +); + +// Given an array of size 16, extends it to the message schedule array (of size 64) by writing +// 48 more values. +// Each element represents 7 32-bit words from 7 difference instances, starting at bits +// 0, 35, 35 * 2, ..., 35 * 6. +func compute_message_schedule{bitwise_ptr: BitwiseBuiltin*}(message: felt*) { + alloc_locals; + + // Defining the following constants as local variables saves some instructions. + local shift_mask3 = SHIFTS * (2 ** 32 - 2 ** 3); + local shift_mask7 = SHIFTS * (2 ** 32 - 2 ** 7); + local shift_mask10 = SHIFTS * (2 ** 32 - 2 ** 10); + local shift_mask17 = SHIFTS * (2 ** 32 - 2 ** 17); + local shift_mask18 = SHIFTS * (2 ** 32 - 2 ** 18); + local shift_mask19 = SHIFTS * (2 ** 32 - 2 ** 19); + local mask32ones = SHIFTS * (2 ** 32 - 1); + + // Loop variables. + tempvar bitwise_ptr = bitwise_ptr; + tempvar message = message + 16; + tempvar n = 64 - 16; + + loop: + // Compute s0 = right_rot(w[i - 15], 7) ^ right_rot(w[i - 15], 18) ^ (w[i - 15] >> 3). + tempvar w0 = message[-15]; + assert bitwise_ptr[0].x = w0; + assert bitwise_ptr[0].y = shift_mask7; + let w0_rot7 = (2 ** (32 - 7)) * w0 + (1 / 2 ** 7 - 2 ** (32 - 7)) * bitwise_ptr[0].x_and_y; + assert bitwise_ptr[1].x = w0; + assert bitwise_ptr[1].y = shift_mask18; + let w0_rot18 = (2 ** (32 - 18)) * w0 + (1 / 2 ** 18 - 2 ** (32 - 18)) * bitwise_ptr[1].x_and_y; + assert bitwise_ptr[2].x = w0; + assert bitwise_ptr[2].y = shift_mask3; + let w0_shift3 = (1 / 2 ** 3) * bitwise_ptr[2].x_and_y; + assert bitwise_ptr[3].x = w0_rot7; + assert bitwise_ptr[3].y = w0_rot18; + assert bitwise_ptr[4].x = bitwise_ptr[3].x_xor_y; + assert bitwise_ptr[4].y = w0_shift3; + let s0 = bitwise_ptr[4].x_xor_y; + let bitwise_ptr = bitwise_ptr + 5 * BitwiseBuiltin.SIZE; + + // Compute s1 = right_rot(w[i - 2], 17) ^ right_rot(w[i - 2], 19) ^ (w[i - 2] >> 10). + tempvar w1 = message[-2]; + assert bitwise_ptr[0].x = w1; + assert bitwise_ptr[0].y = shift_mask17; + let w1_rot17 = (2 ** (32 - 17)) * w1 + (1 / 2 ** 17 - 2 ** (32 - 17)) * bitwise_ptr[0].x_and_y; + assert bitwise_ptr[1].x = w1; + assert bitwise_ptr[1].y = shift_mask19; + let w1_rot19 = (2 ** (32 - 19)) * w1 + (1 / 2 ** 19 - 2 ** (32 - 19)) * bitwise_ptr[1].x_and_y; + assert bitwise_ptr[2].x = w1; + assert bitwise_ptr[2].y = shift_mask10; + let w1_shift10 = (1 / 2 ** 10) * bitwise_ptr[2].x_and_y; + assert bitwise_ptr[3].x = w1_rot17; + assert bitwise_ptr[3].y = w1_rot19; + assert bitwise_ptr[4].x = bitwise_ptr[3].x_xor_y; + assert bitwise_ptr[4].y = w1_shift10; + let s1 = bitwise_ptr[4].x_xor_y; + let bitwise_ptr = bitwise_ptr + 5 * BitwiseBuiltin.SIZE; + + assert bitwise_ptr[0].x = message[-16] + s0 + message[-7] + s1; + assert bitwise_ptr[0].y = mask32ones; + assert message[0] = bitwise_ptr[0].x_and_y; + let bitwise_ptr = bitwise_ptr + BitwiseBuiltin.SIZE; + + tempvar bitwise_ptr = bitwise_ptr; + tempvar message = message + 1; + tempvar n = n - 1; + jmp loop if n != 0; + + return (); +} + +func sha2_compress{bitwise_ptr: BitwiseBuiltin*}( + state: felt*, message: felt*, round_constants: felt* +) -> (new_state: felt*) { + alloc_locals; + + // Defining the following constants as local variables saves some instructions. + local shift_mask2 = SHIFTS * (2 ** 32 - 2 ** 2); + local shift_mask13 = SHIFTS * (2 ** 32 - 2 ** 13); + local shift_mask22 = SHIFTS * (2 ** 32 - 2 ** 22); + local shift_mask6 = SHIFTS * (2 ** 32 - 2 ** 6); + local shift_mask11 = SHIFTS * (2 ** 32 - 2 ** 11); + local shift_mask25 = SHIFTS * (2 ** 32 - 2 ** 25); + local mask32ones = SHIFTS * (2 ** 32 - 1); + + tempvar a = state[0]; + tempvar b = state[1]; + tempvar c = state[2]; + tempvar d = state[3]; + tempvar e = state[4]; + tempvar f = state[5]; + tempvar g = state[6]; + tempvar h = state[7]; + tempvar round_constants = round_constants; + tempvar message = message; + tempvar bitwise_ptr = bitwise_ptr; + tempvar n = 64; + + loop: + // Compute s0 = right_rot(a, 2) ^ right_rot(a, 13) ^ right_rot(a, 22). + assert bitwise_ptr[0].x = a; + assert bitwise_ptr[0].y = shift_mask2; + let a_rot2 = (2 ** (32 - 2)) * a + (1 / 2 ** 2 - 2 ** (32 - 2)) * bitwise_ptr[0].x_and_y; + assert bitwise_ptr[1].x = a; + assert bitwise_ptr[1].y = shift_mask13; + let a_rot13 = (2 ** (32 - 13)) * a + (1 / 2 ** 13 - 2 ** (32 - 13)) * bitwise_ptr[1].x_and_y; + assert bitwise_ptr[2].x = a; + assert bitwise_ptr[2].y = shift_mask22; + let a_rot22 = (2 ** (32 - 22)) * a + (1 / 2 ** 22 - 2 ** (32 - 22)) * bitwise_ptr[2].x_and_y; + assert bitwise_ptr[3].x = a_rot2; + assert bitwise_ptr[3].y = a_rot13; + assert bitwise_ptr[4].x = bitwise_ptr[3].x_xor_y; + assert bitwise_ptr[4].y = a_rot22; + let s0 = bitwise_ptr[4].x_xor_y; + let bitwise_ptr = bitwise_ptr + 5 * BitwiseBuiltin.SIZE; + + // Compute s1 = right_rot(e, 6) ^ right_rot(e, 11) ^ right_rot(e, 25). + assert bitwise_ptr[0].x = e; + assert bitwise_ptr[0].y = shift_mask6; + let e_rot6 = (2 ** (32 - 6)) * e + (1 / 2 ** 6 - 2 ** (32 - 6)) * bitwise_ptr[0].x_and_y; + assert bitwise_ptr[1].x = e; + assert bitwise_ptr[1].y = shift_mask11; + let e_rot11 = (2 ** (32 - 11)) * e + (1 / 2 ** 11 - 2 ** (32 - 11)) * bitwise_ptr[1].x_and_y; + assert bitwise_ptr[2].x = e; + assert bitwise_ptr[2].y = shift_mask25; + let e_rot25 = (2 ** (32 - 25)) * e + (1 / 2 ** 25 - 2 ** (32 - 25)) * bitwise_ptr[2].x_and_y; + assert bitwise_ptr[3].x = e_rot6; + assert bitwise_ptr[3].y = e_rot11; + assert bitwise_ptr[4].x = bitwise_ptr[3].x_xor_y; + assert bitwise_ptr[4].y = e_rot25; + let s1 = bitwise_ptr[4].x_xor_y; + let bitwise_ptr = bitwise_ptr + 5 * BitwiseBuiltin.SIZE; + + // Compute ch = (e & f) ^ ((~e) & g). + assert bitwise_ptr[0].x = e; + assert bitwise_ptr[0].y = f; + assert bitwise_ptr[1].x = ALL_ONES - e; + assert bitwise_ptr[1].y = g; + let ch = bitwise_ptr[0].x_and_y + bitwise_ptr[1].x_and_y; + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + // Compute maj = (a & b) ^ (a & c) ^ (b & c). + assert bitwise_ptr[0].x = a; + assert bitwise_ptr[0].y = b; + assert bitwise_ptr[1].x = bitwise_ptr[0].x_xor_y; + assert bitwise_ptr[1].y = c; + let maj = (a + b + c - bitwise_ptr[1].x_xor_y) / 2; + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + tempvar temp1 = h + s1 + ch + round_constants[0] + message[0]; + tempvar temp2 = s0 + maj; + + assert bitwise_ptr[0].x = temp1 + temp2; + assert bitwise_ptr[0].y = mask32ones; + let new_a = bitwise_ptr[0].x_and_y; + assert bitwise_ptr[1].x = d + temp1; + assert bitwise_ptr[1].y = mask32ones; + let new_e = bitwise_ptr[1].x_and_y; + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + + tempvar new_a = new_a; + tempvar new_b = a; + tempvar new_c = b; + tempvar new_d = c; + tempvar new_e = new_e; + tempvar new_f = e; + tempvar new_g = f; + tempvar new_h = g; + tempvar round_constants = round_constants + 1; + tempvar message = message + 1; + tempvar bitwise_ptr = bitwise_ptr; + tempvar n = n - 1; + jmp loop if n != 0; + + // Add the compression result to the original state: + let (res) = alloc(); + assert bitwise_ptr[0].x = state[0] + new_a; + assert bitwise_ptr[0].y = mask32ones; + assert res[0] = bitwise_ptr[0].x_and_y; + assert bitwise_ptr[1].x = state[1] + new_b; + assert bitwise_ptr[1].y = mask32ones; + assert res[1] = bitwise_ptr[1].x_and_y; + assert bitwise_ptr[2].x = state[2] + new_c; + assert bitwise_ptr[2].y = mask32ones; + assert res[2] = bitwise_ptr[2].x_and_y; + assert bitwise_ptr[3].x = state[3] + new_d; + assert bitwise_ptr[3].y = mask32ones; + assert res[3] = bitwise_ptr[3].x_and_y; + assert bitwise_ptr[4].x = state[4] + new_e; + assert bitwise_ptr[4].y = mask32ones; + assert res[4] = bitwise_ptr[4].x_and_y; + assert bitwise_ptr[5].x = state[5] + new_f; + assert bitwise_ptr[5].y = mask32ones; + assert res[5] = bitwise_ptr[5].x_and_y; + assert bitwise_ptr[6].x = state[6] + new_g; + assert bitwise_ptr[6].y = mask32ones; + assert res[6] = bitwise_ptr[6].x_and_y; + assert bitwise_ptr[7].x = state[7] + new_h; + assert bitwise_ptr[7].y = mask32ones; + assert res[7] = bitwise_ptr[7].x_and_y; + let bitwise_ptr = bitwise_ptr + 8 * BitwiseBuiltin.SIZE; + + return (res,); +} + +// Returns the 64 round constants of SHA256. +func get_round_constants() -> (round_constants: felt*) { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + local round_constants = 0x428A2F98 * SHIFTS; + local a = 0x71374491 * SHIFTS; + local a = 0xB5C0FBCF * SHIFTS; + local a = 0xE9B5DBA5 * SHIFTS; + local a = 0x3956C25B * SHIFTS; + local a = 0x59F111F1 * SHIFTS; + local a = 0x923F82A4 * SHIFTS; + local a = 0xAB1C5ED5 * SHIFTS; + local a = 0xD807AA98 * SHIFTS; + local a = 0x12835B01 * SHIFTS; + local a = 0x243185BE * SHIFTS; + local a = 0x550C7DC3 * SHIFTS; + local a = 0x72BE5D74 * SHIFTS; + local a = 0x80DEB1FE * SHIFTS; + local a = 0x9BDC06A7 * SHIFTS; + local a = 0xC19BF174 * SHIFTS; + local a = 0xE49B69C1 * SHIFTS; + local a = 0xEFBE4786 * SHIFTS; + local a = 0x0FC19DC6 * SHIFTS; + local a = 0x240CA1CC * SHIFTS; + local a = 0x2DE92C6F * SHIFTS; + local a = 0x4A7484AA * SHIFTS; + local a = 0x5CB0A9DC * SHIFTS; + local a = 0x76F988DA * SHIFTS; + local a = 0x983E5152 * SHIFTS; + local a = 0xA831C66D * SHIFTS; + local a = 0xB00327C8 * SHIFTS; + local a = 0xBF597FC7 * SHIFTS; + local a = 0xC6E00BF3 * SHIFTS; + local a = 0xD5A79147 * SHIFTS; + local a = 0x06CA6351 * SHIFTS; + local a = 0x14292967 * SHIFTS; + local a = 0x27B70A85 * SHIFTS; + local a = 0x2E1B2138 * SHIFTS; + local a = 0x4D2C6DFC * SHIFTS; + local a = 0x53380D13 * SHIFTS; + local a = 0x650A7354 * SHIFTS; + local a = 0x766A0ABB * SHIFTS; + local a = 0x81C2C92E * SHIFTS; + local a = 0x92722C85 * SHIFTS; + local a = 0xA2BFE8A1 * SHIFTS; + local a = 0xA81A664B * SHIFTS; + local a = 0xC24B8B70 * SHIFTS; + local a = 0xC76C51A3 * SHIFTS; + local a = 0xD192E819 * SHIFTS; + local a = 0xD6990624 * SHIFTS; + local a = 0xF40E3585 * SHIFTS; + local a = 0x106AA070 * SHIFTS; + local a = 0x19A4C116 * SHIFTS; + local a = 0x1E376C08 * SHIFTS; + local a = 0x2748774C * SHIFTS; + local a = 0x34B0BCB5 * SHIFTS; + local a = 0x391C0CB3 * SHIFTS; + local a = 0x4ED8AA4A * SHIFTS; + local a = 0x5B9CCA4F * SHIFTS; + local a = 0x682E6FF3 * SHIFTS; + local a = 0x748F82EE * SHIFTS; + local a = 0x78A5636F * SHIFTS; + local a = 0x84C87814 * SHIFTS; + local a = 0x8CC70208 * SHIFTS; + local a = 0x90BEFFFA * SHIFTS; + local a = 0xA4506CEB * SHIFTS; + local a = 0xBEF9A3F7 * SHIFTS; + local a = 0xC67178F2 * SHIFTS; + return (&round_constants,); +} diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo new file mode 100644 index 00000000..6d17b3b7 --- /dev/null +++ b/cairo/src/utils/signature.cairo @@ -0,0 +1,34 @@ +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.cairo_secp.bigint3 import BigInt3, UnreducedBigInt3 +from starkware.cairo.common.cairo_secp.signature import validate_signature_entry +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.cairo_secp.bigint import uint256_to_bigint + +from src.interfaces.interfaces import ICairo1Helpers + +namespace Signature { + // A version of verify_eth_signature, with that msg_hash, r and s as Uint256 and + // using the Cairo1 helpers class. + func verify_eth_signature_uint256{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + msg_hash: Uint256, r: Uint256, s: Uint256, v: felt, eth_address: felt + ) { + alloc_locals; + let (msg_hash_bigint: BigInt3) = uint256_to_bigint(msg_hash); + let (r_bigint: BigInt3) = uint256_to_bigint(r); + let (s_bigint: BigInt3) = uint256_to_bigint(s); + + with_attr error_message("Signature out of range.") { + validate_signature_entry(r_bigint); + validate_signature_entry(s_bigint); + } + + with_attr error_message("Invalid signature.") { + let (success, recovered_address) = ICairo1Helpers.recover_eth_address( + msg_hash=msg_hash, r=r, s=s, y_parity=v + ); + assert success = 1; + assert eth_address = recovered_address; + } + return (); + } +} diff --git a/cairo/src/utils/uint256.cairo b/cairo/src/utils/uint256.cairo new file mode 100644 index 00000000..3068649a --- /dev/null +++ b/cairo/src/utils/uint256.cairo @@ -0,0 +1,394 @@ +from starkware.cairo.common.uint256 import ( + Uint256, + uint256_mul, + uint256_le, + uint256_pow2, + SHIFT, + ALL_ONES, + uint256_lt, + uint256_not, +) +from starkware.cairo.common.bool import FALSE +from starkware.cairo.common.math_cmp import is_nn + +from src.utils.maths import unsigned_div_rem + +// Adds two integers. Returns the result as a 256-bit integer and the (1-bit) carry. +// Strictly equivalent and faster version of common.uint256.uint256_add using the same whitelisted hint. +func uint256_add{range_check_ptr}(a: Uint256, b: Uint256) -> (res: Uint256, carry: felt) { + alloc_locals; + local carry_low: felt; + local carry_high: felt; + %{ + sum_low = ids.a.low + ids.b.low + ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 + sum_high = ids.a.high + ids.b.high + ids.carry_low + ids.carry_high = 1 if sum_high >= ids.SHIFT else 0 + %} + + if (carry_low != 0) { + if (carry_high != 0) { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low - SHIFT, high=a.high + b.high + 1 - SHIFT); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res, 1); + } else { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low - SHIFT, high=a.high + b.high + 1); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res, 0); + } + } else { + if (carry_high != 0) { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low, high=a.high + b.high - SHIFT); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res, 1); + } else { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low, high=a.high + b.high); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res, 0); + } + } +} + +// Subtracts two integers. Returns the result as a 256-bit integer. +// Strictly equivalent and faster version of common.uint256.uint256_sub using uint256_add's whitelisted hint. +func uint256_sub{range_check_ptr}(a: Uint256, b: Uint256) -> (res: Uint256) { + alloc_locals; + // Reference "b" as -b. + local b: Uint256 = Uint256(ALL_ONES - b.low + 1, ALL_ONES - b.high); + // Computes a + (-b) + local carry_low: felt; + local carry_high: felt; + %{ + sum_low = ids.a.low + ids.b.low + ids.carry_low = 1 if sum_low >= ids.SHIFT else 0 + sum_high = ids.a.high + ids.b.high + ids.carry_low + ids.carry_high = 1 if sum_high >= ids.SHIFT else 0 + %} + + if (carry_low != 0) { + if (carry_high != 0) { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low - SHIFT, high=a.high + b.high + 1 - SHIFT); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res,); + } else { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low - SHIFT, high=a.high + b.high + 1); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res,); + } + } else { + if (carry_high != 0) { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low, high=a.high + b.high - SHIFT); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res,); + } else { + tempvar range_check_ptr = range_check_ptr + 2; + tempvar res = Uint256(low=a.low + b.low, high=a.high + b.high); + assert [range_check_ptr - 2] = res.low; + assert [range_check_ptr - 1] = res.high; + return (res,); + } + } +} + +// ! The following functions are taken from starkware's cairo common library +// ! to use the optimized uint256_add and uint256_sub, with inlined uint256_check + +// Returns 1 if the first signed integer is less than the second signed integer. +func uint256_signed_lt{range_check_ptr}(a: Uint256, b: Uint256) -> (res: felt) { + alloc_locals; + let (a, _) = uint256_add(a, Uint256(low=0, high=2 ** 127)); + let (b, _) = uint256_add(b, Uint256(low=0, high=2 ** 127)); + return uint256_lt(a, b); +} + +// Unsigned integer division between two integers. Returns the quotient and the remainder. +// Conforms to EVM specifications: division by 0 yields 0. +func uint256_unsigned_div_rem{range_check_ptr}(a: Uint256, div: Uint256) -> ( + quotient: Uint256, remainder: Uint256 +) { + alloc_locals; + + // If div == 0, return (0, 0). + if (div.low + div.high == 0) { + return (quotient=Uint256(0, 0), remainder=Uint256(0, 0)); + } + + // Guess the quotient and the remainder. + local quotient: Uint256; + local remainder: Uint256; + %{ + a = (ids.a.high << 128) + ids.a.low + div = (ids.div.high << 128) + ids.div.low + quotient, remainder = divmod(a, div) + + ids.quotient.low = quotient & ((1 << 128) - 1) + ids.quotient.high = quotient >> 128 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + %} + [range_check_ptr] = quotient.low; + [range_check_ptr + 1] = quotient.high; + [range_check_ptr + 2] = remainder.low; + [range_check_ptr + 3] = remainder.high; + let range_check_ptr = range_check_ptr + 4; + let (res_mul, carry) = uint256_mul(quotient, div); + assert carry = Uint256(0, 0); + + let (check_val, add_carry) = uint256_add(res_mul, remainder); + assert check_val = a; + assert add_carry = 0; + + let (is_valid) = uint256_lt(remainder, div); + assert is_valid = 1; + return (quotient=quotient, remainder=remainder); +} + +// Computes: +// 1. The integer division `(a * b) // div` (as a 512-bit number). +// 2. The remainder `(a * b) modulo div`. +// Assumption: div != 0. +func uint256_mul_div_mod{range_check_ptr}(a: Uint256, b: Uint256, div: Uint256) -> ( + quotient_low: Uint256, quotient_high: Uint256, remainder: Uint256 +) { + alloc_locals; + + // Compute a * b (512 bits). + let (ab_low, ab_high) = uint256_mul(a, b); + + // Guess the quotient and remainder of (a * b) / d. + local quotient_low: Uint256; + local quotient_high: Uint256; + local remainder: Uint256; + + %{ + a = (ids.a.high << 128) + ids.a.low + b = (ids.b.high << 128) + ids.b.low + div = (ids.div.high << 128) + ids.div.low + quotient, remainder = divmod(a * b, div) + + ids.quotient_low.low = quotient & ((1 << 128) - 1) + ids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1) + ids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1) + ids.quotient_high.high = quotient >> 384 + ids.remainder.low = remainder & ((1 << 128) - 1) + ids.remainder.high = remainder >> 128 + %} + + // Compute x = quotient * div + remainder. + [range_check_ptr] = quotient_high.low; + [range_check_ptr + 1] = quotient_high.high; + let range_check_ptr = range_check_ptr + 2; + let (quotient_mod10, quotient_mod11) = uint256_mul(quotient_high, div); + + [range_check_ptr] = quotient_low.low; + [range_check_ptr + 1] = quotient_low.high; + let range_check_ptr = range_check_ptr + 2; + let (quotient_mod00, quotient_mod01) = uint256_mul(quotient_low, div); + // Since x should equal a * b, the high 256 bits must be zero. + assert quotient_mod11 = Uint256(0, 0); + + // The low 256 bits of x must be ab_low. + [range_check_ptr] = remainder.low; + [range_check_ptr + 1] = remainder.high; + let range_check_ptr = range_check_ptr + 2; + let (x0, carry0) = uint256_add(quotient_mod00, remainder); + assert x0 = ab_low; + + let (x1, carry1) = uint256_add(quotient_mod01, quotient_mod10); + assert carry1 = 0; + let (x1, carry2) = uint256_add(x1, Uint256(low=carry0, high=0)); + assert carry2 = 0; + + assert x1 = ab_high; + + // Verify that 0 <= remainder < div. + let (is_valid) = uint256_lt(remainder, div); + assert is_valid = 1; + + return (quotient_low=quotient_low, quotient_high=quotient_high, remainder=remainder); +} + +// Returns the negation of an integer. +// Note that the negation of -2**255 is -2**255. +func uint256_neg{range_check_ptr}(a: Uint256) -> (res: Uint256) { + let (not_num) = uint256_not(a); + let (res, _) = uint256_add(not_num, Uint256(low=1, high=0)); + return (res=res); +} + +// Conditionally negates an integer. +func uint256_cond_neg{range_check_ptr}(a: Uint256, should_neg) -> (res: Uint256) { + if (should_neg != 0) { + return uint256_neg(a); + } else { + return (res=a); + } +} + +// Signed integer division between two integers. Returns the quotient and the remainder. +// Conforms to EVM specifications. +// See ethereum yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf, page 29). +// Note that the remainder may be negative if one of the inputs is negative and that +// (-2**255) / (-1) = -2**255 because 2*255 is out of range. +func uint256_signed_div_rem{range_check_ptr}(a: Uint256, div: Uint256) -> ( + quot: Uint256, rem: Uint256 +) { + alloc_locals; + + // When div=-1, simply return -a. + if (div.low == SHIFT - 1 and div.high == SHIFT - 1) { + let (quot) = uint256_neg(a); + return (quot, cast((0, 0), Uint256)); + } + + // Take the absolute value of a. + local a_sign = is_nn(a.high - 2 ** 127); + local range_check_ptr = range_check_ptr; + let (local a) = uint256_cond_neg(a, should_neg=a_sign); + + // Take the absolute value of div. + local div_sign = is_nn(div.high - 2 ** 127); + local range_check_ptr = range_check_ptr; + let (div) = uint256_cond_neg(div, should_neg=div_sign); + + // Unsigned division. + let (local quot, local rem) = uint256_unsigned_div_rem(a, div); + local range_check_ptr = range_check_ptr; + + // Fix the remainder according to the sign of a. + let (rem) = uint256_cond_neg(rem, should_neg=a_sign); + + // Fix the quotient according to the signs of a and div. + if (a_sign == div_sign) { + return (quot=quot, rem=rem); + } + let (local quot_neg) = uint256_neg(quot); + + return (quot=quot_neg, rem=rem); +} + +// Computes the logical right shift of a uint256 integer. +func uint256_shr{range_check_ptr}(a: Uint256, b: Uint256) -> (res: Uint256) { + let (c) = uint256_pow2(b); + let (res, _) = uint256_unsigned_div_rem(a, c); + return (res=res); +} + +// ! End of functions taken from starkware's cairo common library + +// @notice Internal exponentiation of two 256-bit integers. +// @dev The result is modulo 2^256. +// @param value - The base. +// @param exponent - The exponent. +// @return The result of the exponentiation. +func uint256_exp{range_check_ptr}(value: Uint256, exponent: Uint256) -> Uint256 { + let one = Uint256(1, 0); + let zero = Uint256(0, 0); + + let (exponent_is_zero) = uint256_eq(exponent, zero); + if (exponent_is_zero != FALSE) { + return one; + } + let (exponent_minus_one) = uint256_sub(exponent, one); + let pow = uint256_exp(value, exponent_minus_one); + let (res, _) = uint256_mul(value, pow); + return res; +} + +// @notice Extend a signed number which fits in N bytes to 32 bytes. +// @param x The number to be sign extended. +// @param byte_num The size in bytes minus one of x to consider. +// @returns x if byteNum > 31, or x interpreted as a signed number with sign-bit at (byte_num*8+7), extended to the full 256 bits +func uint256_signextend{range_check_ptr}(x: Uint256, byte_num: Uint256) -> Uint256 { + alloc_locals; + let (byte_num_gt_word_size) = uint256_le(Uint256(32, 0), byte_num); + if (byte_num_gt_word_size != 0) { + return x; + } + + let sign_bit_position = byte_num.low * 8 + 7; + + let (s) = uint256_pow2(Uint256(sign_bit_position, 0)); + let (sign_bit, value) = uint256_unsigned_div_rem(x, s); + let (_, x_is_negative) = uint256_unsigned_div_rem(sign_bit, Uint256(2, 0)); + + if (x_is_negative.low == 0) { + return value; + } + + let (mask) = uint256_sub(s, Uint256(1, 0)); + let max_uint256 = Uint256(2 ** 128 - 1, 2 ** 128 - 1); + let (padding) = uint256_sub(max_uint256, mask); + let (value, _) = uint256_add(value, padding); + return value; +} + +// @notice Internal fast exponentiation of two 256-bit integers. +// @dev The result is modulo 2^256. +// @param value - The base. +// @param exponent - The exponent. +// @return The result of the exponentiation. +func uint256_fast_exp{range_check_ptr}(value: Uint256, exponent: Uint256) -> Uint256 { + alloc_locals; + + let one = Uint256(1, 0); + let zero = Uint256(0, 0); + + let (exponent_is_zero) = uint256_eq(exponent, zero); + if (exponent_is_zero != FALSE) { + return one; + } + + let (exponent_is_one) = uint256_eq(exponent, one); + if (exponent_is_one != FALSE) { + return value; + } + + let (half_exponent, is_odd) = uint256_unsigned_div_rem(exponent, Uint256(2, 0)); + let pow = uint256_fast_exp(value, half_exponent); + + if (is_odd.low != FALSE) { + let (res, _) = uint256_mul(pow, pow); + let (res, _) = uint256_mul(res, value); + return res; + } + + let pow = uint256_fast_exp(value, half_exponent); + let (res, _) = uint256_mul(pow, pow); + return res; +} + +// @notice Converts a 256-bit unsigned integer to a 160-bit unsigned integer. +// @dev The result is modulo 2^160. +// @param x The 256-bit unsigned integer. +// @return The 160-bit unsigned integer. +func uint256_to_uint160{range_check_ptr}(x: Uint256) -> felt { + let (_, high) = unsigned_div_rem(x.high, 2 ** 32); + return x.low + high * 2 ** 128; +} + +// @notice Return true if both integers are equal. +// @dev Same as the one from starkware's cairo common library, but without the useless range_check arg +func uint256_eq(a: Uint256, b: Uint256) -> (res: felt) { + if (a.high != b.high) { + return (res=0); + } + if (a.low != b.low) { + return (res=0); + } + return (res=1); +} diff --git a/cairo/src/utils/uint256.py b/cairo/src/utils/uint256.py new file mode 100644 index 00000000..4e13b95d --- /dev/null +++ b/cairo/src/utils/uint256.py @@ -0,0 +1,8 @@ +def int_to_uint256(value): + low = value & ((1 << 128) - 1) + high = value >> 128 + return low, high + + +def uint256_to_int(low, high): + return low + high * 2**128 diff --git a/cairo/src/utils/utils.cairo b/cairo/src/utils/utils.cairo new file mode 100644 index 00000000..fa4db228 --- /dev/null +++ b/cairo/src/utils/utils.cairo @@ -0,0 +1,1031 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.math import assert_le, split_felt, assert_nn_le +from starkware.cairo.common.math_cmp import is_nn, is_not_zero +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.dict import dict_write +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.cairo_secp.bigint import BigInt3, bigint_to_uint256, uint256_to_bigint +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin + +from src.model import model +from src.utils.bytes import uint256_to_bytes32, felt_to_bytes32 +from src.utils.maths import unsigned_div_rem + +// @title Helper Functions +// @notice This file contains a selection of helper function that simplify tasks such as type conversion and bit manipulation +namespace Helpers { + // Returns 1 if value == 0. Returns 0 otherwise. + @known_ap_change + func is_zero(value) -> felt { + if (value == 0) { + return 1; + } + + return 0; + } + + // @notice Performs subtraction and returns 0 if the result is negative. + func saturated_sub{range_check_ptr}(a, b) -> felt { + let res = a - b; + let is_res_nn = is_nn(res); + if (is_res_nn != FALSE) { + return res; + } + return 0; + } + + func to_uint256{range_check_ptr}(val: felt) -> Uint256* { + let (high, low) = split_felt(val); + tempvar res = new Uint256(low, high); + return res; + } + + // @notice This helper converts a felt straight to BigInt3 + // @param val: felt value to be converted + // @return res: BigInt3 representation of the given input + func to_bigint{range_check_ptr}(val: felt) -> BigInt3 { + let val_uint256: Uint256 = to_uint256(val); + let (res: BigInt3) = uint256_to_bigint(val_uint256); + return res; + } + + // @notice This helper converts a BigInt3 straight to felt + // @param val: BigInt3 value to be converted + // @return res: felt representation of the given input + func bigint_to_felt{range_check_ptr}(val: BigInt3) -> felt { + let (val_uint256: Uint256) = bigint_to_uint256(val); + let res = uint256_to_felt(val_uint256); + return res; + } + + // @notice This function is used to convert a sequence of 32 bytes to Uint256. + // @param val: pointer to the first byte of the 32. + // @return res: Uint256 representation of the given input in bytes32. + func bytes32_to_uint256(val: felt*) -> Uint256 { + let low = [val + 16] * 256 ** 15; + let low = low + [val + 17] * 256 ** 14; + let low = low + [val + 18] * 256 ** 13; + let low = low + [val + 19] * 256 ** 12; + let low = low + [val + 20] * 256 ** 11; + let low = low + [val + 21] * 256 ** 10; + let low = low + [val + 22] * 256 ** 9; + let low = low + [val + 23] * 256 ** 8; + let low = low + [val + 24] * 256 ** 7; + let low = low + [val + 25] * 256 ** 6; + let low = low + [val + 26] * 256 ** 5; + let low = low + [val + 27] * 256 ** 4; + let low = low + [val + 28] * 256 ** 3; + let low = low + [val + 29] * 256 ** 2; + let low = low + [val + 30] * 256 ** 1; + let low = low + [val + 31]; + let high = [val] * 256 ** 1 * 256 ** 14; + let high = high + [val + 1] * 256 ** 14; + let high = high + [val + 2] * 256 ** 13; + let high = high + [val + 3] * 256 ** 12; + let high = high + [val + 4] * 256 ** 11; + let high = high + [val + 5] * 256 ** 10; + let high = high + [val + 6] * 256 ** 9; + let high = high + [val + 7] * 256 ** 8; + let high = high + [val + 8] * 256 ** 7; + let high = high + [val + 9] * 256 ** 6; + let high = high + [val + 10] * 256 ** 5; + let high = high + [val + 11] * 256 ** 4; + let high = high + [val + 12] * 256 ** 3; + let high = high + [val + 13] * 256 ** 2; + let high = high + [val + 14] * 256; + let high = high + [val + 15]; + let res = Uint256(low=low, high=high); + return res; + } + // @notice This function is used to convert bytes array in big-endian to Uint256. + // @dev The function is limited to 32 bytes or less. + // @param bytes_len: bytes array length. + // @param bytes: pointer to the first byte of the bytes array. + // @return res: Uint256 representation of the given input in bytes. + func bytes_to_uint256{range_check_ptr}(bytes_len: felt, bytes: felt*) -> Uint256 { + alloc_locals; + + if (bytes_len == 0) { + let res = Uint256(0, 0); + return res; + } + + let is_bytes_len_16_bytes_or_less = is_nn(16 - bytes_len); + + // 1 - 16 bytes + if (is_bytes_len_16_bytes_or_less != FALSE) { + let low = bytes_to_felt(bytes_len, bytes); + let res = Uint256(low=low, high=0); + + return res; + } + + // 17 - 32 bytes + let low = bytes_to_felt(16, bytes + bytes_len - 16); + let high = bytes_to_felt(bytes_len - 16, bytes); + let res = Uint256(low=low, high=high); + + return res; + } + + // @notice This helper is used to convert a sequence of 32 bytes straight to BigInt3. + // @param val: pointer to the first byte of the 32. + // @return res: BigInt3 representation of the given input in bytes32. + func bytes32_to_bigint{range_check_ptr}(val: felt*) -> BigInt3 { + alloc_locals; + + let val_uint256: Uint256 = bytes32_to_uint256(val); + let (res: BigInt3) = uint256_to_bigint(val_uint256); + return res; + } + + // @notice This function is used to convert a BigInt3 to straight to a bytes array represented by an array of felts (1 felt represents 1 byte). + // @param value: BigInt3 value to convert. + // @return: array length and felt array representation of the value. + func bigint_to_bytes_array{range_check_ptr}(val: BigInt3) -> ( + bytes_array_len: felt, bytes_array: felt* + ) { + alloc_locals; + let (val_uint256: Uint256) = bigint_to_uint256(val); + let (bytes: felt*) = alloc(); + uint256_to_bytes32(bytes, val_uint256); + return (32, bytes); + } + + // @notice: This helper returns the minimal number of EVM words for a given bytes length + // @param length: a given bytes length + // @return res: the minimal number of EVM words + func minimum_word_count{range_check_ptr}(length: felt) -> (res: felt) { + let (quotient, remainder) = unsigned_div_rem(length + 31, 32); + return (res=quotient); + } + + // @notice This function is used to convert a sequence of 8 bytes to a felt. + // @param val: pointer to the first byte. + // @return: felt representation of the input. + func bytes_to_64_bits_little_felt(bytes: felt*) -> felt { + let res = [bytes + 7] * 256 ** 7; + let res = res + [bytes + 6] * 256 ** 6; + let res = res + [bytes + 5] * 256 ** 5; + let res = res + [bytes + 4] * 256 ** 4; + let res = res + [bytes + 3] * 256 ** 3; + let res = res + [bytes + 2] * 256 ** 2; + let res = res + [bytes + 1] * 256; + let res = res + [bytes]; + return res; + } + + // @notice This function is used to convert a uint256 to a felt. + // @param val: value to convert. + // @return: felt representation of the input. + func uint256_to_felt{range_check_ptr}(val: Uint256) -> felt { + [range_check_ptr] = val.low; + [range_check_ptr + 1] = val.high; + let range_check_ptr = range_check_ptr + 2; + return val.low + val.high * 2 ** 128; + } + + // @notice Loads a sequence of bytes into a single felt in big-endian. + // @param len: number of bytes. + // @param ptr: pointer to bytes array. + // @return: packed felt. + func bytes_to_felt(len: felt, ptr: felt*) -> felt { + if (len == 0) { + return 0; + } + tempvar current = 0; + + // len, ptr, ?, ?, current + // ?, ? are intermediate steps created by the compiler to unfold the + // complex expression. + loop: + let len = [ap - 5]; + let ptr = cast([ap - 4], felt*); + let current = [ap - 1]; + + tempvar len = len - 1; + tempvar ptr = ptr + 1; + tempvar current = current * 256 + [ptr - 1]; + + static_assert len == [ap - 5]; + static_assert ptr == [ap - 4]; + static_assert current == [ap - 1]; + jmp loop if len != 0; + + return current; + } + + func try_parse_destination_from_bytes(bytes_len: felt, bytes: felt*) -> model.Option { + if (bytes_len != 20) { + with_attr error_message("Bytes has length {bytes_len}, expected 0 or 20") { + assert bytes_len = 0; + } + let res = model.Option(is_some=0, value=0); + return res; + } + let address = bytes20_to_felt(bytes); + let res = model.Option(is_some=1, value=address); + return res; + } + + // @notice This function is used to convert a sequence of 4 bytes big-endian + // to a felt. + // @param val: pointer to the first byte of the 4. + // @return res: felt representation of the given input in bytes4. + func bytes4_to_felt(val: felt*) -> felt { + let current = [val] * 256 ** 3; + let current = current + [val + 1] * 256 ** 2; + let current = current + [val + 2] * 256; + let current = current + [val + 3]; + return current; + } + + // @notice This function is used to convert a sequence of 20 bytes big-endian + // to felt. + // @param val: pointer to the first byte of the 20. + // @return res: felt representation of the given input in bytes20. + func bytes20_to_felt(val: felt*) -> felt { + let current = [val] * 256 ** 19; + let current = current + [val + 1] * 256 ** 18; + let current = current + [val + 2] * 256 ** 17; + let current = current + [val + 3] * 256 ** 16; + let current = current + [val + 4] * 256 ** 15; + let current = current + [val + 5] * 256 ** 14; + let current = current + [val + 6] * 256 ** 13; + let current = current + [val + 7] * 256 ** 12; + let current = current + [val + 8] * 256 ** 11; + let current = current + [val + 9] * 256 ** 10; + let current = current + [val + 10] * 256 ** 9; + let current = current + [val + 11] * 256 ** 8; + let current = current + [val + 12] * 256 ** 7; + let current = current + [val + 13] * 256 ** 6; + let current = current + [val + 14] * 256 ** 5; + let current = current + [val + 15] * 256 ** 4; + let current = current + [val + 16] * 256 ** 3; + let current = current + [val + 17] * 256 ** 2; + let current = current + [val + 18] * 256 ** 1; + let current = current + [val + 19]; + return current; + } + + // @notice This function is used to convert a sequence of 32 bytes big-endian + // to a felt. + // @dev If the value doesn't fit in a felt, the value will be wrapped around. + // @param val: pointer to the first byte of the 32. + // @return res: felt representation of the given input in bytes32. + @known_ap_change + func bytes32_to_felt(val: felt*) -> felt { + let current = [val] * 256 ** 31; + let current = current + [val + 1] * 256 ** 30; + let current = current + [val + 2] * 256 ** 29; + let current = current + [val + 3] * 256 ** 28; + let current = current + [val + 4] * 256 ** 27; + let current = current + [val + 5] * 256 ** 26; + let current = current + [val + 6] * 256 ** 25; + let current = current + [val + 7] * 256 ** 24; + let current = current + [val + 8] * 256 ** 23; + let current = current + [val + 9] * 256 ** 22; + let current = current + [val + 10] * 256 ** 21; + let current = current + [val + 11] * 256 ** 20; + let current = current + [val + 12] * 256 ** 19; + let current = current + [val + 13] * 256 ** 18; + let current = current + [val + 14] * 256 ** 17; + let current = current + [val + 15] * 256 ** 16; + let current = current + [val + 16] * 256 ** 15; + let current = current + [val + 17] * 256 ** 14; + let current = current + [val + 18] * 256 ** 13; + let current = current + [val + 19] * 256 ** 12; + let current = current + [val + 20] * 256 ** 11; + let current = current + [val + 21] * 256 ** 10; + let current = current + [val + 22] * 256 ** 9; + let current = current + [val + 23] * 256 ** 8; + let current = current + [val + 24] * 256 ** 7; + let current = current + [val + 25] * 256 ** 6; + let current = current + [val + 26] * 256 ** 5; + let current = current + [val + 27] * 256 ** 4; + let current = current + [val + 28] * 256 ** 3; + let current = current + [val + 29] * 256 ** 2; + let current = current + [val + 30] * 256 ** 1; + let current = current + [val + 31]; + return current; + } + + // @notice Load sequences of 8 bytes little endian into an array of felts + // @param len: final length of the output. + // @param input: pointer to bytes array input. + // @param output: pointer to bytes array output. + func load_64_bits_array(len: felt, input: felt*, output: felt*) { + if (len == 0) { + return (); + } + let loaded = bytes_to_64_bits_little_felt(input); + assert [output] = loaded; + return load_64_bits_array(len - 1, input + 8, output + 1); + } + + // @notice Load sequence of 32 bytes into an array of felts + // @dev If the input doesn't fit in a felt, the value will be wrapped around. + // @param input_len: The number of bytes in the input. + // @param input: pointer to bytes array input. + // @param output: pointer to bytes array output. + func load_256_bits_array(input_len: felt, input: felt*) -> (output_len: felt, output: felt*) { + alloc_locals; + let (local output_start) = alloc(); + if (input_len == 0) { + return (0, output_start); + } + + tempvar ptr = input; + tempvar output = output_start; + tempvar remaining = input_len; + + loop: + let ptr = cast([ap - 3], felt*); + let output = cast([ap - 2], felt*); + let remaining = [ap - 1]; + + let loaded = bytes32_to_felt(ptr); + assert [output] = loaded; + + tempvar ptr = ptr + 32; + tempvar output = output + 1; + tempvar remaining = remaining - 32; + + static_assert ptr == [ap - 3]; + static_assert output == [ap - 2]; + static_assert remaining == [ap - 1]; + jmp loop if remaining != 0; + + let output_len = output - output_start; + return (output_len, output_start); + } + + // @notice Converts an array of felt to an array of bytes. + // @dev Each input felt is converted to 32 bytes. + // @param input_len: The number of felts in the input. + // @param input: pointer to the input array. + // @param output: pointer to the output array. + func felt_array_to_bytes32_array{range_check_ptr}( + input_len: felt, input: felt*, output: felt* + ) { + if (input_len == 0) { + return (); + } + felt_to_bytes32(output, [input]); + return felt_array_to_bytes32_array(input_len - 1, input + 1, output + 32); + } + + // @notice Divides a 128-bit number with remainder. + // @dev This is almost identical to cairo.common.math.unsigned_dev_rem, but supports the case + // @dev of div == 2**128 as well. assert_le is also inlined. + // @param value: 128bit value to divide. + // @param div: divisor. + // @return: quotient and remainder. + func div_rem{range_check_ptr}(value, div) -> (q: felt, r: felt) { + if (div == 2 ** 128) { + return (0, value); + } + + // Copied from unsigned_div_rem. + let r = [range_check_ptr]; + let q = [range_check_ptr + 1]; + let range_check_ptr = range_check_ptr + 2; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.div) + assert 0 < ids.div <= PRIME // range_check_builtin.bound, \ + f'div={hex(ids.div)} is out of the valid range.' + ids.q, ids.r = divmod(ids.value, ids.div) + %} + + // equivalent to assert_le(r, div - 1); + tempvar a = div - 1 - r; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.' + %} + a = [range_check_ptr]; + let range_check_ptr = range_check_ptr + 1; + + assert value = q * div + r; + return (q, r); + } + + // @notice Computes 256 ** (16 - i) for 0 <= i <= 16. + func pow256_rev(i: felt) -> felt { + let (pow256_rev_address) = get_label_location(pow256_rev_table); + return pow256_rev_address[i]; + + pow256_rev_table: + dw 256 ** 16; + dw 256 ** 15; + dw 256 ** 14; + dw 256 ** 13; + dw 256 ** 12; + dw 256 ** 11; + dw 256 ** 10; + dw 256 ** 9; + dw 256 ** 8; + dw 256 ** 7; + dw 256 ** 6; + dw 256 ** 5; + dw 256 ** 4; + dw 256 ** 3; + dw 256 ** 2; + dw 256 ** 1; + dw 256 ** 0; + } + + // @notice Splits a felt into `len` bytes, big-endian, and outputs to `dst`. + func split_word{range_check_ptr}(value: felt, len: felt, dst: felt*) { + if (len == 0) { + with_attr error_message("value not empty") { + assert value = 0; + } + return (); + } + with_attr error_message("len must be < 32") { + assert is_nn(31 - len) = TRUE; + } + + tempvar len = len - 1; + let output = &dst[len]; + let base = 256; + let bound = 256; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar low_part = [output]; + assert_nn_le(low_part, 255); + return split_word((value - low_part) / 256, len, dst); + } + + // @notice Splits a felt into `len` bytes, little-endian, and outputs to `dst`. + func split_word_little{range_check_ptr}(value: felt, len: felt, dst: felt*) { + if (len == 0) { + with_attr error_message("value not empty") { + assert value = 0; + } + return (); + } + with_attr error_message("len must be < 32") { + assert is_nn(31 - len) = TRUE; + } + let output = &dst[0]; + let base = 256; + let bound = 256; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar low_part = [output]; + assert_nn_le(low_part, 255); + return split_word_little((value - low_part) / 256, len - 1, dst + 1); + } + + // @notice Splits a felt into 16 bytes, big-endian, and outputs to `dst`. + func split_word_128{range_check_ptr}(start_value: felt, dst: felt*) { + // Fill dst using only hints with no opcodes. + let value = start_value; + let offset = 15; + tempvar base = 256; + let bound = 256; + tempvar max = 255; + + // 0. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 1. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 2. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 3. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 0. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 1. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 2. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 3. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 0. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 1. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 2. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 3. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 0. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 1. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 2. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + // 3. + let output = &dst[offset]; + let offset = offset - 1; + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar x = [output]; + [range_check_ptr] = x; + assert [range_check_ptr + 1] = max - x; + let range_check_ptr = range_check_ptr + 2; + tempvar value = (value - x) / base; + + assert value = 0; + return (); + } + + // @notice Calculates the number of bytes used by a 128-bit value. + // @param value The 128-bit value. + // @return The number of bytes used by the value. + func bytes_used_128{range_check_ptr}(value: felt) -> felt { + let (q, r) = unsigned_div_rem(value, 256 ** 15); + if (q != 0) { + return 16; + } + let (q, r) = unsigned_div_rem(value, 256 ** 14); + if (q != 0) { + return 15; + } + let (q, r) = unsigned_div_rem(value, 256 ** 13); + if (q != 0) { + return 14; + } + let (q, r) = unsigned_div_rem(value, 256 ** 12); + if (q != 0) { + return 13; + } + let (q, r) = unsigned_div_rem(value, 256 ** 11); + if (q != 0) { + return 12; + } + let (q, r) = unsigned_div_rem(value, 256 ** 10); + if (q != 0) { + return 11; + } + let (q, r) = unsigned_div_rem(value, 256 ** 9); + if (q != 0) { + return 10; + } + let (q, r) = unsigned_div_rem(value, 256 ** 8); + if (q != 0) { + return 9; + } + let (q, r) = unsigned_div_rem(value, 256 ** 7); + if (q != 0) { + return 8; + } + let (q, r) = unsigned_div_rem(value, 256 ** 6); + if (q != 0) { + return 7; + } + let (q, r) = unsigned_div_rem(value, 256 ** 5); + if (q != 0) { + return 6; + } + let (q, r) = unsigned_div_rem(value, 256 ** 4); + if (q != 0) { + return 5; + } + let (q, r) = unsigned_div_rem(value, 256 ** 3); + if (q != 0) { + return 4; + } + let (q, r) = unsigned_div_rem(value, 256 ** 2); + if (q != 0) { + return 3; + } + let (q, r) = unsigned_div_rem(value, 256 ** 1); + if (q != 0) { + return 2; + } + if (value != 0) { + return 1; + } + return 0; + } + + // @notice transform multiple bytes into words of 32 bits (big endian) + // @dev the input data must have length in multiples of 4 + // @param data_len The length of the bytes + // @param data The pointer to the bytes array + // @param n_len used for recursion, set to 0 + // @param n used for recursion, set to pointer + // @return n_len the resulting array length + // @return n the resulting array + func bytes_to_bytes4_array{range_check_ptr}( + data_len: felt, data: felt*, n_len: felt, n: felt* + ) -> (n_len: felt, n: felt*) { + alloc_locals; + if (data_len == 0) { + return (n_len=n_len, n=n); + } + + let (_, r) = unsigned_div_rem(data_len, 4); + with_attr error_message("data length must be multiple of 4") { + assert r = 0; + } + + // Load sequence of 4 bytes into a single 32-bit word (big endian) + let res = bytes_to_felt(4, data); + assert n[n_len] = res; + return bytes_to_bytes4_array(data_len=data_len - 4, data=data + 4, n_len=n_len + 1, n=n); + } + + // @notice transform array of 32-bit words (big endian) into a bytes array + // @param data_len The length of the 32-bit array + // @param data The pointer to the 32-bit array + // @param bytes_len used for recursion, set to 0 + // @param bytes used for recursion, set to pointer + // @return bytes_len the resulting array length + // @return bytes the resulting array + func bytes4_array_to_bytes{range_check_ptr}( + data_len: felt, data: felt*, bytes_len: felt, bytes: felt* + ) -> (bytes_len: felt, bytes: felt*) { + alloc_locals; + if (data_len == 0) { + return (bytes_len=bytes_len, bytes=bytes); + } + + // Split a 32-bit big endian word into 4 bytes + // Store result in a temporary array + let (temp: felt*) = alloc(); + split_word([data], 4, temp); + + // Append temp array to bytes array + let (local res: felt*) = alloc(); + memcpy(res, bytes, bytes_len); + memcpy(res + bytes_len, temp, 4); + + return bytes4_array_to_bytes( + data_len=data_len - 1, data=data + 1, bytes_len=bytes_len + 4, bytes=res + ); + } + // Returns 1 if lhs <= rhs (or more precisely 0 <= rhs - lhs < RANGE_CHECK_BOUND). + // Returns 0 otherwise. + // Soundness assumptions (caller responsibility to ensure those) : + // - 0 <= lhs < RANGE_CHECK_BOUND + // - 0 <= rhs < RANGE_CHECK_BOUND + @known_ap_change + func is_le_unchecked{range_check_ptr}(lhs: felt, rhs: felt) -> felt { + tempvar a = rhs - lhs; // reference (rhs-lhs) as "a" to use already whitelisted hint + %{ memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1 %} + jmp false if [ap] != 0, ap++; + + // Ensure lhs <= rhs + assert [range_check_ptr] = a; + ap += 2; // Two memory holes for known_ap_change in case of false case: Two instructions more: -1*a, and (-1*a) - 1. + tempvar range_check_ptr = range_check_ptr + 1; + tempvar res = 1; + ret; + + false: + // Ensure rhs < lhs + assert [range_check_ptr] = (-a) - 1; + tempvar range_check_ptr = range_check_ptr + 1; + tempvar res = 0; + ret; + } + + // @notice Initializes a dictionary of valid jump destinations in EVM bytecode. + // @param bytecode_len The length of the bytecode. + // @param bytecode The EVM bytecode to analyze. + // @return (valid_jumpdests_start, valid_jumpdests) The starting and ending pointers of the valid jump destinations. + // + // @dev This function iterates over the bytecode from the current index 'i'. + // If the opcode at the current index is between 0x5f and 0x7f (PUSHN opcodes) (inclusive), + // it skips the next 'n_args' opcodes, where 'n_args' is the opcode minus 0x5f. + // If the opcode is 0x5b (JUMPDEST), it marks the current index as a valid jump destination. + // It continues by jumping back to the body flag until it has processed the entire bytecode. + func initialize_jumpdests{range_check_ptr}(bytecode_len: felt, bytecode: felt*) -> ( + valid_jumpdests_start: DictAccess*, valid_jumpdests: DictAccess* + ) { + alloc_locals; + let (local valid_jumpdests_start: DictAccess*) = default_dict_new(0); + tempvar range_check_ptr = range_check_ptr; + tempvar valid_jumpdests = valid_jumpdests_start; + tempvar i = 0; + jmp body if bytecode_len != 0; + + static_assert range_check_ptr == [ap - 3]; + jmp end; + + body: + let bytecode_len = [fp - 4]; + let bytecode = cast([fp - 3], felt*); + let range_check_ptr = [ap - 3]; + let valid_jumpdests = cast([ap - 2], DictAccess*); + let i = [ap - 1]; + + tempvar opcode = [bytecode + i]; + let is_opcode_ge_0x5f = Helpers.is_le_unchecked(0x5f, opcode); + let is_opcode_le_0x7f = Helpers.is_le_unchecked(opcode, 0x7f); + let is_push_opcode = is_opcode_ge_0x5f * is_opcode_le_0x7f; + let next_i = i + 1 + is_push_opcode * (opcode - 0x5f); // 0x5f is the first PUSHN opcode, opcode - 0x5f is the number of arguments. + + if (opcode == 0x5b) { + dict_write{dict_ptr=valid_jumpdests}(i, TRUE); + tempvar valid_jumpdests = valid_jumpdests; + tempvar next_i = next_i; + tempvar range_check_ptr = range_check_ptr; + } else { + tempvar valid_jumpdests = valid_jumpdests; + tempvar next_i = next_i; + tempvar range_check_ptr = range_check_ptr; + } + + // continue_loop != 0 => next_i - bytecode_len < 0 <=> next_i < bytecode_len + tempvar a = next_i - bytecode_len; + %{ memory[ap] = 0 if 0 <= (ids.a % PRIME) < range_check_builtin.bound else 1 %} + ap += 1; + let continue_loop = [ap - 1]; + tempvar range_check_ptr = range_check_ptr; + tempvar valid_jumpdests = valid_jumpdests; + tempvar i = next_i; + static_assert range_check_ptr == [ap - 3]; + static_assert valid_jumpdests == [ap - 2]; + static_assert i == [ap - 1]; + jmp body if continue_loop != 0; + + end: + let range_check_ptr = [ap - 3]; + let i = [ap - 1]; + // Verify that i >= bytecode_len to ensure loop terminated correctly. + let check = Helpers.is_le_unchecked(bytecode_len, i); + assert check = 1; + return (valid_jumpdests_start, valid_jumpdests); + } + + const BYTES_PER_FELT = 31; + + // @notice Load packed bytes from an array of bytes packed in 31-byte words and a final word. + // @param input_len The total amount of bytes in the array. + // @param input The input, an array of 31-bytes words and a final word. + // @param bytes_len The total amount of bytes to load. + // @returns bytes An array of individual bytes loaded from the packed input. + func load_packed_bytes{range_check_ptr}(input_len: felt, input: felt*, bytes_len: felt) -> ( + bytes: felt* + ) { + alloc_locals; + + let (local bytes: felt*) = alloc(); + if (bytes_len == 0) { + return (bytes=bytes); + } + + local bound = 256; + local base = 256; + let (local chunk_counts, local remainder) = unsigned_div_rem(bytes_len, BYTES_PER_FELT); + + tempvar remaining_bytes = bytes_len; + tempvar range_check_ptr = range_check_ptr; + tempvar index = 0; + tempvar value = 0; + tempvar count = 0; + + read: + let remaining_bytes = [ap - 5]; + let range_check_ptr = [ap - 4]; + let index = [ap - 3]; + let value = [ap - 2]; + let count = [ap - 1]; + let input = cast([fp - 4], felt*); + + tempvar value = input[index]; + + let chunk_counts = [fp + 3]; + let remainder = [fp + 4]; + + tempvar remaining_chunk = chunk_counts - index; + jmp full_chunk if remaining_chunk != 0; + tempvar count = remainder; + jmp next; + + full_chunk: + tempvar count = BYTES_PER_FELT; + + next: + tempvar remaining_bytes = remaining_bytes; + tempvar range_check_ptr = range_check_ptr; + tempvar index = index + 1; + tempvar value = value; + tempvar count = count; + + body: + let remaining_bytes = [ap - 5]; + let range_check_ptr = [ap - 4]; + let index = [ap - 3]; + let value = [ap - 2]; + let count = [ap - 1]; + + let bytes = cast([fp], felt*); + let bound = [fp + 1]; + let base = [fp + 2]; + + tempvar offset = (index - 1) * BYTES_PER_FELT + count - 1; + let output = bytes + offset; + + // Put byte in output and assert that 0 <= byte < bound + // See math.split_int + %{ + memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base + assert res < ids.bound, f'split_int(): Limb {res} is out of range.' + %} + tempvar a = [output]; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.' + %} + assert a = [range_check_ptr]; + tempvar a = bound - 1 - a; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.' + %} + assert a = [range_check_ptr + 1]; + + tempvar value = (value - [output]) / base; + tempvar remaining_bytes = remaining_bytes - 1; + tempvar range_check_ptr = range_check_ptr + 2; + tempvar index = index; + tempvar value = value; + tempvar count = count - 1; + + jmp cond if remaining_bytes != 0; + + with_attr error_message("Value is not empty") { + assert value = 0; + } + let bytes = cast([fp], felt*); + return (bytes=bytes); + + cond: + jmp body if count != 0; + with_attr error_message("Value is not empty") { + assert value = 0; + } + jmp read; + } +} diff --git a/cairo/tests/__init__.py b/cairo/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cairo/tests/conftest.py b/cairo/tests/conftest.py new file mode 100644 index 00000000..c44db393 --- /dev/null +++ b/cairo/tests/conftest.py @@ -0,0 +1,78 @@ +import logging +import os + +os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python" + +import pytest +from dotenv import load_dotenv +from hypothesis import Phase, Verbosity, settings +from starkware.cairo.lang.instances import LAYOUTS + +load_dotenv() +logger = logging.getLogger() + + +def pytest_addoption(parser): + parser.addoption( + "--profile-cairo", + action="store_true", + default=False, + help="compute and dump TracerData for the VM runner: True or False", + ) + parser.addoption( + "--proof-mode", + action="store_true", + default=False, + help="run the CairoRunner in proof mode: True or False", + ) + parser.addoption( + "--layout", + choices=list(LAYOUTS.keys()), + default="starknet_with_keccak", + help="The layout of the Cairo AIR.", + ) + parser.addoption( + "--seed", + action="store", + default=None, + type=int, + help="The seed to set random with.", + ) + + +@pytest.fixture(autouse=True, scope="session") +def seed(request): + if request.config.getoption("seed") is not None: + import random + + logger.info(f"Setting seed to {request.config.getoption('seed')}") + + random.seed(request.config.getoption("seed")) + + +settings.register_profile( + "nightly", + deadline=None, + max_examples=1500, + phases=[Phase.explicit, Phase.reuse, Phase.generate, Phase.target], +) +settings.register_profile( + "ci", + deadline=None, + max_examples=100, + phases=[Phase.explicit, Phase.reuse, Phase.generate, Phase.target], +) +settings.register_profile( + "dev", + deadline=None, + max_examples=10, + phases=[Phase.explicit, Phase.reuse, Phase.generate, Phase.target], +) +settings.register_profile( + "debug", + max_examples=10, + verbosity=Verbosity.verbose, + phases=[Phase.explicit, Phase.reuse, Phase.generate, Phase.target], +) +settings.load_profile(os.getenv("HYPOTHESIS_PROFILE", "default")) +logger.info(f"Using Hypothesis profile: {os.getenv('HYPOTHESIS_PROFILE', 'default')}") diff --git a/cairo/tests/src/__init__.py b/cairo/tests/src/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cairo/tests/src/conftest.py b/cairo/tests/src/conftest.py new file mode 100644 index 00000000..e80d7166 --- /dev/null +++ b/cairo/tests/src/conftest.py @@ -0,0 +1,292 @@ +import json +import logging +import math +import shutil +from hashlib import md5 +from pathlib import Path +from time import perf_counter, time_ns + +import pytest +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME +from starkware.cairo.lang.compiler.cairo_compile import compile_cairo, get_module_reader +from starkware.cairo.lang.compiler.preprocessor.default_pass_manager import ( + default_pass_manager, +) +from starkware.cairo.lang.compiler.scoped_name import ScopedName +from starkware.cairo.lang.tracer.tracer_data import TracerData +from starkware.cairo.lang.vm.cairo_run import ( + write_air_public_input, + write_binary_memory, + write_binary_trace, +) +from starkware.cairo.lang.vm.cairo_runner import CairoRunner +from starkware.cairo.lang.vm.memory_dict import MemoryDict +from starkware.cairo.lang.vm.memory_segments import FIRST_MEMORY_ADDR as PROGRAM_BASE +from starkware.cairo.lang.vm.utils import RunResources +from tests.utils.constants import Opcodes +from tests.utils.coverage import VmWithCoverage, report_runs +from tests.utils.hints import debug_info +from tests.utils.reporting import dump_coverage, profile_from_tracer_data +from tests.utils.serde import Serde + +logger = logging.getLogger() + + +def cairo_compile(path): + module_reader = get_module_reader(cairo_path=[str(Path(__file__).parents[2])]) + + pass_manager = default_pass_manager( + prime=DEFAULT_PRIME, read_module=module_reader.read + ) + + return compile_cairo( + Path(path).read_text(), + pass_manager=pass_manager, + debug_info=True, + ) + + +@pytest.fixture(scope="module") +def cairo_program(request) -> list: + cairo_file = Path(request.node.fspath).with_suffix(".cairo") + if not cairo_file.exists(): + raise ValueError(f"Missing cairo file: {cairo_file}") + + start = perf_counter() + program = cairo_compile(cairo_file) + stop = perf_counter() + logger.info(f"{cairo_file} compiled in {stop - start:.2f}s") + return program + + +@pytest.fixture(scope="module") +def cairo_run(request, cairo_program) -> list: + """ + Run the cairo program corresponding to the python test file at a given entrypoint with given program inputs as kwargs. + Returns the output of the cairo program put in the output memory segment. + + When --profile-cairo is passed, the cairo program is run with the tracer enabled and the resulting trace is dumped. + + Logic is mainly taken from starkware.cairo.lang.vm.cairo_run with minor updates like the addition of the output segment. + """ + + def _factory(entrypoint, **kwargs) -> list: + implicit_args = list( + cairo_program.identifiers.get_by_full_name( + ScopedName(path=["__main__", entrypoint, "ImplicitArgs"]) + ).members.keys() + ) + args = list( + cairo_program.identifiers.get_by_full_name( + ScopedName(path=["__main__", entrypoint, "Args"]) + ).members.keys() + ) + return_data = cairo_program.identifiers.get_by_full_name( + ScopedName(path=["__main__", entrypoint, "Return"]) + ) + # Fix builtins runner based on the implicit args since the compiler doesn't find them + cairo_program.builtins = [ + builtin + # This list is extracted from the builtin runners + # Builtins have to be declared in this order + for builtin in [ + "output", + "pedersen", + "range_check", + "ecdsa", + "bitwise", + "ec_op", + "keccak", + "poseidon", + "range_check96", + "add_mod", + "mul_mod", + ] + if builtin in {arg.replace("_ptr", "") for arg in implicit_args} + ] + + memory = MemoryDict() + runner = CairoRunner( + program=cairo_program, + layout=request.config.getoption("layout"), + memory=memory, + proof_mode=request.config.getoption("proof_mode"), + allow_missing_builtins=False, + ) + serde = Serde(runner) + + runner.program_base = runner.segments.add() + runner.execution_base = runner.segments.add() + for builtin_runner in runner.builtin_runners.values(): + builtin_runner.initialize_segments(runner) + + stack = [] + for arg in implicit_args: + builtin_runner = runner.builtin_runners.get(arg.replace("_ptr", "_builtin")) + if builtin_runner is not None: + stack.extend(builtin_runner.initial_stack()) + continue + + add_output = "output_ptr" in args + if add_output: + output_ptr = runner.segments.add() + stack.append(output_ptr) + + return_fp = runner.execution_base + 2 + end = runner.segments.add() + # Add a jmp rel 0 instruction to be able to loop in proof mode + runner.memory[end] = 0x10780017FFF7FFF + runner.memory[end + 1] = 0 + # Proof mode expects the program to start with __start__ and call main + # Adding [return_fp, end] before and after the stack makes this work both in proof mode and normal mode + stack = [return_fp, end] + stack + [return_fp, end] + runner.execution_public_memory = list(range(len(stack))) + + runner.initialize_state( + entrypoint=cairo_program.identifiers.get_by_full_name( + ScopedName(path=["__main__", entrypoint]) + ).pc, + stack=stack, + ) + runner.initial_fp = runner.initial_ap = runner.execution_base + len(stack) + + runner.initialize_vm( + hint_locals={"program_input": kwargs}, + static_locals={ + "debug_info": debug_info(cairo_program), + "serde": serde, + "Opcodes": Opcodes, + }, + vm_class=VmWithCoverage, + ) + run_resources = RunResources(n_steps=10_000_000) + try: + runner.run_until_pc(end, run_resources) + except Exception as e: + raise Exception(str(e)) from e + + runner.original_steps = runner.vm.current_step + runner.end_run(disable_trace_padding=False) + if request.config.getoption("proof_mode"): + return_data_offset = serde.get_offset(return_data.cairo_type) + pointer = runner.vm.run_context.ap - return_data_offset + for arg in implicit_args[::-1]: + builtin_runner = runner.builtin_runners.get( + arg.replace("_ptr", "_builtin") + ) + if builtin_runner is not None: + builtin_runner.final_stack(runner, pointer) + pointer -= 1 + + runner.execution_public_memory += list( + range( + pointer.offset, + runner.vm.run_context.ap.offset - return_data_offset, + ) + ) + runner.finalize_segments() + + runner.relocate() + + # Create a unique output stem for the given test by using the test file name, the entrypoint and the kwargs + displayed_args = "" + if kwargs: + try: + displayed_args = json.dumps(kwargs) + except TypeError as e: + logger.info(f"Failed to serialize kwargs: {e}") + output_stem = str( + request.node.path.parent + / f"{request.node.path.stem}_{entrypoint}_{displayed_args}" + ) + # File names cannot be longer than 255 characters on Unix so we slice the base stem and happen a unique suffix + # Timestamp is used to avoid collisions when running the same test multiple times and to allow sorting by time + output_stem = Path( + f"{output_stem[:160]}_{int(time_ns())}_{md5(output_stem.encode()).digest().hex()[:8]}" + ) + if request.config.getoption("profile_cairo"): + tracer_data = TracerData( + program=cairo_program, + memory=runner.relocated_memory, + trace=runner.relocated_trace, + debug_info=runner.get_relocated_debug_info(), + program_base=PROGRAM_BASE, + ) + data = profile_from_tracer_data(tracer_data) + + with open(output_stem.with_suffix(".pb.gz"), "wb") as fp: + fp.write(data) + + if request.config.getoption("proof_mode"): + with open(output_stem.with_suffix(".trace"), "wb") as fp: + write_binary_trace(fp, runner.relocated_trace) + + with open(output_stem.with_suffix(".memory"), "wb") as fp: + write_binary_memory( + fp, + runner.relocated_memory, + math.ceil(cairo_program.prime.bit_length() / 8), + ) + + rc_min, rc_max = runner.get_perm_range_check_limits() + with open(output_stem.with_suffix(".air_public_input.json"), "w") as fp: + write_air_public_input( + layout=request.config.getoption("layout"), + public_input_file=fp, + memory=runner.relocated_memory, + public_memory_addresses=runner.segments.get_public_memory_addresses( + segment_offsets=runner.get_segment_offsets() + ), + memory_segment_addresses=runner.get_memory_segment_addresses(), + trace=runner.relocated_trace, + rc_min=rc_min, + rc_max=rc_max, + ) + with open(output_stem.with_suffix(".air_private_input.json"), "w") as fp: + json.dump( + { + "trace_path": str(output_stem.with_suffix(".trace").absolute()), + "memory_path": str( + output_stem.with_suffix(".memory").absolute() + ), + **runner.get_air_private_input(), + }, + fp, + indent=4, + ) + + final_output = None + if add_output: + final_output = serde.serialize_list(output_ptr) + function_output = serde.serialize(return_data.cairo_type) + if final_output is not None: + function_output = ( + function_output + if isinstance(function_output, list) + else [function_output] + ) + if len(function_output) > 0: + final_output = (final_output, *function_output) + else: + final_output = function_output + + return final_output + + return _factory + + +@pytest.fixture(scope="session", autouse=True) +def coverage(worker_id): + + output_dir = Path("coverage") + shutil.rmtree(output_dir, ignore_errors=True) + + yield + + output_dir.mkdir(exist_ok=True, parents=True) + files = report_runs(excluded_file={"site-packages", "tests"}) + + if worker_id == "master": + dump_coverage(output_dir, files) + else: + dump_coverage(output_dir / worker_id, files) diff --git a/cairo/tests/src/instructions/test_duplication_operations.cairo b/cairo/tests/src/instructions/test_duplication_operations.cairo new file mode 100644 index 00000000..ba196584 --- /dev/null +++ b/cairo/tests/src/instructions/test_duplication_operations.cairo @@ -0,0 +1,39 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 + +from src.model import model +from src.stack import Stack +from src.state import State +from src.memory import Memory +from src.instructions.duplication_operations import DuplicationOperations +from tests.utils.helpers import TestHelpers + +func test__exec_dup{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> model.Stack* { + alloc_locals; + local i: felt; + local initial_stack_len: felt; + let (initial_stack_ptr) = alloc(); + let initial_stack = cast(initial_stack_ptr, Uint256*); + %{ + from itertools import chain + ids.i = program_input["i"] + ids.initial_stack_len = len(program_input["initial_stack"]) + segments.write_arg(ids.initial_stack_ptr, list(chain.from_iterable(program_input["initial_stack"]))) + %} + + let stack = TestHelpers.init_stack_with_values(initial_stack_len, initial_stack); + let memory = Memory.init(); + let state = State.init(); + let (bytecode) = alloc(); + assert [bytecode] = i + 0x7f; + let evm = TestHelpers.init_evm_with_bytecode(1, bytecode); + + with stack, memory, state { + let evm = DuplicationOperations.exec_dup(evm); + let (top) = Stack.peek(0); + } + + return stack; +} diff --git a/cairo/tests/src/instructions/test_duplication_operations.py b/cairo/tests/src/instructions/test_duplication_operations.py new file mode 100644 index 00000000..244818ed --- /dev/null +++ b/cairo/tests/src/instructions/test_duplication_operations.py @@ -0,0 +1,9 @@ +import pytest + + +class TestDupOperations: + @pytest.mark.parametrize("i", range(1, 17)) + def test__exec_dup(self, cairo_run, i): + stack = [[v, 0] for v in range(16)] + output = cairo_run("test__exec_dup", initial_stack=stack, i=i) + assert output == [hex(i[0]) for i in stack][::-1] + [hex(stack[i - 1][0])] diff --git a/cairo/tests/src/instructions/test_environmental_information.cairo b/cairo/tests/src/instructions/test_environmental_information.cairo new file mode 100644 index 00000000..0f4ab68a --- /dev/null +++ b/cairo/tests/src/instructions/test_environmental_information.cairo @@ -0,0 +1,292 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.uint256 import ALL_ONES + +from src.instructions.environmental_information import EnvironmentalInformation +from src.instructions.memory_operations import MemoryOperations +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.state import State +from tests.utils.helpers import TestHelpers +from src.utils.utils import Helpers + +func test__exec_address__should_push_address_to_stack{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + // Given + alloc_locals; + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + let (bytecode) = alloc(); + let address = 0xdead; + let (calldata) = alloc(); + let evm = TestHelpers.init_evm_at_address(0, bytecode, 0, address, 0, calldata); + + // When + with stack, memory, state { + let result = EnvironmentalInformation.exec_address(evm); + let (index0) = Stack.peek(0); + } + + // Then + assert stack.size = 1; + assert index0.low = address; + assert index0.high = 0; + return (); +} + +func test__exec_extcodesize{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> Uint256* { + // Given + alloc_locals; + local address: felt; + %{ ids.address = program_input["address"] %} + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + // When + with stack, memory, state { + Stack.push_uint128(address); + let evm = EnvironmentalInformation.exec_extcodesize(evm); + let (extcodesize) = Stack.peek(0); + } + + // Then + return extcodesize; +} + +func test__exec_extcodecopy{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> model.Memory* { + // Given + alloc_locals; + local size: felt; + local offset: felt; + local dest_offset: felt; + local address: felt; + %{ + ids.size = program_input["size"] + ids.offset = program_input["offset"] + ids.dest_offset = program_input["dest_offset"] + ids.address = program_input["address"] + %} + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + tempvar item_3 = new Uint256(size, 0); + tempvar item_2 = new Uint256(offset, 0); + tempvar item_1 = new Uint256(dest_offset, 0); + tempvar item_0 = new Uint256(address, 0); + + // When + with stack, memory, state { + Stack.push(item_3); // size + Stack.push(item_2); // offset + Stack.push(item_1); // dest_offset + Stack.push(item_0); // address + let evm = EnvironmentalInformation.exec_extcodecopy(evm); + } + + // Then + assert stack.size = 0; + return memory; +} + +func test__exec_extcodecopy_zellic_issue_1258{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> model.Memory* { + // Given + alloc_locals; + local size: felt; + local offset_high: felt; + local dest_offset: felt; + local address: felt; + %{ + ids.size = program_input["size"] + ids.offset_high = program_input["offset_high"] + ids.dest_offset = program_input["dest_offset"] + ids.address = program_input["address"] + %} + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + tempvar item_1_mstore = new Uint256(ALL_ONES, ALL_ONES); + tempvar item_0_mstore = new Uint256(0, 0); + + tempvar item_3_extcodecopy = new Uint256(size, 0); + tempvar item_2_extcodecopy = new Uint256(0, offset_high); + tempvar item_1_extcodecopy = new Uint256(dest_offset, 0); + tempvar item_0_extcodecopy = new Uint256(address, 0); + + // When + with stack, memory, state { + Stack.push(item_1_mstore); + Stack.push(item_0_mstore); + + let evm = MemoryOperations.exec_mstore(evm); + + Stack.push(item_3_extcodecopy); // size + Stack.push(item_2_extcodecopy); // offset + Stack.push(item_1_extcodecopy); // dest_offset + Stack.push(item_0_extcodecopy); // address + let evm = EnvironmentalInformation.exec_extcodecopy(evm); + } + + // Then + assert stack.size = 0; + return memory; +} + +func test__exec_copy{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> (model.EVM*, model.Memory*) { + // Given + alloc_locals; + local size: felt; + local offset: felt; + local dest_offset: felt; + local bytecode_len: felt; + let (bytecode) = alloc(); + local opcode_number: felt; + %{ + ids.size = program_input["size"] + ids.offset = program_input["offset"] + ids.dest_offset = program_input["dest_offset"] + ids.bytecode_len = len(program_input["bytecode"]) + segments.write_arg(ids.bytecode, program_input["bytecode"]) + ids.opcode_number = program_input["opcode_number"] + %} + if (opcode_number == 0x37) { + // bytecode is passed as calldata and opcode_number (first element in bytecode variable) + // is passed as bytecode + let evm = TestHelpers.init_evm_with_calldata(1, bytecode, bytecode_len, bytecode); + } else { + let evm = TestHelpers.init_evm_with_bytecode(bytecode_len, bytecode); + } + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + tempvar item_2 = new Uint256(size, 0); + tempvar item_1 = new Uint256(offset, 0); + tempvar item_0 = new Uint256(dest_offset, 0); + + // When + with stack, memory, state { + Stack.push(item_2); // size + Stack.push(item_1); // offset + Stack.push(item_0); // dest_offset + let evm = EnvironmentalInformation.exec_copy(evm); + } + + // Then + assert stack.size = 0; + return (evm, memory); +} + +func test__exec_copy_offset_high_zellic_issue_1258{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> model.Memory* { + // Given + alloc_locals; + local size: felt; + local offset_high: felt; + local dest_offset: felt; + local bytecode_len: felt; + let (bytecode) = alloc(); + local opcode_number: felt; + %{ + ids.size = program_input["size"] + ids.offset_high = program_input["offset_high"] + ids.dest_offset = program_input["dest_offset"] + ids.bytecode_len = len(program_input["bytecode"]) + segments.write_arg(ids.bytecode, program_input["bytecode"]) + ids.opcode_number = program_input["opcode_number"] + %} + if (opcode_number == 0x37) { + // bytecode is passed as calldata and opcode_number (first element in bytecode variable + // is passed as bytecode + let evm = TestHelpers.init_evm_with_calldata(1, bytecode, bytecode_len, bytecode); + } else { + let evm = TestHelpers.init_evm_with_bytecode(bytecode_len, bytecode); + } + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + tempvar item_2_exec_copy = new Uint256(size, 0); + tempvar item_1_exec_copy = new Uint256(0, offset_high); + tempvar item_0_exec_copy = new Uint256(dest_offset, 0); + + tempvar item_1_mstore = new Uint256(ALL_ONES, ALL_ONES); + tempvar item_0_mstore = new Uint256(0, 0); + + // When + with stack, memory, state { + Stack.push(item_1_mstore); + Stack.push(item_0_mstore); + + let evm = MemoryOperations.exec_mstore(evm); + + Stack.push(item_2_exec_copy); // size + Stack.push(item_1_exec_copy); // offset + Stack.push(item_0_exec_copy); // dest_offset + let evm = EnvironmentalInformation.exec_copy(evm); + } + + // Then + assert stack.size = 0; + return memory; +} + +func test__exec_gasprice{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) { + alloc_locals; + + // Given + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + let expected_gas_price_uint256 = Helpers.to_uint256(evm.message.env.gas_price); + + // When + with stack, memory, state { + let result = EnvironmentalInformation.exec_gasprice(evm); + let (gasprice) = Stack.peek(0); + } + + // Then + assert_uint256_eq([gasprice], [expected_gas_price_uint256]); + return (); +} + +func test__exec_extcodehash{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> Uint256* { + // Given + alloc_locals; + local address: felt; + %{ ids.address = program_input["address"] %} + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + // When + with stack, memory, state { + Stack.push_uint128(address); + let result = EnvironmentalInformation.exec_extcodehash(evm); + let (extcodehash) = Stack.peek(0); + } + + // Then + return extcodehash; +} diff --git a/cairo/tests/src/instructions/test_environmental_information.py b/cairo/tests/src/instructions/test_environmental_information.py new file mode 100644 index 00000000..92898f9c --- /dev/null +++ b/cairo/tests/src/instructions/test_environmental_information.py @@ -0,0 +1,126 @@ +import random + +import pytest +from Crypto.Hash import keccak +from hypothesis import example, given +from hypothesis import strategies as st + +EXISTING_ACCOUNT = 0xABDE1 +EXISTING_ACCOUNT_SN_ADDR = 0x1234 +NON_EXISTING_ACCOUNT = 0xDEAD + + +@pytest.fixture(scope="module", params=[0, 32], ids=["no bytecode", "32 bytes"]) +def bytecode(request): + return [random.randint(0, 255) for _ in range(request.param)] + + +@pytest.fixture(scope="module") +def bytecode_hash(bytecode): + keccak_hash = keccak.new(digest_bits=256) + keccak_hash.update(bytearray(bytecode)) + return int.from_bytes(keccak_hash.digest(), byteorder="big") + + +@pytest.fixture( + scope="module", + params=[EXISTING_ACCOUNT, NON_EXISTING_ACCOUNT], + ids=["existing", "non existing"], +) +def address(request): + return request.param + + +class TestEnvironmentalInformation: + class TestAddress: + def test_should_push_address(self, cairo_run): + cairo_run("test__exec_address__should_push_address_to_stack") + + class TestCopy: + @pytest.mark.parametrize("opcode_number", [0x39, 0x37]) + @pytest.mark.parametrize( + "size, offset, dest_offset", + [(31, 0, 0), (33, 0, 0), (1, 32, 0)], + ids=[ + "size_is_bytecodelen-1", + "size_is_bytecodelen+1", + "offset_is_bytecodelen", + ], + ) + def test_exec_copy_should_copy_code( + self, cairo_run, size, offset, dest_offset, opcode_number, bytecode + ): + bytecode.insert(0, opcode_number) # random bytecode that can be mutated + (_, memory) = cairo_run( + "test__exec_copy", + size=size, + offset=offset, + dest_offset=dest_offset, + bytecode=bytecode, + opcode_number=opcode_number, + ) + + copied_bytecode = bytes( + # bytecode is padded with surely enough 0 and then sliced + (bytecode + [0] * (offset + size))[offset : offset + size] + ) + assert ( + bytes.fromhex(memory)[dest_offset : dest_offset + size] + == copied_bytecode + ) + + @given( + opcode_number=st.sampled_from([0x39, 0x37]), + offset=st.integers(0, 2**128 - 1), + dest_offset=st.integers(0, 2**128 - 1), + ) + @example(opcode_number=0x39, offset=2**128 - 1, dest_offset=0) + @example(opcode_number=0x39, offset=0, dest_offset=2**128 - 1) + @example(opcode_number=0x37, offset=2**128 - 1, dest_offset=0) + @example(opcode_number=0x37, offset=0, dest_offset=2**128 - 1) + def test_exec_copy_fail_oog( + self, cairo_run, opcode_number, bytecode, offset, dest_offset + ): + bytecode.insert(0, opcode_number) # random bytecode that can be mutated + (evm, _) = cairo_run( + "test__exec_copy", + size=2**128 - 1, + offset=offset, + dest_offset=dest_offset, + bytecode=bytecode, + opcode_number=opcode_number, + ) + assert evm["reverted"] == 2 + assert b"Kakarot: outOfGas left" in bytes(evm["return_data"]) + + @pytest.mark.parametrize("opcode_number", [0x39, 0x37]) + @pytest.mark.parametrize( + "size", + [31, 32, 33, 0], + ids=[ + "size_is_bytecodelen-1", + "size_is_bytecodelen", + "size_is_bytecodelen+1", + "size_is_0", + ], + ) + def test_exec_copy_offset_high_zellic_issue_1258( + self, cairo_run, size, opcode_number, bytecode + ): + bytecode.insert(0, opcode_number) # random bytecode that can be mutated + offset_high = 1 + memory = cairo_run( + "test__exec_copy_offset_high_zellic_issue_1258", + size=size, + offset_high=offset_high, + dest_offset=0, + bytecode=bytecode, + opcode_number=opcode_number, + ) + # with a offset_high != 0 all copied bytes are 0 + copied_bytecode = bytes([0] * size) + assert bytes.fromhex(memory)[0:size] == copied_bytecode + + class TestGasPrice: + def test_gasprice(self, cairo_run): + cairo_run("test__exec_gasprice") diff --git a/cairo/tests/src/instructions/test_exchange_operations.cairo b/cairo/tests/src/instructions/test_exchange_operations.cairo new file mode 100644 index 00000000..68132460 --- /dev/null +++ b/cairo/tests/src/instructions/test_exchange_operations.cairo @@ -0,0 +1,43 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.memcpy import memcpy + +from src.stack import Stack +from src.memory import Memory +from src.state import State +from src.model import model +from src.instructions.exchange_operations import ExchangeOperations +from tests.utils.helpers import TestHelpers + +func test__exec_swap{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> model.Stack* { + alloc_locals; + + local i: felt; + local initial_stack_len: felt; + let (initial_stack_ptr: felt*) = alloc(); + let initial_stack = cast(initial_stack_ptr, Uint256*); + %{ + from itertools import chain + ids.i = program_input["i"] + ids.initial_stack_len = len(program_input["initial_stack"]) + segments.write_arg(ids.initial_stack_ptr, list(chain(*program_input["initial_stack"]))) + %} + + let stack = TestHelpers.init_stack_with_values(initial_stack_len, initial_stack); + let (bytecode) = alloc(); + assert [bytecode] = i + 0x8f; + let evm = TestHelpers.init_evm_with_bytecode(1, bytecode); + let memory = Memory.init(); + let state = State.init(); + + // When + with stack, memory, state { + let evm = ExchangeOperations.exec_swap(evm); + let (top) = Stack.peek(0); + let (swapped) = Stack.peek(i); + } + + return stack; +} diff --git a/cairo/tests/src/instructions/test_exchange_operations.py b/cairo/tests/src/instructions/test_exchange_operations.py new file mode 100644 index 00000000..a07bfe12 --- /dev/null +++ b/cairo/tests/src/instructions/test_exchange_operations.py @@ -0,0 +1,10 @@ +import pytest + + +class TestSwapOperations: + @pytest.mark.parametrize("i", range(1, 17)) + def test__exec_swap(self, cairo_run, i): + stack = [[v, 0] for v in range(17)] + output = cairo_run("test__exec_swap", i=i, initial_stack=stack) + stack[i], stack[0] = stack[0], stack[i] + assert output == [hex(i[0]) for i in stack][::-1] diff --git a/cairo/tests/src/instructions/test_memory_operations.cairo b/cairo/tests/src/instructions/test_memory_operations.cairo new file mode 100644 index 00000000..8683eaf4 --- /dev/null +++ b/cairo/tests/src/instructions/test_memory_operations.cairo @@ -0,0 +1,231 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq + +from src.model import model +from src.stack import Stack +from src.state import State +from src.memory import Memory +from src.evm import EVM +from src.instructions.memory_operations import MemoryOperations +from tests.utils.helpers import TestHelpers + +func test__exec_pc__should_return_evm_program_counter{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + // Given + alloc_locals; + + local increment: felt; + %{ ids.increment = program_input["increment"] %} + + let (bytecode) = alloc(); + let evm = TestHelpers.init_evm_with_bytecode(0, bytecode); + let evm = EVM.increment_program_counter(evm, increment); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + // When + with stack, memory, state { + let evm = MemoryOperations.exec_pc(evm); + let (index0) = Stack.peek(0); + } + + // Then + assert stack.size = 1; + assert index0.low = increment; + assert index0.high = 0; + return (); +} + +func test__exec_pop_should_pop_an_item_from_execution_context{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + // Given + alloc_locals; + let (bytecode) = alloc(); + let evm = TestHelpers.init_evm_with_bytecode(0, bytecode); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + tempvar item_1 = new Uint256(1, 0); + tempvar item_0 = new Uint256(2, 0); + + // When + with stack, memory, state { + Stack.push(item_1); + Stack.push(item_0); + + let evm = MemoryOperations.exec_pop(evm); + let (index0) = Stack.peek(0); + } + + // Then + assert stack.size = 1; + assert_uint256_eq([index0], Uint256(1, 0)); + return (); +} + +func test__exec_mload_should_load_a_value_from_memory{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + // Given + alloc_locals; + let (bytecode) = alloc(); + let evm = TestHelpers.init_evm_with_bytecode(0, bytecode); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + tempvar item_1 = new Uint256(1, 0); + tempvar item_0 = new Uint256(0, 0); + + // When + with stack, memory, state { + Stack.push(item_1); + Stack.push(item_0); + + let evm = MemoryOperations.exec_mstore(evm); + + Stack.push(item_0); + + let evm = MemoryOperations.exec_mload(evm); + let (index0) = Stack.peek(0); + } + + // Then + assert stack.size = 1; + assert_uint256_eq([index0], [item_1]); + return (); +} + +func test__exec_mload_should_load_a_value_from_memory_with_memory_expansion{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + // Given + alloc_locals; + let (bytecode) = alloc(); + let evm = TestHelpers.init_evm_with_bytecode(0, bytecode); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + with stack, memory, state { + tempvar item_1 = new Uint256(1, 0); + tempvar item_0 = new Uint256(0, 0); + + Stack.push(item_1); + Stack.push(item_0); + + let evm = MemoryOperations.exec_mstore(evm); + + tempvar offset = new Uint256(16, 0); + Stack.push(offset); + + let evm = MemoryOperations.exec_mload(evm); + let (index0) = Stack.peek(0); + } + + assert stack.size = 1; + assert_uint256_eq([index0], Uint256(0, 1)); + assert memory.words_len = 2; + return (); +} + +func test__exec_mload_should_load_a_value_from_memory_with_offset_larger_than_msize{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() { + // Given + alloc_locals; + let (bytecode) = alloc(); + let evm = TestHelpers.init_evm_with_bytecode(0, bytecode); + let test_offset = 684; + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + tempvar item_1 = new Uint256(1, 0); + tempvar item_0 = new Uint256(0, 0); + + with stack, memory, state { + Stack.push(item_1); + Stack.push(item_0); + + let evm = MemoryOperations.exec_mstore(evm); + tempvar offset = new Uint256(test_offset, 0); + Stack.push(offset); + + let evm = MemoryOperations.exec_mload(evm); + + let (index0) = Stack.peek(0); + } + assert stack.size = 1; + assert_uint256_eq([index0], Uint256(0, 0)); + assert memory.words_len = 23; + return (); +} + +func test__exec_mcopy{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> (model.EVM*, model.Memory*) { + alloc_locals; + let (memory_init_state) = alloc(); + local memory_init_state_len: felt; + let (size_mcopy_ptr) = alloc(); + let (src_offset_mcopy_ptr) = alloc(); + let (dst_offset_mcopy_ptr) = alloc(); + + %{ + ids.memory_init_state_len = len(program_input["memory_init_state"]) + segments.write_arg(ids.memory_init_state, program_input["memory_init_state"]) + segments.write_arg(ids.size_mcopy_ptr, program_input["size_mcopy"]) + segments.write_arg(ids.src_offset_mcopy_ptr, program_input["src_offset_mcopy"]) + segments.write_arg(ids.dst_offset_mcopy_ptr, program_input["dst_offset_mcopy"]) + %} + + let size_mcopy = cast(size_mcopy_ptr, Uint256*); + let src_offset_mcopy = cast(src_offset_mcopy_ptr, Uint256*); + let dst_offset_mcopy = cast(dst_offset_mcopy_ptr, Uint256*); + + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = TestHelpers.init_memory_with_values(memory_init_state_len, memory_init_state); + + with stack, memory, state { + Stack.push(size_mcopy); + Stack.push(src_offset_mcopy); + Stack.push(dst_offset_mcopy); + let evm = MemoryOperations.exec_mcopy(evm); + } + return (evm, memory); +} + +func test_exec_mstore{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> (model.EVM*, model.Memory*) { + alloc_locals; + let (value_ptr) = alloc(); + let (offset_ptr) = alloc(); + + %{ + segments.write_arg(ids.value_ptr, program_input["value"]) + segments.write_arg(ids.offset_ptr, program_input["offset"]) + %} + + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + let value = cast(value_ptr, Uint256*); + let offset = cast(offset_ptr, Uint256*); + + with stack, memory, state { + Stack.push(value); + Stack.push(offset); + + let evm = MemoryOperations.exec_mstore(evm); + } + return (evm, memory); +} diff --git a/cairo/tests/src/instructions/test_memory_operations.py b/cairo/tests/src/instructions/test_memory_operations.py new file mode 100644 index 00000000..45448eed --- /dev/null +++ b/cairo/tests/src/instructions/test_memory_operations.py @@ -0,0 +1,148 @@ +import pytest +from hypothesis import example, given +from hypothesis.strategies import binary, integers +from src.utils.uint256 import int_to_uint256 +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME + + +class TestMemoryOperations: + class TestPc: + @pytest.mark.parametrize("increment", list(range(1, 15))) + def test_should_update_after_incrementing(self, cairo_run, increment): + cairo_run( + "test__exec_pc__should_return_evm_program_counter", increment=increment + ) + + class TestPop: + def test_should_pop_an_item_from_execution_context(self, cairo_run): + cairo_run("test__exec_pop_should_pop_an_item_from_execution_context") + + class TestMload: + def test_should_load_a_value_from_memory(self, cairo_run): + cairo_run("test__exec_mload_should_load_a_value_from_memory") + + def test_should_load_a_value_from_memory_with_memory_expansion(self, cairo_run): + cairo_run( + "test__exec_mload_should_load_a_value_from_memory_with_memory_expansion" + ) + + def test_should_load_a_value_from_memory_with_offset_larger_than_msize( + self, cairo_run + ): + cairo_run( + "test__exec_mload_should_load_a_value_from_memory_with_offset_larger_than_msize" + ) + + class TestMcopy: + + @given( + memory_init_state=binary(min_size=1, max_size=100), + size_mcopy=integers(min_value=1, max_value=100), + src_offset_mcopy=integers(min_value=0, max_value=100), + dst_offset_mcopy=integers(min_value=0, max_value=100), + ) + def test_should_copy_a_value_from_memory( + self, + cairo_run, + memory_init_state, + size_mcopy, + src_offset_mcopy, + dst_offset_mcopy, + ): + (evm, memory) = cairo_run( + "test__exec_mcopy", + memory_init_state=memory_init_state, + size_mcopy=int_to_uint256(size_mcopy), + src_offset_mcopy=int_to_uint256(src_offset_mcopy), + dst_offset_mcopy=int_to_uint256(dst_offset_mcopy), + ) + expected_memory_state = list(memory_init_state) + [0] * ( + max(src_offset_mcopy, dst_offset_mcopy) + + size_mcopy + - len(memory_init_state) + ) + expected_memory_state[dst_offset_mcopy : dst_offset_mcopy + size_mcopy] = ( + expected_memory_state[src_offset_mcopy : src_offset_mcopy + size_mcopy] + ) + words_len = (len(expected_memory_state) + 31) // 32 + expected_memory_state = expected_memory_state + [0] * ( + words_len * 32 - len(expected_memory_state) + ) + assert bytes.fromhex(memory) == bytes(expected_memory_state) + + @given( + memory_init_state=binary(min_size=1, max_size=100), + size_mcopy=integers(min_value=2**128, max_value=DEFAULT_PRIME - 1), + src_offset_mcopy=integers(min_value=0, max_value=100), + dst_offset_mcopy=integers(min_value=0, max_value=100), + ) + @example( + memory_init_state=b"a" * 100, + size_mcopy=2**128 - 1, + src_offset_mcopy=2**128 - 1, + dst_offset_mcopy=0, + ) + @example( + memory_init_state=b"a" * 100, + size_mcopy=2**128 - 1, + src_offset_mcopy=0, + dst_offset_mcopy=2**128 - 1, + ) + def test_should_fail_if_memory_expansion_too_large( + self, + cairo_run, + memory_init_state, + size_mcopy, + src_offset_mcopy, + dst_offset_mcopy, + ): + (evm, memory) = cairo_run( + "test__exec_mcopy", + memory_init_state=memory_init_state, + size_mcopy=int_to_uint256(size_mcopy), + src_offset_mcopy=int_to_uint256(src_offset_mcopy), + dst_offset_mcopy=int_to_uint256(dst_offset_mcopy), + ) + assert evm["reverted"] == 2 + assert b"Kakarot: outOfGas left" in bytes(evm["return_data"]) + + class TestMstore: + + @given( + value=integers(min_value=0, max_value=2**256 - 1), + offset=integers(min_value=0, max_value=0xFFFF), + ) + def test_exec_mstore_should_store_a_value_in_memory( + self, cairo_run, value, offset + ): + (evm, memory) = cairo_run( + "test_exec_mstore", + value=int_to_uint256(value), + offset=int_to_uint256(offset), + ) + + expected_memory = ( + int.to_bytes( + value, length=(value.bit_length() + 7) // 8, byteorder="big" + ) + if value > 0 + else b"\x00" + ) + assert bytes.fromhex(memory)[offset : offset + 32] == bytes( + [0] * (32 - len(expected_memory)) + list(expected_memory) + ) + + @given( + value=integers(min_value=0, max_value=2**256 - 1), + offset=integers(min_value=2**32, max_value=2**256 - 1), + ) + def test_exec_mstore_should_fail_if_memory_expansion_too_large( + self, cairo_run, value, offset + ): + (evm, _) = cairo_run( + "test_exec_mstore", + value=int_to_uint256(value), + offset=int_to_uint256(offset), + ) + assert evm["reverted"] == 2 + assert b"Kakarot: outOfGas left" in bytes(evm["return_data"]) diff --git a/cairo/tests/src/instructions/test_push_operations.cairo b/cairo/tests/src/instructions/test_push_operations.cairo new file mode 100644 index 00000000..0faffdb6 --- /dev/null +++ b/cairo/tests/src/instructions/test_push_operations.cairo @@ -0,0 +1,34 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.memset import memset +from starkware.cairo.common.memcpy import memcpy + +from src.utils.utils import Helpers +from src.model import model +from src.stack import Stack +from src.state import State +from src.memory import Memory +from src.instructions.push_operations import PushOperations +from tests.utils.helpers import TestHelpers + +func test__exec_push{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> model.Stack* { + alloc_locals; + local i: felt; + %{ ids.i = program_input["i"] %} + + let (bytecode) = alloc(); + assert [bytecode] = i + 0x5f; + memset(bytecode + 1, 0xff, i); + let stack = Stack.init(); + let memory = Memory.init(); + let state = State.init(); + let evm = TestHelpers.init_evm_with_bytecode(1 + i, bytecode); + + with stack, memory, state { + let evm = PushOperations.exec_push(evm); + } + + return stack; +} diff --git a/cairo/tests/src/instructions/test_push_operations.py b/cairo/tests/src/instructions/test_push_operations.py new file mode 100644 index 00000000..8b09acd2 --- /dev/null +++ b/cairo/tests/src/instructions/test_push_operations.py @@ -0,0 +1,13 @@ +import pytest + + +class TestPushOperations: + # The `exec_push` is tested by initializing the bytecode with a fill value of 0xFF. + # As we push 'i' bytes onto the stack, + # this results in a stack value of 0xFF repeated 'i' times. + # In decimal notation, this is equivalent to 256**i - 1, + # which forms the basis of our assertion in this test. + @pytest.mark.parametrize("i", range(0, 33)) + def test__exec_push(self, cairo_run, i): + stack = cairo_run("test__exec_push", i=i) + assert stack == [hex(256**i - 1)] diff --git a/cairo/tests/src/instructions/test_stop_and_math_operations.cairo b/cairo/tests/src/instructions/test_stop_and_math_operations.cairo new file mode 100644 index 00000000..d0006945 --- /dev/null +++ b/cairo/tests/src/instructions/test_stop_and_math_operations.cairo @@ -0,0 +1,63 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 + +from src.stack import Stack +from src.state import State +from src.memory import Memory +from src.model import model +from src.instructions.stop_and_math_operations import StopAndMathOperations +from tests.utils.helpers import TestHelpers + +func test__exec_stop{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { + alloc_locals; + + let evm = TestHelpers.init_evm(); + let stack = Stack.init(); + let state = State.init(); + let memory = Memory.init(); + + with stack, memory, state { + let evm = StopAndMathOperations.exec_stop(evm); + } + + assert evm.stopped = TRUE; + assert evm.return_data_len = 0; + + return (); +} + +func test__exec_math_operation{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> (evm: model.EVM*, result: Uint256*) { + // Given + alloc_locals; + + tempvar opcode; + tempvar initial_stack_len: felt; + let (initial_stack: felt*) = alloc(); + %{ + ids.opcode = program_input["opcode"]; + ids.initial_stack_len = len(program_input["stack"]); + segments.write_arg(ids.initial_stack, program_input["stack"]) + %} + + let (bytecode) = alloc(); + assert [bytecode] = opcode; + let memory = Memory.init(); + let stack = TestHelpers.init_stack_with_values( + initial_stack_len, cast(initial_stack, Uint256*) + ); + let evm = TestHelpers.init_evm_with_bytecode(1, bytecode); + let state = State.init(); + + // When + with stack, memory, state { + let evm = StopAndMathOperations.exec_math_operation(evm); + let (result) = Stack.peek(0); + } + + // Then + return (evm, result); +} diff --git a/cairo/tests/src/instructions/test_stop_and_math_operations.py b/cairo/tests/src/instructions/test_stop_and_math_operations.py new file mode 100644 index 00000000..0ac8069d --- /dev/null +++ b/cairo/tests/src/instructions/test_stop_and_math_operations.py @@ -0,0 +1,132 @@ +import pytest +from src.utils.uint256 import int_to_uint256 +from tests.utils.constants import Opcodes + + +class TestStopMathOperations: + class TestStop: + def test__exec_stop(self, cairo_run): + cairo_run("test__exec_stop") + + class TestMathOperations: + @pytest.mark.parametrize( + "opcode,stack,expected_result", + [ + (Opcodes.ADD, [3, 2, 1], 3 + 2), + (Opcodes.MUL, [3, 2, 1], 3 * 2), + (Opcodes.SUB, [3, 2, 1], 3 - 2), + (Opcodes.DIV, [3, 2, 1], 3 // 2), + (Opcodes.SDIV, [3, 2, 1], 3 // 2), + (Opcodes.MOD, [3, 2, 1], 3 % 2), + (Opcodes.SMOD, [3, 2, 1], 3 % 2), + (Opcodes.ADDMOD, [3, 2, 2], (3 + 2) % 2), + (Opcodes.ADDMOD, [3, 2, 2], (3 + 2) % 2), + ( + Opcodes.ADDMOD, + [ + 0x92343C8FA1D4651383994E908DC7A65B8AE59BB5161379B3B4D8EB2881C3A8A1, + 0x9F728D298865647B33FBBEF974967E10D881FCCA251FB1FB72F314033E17E76A, + 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, + ], + 0x31A6C9BA2A39C98DB7950D8A025E246C6367987E3B332BAF27CBFF2BBFDB900C, + ), + ( + Opcodes.MULMOD, + [ + 0xCAD9D0F127DE33D7EEAC15ACD9232B4FB7D4ABBD9E4AC4AC2F044EA995F80831, + 0xCAD9D0F127DE33D7EEAC15ACD9232B4FB7D4ABBD9E4AC4AC2F044EA995F80831, + 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, + ], + 0xE6228DFC2D312EF258CB5EA9536EBAD8D6EDE5BE03564700D6878D191844E865, + ), + ( + Opcodes.MULMOD, + [ + 0xE6228DFC2D312EF258CB5EA9536EBAD8D6EDE5BE03564700D6878D191844E865, + 0xCAD9D0F127DE33D7EEAC15ACD9232B4FB7D4ABBD9E4AC4AC2F044EA995F80831, + 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, + ], + 0x92343C8FA1D4651383994E908DC7A65B8AE59BB5161379B3B4D8EB2881C3A8A1, + ), + (Opcodes.EXP, [3, 2], (3**2)), + (Opcodes.EXP, [3, 1], (3**1)), + (Opcodes.EXP, [3, 0], (3**0)), + ( + Opcodes.EXP, + [0xFF, 0x11], + (0xFF**0x11), + ), + ( + Opcodes.SIGNEXTEND, + [ + 0x01, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0001, + 3, + ], + 0x01, + ), + ( + Opcodes.SIGNEXTEND, + [0x00, 0xFF, 3], + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, + ), + ( + Opcodes.SIGNEXTEND, + [0x20, 0xFF, 3], + 0xFF, + ), + (Opcodes.LT, [2, 1], 0), + (Opcodes.LT, [1, 2], 1), + (Opcodes.GT, [2, 1], 1), + (Opcodes.GT, [1, 2], 0), + (Opcodes.SLT, [1, 2], 1), + (Opcodes.SLT, [2, 1], 0), + (Opcodes.SGT, [1, 2], 0), + (Opcodes.SGT, [2, 1], 1), + (Opcodes.EQ, [1, 2], 0), + (Opcodes.EQ, [2, 2], 1), + (Opcodes.ISZERO, [1], 0), + (Opcodes.ISZERO, [0], 1), + (Opcodes.AND, [1, 0], 0), + (Opcodes.AND, [1, 1], 1), + (Opcodes.AND, [0xBD, 0xC9], 0x89), + (Opcodes.OR, [0, 0], 0), + (Opcodes.OR, [0, 1], 1), + (Opcodes.OR, [0xC5, 0x89], 0xCD), + (Opcodes.XOR, [1, 1], 0), + (Opcodes.XOR, [0, 0], 0), + (Opcodes.XOR, [0, 1], 1), + (Opcodes.XOR, [1, 0], 1), + (Opcodes.XOR, [0xDD, 0xB9], 0x64), + (Opcodes.BYTE, [23, 0xFFEEDDCCBBAA998877665544332211], 0x99), + (Opcodes.BYTE, [8, 0x123456789ABCDEF0 * 2**128], 0x12), + ( + Opcodes.BYTE, + [ + 0x8000000000000000000000000000000000000000000000000000000000000000, # zellic issue 1260 + 0x11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF, + ], + 0x00, + ), + (Opcodes.SHL, [4, 2], 32), + (Opcodes.SHR, [2, 4], 1), + (Opcodes.SAR, [2, 4], 1), + ], + ) + def test__exec_math_operation(self, cairo_run, opcode, stack, expected_result): + stack = [ + u256_member for value in stack for u256_member in int_to_uint256(value) + ] + (evm, result) = cairo_run( + "test__exec_math_operation", opcode=opcode, stack=stack + ) + assert int(result, 16) == expected_result + + @pytest.mark.parametrize( + "opcode, stack", [(0x0C, []), (0x0D, []), (0x0E, []), (0x0F, [])] + ) + def test__invalid_opcode_should_revert(self, cairo_run, opcode, stack): + (evm, result) = cairo_run( + "test__exec_math_operation", opcode=opcode, stack=stack + ) + assert evm["reverted"] == 2 diff --git a/cairo/tests/src/precompiles/test_datacopy.cairo b/cairo/tests/src/precompiles/test_datacopy.cairo new file mode 100644 index 00000000..826416eb --- /dev/null +++ b/cairo/tests/src/precompiles/test_datacopy.cairo @@ -0,0 +1,31 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.alloc import alloc + +from src.utils.utils import Helpers +from src.precompiles.datacopy import PrecompileDataCopy +from tests.utils.helpers import TestHelpers + +func test__datacopy_impl{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) { + // Given # 1 + alloc_locals; + local calldata_len: felt; + let (calldata: felt*) = alloc(); + %{ + ids.calldata_len = len(program_input["calldata"]); + segments.write_arg(ids.calldata, program_input["calldata"]); + %} + + // When + let result = PrecompileDataCopy.run( + PrecompileDataCopy.PRECOMPILE_ADDRESS, calldata_len, calldata + ); + + TestHelpers.assert_array_equal( + array_0_len=calldata_len, + array_0=calldata, + array_1_len=result.output_len, + array_1=result.output, + ); + return (); +} diff --git a/cairo/tests/src/precompiles/test_datacopy.py b/cairo/tests/src/precompiles/test_datacopy.py new file mode 100644 index 00000000..61f14da4 --- /dev/null +++ b/cairo/tests/src/precompiles/test_datacopy.py @@ -0,0 +1,9 @@ +import hypothesis.strategies as st +from hypothesis import given, settings + + +class TestDataCopy: + @given(calldata=st.binary(max_size=100)) + @settings(max_examples=20) + def test_datacopy(self, cairo_run, calldata): + cairo_run("test__datacopy_impl", calldata=list(calldata)) diff --git a/cairo/tests/src/precompiles/test_ec_add.cairo b/cairo/tests/src/precompiles/test_ec_add.cairo new file mode 100644 index 00000000..741c8570 --- /dev/null +++ b/cairo/tests/src/precompiles/test_ec_add.cairo @@ -0,0 +1,61 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.cairo_secp.bigint import BigInt3, bigint_to_uint256, uint256_to_bigint +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.alloc import alloc + +from src.constants import Constants +from src.evm import EVM +from src.instructions.memory_operations import MemoryOperations +from src.instructions.system_operations import SystemOperations, CallHelper, CreateHelper +from src.memory import Memory +from src.model import model +from src.precompiles.ecadd import PrecompileEcAdd +from src.stack import Stack +from src.utils.alt_bn128.alt_bn128_g1 import ALT_BN128, G1Point +from src.utils.utils import Helpers +from tests.utils.helpers import TestHelpers + +const G1POINT_BYTES_LEN = 32; + +func test__ecadd_impl{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { + // Given + alloc_locals; + local calldata_len: felt; + let (calldata: felt*) = alloc(); + %{ + ids.calldata_len = len(program_input["calldata"]); + segments.write_arg(ids.calldata, program_input["calldata"]); + %} + + let x0: BigInt3 = Helpers.bytes32_to_bigint(calldata); + let y0: BigInt3 = Helpers.bytes32_to_bigint(calldata + G1POINT_BYTES_LEN); + let x1: BigInt3 = Helpers.bytes32_to_bigint(calldata + G1POINT_BYTES_LEN * 2); + let y1: BigInt3 = Helpers.bytes32_to_bigint(calldata + G1POINT_BYTES_LEN * 3); + + // When + let point0: G1Point = G1Point(x0, y0); + let point1: G1Point = G1Point(x1, y1); + let (expected_point: G1Point) = ALT_BN128.ec_add(point0, point1); + let (bytes_expected_x_len, bytes_expected_result: felt*) = Helpers.bigint_to_bytes_array( + expected_point.x + ); + let (bytes_expected_y_len, bytes_expected_y: felt*) = Helpers.bigint_to_bytes_array( + expected_point.y + ); + memcpy(bytes_expected_result + bytes_expected_x_len, bytes_expected_y, bytes_expected_y_len); + let (output_len, output: felt*, gas_used, reverted) = PrecompileEcAdd.run( + PrecompileEcAdd.PRECOMPILE_ADDRESS, calldata_len, calldata + ); + + // Then + TestHelpers.assert_array_equal( + array_0_len=bytes_expected_x_len + bytes_expected_y_len, + array_0=bytes_expected_result, + array_1_len=output_len, + array_1=output, + ); + + return (); +} diff --git a/cairo/tests/src/precompiles/test_ec_add.py b/cairo/tests/src/precompiles/test_ec_add.py new file mode 100644 index 00000000..9c143792 --- /dev/null +++ b/cairo/tests/src/precompiles/test_ec_add.py @@ -0,0 +1,11 @@ +import hypothesis.strategies as st +import pytest +from hypothesis import given, settings + + +@pytest.mark.EC_ADD +class TestEcAdd: + @given(calldata=st.binary(min_size=128, max_size=128)) + @settings(max_examples=5) + def test_ecadd(self, cairo_run, calldata): + cairo_run("test__ecadd_impl", calldata=list(calldata)) diff --git a/cairo/tests/src/precompiles/test_ec_mul.cairo b/cairo/tests/src/precompiles/test_ec_mul.cairo new file mode 100644 index 00000000..738a340c --- /dev/null +++ b/cairo/tests/src/precompiles/test_ec_mul.cairo @@ -0,0 +1,53 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.cairo_secp.bigint import BigInt3, bigint_to_uint256, uint256_to_bigint +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.memcpy import memcpy + +from src.utils.utils import Helpers +from src.utils.alt_bn128.alt_bn128_g1 import ALT_BN128, G1Point +from src.precompiles.ecmul import PrecompileEcMul +from tests.utils.helpers import TestHelpers + +const G1POINT_BYTES_LEN = 32; + +func test__ecmul_impl{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() { + // Given + alloc_locals; + + let x: BigInt3 = uint256_to_bigint(Uint256(1, 0)); + let y: BigInt3 = uint256_to_bigint(Uint256(2, 0)); + let scalar: BigInt3 = uint256_to_bigint(Uint256(2, 0)); + let (x_bytes_len, x_bytes: felt*) = Helpers.bigint_to_bytes_array(x); + let (y_bytes_len, y_bytes: felt*) = Helpers.bigint_to_bytes_array(y); + let (scalar_bytes_len, scalar_bytes: felt*) = Helpers.bigint_to_bytes_array(scalar); + + // When + let point: G1Point = G1Point(x, y); + let (expected_point: G1Point) = ALT_BN128.ec_mul(point, scalar); + let (bytes_expected_x_len, bytes_expected_result: felt*) = Helpers.bigint_to_bytes_array( + expected_point.x + ); + let (bytes_expected_y_len, bytes_expected_y: felt*) = Helpers.bigint_to_bytes_array( + expected_point.y + ); + memcpy(bytes_expected_result + bytes_expected_x_len, bytes_expected_y, bytes_expected_y_len); + let input_len = 96; + let (input: felt*) = alloc(); + memcpy(input, x_bytes, x_bytes_len); + memcpy(input + 32, y_bytes, y_bytes_len); + memcpy(input + 64, scalar_bytes, scalar_bytes_len); + let (output_len, output: felt*, gas_used, reverted) = PrecompileEcMul.run( + PrecompileEcMul.PRECOMPILE_ADDRESS, input_len, input + ); + + // Then + TestHelpers.assert_array_equal( + array_0_len=bytes_expected_x_len + bytes_expected_y_len, + array_0=bytes_expected_result, + array_1_len=output_len, + array_1=output, + ); + + return (); +} diff --git a/cairo/tests/src/precompiles/test_ec_mul.py b/cairo/tests/src/precompiles/test_ec_mul.py new file mode 100644 index 00000000..b9db1278 --- /dev/null +++ b/cairo/tests/src/precompiles/test_ec_mul.py @@ -0,0 +1,8 @@ +import pytest + + +@pytest.mark.EC_MUL +class TestEcMul: + @pytest.mark.slow + def test_ec_mul(self, cairo_run): + cairo_run("test__ecmul_impl") diff --git a/cairo/tests/src/precompiles/test_ec_recover.cairo b/cairo/tests/src/precompiles/test_ec_recover.cairo new file mode 100644 index 00000000..7f09f48d --- /dev/null +++ b/cairo/tests/src/precompiles/test_ec_recover.cairo @@ -0,0 +1,23 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math import unsigned_div_rem, assert_not_zero +from starkware.cairo.common.memset import memset +from starkware.cairo.common.memcpy import memcpy + +from src.precompiles.ec_recover import PrecompileEcRecover +from src.utils.utils import Helpers + +func test__ec_recover{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + ) -> (output: felt*) { + alloc_locals; + let (local input) = alloc(); + tempvar input_len: felt; + %{ + ids.input_len = len(program_input["input"]); + segments.write_arg(ids.input, program_input["input"]) + %} + let (output_len: felt, output: felt*, gas_used: felt, reverted: felt) = PrecompileEcRecover.run( + PrecompileEcRecover.PRECOMPILE_ADDRESS, input_len, input + ); + return (output=output); +} diff --git a/cairo/tests/src/precompiles/test_ec_recover.py b/cairo/tests/src/precompiles/test_ec_recover.py new file mode 100644 index 00000000..426282dc --- /dev/null +++ b/cairo/tests/src/precompiles/test_ec_recover.py @@ -0,0 +1,70 @@ +import pytest +from ethereum.base_types import U256 +from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover +from ethereum.crypto.hash import Hash32, keccak256 +from ethereum.utils.byte import left_pad_zero_bytes +from tests.utils.helpers import ec_sign, generate_random_private_key + + +def ecrecover(data): + message_hash_bytes = data[0:32] + message_hash = Hash32(message_hash_bytes) + v = U256.from_be_bytes(data[32:64]) + r = U256.from_be_bytes(data[64:96]) + s = U256.from_be_bytes(data[96:128]) + + if v != 27 and v != 28: + return + if 0 >= r or r >= SECP256K1N: + return + if 0 >= s or s >= SECP256K1N: + return + + try: + public_key = secp256k1_recover(r, s, v - 27, message_hash) + except ValueError: + # unable to extract public key + return + + address = keccak256(public_key)[12:32] + padded_address = left_pad_zero_bytes(address, 32) + return padded_address, public_key + + +@pytest.mark.EC_RECOVER +class TestEcRecover: + def test_should_return_evm_address_in_bytes32(self, cairo_run): + private_key = generate_random_private_key() + msg = keccak256(b"test message") + (v, r, s) = ec_sign(msg, private_key) + + input_data = [ + *msg, + *v.to_bytes(32, "big"), + *r, + *s, + ] + + padded_address, _ = ecrecover(input_data) + + [output] = cairo_run("test__ec_recover", input=input_data) + + assert bytes(output) == bytes(padded_address) + + def test_should_fail_when_input_len_is_not_128(self, cairo_run): + [output] = cairo_run("test__ec_recover", input=[]) + assert output == [] + + def test_should_fail_when_recovery_identifier_is_neither_27_nor_28(self, cairo_run): + private_key = generate_random_private_key() + msg = keccak256(b"test message") + (_, r, s) = ec_sign(msg, private_key) + v = 1 + input_data = [ + *msg, + *v.to_bytes(32, "big"), + *r, + *s, + ] + [output] = cairo_run("test__ec_recover", input=input_data) + assert output == [] diff --git a/cairo/tests/src/precompiles/test_modexp.cairo b/cairo/tests/src/precompiles/test_modexp.cairo new file mode 100644 index 00000000..671449db --- /dev/null +++ b/cairo/tests/src/precompiles/test_modexp.cairo @@ -0,0 +1,27 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.math import split_felt + +from src.utils.utils import Helpers +from src.precompiles.modexp import PrecompileModExpUint256 + +func test__modexp_impl{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + output_ptr: felt* +) { + alloc_locals; + local data_len: felt; + let (data: felt*) = alloc(); + %{ + ids.data_len = len(program_input["data"]); + segments.write_arg(ids.data, program_input["data"]); + %} + + let (output_len, output, gas_used, reverted) = PrecompileModExpUint256.run( + PrecompileModExpUint256.PRECOMPILE_ADDRESS, data_len, data + ); + + let result = Helpers.bytes_to_felt(output_len, output); + assert [output_ptr] = result; + assert [output_ptr + 1] = gas_used; + return (); +} diff --git a/cairo/tests/src/precompiles/test_modexp.py b/cairo/tests/src/precompiles/test_modexp.py new file mode 100644 index 00000000..d64652ab --- /dev/null +++ b/cairo/tests/src/precompiles/test_modexp.py @@ -0,0 +1,32 @@ +import math + +import pytest + + +@pytest.mark.MOD_EXP +class TestModExp: + @pytest.mark.slow + def test_modexp(self, cairo_run): + b = 3 + b_size = math.ceil(math.log(b, 256)) + b_size_bytes = b_size.to_bytes(32, "big") + b_bytes = b.to_bytes(b_size, "big") + + e = 2**256 - 2**32 - 978 + e_size = math.ceil(math.log(e, 256)) + e_size_bytes = e_size.to_bytes(32, "big") + e_bytes = e.to_bytes(e_size, "big") + + m = 2**256 - 2**32 - 977 + m_size = math.ceil(math.log(m, 256)) + m_size_bytes = m_size.to_bytes(32, "big") + m_bytes = m.to_bytes(m_size, "big") + + bytes_array = list( + b_size_bytes + e_size_bytes + m_size_bytes + b_bytes + e_bytes + m_bytes + ) + expected_result = pow(b, e, m) + + cairo_result, gas_cost = cairo_run("test__modexp_impl", data=bytes_array) + assert expected_result == cairo_result + assert 1360 == gas_cost diff --git a/cairo/tests/src/precompiles/test_precompiles.cairo b/cairo/tests/src/precompiles/test_precompiles.cairo new file mode 100644 index 00000000..759393f1 --- /dev/null +++ b/cairo/tests/src/precompiles/test_precompiles.cairo @@ -0,0 +1,50 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.alloc import alloc + +from src.precompiles.precompiles import Precompiles +from src.precompiles.precompiles_helpers import PrecompilesHelpers + +func test__is_precompile{range_check_ptr}() -> felt { + alloc_locals; + // Given + local address; + %{ ids.address = program_input["address"] %} + + // When + let is_precompile = PrecompilesHelpers.is_precompile(address); + return is_precompile; +} + +func test__precompiles_run{ + pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin* +}() -> (output: felt*, reverted: felt, gas_used: felt) { + alloc_locals; + // Given + local address; + local input_len; + local caller_code_address; + local caller_address; + let (local input) = alloc(); + %{ + ids.address = program_input["address"] + ids.input_len = len(program_input["input"]) + segments.write_arg(ids.input, program_input["input"]) + ids.caller_code_address = program_input.get("caller_code_address", 0) + ids.caller_address = program_input.get("caller_address", 0) + %} + + // When + let result = Precompiles.exec_precompile( + precompile_address=address, + input_len=input_len, + input=input, + caller_code_address=caller_code_address, + caller_address=caller_address, + ); + let output_len = result.output_len; + let (output) = alloc(); + memcpy(dst=output, src=result.output, len=output_len); + + return (output, result.reverted, result.gas_used); +} diff --git a/cairo/tests/src/precompiles/test_precompiles.py b/cairo/tests/src/precompiles/test_precompiles.py new file mode 100644 index 00000000..a2a4b29e --- /dev/null +++ b/cairo/tests/src/precompiles/test_precompiles.py @@ -0,0 +1,106 @@ +import pytest +from tests.utils.constants import ( + FIRST_KAKAROT_PRECOMPILE_ADDRESS, + FIRST_ROLLUP_PRECOMPILE_ADDRESS, + LAST_ETHEREUM_PRECOMPILE_ADDRESS, + LAST_KAKAROT_PRECOMPILE_ADDRESS, + LAST_ROLLUP_PRECOMPILE_ADDRESS, +) + +CALL_CONTRACT_SOLIDITY_SELECTOR = "b3eb2c1b" + +AUTHORIZED_CALLER_CODE = 0xA7071ED +UNAUTHORIZED_CALLER_CODE = 0xC0C0C0 +CALLER_ADDRESS = 0x123ABC432 + + +class TestPrecompiles: + class TestRun: + + class TestEthereumPrecompiles: + @pytest.mark.parametrize( + "address, error_message", + [ + (0x0, "Kakarot: UnknownPrecompile 0"), + (0x6, "Kakarot: NotImplementedPrecompile 6"), + (0x7, "Kakarot: NotImplementedPrecompile 7"), + (0x8, "Kakarot: NotImplementedPrecompile 8"), + (0x0A, "Kakarot: NotImplementedPrecompile 10"), + ], + ) + def test__precompiles_run_should_fail( + self, cairo_run, address, error_message + ): + return_data, reverted, _ = cairo_run( + "test__precompiles_run", address=address, input=[] + ) + assert bytes(return_data).decode() == error_message + assert reverted + + class TestRollupPrecompiles: + # input data from + @pytest.mark.parametrize( + "address, input_data, expected_return_data", + [ + ( + 0x100, + bytes.fromhex( + "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e" + ), + [0] * 31 + [1], + ), + ( + 0x100, + bytes.fromhex( + "5cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e" + ), + [], + ), + ], + ) + def test__p256_verify_precompile( + self, cairo_run, address, input_data, expected_return_data + ): + return_data, reverted, gas_used = cairo_run( + "test__precompiles_run", address=address, input=input_data + ) + assert not reverted + assert return_data == expected_return_data + assert gas_used == 3450 + + class TestIsPrecompile: + @pytest.mark.parametrize( + "address", range(0, LAST_ETHEREUM_PRECOMPILE_ADDRESS + 2) + ) + def test__is_precompile_ethereum_precompiles(self, cairo_run, address): + result = cairo_run("test__is_precompile", address=address) + assert result == (address in range(1, LAST_ETHEREUM_PRECOMPILE_ADDRESS + 1)) + + @pytest.mark.parametrize( + "address", + range(FIRST_ROLLUP_PRECOMPILE_ADDRESS, LAST_ROLLUP_PRECOMPILE_ADDRESS + 2), + ) + def test__is_precompile_rollup_precompiles(self, cairo_run, address): + result = cairo_run("test__is_precompile", address=address) + assert result == ( + address + in range( + FIRST_ROLLUP_PRECOMPILE_ADDRESS, LAST_ROLLUP_PRECOMPILE_ADDRESS + 1 + ) + ) + + @pytest.mark.parametrize( + "address", + range( + FIRST_KAKAROT_PRECOMPILE_ADDRESS, LAST_KAKAROT_PRECOMPILE_ADDRESS + 2 + ), + ) + def test__is_precompile_kakarot_precompiles(self, cairo_run, address): + result = cairo_run("test__is_precompile", address=address) + assert result == ( + address + in range( + FIRST_KAKAROT_PRECOMPILE_ADDRESS, + LAST_KAKAROT_PRECOMPILE_ADDRESS + 1, + ) + ) diff --git a/cairo/tests/src/precompiles/test_ripemd160.cairo b/cairo/tests/src/precompiles/test_ripemd160.cairo new file mode 100644 index 00000000..a60dde20 --- /dev/null +++ b/cairo/tests/src/precompiles/test_ripemd160.cairo @@ -0,0 +1,24 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.memcpy import memcpy + +from src.precompiles.ripemd160 import PrecompileRIPEMD160 + +func test__ripemd160{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + output_ptr: felt* +) { + alloc_locals; + tempvar msg_len: felt; + let (msg: felt*) = alloc(); + %{ + ids.msg_len = len(program_input["msg"]) + segments.write_arg(ids.msg, program_input["msg"]) + %} + + let (hash_len, hash, gas, reverted) = PrecompileRIPEMD160.run( + PrecompileRIPEMD160.PRECOMPILE_ADDRESS, msg_len, msg + ); + + memcpy(output_ptr, hash, hash_len); + return (); +} diff --git a/cairo/tests/src/precompiles/test_ripemd160.py b/cairo/tests/src/precompiles/test_ripemd160.py new file mode 100644 index 00000000..05f2f299 --- /dev/null +++ b/cairo/tests/src/precompiles/test_ripemd160.py @@ -0,0 +1,19 @@ +import pytest +from Crypto.Hash import RIPEMD160 +from hypothesis import given, settings +from hypothesis.strategies import binary + + +@pytest.mark.slow +class TestRIPEMD160: + @given(msg_bytes=binary(min_size=1, max_size=200)) + @settings(max_examples=3) + def test_ripemd160_should_return_correct_hash(self, cairo_run, msg_bytes): + precompile_hash = cairo_run("test__ripemd160", msg=list(msg_bytes)) + + # Hash with RIPEMD-160 to compare with precompile result + ripemd160_crypto = RIPEMD160.new() + ripemd160_crypto.update(msg_bytes) + expected_hash = ripemd160_crypto.hexdigest() + + assert expected_hash.rjust(64, "0") == bytes(precompile_hash).hex() diff --git a/cairo/tests/src/precompiles/test_sha256.cairo b/cairo/tests/src/precompiles/test_sha256.cairo new file mode 100644 index 00000000..22ead776 --- /dev/null +++ b/cairo/tests/src/precompiles/test_sha256.cairo @@ -0,0 +1,27 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.memcpy import memcpy + +from src.precompiles.sha256 import PrecompileSHA256 +from src.utils.utils import Helpers + +func test__sha256{pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( + output_ptr: felt* +) { + alloc_locals; + local data_len: felt; + let (data: felt*) = alloc(); + %{ + ids.data_len = len(program_input["data"]) + segments.write_arg(ids.data, program_input["data"]) + %} + + let (hash_len, hash, gas_used, reverted) = PrecompileSHA256.run( + PrecompileSHA256.PRECOMPILE_ADDRESS, data_len, data + ); + let (minimum_word_size) = Helpers.minimum_word_count(data_len); + assert gas_used = 12 * minimum_word_size + PrecompileSHA256.GAS_COST_SHA256; + + memcpy(output_ptr, hash, hash_len); + return (); +} diff --git a/cairo/tests/src/precompiles/test_sha256.py b/cairo/tests/src/precompiles/test_sha256.py new file mode 100644 index 00000000..7886acd0 --- /dev/null +++ b/cairo/tests/src/precompiles/test_sha256.py @@ -0,0 +1,20 @@ +from hashlib import sha256 as py_sha256 + +import pytest +from hypothesis import given, settings +from hypothesis.strategies import binary + + +@pytest.mark.SHA256 +class TestSHA256: + @pytest.mark.slow + @given(message_bytes=binary(min_size=1, max_size=56)) + @settings(max_examples=10) + def test_sha256_should_return_correct_hash(self, cairo_run, message_bytes): + # Hash with SHA256 + m = py_sha256() + m.update(message_bytes) + expected_hash = m.hexdigest() + + precompile_hash = cairo_run("test__sha256", data=list(message_bytes)) + assert precompile_hash == list(bytes.fromhex(expected_hash)) diff --git a/cairo/tests/src/test_account.cairo b/cairo/tests/src/test_account.cairo new file mode 100644 index 00000000..bf89bf32 --- /dev/null +++ b/cairo/tests/src/test_account.cairo @@ -0,0 +1,195 @@ +%builtins pedersen range_check bitwise keccak + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin, KeccakBuiltin +from starkware.cairo.common.dict import dict_read +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.memcpy import memcpy + +from src.model import model +from src.account import Account +from tests.utils.helpers import TestHelpers + +func test__init__should_return_account_with_default_dict_as_storage{}() { + alloc_locals; + + // Given + local evm_address: felt; + local code_len: felt; + let (code) = alloc(); + let (code_hash_ptr) = alloc(); + local nonce: felt; + local balance_low: felt; + %{ + from src.utils.uint256 import int_to_uint256 + + ids.evm_address = program_input["evm_address"] + ids.code_len = len(program_input["code"]) + segments.write_arg(ids.code, program_input["code"]) + segments.write_arg(ids.code_hash_ptr, int_to_uint256(program_input["code_hash"])) + ids.nonce = program_input["nonce"] + ids.balance_low = program_input["balance_low"] + %} + + tempvar address = new model.Address(starknet=0xdead, evm=evm_address); + tempvar balance = new Uint256(balance_low, 0); + + // When + let account = Account.init( + address, code_len, code, cast(code_hash_ptr, Uint256*), nonce, balance + ); + + // Then + assert account.address = address; + assert account.code_len = code_len; + assert account.nonce = nonce; + assert account.balance.low = balance_low; + assert account.balance.high = 0; + assert account.selfdestruct = 0; + let storage = account.storage; + let (value) = dict_read{dict_ptr=storage}(0xdead); + assert value = 0; + return (); +} + +func test__copy__should_return_new_account_with_same_attributes{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + alloc_locals; + // Given + local evm_address: felt; + local code_len: felt; + let (code) = alloc(); + let (code_hash_ptr) = alloc(); + local nonce: felt; + local balance_low: felt; + %{ + from src.utils.uint256 import int_to_uint256 + + ids.evm_address = program_input["evm_address"] + ids.code_len = len(program_input["code"]) + segments.write_arg(ids.code, program_input["code"]) + segments.write_arg(ids.code_hash_ptr, int_to_uint256(program_input["code_hash"])) + ids.nonce = program_input["nonce"] + ids.balance_low = program_input["balance_low"] + %} + + tempvar address = new model.Address(starknet=0xdead, evm=evm_address); + tempvar balance = new Uint256(balance_low, 0); + let account = Account.init( + address, code_len, code, cast(code_hash_ptr, Uint256*), nonce, balance + ); + tempvar key = new Uint256(1, 2); + tempvar value = new Uint256(3, 4); + let account = Account.write_storage(account, key, value); + + // When + let account_copy = Account.copy(account); + + // Then + + // Same immutable attributes + assert account.address = account_copy.address; + assert account.code_len = account_copy.code_len; + assert account.nonce = account_copy.nonce; + assert account.balance.low = balance_low; + assert account.balance.high = 0; + assert account.selfdestruct = account_copy.selfdestruct; + + // Same storage + let storage_len = account.storage - account.storage_start; + let storage_copy_len = account_copy.storage - account_copy.storage_start; + assert storage_len = storage_copy_len; + let (account_copy, value_copy) = Account.read_storage(account_copy, key); + assert_uint256_eq([value], [value_copy]); + + // Updating copy doesn't update original + tempvar new_value = new Uint256(5, 6); + let account_copy = Account.write_storage(account_copy, key, new_value); + let (account, value_original) = Account.read_storage(account, key); + assert_uint256_eq([value], [value_original]); + + return (); +} + +func test__write_storage__should_store_value_at_key{pedersen_ptr: HashBuiltin*, range_check_ptr}() { + // Given + alloc_locals; + let (key_ptr) = alloc(); + let (value_ptr) = alloc(); + + %{ + segments.write_arg(ids.key_ptr, program_input["key"]) + segments.write_arg(ids.value_ptr, program_input["value"]) + %} + + let key = cast(key_ptr, Uint256*); + let value = cast(value_ptr, Uint256*); + + tempvar address = new model.Address(0xdead, 0); + let (local code: felt*) = alloc(); + tempvar code_hash = new Uint256(0, 0); + tempvar balance = new Uint256(0, 0); + let account = Account.init(address, 0, code, code_hash, 0, balance); + + // When + let account = Account.write_storage(account, key, value); + + // Then + let storage_len = account.storage - account.storage_start; + assert storage_len = DictAccess.SIZE; + let (account, value_read) = Account.read_storage(account, key); + assert_uint256_eq([value_read], [value]); + + return (); +} + +func test__has_code_or_nonce() -> felt { + alloc_locals; + // Given + local code_len: felt; + let (code) = alloc(); + let (code_hash_ptr) = alloc(); + local nonce: felt; + %{ + from src.utils.uint256 import int_to_uint256 + + ids.code_len = len(program_input["code"]) + segments.write_arg(ids.code, program_input["code"]) + segments.write_arg(ids.code_hash_ptr, int_to_uint256(program_input["code_hash"])) + ids.nonce = program_input["nonce"] + %} + + tempvar address = new model.Address(0xdead, 0); + tempvar balance = new Uint256(0, 0); + let account = Account.init( + address, code_len, code, cast(code_hash_ptr, Uint256*), nonce, balance + ); + + // When + let result = Account.has_code_or_nonce(account); + + // Then + return result; +} + +func test__compute_code_hash{ + range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* +}() -> Uint256 { + alloc_locals; + + // Given + local code_len: felt; + let (code) = alloc(); + %{ + ids.code_len = len(program_input["code"]) + segments.write_arg(ids.code, program_input["code"]) + %} + + // When + let result = Account.compute_code_hash(code_len, code); + + // Then + return result; +} diff --git a/cairo/tests/src/test_account.py b/cairo/tests/src/test_account.py new file mode 100644 index 00000000..9af1788c --- /dev/null +++ b/cairo/tests/src/test_account.py @@ -0,0 +1,61 @@ +import pytest +from eth_utils import keccak +from hypothesis import given +from hypothesis.strategies import binary +from src.utils.uint256 import int_to_uint256 + + +class TestAccount: + class TestInit: + @pytest.mark.parametrize( + "address, code, nonce, balance", + [(0, [], 0, 0), (2**160 - 1, [1, 2, 3], 1, 1)], + ) + def test_should_return_account_with_default_dict_as_storage( + self, cairo_run, address, code, nonce, balance + ): + code_hash_bytes = keccak(bytes(code)) + code_hash = int.from_bytes(code_hash_bytes, "big") + cairo_run( + "test__init__should_return_account_with_default_dict_as_storage", + evm_address=address, + code=code, + nonce=nonce, + balance_low=balance, + code_hash=code_hash, + ) + + class TestCopy: + @pytest.mark.parametrize( + "address, code, nonce, balance", + [(0, [], 0, 0), (2**160 - 1, [1, 2, 3], 1, 1)], + ) + def test_should_return_new_account_with_same_attributes( + self, cairo_run, address, code, nonce, balance + ): + code_hash_bytes = keccak(bytes(code)) + code_hash = int.from_bytes(code_hash_bytes, "big") + cairo_run( + "test__copy__should_return_new_account_with_same_attributes", + evm_address=address, + code=code, + nonce=nonce, + balance_low=balance, + code_hash=code_hash, + ) + + class TestWriteStorage: + @pytest.mark.parametrize("key, value", [(0, 0), (2**256 - 1, 2**256 - 1)]) + def test_should_store_value_at_key(self, cairo_run, key, value): + cairo_run( + "test__write_storage__should_store_value_at_key", + key=int_to_uint256(key), + value=int_to_uint256(value), + ) + + class TestComputeCodeHash: + @given(bytecode=binary(min_size=0, max_size=400)) + def test_should_compute_code_hash(self, cairo_run, bytecode): + output = cairo_run("test__compute_code_hash", code=bytecode) + code_hash = int.from_bytes(keccak(bytecode), byteorder="big") + assert int(output, 16) == code_hash diff --git a/cairo/tests/src/test_evm.cairo b/cairo/tests/src/test_evm.cairo new file mode 100644 index 00000000..910e0789 --- /dev/null +++ b/cairo/tests/src/test_evm.cairo @@ -0,0 +1,69 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.dict_access import DictAccess + +from src.evm import EVM, Internals +from src.model import model +from src.state import State +from tests.utils.helpers import TestHelpers + +func test__jump{pedersen_ptr: HashBuiltin*, range_check_ptr}() -> model.EVM* { + alloc_locals; + local bytecode_len: felt; + let (bytecode) = alloc(); + local jumpdest: felt; + %{ + ids.bytecode_len = len(program_input["bytecode"]); + segments.write_arg(ids.bytecode, program_input["bytecode"]); + ids.jumpdest = program_input["jumpdest"]; + %} + let evm = TestHelpers.init_evm_with_bytecode(bytecode_len, bytecode); + let state = State.init(); + with state { + let evm = EVM.jump(evm, jumpdest); + } + + return evm; +} + +func test__is_valid_jumpdest{pedersen_ptr: HashBuiltin*, range_check_ptr}() -> felt { + alloc_locals; + + local index; + + %{ + from collections import defaultdict + from tests.utils.hints import new_default_dict + + if '__dict_manager' not in globals(): + from starkware.cairo.common.dict import DictManager + __dict_manager = DictManager() + + initial_dict = defaultdict(int, program_input["cached_jumpdests"]) + memory[ap] = new_default_dict(__dict_manager, segments, 0, initial_dict) + del initial_dict + + ids.index = program_input["index"] + %} + ap += 1; + let valid_jumpdests = cast([ap - 1], DictAccess*); + let state = State.init(); + tempvar address_zero = new model.Address(starknet=0, evm=0); + + with valid_jumpdests, state { + let result = Internals.is_valid_jumpdest(address_zero, index); + } + + return result; +} + +func test__charge_gas{pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (felt, felt) { + alloc_locals; + local amount; + + %{ ids.amount = program_input["amount"] %} + let evm = TestHelpers.init_evm(); + let result = EVM.charge_gas(evm, amount); + + return (result.gas_left, result.stopped); +} diff --git a/cairo/tests/src/test_evm.py b/cairo/tests/src/test_evm.py new file mode 100644 index 00000000..302618d9 --- /dev/null +++ b/cairo/tests/src/test_evm.py @@ -0,0 +1,38 @@ +import pytest +from hypothesis import given +from hypothesis.strategies import integers + + +class TestIsValidJumpdest: + @pytest.mark.parametrize( + "cached_jumpdests, index, expected", + [ + ({0x01: True, 0x10: True, 0x101: True}, 0x10, 1), + ({0x01: True, 0x10: True, 0x101: True}, 0x101, 1), + ], + ) + def test_should_return_cached_valid_jumpdest( + self, cairo_run, cached_jumpdests, index, expected + ): + assert ( + cairo_run( + "test__is_valid_jumpdest", + cached_jumpdests=cached_jumpdests, + index=index, + ) + == expected + ) + + # 1000000 is the default value for the init_evm test helper + @given(amount=integers(min_value=0, max_value=1000000)) + def test_should_return_gas_left(self, cairo_run, amount): + gas_left, stopped = cairo_run("test__charge_gas", amount=amount) + assert gas_left == 1000000 - amount + assert stopped == 0 + + # 1000000 is the default value for the init_evm test helper + @given(amount=integers(min_value=1000001, max_value=2**248 - 1)) + def test_should_return_not_enough_gas(self, cairo_run, amount): + gas_left, stopped = cairo_run("test__charge_gas", amount=amount) + assert gas_left == 0 + assert stopped == 1 diff --git a/cairo/tests/src/test_gas.cairo b/cairo/tests/src/test_gas.cairo new file mode 100644 index 00000000..e3032f8c --- /dev/null +++ b/cairo/tests/src/test_gas.cairo @@ -0,0 +1,85 @@ +%builtins range_check + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc + +from src.gas import Gas + +func test__memory_cost{range_check_ptr}() -> felt { + tempvar words_len: felt; + %{ ids.words_len = program_input["words_len"]; %} + let cost = Gas.memory_cost(words_len); + + return cost; +} + +func test__memory_expansion_cost{range_check_ptr}() -> felt { + tempvar words_len: felt; + tempvar max_offset: felt; + %{ + ids.words_len = program_input["words_len"]; + ids.max_offset = program_input["max_offset"]; + %} + let memory_expansion = Gas.calculate_gas_extend_memory(words_len, max_offset); + + return memory_expansion.cost; +} + +func test__max_memory_expansion_cost{range_check_ptr}() -> felt { + alloc_locals; + let fp_and_pc = get_fp_and_pc(); + local __fp__: felt* = fp_and_pc.fp_val; + local words_len: felt; + local offset_1: Uint256; + local size_1: Uint256; + local offset_2: Uint256; + local size_2: Uint256; + %{ + ids.words_len = program_input["words_len"]; + ids.offset_1.low = program_input["offset_1"]; + ids.offset_1.high = 0; + ids.size_1.low = program_input["size_1"]; + ids.size_1.high = 0; + ids.offset_2.low = program_input["offset_2"]; + ids.offset_2.high = 0; + ids.size_2.low = program_input["size_2"]; + ids.size_2.high = 0; + %} + let memory_expansion = Gas.max_memory_expansion_cost( + words_len, &offset_1, &size_1, &offset_2, &size_2 + ); + + return memory_expansion.cost; +} + +func test__memory_expansion_cost_saturated{range_check_ptr}() -> felt { + alloc_locals; + local words_len: felt; + let (offset) = alloc(); + let (size) = alloc(); + %{ + from src.utils.uint256 import int_to_uint256 + ids.words_len = program_input["words_len"] + segments.write_arg(ids.offset, int_to_uint256(program_input["offset"])) + segments.write_arg(ids.size, int_to_uint256(program_input["size"])) + %} + + let memory_expansion = Gas.memory_expansion_cost_saturated( + words_len, [cast(offset, Uint256*)], [cast(size, Uint256*)] + ); + return memory_expansion.cost; +} + +func test__compute_message_call_gas{range_check_ptr}() -> felt { + tempvar gas_param: Uint256; + tempvar gas_left: felt; + %{ + ids.gas_param.low = program_input["gas_param"]; + ids.gas_param.high = 0; + ids.gas_left = program_input["gas_left"]; + %} + let gas = Gas.compute_message_call_gas(gas_param, gas_left); + + return gas; +} diff --git a/cairo/tests/src/test_gas.py b/cairo/tests/src/test_gas.py new file mode 100644 index 00000000..91d0104c --- /dev/null +++ b/cairo/tests/src/test_gas.py @@ -0,0 +1,102 @@ +import pytest +from ethereum.shanghai.vm.gas import ( + calculate_gas_extend_memory, + calculate_memory_gas_cost, +) +from hypothesis import given +from hypothesis.strategies import integers +from src.utils.uint256 import int_to_uint256 + +int_to_uint256(0) # (0, 0) + + +class TestGas: + class TestCost: + @given(max_offset=integers(min_value=0, max_value=0xFFFFFF)) + def test_should_return_same_as_execution_specs(self, cairo_run, max_offset): + output = cairo_run("test__memory_cost", words_len=(max_offset + 31) // 32) + assert calculate_memory_gas_cost(max_offset) == output + + @given( + bytes_len=integers(min_value=0, max_value=2**128 - 1), + added_offset=integers(min_value=0, max_value=2**128 - 1), + ) + def test_should_return_correct_expansion_cost( + self, cairo_run, bytes_len, added_offset + ): + max_offset = bytes_len + added_offset + output = cairo_run( + "test__memory_expansion_cost", + words_len=(bytes_len + 31) // 32, + max_offset=max_offset, + ) + cost_before = calculate_memory_gas_cost(bytes_len) + cost_after = calculate_memory_gas_cost(max_offset) + diff = cost_after - cost_before + assert diff == output + + @given( + offset_1=integers(min_value=0, max_value=0xFFFFF), + size_1=integers(min_value=0, max_value=0xFFFFF), + offset_2=integers(min_value=0, max_value=0xFFFFF), + size_2=integers(min_value=0, max_value=0xFFFFF), + ) + def test_should_return_max_expansion_cost( + self, cairo_run, offset_1, size_1, offset_2, size_2 + ): + output = cairo_run( + "test__max_memory_expansion_cost", + words_len=0, + offset_1=offset_1, + size_1=size_1, + offset_2=offset_2, + size_2=size_2, + ) + assert ( + output + == calculate_gas_extend_memory( + b"", + [ + (offset_1, size_1), + (offset_2, size_2), + ], + ).cost + ) + + @given( + offset=integers(min_value=0, max_value=2**256 - 1), + size=integers(min_value=0, max_value=2**256 - 1), + ) + def test_memory_expansion_cost_saturated(self, cairo_run, offset, size): + output = cairo_run( + "test__memory_expansion_cost_saturated", + words_len=0, + offset=offset, + size=size, + ) + if size == 0: + cost = 0 + elif offset + size > 2**32: + cost = calculate_memory_gas_cost(2**32) + else: + cost = calculate_gas_extend_memory(b"", [(offset, size)]).cost + + assert cost == output + + class TestMessageGas: + @pytest.mark.parametrize( + "gas_param, gas_left, expected", + [ + (0, 0, 0), + (10, 100, 10), + (100, 100, 99), + (100, 10, 10), + ], + ) + def test_should_return_message_base_gas( + self, cairo_run, gas_param, gas_left, expected + ): + output = cairo_run( + "test__compute_message_call_gas", gas_param=gas_param, gas_left=gas_left + ) + assert output == expected diff --git a/cairo/tests/src/test_memory.cairo b/cairo/tests/src/test_memory.cairo new file mode 100644 index 00000000..fae93311 --- /dev/null +++ b/cairo/tests/src/test_memory.cairo @@ -0,0 +1,81 @@ +%builtins range_check + +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq + +from src.memory import Memory +from src.model import model + +func test__init__should_return_an_empty_memory() { + // When + let memory = Memory.init(); + + // Then + assert memory.words_len = 0; + return (); +} + +func test__store__should_add_an_element_to_the_memory{range_check_ptr}() { + alloc_locals; + // Given + let memory = Memory.init(); + let value = Uint256(1, 0); + + // When + with memory { + Memory.store(value, 0); + let stored = Memory.load(0); + } + + assert_uint256_eq(value, stored); + + // Then + return (); +} + +func test__load__should_load_an_element_from_the_memory_with_offset{range_check_ptr}() { + alloc_locals; + // Given + local offset: felt; + local low: felt; + local high: felt; + %{ + ids.offset = program_input["offset"] + ids.low = program_input["low"] + ids.high = program_input["high"] + %} + + let memory = Memory.init(); + let first_value = Uint256(low=2, high=1); + let second_value = Uint256(low=4, high=3); + + // When + with memory { + Memory.store(first_value, 0); + Memory.store(second_value, 32); + let result = Memory.load(offset); + } + + // Then + assert_uint256_eq(result, Uint256(low, high)); + + return (); +} + +func test__load__should_return_element{range_check_ptr}() { + // Given + alloc_locals; + let memory = Memory.init(); + let value = Uint256(1, 0); + + // When + with memory { + Memory.store(value, 0); + let value = Memory.load(0); + // Then + assert value = Uint256(1, 0); + + let value = Memory.load(32); + } + assert value = Uint256(0, 0); + return (); +} diff --git a/cairo/tests/src/test_memory.py b/cairo/tests/src/test_memory.py new file mode 100644 index 00000000..d7a260cd --- /dev/null +++ b/cairo/tests/src/test_memory.py @@ -0,0 +1,36 @@ +import pytest + + +class TestMemory: + class TestInit: + def test_should_return_an_empty_memory(self, cairo_run): + cairo_run("test__init__should_return_an_empty_memory") + + class TestStore: + def test_should_add_an_element_to_the_memory(self, cairo_run): + cairo_run("test__store__should_add_an_element_to_the_memory") + + class TestLoad: + @pytest.mark.parametrize( + "offset, low, high", + [ + (8, 2 * 256**8, 256**8), + (7, 2 * 256**7, 256**7), + (23, 3 * 256**7, 2 * 256**7), + (33, 4 * 256**1, 3 * 256**1), + (63, 0, 4 * 256**15), + (500, 0, 0), + ], + ) + def test_should_load_an_element_from_the_memory_with_offset( + self, cairo_run, offset, low, high + ): + cairo_run( + "test__load__should_load_an_element_from_the_memory_with_offset", + offset=offset, + low=low, + high=high, + ) + + def test_should_expand_memory_and_return_element(self, cairo_run): + cairo_run("test__load__should_return_element") diff --git a/cairo/tests/src/test_stack.cairo b/cairo/tests/src/test_stack.cairo new file mode 100644 index 00000000..fdc9dc5f --- /dev/null +++ b/cairo/tests/src/test_stack.cairo @@ -0,0 +1,147 @@ +%builtins range_check + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.uint256 import assert_uint256_eq + +from src.utils.utils import Helpers +from src.constants import Constants +from src.model import model +from src.stack import Stack + +func test__init__should_return_an_empty_stack() { + // When + let stack = Stack.init(); + + // Then + assert stack.size = 0; + return (); +} + +func test__push__should_add_an_element_to_the_stack() { + // Given + let stack = Stack.init(); + + // When + Stack.push_uint128{stack=stack}(1); + + // Then + assert stack.size = 1; + return (); +} + +func test__pop__should_pop_an_element_to_the_stack{range_check_ptr}() { + // Given + let stack = Stack.init(); + tempvar item_0 = new Uint256(1, 0); + tempvar item_1 = new Uint256(2, 0); + tempvar item_2 = new Uint256(3, 0); + + with stack { + Stack.push(item_2); + Stack.push(item_1); + Stack.push(item_0); + + // When + let (element) = Stack.pop(); + } + + // Then + assert stack.size = 2; + assert_uint256_eq([element], [item_0]); + return (); +} + +func test__pop__should_pop_N_elements_to_the_stack{range_check_ptr}() { + alloc_locals; + // Given + let stack = Stack.init(); + tempvar item_0 = new Uint256(1, 0); + tempvar item_1 = new Uint256(2, 0); + tempvar item_2 = new Uint256(3, 0); + + with stack { + Stack.push(item_2); + Stack.push(item_1); + Stack.push(item_0); + + // When + let (local elements) = Stack.pop_n(3); + } + + // Then + assert_uint256_eq(elements[0], Uint256(1, 0)); + assert_uint256_eq(elements[1], Uint256(2, 0)); + assert_uint256_eq(elements[2], Uint256(3, 0)); + + assert stack.size = 0; + return (); +} + +func test__peek__should_return_stack_at_given_index__when_value_is_0{range_check_ptr}() { + // Given + let stack = Stack.init(); + tempvar item_0 = new Uint256(1, 0); + tempvar item_1 = new Uint256(2, 0); + tempvar item_2 = new Uint256(3, 0); + + with stack { + Stack.push(item_2); + Stack.push(item_1); + Stack.push(item_0); + + // When + let (peek_0) = Stack.peek(0); + } + + // Then + assert_uint256_eq([peek_0], [item_0]); + return (); +} + +func test__peek__should_return_stack_at_given_index__when_value_is_1{range_check_ptr}() { + // Given + let stack = Stack.init(); + tempvar item_0 = new Uint256(1, 0); + tempvar item_1 = new Uint256(2, 0); + tempvar item_2 = new Uint256(3, 0); + + with stack { + Stack.push(item_2); + Stack.push(item_1); + Stack.push(item_0); + + // When + let (peek_1) = Stack.peek(1); + } + + // Then + assert_uint256_eq([peek_1], [item_1]); + return (); +} + +func test__swap__should_swap_2_stacks() -> model.Stack* { + // Given + alloc_locals; + + // Given + let stack = Stack.init(); + tempvar item_0 = new Uint256(1, 0); + tempvar item_1 = new Uint256(2, 0); + tempvar item_2 = new Uint256(3, 0); + tempvar item_3 = new Uint256(4, 0); + + with stack { + Stack.push(item_3); + Stack.push(item_2); + Stack.push(item_1); + Stack.push(item_0); + + // When + Stack.swap_i(3); + } + + return stack; +} diff --git a/cairo/tests/src/test_stack.py b/cairo/tests/src/test_stack.py new file mode 100644 index 00000000..521e2841 --- /dev/null +++ b/cairo/tests/src/test_stack.py @@ -0,0 +1,27 @@ +class TestStack: + class TestPeek: + def test_should_return_stack_at_given_index__when_value_is_0(self, cairo_run): + cairo_run("test__peek__should_return_stack_at_given_index__when_value_is_0") + + def test_should_return_stack_at_given_index__when_value_is_1(self, cairo_run): + cairo_run("test__peek__should_return_stack_at_given_index__when_value_is_1") + + class TestInit: + def test_should_return_an_empty_stack(self, cairo_run): + cairo_run("test__init__should_return_an_empty_stack") + + class TestPush: + def test_should_add_an_element_to_the_stack(self, cairo_run): + cairo_run("test__push__should_add_an_element_to_the_stack") + + class TestPop: + def test_should_pop_an_element_to_the_stack(self, cairo_run): + cairo_run("test__pop__should_pop_an_element_to_the_stack") + + def test_should_pop_N_elements_to_the_stack(self, cairo_run): + cairo_run("test__pop__should_pop_N_elements_to_the_stack") + + class TestSwap: + def test_should_swap_2_stacks(self, cairo_run): + stack = cairo_run("test__swap__should_swap_2_stacks") + assert stack == ["0x1", "0x3", "0x2", "0x4"] diff --git a/cairo/tests/src/test_state.cairo b/cairo/tests/src/test_state.cairo new file mode 100644 index 00000000..f2c9df2d --- /dev/null +++ b/cairo/tests/src/test_state.cairo @@ -0,0 +1,288 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.dict import dict_read, dict_write +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq +from starkware.cairo.common.math import assert_not_equal +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.registers import get_fp_and_pc +from starkware.cairo.common.memcpy import memcpy + +from src.model import model +from src.state import State, Internals +from src.account import Account +from src.utils.dict import dict_keys + +func test__init__should_return_state_with_default_dicts() { + // When + let state = State.init(); + + // Then + assert state.accounts - state.accounts_start = 0; + assert state.events_len = 0; + assert state.transfers_len = 0; + + let accounts = state.accounts; + let (value) = dict_read{dict_ptr=accounts}(0xdead); + assert value = 0; + + return (); +} + +func test__copy__should_return_new_state_with_same_attributes{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + alloc_locals; + // Given + + // 1. Create empty State + let state = State.init(); + + // 2. Put two accounts with some storage + tempvar address_0 = new model.Address(1, 2); + tempvar address_1 = new model.Address(3, 4); + tempvar key_0 = new Uint256(1, 2); + tempvar key_1 = new Uint256(3, 4); + tempvar value = new Uint256(3, 4); + with state { + State.write_storage(address_0.evm, key_0, value); + State.write_storage(address_1.evm, key_0, value); + State.write_storage(address_1.evm, key_1, value); + + // 3. Put some events + let (local topics: felt*) = alloc(); + let (local data: felt*) = alloc(); + let event = model.Event(topics_len=0, topics=topics, data_len=0, data=data); + State.add_event(event); + + // 4. Add transfers + // State.add_transfer requires a native token contract deployed so we just push. + let amount = Uint256(0xa, 0xb); + tempvar transfer = model.Transfer(address_0, address_1, amount); + assert state.transfers[0] = transfer; + tempvar state = new model.State( + accounts_start=state.accounts_start, + accounts=state.accounts, + events_len=state.events_len, + events=state.events, + transfers_len=1, + transfers=state.transfers, + ); + + // When + let state_copy = State.copy(); + } + + // Then + + // Storage + let value_copy = State.read_storage{state=state_copy}(address_0.evm, key_0); + assert_uint256_eq([value], [value_copy]); + let value_copy = State.read_storage{state=state_copy}(address_1.evm, key_0); + assert_uint256_eq([value], [value_copy]); + let value_copy = State.read_storage{state=state_copy}(address_1.evm, key_1); + assert_uint256_eq([value], [value_copy]); + + // Events + assert state_copy.events_len = state.events_len; + + // Transfers + assert state_copy.transfers_len = state.transfers_len; + let transfer_copy = state_copy.transfers; + assert transfer.sender.starknet = transfer_copy.sender.starknet; + assert transfer.sender.evm = transfer_copy.sender.evm; + assert transfer.recipient.starknet = transfer_copy.recipient.starknet; + assert transfer.recipient.evm = transfer_copy.recipient.evm; + assert_uint256_eq(transfer.amount, transfer_copy.amount); + + return (); +} + +func test__is_account_alive__account_alive_not_in_state{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + // As the account is not in the local state, data is fetched from + // Starknet, which is mocked by pytest. + let state = State.init(); + with state { + let is_alive = State.is_account_alive(0xabde1); + } + + assert is_alive = 1; + return (); +} + +func test__is_account_alive__account_not_alive_not_in_state{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + let state = State.init(); + with state { + let is_alive = State.is_account_alive(0xdead); + } + + assert is_alive = 0; + return (); +} + +func test___copy_accounts__should_handle_null_pointers{range_check_ptr}() { + alloc_locals; + let (accounts) = default_dict_new(0); + tempvar accounts_start = accounts; + tempvar address = new model.Address(1, 2); + tempvar balance = new Uint256(1, 0); + let (code) = alloc(); + tempvar code_hash = new Uint256( + 304396909071904405792975023732328604784, 262949717399590921288928019264691438528 + ); + let account = Account.init(address, 0, code, code_hash, 1, balance); + dict_write{dict_ptr=accounts}(address.evm, cast(account, felt)); + let empty_address = 'empty address'; + dict_read{dict_ptr=accounts}(empty_address); + let (local accounts_copy: DictAccess*) = default_dict_new(0); + Internals._copy_accounts{accounts=accounts_copy}(accounts_start, accounts); + + let (pointer) = dict_read{dict_ptr=accounts_copy}(address.evm); + tempvar existing_account = cast(pointer, model.Account*); + + assert existing_account.address.starknet = address.starknet; + assert existing_account.address.evm = address.evm; + assert existing_account.balance.low = 1; + assert existing_account.balance.high = 0; + assert existing_account.code_len = 0; + + return (); +} + +func test__is_account_warm__account_in_state{pedersen_ptr: HashBuiltin*, range_check_ptr}() { + let evm_address = 'alive'; + tempvar address = new model.Address(0xdead, evm_address); + tempvar balance = new Uint256(1, 0); + let (code) = alloc(); + tempvar code_hash = new Uint256( + 304396909071904405792975023732328604784, 262949717399590921288928019264691438528 + ); + let account = Account.init(address, 0, code, code_hash, 1, balance); + tempvar state = State.init(); + + with state { + State.update_account(account); + let is_warm = State.is_account_warm(evm_address); + } + + assert is_warm = 1; + return (); +} + +func test__is_account_warm__account_not_in_state{pedersen_ptr: HashBuiltin*, range_check_ptr}() { + let state = State.init(); + let evm_address = 'alive'; + with state { + let is_warm = State.is_account_warm(evm_address); + } + assert is_warm = 0; + return (); +} + +func test__is_account_warm__warms_up_account{pedersen_ptr: HashBuiltin*, range_check_ptr}() { + let state = State.init(); + let evm_address = 'alive'; + with state { + let is_warm = State.is_account_warm(evm_address); + } + assert is_warm = 0; + + with state { + let is_warm = State.is_account_warm(evm_address); + } + + assert is_warm = 1; + return (); +} + +func test__cache_precompiles{pedersen_ptr: HashBuiltin*, range_check_ptr}() -> model.State* { + alloc_locals; + let state = State.init(); + with state { + State.cache_precompiles(); + } + + return state; +} + +func test__cache_access_list{pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( + access_list_cost: felt, state: model.State* +) { + alloc_locals; + local access_list_len: felt; + let (access_list) = alloc(); + %{ + ids.access_list_len = len(program_input["access_list"]) + segments.write_arg(ids.access_list, program_input["access_list"]) + %} + let state = State.init(); + with state { + let access_list_cost = State.cache_access_list(access_list_len, access_list); + } + + return (access_list_cost, state); +} + +func test__is_storage_warm__should_return_true_when_already_read{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + alloc_locals; + let state = State.init(); + tempvar key = new Uint256(1, 2); + tempvar address = 'evm_address'; + with state { + let account = State.get_account('evm_address'); + let (account, value) = Account.read_storage(account, key); + State.update_account(account); + + // When + let result = State.is_storage_warm(address, key); + } + + // Then + assert result = 1; + return (); +} + +func test__is_storage_warm__should_return_true_when_already_written{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + alloc_locals; + let state = State.init(); + tempvar key = new Uint256(1, 2); + tempvar address = 'evm_address'; + tempvar value = new Uint256(2, 3); + with state { + let account = State.get_account('evm_address'); + let account = Account.write_storage(account, key, value); + State.update_account(account); + + // When + let result = State.is_storage_warm(address, key); + } + + // Then + assert result = 1; + return (); +} + +func test__is_storage_warm__should_return_false_when_not_accessed{ + pedersen_ptr: HashBuiltin*, range_check_ptr +}() { + alloc_locals; + let state = State.init(); + tempvar address = 'evm_address'; + tempvar key = new Uint256(1, 2); + + // When + with state { + let result = State.is_storage_warm(address, key); + } + // Then + assert result = 0; + return (); +} diff --git a/cairo/tests/src/test_state.py b/cairo/tests/src/test_state.py new file mode 100644 index 00000000..cc81b28a --- /dev/null +++ b/cairo/tests/src/test_state.py @@ -0,0 +1,12 @@ +class TestState: + class TestInit: + def test_should_return_state_with_default_dicts(self, cairo_run): + cairo_run("test__init__should_return_state_with_default_dicts") + + class TestIsAccountWarm: + def test_should_return_true_when_account_in_state(self, cairo_run): + cairo_run("test__is_account_warm__account_in_state") + + class TestCopyAccounts: + def test_should_handle_null_pointers(self, cairo_run): + cairo_run("test___copy_accounts__should_handle_null_pointers") diff --git a/cairo/tests/src/utils/test_array.cairo b/cairo/tests/src/utils/test_array.cairo new file mode 100644 index 00000000..9934fc56 --- /dev/null +++ b/cairo/tests/src/utils/test_array.cairo @@ -0,0 +1,81 @@ +%builtins range_check + +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.alloc import alloc + +from src.utils.array import reverse, count_not_zero, slice, contains, pad_end + +func test__reverse(output_ptr: felt*) { + alloc_locals; + tempvar arr_len: felt; + let (arr) = alloc(); + %{ + ids.arr_len = len(program_input["arr"]) + segments.write_arg(ids.arr, program_input["arr"]) + %} + + reverse(output_ptr, arr_len, arr); + return (); +} + +func test__count_not_zero(output_ptr: felt*) { + tempvar arr_len: felt; + let (arr) = alloc(); + %{ + ids.arr_len = len(program_input["arr"]) + segments.write_arg(ids.arr, program_input["arr"]) + %} + + let count = count_not_zero(arr_len, arr); + assert [output_ptr] = count; + return (); +} + +func test__slice{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar arr_len: felt; + let (arr) = alloc(); + tempvar offset: felt; + tempvar size: felt; + %{ + ids.arr_len = len(program_input["arr"]) + segments.write_arg(ids.arr, program_input["arr"]) + ids.offset = program_input["offset"] + ids.size = program_input["size"] + %} + + slice(output_ptr, arr_len, arr, offset, size); + return (); +} + +func test_contains{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar arr_len: felt; + let (arr) = alloc(); + tempvar value: felt; + %{ + ids.arr_len = len(program_input["arr"]) + segments.write_arg(ids.arr, program_input["arr"]) + ids.value = program_input["value"] + %} + + let result = contains(arr_len, arr, value); + assert [output_ptr] = result; + return (); +} + +func test_pad_end{range_check_ptr}() -> (arr: felt*) { + alloc_locals; + tempvar arr_len: felt; + let (local arr) = alloc(); + tempvar size: felt; + %{ + ids.arr_len = len(program_input["arr"]) + segments.write_arg(ids.arr, program_input["arr"]) + ids.size = program_input["size"] + %} + + pad_end(arr_len, arr, size); + return (arr=arr); +} diff --git a/cairo/tests/src/utils/test_array.py b/cairo/tests/src/utils/test_array.py new file mode 100644 index 00000000..3c6e4018 --- /dev/null +++ b/cairo/tests/src/utils/test_array.py @@ -0,0 +1,74 @@ +import pytest + + +class TestArray: + class TestReverse: + @pytest.mark.parametrize( + "arr", + [ + [0, 1, 2, 3, 4], + [0, 1, 2, 3], + [0, 1, 2], + [0, 1], + [0], + [], + ], + ) + def test_should_return_reversed_array(self, cairo_run, arr): + output = cairo_run("test__reverse", arr=arr) + assert arr[::-1] == output + + class TestCountNotZero: + @pytest.mark.parametrize( + "arr", + [ + [0, 1, 0, 0, 4], + [0, 1, 0, 3], + [0, 1, 0], + [0, 1], + [0], + [], + ], + ) + def test_should_return_count_of_non_zero_elements(self, cairo_run, arr): + output = cairo_run("test__count_not_zero", arr=arr) + assert len(arr) - arr.count(0) == output[0] + + class TestSlice: + @pytest.mark.parametrize("offset", [0, 1, 2, 3, 4, 5, 6]) + @pytest.mark.parametrize("size", [0, 1, 2, 3, 4, 5, 6]) + def test_should_return_slice(self, cairo_run, offset, size): + arr = [0, 1, 2, 3, 4] + output = cairo_run("test__slice", arr=arr, offset=offset, size=size) + assert (arr + (offset + size) * [0])[offset : offset + size] == output + + class TestContains: + @pytest.mark.parametrize( + "arr, value, expected", + [ + ([0, 1, 2, 3, 4], 1, True), + ([0, 1, 2, 3], 5, False), + ([0, 1, 19], 19, True), + ([0], 0, True), + ([], 1, False), + ], + ) + def test_should_return_if_contains(self, cairo_run, arr, value, expected): + output = cairo_run("test_contains", arr=arr, value=value) + assert expected == output[0] + + class TestPadEnd: + @pytest.mark.parametrize( + "arr, size, expected", + [ + ([0, 1, 2, 3, 4], 7, [0, 1, 2, 3, 4, 0, 0]), + ([0, 1, 2, 3], 5, [0, 1, 2, 3, 0]), + ([0], 1, [0]), + ([], 1, [0]), + ([0, 1, 2, 3], 4, [0, 1, 2, 3]), + ([0, 1, 2, 3], 1, [0, 1, 2, 3]), + ], + ) + def test_should_pad_end(self, cairo_run, arr, size, expected): + [output] = cairo_run("test_pad_end", arr=arr, size=size) + assert expected == output diff --git a/cairo/tests/src/utils/test_bytes.cairo b/cairo/tests/src/utils/test_bytes.cairo new file mode 100644 index 00000000..dbc93333 --- /dev/null +++ b/cairo/tests/src/utils/test_bytes.cairo @@ -0,0 +1,103 @@ +%builtins range_check + +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.uint256 import Uint256 + +from src.utils.bytes import ( + felt_to_ascii, + felt_to_bytes_little, + felt_to_bytes, + felt_to_bytes20, + uint256_to_bytes_little, + uint256_to_bytes, + uint256_to_bytes32, + bytes_to_bytes8_little_endian, +) + +func test__felt_to_ascii{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar n: felt; + %{ ids.n = program_input["n"] %} + + felt_to_ascii(output_ptr, n); + return (); +} + +func test__felt_to_bytes_little{range_check_ptr}() -> felt* { + alloc_locals; + tempvar n: felt; + %{ ids.n = program_input["n"] %} + + let (output) = alloc(); + felt_to_bytes_little(output, n); + return output; +} + +func test__felt_to_bytes{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar n: felt; + %{ ids.n = program_input["n"] %} + + felt_to_bytes(output_ptr, n); + return (); +} + +func test__felt_to_bytes20{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar n: felt; + %{ ids.n = program_input["n"] %} + + felt_to_bytes20(output_ptr, n); + return (); +} + +func test__uint256_to_bytes_little{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar n: Uint256; + %{ + ids.n.low = program_input["n"][0] + ids.n.high = program_input["n"][1] + %} + + uint256_to_bytes_little(output_ptr, n); + return (); +} + +func test__uint256_to_bytes{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar n: Uint256; + %{ + ids.n.low = program_input["n"][0] + ids.n.high = program_input["n"][1] + %} + + uint256_to_bytes(output_ptr, n); + return (); +} + +func test__uint256_to_bytes32{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + tempvar n: Uint256; + %{ + ids.n.low = program_input["n"][0] + ids.n.high = program_input["n"][1] + %} + + uint256_to_bytes32(output_ptr, n); + return (); +} + +func test__bytes_to_bytes8_little_endian{range_check_ptr}() -> felt* { + alloc_locals; + tempvar bytes_len: felt; + let (bytes) = alloc(); + %{ + ids.bytes_len = len(program_input["bytes"]) + segments.write_arg(ids.bytes, program_input["bytes"]) + %} + + let (bytes8) = alloc(); + bytes_to_bytes8_little_endian(bytes8, bytes_len, bytes); + + return bytes8; +} diff --git a/cairo/tests/src/utils/test_bytes.py b/cairo/tests/src/utils/test_bytes.py new file mode 100644 index 00000000..d3c4d7e8 --- /dev/null +++ b/cairo/tests/src/utils/test_bytes.py @@ -0,0 +1,124 @@ +import pytest +from hypothesis import given +from hypothesis.strategies import binary, integers +from src.utils.uint256 import int_to_uint256 +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME +from tests.utils.errors import cairo_error +from tests.utils.hints import patch_hint + + +class TestBytes: + class TestFeltToAscii: + @pytest.mark.parametrize("n", [0, 10, 1234, 0xFFFFFF]) + def test_should_return_ascii(self, cairo_run, n): + output = cairo_run("test__felt_to_ascii", n=n) + assert str(n) == bytes(output).decode() + + class TestFeltToBytesLittle: + @given(n=integers(min_value=0, max_value=2**248 - 1)) + def test_should_return_bytes(self, cairo_run, n): + output = cairo_run("test__felt_to_bytes_little", n=n) + expected = ( + int.to_bytes(n, length=(n.bit_length() + 7) // 8, byteorder="little") + if n > 0 + else b"\x00" + ) + assert expected == bytes(output) + + @given(n=integers(min_value=2**248, max_value=DEFAULT_PRIME - 1)) + def test_should_raise_when_value_sup_31_bytes(self, cairo_run, n): + with cairo_error(message="felt_to_bytes_little: value >= 2**248"): + cairo_run("test__felt_to_bytes_little", n=n) + + # This test checks the function fails if the % base is removed from the hint + # All values up to 256 will have the same decomposition if the it is removed + @given(n=integers(min_value=256, max_value=2**248 - 1)) + def test_should_raise_when_byte_value_not_modulo_base( + self, cairo_program, cairo_run, n + ): + with ( + patch_hint( + cairo_program, + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base\nassert res < ids.bound, f'split_int(): Limb {res} is out of range.'", + "memory[ids.output] = (int(ids.value) % PRIME)\n", + ), + cairo_error(message="felt_to_bytes_little: byte value is too big"), + ): + cairo_run("test__felt_to_bytes_little", n=n) + + # This test checks the function fails if the first bytes is replaced by 0 + # All values that have 0 as first bytes will not raise an error + # The value 0 is also excluded as it is treated as a special case in the function + @given( + n=integers(min_value=1, max_value=2**248 - 1).filter( + lambda x: int.to_bytes( + x, length=(x.bit_length() + 7) // 8, byteorder="little" + )[0] + != 0 + ) + ) + def test_should_raise_when_bytes_len_is_not_minimal( + self, cairo_program, cairo_run, n + ): + with ( + patch_hint( + cairo_program, + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base\nassert res < ids.bound, f'split_int(): Limb {res} is out of range.'", + f"if ids.value == {n} and ids.bytes_len == 0:\n memory[ids.output] = 0\nelse:\n memory[ids.output] = (int(ids.value) % PRIME) % ids.base", + ), + cairo_error(message="bytes_len is not the minimal possible"), + ): + cairo_run("test__felt_to_bytes_little", n=n) + + class TestFeltToBytes: + @given(n=integers(min_value=0, max_value=2**248 - 1)) + def test_should_return_bytes(self, cairo_run, n): + output = cairo_run("test__felt_to_bytes", n=n) + res = bytes(output) + assert bytes.fromhex(f"{n:x}".rjust(len(res) * 2, "0")) == res + + class TestFeltToBytes20: + @pytest.mark.parametrize( + "n", [0, 10, 1234, 0xFFFFFF, 2**128, DEFAULT_PRIME - 1] + ) + def test_should_return_bytes20(self, cairo_run, n): + output = cairo_run("test__felt_to_bytes20", n=n) + assert f"{n:064x}"[-40:] == bytes(output).hex() + + class TestUint256ToBytesLittle: + @pytest.mark.parametrize( + "n", [0, 10, 1234, 0xFFFFFF, 2**128, DEFAULT_PRIME - 1, 2**256 - 1] + ) + def test_should_return_bytes(self, cairo_run, n): + output = cairo_run("test__uint256_to_bytes_little", n=int_to_uint256(n)) + res = bytes(output) + assert bytes.fromhex(f"{n:x}".rjust(len(res) * 2, "0"))[::-1] == res + + class TestUint256ToBytes: + @pytest.mark.parametrize( + "n", [0, 10, 1234, 0xFFFFFF, 2**128, DEFAULT_PRIME - 1, 2**256 - 1] + ) + def test_should_return_bytes(self, cairo_run, n): + output = cairo_run("test__uint256_to_bytes", n=int_to_uint256(n)) + res = bytes(output) + assert bytes.fromhex(f"{n:x}".rjust(len(res) * 2, "0")) == res + + class TestUint256ToBytes32: + @pytest.mark.parametrize( + "n", [0, 10, 1234, 0xFFFFFF, 2**128, DEFAULT_PRIME - 1, 2**256 - 1] + ) + def test_should_return_bytes(self, cairo_run, n): + output = cairo_run("test__uint256_to_bytes32", n=int_to_uint256(n)) + assert bytes.fromhex(f"{n:064x}") == bytes(output) + + class TestBytesToBytes8LittleEndian: + + @given(data=binary(max_size=1000)) + def test_should_return_bytes8(self, cairo_run, data): + bytes8_little_endian = [ + int.from_bytes(bytes(data[i : i + 8]), "little") + for i in range(0, len(data), 8) + ] + output = cairo_run("test__bytes_to_bytes8_little_endian", bytes=data) + + assert bytes8_little_endian == output diff --git a/cairo/tests/src/utils/test_dict.cairo b/cairo/tests/src/utils/test_dict.cairo new file mode 100644 index 00000000..f0ff5338 --- /dev/null +++ b/cairo/tests/src/utils/test_dict.cairo @@ -0,0 +1,120 @@ +%builtins range_check + +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.default_dict import default_dict_new, default_dict_finalize +from starkware.cairo.common.dict import dict_write, dict_read +from starkware.cairo.common.dict_access import DictAccess +from starkware.cairo.common.uint256 import Uint256 + +from src.utils.dict import dict_keys, default_dict_copy, dict_values + +func test__dict_keys__should_return_keys{range_check_ptr}() { + alloc_locals; + let (local dict_start) = default_dict_new(0); + let dict_ptr = dict_start; + + with dict_ptr { + dict_write(0xa, 2); + dict_write(0xb, 3); + dict_write(0xb, 4); + dict_read(0xb); + dict_write(0xc, 5); + } + + let (keys_len, keys) = dict_keys(dict_start, dict_ptr); + + assert keys_len = 5; + assert [keys + 0] = 0xa; + assert [keys + 1] = 0xb; + assert [keys + 2] = 0xb; + assert [keys + 3] = 0xb; + assert [keys + 4] = 0xc; + + let (squashed_start, squashed_end) = default_dict_finalize(dict_start, dict_ptr, 0); + + let (keys_len, keys) = dict_keys(squashed_start, squashed_end); + + assert keys_len = 3; + assert [keys + 0] = 0xa; + assert [keys + 1] = 0xb; + assert [keys + 2] = 0xc; + + return (); +} + +func test__default_dict_copy__should_return_copied_dict{range_check_ptr}() { + let default_value = 0xdead; + let (dict_ptr_start) = default_dict_new(default_value); + let dict_ptr = dict_ptr_start; + let key = 0x7e1; + with dict_ptr { + let (value) = dict_read(key); + assert value = default_value; + dict_write(key, 0xff); + let (value) = dict_read(key); + assert value = 0xff; + dict_write(key + 1, 0xff + 1); + dict_write(key + 2, 0xff + 2); + dict_write(key + 3, 0xff + 3); + dict_write(key + 4, 0xff + 4); + } + let (new_start, new_ptr) = default_dict_copy(dict_ptr_start, dict_ptr); + + assert new_ptr - new_start = DictAccess.SIZE * 5; + + let dict_ptr = new_ptr; + with dict_ptr { + let (value) = dict_read(key); + assert value = 0xff; + let (value) = dict_read(key + 1); + assert value = 0xff + 1; + let (value) = dict_read(key + 2); + assert value = 0xff + 2; + let (value) = dict_read(key + 3); + assert value = 0xff + 3; + let (value) = dict_read(key + 4); + assert value = 0xff + 4; + let (value) = dict_read(key + 10); + assert value = default_value; + } + + return (); +} + +func test__dict_values__should_return_values{range_check_ptr}() { + alloc_locals; + let (local dict_start) = default_dict_new(0); + tempvar value_a = new Uint256(2, 0); + tempvar value_tmp = new Uint256(3, 0); + tempvar value_b = new Uint256(4, 0); + tempvar value_c = new Uint256(5, 0); + let dict_ptr = dict_start; + + with dict_ptr { + dict_write(0xa, cast(value_a, felt)); + dict_write(0xb, cast(value_tmp, felt)); + dict_write(0xb, cast(value_b, felt)); + dict_read(0xb); + dict_write(0xc, cast(value_c, felt)); + } + + let (values_len, values) = dict_values(dict_start, dict_ptr); + + assert values_len = 5; + assert values[0] = value_a[0]; + assert values[1] = value_tmp[0]; + assert values[2] = value_b[0]; + assert values[3] = value_b[0]; + assert values[4] = value_c[0]; + + let (squashed_start, squashed_end) = default_dict_finalize(dict_start, dict_ptr, 0); + + let (values_len, values) = dict_values(squashed_start, squashed_end); + + assert values_len = 3; + assert values[0] = value_a[0]; + assert values[1] = value_b[0]; + assert values[2] = value_c[0]; + + return (); +} diff --git a/cairo/tests/src/utils/test_dict.py b/cairo/tests/src/utils/test_dict.py new file mode 100644 index 00000000..c5872cf3 --- /dev/null +++ b/cairo/tests/src/utils/test_dict.py @@ -0,0 +1,13 @@ +import pytest + + +@pytest.mark.parametrize( + "test_case", + [ + "test__dict_keys__should_return_keys", + "test__dict_values__should_return_values", + "test__default_dict_copy__should_return_copied_dict", + ], +) +def test_dict(cairo_run, test_case): + cairo_run(test_case) diff --git a/cairo/tests/src/utils/test_eth_transaction.cairo b/cairo/tests/src/utils/test_eth_transaction.cairo new file mode 100644 index 00000000..e6ab4324 --- /dev/null +++ b/cairo/tests/src/utils/test_eth_transaction.cairo @@ -0,0 +1,65 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.memcpy import memcpy + +from src.model import model +from src.utils.eth_transaction import EthTransaction +from src.utils.rlp import RLP + +func test__decode{bitwise_ptr: BitwiseBuiltin*, range_check_ptr}() -> model.EthTransaction* { + alloc_locals; + // Given + tempvar data_len: felt; + let (data) = alloc(); + %{ + ids.data_len = len(program_input["data"]) + segments.write_arg(ids.data, program_input["data"]) + %} + + let tx = EthTransaction.decode(data_len, data); + return tx; +} + +func test__parse_access_list{range_check_ptr}(output_ptr: felt*) { + alloc_locals; + // Given + tempvar data_len: felt; + let (data) = alloc(); + %{ + ids.data_len = len(program_input["data"]) + segments.write_arg(ids.data, program_input["data"]) + %} + + // Decode the RLP-encoded access list to get the data in the cairo format + let (items: RLP.Item*) = alloc(); + RLP.decode(items, data_len, data); + + // first level RLP decoding is a list of items. In our case the only item we decoded was the access list. + // the access list is a list of tuples (address, list(keys)), hence first level RLP decoding + // is a single item of type list. + let (local access_list: felt*) = alloc(); + // When + let access_list_len = EthTransaction.parse_access_list( + access_list, items.data_len, cast(items.data, RLP.Item*) + ); + + memcpy(output_ptr, access_list, access_list_len); + return (); +} + +func test__get_tx_type{range_check_ptr}() -> felt { + alloc_locals; + // Given + tempvar data_len: felt; + let (data) = alloc(); + %{ + ids.data_len = program_input.get("data_len", len(program_input["data"])) + segments.write_arg(ids.data, program_input["data"]) + %} + + // When + let tx_type = EthTransaction.get_tx_type(data_len, data); + + return tx_type; +} diff --git a/cairo/tests/src/utils/test_eth_transaction.py b/cairo/tests/src/utils/test_eth_transaction.py new file mode 100644 index 00000000..b4a05a54 --- /dev/null +++ b/cairo/tests/src/utils/test_eth_transaction.py @@ -0,0 +1,148 @@ +import pytest +from eth_account._utils.transaction_utils import transaction_rpc_to_rlp_structure +from eth_account._utils.validation import LEGACY_TRANSACTION_VALID_VALUES +from eth_account.typed_transactions.access_list_transaction import AccessListTransaction +from eth_account.typed_transactions.dynamic_fee_transaction import DynamicFeeTransaction +from hypothesis import given +from hypothesis import strategies as st +from rlp import encode +from tests.utils.constants import INVALID_TRANSACTIONS, TRANSACTIONS +from tests.utils.errors import cairo_error +from tests.utils.helpers import flatten_tx_access_list, rlp_encode_signed_data + + +class TestEthTransaction: + + class TestDecodeTransaction: + + def test_should_raise_with_list_items(self, cairo_run): + transaction = { + "nonce": 0, + "gasPrice": 234567897654321, + "gas": 2_000_000, + "to": "0xF0109fC8DF283027b6285cc889F5aA624EaC1F55", + "value": ["000000000"], + "data": b"", + } + with cairo_error(): + cairo_run("test__decode", data=list(encode(list(transaction.values())))) + + @given(value=st.integers(min_value=2**248)) + @pytest.mark.parametrize("transaction", TRANSACTIONS) + @pytest.mark.parametrize( + "key", + [ + "nonce", + "gasPrice", + "gas", + "value", + "chainId", + "maxFeePerGas", + "maxPriorityFeePerGas", + ], + ) + def test_should_raise_with_params_overflow( + self, cairo_run, transaction, key, value + ): + # Not all transactions have all keys + if key not in transaction: + return + + # Value can be up to 32 bytes + if key == "value": + value *= 256 + + # Override the value + transaction = {**transaction, key: value} + + tx_type = transaction.pop("type", 0) + # Remove accessList from the transaction if it exists, not relevant for this test + if tx_type > 0: + transaction["accessList"] = [] + + # Encode the transaction + encoded_unsigned_tx = ( + b"" if tx_type == 0 else tx_type.to_bytes(1, "big") + ) + encode( + [ + transaction[key] + for key in [ + LEGACY_TRANSACTION_VALID_VALUES.keys(), + dict(AccessListTransaction.unsigned_transaction_fields).keys(), + dict(DynamicFeeTransaction.unsigned_transaction_fields).keys(), + ][tx_type] + ] + ) + + # Run the test + with cairo_error(): + cairo_run("test__decode", data=list(encoded_unsigned_tx)) + + @pytest.mark.parametrize("transaction", TRANSACTIONS) + def test_should_decode_all_transactions_types(self, cairo_run, transaction): + encoded_unsigned_tx = rlp_encode_signed_data(transaction) + decoded_tx = cairo_run("test__decode", data=list(encoded_unsigned_tx)) + + expected_data = ( + "0x" + transaction["data"].hex() + if isinstance(transaction["data"], bytes) + else transaction["data"] + ) + expected_access_list = flatten_tx_access_list( + transaction.get("accessList", []) + ) + expected_to = transaction["to"] or None + + assert transaction["nonce"] == decoded_tx["signer_nonce"] + assert ( + transaction.get("gasPrice", transaction.get("maxFeePerGas")) + == decoded_tx["max_fee_per_gas"] + ) + assert transaction["gas"] == decoded_tx["gas_limit"] + assert expected_to == decoded_tx["destination"] + assert transaction["value"] == int(decoded_tx["amount"], 16) + # pre-eip155 txs have an internal chain_id set to 0 in the decoded tx + assert transaction.get("chainId") == decoded_tx["chain_id"] + assert expected_data == decoded_tx["payload"] + assert expected_access_list == decoded_tx["access_list"] + + @pytest.mark.parametrize("transaction", INVALID_TRANSACTIONS) + def test_should_panic_on_unsupported_tx_types(self, cairo_run, transaction): + encoded_unsigned_tx = rlp_encode_signed_data(transaction) + with cairo_error("Kakarot: transaction type not supported"): + cairo_run( + "test__decode", + data=list(encoded_unsigned_tx), + ) + + class TestParseAccessList: + @pytest.mark.parametrize("transaction", TRANSACTIONS) + def test_should_parse_access_list(self, cairo_run, transaction): + rlp_structure_tx = transaction_rpc_to_rlp_structure(transaction) + sanitized_access_list = [ + ( + bytes.fromhex(address[2:]), + tuple( + bytes.fromhex(storage_key[2:]) for storage_key in storage_keys + ), + ) + for address, storage_keys in rlp_structure_tx.get("accessList", []) + ] + encoded_access_list = encode(sanitized_access_list) + + output = cairo_run( + "test__parse_access_list", data=list(encoded_access_list) + ) + expected_output = flatten_tx_access_list(transaction.get("accessList", [])) + assert output == expected_output + + class TestGetTxType: + @pytest.mark.parametrize("transaction", TRANSACTIONS) + def test_should_return_tx_type(self, cairo_run, transaction): + encoded_unsigned_tx = rlp_encode_signed_data(transaction) + tx_type = cairo_run("test__get_tx_type", data=list(encoded_unsigned_tx)) + assert tx_type == transaction.get("type", 0) + + def test_should_raise_when_data_len_is_zero(self, cairo_run): + with cairo_error("tx_data_len is zero"): + cairo_run("test__get_tx_type", data_len=0, data=[1, 2, 3]) diff --git a/cairo/tests/src/utils/test_rlp.cairo b/cairo/tests/src/utils/test_rlp.cairo new file mode 100644 index 00000000..4d0aab80 --- /dev/null +++ b/cairo/tests/src/utils/test_rlp.cairo @@ -0,0 +1,54 @@ +%builtins range_check + +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.memcpy import memcpy + +from src.utils.rlp import RLP + +func test__decode_raw{range_check_ptr}() -> RLP.Item* { + alloc_locals; + // Given + tempvar data_len: felt; + let (data) = alloc(); + %{ + ids.data_len = program_input.get("data_len", len(program_input["data"])) + segments.write_arg(ids.data, program_input["data"]) + %} + + // When + let (local items: RLP.Item*) = alloc(); + RLP.decode_raw(items, data_len, data); + + return items; +} + +func test__decode{range_check_ptr}() -> RLP.Item* { + alloc_locals; + // Given + tempvar data_len: felt; + let (data) = alloc(); + %{ + ids.data_len = len(program_input["data"]) + segments.write_arg(ids.data, program_input["data"]) + %} + + // When + let (local items: RLP.Item*) = alloc(); + RLP.decode(items, data_len, data); + + return items; +} + +func test__decode_type{range_check_ptr}() -> (felt, felt, felt) { + alloc_locals; + // Given + let (data) = alloc(); + %{ segments.write_arg(ids.data, program_input["data"]) %} + + // When + let (type, offset, len) = RLP.decode_type_unsafe(data); + + // Then + return (type, offset, len); +} diff --git a/cairo/tests/src/utils/test_rlp.py b/cairo/tests/src/utils/test_rlp.py new file mode 100644 index 00000000..c9a7e740 --- /dev/null +++ b/cairo/tests/src/utils/test_rlp.py @@ -0,0 +1,82 @@ +import pytest +from hypothesis import given +from hypothesis.strategies import binary, lists, recursive +from rlp import codec, decode, encode +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME +from tests.utils.constants import TRANSACTIONS +from tests.utils.errors import cairo_error +from tests.utils.helpers import rlp_encode_signed_data + + +class TestRLP: + class TestDecodeType: + @given(data=lists(binary()) | binary()) + def test_should_match_prefix_reference_implementation(self, cairo_run, data): + encoded_data = encode(data) + + [ + prefix, + rlp_type, + expected_len, + expected_offset, + ] = codec.consume_length_prefix(encoded_data, 0) + expected_type = 0 if rlp_type is bytes else 1 + + output = cairo_run("test__decode_type", data=list(encoded_data)) + + assert output == [expected_type, expected_offset, expected_len] + + class TestDecodeRaw: + def test_should_raise_when_parsed_len_greater_than_data(self, cairo_run): + with cairo_error("RLP data too short for declared length"): + cairo_run("test__decode_raw", data=[0xB8, 0x01]) + + @given(data=lists(binary(min_size=2), min_size=2) | binary(min_size=2)) + def test_should_raise_when_malicious_prover_fills_data(self, cairo_run, data): + with cairo_error("RLP data too short for declared length"): + cairo_run( + "test__decode_raw", + data_len=len(encode(data)) - 1, + data=list(encode(data)), + ) + + def test_should_raise_when_decoded_params_overflow(self, cairo_run): + size = bytes.fromhex(f"{DEFAULT_PRIME - 1:064x}") + data = [len(size) + 0xF7] + list(size) + with cairo_error("RLP data too short for declared length"): + cairo_run("test__decode_raw", data=data) + + class TestDecode: + @given(data=recursive(binary(), lists)) + def test_should_match_decode_reference_implementation(self, cairo_run, data): + encoded_data = encode(data) + + items = cairo_run("test__decode", data=list(encoded_data)) + assert items[0] == decode(encoded_data) + + @given( + data=recursive(binary(), lists), + extra_data=binary(min_size=1, max_size=255), + ) + def test_raise_when_data_contains_extra_bytes( + self, cairo_run, data, extra_data + ): + encoded_data = encode(data) + + with cairo_error( + f"RLP string ends with {len(extra_data)} superfluous bytes" + ): + cairo_run("test__decode", data=list(encoded_data + extra_data)) + + @pytest.mark.parametrize("transaction", TRANSACTIONS) + def test_should_decode_all_tx_types(self, cairo_run, transaction): + encoded_unsigned_tx = rlp_encode_signed_data(transaction) + if "type" in transaction: + # remove the type info from the encoded RLP + # create bytearray from bytes list and remove the first byte + rlp_encoding = bytes(encoded_unsigned_tx[1:]) + else: + rlp_encoding = encoded_unsigned_tx + + items = cairo_run("test__decode", data=list(rlp_encoding)) + assert items[0] == decode(rlp_encoding) diff --git a/cairo/tests/src/utils/test_uint256.cairo b/cairo/tests/src/utils/test_uint256.cairo new file mode 100644 index 00000000..a47f471a --- /dev/null +++ b/cairo/tests/src/utils/test_uint256.cairo @@ -0,0 +1,51 @@ +%builtins range_check + +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.alloc import alloc + +from src.utils.uint256 import uint256_to_uint160, uint256_add, uint256_sub + +func test__uint256_to_uint160{range_check_ptr}() { + // Given + let (x) = alloc(); + tempvar expected: felt; + %{ + segments.write_arg(ids.x, program_input["x"]) + ids.expected = program_input["expected"] + %} + + // When + let result = uint256_to_uint160([cast(x, Uint256*)]); + + // Then + assert result = expected; + + return (); +} + +func test__uint256_add{range_check_ptr}() -> (felt, felt, felt) { + alloc_locals; + let (a_ptr) = alloc(); + let (b_ptr) = alloc(); + %{ + segments.write_arg(ids.a_ptr, program_input["a"]) + segments.write_arg(ids.b_ptr, program_input["b"]) + %} + let (res, carry) = uint256_add([cast(a_ptr, Uint256*)], [cast(b_ptr, Uint256*)]); + + return (res.low, res.high, carry); +} + +func test__uint256_sub{range_check_ptr}() -> Uint256 { + alloc_locals; + let (a_ptr) = alloc(); + let (b_ptr) = alloc(); + %{ + segments.write_arg(ids.a_ptr, program_input["a"]) + segments.write_arg(ids.b_ptr, program_input["b"]) + %} + let (res) = uint256_sub([cast(a_ptr, Uint256*)], [cast(b_ptr, Uint256*)]); + + return res; +} diff --git a/cairo/tests/src/utils/test_uint256.py b/cairo/tests/src/utils/test_uint256.py new file mode 100644 index 00000000..2bf485a1 --- /dev/null +++ b/cairo/tests/src/utils/test_uint256.py @@ -0,0 +1,38 @@ +import pytest +from hypothesis import given, settings +from hypothesis.strategies import integers +from src.utils.uint256 import int_to_uint256, uint256_to_int + + +class TestUint256: + class TestUint256ToUint160: + @pytest.mark.parametrize("n", [0, 2**128, 2**160 - 1, 2**160, 2**256]) + def test_should_cast_value(self, cairo_run, n): + cairo_run( + "test__uint256_to_uint160", x=int_to_uint256(n), expected=n % 2**160 + ) + + class TestUint256Add: + @given( + a=integers(min_value=0, max_value=2**256 - 1), + b=integers(min_value=0, max_value=2**256 - 1), + ) + @settings(max_examples=50) + def test_add(self, cairo_run, a, b): + low, high, carry = cairo_run( + "test__uint256_add", a=int_to_uint256(a), b=int_to_uint256(b) + ) + assert uint256_to_int(low, high) == (a + b) % 2**256 + assert carry == (a + b) // 2**256 + + class TestUint256Sub: + @given( + a=integers(min_value=0, max_value=2**256 - 1), + b=integers(min_value=0, max_value=2**256 - 1), + ) + @settings(max_examples=50) + def test_sub(self, cairo_run, a, b): + res = cairo_run( + "test__uint256_sub", a=int_to_uint256(a), b=int_to_uint256(b) + ) + assert int(res, 16) == (a - b) % 2**256 diff --git a/cairo/tests/src/utils/test_utils.cairo b/cairo/tests/src/utils/test_utils.cairo new file mode 100644 index 00000000..ef0f0ee3 --- /dev/null +++ b/cairo/tests/src/utils/test_utils.cairo @@ -0,0 +1,231 @@ +%builtins range_check + +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.uint256 import Uint256, assert_uint256_eq +from starkware.cairo.common.memset import memset +from starkware.cairo.common.memcpy import memcpy +from starkware.cairo.common.default_dict import default_dict_new + +from src.utils.utils import Helpers +from src.utils.dict import dict_keys +from src.constants import Constants + +func test__bytes_to_uint256{range_check_ptr}() -> Uint256 { + alloc_locals; + + tempvar word_len; + let (word) = alloc(); + %{ + ids.word_len = len(program_input["word"]) + segments.write_arg(ids.word, program_input["word"]) + %} + + let res = Helpers.bytes_to_uint256(word_len, word); + + return res; +} + +func test__bytes_to_bytes4_array{range_check_ptr}() { + alloc_locals; + // Given + let (data) = alloc(); + let (expected) = alloc(); + %{ + segments.write_arg(ids.data, program_input["data"]) + segments.write_arg(ids.expected, program_input["expected"]) + %} + + // When + let (tmp: felt*) = alloc(); + let (_, result: felt*) = Helpers.bytes_to_bytes4_array(12, data, 0, tmp); + + // Then + assert expected[0] = result[0]; + assert expected[1] = result[1]; + assert expected[2] = result[2]; + + return (); +} + +func test__bytes4_array_to_bytes{range_check_ptr}() { + alloc_locals; + // Given + let (data) = alloc(); + let (expected) = alloc(); + %{ + segments.write_arg(ids.data, program_input["data"]) + segments.write_arg(ids.expected, program_input["expected"]) + %} + + // When + let (tmp) = alloc(); + let (_, result) = Helpers.bytes4_array_to_bytes(3, data, 0, tmp); + + // Then + assert result[0] = expected[0]; + assert result[1] = expected[1]; + assert result[2] = expected[2]; + assert result[3] = expected[3]; + assert result[4] = expected[4]; + assert result[5] = expected[5]; + assert result[6] = expected[6]; + assert result[7] = expected[7]; + assert result[8] = expected[8]; + assert result[9] = expected[9]; + assert result[10] = expected[10]; + assert result[11] = expected[11]; + + return (); +} + +func test__bytes_used_128{range_check_ptr}(output_ptr: felt*) { + tempvar word; + %{ ids.word = program_input["word"] %} + + // When + let bytes_used = Helpers.bytes_used_128(word); + + // Then + assert [output_ptr] = bytes_used; + return (); +} + +func test__try_parse_destination_from_bytes{range_check_ptr}(output_ptr: felt*) { + let (bytes) = alloc(); + tempvar bytes_len; + %{ + segments.write_arg(ids.bytes, program_input["bytes"]) + ids.bytes_len = len(program_input["bytes"]) + %} + + // When + let maybe_address = Helpers.try_parse_destination_from_bytes(bytes_len, bytes); + + // Then + assert [output_ptr] = maybe_address.is_some; + assert [output_ptr + 1] = maybe_address.value; + + return (); +} + +func test__initialize_jumpdests{pedersen_ptr: HashBuiltin*, range_check_ptr}(output_ptr: felt*) { + alloc_locals; + + tempvar bytecode_len; + let (bytecode) = alloc(); + + %{ + ids.bytecode_len = len(program_input["bytecode"]) + segments.write_arg(ids.bytecode, program_input["bytecode"]) + %} + + let (valid_jumpdests_start, valid_jumpdests) = Helpers.initialize_jumpdests( + bytecode_len, bytecode + ); + let (keys_len, keys) = dict_keys(valid_jumpdests_start, valid_jumpdests); + memcpy(output_ptr, keys, keys_len); + + return (); +} + +func test__load_256_bits_array{range_check_ptr}() -> (felt, felt*) { + alloc_locals; + + // Given + let (data) = alloc(); + local data_len: felt; + %{ + segments.write_arg(ids.data, program_input["data"]) + ids.data_len = len(program_input["data"]) + %} + + // When + let (result_len, result) = Helpers.load_256_bits_array(data_len, data); + + // Then + return (result_len, result); +} + +func test__bytes4_to_felt{range_check_ptr}() -> felt { + alloc_locals; + + // Given + let (data) = alloc(); + %{ segments.write_arg(ids.data, program_input["data"]) %} + + // When + let result = Helpers.bytes4_to_felt(data); + + // Then + return result; +} + +func test__felt_array_to_bytes32_array{range_check_ptr}() -> felt* { + alloc_locals; + + let (data) = alloc(); + local data_len: felt; + %{ + segments.write_arg(ids.data, program_input["data"]) + ids.data_len = len(program_input["data"]) + %} + + let (output) = alloc(); + Helpers.felt_array_to_bytes32_array(data_len, data, output); + + return output; +} + +func test__load_packed_bytes{range_check_ptr}() -> felt* { + alloc_locals; + + let (data) = alloc(); + local data_len: felt; + %{ + segments.write_arg(ids.data, program_input["data"]) + ids.data_len = len(program_input["data"]) + %} + + let bytes_len = [data]; + let (output) = Helpers.load_packed_bytes(data_len - 1, data + 1, bytes_len); + + return output; +} + +func test__split_word{range_check_ptr}() -> felt* { + alloc_locals; + local value: felt; + local len: felt; + %{ + ids.value = program_input["value"] + ids.len = program_input["length"] + %} + let (dst) = alloc(); + Helpers.split_word(value, len, dst); + return dst; +} + +func test__split_word_little{range_check_ptr}() -> felt* { + alloc_locals; + local value: felt; + local len: felt; + %{ + ids.value = program_input["value"] + ids.len = program_input["length"] + %} + let (dst) = alloc(); + Helpers.split_word_little(value, len, dst); + return dst; +} + +func test__bytes_to_felt() -> felt { + tempvar len; + let (ptr) = alloc(); + %{ + ids.len = len(program_input["data"]) + segments.write_arg(ids.ptr, program_input["data"]) + %} + let res = Helpers.bytes_to_felt(len, ptr); + return res; +} diff --git a/cairo/tests/src/utils/test_utils.py b/cairo/tests/src/utils/test_utils.py new file mode 100644 index 00000000..584e23a9 --- /dev/null +++ b/cairo/tests/src/utils/test_utils.py @@ -0,0 +1,236 @@ +import random +from math import ceil + +import pytest +from hypothesis import given, settings +from hypothesis import strategies as st +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME +from tests.utils.errors import cairo_error +from tests.utils.helpers import pack_calldata +from tests.utils.hints import patch_hint + + +@pytest.mark.parametrize( + "test_case,data,expected", + [ + ( + "test__bytes4_array_to_bytes", + [ + 0x68656C6C, + 0x6F20776F, + 0x726C6400, + ], + [ + 0x68, + 0x65, + 0x6C, + 0x6C, + 0x6F, + 0x20, + 0x77, + 0x6F, + 0x72, + 0x6C, + 0x64, + 0x00, + ], + ), + ( + "test__bytes_to_bytes4_array", + [ + 0x68, + 0x65, + 0x6C, + 0x6C, + 0x6F, + 0x20, + 0x77, + 0x6F, + 0x72, + 0x6C, + 0x64, + 0x00, + ], + [ + 0x68656C6C, + 0x6F20776F, + 0x726C6400, + ], + ), + ], +) +def test_utils(cairo_run, test_case, data, expected): + cairo_run(test_case, data=data, expected=expected) + + +@given(word=st.integers(min_value=0, max_value=2**256 - 1)) +@settings(max_examples=20) +def test_bytes_to_uint256(cairo_run, word): + output = cairo_run( + "test__bytes_to_uint256", + word=int.to_bytes(word, ceil(word.bit_length() / 8), byteorder="big"), + ) + assert int(output, 16) == word + + +@given(word=st.integers(min_value=0, max_value=2**128 - 1)) +def test_should_return_bytes_used_in_128_word(cairo_run, word): + bytes_length = (word.bit_length() + 7) // 8 + output = cairo_run( + "test__bytes_used_128", + word=word, + ) + assert bytes_length == output[0] + + +@pytest.mark.parametrize( + "bytes,expected", + [ + (b"", [0, 0]), # An empty field + ( + b"\x01" * 20, + [1, 0x0101010101010101010101010101010101010101], + ), # An address of 20 bytes + ], +) +def test_should_parse_destination_from_bytes(cairo_run, bytes, expected): + result = cairo_run("test__try_parse_destination_from_bytes", bytes=list(bytes)) + assert result == expected + + +@given(bytes_array=st.binary(min_size=1, max_size=32).filter(lambda x: len(x) != 20)) +def test_should_panic_incorrect_address_encoding(cairo_run, bytes_array): + with cairo_error(message=f"Bytes has length {len(bytes_array)}, expected 0 or 20"): + cairo_run("test__try_parse_destination_from_bytes", bytes=list(bytes_array)) + + +@pytest.mark.parametrize( + "data, expected", + [ + (b"", []), # An empty field + ( + bytes.fromhex( + "0800000000000000000000000000000000000000000000000000000000000000" + ), + [0x800000000000000000000000000000000000000000000000000000000000000], + ), # 251-bit word + # two 128-bit words + ( + bytes.fromhex("8000".zfill(64) + "7000".zfill(64)), + [0x8000, 0x7000], + ), + ], +) +def test_should_load_256_bits_array(cairo_run, data, expected): + result_len, result = cairo_run("test__load_256_bits_array", data=data) + assert result == expected + assert result_len == len(expected) + + +@pytest.mark.parametrize( + "data, expected", + [ + ([0xAB, 0xCD, 0xEF, 0x01], 0xABCDEF01), + ([0x00, 0x00, 0x05, 0x67], 0x567), + ], +) +def test_should_convert_bytes4_to_felt(cairo_run, data, expected): + output = cairo_run("test__bytes4_to_felt", data=data) + assert output == expected + + +@pytest.mark.parametrize( + "data, expected", + [ + ([0x8000, 0x7000], bytes.fromhex(f"{0x8000:064x}" + f"{0x7000:064x}")), + ([0x8000], bytes.fromhex(f"{0x8000:064x}")), + ( + [0x8000, 0x7000, 0x6000], + bytes.fromhex(f"{0x8000:064x}" + f"{0x7000:064x}" + f"{0x6000:064x}"), + ), + ], +) +def test_should_unpack_felt_array_to_bytes32_array(cairo_run, data, expected): + result = cairo_run("test__felt_array_to_bytes32_array", data=data) + assert bytes(result) == expected + + +class TestLoadPackedBytes: + def test_should_load_packed_bytes(self, cairo_run): + bytes = random.randbytes(100) + packed_bytes = pack_calldata(bytes) + output = cairo_run("test__load_packed_bytes", data=packed_bytes) + assert output == list(bytes) + + def test_should_raise_zellic_issue_1283_load_packed_bytes( + self, cairo_program, cairo_run + ): + bytes = random.randbytes(100) + packed_bytes = pack_calldata(bytes) + with ( + patch_hint( + cairo_program, + "memory[ids.output] = res = (int(ids.value) % PRIME) % ids.base\nassert res < ids.bound, f'split_int(): Limb {res} is out of range.'", + "memory[ids.output] = res = 0x12", + ), + cairo_error(message="Value is not empty"), + ): + cairo_run("test__load_packed_bytes", data=packed_bytes) + + +class TestSplitWord: + @given(value=st.integers(min_value=0, max_value=2**248 - 1)) + def test_should_split_word(self, cairo_run, value): + length = (value.bit_length() + 7) // 8 + output = cairo_run("test__split_word", value=value, length=length) + assert bytes(output) == ( + value.to_bytes(byteorder="big", length=length) if value != 0 else b"" + ) + + @given(value=st.integers(min_value=1, max_value=2**248 - 1)) + def test_should_raise_when_length_is_too_short_split_word(self, cairo_run, value): + length = (value.bit_length() + 7) // 8 + with cairo_error("value not empty"): + cairo_run("test__split_word", value=value, length=length - 1) + + @given( + value=st.integers(min_value=0, max_value=2**248 - 1), + length=st.integers(min_value=32), + ) + def test_should_raise_when_len_ge_32_split_word(self, cairo_run, value, length): + with cairo_error("len must be < 32"): + cairo_run("test__split_word", value=value, length=length) + + @given(value=st.integers(min_value=0, max_value=2**248 - 1)) + def test_should_split_word_little(self, cairo_run, value): + length = (value.bit_length() + 7) // 8 + output = cairo_run("test__split_word_little", value=value, length=length) + assert bytes(output) == ( + value.to_bytes(byteorder="little", length=length) if value != 0 else b"" + ) + + @given(value=st.integers(min_value=1, max_value=2**248 - 1)) + def test_should_raise_when_len_is_too_small_split_word_little( + self, cairo_run, value + ): + length = (value.bit_length() + 7) // 8 + with cairo_error("value not empty"): + cairo_run("test__split_word_little", value=value, length=length - 1) + + @given( + value=st.integers(min_value=0, max_value=2**248 - 1), + length=st.integers(min_value=32), + ) + def test_should_raise_when_len_ge_32_split_word_little( + self, cairo_run, value, length + ): + with cairo_error("len must be < 32"): + cairo_run("test__split_word_little", value=value, length=length) + + +class TestBytesToFelt: + + @given(data=st.binary(min_size=0, max_size=35)) + def test_should_convert_bytes_to_felt_with_overflow(self, cairo_run, data): + output = cairo_run("test__bytes_to_felt", data=list(data)) + assert output == int.from_bytes(data, byteorder="big") % DEFAULT_PRIME diff --git a/cairo/tests/utils/constants.py b/cairo/tests/utils/constants.py new file mode 100644 index 00000000..21a030fb --- /dev/null +++ b/cairo/tests/utils/constants.py @@ -0,0 +1,349 @@ +from enum import IntEnum + +import pytest + +# STACK +STACK_MAX_DEPTH = 1024 + +# GAS METERING +TRANSACTION_INTRINSIC_GAS_COST = 21_000 + +# PRECOMPILES +LAST_ETHEREUM_PRECOMPILE_ADDRESS = 0x0A +FIRST_ROLLUP_PRECOMPILE_ADDRESS = 0x100 +LAST_ROLLUP_PRECOMPILE_ADDRESS = 0x100 +FIRST_KAKAROT_PRECOMPILE_ADDRESS = 0x75001 +LAST_KAKAROT_PRECOMPILE_ADDRESS = 0x75002 + +CAIRO_PRECOMPILE_GAS = 10000 +CAIRO_MESSAGE_GAS = 5000 + +# Taken from eth_account.account.Account.sign_transaction docstring +# https://eth-account.readthedocs.io/en/stable/eth_account.html?highlight=sign_transaction#eth_account.account.Account.sign_transaction +CHAIN_ID = int.from_bytes(b"keth", "big") +TRANSACTIONS = [ + { + "to": "0xF0109fC8DF283027b6285cc889F5aA624EaC1F55", + "value": 1_000_000_000, + "gas": 2_000_000, + "gasPrice": 234567897654321, + "nonce": 0, + "chainId": CHAIN_ID, + "data": b"", + }, + { + "type": 1, + "gas": 100_000, + "gasPrice": 1_000_000_000, + "data": "0x616263646566", + "nonce": 34, + "to": "0x09616C3d61b3331fc4109a9E41a8BDB7d9776609", + "value": 0x5AF3107A4000, + "accessList": ( + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ( + "0x0100000000000000000000000000000000000000000000000000000000000000", + ), + }, + ), + "chainId": CHAIN_ID, + }, + # Access list with two addresses + { + "type": 1, + "gas": 100_000, + "gasPrice": 1_000_000_000, + "data": "0x616263646566", + "nonce": 34, + "to": "0x09616C3d61b3331fc4109a9E41a8BDB7d9776609", + "value": 0x5AF3107A4000, + "accessList": ( + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ( + "0x0100000000000000000000000000000000000000000000000000000000000000", + ), + }, + { + "address": "0x0000000000000000000000000000000000000002", + "storageKeys": ( + "0x0100000000000000000000000000000000000000000000000000000000000000", + "0x0200000000000000000000000000000000000000000000000000000000000000", + ), + }, + { + "address": "0x0000000000000000000000000000000000000003", + "storageKeys": [], + }, + ), + "chainId": CHAIN_ID, + }, + { + "type": 2, + "gas": 100_000, + "maxFeePerGas": 2_000_000_000, + "maxPriorityFeePerGas": 2_000_000_000, + "data": "0x616263646566", + "nonce": 34, + "to": "0x09616C3d61b3331fc4109a9E41a8BDB7d9776609", + "value": 0x5AF3107A4000, + "accessList": ( + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ( + "0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + ), + }, + ), + "chainId": CHAIN_ID, + }, + # eip1559 with storage keys in accesslist and 2 addresses, including one duplication + { + "type": 2, + "gas": 100_000, + "maxFeePerGas": 2_000_000_000, + "maxPriorityFeePerGas": 2_000_000_000, + "data": "0x616263646566", + "nonce": 34, + "to": "0x09616C3d61b3331fc4109a9E41a8BDB7d9776609", + "value": 0x5AF3107A4000, + "accessList": ( + { + "address": "0x0000000000000000000000000000000000000101", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + }, + { + "address": "0x0000000000000000000000000000000000000101", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000001" + ], + }, + ), + "chainId": CHAIN_ID, + }, + { + "type": 2, + "gas": 100_000, + "maxFeePerGas": 2_000_000_000, + "maxPriorityFeePerGas": 2_000_000_000, + "data": "0x616263646566", + "nonce": 34, + "to": "", + "value": 0x00, + "accessList": ( + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ( + "0x0100000000000000000000000000000000000000000000000000000000000000", + ), + }, + ), + "chainId": CHAIN_ID, + }, + # Deploy counter tx + { + "type": 2, + "value": 0, + "gas": 21000, + "maxFeePerGas": 10_000_000_002, + "maxPriorityFeePerGas": 10_000_000_000, + "chainId": CHAIN_ID, + "nonce": 4, + "data": "0x608060405234801561001057600080fd5b506000805561023c806100246000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806306661abd14610067578063371303c0146100825780637c507cbd1461008c578063b3bcfa8214610094578063d826f88f1461009c578063f0707ea9146100a5575b600080fd5b61007060005481565b60405190815260200160405180910390f35b61008a6100ad565b005b61008a6100c6565b61008a610106565b61008a60008055565b61008a610139565b60016000808282546100bf919061017c565b9091555050565b60008054116100f05760405162461bcd60e51b81526004016100e790610195565b60405180910390fd5b6000805490806100ff836101dc565b9190505550565b60008054116101275760405162461bcd60e51b81526004016100e790610195565b60016000808282546100bf91906101f3565b600080541161015a5760405162461bcd60e51b81526004016100e790610195565b60008054600019019055565b634e487b7160e01b600052601160045260246000fd5b8082018082111561018f5761018f610166565b92915050565b60208082526027908201527f636f756e742073686f756c64206265207374726963746c7920677265617465726040820152660207468616e20360cc1b606082015260800190565b6000816101eb576101eb610166565b506000190190565b8181038181111561018f5761018f61016656fea2646970667358221220d15685bf0e446bfa459abadf9c47cf4c3367c09c39dccb9b38f2106bb7ffca2a64736f6c63430008110033", + "to": b"", + }, + # Deploy UniswapV2Router02.sol + # + pytest.param( + { + "type": 2, + "value": 0, + "gas": 2_000_000, + "maxFeePerGas": 10_000_000_002, + "maxPriorityFeePerGas": 10_000_000_000, + "chainId": CHAIN_ID, + "nonce": 5, + "data": "0x60c060405234801561001057600080fd5b506040516200479d3803806200479d8339818101604052604081101561003557600080fd5b5080516020909101516001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c614618620001856000398061015f5280610ce45280610d1f5280610e16528061103452806113be528061152452806118eb52806119e55280611a9b5280611b695280611caf5280611d375280611f7c5280611ff752806120a652806121725280612207528061227b528061277952806129ec5280612a425280612a765280612aea5280612c8a5280612dcd5280612e55525080610ea45280610f7b52806110fa5280611133528061126e528061144c528061150252806116725280611bfc5280611d695280611ecc52806122ad528061250652806126fe5280612727528061275752806128c45280612a205280612d1d5280612e875280613718528061375b5280613a3e5280613bbd5280613fed528061409b528061411b52506146186000f3fe60806040526004361061014f5760003560e01c80638803dbee116100b6578063c45a01551161006f578063c45a015514610a10578063d06ca61f14610a25578063ded9382a14610ada578063e8e3370014610b4d578063f305d71914610bcd578063fb3bdb4114610c1357610188565b80638803dbee146107df578063ad5c464814610875578063ad615dec146108a6578063af2979eb146108dc578063b6f9de951461092f578063baa2abde146109b357610188565b80634a25d94a116101085780634a25d94a146104f05780635b0d5984146105865780635c11d795146105f9578063791ac9471461068f5780637ff36ab51461072557806385f8c259146107a957610188565b806302751cec1461018d578063054d50d4146101f957806318cbafe5146102415780631f00ca74146103275780632195995c146103dc57806338ed17391461045a57610188565b3661018857336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461018657fe5b005b600080fd5b34801561019957600080fd5b506101e0600480360360c08110156101b057600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a00135610c97565b6040805192835260208301919091528051918290030190f35b34801561020557600080fd5b5061022f6004803603606081101561021c57600080fd5b5080359060208101359060400135610db1565b60408051918252519081900360200190f35b34801561024d57600080fd5b506102d7600480360360a081101561026457600080fd5b813591602081013591810190606081016040820135600160201b81111561028a57600080fd5b82018360208201111561029c57600080fd5b803590602001918460208302840111600160201b831117156102bd57600080fd5b91935091506001600160a01b038135169060200135610dc6565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156103135781810151838201526020016102fb565b505050509050019250505060405180910390f35b34801561033357600080fd5b506102d76004803603604081101561034a57600080fd5b81359190810190604081016020820135600160201b81111561036b57600080fd5b82018360208201111561037d57600080fd5b803590602001918460208302840111600160201b8311171561039e57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506110f3945050505050565b3480156103e857600080fd5b506101e0600480360361016081101561040057600080fd5b506001600160a01b038135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff6101008201351690610120810135906101400135611129565b34801561046657600080fd5b506102d7600480360360a081101561047d57600080fd5b813591602081013591810190606081016040820135600160201b8111156104a357600080fd5b8201836020820111156104b557600080fd5b803590602001918460208302840111600160201b831117156104d657600080fd5b91935091506001600160a01b038135169060200135611223565b3480156104fc57600080fd5b506102d7600480360360a081101561051357600080fd5b813591602081013591810190606081016040820135600160201b81111561053957600080fd5b82018360208201111561054b57600080fd5b803590602001918460208302840111600160201b8311171561056c57600080fd5b91935091506001600160a01b03813516906020013561136e565b34801561059257600080fd5b5061022f60048036036101408110156105aa57600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e082013516906101008101359061012001356114fa565b34801561060557600080fd5b50610186600480360360a081101561061c57600080fd5b813591602081013591810190606081016040820135600160201b81111561064257600080fd5b82018360208201111561065457600080fd5b803590602001918460208302840111600160201b8311171561067557600080fd5b91935091506001600160a01b038135169060200135611608565b34801561069b57600080fd5b50610186600480360360a08110156106b257600080fd5b813591602081013591810190606081016040820135600160201b8111156106d857600080fd5b8201836020820111156106ea57600080fd5b803590602001918460208302840111600160201b8311171561070b57600080fd5b91935091506001600160a01b03813516906020013561189d565b6102d76004803603608081101561073b57600080fd5b81359190810190604081016020820135600160201b81111561075c57600080fd5b82018360208201111561076e57600080fd5b803590602001918460208302840111600160201b8311171561078f57600080fd5b91935091506001600160a01b038135169060200135611b21565b3480156107b557600080fd5b5061022f600480360360608110156107cc57600080fd5b5080359060208101359060400135611e74565b3480156107eb57600080fd5b506102d7600480360360a081101561080257600080fd5b813591602081013591810190606081016040820135600160201b81111561082857600080fd5b82018360208201111561083a57600080fd5b803590602001918460208302840111600160201b8311171561085b57600080fd5b91935091506001600160a01b038135169060200135611e81565b34801561088157600080fd5b5061088a611f7a565b604080516001600160a01b039092168252519081900360200190f35b3480156108b257600080fd5b5061022f600480360360608110156108c957600080fd5b5080359060208101359060400135611f9e565b3480156108e857600080fd5b5061022f600480360360c08110156108ff57600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a00135611fab565b6101866004803603608081101561094557600080fd5b81359190810190604081016020820135600160201b81111561096657600080fd5b82018360208201111561097857600080fd5b803590602001918460208302840111600160201b8311171561099957600080fd5b91935091506001600160a01b03813516906020013561212c565b3480156109bf57600080fd5b506101e0600480360360e08110156109d657600080fd5b506001600160a01b038135811691602081013582169160408201359160608101359160808201359160a08101359091169060c001356124b8565b348015610a1c57600080fd5b5061088a6126fc565b348015610a3157600080fd5b506102d760048036036040811015610a4857600080fd5b81359190810190604081016020820135600160201b811115610a6957600080fd5b820183602082011115610a7b57600080fd5b803590602001918460208302840111600160201b83111715610a9c57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550612720945050505050565b348015610ae657600080fd5b506101e06004803603610140811015610afe57600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a08101359060c081013515159060ff60e0820135169061010081013590610120013561274d565b348015610b5957600080fd5b50610baf6004803603610100811015610b7157600080fd5b506001600160a01b038135811691602081013582169160408201359160608101359160808201359160a08101359160c0820135169060e00135612861565b60408051938452602084019290925282820152519081900360600190f35b610baf600480360360c0811015610be357600080fd5b506001600160a01b0381358116916020810135916040820135916060810135916080820135169060a0013561299d565b6102d760048036036080811015610c2957600080fd5b81359190810190604081016020820135600160201b811115610c4a57600080fd5b820183602082011115610c5c57600080fd5b803590602001918460208302840111600160201b83111715610c7d57600080fd5b91935091506001600160a01b038135169060200135612c42565b6000808242811015610cde576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b610d0d897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a6124b8565b9093509150610d1d898685612fc4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610d8357600080fd5b505af1158015610d97573d6000803e3d6000fd5b50505050610da58583613118565b50965096945050505050565b6000610dbe848484613210565b949350505050565b60608142811015610e0c576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001686866000198101818110610e4657fe5b905060200201356001600160a01b03166001600160a01b031614610e9f576040805162461bcd60e51b815260206004820152601d60248201526000805160206144fa833981519152604482015290519081900360640190fd5b610efd7f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061330092505050565b91508682600184510381518110610f1057fe5b60200260200101511015610f555760405162461bcd60e51b815260040180806020018281038252602b815260200180614540602b913960400191505060405180910390fd5b610ff386866000818110610f6557fe5b905060200201356001600160a01b031633610fd97f00000000000000000000000000000000000000000000000000000000000000008a8a6000818110610fa757fe5b905060200201356001600160a01b03168b8b6001818110610fc457fe5b905060200201356001600160a01b031661344c565b85600081518110610fe657fe5b602002602001015161350c565b61103282878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250613669915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d8360018551038151811061107157fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156110af57600080fd5b505af11580156110c3573d6000803e3d6000fd5b505050506110e884836001855103815181106110db57fe5b6020026020010151613118565b509695505050505050565b60606111207f000000000000000000000000000000000000000000000000000000000000000084846138af565b90505b92915050565b60008060006111597f00000000000000000000000000000000000000000000000000000000000000008f8f61344c565b9050600087611168578c61116c565b6000195b6040805163d505accf60e01b815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c4810188905290519192506001600160a01b0384169163d505accf9160e48082019260009290919082900301818387803b1580156111e257600080fd5b505af11580156111f6573d6000803e3d6000fd5b505050506112098f8f8f8f8f8f8f6124b8565b809450819550505050509b509b9950505050505050505050565b60608142811015611269576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b6112c77f00000000000000000000000000000000000000000000000000000000000000008988888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061330092505050565b915086826001845103815181106112da57fe5b6020026020010151101561131f5760405162461bcd60e51b815260040180806020018281038252602b815260200180614540602b913960400191505060405180910390fd5b61132f86866000818110610f6557fe5b6110e882878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250613669915050565b606081428110156113b4576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016868660001981018181106113ee57fe5b905060200201356001600160a01b03166001600160a01b031614611447576040805162461bcd60e51b815260206004820152601d60248201526000805160206144fa833981519152604482015290519081900360640190fd5b6114a57f0000000000000000000000000000000000000000000000000000000000000000898888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506138af92505050565b915086826000815181106114b557fe5b60200260200101511115610f555760405162461bcd60e51b81526004018080602001828103825260278152602001806144d36027913960400191505060405180910390fd5b6000806115487f00000000000000000000000000000000000000000000000000000000000000008d7f000000000000000000000000000000000000000000000000000000000000000061344c565b9050600086611557578b61155b565b6000195b6040805163d505accf60e01b815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c4810187905290519192506001600160a01b0384169163d505accf9160e48082019260009290919082900301818387803b1580156115d157600080fd5b505af11580156115e5573d6000803e3d6000fd5b505050506115f78d8d8d8d8d8d611fab565b9d9c50505050505050505050505050565b804281101561164c576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b6116c18585600081811061165c57fe5b905060200201356001600160a01b0316336116bb7f00000000000000000000000000000000000000000000000000000000000000008989600081811061169e57fe5b905060200201356001600160a01b03168a8a6001818110610fc457fe5b8a61350c565b6000858560001981018181106116d357fe5b905060200201356001600160a01b03166001600160a01b03166370a08231856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561173857600080fd5b505afa15801561174c573d6000803e3d6000fd5b505050506040513d602081101561176257600080fd5b505160408051602088810282810182019093528882529293506117a49290918991899182918501908490808284376000920191909152508892506139e7915050565b8661185682888860001981018181106117b957fe5b905060200201356001600160a01b03166001600160a01b03166370a08231886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561181e57600080fd5b505afa158015611832573d6000803e3d6000fd5b505050506040513d602081101561184857600080fd5b50519063ffffffff613cf216565b10156118935760405162461bcd60e51b815260040180806020018281038252602b815260200180614540602b913960400191505060405180910390fd5b5050505050505050565b80428110156118e1576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168585600019810181811061191b57fe5b905060200201356001600160a01b03166001600160a01b031614611974576040805162461bcd60e51b815260206004820152601d60248201526000805160206144fa833981519152604482015290519081900360640190fd5b6119848585600081811061165c57fe5b6119c28585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152503092506139e7915050565b604080516370a0823160e01b815230600482015290516000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b158015611a2c57600080fd5b505afa158015611a40573d6000803e3d6000fd5b505050506040513d6020811015611a5657600080fd5b5051905086811015611a995760405162461bcd60e51b815260040180806020018281038252602b815260200180614540602b913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611aff57600080fd5b505af1158015611b13573d6000803e3d6000fd5b505050506118938482613118565b60608142811015611b67576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686866000818110611b9e57fe5b905060200201356001600160a01b03166001600160a01b031614611bf7576040805162461bcd60e51b815260206004820152601d60248201526000805160206144fa833981519152604482015290519081900360640190fd5b611c557f00000000000000000000000000000000000000000000000000000000000000003488888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061330092505050565b91508682600184510381518110611c6857fe5b60200260200101511015611cad5760405162461bcd60e51b815260040180806020018281038252602b815260200180614540602b913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110611ce957fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d1c57600080fd5b505af1158015611d30573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb611d957f00000000000000000000000000000000000000000000000000000000000000008989600081811061169e57fe5b84600081518110611da257fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015611df957600080fd5b505af1158015611e0d573d6000803e3d6000fd5b505050506040513d6020811015611e2357600080fd5b5051611e2b57fe5b611e6a82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250613669915050565b5095945050505050565b6000610dbe848484613d42565b60608142811015611ec7576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b611f257f0000000000000000000000000000000000000000000000000000000000000000898888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506138af92505050565b91508682600081518110611f3557fe5b6020026020010151111561131f5760405162461bcd60e51b81526004018080602001828103825260278152602001806144d36027913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610dbe848484613e32565b60008142811015611ff1576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b612020887f000000000000000000000000000000000000000000000000000000000000000089898930896124b8565b604080516370a0823160e01b815230600482015290519194506120a492508a9187916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561207357600080fd5b505afa158015612087573d6000803e3d6000fd5b505050506040513d602081101561209d57600080fd5b5051612fc4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561210a57600080fd5b505af115801561211e573d6000803e3d6000fd5b505050506110e88483613118565b8042811015612170576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316858560008181106121a757fe5b905060200201356001600160a01b03166001600160a01b031614612200576040805162461bcd60e51b815260206004820152601d60248201526000805160206144fa833981519152604482015290519081900360640190fd5b60003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561226057600080fd5b505af1158015612274573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6122d97f00000000000000000000000000000000000000000000000000000000000000008989600081811061169e57fe5b836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561232957600080fd5b505af115801561233d573d6000803e3d6000fd5b505050506040513d602081101561235357600080fd5b505161235b57fe5b60008686600019810181811061236d57fe5b905060200201356001600160a01b03166001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156123d257600080fd5b505afa1580156123e6573d6000803e3d6000fd5b505050506040513d60208110156123fc57600080fd5b5051604080516020898102828101820190935289825292935061243e9290918a918a9182918501908490808284376000920191909152508992506139e7915050565b87611856828989600019810181811061245357fe5b905060200201356001600160a01b03166001600160a01b03166370a08231896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561181e57600080fd5b60008082428110156124ff576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b600061252c7f00000000000000000000000000000000000000000000000000000000000000008c8c61344c565b604080516323b872dd60e01b81523360048201526001600160a01b03831660248201819052604482018d9052915192935090916323b872dd916064808201926020929091908290030181600087803b15801561258757600080fd5b505af115801561259b573d6000803e3d6000fd5b505050506040513d60208110156125b157600080fd5b50506040805163226bf2d160e21b81526001600160a01b03888116600483015282516000938493928616926389afcb44926024808301939282900301818787803b1580156125fe57600080fd5b505af1158015612612573d6000803e3d6000fd5b505050506040513d604081101561262857600080fd5b508051602090910151909250905060006126428e8e613ede565b509050806001600160a01b03168e6001600160a01b031614612665578183612668565b82825b90975095508a8710156126ac5760405162461bcd60e51b815260040180806020018281038252602681526020018061451a6026913960400191505060405180910390fd5b898610156126eb5760405162461bcd60e51b81526004018080602001828103825260268152602001806144606026913960400191505060405180910390fd5b505050505097509795505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60606111207f00000000000000000000000000000000000000000000000000000000000000008484613300565b600080600061279d7f00000000000000000000000000000000000000000000000000000000000000008e7f000000000000000000000000000000000000000000000000000000000000000061344c565b90506000876127ac578c6127b0565b6000195b6040805163d505accf60e01b815233600482015230602482015260448101839052606481018c905260ff8a16608482015260a4810189905260c4810188905290519192506001600160a01b0384169163d505accf9160e48082019260009290919082900301818387803b15801561282657600080fd5b505af115801561283a573d6000803e3d6000fd5b5050505061284c8e8e8e8e8e8e610c97565b909f909e509c50505050505050505050505050565b600080600083428110156128aa576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b6128b88c8c8c8c8c8c613fbc565b909450925060006128ea7f00000000000000000000000000000000000000000000000000000000000000008e8e61344c565b90506128f88d33838861350c565b6129048c33838761350c565b806001600160a01b0316636a627842886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b15801561295c57600080fd5b505af1158015612970573d6000803e3d6000fd5b505050506040513d602081101561298657600080fd5b5051949d939c50939a509198505050505050505050565b600080600083428110156129e6576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b612a148a7f00000000000000000000000000000000000000000000000000000000000000008b348c8c613fbc565b90945092506000612a667f00000000000000000000000000000000000000000000000000000000000000008c7f000000000000000000000000000000000000000000000000000000000000000061344c565b9050612a748b33838861350c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015612acf57600080fd5b505af1158015612ae3573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb82866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612b6857600080fd5b505af1158015612b7c573d6000803e3d6000fd5b505050506040513d6020811015612b9257600080fd5b5051612b9a57fe5b806001600160a01b0316636a627842886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b158015612bf257600080fd5b505af1158015612c06573d6000803e3d6000fd5b505050506040513d6020811015612c1c57600080fd5b5051925034841015612c3457612c3433853403613118565b505096509650969350505050565b60608142811015612c88576040805162461bcd60e51b815260206004820152601860248201526000805160206145c3833981519152604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686866000818110612cbf57fe5b905060200201356001600160a01b03166001600160a01b031614612d18576040805162461bcd60e51b815260206004820152601d60248201526000805160206144fa833981519152604482015290519081900360640190fd5b612d767f0000000000000000000000000000000000000000000000000000000000000000888888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506138af92505050565b91503482600081518110612d8657fe5b60200260200101511115612dcb5760405162461bcd60e51b81526004018080602001828103825260278152602001806144d36027913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110612e0757fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015612e3a57600080fd5b505af1158015612e4e573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb612eb37f00000000000000000000000000000000000000000000000000000000000000008989600081811061169e57fe5b84600081518110612ec057fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612f1757600080fd5b505af1158015612f2b573d6000803e3d6000fd5b505050506040513d6020811015612f4157600080fd5b5051612f4957fe5b612f8882878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250613669915050565b81600081518110612f9557fe5b6020026020010151341115611e6a57611e6a3383600081518110612fb557fe5b60200260200101513403613118565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b602083106130415780518252601f199092019160209182019101613022565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146130a3576040519150601f19603f3d011682016040523d82523d6000602084013e6130a8565b606091505b50915091508180156130d65750805115806130d657508080602001905160208110156130d357600080fd5b50515b6131115760405162461bcd60e51b815260040180806020018281038252602d81526020018061456b602d913960400191505060405180910390fd5b5050505050565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b602083106131645780518252601f199092019160209182019101613145565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146131c6576040519150601f19603f3d011682016040523d82523d6000602084013e6131cb565b606091505b505090508061320b5760405162461bcd60e51b81526004018080602001828103825260348152602001806144076034913960400191505060405180910390fd5b505050565b60008084116132505760405162461bcd60e51b815260040180806020018281038252602b815260200180614598602b913960400191505060405180910390fd5b6000831180156132605750600082115b61329b5760405162461bcd60e51b81526004018080602001828103825260288152602001806144866028913960400191505060405180910390fd5b60006132af856103e563ffffffff61423016565b905060006132c3828563ffffffff61423016565b905060006132e9836132dd886103e863ffffffff61423016565b9063ffffffff61429316565b90508082816132f457fe5b04979650505050505050565b6060600282511015613359576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561337157600080fd5b5060405190808252806020026020018201604052801561339b578160200160208202803683370190505b50905082816000815181106133ac57fe5b60200260200101818152505060005b6001835103811015613444576000806133fe878685815181106133da57fe5b60200260200101518786600101815181106133f157fe5b60200260200101516142e2565b9150915061342084848151811061341157fe5b60200260200101518383613210565b84846001018151811061342f57fe5b602090810291909101015250506001016133bb565b509392505050565b600080600061345b8585613ede565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501206001600160f81b031960688401529a90941b9093166069840152607d8301989098527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251600094606094938a169392918291908083835b602083106135915780518252601f199092019160209182019101613572565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146135f3576040519150601f19603f3d011682016040523d82523d6000602084013e6135f8565b606091505b5091509150818015613626575080511580613626575080806020019051602081101561362357600080fd5b50515b6136615760405162461bcd60e51b81526004018080602001828103825260318152602001806143d66031913960400191505060405180910390fd5b505050505050565b60005b60018351038110156138a95760008084838151811061368757fe5b602002602001015185846001018151811061369e57fe5b60200260200101519150915060006136b68383613ede565b50905060008785600101815181106136ca57fe5b60200260200101519050600080836001600160a01b0316866001600160a01b0316146136f8578260006136fc565b6000835b91509150600060028a510388106137135788613754565b6137547f0000000000000000000000000000000000000000000000000000000000000000878c8b6002018151811061374757fe5b602002602001015161344c565b90506137817f0000000000000000000000000000000000000000000000000000000000000000888861344c565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f1916602001820160405280156137be576020820181803683370190505b506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b03166001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561382f578181015183820152602001613817565b50505050905090810190601f16801561385c5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561387e57600080fd5b505af1158015613892573d6000803e3d6000fd5b50506001909901985061366c975050505050505050565b50505050565b6060600282511015613908576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b815167ffffffffffffffff8111801561392057600080fd5b5060405190808252806020026020018201604052801561394a578160200160208202803683370190505b509050828160018351038151811061395e57fe5b60209081029190910101528151600019015b8015613444576000806139a08786600186038151811061398c57fe5b60200260200101518786815181106133f157fe5b915091506139c28484815181106139b357fe5b60200260200101518383613d42565b8460018503815181106139d157fe5b6020908102919091010152505060001901613970565b60005b600183510381101561320b57600080848381518110613a0557fe5b6020026020010151858460010181518110613a1c57fe5b6020026020010151915091506000613a348383613ede565b5090506000613a647f0000000000000000000000000000000000000000000000000000000000000000858561344c565b9050600080600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015613aa557600080fd5b505afa158015613ab9573d6000803e3d6000fd5b505050506040513d6060811015613acf57600080fd5b5080516020909101516001600160701b0391821693501690506000806001600160a01b038a811690891614613b05578284613b08565b83835b91509150613b66828b6001600160a01b03166370a082318a6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561181e57600080fd5b9550613b73868383613210565b945050505050600080856001600160a01b0316886001600160a01b031614613b9d57826000613ba1565b6000835b91509150600060028c51038a10613bb8578a613bec565b613bec7f0000000000000000000000000000000000000000000000000000000000000000898e8d6002018151811061374757fe5b604080516000808252602082019283905263022c0d9f60e01b835260248201878152604483018790526001600160a01b038086166064850152608060848501908152845160a48601819052969750908c169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015613c76578181015183820152602001613c5e565b50505050905090810190601f168015613ca35780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015613cc557600080fd5b505af1158015613cd9573d6000803e3d6000fd5b50506001909b019a506139ea9950505050505050505050565b80820382811115611123576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6000808411613d825760405162461bcd60e51b815260040180806020018281038252602c8152602001806143aa602c913960400191505060405180910390fd5b600083118015613d925750600082115b613dcd5760405162461bcd60e51b81526004018080602001828103825260288152602001806144866028913960400191505060405180910390fd5b6000613df16103e8613de5868863ffffffff61423016565b9063ffffffff61423016565b90506000613e0b6103e5613de5868963ffffffff613cf216565b9050613e286001828481613e1b57fe5b049063ffffffff61429316565b9695505050505050565b6000808411613e725760405162461bcd60e51b81526004018080602001828103825260258152602001806144ae6025913960400191505060405180910390fd5b600083118015613e825750600082115b613ebd5760405162461bcd60e51b81526004018080602001828103825260288152602001806144866028913960400191505060405180910390fd5b82613ece858463ffffffff61423016565b81613ed557fe5b04949350505050565b600080826001600160a01b0316846001600160a01b03161415613f325760405162461bcd60e51b815260040180806020018281038252602581526020018061443b6025913960400191505060405180910390fd5b826001600160a01b0316846001600160a01b031610613f52578284613f55565b83835b90925090506001600160a01b038216613fb5576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b6040805163e6a4390560e01b81526001600160a01b03888116600483015287811660248301529151600092839283927f00000000000000000000000000000000000000000000000000000000000000009092169163e6a4390591604480820192602092909190829003018186803b15801561403657600080fd5b505afa15801561404a573d6000803e3d6000fd5b505050506040513d602081101561406057600080fd5b50516001600160a01b0316141561411357604080516364e329cb60e11b81526001600160a01b038a81166004830152898116602483015291517f00000000000000000000000000000000000000000000000000000000000000009092169163c9c65396916044808201926020929091908290030181600087803b1580156140e657600080fd5b505af11580156140fa573d6000803e3d6000fd5b505050506040513d602081101561411057600080fd5b50505b6000806141417f00000000000000000000000000000000000000000000000000000000000000008b8b6142e2565b91509150816000148015614153575080155b1561416357879350869250614223565b6000614170898484613e32565b90508781116141c357858110156141b85760405162461bcd60e51b81526004018080602001828103825260268152602001806144606026913960400191505060405180910390fd5b889450925082614221565b60006141d0898486613e32565b9050898111156141dc57fe5b8781101561421b5760405162461bcd60e51b815260040180806020018281038252602681526020018061451a6026913960400191505060405180910390fd5b94508793505b505b5050965096945050505050565b600081158061424b5750508082028282828161424857fe5b04145b611123576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b80820182811015611123576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b60008060006142f18585613ede565b50905060008061430288888861344c565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561433a57600080fd5b505afa15801561434e573d6000803e3d6000fd5b505050506040513d606081101561436457600080fd5b5080516020909101516001600160701b0391821693501690506001600160a01b038781169084161461439757808261439a565b81815b9099909850965050505050505056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472616e7366657246726f6d206661696c65645472616e7366657248656c7065723a3a736166655472616e736665724554483a20455448207472616e73666572206661696c6564556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e69737761705632526f757465723a20494e53554646494349454e545f425f414d4f554e54556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f414d4f554e54556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e54556e69737761705632526f757465723a20494e56414c49445f50415448000000556e69737761705632526f757465723a20494e53554646494349454e545f415f414d4f554e54556e69737761705632526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a3a736166655472616e736665723a207472616e73666572206661696c6564556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54556e69737761705632526f757465723a20455850495245440000000000000000a2646970667358221220767788d45eb41ef38f5c034d893b6a335c72759e00cf784f9bee9729c9aef8cb64736f6c63430006060033", + "to": b"", + }, + marks=pytest.mark.slow, + ), +] + +INVALID_TRANSACTIONS = [ + { # invalid tx type (blob) + "type": 3, + "gas": 100_000, + "maxFeePerGas": 2_000_000_000, + "maxPriorityFeePerGas": 2_000_000_000, + "data": "0x616263646566", + "nonce": 34, + "to": "", + "value": 0x00, + "accessList": ( + { + "address": "0x0000000000000000000000000000000000000001", + "storageKeys": ( + "0x0100000000000000000000000000000000000000000000000000000000000000", + ), + }, + ), + "chainId": CHAIN_ID, + "blobVersionedHashes": [f"{12345:064x}"], + "maxFeePerBlobGas": int(1e9), + }, +] + + +class Opcodes(IntEnum): + STOP = 0x00 + ADD = 0x01 + MUL = 0x02 + SUB = 0x03 + DIV = 0x04 + SDIV = 0x05 + MOD = 0x06 + SMOD = 0x07 + ADDMOD = 0x08 + MULMOD = 0x09 + EXP = 0x0A + SIGNEXTEND = 0x0B + LT = 0x10 + GT = 0x11 + SLT = 0x12 + SGT = 0x13 + EQ = 0x14 + ISZERO = 0x15 + AND = 0x16 + OR = 0x17 + XOR = 0x18 + NOT = 0x19 + BYTE = 0x1A + SHL = 0x1B + SHR = 0x1C + SAR = 0x1D + KECCAK256 = 0x20 + ADDRESS = 0x30 + BALANCE = 0x31 + ORIGIN = 0x32 + CALLER = 0x33 + CALLVALUE = 0x34 + CALLDATALOAD = 0x35 + CALLDATASIZE = 0x36 + CALLDATACOPY = 0x37 + CODESIZE = 0x38 + CODECOPY = 0x39 + GASPRICE = 0x3A + EXTCODESIZE = 0x3B + EXTCODECOPY = 0x3C + RETURNDATASIZE = 0x3D + RETURNDATACOPY = 0x3E + EXTCODEHASH = 0x3F + BLOCKHASH = 0x40 + COINBASE = 0x41 + TIMESTAMP = 0x42 + NUMBER = 0x43 + PREVRANDAO = 0x44 + GASLIMIT = 0x45 + CHAINID = 0x46 + SELFBALANCE = 0x47 + BASEFEE = 0x48 + BLOBHASH = 0x49 + BLOBBASEFEE = 0x4A + POP = 0x50 + MLOAD = 0x51 + MSTORE = 0x52 + MSTORE8 = 0x53 + SLOAD = 0x54 + SSTORE = 0x55 + JUMP = 0x56 + JUMPI = 0x57 + PC = 0x58 + MSIZE = 0x59 + GAS = 0x5A + JUMPDEST = 0x5B + TLOAD = 0x5C + TSTORE = 0x5D + PUSH0 = 0x5F + PUSH1 = 0x60 + PUSH2 = 0x61 + PUSH3 = 0x62 + PUSH4 = 0x63 + PUSH5 = 0x64 + PUSH6 = 0x65 + PUSH7 = 0x66 + PUSH8 = 0x67 + PUSH9 = 0x68 + PUSH10 = 0x69 + PUSH11 = 0x6A + PUSH12 = 0x6B + PUSH13 = 0x6C + PUSH14 = 0x6D + PUSH15 = 0x6E + PUSH16 = 0x6F + PUSH17 = 0x70 + PUSH18 = 0x71 + PUSH19 = 0x72 + PUSH20 = 0x73 + PUSH21 = 0x74 + PUSH22 = 0x75 + PUSH23 = 0x76 + PUSH24 = 0x77 + PUSH25 = 0x78 + PUSH26 = 0x79 + PUSH27 = 0x7A + PUSH28 = 0x7B + PUSH29 = 0x7C + PUSH30 = 0x7D + PUSH31 = 0x7E + PUSH32 = 0x7F + DUP1 = 0x80 + DUP2 = 0x81 + DUP3 = 0x82 + DUP4 = 0x83 + DUP5 = 0x84 + DUP6 = 0x85 + DUP7 = 0x86 + DUP8 = 0x87 + DUP9 = 0x88 + DUP10 = 0x89 + DUP11 = 0x8A + DUP12 = 0x8B + DUP13 = 0x8C + DUP14 = 0x8D + DUP15 = 0x8E + DUP16 = 0x8F + SWAP1 = 0x90 + SWAP2 = 0x91 + SWAP3 = 0x92 + SWAP4 = 0x93 + SWAP5 = 0x94 + SWAP6 = 0x95 + SWAP7 = 0x96 + SWAP8 = 0x97 + SWAP9 = 0x98 + SWAP10 = 0x99 + SWAP11 = 0x9A + SWAP12 = 0x9B + SWAP13 = 0x9C + SWAP14 = 0x9D + SWAP15 = 0x9E + SWAP16 = 0x9F + LOG0 = 0xA0 + LOG1 = 0xA1 + LOG2 = 0xA2 + LOG3 = 0xA3 + LOG4 = 0xA4 + CREATE = 0xF0 + CALL = 0xF1 + CALLCODE = 0xF2 + RETURN = 0xF3 + DELEGATECALL = 0xF4 + CREATE2 = 0xF5 + STATICCALL = 0xFA + REVERT = 0xFD + INVALID = 0xFE + SELFDESTRUCT = 0xFF diff --git a/cairo/tests/utils/coverage.py b/cairo/tests/utils/coverage.py new file mode 100644 index 00000000..d93d8974 --- /dev/null +++ b/cairo/tests/utils/coverage.py @@ -0,0 +1,128 @@ +""" +Copied from cairo_coverage. +""" + +from collections import defaultdict +from dataclasses import dataclass +from typing import DefaultDict, List, Optional, Set + +from starkware.cairo.lang.compiler.instruction import Instruction +from starkware.cairo.lang.vm.vm_core import VirtualMachine + + +@dataclass +class CoverageFile: + name: str # Filename. + covered: Set[int] # Tested lines. + statements: Set[int] # Lines with code. + + def __post_init__(self): + if not self.statements: + return + self.missed = sorted(list(self.statements - self.covered)) + + +def report_runs(excluded_file: Optional[Set[str]] = None): + if excluded_file is None: + excluded_file = set() + report_dict = VmWithCoverage.covered # Get the infos of all the covered files. + statements = VmWithCoverage.statements # Get the lines of codes of each files. + files = sorted( + [ + CoverageFile( + statements=set(statements[file]), covered=set(coverage), name=file + ) + for file, coverage in report_dict.items() + if not any(excluded in file for excluded in excluded_file) and file + ], + key=lambda x: x.name, + ) + + reset() + return files + + +def reset(): + VmWithCoverage.covered.clear() + VmWithCoverage.statements.clear() + + +class VmWithCoverage(VirtualMachine): + covered: DefaultDict[str, List[int]] = defaultdict(list) + statements: DefaultDict[str, List[int]] = defaultdict(list) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.old_end_run = ( + super().end_run + ) # Save the old end run function to wrap it afterwards. + self.old_run_instruction = ( + super().run_instruction + ) # Save the old run instruction function to wrap it afterwards. + self.old_as_vm_exception = ( + super().as_vm_exception + ) # Save the old vm as exception function to wrap it afterwards. + self.touched_pcs: List[int] = [] + + def run_instruction(self, instruction: Instruction): + """Save the current pc and runs the instruction.""" + self.touched_pcs.append(self.run_context.pc.offset) + self.old_run_instruction(instruction=instruction) + + def end_run(self): + """In case the run doesn't fail creates report coverage.""" + self.old_end_run() + self.cover_file() + + def as_vm_exception( + self, + exc, + with_traceback: bool = True, + notes: Optional[List[str]] = None, + hint_index: Optional[int] = None, + ): + """In case the run fails creates report coverage.""" + self.cover_file() + return self.old_as_vm_exception(exc, with_traceback, notes, hint_index) + + def pc_to_line( + self, + pc, + statements: DefaultDict[str, list], + report_dict: DefaultDict[str, List[int]], + ) -> None: + """Convert the touched pcs to the line numbers of the original file and saves them.""" + should_update_report = ( + pc in self.touched_pcs + ) # If the pc is not touched by the test don't report it. + instruct = self.program.debug_info.instruction_locations[ + pc + ].inst # First instruction in the debug info. + file = instruct.input_file.filename # Current analyzed file. + while True: + if "autogen" not in file: # If file is auto generated discard it. + lines = list( + range( + instruct.start_line, + instruct.end_line + 1, + ) + ) # Get the lines touched. + if should_update_report: + report_dict[file].extend(lines) + statements[file].extend(lines) + if ( + instruct.parent_location is not None + ): # Continue until we have last parent location. + instruct = instruct.parent_location[0] + file = instruct.input_file.filename + else: + return + + def cover_file(self): + """Add the coverage report in the report dict and all the lines of code.""" + if self.program.debug_info is not None: + report_dict = self.__class__.covered + statements = self.__class__.statements + for pc in set(self.program.debug_info.instruction_locations.keys()): + self.pc_to_line(pc=pc, report_dict=report_dict, statements=statements) diff --git a/cairo/tests/utils/debug.cairo b/cairo/tests/utils/debug.cairo new file mode 100644 index 00000000..320ad48d --- /dev/null +++ b/cairo/tests/utils/debug.cairo @@ -0,0 +1,61 @@ +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.dict_access import DictAccess +from model import model + +namespace Debug { + func print_felt(x: felt) { + %{ print(ids.x) %} + return (); + } + + func print_uint256(val: Uint256) { + %{ + low = ids.val.low + high = ids.val.high + print(f"Uint256(low={low}, high={high}) = {2 ** 128 * high + low}") + %} + return (); + } + + func print_array(name: felt, arr_len: felt, arr: felt*) { + %{ + print(bytes.fromhex(f"{ids.name:062x}").decode().replace('\x00','')) + arr = [memory[ids.arr + i] for i in range(ids.arr_len)] + print(arr) + %} + return (); + } + + func print_dict(name: felt, dict_ptr: DictAccess*, pointer_size: felt) { + %{ + print(bytes.fromhex(f"{ids.name:062x}").decode().replace('\x00','')) + data = __dict_manager.get_dict(ids.dict_ptr) + print( + {k: v if isinstance(v, int) else [memory[v + i] for i in range(ids.pointer_size)] for k, v in data.items()} + ) + %} + return (); + } + + func print_message(message: model.Message*) { + print_array('calldata', message.calldata_len, message.calldata); + print_array('bytecode', message.bytecode_len, message.bytecode); + print_felt(message.env.gas_price); + print_felt(message.env.origin); + print_felt(message.address.evm); + print_felt(message.address.starknet); + print_felt(message.read_only); + print_felt(message.is_create); + return (); + } + + func print_execution_context(evm: model.EVM*) { + print_message(evm.message); + print_array('return_data', evm.return_data_len, evm.return_data); + print_felt(evm.program_counter); + print_felt(evm.stopped); + print_felt(evm.gas_left); + print_felt(evm.reverted); + return (); + } +} diff --git a/cairo/tests/utils/errors.py b/cairo/tests/utils/errors.py new file mode 100644 index 00000000..33b805b9 --- /dev/null +++ b/cairo/tests/utils/errors.py @@ -0,0 +1,18 @@ +import re +from contextlib import contextmanager + +import pytest + + +@contextmanager +def cairo_error(message=None): + try: + with pytest.raises(Exception) as e: + yield e + if message is None: + return + error = re.search(r"Error message: (.*)", str(e.value)) + error = error.group(1) if error else str(e.value) + assert message == error, f"Expected {message}, got {error}" + finally: + pass diff --git a/cairo/tests/utils/helpers.cairo b/cairo/tests/utils/helpers.cairo new file mode 100644 index 00000000..af40972b --- /dev/null +++ b/cairo/tests/utils/helpers.cairo @@ -0,0 +1,206 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.bool import TRUE, FALSE +from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin +from starkware.cairo.common.default_dict import default_dict_new +from starkware.cairo.common.dict import dict_write +from starkware.cairo.common.math import split_felt +from starkware.cairo.common.memset import memset +from starkware.cairo.common.uint256 import Uint256, uint256_eq, assert_uint256_eq +from starkware.cairo.common.dict_access import DictAccess + +from src.evm import EVM +from src.memory import Memory +from src.model import model +from src.stack import Stack +from src.utils.maths import unsigned_div_rem +from src.utils.utils import Helpers + +namespace TestHelpers { + func init_evm_at_address{pedersen_ptr: HashBuiltin*, range_check_ptr}( + bytecode_len: felt, + bytecode: felt*, + starknet_contract_address: felt, + evm_contract_address: felt, + calldata_len: felt, + calldata: felt*, + ) -> model.EVM* { + alloc_locals; + tempvar env = new model.Environment( + origin=0, + gas_price=0, + chain_id=0, + prev_randao=Uint256(0, 0), + block_number=0, + block_gas_limit=0, + block_timestamp=0, + coinbase=0, + base_fee=0, + ); + tempvar address = new model.Address( + starknet=starknet_contract_address, evm=evm_contract_address + ); + let (valid_jumpdests_start, valid_jumpdests) = Helpers.initialize_jumpdests( + bytecode_len=bytecode_len, bytecode=bytecode + ); + tempvar zero = new Uint256(0, 0); + local message: model.Message* = new model.Message( + bytecode=bytecode, + bytecode_len=bytecode_len, + valid_jumpdests_start=valid_jumpdests_start, + valid_jumpdests=valid_jumpdests, + calldata=calldata, + calldata_len=calldata_len, + value=zero, + caller=env.origin, + parent=cast(0, model.Parent*), + address=address, + code_address=address, + read_only=FALSE, + is_create=FALSE, + depth=0, + env=env, + cairo_precompile_called=FALSE, + ); + let evm: model.EVM* = EVM.init(message, 1000000); + return evm; + } + + func init_evm{pedersen_ptr: HashBuiltin*, range_check_ptr}() -> model.EVM* { + let (bytecode) = alloc(); + let (calldata) = alloc(); + return init_evm_at_address(0, bytecode, 0, 0, 0, calldata); + } + + func init_evm_with_bytecode{pedersen_ptr: HashBuiltin*, range_check_ptr}( + bytecode_len: felt, bytecode: felt* + ) -> model.EVM* { + let (calldata) = alloc(); + return init_evm_at_address(bytecode_len, bytecode, 0, 0, 0, calldata); + } + + func init_evm_with_calldata{pedersen_ptr: HashBuiltin*, range_check_ptr}( + bytecode_len: felt, bytecode: felt*, calldata_len: felt, calldata: felt* + ) -> model.EVM* { + return init_evm_at_address(bytecode_len, bytecode, 0, 0, calldata_len, calldata); + } + + func init_stack_with_values(stack_len: felt, stack: Uint256*) -> model.Stack* { + let stack_ = Stack.init(); + + tempvar stack_ = stack_; + tempvar stack_len = stack_len; + tempvar stack = stack; + + jmp cond; + + loop: + let stack_ = cast([ap - 3], model.Stack*); + let stack_len = [ap - 2]; + let stack = cast([ap - 1], Uint256*); + + Stack.push{stack=stack_}(stack + (stack_len - 1) * Uint256.SIZE); + + tempvar stack_len = stack_len - 1; + tempvar stack = stack; + + static_assert stack_ == [ap - 3]; + static_assert stack_len == [ap - 2]; + static_assert stack == [ap - 1]; + + cond: + let stack_len = [ap - 2]; + jmp loop if stack_len != 0; + + let stack_ = cast([ap - 3], model.Stack*); + + return stack_; + } + + func init_memory_with_values{range_check_ptr}( + serialized_memory_len: felt, serialized_memory: felt* + ) -> model.Memory* { + alloc_locals; + let memory = Memory.init(); + let (words_len, _) = unsigned_div_rem(serialized_memory_len + 31, 32); + tempvar memory = new model.Memory(memory.word_dict_start, memory.word_dict, words_len); + with memory { + Memory.store_n(serialized_memory_len, serialized_memory, 0); + } + return memory; + } + + func init_jumpdests_with_values(jumpdests_len: felt, jumpdests: felt*) -> ( + DictAccess*, DictAccess* + ) { + alloc_locals; + let (local valid_jumpdests_start) = default_dict_new(0); + let valid_jumpdests = valid_jumpdests_start; + + tempvar valid_jumpdests = valid_jumpdests; + tempvar jumpdests_len = jumpdests_len; + tempvar jumpdests = jumpdests; + + jmp cond; + + loop: + let valid_jumpdests = cast([ap - 3], DictAccess*); + let jumpdests_len = [ap - 2]; + let jumpdests = cast([ap - 1], felt*); + + dict_write{dict_ptr=valid_jumpdests}(jumpdests[jumpdests_len - 1], 1); + + tempvar jumpdests_len = jumpdests_len - 1; + tempvar jumpdests = jumpdests; + + static_assert valid_jumpdests == [ap - 3]; + static_assert jumpdests_len == [ap - 2]; + static_assert jumpdests == [ap - 1]; + + cond: + let jumpdests_len = [ap - 2]; + jmp loop if jumpdests_len != 0; + + let valid_jumpdests = cast([ap - 3], DictAccess*); + let valid_jumpdests_start = cast([fp], DictAccess*); + + return (valid_jumpdests_start, valid_jumpdests); + } + + func assert_array_equal(array_0_len: felt, array_0: felt*, array_1_len: felt, array_1: felt*) { + assert array_0_len = array_1_len; + if (array_0_len == 0) { + return (); + } + assert [array_0] = [array_1]; + return assert_array_equal(array_0_len - 1, array_0 + 1, array_1_len - 1, array_1 + 1); + } + + func assert_message_equal(evm_0: model.Message*, evm_1: model.Message*) { + assert evm_0.value = evm_1.value; + assert_array_equal(evm_0.bytecode_len, evm_0.bytecode, evm_1.bytecode_len, evm_1.bytecode); + assert_array_equal(evm_0.calldata_len, evm_0.calldata, evm_1.calldata_len, evm_1.calldata); + + assert evm_0.address.starknet = evm_1.address.starknet; + assert evm_0.gas_price = evm_1.gas_price; + assert evm_0.address.evm = evm_1.address.evm; + assert_execution_context_equal(evm_0.parent, evm_1.parent); + return (); + } + + func assert_execution_context_equal(evm_0: model.EVM*, evm_1: model.EVM*) { + assert evm_0.message.depth = evm_1.message.depth; + + assert_message_equal(evm_0.message, evm_1.message); + assert evm_0.program_counter = evm_1.program_counter; + assert evm_0.stopped = evm_1.stopped; + + assert_array_equal( + evm_0.return_data_len, evm_0.return_data, evm_1.return_data_len, evm_1.return_data + ); + + // TODO: Implement assert_dict_access_equal and finalize this helper once Stack and Memory are stabilized + // assert evm_0.stack = evm_1.stack; + // assert evm_0.memory = evm_1.memory; + return (); + } +} diff --git a/cairo/tests/utils/helpers.py b/cairo/tests/utils/helpers.py new file mode 100644 index 00000000..16bd369b --- /dev/null +++ b/cairo/tests/utils/helpers.py @@ -0,0 +1,167 @@ +import random +from collections import defaultdict +from textwrap import wrap +from typing import List, Tuple, Union + +import rlp +from eth_account._utils.transaction_utils import transaction_rpc_to_rlp_structure +from eth_account.typed_transactions import TypedTransaction +from eth_keys import keys +from eth_utils import decode_hex, keccak, to_checksum_address +from src.utils.uint256 import int_to_uint256 +from starkware.cairo.lang.vm.crypto import pedersen_hash + + +def rlp_encode_signed_data(tx: dict) -> bytes: + if "type" in tx: + typed_transaction = TypedTransaction.from_dict(tx) + + sanitized_transaction = transaction_rpc_to_rlp_structure( + typed_transaction.transaction.dictionary + ) + + # RPC-structured transaction to rlp-structured transaction + rlp_serializer = ( + typed_transaction.transaction.__class__._unsigned_transaction_serializer + ) + encoded_unsigned_tx = [ + typed_transaction.transaction_type, + *rlp.encode(rlp_serializer.from_dict(sanitized_transaction)), + ] + + return encoded_unsigned_tx + else: + legacy_tx = ( + [ + tx["nonce"], + tx["gasPrice"], + tx["gas"], + int(tx["to"], 16), + tx["value"], + tx["data"], + tx["chainId"], + 0, + 0, + ] + if "chainId" in tx + else [ + tx["nonce"], + tx["gasPrice"], + tx["gas"], + int(tx["to"], 16), + tx["value"], + tx["data"], + ] + ) + encoded_unsigned_tx = rlp.encode(legacy_tx) + + return encoded_unsigned_tx + + +def get_create_address(sender_address: Union[int, str], nonce: int) -> str: + """ + See [CREATE](https://www.evm.codes/#f0). + """ + return to_checksum_address( + keccak(rlp.encode([decode_hex(to_checksum_address(sender_address)), nonce]))[ + -20: + ] + ) + + +def get_create2_address( + sender_address: Union[int, str], salt: int, initialization_code: bytes +) -> str: + """ + See [CREATE2](https://www.evm.codes/#f5). + """ + return to_checksum_address( + keccak( + b"\xff" + + decode_hex(to_checksum_address(sender_address)) + + salt.to_bytes(32, "big") + + keccak(initialization_code) + )[-20:] + ) + + +def private_key_from_hex(hex_key: str): + return keys.PrivateKey(bytes.fromhex(hex_key)) + + +def generate_random_private_key(): + return keys.PrivateKey(int.to_bytes(random.getrandbits(256), 32, "big")) + + +def generate_random_evm_address(): + return generate_random_private_key().public_key.to_checksum_address() + + +def ec_sign( + digest: bytes, owner_private_key: keys.PrivateKey +) -> Tuple[int, bytes, bytes]: + signature = owner_private_key.sign_msg_hash(digest) + return ( + signature.v + 27, + int.to_bytes(signature.r, 32, "big"), + int.to_bytes(signature.s, 32, "big"), + ) + + +def pack_64_bits_little(input: List[int]): + return sum([x * 256**i for (i, x) in enumerate(input)]) + + +def flatten(data): + result = [] + + def _flatten(item): + if isinstance(item, list): + for sub_item in item: + _flatten(sub_item) + else: + result.extend(item) + + _flatten(data) + return result + + +def flatten_tx_access_list(access_list): + """ + Transform the access list from the transaction dict into a flattened list of + [address, storage_keys, ...]. + """ + result = [] + for item in access_list: + result.append(int(item["address"], 16)) + result.append(len(item["storageKeys"])) + for key in item["storageKeys"]: + result.extend(int_to_uint256(int(key, 16))) + return result + + +def merge_access_list(access_list): + """ + Merge all entries of the access list to get one entry per account with all its storage keys. + """ + merged_list = defaultdict(set) + for access in access_list: + merged_list[access["address"]] = merged_list[access["address"]].union( + { + pedersen_hash(*int_to_uint256(int(key, 16))) + for key in access["storageKeys"] + } + ) + return merged_list + + +def pack_calldata(data: bytes) -> List[int]: + """ + Pack the incoming calldata bytes 31-bytes at a time in big-endian order. + Returns a serialized array with the following elements: + - data_len: full length of input data + - full_words: full 31-byte words + - last_word: the last word taking less than or equal to 31 bytes. + """ + + return [len(data), *[int(chunk, 16) for chunk in wrap(data.hex(), 2 * 31)]] diff --git a/cairo/tests/utils/hints.py b/cairo/tests/utils/hints.py new file mode 100644 index 00000000..d32db034 --- /dev/null +++ b/cairo/tests/utils/hints.py @@ -0,0 +1,55 @@ +from collections import defaultdict +from contextlib import contextmanager +from unittest.mock import patch + +from starkware.cairo.common.dict import DictTracker +from starkware.cairo.lang.compiler.program import CairoHint + + +def debug_info(program): + def _debug_info(pc): + print( + program.debug_info.instruction_locations.get( + pc.offset + ).inst.to_string_with_content("") + ) + + return _debug_info + + +def new_default_dict( + dict_manager, segments, default_value, initial_dict, temp_segment: bool = False +): + """ + Create a new Cairo default dictionary. + """ + base = segments.add_temp_segment() if temp_segment else segments.add() + assert base.segment_index not in dict_manager.trackers + dict_manager.trackers[base.segment_index] = DictTracker( + data=defaultdict(lambda: default_value, initial_dict), + current_ptr=base, + ) + return base + + +@contextmanager +def patch_hint(program, hint, new_hint): + patched_hints = { + k: [ + ( + hint_ + if hint_.code != hint + else CairoHint( + accessible_scopes=hint_.accessible_scopes, + flow_tracking_data=hint_.flow_tracking_data, + code=new_hint, + ) + ) + for hint_ in v + ] + for k, v in program.hints.items() + } + if patched_hints == program.hints: + raise ValueError(f"Hint\n\n{hint}\n\nnot found in program hints.") + with patch.object(program, "hints", new=patched_hints): + yield diff --git a/cairo/tests/utils/interface_id.py b/cairo/tests/utils/interface_id.py new file mode 100644 index 00000000..7c52a3d5 --- /dev/null +++ b/cairo/tests/utils/interface_id.py @@ -0,0 +1,25 @@ +from eth_utils import keccak + + +def get_interface_id(): + validate = keccak( + text="__validate__(call_array_len: felt, call_array: ExternallyOwnedAccount.CallArray*, calldata_len: felt, calldata: felt*)" + ) + validate_declare = keccak(text="__validate_declare__(class_hash: felt)") + execute = keccak( + text="__execute__(call_array_len: felt, call_array: ExternallyOwnedAccount.CallArray*, calldata_len: felt, calldata: felt*)" + ) + get_evm_address = keccak(text="get_evm_address()") + supports_interface = keccak(text="supports_interface(interface_id: felt)") + is_valid_signature = keccak( + text="is_valid_signature(hash_len: felt, hash: felt*, signature_len: felt, signature: felt*)" + ) + return bytes( + validate[i] + ^ validate_declare[i] + ^ execute[i] + ^ get_evm_address[i] + ^ supports_interface[i] + ^ is_valid_signature[i] + for i in range(4) + ) diff --git a/cairo/tests/utils/reporting.py b/cairo/tests/utils/reporting.py new file mode 100644 index 00000000..5f44f35d --- /dev/null +++ b/cairo/tests/utils/reporting.py @@ -0,0 +1,80 @@ +import json +import logging +from functools import wraps +from pathlib import Path +from time import perf_counter +from typing import Any, Callable, List, TypeVar, Union, cast + +from starkware.cairo.lang.compiler.identifier_definition import LabelDefinition +from starkware.cairo.lang.tracer.profile import ProfileBuilder +from tests.utils.coverage import CoverageFile + +logging.basicConfig(format="%(levelname)-8s %(message)s") +logger = logging.getLogger("timer") + +_time_report: List[dict] = [] +# A mapping to fix the mismatch between the debug_info and the identifiers. +_label_scope = { + "kakarot.constants.opcodes_label": "kakarot.constants", + "kakarot.accounts.library.internal.pow_": "kakarot.accounts.library.internal", +} +T = TypeVar("T", bound=Callable[..., Any]) + + +def dump_coverage(path: Union[str, Path], files: List[CoverageFile]): + p = Path(path) + p.mkdir(exist_ok=True, parents=True) + json.dump( + { + "coverage": { + file.name.split("__main__/")[-1]: { + **{line: 0 for line in file.missed}, + **{line: 1 for line in file.covered}, + } + for file in files + } + }, + open(p / "coverage.json", "w"), + indent=2, + ) + + +def profile_from_tracer_data(tracer_data): + """ + Un-bundle the profile.profile_from_tracer_data to hard fix the opcode_labels name mismatch + between the debug_info and the identifiers; and adding a try/catch for the traces (pc going out of bounds). + """ + + builder = ProfileBuilder( + initial_fp=tracer_data.trace[0].fp, memory=tracer_data.memory + ) + + # Functions. + for name, ident in tracer_data.program.identifiers.as_dict().items(): + if not isinstance(ident, LabelDefinition): + continue + builder.function_id( + name=_label_scope.get(str(name), str(name)), + inst_location=tracer_data.program.debug_info.instruction_locations[ + ident.pc + ], + ) + + # Locations. + for ( + pc_offset, + inst_location, + ) in tracer_data.program.debug_info.instruction_locations.items(): + builder.location_id( + pc=tracer_data.get_pc_from_offset(pc_offset), + inst_location=inst_location, + ) + + # Samples. + for trace_entry in tracer_data.trace: + try: + builder.add_sample(trace_entry) + except KeyError: + pass + + return builder.dump() diff --git a/cairo/tests/utils/serde.py b/cairo/tests/utils/serde.py new file mode 100644 index 00000000..4d6208fe --- /dev/null +++ b/cairo/tests/utils/serde.py @@ -0,0 +1,303 @@ +from eth_utils.address import to_checksum_address +from starkware.cairo.lang.compiler.ast.cairo_types import ( + TypeFelt, + TypePointer, + TypeStruct, + TypeTuple, +) +from starkware.cairo.lang.compiler.identifier_definition import StructDefinition +from starkware.cairo.lang.compiler.identifier_manager import MissingIdentifierError + + +class Serde: + def __init__(self, runner): + self.runner = runner + self.memory = runner.segments.memory + + def get_identifier(self, struct_name, expected_type): + identifiers = [ + value + for key, value in self.runner.program.identifiers.as_dict().items() + if struct_name in str(key) + and isinstance(value, expected_type) + and struct_name.split(".")[-1] == str(key).split(".")[-1] + ] + if len(identifiers) != 1: + raise ValueError( + f"Expected one struct named {struct_name}, found {identifiers}" + ) + return identifiers[0] + + def serialize_list(self, segment_ptr, item_scope=None, list_len=None): + item_identifier = ( + self.get_identifier(item_scope, StructDefinition) + if item_scope is not None + else None + ) + item_type = ( + TypeStruct(item_identifier.full_name) + if item_scope is not None + else TypeFelt() + ) + item_size = item_identifier.size if item_identifier is not None else 1 + list_len = ( + list_len * item_size + if list_len is not None + else self.runner.segments.get_segment_size(segment_ptr.segment_index) + ) + output = [] + for i in range(0, list_len, item_size): + try: + output.append(self._serialize(item_type, segment_ptr + i)) + # Because there is no way to know for sure the length of the list, we stop when we + # encounter an error. + # trunk-ignore(ruff/E722) + except: + break + return output + + def serialize_dict(self, dict_ptr, value_scope=None, dict_size=None): + """ + Serialize a dict. + """ + if dict_size is None: + dict_size = self.runner.segments.get_segment_size(dict_ptr.segment_index) + output = {} + value_scope = ( + self.get_identifier(value_scope, StructDefinition).full_name + if value_scope is not None + else None + ) + for dict_index in range(0, dict_size, 3): + key = self.memory.get(dict_ptr + dict_index) + value_ptr = self.memory.get(dict_ptr + dict_index + 2) + if value_scope is None: + output[key] = value_ptr + else: + output[key] = ( + self.serialize_scope(value_scope, value_ptr) + if value_ptr != 0 + else None + ) + return output + + def serialize_pointers(self, name, ptr): + """ + Serialize a pointer to a struct, e.g. Uint256*. + """ + members = self.get_identifier(name, StructDefinition).members + output = {} + for name, member in members.items(): + member_ptr = self.memory.get(ptr + member.offset) + if member_ptr == 0 and isinstance(member.cairo_type, TypePointer): + member_ptr = None + output[name] = member_ptr + return output + + def serialize_struct(self, name, ptr): + """ + Serialize a struct, e.g. Uint256. + """ + if ptr is None: + return None + members = self.get_identifier(name, StructDefinition).members + return { + name: self._serialize(member.cairo_type, ptr + member.offset) + for name, member in members.items() + } + + def serialize_address(self, ptr): + raw = self.serialize_pointers("model.Address", ptr) + return { + "starknet": f'0x{raw["starknet"]:064x}', + "evm": to_checksum_address(f'{raw["evm"]:040x}'), + } + + def serialize_uint256(self, ptr): + raw = self.serialize_pointers("Uint256", ptr) + return hex(raw["low"] + raw["high"] * 2**128) + + def serialize_account(self, ptr): + raw = self.serialize_pointers("model.Account", ptr) + return { + "address": self.serialize_address(raw["address"]), + "code": self.serialize_list(raw["code"], list_len=raw["code_len"]), + "storage": self.serialize_dict(raw["storage_start"], "Uint256"), + "nonce": raw["nonce"], + "balance": self.serialize_uint256(raw["balance"]), + "selfdestruct": raw["selfdestruct"], + } + + def serialize_state(self, ptr): + raw = self.serialize_pointers("model.State", ptr) + return { + "accounts": { + to_checksum_address(f"{key:040x}"): value + for key, value in self.serialize_dict( + raw["accounts_start"], "model.Account" + ).items() + }, + "events": self.serialize_list( + raw["events"], "model.Event", list_len=raw["events_len"] + ), + "transfers": self.serialize_list( + raw["transfers"], "model.Transfer", list_len=raw["transfers_len"] + ), + } + + def serialize_eth_transaction(self, ptr): + raw = self.serialize_struct("model.EthTransaction", ptr) + return { + "signer_nonce": raw["signer_nonce"], + "gas_limit": raw["gas_limit"], + "max_priority_fee_per_gas": raw["max_priority_fee_per_gas"], + "max_fee_per_gas": raw["max_fee_per_gas"], + "destination": ( + to_checksum_address(f'0x{raw["destination"]["value"]:040x}') + if raw["destination"]["is_some"] == 1 + else None + ), + "amount": raw["amount"], + "payload": ("0x" + bytes(raw["payload"][: raw["payload_len"]]).hex()), + "access_list": ( + raw["access_list"][: raw["access_list_len"]] + if raw["access_list"] is not None + else [] + ), + "chain_id": ( + raw["chain_id"]["value"] if raw["chain_id"]["is_some"] == 1 else None + ), + } + + def serialize_message(self, ptr): + raw = self.serialize_pointers("model.Message", ptr) + return { + "bytecode": self.serialize_list( + raw["bytecode"], list_len=raw["bytecode_len"] + ), + "valid_jumpdest": list( + self.serialize_dict(raw["valid_jumpdests_start"]).keys() + ), + "calldata": self.serialize_list( + raw["calldata"], list_len=raw["calldata_len"] + ), + "caller": to_checksum_address(f'{raw["caller"]:040x}'), + "value": self.serialize_uint256(raw["value"]), + "parent": self.serialize_struct("model.Parent", raw["parent"]), + "address": self.serialize_address(raw["address"]), + "code_address": raw["code_address"], + "read_only": bool(raw["read_only"]), + "is_create": bool(raw["is_create"]), + "depth": raw["depth"], + "env": self.serialize_struct("model.Environment", raw["env"]), + } + + def serialize_evm(self, ptr): + evm = self.serialize_struct("model.EVM", ptr) + return { + "message": evm["message"], + "return_data": evm["return_data"][: evm["return_data_len"]], + "program_counter": evm["program_counter"], + "stopped": bool(evm["stopped"]), + "gas_left": evm["gas_left"], + "gas_refund": evm["gas_refund"], + "reverted": evm["reverted"], + } + + def serialize_stack(self, ptr): + raw = self.serialize_pointers("model.Stack", ptr) + stack_dict = self.serialize_dict( + raw["dict_ptr_start"], "Uint256", raw["dict_ptr"] - raw["dict_ptr_start"] + ) + return [stack_dict[i] for i in range(raw["size"])] + + def serialize_memory(self, ptr): + raw = self.serialize_pointers("model.Memory", ptr) + memory_dict = self.serialize_dict( + raw["word_dict_start"], dict_size=raw["word_dict"] - raw["word_dict_start"] + ) + return "".join( + [f"{memory_dict.get(i, 0):032x}" for i in range(raw["words_len"] * 2)] + ) + + def serialize_rlp_item(self, ptr): + raw = self.serialize_list(ptr) + items = [] + for i in range(0, len(raw), 3): + data_len = raw[i] + data_ptr = raw[i + 1] + is_list = raw[i + 2] + if not is_list: + items += [bytes(self.serialize_list(data_ptr)[:data_len])] + else: + items += [self.serialize_rlp_item(data_ptr)] + return items + + def serialize_scope(self, scope, scope_ptr): + if scope.path[-1] == "State": + return self.serialize_state(scope_ptr) + if scope.path[-1] == "Account": + return self.serialize_account(scope_ptr) + if scope.path[-1] == "Address": + return self.serialize_address(scope_ptr) + if scope.path[-1] == "EthTransaction": + return self.serialize_eth_transaction(scope_ptr) + if scope.path[-1] == "Stack": + return self.serialize_stack(scope_ptr) + if scope.path[-1] == "Memory": + return self.serialize_memory(scope_ptr) + if scope.path[-1] == "Uint256": + return self.serialize_uint256(scope_ptr) + if scope.path[-1] == "Message": + return self.serialize_message(scope_ptr) + if scope.path[-1] == "EVM": + return self.serialize_evm(scope_ptr) + if scope.path[-2:] == ("RLP", "Item"): + return self.serialize_rlp_item(scope_ptr) + try: + return self.serialize_struct(str(scope), scope_ptr) + except MissingIdentifierError: + return scope_ptr + + def _serialize(self, cairo_type, ptr, length=1): + if isinstance(cairo_type, TypePointer): + # A pointer can be a pointer to one single struct or to the beginning of a list of structs. + # As such, every pointer is considered a list of structs, with length 1 or more. + pointee = self.memory.get(ptr) + # Edge case: 0 pointers are not pointer but no data + if pointee == 0: + return None + if isinstance(cairo_type.pointee, TypeFelt): + return self.serialize_list(pointee) + serialized = self.serialize_list( + pointee, str(cairo_type.pointee.scope), list_len=length + ) + if len(serialized) == 1: + return serialized[0] + return serialized + if isinstance(cairo_type, TypeTuple): + return [ + self._serialize(m.typ, ptr + i) + for i, m in enumerate(cairo_type.members) + ] + if isinstance(cairo_type, TypeFelt): + return self.memory.get(ptr) + if isinstance(cairo_type, TypeStruct): + return self.serialize_scope(cairo_type.scope, ptr) + raise ValueError(f"Unknown type {cairo_type}") + + def get_offset(self, cairo_type): + if hasattr(cairo_type, "members"): + return len(cairo_type.members) + else: + try: + identifier = self.get_identifier( + str(cairo_type.scope), StructDefinition + ) + return len(identifier.members) + except (ValueError, AttributeError): + return 1 + + def serialize(self, cairo_type): + shift = self.get_offset(cairo_type) + return self._serialize(cairo_type, self.runner.vm.run_context.ap - shift, shift) diff --git a/cairo_programs/fibonacci.cairo b/cairo_programs/fibonacci.cairo deleted file mode 100644 index cc742b87..00000000 --- a/cairo_programs/fibonacci.cairo +++ /dev/null @@ -1,18 +0,0 @@ -func main() { - // Call fib(1, 1, 10). - let result: felt = fib(1, 1, 10); - - // Make sure the 10th Fibonacci number is 144. - assert result = 144; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} diff --git a/cairo_programs/fibonacci.json b/cairo_programs/fibonacci.json deleted file mode 100644 index f3bbf07b..00000000 --- a/cairo_programs/fibonacci.json +++ /dev/null @@ -1,260 +0,0 @@ -{ - "attributes": [], - "builtins": [], - "compiler_version": "0.12.0", - "data": [ - "0x40780017fff7fff", - "0x0", - "0x1104800180018000", - "0x4", - "0x10780017fff7fff", - "0x0", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0x1", - "0x480680017fff8000", - "0xa", - "0x1104800180018000", - "0x5", - "0x400680017fff7fff", - "0x90", - "0x208b7fff7fff7ffe", - "0x20780017fff7ffd", - "0x5", - "0x480a7ffc7fff8000", - "0x480a7ffc7fff8000", - "0x208b7fff7fff7ffe", - "0x482a7ffc7ffb8000", - "0x480a7ffc7fff8000", - "0x48127ffe7fff8000", - "0x482680017ffd8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff7", - "0x208b7fff7fff7ffe" - ], - "debug_info": null, - "hints": {}, - "identifiers": { - "__main__.__end__": { - "pc": 4, - "type": "label" - }, - "__main__.__start__": { - "pc": 0, - "type": "label" - }, - "__main__.fib": { - "decorators": [], - "pc": 17, - "type": "function" - }, - "__main__.fib.Args": { - "full_name": "__main__.fib.Args", - "members": { - "first_element": { - "cairo_type": "felt", - "offset": 0 - }, - "n": { - "cairo_type": "felt", - "offset": 2 - }, - "second_element": { - "cairo_type": "felt", - "offset": 1 - } - }, - "size": 3, - "type": "struct" - }, - "__main__.fib.ImplicitArgs": { - "full_name": "__main__.fib.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.fib.Return": { - "cairo_type": "(res: felt)", - "type": "type_definition" - }, - "__main__.fib.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__main__.fib.fib_body": { - "pc": 22, - "type": "label" - }, - "__main__.fib.first_element": { - "cairo_type": "felt", - "full_name": "__main__.fib.first_element", - "references": [ - { - "ap_tracking_data": { - "group": 4, - "offset": 0 - }, - "pc": 17, - "value": "[cast(fp + (-5), felt*)]" - } - ], - "type": "reference" - }, - "__main__.fib.n": { - "cairo_type": "felt", - "full_name": "__main__.fib.n", - "references": [ - { - "ap_tracking_data": { - "group": 4, - "offset": 0 - }, - "pc": 17, - "value": "[cast(fp + (-3), felt*)]" - } - ], - "type": "reference" - }, - "__main__.fib.result": { - "cairo_type": "felt", - "full_name": "__main__.fib.result", - "references": [ - { - "ap_tracking_data": { - "group": 4, - "offset": 1 - }, - "pc": 20, - "value": "[cast(ap + (-1), felt*)]" - } - ], - "type": "reference" - }, - "__main__.fib.second_element": { - "cairo_type": "felt", - "full_name": "__main__.fib.second_element", - "references": [ - { - "ap_tracking_data": { - "group": 4, - "offset": 0 - }, - "pc": 17, - "value": "[cast(fp + (-4), felt*)]" - } - ], - "type": "reference" - }, - "__main__.fib.y": { - "cairo_type": "felt", - "full_name": "__main__.fib.y", - "references": [ - { - "ap_tracking_data": { - "group": 4, - "offset": 1 - }, - "pc": 23, - "value": "[cast(ap + (-1), felt*)]" - } - ], - "type": "reference" - }, - "__main__.main": { - "decorators": [], - "pc": 6, - "type": "function" - }, - "__main__.main.Args": { - "full_name": "__main__.main.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.main.ImplicitArgs": { - "full_name": "__main__.main.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.main.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.main.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__main__.main.result": { - "cairo_type": "felt", - "full_name": "__main__.main.result", - "references": [ - { - "ap_tracking_data": { - "group": 3, - "offset": 0 - }, - "pc": 14, - "value": "[cast(ap + (-1), felt*)]" - } - ], - "type": "reference" - } - }, - "main_scope": "__main__", - "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "reference_manager": { - "references": [ - { - "ap_tracking_data": { - "group": 3, - "offset": 0 - }, - "pc": 14, - "value": "[cast(ap + (-1), felt*)]" - }, - { - "ap_tracking_data": { - "group": 4, - "offset": 0 - }, - "pc": 17, - "value": "[cast(fp + (-5), felt*)]" - }, - { - "ap_tracking_data": { - "group": 4, - "offset": 0 - }, - "pc": 17, - "value": "[cast(fp + (-4), felt*)]" - }, - { - "ap_tracking_data": { - "group": 4, - "offset": 0 - }, - "pc": 17, - "value": "[cast(fp + (-3), felt*)]" - }, - { - "ap_tracking_data": { - "group": 4, - "offset": 1 - }, - "pc": 20, - "value": "[cast(ap + (-1), felt*)]" - }, - { - "ap_tracking_data": { - "group": 4, - "offset": 1 - }, - "pc": 23, - "value": "[cast(ap + (-1), felt*)]" - } - ] - } -} diff --git a/cairo_programs/syscalls.cairo b/cairo_programs/syscalls.cairo deleted file mode 100644 index 52f7faef..00000000 --- a/cairo_programs/syscalls.cairo +++ /dev/null @@ -1,9 +0,0 @@ -%builtins syscall - -from starkware.starknet.common.syscalls import get_block_number - -func main{syscall_ptr : felt*}() { - let (block_number) = get_block_number(); - %{ print(ids.block_number) %} - return (); -} diff --git a/cairo_programs/syscalls.json b/cairo_programs/syscalls.json deleted file mode 100644 index 787b4f5f..00000000 --- a/cairo_programs/syscalls.json +++ /dev/null @@ -1,977 +0,0 @@ -{ - "attributes": [], - "builtins": ["syscall"], - "compiler_version": "0.13.2", - "data": [ - "0x40780017fff7fff", - "0x1", - "0x1104800180018000", - "0xb", - "0x10780017fff7fff", - "0x0", - "0x480680017fff8000", - "0x476574426c6f636b4e756d626572", - "0x400280007ffd7fff", - "0x482680017ffd8000", - "0x2", - "0x480280017ffd8000", - "0x208b7fff7fff7ffe", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff9", - "0x48127ffe7fff8000", - "0x208b7fff7fff7ffe" - ], - "debug_info": null, - "hints": { - "9": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.get_block_number" - ], - "code": "syscall_handler.get_block_number(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { - "group": 2, - "offset": 1 - }, - "reference_ids": { - "starkware.starknet.common.syscalls.get_block_number.__temp0": 2, - "starkware.starknet.common.syscalls.get_block_number.syscall": 1, - "starkware.starknet.common.syscalls.get_block_number.syscall_ptr": 0 - } - } - } - ], - "16": [ - { - "accessible_scopes": ["__main__", "__main__.main"], - "code": "print(ids.block_number)", - "flow_tracking_data": { - "ap_tracking": { - "group": 3, - "offset": 6 - }, - "reference_ids": { - "__main__.main.block_number": 6, - "__main__.main.syscall_ptr": 5 - } - } - } - ] - }, - "identifiers": { - "__main__.__end__": { - "pc": 4, - "type": "label" - }, - "__main__.__start__": { - "pc": 0, - "type": "label" - }, - "__main__.get_block_number": { - "destination": "starkware.starknet.common.syscalls.get_block_number", - "type": "alias" - }, - "__main__.main": { - "decorators": [], - "pc": 13, - "type": "function" - }, - "__main__.main.Args": { - "full_name": "__main__.main.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.main.ImplicitArgs": { - "full_name": "__main__.main.ImplicitArgs", - "members": { - "syscall_ptr": { - "cairo_type": "felt*", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "__main__.main.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.main.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__main__.main.block_number": { - "cairo_type": "felt", - "full_name": "__main__.main.block_number", - "references": [ - { - "ap_tracking_data": { - "group": 3, - "offset": 6 - }, - "pc": 16, - "value": "[cast(ap + (-1), felt*)]" - } - ], - "type": "reference" - }, - "__main__.main.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "__main__.main.syscall_ptr", - "references": [ - { - "ap_tracking_data": { - "group": 3, - "offset": 0 - }, - "pc": 13, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { - "group": 3, - "offset": 6 - }, - "pc": 16, - "value": "[cast(ap + (-2), felt**)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.dict_access.DictAccess": { - "full_name": "starkware.cairo.common.dict_access.DictAccess", - "members": { - "key": { - "cairo_type": "felt", - "offset": 0 - }, - "new_value": { - "cairo_type": "felt", - "offset": 2 - }, - "prev_value": { - "cairo_type": "felt", - "offset": 1 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.CALL_CONTRACT_SELECTOR": { - "type": "const", - "value": 20853273475220472486191784820 - }, - "starkware.starknet.common.syscalls.CallContract": { - "full_name": "starkware.starknet.common.syscalls.CallContract", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.CallContractRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse", - "offset": 5 - } - }, - "size": 7, - "type": "struct" - }, - "starkware.starknet.common.syscalls.CallContractRequest": { - "full_name": "starkware.starknet.common.syscalls.CallContractRequest", - "members": { - "calldata": { - "cairo_type": "felt*", - "offset": 4 - }, - "calldata_size": { - "cairo_type": "felt", - "offset": 3 - }, - "contract_address": { - "cairo_type": "felt", - "offset": 1 - }, - "function_selector": { - "cairo_type": "felt", - "offset": 2 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 5, - "type": "struct" - }, - "starkware.starknet.common.syscalls.CallContractResponse": { - "full_name": "starkware.starknet.common.syscalls.CallContractResponse", - "members": { - "retdata": { - "cairo_type": "felt*", - "offset": 1 - }, - "retdata_size": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DELEGATE_CALL_SELECTOR": { - "type": "const", - "value": 21167594061783206823196716140 - }, - "starkware.starknet.common.syscalls.DELEGATE_L1_HANDLER_SELECTOR": { - "type": "const", - "value": 23274015802972845247556842986379118667122 - }, - "starkware.starknet.common.syscalls.DEPLOY_SELECTOR": { - "type": "const", - "value": 75202468540281 - }, - "starkware.starknet.common.syscalls.Deploy": { - "full_name": "starkware.starknet.common.syscalls.Deploy", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.DeployRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.DeployResponse", - "offset": 6 - } - }, - "size": 9, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DeployRequest": { - "full_name": "starkware.starknet.common.syscalls.DeployRequest", - "members": { - "class_hash": { - "cairo_type": "felt", - "offset": 1 - }, - "constructor_calldata": { - "cairo_type": "felt*", - "offset": 4 - }, - "constructor_calldata_size": { - "cairo_type": "felt", - "offset": 3 - }, - "contract_address_salt": { - "cairo_type": "felt", - "offset": 2 - }, - "deploy_from_zero": { - "cairo_type": "felt", - "offset": 5 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 6, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DeployResponse": { - "full_name": "starkware.starknet.common.syscalls.DeployResponse", - "members": { - "constructor_retdata": { - "cairo_type": "felt*", - "offset": 2 - }, - "constructor_retdata_size": { - "cairo_type": "felt", - "offset": 1 - }, - "contract_address": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DictAccess": { - "destination": "starkware.cairo.common.dict_access.DictAccess", - "type": "alias" - }, - "starkware.starknet.common.syscalls.EMIT_EVENT_SELECTOR": { - "type": "const", - "value": 1280709301550335749748 - }, - "starkware.starknet.common.syscalls.EmitEvent": { - "full_name": "starkware.starknet.common.syscalls.EmitEvent", - "members": { - "data": { - "cairo_type": "felt*", - "offset": 4 - }, - "data_len": { - "cairo_type": "felt", - "offset": 3 - }, - "keys": { - "cairo_type": "felt*", - "offset": 2 - }, - "keys_len": { - "cairo_type": "felt", - "offset": 1 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 5, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GET_BLOCK_NUMBER_SELECTOR": { - "type": "const", - "value": 1448089106835523001438702345020786 - }, - "starkware.starknet.common.syscalls.GET_BLOCK_TIMESTAMP_SELECTOR": { - "type": "const", - "value": 24294903732626645868215235778792757751152 - }, - "starkware.starknet.common.syscalls.GET_CALLER_ADDRESS_SELECTOR": { - "type": "const", - "value": 94901967781393078444254803017658102643 - }, - "starkware.starknet.common.syscalls.GET_CONTRACT_ADDRESS_SELECTOR": { - "type": "const", - "value": 6219495360805491471215297013070624192820083 - }, - "starkware.starknet.common.syscalls.GET_SEQUENCER_ADDRESS_SELECTOR": { - "type": "const", - "value": 1592190833581991703053805829594610833820054387 - }, - "starkware.starknet.common.syscalls.GET_TX_INFO_SELECTOR": { - "type": "const", - "value": 1317029390204112103023 - }, - "starkware.starknet.common.syscalls.GET_TX_SIGNATURE_SELECTOR": { - "type": "const", - "value": 1448089128652340074717162277007973 - }, - "starkware.starknet.common.syscalls.GetBlockNumber": { - "full_name": "starkware.starknet.common.syscalls.GetBlockNumber", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumberRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumberResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockNumberRequest": { - "full_name": "starkware.starknet.common.syscalls.GetBlockNumberRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockNumberResponse": { - "full_name": "starkware.starknet.common.syscalls.GetBlockNumberResponse", - "members": { - "block_number": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockTimestamp": { - "full_name": "starkware.starknet.common.syscalls.GetBlockTimestamp", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockTimestampRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockTimestampResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockTimestampRequest": { - "full_name": "starkware.starknet.common.syscalls.GetBlockTimestampRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockTimestampResponse": { - "full_name": "starkware.starknet.common.syscalls.GetBlockTimestampResponse", - "members": { - "block_timestamp": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetCallerAddress": { - "full_name": "starkware.starknet.common.syscalls.GetCallerAddress", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetCallerAddressRequest": { - "full_name": "starkware.starknet.common.syscalls.GetCallerAddressRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetCallerAddressResponse": { - "full_name": "starkware.starknet.common.syscalls.GetCallerAddressResponse", - "members": { - "caller_address": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetContractAddress": { - "full_name": "starkware.starknet.common.syscalls.GetContractAddress", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetContractAddressRequest": { - "full_name": "starkware.starknet.common.syscalls.GetContractAddressRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetContractAddressResponse": { - "full_name": "starkware.starknet.common.syscalls.GetContractAddressResponse", - "members": { - "contract_address": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetSequencerAddress": { - "full_name": "starkware.starknet.common.syscalls.GetSequencerAddress", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetSequencerAddressRequest": { - "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetSequencerAddressResponse": { - "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", - "members": { - "sequencer_address": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxInfo": { - "full_name": "starkware.starknet.common.syscalls.GetTxInfo", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxInfoRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxInfoResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxInfoRequest": { - "full_name": "starkware.starknet.common.syscalls.GetTxInfoRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxInfoResponse": { - "full_name": "starkware.starknet.common.syscalls.GetTxInfoResponse", - "members": { - "tx_info": { - "cairo_type": "starkware.starknet.common.syscalls.TxInfo*", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxSignature": { - "full_name": "starkware.starknet.common.syscalls.GetTxSignature", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureResponse", - "offset": 1 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxSignatureRequest": { - "full_name": "starkware.starknet.common.syscalls.GetTxSignatureRequest", - "members": { - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxSignatureResponse": { - "full_name": "starkware.starknet.common.syscalls.GetTxSignatureResponse", - "members": { - "signature": { - "cairo_type": "felt*", - "offset": 1 - }, - "signature_len": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.LIBRARY_CALL_L1_HANDLER_SELECTOR": { - "type": "const", - "value": 436233452754198157705746250789557519228244616562 - }, - "starkware.starknet.common.syscalls.LIBRARY_CALL_SELECTOR": { - "type": "const", - "value": 92376026794327011772951660 - }, - "starkware.starknet.common.syscalls.LibraryCall": { - "full_name": "starkware.starknet.common.syscalls.LibraryCall", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.LibraryCallRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse", - "offset": 5 - } - }, - "size": 7, - "type": "struct" - }, - "starkware.starknet.common.syscalls.LibraryCallRequest": { - "full_name": "starkware.starknet.common.syscalls.LibraryCallRequest", - "members": { - "calldata": { - "cairo_type": "felt*", - "offset": 4 - }, - "calldata_size": { - "cairo_type": "felt", - "offset": 3 - }, - "class_hash": { - "cairo_type": "felt", - "offset": 1 - }, - "function_selector": { - "cairo_type": "felt", - "offset": 2 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 5, - "type": "struct" - }, - "starkware.starknet.common.syscalls.REPLACE_CLASS_SELECTOR": { - "type": "const", - "value": 25500403217443378527601783667 - }, - "starkware.starknet.common.syscalls.ReplaceClass": { - "full_name": "starkware.starknet.common.syscalls.ReplaceClass", - "members": { - "class_hash": { - "cairo_type": "felt", - "offset": 1 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.SEND_MESSAGE_TO_L1_SELECTOR": { - "type": "const", - "value": 433017908768303439907196859243777073 - }, - "starkware.starknet.common.syscalls.STORAGE_READ_SELECTOR": { - "type": "const", - "value": 100890693370601760042082660 - }, - "starkware.starknet.common.syscalls.STORAGE_WRITE_SELECTOR": { - "type": "const", - "value": 25828017502874050592466629733 - }, - "starkware.starknet.common.syscalls.SendMessageToL1SysCall": { - "full_name": "starkware.starknet.common.syscalls.SendMessageToL1SysCall", - "members": { - "payload_ptr": { - "cairo_type": "felt*", - "offset": 3 - }, - "payload_size": { - "cairo_type": "felt", - "offset": 2 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - }, - "to_address": { - "cairo_type": "felt", - "offset": 1 - } - }, - "size": 4, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageRead": { - "full_name": "starkware.starknet.common.syscalls.StorageRead", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.StorageReadRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.StorageReadResponse", - "offset": 2 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageReadRequest": { - "full_name": "starkware.starknet.common.syscalls.StorageReadRequest", - "members": { - "address": { - "cairo_type": "felt", - "offset": 1 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageReadResponse": { - "full_name": "starkware.starknet.common.syscalls.StorageReadResponse", - "members": { - "value": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageWrite": { - "full_name": "starkware.starknet.common.syscalls.StorageWrite", - "members": { - "address": { - "cairo_type": "felt", - "offset": 1 - }, - "selector": { - "cairo_type": "felt", - "offset": 0 - }, - "value": { - "cairo_type": "felt", - "offset": 2 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.TxInfo": { - "full_name": "starkware.starknet.common.syscalls.TxInfo", - "members": { - "account_contract_address": { - "cairo_type": "felt", - "offset": 1 - }, - "chain_id": { - "cairo_type": "felt", - "offset": 6 - }, - "max_fee": { - "cairo_type": "felt", - "offset": 2 - }, - "nonce": { - "cairo_type": "felt", - "offset": 7 - }, - "signature": { - "cairo_type": "felt*", - "offset": 4 - }, - "signature_len": { - "cairo_type": "felt", - "offset": 3 - }, - "transaction_hash": { - "cairo_type": "felt", - "offset": 5 - }, - "version": { - "cairo_type": "felt", - "offset": 0 - } - }, - "size": 8, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_block_number": { - "decorators": [], - "pc": 6, - "type": "function" - }, - "starkware.starknet.common.syscalls.get_block_number.Args": { - "full_name": "starkware.starknet.common.syscalls.get_block_number.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_block_number.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.get_block_number.ImplicitArgs", - "members": { - "syscall_ptr": { - "cairo_type": "felt*", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_block_number.Return": { - "cairo_type": "(block_number: felt)", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.get_block_number.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.get_block_number.__temp0": { - "cairo_type": "felt", - "full_name": "starkware.starknet.common.syscalls.get_block_number.__temp0", - "references": [ - { - "ap_tracking_data": { - "group": 2, - "offset": 1 - }, - "pc": 8, - "value": "[cast(ap + (-1), felt*)]" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.get_block_number.syscall": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumber", - "full_name": "starkware.starknet.common.syscalls.get_block_number.syscall", - "references": [ - { - "ap_tracking_data": { - "group": 2, - "offset": 0 - }, - "pc": 6, - "value": "[cast([fp + (-3)], starkware.starknet.common.syscalls.GetBlockNumber*)]" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.get_block_number.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.get_block_number.syscall_ptr", - "references": [ - { - "ap_tracking_data": { - "group": 2, - "offset": 0 - }, - "pc": 6, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { - "group": 2, - "offset": 1 - }, - "pc": 9, - "value": "cast([fp + (-3)] + 2, felt*)" - } - ], - "type": "reference" - } - }, - "main_scope": "__main__", - "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "reference_manager": { - "references": [ - { - "ap_tracking_data": { - "group": 2, - "offset": 0 - }, - "pc": 6, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { - "group": 2, - "offset": 0 - }, - "pc": 6, - "value": "[cast([fp + (-3)], starkware.starknet.common.syscalls.GetBlockNumber*)]" - }, - { - "ap_tracking_data": { - "group": 2, - "offset": 1 - }, - "pc": 8, - "value": "[cast(ap + (-1), felt*)]" - }, - { - "ap_tracking_data": { - "group": 2, - "offset": 1 - }, - "pc": 9, - "value": "cast([fp + (-3)] + 2, felt*)" - }, - { - "ap_tracking_data": { - "group": 3, - "offset": 0 - }, - "pc": 13, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { - "group": 3, - "offset": 6 - }, - "pc": 16, - "value": "[cast(ap + (-2), felt**)]" - }, - { - "ap_tracking_data": { - "group": 3, - "offset": 6 - }, - "pc": 16, - "value": "[cast(ap + (-1), felt*)]" - } - ] - } -} diff --git a/cairo_programs/transaction_hash.cairo b/cairo_programs/transaction_hash.cairo deleted file mode 100644 index fbe31f9f..00000000 --- a/cairo_programs/transaction_hash.cairo +++ /dev/null @@ -1,7 +0,0 @@ -func main() { - %{ - print_latest_block_transactions - %} - - ret; -} diff --git a/cairo_programs/transaction_hash.json b/cairo_programs/transaction_hash.json deleted file mode 100644 index c65f04a7..00000000 --- a/cairo_programs/transaction_hash.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "attributes": [], - "builtins": [], - "compiler_version": "0.12.0", - "data": [ - "0x40780017fff7fff", - "0x0", - "0x1104800180018000", - "0x4", - "0x10780017fff7fff", - "0x0", - "0x208b7fff7fff7ffe" - ], - "debug_info": null, - "hints": { - "6": [ - { - "accessible_scopes": ["__main__", "__main__.main"], - "code": "print_latest_block_transactions", - "flow_tracking_data": { - "ap_tracking": { - "group": 2, - "offset": 0 - }, - "reference_ids": {} - } - } - ] - }, - "identifiers": { - "__main__.__end__": { - "pc": 4, - "type": "label" - }, - "__main__.__start__": { - "pc": 0, - "type": "label" - }, - "__main__.main": { - "decorators": [], - "pc": 6, - "type": "function" - }, - "__main__.main.Args": { - "full_name": "__main__.main.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.main.ImplicitArgs": { - "full_name": "__main__.main.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.main.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.main.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - } - }, - "main_scope": "__main__", - "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "reference_manager": { - "references": [] - } -} diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 9c92462b..00000000 --- a/poetry.lock +++ /dev/null @@ -1,2305 +0,0 @@ -# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. - -[[package]] -name = "aiohappyeyeballs" -version = "2.4.0" -description = "Happy Eyeballs for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd"}, - {file = "aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2"}, -] - -[[package]] -name = "aiohttp" -version = "3.10.5" -description = "Async http client/server framework (asyncio)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, - {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, - {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, - {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, - {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, - {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, - {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, - {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, - {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, - {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, - {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, - {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, - {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, - {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, -] - -[package.dependencies] -aiohappyeyeballs = ">=2.3.0" -aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} -attrs = ">=17.3.0" -frozenlist = ">=1.1.1" -multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" - -[package.extras] -speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] - -[[package]] -name = "aiosignal" -version = "1.3.1" -description = "aiosignal: a list of registered asynchronous callbacks" -optional = false -python-versions = ">=3.7" -files = [ - {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, - {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, -] - -[package.dependencies] -frozenlist = ">=1.1.0" - -[[package]] -name = "annotated-types" -version = "0.7.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - -[[package]] -name = "async-timeout" -version = "4.0.3" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -] - -[[package]] -name = "attrs" -version = "24.2.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, -] - -[package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] - -[[package]] -name = "bitarray" -version = "2.9.2" -description = "efficient arrays of booleans -- C extension" -optional = false -python-versions = "*" -files = [ - {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:917905de565d9576eb20f53c797c15ba88b9f4f19728acabec8d01eee1d3756a"}, - {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b35bfcb08b7693ab4bf9059111a6e9f14e07d57ac93cd967c420db58ab9b71e1"}, - {file = "bitarray-2.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea1923d2e7880f9e1959e035da661767b5a2e16a45dfd57d6aa831e8b65ee1bf"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0b63a565e8a311cc8348ff1262d5784df0f79d64031d546411afd5dd7ef67d"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf0620da2b81946d28c0b16f3e3704d38e9837d85ee4f0652816e2609aaa4fed"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a9b8b05f2876c7195a2b698c47528e86a73c61ea203394ff8e7a4434bda5c8"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:345c76b349ff145549652436235c5532e5bfe9db690db6f0a6ad301c62b9ef21"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e2936f090bf3f4d1771f44f9077ebccdbc0415d2b598d51a969afcb519df505"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f9346e98fc2abcef90b942973087e2462af6d3e3710e82938078d3493f7fef52"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6ec283d4741befb86e8c3ea2e9ac1d17416c956d392107e45263e736954b1f7"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:962892646599529917ef26266091e4cb3077c88b93c3833a909d68dcc971c4e3"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e8da5355d7d75a52df5b84750989e34e39919ec7e59fafc4c104cc1607ab2d31"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:603e7d640e54ad764d2b4da6b61e126259af84f253a20f512dd10689566e5478"}, - {file = "bitarray-2.9.2-cp310-cp310-win32.whl", hash = "sha256:f00079f8e69d75c2a417de7961a77612bb77ef46c09bc74607d86de4740771ef"}, - {file = "bitarray-2.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:1bb33673e7f7190a65f0a940c1ef63266abdb391f4a3e544a47542d40a81f536"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe71fd4b76380c2772f96f1e53a524da7063645d647a4fcd3b651bdd80ca0f2e"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d527172919cdea1e13994a66d9708a80c3d33dedcf2f0548e4925e600fef3a3a"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:052c5073bdcaa9dd10628d99d37a2f33ec09364b86dd1f6281e2d9f8d3db3060"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e064caa55a6ed493aca1eda06f8b3f689778bc780a75e6ad7724642ba5dc62f7"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:508069a04f658210fdeee85a7a0ca84db4bcc110cbb1d21f692caa13210f24a7"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4da73ebd537d75fa7bccfc2228fcaedea0803f21dd9d0bf0d3b67fef3c4af294"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb378eaa65cd43098f11ff5d27e48ee3b956d2c00d2d6b5bfc2a09fe183be47"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d14c790b91f6cbcd9b718f88ed737c78939980c69ac8c7f03dd7e60040c12951"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eea9318293bc0ea6447e9ebfba600a62f3428bea7e9c6d42170ae4f481dbab3"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b76ffec27c7450b8a334f967366a9ebadaea66ee43f5b530c12861b1a991f503"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:76b76a07d4ee611405045c6950a1e24c4362b6b44808d4ad6eea75e0dbc59af4"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c7d16beeaaab15b075990cd26963d6b5b22e8c5becd131781514a00b8bdd04bd"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60df43e868a615c7e15117a1e1c2e5e11f48f6457280eba6ddf8fbefbec7da99"}, - {file = "bitarray-2.9.2-cp311-cp311-win32.whl", hash = "sha256:e788608ed7767b7b3bbde6d49058bccdf94df0de9ca75d13aa99020cc7e68095"}, - {file = "bitarray-2.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:a23397da092ef0a8cfe729571da64c2fc30ac18243caa82ac7c4f965087506ff"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:90e3a281ffe3897991091b7c46fca38c2675bfd4399ffe79dfeded6c52715436"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bed637b674db5e6c8a97a4a321e3e4d73e72d50b5c6b29950008a93069cc64cd"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e49066d251dbbe4e6e3a5c3937d85b589e40e2669ad0eef41a00f82ec17d844b"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4344e96642e2211fb3a50558feff682c31563a4c64529a931769d40832ca79"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aeb60962ec4813c539a59fbd4f383509c7222b62c3fb1faa76b54943a613e33a"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f7982f10581bb16553719e5e8f933e003f5b22f7d25a68bdb30fac630a6ff"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71d1cabdeee0cdda4669168618f0e46b7dace207b29da7b63aaa1adc2b54081"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0ef2d0a6f1502d38d911d25609b44c6cc27bee0a4363dd295df78b075041b60"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6f71d92f533770fb027388b35b6e11988ab89242b883f48a6fe7202d238c61f8"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba0734aa300757c924f3faf8148e1b8c247176a0ac8e16aefdf9c1eb19e868f7"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d91406f413ccbf4af6ab5ae7bc78f772a95609f9ddd14123db36ef8c37116d95"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:87abb7f80c0a042f3fe8e5264da1a2756267450bb602110d5327b8eaff7682e7"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b558ce85579b51a2e38703877d1e93b7728a7af664dd45a34e833534f0b755d"}, - {file = "bitarray-2.9.2-cp312-cp312-win32.whl", hash = "sha256:dac2399ee2889fbdd3472bfc2ede74c34cceb1ccf29a339964281a16eb1d3188"}, - {file = "bitarray-2.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:48a30d718d1a6dfc22a49547450107abe8f4afdf2abdcbe76eb9ed88edc49498"}, - {file = "bitarray-2.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2c6be1b651fad8f3adb7a5aa12c65b612cd9b89530969af941844ae680f7d981"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b399ae6ab975257ec359f03b48fc00b1c1cd109471e41903548469b8feae5c"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b3543c8a1cb286ad105f11c25d8d0f712f41c5c55f90be39f0e5a1376c7d0b0"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03adaacb79e2fb8f483ab3a67665eec53bb3fd0cd5dbd7358741aef124688db3"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae5b0657380d2581e13e46864d147a52c1e2bbac9f59b59c576e42fa7d10cf0"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1f4bf6ea8eb9d7f30808c2e9894237a96650adfecbf5f3643862dc5982f89e"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a8873089be2aa15494c0f81af1209f6e1237d762c5065bc4766c1b84321e1b50"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:677e67f50e2559efc677a4366707070933ad5418b8347a603a49a070890b19bc"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a620d8ce4ea2f1c73c6b6b1399e14cb68c6915e2be3fad5808c2998ed55b4acf"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:64115ccabbdbe279c24c367b629c6b1d3da9ed36c7420129e27c338a3971bfee"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d6fb422772e75385b76ad1c52f45a68bd4efafd8be8d0061c11877be74c4d43"}, - {file = "bitarray-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:852e202875dd6dfd6139ce7ec4e98dac2b17d8d25934dc99900831e81c3adaef"}, - {file = "bitarray-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7dfefdcb0dc6a3ba9936063cec65a74595571b375beabe18742b3d91d087eefd"}, - {file = "bitarray-2.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b306c4cf66912511422060f7f5e1149c8bdb404f8e00e600561b0749fdd45659"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a09c4f81635408e3387348f415521d4b94198c562c23330f560596a6aaa26eaf"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5361413fd2ecfdf44dc8f065177dc6aba97fa80a91b815586cb388763acf7f8d"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8a9475d415ef1eaae7942df6f780fa4dcd48fce32825eda591a17abba869299"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b87baa7bfff9a5878fcc1bffe49ecde6e647a72a64b39a69cd8a2992a43a34"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb6b86cfdfc503e92cb71c68766a24565359136961642504a7cc9faf936d9c88"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cd56b8ae87ebc71bcacbd73615098e8a8de952ecbb5785b6b4e2b07da8a06e1f"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3fa909cfd675004aed8b4cc9df352415933656e0155a6209d878b7cb615c787e"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b069ca9bf728e0c5c5b60e00a89df9af34cc170c695c3bfa3b372d8f40288efb"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6067f2f07a7121749858c7daa93c8774325c91590b3e81a299621e347740c2ae"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:321841cdad1dd0f58fe62e80e9c9c7531f8ebf8be93f047401e930dc47425b1e"}, - {file = "bitarray-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:54e16e32e60973bb83c315de9975bc1bcfc9bd50bb13001c31da159bc49b0ca1"}, - {file = "bitarray-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4dcadb7b8034aa3491ee8f5a69b3d9ba9d7d1e55c3cc1fc45be313e708277f8"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c8919fdbd3bb596b104388b56ae4b266eb28da1f2f7dff2e1f9334a21840fe96"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb7a9d8a2e400a1026de341ad48e21670a6261a75b06df162c5c39b0d0e7c8f4"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6ec84668dd7b937874a2b2c293cd14ba84f37be0d196dead852e0ada9815d807"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2de9a31c34e543ae089fd2a5ced01292f725190e379921384f695e2d7184bd3"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9521f49ae121a17c0a41e5112249e6fa7f6a571245b1118de81fb86e7c1bc1ce"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6cc6545d6d76542aee3d18c1c9485fb7b9812b8df4ebe52c4535ec42081b48f"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:856bbe1616425f71c0df5ef2e8755e878d9504d5a531acba58ab4273c52c117a"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4bba8042ea6ab331ade91bc435d81ad72fddb098e49108610b0ce7780c14e68"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a035da89c959d98afc813e3c62f052690d67cfd55a36592f25d734b70de7d4b0"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d70b1579da7fb71be5a841a1f965d19aca0ef27f629cfc07d06b09aafd0a333"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:405b83bed28efaae6d86b6ab287c75712ead0adbfab2a1075a1b7ab47dad4d62"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7eb8be687c50da0b397d5e0ab7ca200b5ebb639e79a9f5e285851d1944c94be9"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eceb551dfeaf19c609003a69a0cf8264b0efd7abc3791a11dfabf4788daf0d19"}, - {file = "bitarray-2.9.2-cp38-cp38-win32.whl", hash = "sha256:bb198c6ed1edbcdaf3d1fa3c9c9d1cdb7e179a5134ef5ee660b53cdec43b34e7"}, - {file = "bitarray-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:648d2f2685590b0103c67a937c2fb9e09bcc8dfb166f0c7c77bd341902a6f5b3"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ea816dc8f8e65841a8bbdd30e921edffeeb6f76efe6a1eb0da147b60d539d1cf"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4d0e32530f941c41eddfc77600ec89b65184cb909c549336463a738fab3ed285"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a22266fb416a3b6c258bf7f83c9fe531ba0b755a56986a81ad69dc0f3bcc070"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc6d3e80dd8239850f2604833ff3168b28909c8a9357abfed95632cccd17e3e7"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f135e804986b12bf14f2cd1eb86674c47dea86c4c5f0fa13c88978876b97ebe6"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87580c7f7d14f7ec401eda7adac1e2a25e95153e9c339872c8ae61b3208819a1"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64b433e26993127732ac7b66a7821b2537c3044355798de7c5fcb0af34b8296f"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e497c535f2a9b68c69d36631bf2dba243e05eb343b00b9c7bbdc8c601c6802d"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e40b3cb9fa1edb4e0175d7c06345c49c7925fe93e39ef55ecb0bc40c906b0c09"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f2f8692f95c9e377eb19ca519d30d1f884b02feb7e115f798de47570a359e43f"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f0b84fc50b6dbeced4fa390688c07c10a73222810fb0e08392bd1a1b8259de36"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d656ad38c942e38a470ddbce26b5020e08e1a7ea86b8fd413bb9024b5189993a"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ab0f1dbfe5070db98771a56aa14797595acd45a1af9eadfb193851a270e7996"}, - {file = "bitarray-2.9.2-cp39-cp39-win32.whl", hash = "sha256:0a99b23ac845a9ea3157782c97465e6ae026fe0c7c4c1ed1d88f759fd6ea52d9"}, - {file = "bitarray-2.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:9bbcfc7c279e8d74b076e514e669b683f77b4a2a328585b3f16d4c5259c91222"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:43847799461d8ba71deb4d97b47250c2c2fb66d82cd3cb8b4caf52bb97c03034"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f44381b0a4bdf64416082f4f0e7140377ae962c0ced6f983c6d7bbfc034040"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a484061616fb4b158b80789bd3cb511f399d2116525a8b29b6334c68abc2310f"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ff9e38356cc803e06134cf8ae9758e836ccd1b793135ef3db53c7c5d71e93bc"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b44105792fbdcfbda3e26ee88786790fda409da4c71f6c2b73888108cf8f062f"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7e913098de169c7fc890638ce5e171387363eb812579e637c44261460ac00aa2"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6fe315355cdfe3ed22ef355b8bdc81a805ca4d0949d921576560e5b227a1112"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f708e91fdbe443f3bec2df394ed42328fb9b0446dff5cb4199023ac6499e09fd"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b7b09489b71f9f1f64c0fa0977e250ec24500767dab7383ba9912495849cadf"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:128cc3488176145b9b137fdcf54c1c201809bbb8dd30b260ee40afe915843b43"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21f21e7f56206be346bdbda2a6bdb2165a5e6a11821f88fd4911c5a6bbbdc7e2"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f4dd3af86dd8a617eb6464622fb64ca86e61ce99b59b5c35d8cd33f9c30603d"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6465de861aff7a2559f226b37982007417eab8c3557543879987f58b453519bd"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbaf2bb71d6027152d603f1d5f31e0dfd5e50173d06f877bec484e5396d4594b"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2f32948c86e0d230a296686db28191b67ed229756f84728847daa0c7ab7406e3"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be94e5a685e60f9d24532af8fe5c268002e9016fa80272a94727f435de3d1003"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5cc9381fd54f3c23ae1039f977bfd6d041a5c3c1518104f616643c3a5a73b15"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd926e8ae4d1ed1ac4a8f37212a62886292f692bc1739fde98013bf210c2d175"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:461a3dafb9d5fda0bb3385dc507d78b1984b49da3fe4c6d56c869a54373b7008"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:393cb27fd859af5fd9c16eb26b1c59b17b390ff66b3ae5d0dd258270191baf13"}, - {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, -] - -[[package]] -name = "cachetools" -version = "5.5.0" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, -] - -[[package]] -name = "cairo-lang" -version = "0.13.2" -description = "Compiler and runner for the Cairo language" -optional = false -python-versions = ">=3.6" -files = [ - {file = "cairo-lang-0.13.2.zip", hash = "sha256:46cc20f0053ef863263940fa9f86f52a29e9a7269dea45c3cbde4223e1c2e2e0"}, -] - -[package.dependencies] -aiohttp = "*" -cachetools = "*" -ecdsa = "*" -eth-hash = {version = "*", extras = ["pycryptodome"]} -execnet = "*" -fastecdsa = "*" -frozendict = "*" -gprof2dot = "*" -lark = "*" -marshmallow = ">=3.2.1" -marshmallow-dataclass = "8.6.1" -marshmallow-enum = "*" -marshmallow-oneofschema = "*" -mpmath = "*" -numpy = "*" -pipdeptree = "*" -prometheus-client = "*" -pytest = "*" -pytest-asyncio = "*" -pytest-profiling = "*" -pytest-xdist = "*" -PyYAML = "*" -sympy = "*" -typeguard = "<3.0.0" -web3 = "*" - -[[package]] -name = "certifi" -version = "2024.7.4" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "ckzg" -version = "2.0.0" -description = "Python bindings for C-KZG-4844" -optional = false -python-versions = "*" -files = [ - {file = "ckzg-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a30f093231a7290badbf7b9b3c1e0945dae9075830adf502b9825de297054982"}, - {file = "ckzg-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ebe26fd27e447be2a03f9ce37a15c2850c348851f419d857304435c8e0ad3667"}, - {file = "ckzg-2.0.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5eec35b0d66324e6de49f6f79500f723c5577eb51d34ebb05d2ffbb8327f9067"}, - {file = "ckzg-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0193721088a6eb73973d49cea422241421f72f4050729160fce94aee937f76b9"}, - {file = "ckzg-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7ae6d0afc6a878472975a48538b06bece71fcb42dcc12f9d07797fa800d0bd8"}, - {file = "ckzg-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c9ca8ce54699be8be918ba8177d95814f24b1bab64b83be6dc29313310994a81"}, - {file = "ckzg-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6c115e4dea324fd77c1c7e3c7b8b8e3056db6b3b839eb989ac05eb74702fb8db"}, - {file = "ckzg-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:61d993c615ae64b3709a17b6bca0129680c742aa3fd57b6f62c982e0150260cf"}, - {file = "ckzg-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6146814f3c73e895327f4954510d85900f29662f1b6add5a63aee63bf53b0b6"}, - {file = "ckzg-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bed234e23203399b3ed156dd7c35bf36c346e3df18e961cf94101653d37127df"}, - {file = "ckzg-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0aa8214c780b11b88a2e7ee19fd57bd6f02fab7a48f9b3a2d3d24664bd46a658"}, - {file = "ckzg-2.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e206dd6dc87c37fd294aa96e39e15943ac8deb768786b3ad8634393f14ab2bf"}, - {file = "ckzg-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7721cb382f67618e04f2312dfc1ac03a81377cc256ca3c07f6d2e630d4d3cf8b"}, - {file = "ckzg-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:728ec7d184d16e13ceed7f270c645643557f0fca0bad842b5c65ce89bdcd56bb"}, - {file = "ckzg-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:88773a51242bb85b0738752495208187150935e252e91550af45ddf9cb206f92"}, - {file = "ckzg-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:20bbd544b6739533c986de2291ae13d9739b54764cbf42b4b9dea6c6b8c61b08"}, - {file = "ckzg-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0b20ac3132d57da95eb7e1a26f02ab0ca363d858e835776bf6480a871674c98"}, - {file = "ckzg-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:5da79a26ff8e8d899fb357ebd19f2ebd6623c875584015ba629560345358b602"}, - {file = "ckzg-2.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5fb8a7ed9f430e1102f7d25df015e555c255c512c372373bd1b52fa65b2c32b2"}, - {file = "ckzg-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a93ef601f87960f881b6a2519d6689ee829cc35e0847ed3dff38c6afff383b41"}, - {file = "ckzg-2.0.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d0ca9e939b7b0dfd5a91cd981a595512000f42739b6262824c886b3a06960fe"}, - {file = "ckzg-2.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:187a0fc230f3993fa8cb2c17d589f8b3ea6b74e1f5ac9927d4f37c19e153afd1"}, - {file = "ckzg-2.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a3c4aec3ffef2a20f67f6d4a13e9980560aa25d89bbc553aff1e4144f3239a"}, - {file = "ckzg-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cb48fd7d110fda65a5b9f34f921d15d468354662752d252a0de02797e9510c50"}, - {file = "ckzg-2.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:de94dd1615e6aa003a6c864d5c8e8771d98ef912e32f12c555e7703134e77717"}, - {file = "ckzg-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:805d3a11bf6c50badaf02464340dcfb52363b1889b7f75b04a7179959285bac7"}, - {file = "ckzg-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea02a706d42e9c273554192949439742267b0031054d859c5c63db064b768a79"}, - {file = "ckzg-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0669fd7c928f7cd3591cc7ce26bf6d1a89a80f6281e7c7a8156b09132a67c6a3"}, - {file = "ckzg-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f49344e2184c5987a8c3a75f4e28a5c98d915dbee1ed5aebe6c2d9cb0ce8c826"}, - {file = "ckzg-2.0.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1bc8fe0f9a71c21d4e3600ec4f85843a19f9c33948ac26e26e28a5439d20b56"}, - {file = "ckzg-2.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec302a38f2219d45e2b32150303c0400f94846c6036568fbee690b47b3557e7a"}, - {file = "ckzg-2.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea666d29029ecac5be6c193846ed9e0ce1ead6701f687d45ed9985d9f90ea37c"}, - {file = "ckzg-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76dcbd3b598f6a90582aa97516af10b9f5c0d640da2c28e08d4c713f08c85716"}, - {file = "ckzg-2.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:242ffeb6607a8b860849bd6fdd4f3fbbc2c547e65fd80e8482787fe84c4b910f"}, - {file = "ckzg-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb2ca4ed9ed3cd5cdbd51f4dd00e16d71387923e474888a5546a301a699a0d75"}, - {file = "ckzg-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:7b8f291918ce4ab56bdef4b47c9a7348d7acaa429a6cc17ec5e250784ffe6e6e"}, - {file = "ckzg-2.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:27c9018d9e1e32db5a39a23ad6eb410b1fb2f11db86c98f6630ab0af70578092"}, - {file = "ckzg-2.0.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8e9a6cbce7cc663ab965837dc87690f1707f0e81fb74dccc0395c2a1bc2a648"}, - {file = "ckzg-2.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b9a954de7e255f0213cae602dbda532b055c7a454e5155389186fa1780b1660"}, - {file = "ckzg-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49a28b3756c7f46a33581bf84d616548569e6b7691f75e27d105f351e033ba36"}, - {file = "ckzg-2.0.0-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:29853f5cd7d4a32fb691d02a483461c570dfc81d6590b1103560f015ebe2562b"}, - {file = "ckzg-2.0.0-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:f9b0acdd393b8f4b2f5d71f726a06048f208290a9f167d6360263445bcda1b6e"}, - {file = "ckzg-2.0.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:17e690e9c108bcab084c9e68e2c705803dbc97583c9b3403b0bf11e9923ffb86"}, - {file = "ckzg-2.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:dc50657be6d1f4a1625e2f25877d95720517aca74255b846f32532dde3fcdccf"}, - {file = "ckzg-2.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4535975f2bd4196b24668c82a0482ad818aa1d00a92d35b6c01f7b4b9ac86f85"}, - {file = "ckzg-2.0.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54ddeca701d452c670a982b849c7239cf25ea4ac4784ccac30bd86d3a3ef48ef"}, - {file = "ckzg-2.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:441ce60d984c1043a4553ed06ad81c5b05db4c1ab0ccc54c60617bed0bda4d8e"}, - {file = "ckzg-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc03330e6bf762aa361079238115f90996fca030ac12759b2b48b4019e01ac96"}, - {file = "ckzg-2.0.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:e1cbe124610440f99e1a495f01b09b67b89e04f4b48fd42a36524d999cafed97"}, - {file = "ckzg-2.0.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:d7541c35c5feae75da34415510d615209f3f70cb27a61ce122cec596b9a7e0a3"}, - {file = "ckzg-2.0.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9b75fabdf188927d63fb0a3fd049b8361a0c37fc5ef12623556219a9a759c893"}, - {file = "ckzg-2.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:12db77d3f7ec682899107bc034c2d2bb067ee0c74f534bc6ca4efcab37064fe0"}, - {file = "ckzg-2.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:17530983bd3eafc786e5e04df4f060a737214064de72f4f33898e00bcb16ca0f"}, - {file = "ckzg-2.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e88c1e569700c618eabca08ca708acb1b89adebc2a834033e240160d780bf85e"}, - {file = "ckzg-2.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:225ea65947d6b665af740e6abde64708af4793c85abeeacdf340f655c6eba0d9"}, - {file = "ckzg-2.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e10f741f97af7686b8647b84f867dd4a307d2525263b44375cfed631879c0c4f"}, - {file = "ckzg-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19a1cb81c13ef688e52c69d8bcbef648a8a99b759f33fa0a185c6b5af89a7d49"}, - {file = "ckzg-2.0.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6f5e3dbda8618502e86d8089e80f45b685302eaf16f226b484ea24ec605e5562"}, - {file = "ckzg-2.0.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ac1c457d15bc10305cd19b1356c035412b8d1debde8f8278cdde34f2c1621ea9"}, - {file = "ckzg-2.0.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ad3d3d3cfcacdcb09cc8372c71edf66d9912051133727a17bc0f1318ef3c8f9b"}, - {file = "ckzg-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1449f93f3df6ad414d8c7c002d920ac2101444bd56e760066d270fd5e236962"}, - {file = "ckzg-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cfaf02084d38def0faa889f0a6cdcf13e61476a3289adbd375abd57bc612ff9a"}, - {file = "ckzg-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1af739ef793f611068892230e34d843750f7d4ec5407d2b6aa8157b09eeb0eb"}, - {file = "ckzg-2.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddbc4eb124bb92f4abc820764e6cb2d2f87c5346de52b8e57c7d853269d3467d"}, - {file = "ckzg-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c20efefdbb7eea2335739788b1934b88d5f3ac2c4dea1d8e4c08c1af6eb3b24"}, - {file = "ckzg-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8e0031c5350033a91a77dad40ba10e13f25f3882b3f863cee8ad55c22c765a9"}, - {file = "ckzg-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1816c1478d3b1505f80ed991c761aac5dfdcfa6fc930a75b50101d666f239cad"}, - {file = "ckzg-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dd499405ba9e55f6b44f5d6e087a476736e5c7a1976c32363cdc2e614ed34c5f"}, - {file = "ckzg-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:24a86e8cc2c1dd73176ecad33eeb0445ca3276589532b94960be82f3bdff74de"}, - {file = "ckzg-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:ebc97111f65fb287443859433a8592a2366eb3ed8abd997a611b060a509e6aed"}, - {file = "ckzg-2.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bdad8f56de4c80b35c5beff8918912e78c86e6d6187a55b894d24206e7abfeb1"}, - {file = "ckzg-2.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9694bbf6a474ab6d708c7f1aee58d496669239594a4e63a482a710fe43db7f58"}, - {file = "ckzg-2.0.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e44090cf42f038a51e2b097cd8a1d0f9d6c2a1ac6cc44322393719663216a33"}, - {file = "ckzg-2.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bd980b20aaf3edd40d16dd061b0126d8fafe3481d222422e6790ff4e995df"}, - {file = "ckzg-2.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646d0e4427887a8ebf54d42acec31ba86cab5a9537a51fb833135023bfbd1481"}, - {file = "ckzg-2.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2578c1c47397b65d5bc30d53644e626e250f4f131859cbd727849d05b3ba14c3"}, - {file = "ckzg-2.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:69c0af3917e067de61bddd4e73a0d56daad690e845f38592d3dd525810ff3391"}, - {file = "ckzg-2.0.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:085562e98e0edd8285caeb0b7d512aba7c1d059d0451da9fdb56e547e12c7588"}, - {file = "ckzg-2.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92db021e56fd78812d722160a7f20695b45ab5336c1ac39f99b23a297ccede6"}, - {file = "ckzg-2.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e35a3c9f846879a87f13cae4fd50822c5ed239e0221f3735b7e201e597f1ffde"}, - {file = "ckzg-2.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3589a4e14cbba65be5b1e6a87343ca530681be8654c65ccdf24c90d1b52f3bb3"}, - {file = "ckzg-2.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0f6cee7a72fc1c91cfef31f53935dca8da5e8996d3bbe2953a9e9591d05db964"}, - {file = "ckzg-2.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:c2c103eb7e2d3996430597b9b2f1223ab50cff8d807d3c1de2506ac47fe60e05"}, - {file = "ckzg-2.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f86b993b12f1d0d052003ba4600fe870d6e98ee347d3d924955c47ec2d62a53"}, - {file = "ckzg-2.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ac6c832ad7bf24520371affb63d27044a5e8c338afb572677a0df4a13937cd3"}, - {file = "ckzg-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83dbc5291bc54ba1ffc61f74473ca2f0cd65e7519e0e3ea0e78d8b391df5f377"}, - {file = "ckzg-2.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b53f346f0c673b707bc858df5d1582b86991319d3b08037f623a8f6da09819f0"}, - {file = "ckzg-2.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:affcf68c1c712534ac581b03d443319d7798b640806d05b555f7a4df1d873dff"}, - {file = "ckzg-2.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bed3b49833516dc5ec5701a35f2e1d8f4cffe53e5c7e3e20d34748d55ac00255"}, - {file = "ckzg-2.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea13ac6003127a48c1c6c103249890111810a03e865655bc04236afe515e26db"}, - {file = "ckzg-2.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19f7c2ecf31a0f3d0f02e0de133a98bd09c640a7a6600a836dfc6584a0066d8a"}, - {file = "ckzg-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90cb5aa0142485003bfb1fe577517d667bf64f2e7dc7d1fe850baef548e57589"}, - {file = "ckzg-2.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cd051e233a60bdd98b4df8f0d0f7db0a652c3f04c24942426882468e6cf2162b"}, - {file = "ckzg-2.0.0.tar.gz", hash = "sha256:cd115a39cbc301b8465f6e19191cbb375b3589f3458cc995122595649a6f193f"}, -] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "cytoolz" -version = "0.12.3" -description = "Cython implementation of Toolz: High performance functional utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cytoolz-0.12.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bbe58e26c84b163beba0fbeacf6b065feabc8f75c6d3fe305550d33f24a2d346"}, - {file = "cytoolz-0.12.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c51b66ada9bfdb88cf711bf350fcc46f82b83a4683cf2413e633c31a64df6201"}, - {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e70d9c615e5c9dc10d279d1e32e846085fe1fd6f08d623ddd059a92861f4e3dd"}, - {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a83f4532707963ae1a5108e51fdfe1278cc8724e3301fee48b9e73e1316de64f"}, - {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d028044524ee2e815f36210a793c414551b689d4f4eda28f8bbb0883ad78bf5f"}, - {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c2875bcd1397d0627a09a4f9172fa513185ad302c63758efc15b8eb33cc2a98"}, - {file = "cytoolz-0.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:131ff4820e5d64a25d7ad3c3556f2d8aa65c66b3f021b03f8a8e98e4180dd808"}, - {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:04afa90d9d9d18394c40d9bed48c51433d08b57c042e0e50c8c0f9799735dcbd"}, - {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dc1ca9c610425f9854323669a671fc163300b873731584e258975adf50931164"}, - {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bfa3f8e01bc423a933f2e1c510cbb0632c6787865b5242857cc955cae220d1bf"}, - {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:f702e295dddef5f8af4a456db93f114539b8dc2a7a9bc4de7c7e41d169aa6ec3"}, - {file = "cytoolz-0.12.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0fbad1fb9bb47e827d00e01992a099b0ba79facf5e5aa453be066033232ac4b5"}, - {file = "cytoolz-0.12.3-cp310-cp310-win32.whl", hash = "sha256:8587c3c3dbe78af90c5025288766ac10dc2240c1e76eb0a93a4e244c265ccefd"}, - {file = "cytoolz-0.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e45803d9e75ef90a2f859ef8f7f77614730f4a8ce1b9244375734567299d239"}, - {file = "cytoolz-0.12.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ac4f2fb38bbc67ff1875b7d2f0f162a247f43bd28eb7c9d15e6175a982e558d"}, - {file = "cytoolz-0.12.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0cf1e1e96dd86829a0539baf514a9c8473a58fbb415f92401a68e8e52a34ecd5"}, - {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08a438701c6141dd34eaf92e9e9a1f66e23a22f7840ef8a371eba274477de85d"}, - {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b6f11b0d7ed91be53166aeef2a23a799e636625675bb30818f47f41ad31821"}, - {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7fde09384d23048a7b4ac889063761e44b89a0b64015393e2d1d21d5c1f534a"}, - {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d3bfe45173cc8e6c76206be3a916d8bfd2214fb2965563e288088012f1dabfc"}, - {file = "cytoolz-0.12.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27513a5d5b6624372d63313574381d3217a66e7a2626b056c695179623a5cb1a"}, - {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d294e5e81ff094fe920fd545052ff30838ea49f9e91227a55ecd9f3ca19774a0"}, - {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:727b01a2004ddb513496507a695e19b5c0cfebcdfcc68349d3efd92a1c297bf4"}, - {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:fe1e1779a39dbe83f13886d2b4b02f8c4b10755e3c8d9a89b630395f49f4f406"}, - {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:de74ef266e2679c3bf8b5fc20cee4fc0271ba13ae0d9097b1491c7a9bcadb389"}, - {file = "cytoolz-0.12.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e04d22049233394e0b08193aca9737200b4a2afa28659d957327aa780ddddf2"}, - {file = "cytoolz-0.12.3-cp311-cp311-win32.whl", hash = "sha256:20d36430d8ac809186736fda735ee7d595b6242bdb35f69b598ef809ebfa5605"}, - {file = "cytoolz-0.12.3-cp311-cp311-win_amd64.whl", hash = "sha256:780c06110f383344d537f48d9010d79fa4f75070d214fc47f389357dd4f010b6"}, - {file = "cytoolz-0.12.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:86923d823bd19ce35805953b018d436f6b862edd6a7c8b747a13d52b39ed5716"}, - {file = "cytoolz-0.12.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3e61acfd029bfb81c2c596249b508dfd2b4f72e31b7b53b62e5fb0507dd7293"}, - {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd728f4e6051af6af234651df49319da1d813f47894d4c3c8ab7455e01703a37"}, - {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe8c6267caa7ec67bcc37e360f0d8a26bc3bdce510b15b97f2f2e0143bdd3673"}, - {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99462abd8323c52204a2a0ce62454ce8fa0f4e94b9af397945c12830de73f27e"}, - {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da125221b1fa25c690fcd030a54344cecec80074df018d906fc6a99f46c1e3a6"}, - {file = "cytoolz-0.12.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c18e351956f70db9e2d04ff02f28e9a41839250d3f936a4c8a1eabd1c3094d2"}, - {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:921e6d2440ac758c4945c587b1d1d9b781b72737ac0c0ca5d5e02ca1db8bded2"}, - {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1651a9bd591a8326329ce1d6336f3129161a36d7061a4d5ea9e5377e033364cf"}, - {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8893223b87c2782bd59f9c4bd5c7bf733edd8728b523c93efb91d7468b486528"}, - {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:e4d2961644153c5ae186db964aa9f6109da81b12df0f1d3494b4e5cf2c332ee2"}, - {file = "cytoolz-0.12.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:71b6eb97f6695f7ba8ce69c49b707a351c5f46fd97f5aeb5f6f2fb0d6e72b887"}, - {file = "cytoolz-0.12.3-cp312-cp312-win32.whl", hash = "sha256:cee3de65584e915053412cd178729ff510ad5f8f585c21c5890e91028283518f"}, - {file = "cytoolz-0.12.3-cp312-cp312-win_amd64.whl", hash = "sha256:9eef0d23035fa4dcfa21e570961e86c375153a7ee605cdd11a8b088c24f707f6"}, - {file = "cytoolz-0.12.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9a38332cfad2a91e89405b7c18b3f00e2edc951c225accbc217597d3e4e9fde"}, - {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f501ae1353071fa5d6677437bbeb1aeb5622067dce0977cedc2c5ec5843b202"}, - {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56f899758146a52e2f8cfb3fb6f4ca19c1e5814178c3d584de35f9e4d7166d91"}, - {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:800f0526adf9e53d3c6acda748f4def1f048adaa780752f154da5cf22aa488a2"}, - {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0976a3fcb81d065473173e9005848218ce03ddb2ec7d40dd6a8d2dba7f1c3ae"}, - {file = "cytoolz-0.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c835eab01466cb67d0ce6290601ebef2d82d8d0d0a285ed0d6e46989e4a7a71a"}, - {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4fba0616fcd487e34b8beec1ad9911d192c62e758baa12fcb44448b9b6feae22"}, - {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6f6e8207d732651e0204779e1ba5a4925c93081834570411f959b80681f8d333"}, - {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8119bf5961091cfe644784d0bae214e273b3b3a479f93ee3baab97bbd995ccfe"}, - {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7ad1331cb68afeec58469c31d944a2100cee14eac221553f0d5218ace1a0b25d"}, - {file = "cytoolz-0.12.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:92c53d508fb8a4463acc85b322fa24734efdc66933a5c8661bdc862103a3373d"}, - {file = "cytoolz-0.12.3-cp37-cp37m-win32.whl", hash = "sha256:2c6dd75dae3d84fa8988861ab8b1189d2488cb8a9b8653828f9cd6126b5e7abd"}, - {file = "cytoolz-0.12.3-cp37-cp37m-win_amd64.whl", hash = "sha256:caf07a97b5220e6334dd32c8b6d8b2bd255ca694eca5dfe914bb5b880ee66cdb"}, - {file = "cytoolz-0.12.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ed0cfb9326747759e2ad81cb6e45f20086a273b67ac3a4c00b19efcbab007c60"}, - {file = "cytoolz-0.12.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:96a5a0292575c3697121f97cc605baf2fd125120c7dcdf39edd1a135798482ca"}, - {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b76f2f50a789c44d6fd7f773ec43d2a8686781cd52236da03f7f7d7998989bee"}, - {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2905fdccacc64b4beba37f95cab9d792289c80f4d70830b70de2fc66c007ec01"}, - {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ebe23028eac51251f22ba01dba6587d30aa9c320372ca0c14eeab67118ec3f"}, - {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96c715404a3825e37fe3966fe84c5f8a1f036e7640b2a02dbed96cac0c933451"}, - {file = "cytoolz-0.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bac0adffc1b6b6a4c5f1fd1dd2161afb720bcc771a91016dc6bdba59af0a5d3"}, - {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:37441bf4a2a4e2e0fe9c3b0ea5e72db352f5cca03903977ffc42f6f6c5467be9"}, - {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f04037302049cb30033f7fa4e1d0e44afe35ed6bfcf9b380fc11f2a27d3ed697"}, - {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f37b60e66378e7a116931d7220f5352186abfcc950d64856038aa2c01944929c"}, - {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ec9be3e4b6f86ea8b294d34c990c99d2ba6c526ef1e8f46f1d52c263d4f32cd7"}, - {file = "cytoolz-0.12.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e9199c9e3fbf380a92b8042c677eb9e7ed4bccb126de5e9c0d26f5888d96788"}, - {file = "cytoolz-0.12.3-cp38-cp38-win32.whl", hash = "sha256:18cd61e078bd6bffe088e40f1ed02001387c29174750abce79499d26fa57f5eb"}, - {file = "cytoolz-0.12.3-cp38-cp38-win_amd64.whl", hash = "sha256:765b8381d4003ceb1a07896a854eee2c31ebc950a4ae17d1e7a17c2a8feb2a68"}, - {file = "cytoolz-0.12.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b4a52dd2a36b0a91f7aa50ca6c8509057acc481a24255f6cb07b15d339a34e0f"}, - {file = "cytoolz-0.12.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:581f1ce479769fe7eeb9ae6d87eadb230df8c7c5fff32138162cdd99d7fb8fc3"}, - {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46f505d4c6eb79585c8ad0b9dc140ef30a138c880e4e3b40230d642690e36366"}, - {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59276021619b432a5c21c01cda8320b9cc7dbc40351ffc478b440bfccd5bbdd3"}, - {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e44f4c25e1e7cf6149b499c74945a14649c8866d36371a2c2d2164e4649e7755"}, - {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c64f8e60c1dd69e4d5e615481f2d57937746f4a6be2d0f86e9e7e3b9e2243b5e"}, - {file = "cytoolz-0.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33c63186f3bf9d7ef1347bc0537bb9a0b4111a0d7d6e619623cabc18fef0dc3b"}, - {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fdddb9d988405f24035234f1e8d1653ab2e48cc2404226d21b49a129aefd1d25"}, - {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6986632d8a969ea1e720990c818dace1a24c11015fd7c59b9fea0b65ef71f726"}, - {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0ba1cbc4d9cd7571c917f88f4a069568e5121646eb5d82b2393b2cf84712cf2a"}, - {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7d267ffc9a36c0a9a58c7e0adc9fa82620f22e4a72533e15dd1361f57fc9accf"}, - {file = "cytoolz-0.12.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95e878868a172a41fbf6c505a4b967309e6870e22adc7b1c3b19653d062711fa"}, - {file = "cytoolz-0.12.3-cp39-cp39-win32.whl", hash = "sha256:8e21932d6d260996f7109f2a40b2586070cb0a0cf1d65781e156326d5ebcc329"}, - {file = "cytoolz-0.12.3-cp39-cp39-win_amd64.whl", hash = "sha256:0d8edfbc694af6c9bda4db56643fb8ed3d14e47bec358c2f1417de9a12d6d1fb"}, - {file = "cytoolz-0.12.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:55f9bd1ae6c2a27eda5abe2a0b65a83029d2385c5a1da7b8ef47af5905d7e905"}, - {file = "cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2d271393c378282727f1231d40391ae93b93ddc0997448acc21dd0cb6a1e56d"}, - {file = "cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee98968d6a66ee83a8ceabf31182189ab5d8598998c8ce69b6d5843daeb2db60"}, - {file = "cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01cfb8518828c1189200c02a5010ea404407fb18fd5589e29c126e84bbeadd36"}, - {file = "cytoolz-0.12.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:456395d7aec01db32bf9e6db191d667347c78d8d48e77234521fa1078f60dabb"}, - {file = "cytoolz-0.12.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:cd88028bb897fba99ddd84f253ca6bef73ecb7bdf3f3cf25bc493f8f97d3c7c5"}, - {file = "cytoolz-0.12.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b19223e7f7bd7a73ec3aa6fdfb73b579ff09c2bc0b7d26857eec2d01a58c76"}, - {file = "cytoolz-0.12.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a79d72b08048a0980a59457c239555f111ac0c8bdc140c91a025f124104dbb4"}, - {file = "cytoolz-0.12.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dd70141b32b717696a72b8876e86bc9c6f8eff995c1808e299db3541213ff82"}, - {file = "cytoolz-0.12.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a1445c91009eb775d479e88954c51d0b4cf9a1e8ce3c503c2672d17252882647"}, - {file = "cytoolz-0.12.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ca6a9a9300d5bda417d9090107c6d2b007683efc59d63cc09aca0e7930a08a85"}, - {file = "cytoolz-0.12.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be6feb903d2a08a4ba2e70e950e862fd3be9be9a588b7c38cee4728150a52918"}, - {file = "cytoolz-0.12.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b6f43f086e5a965d33d62a145ae121b4ccb6e0789ac0acc895ce084fec8c65"}, - {file = "cytoolz-0.12.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:534fa66db8564d9b13872d81d54b6b09ae592c585eb826aac235bd6f1830f8ad"}, - {file = "cytoolz-0.12.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:fea649f979def23150680de1bd1d09682da3b54932800a0f90f29fc2a6c98ba8"}, - {file = "cytoolz-0.12.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a447247ed312dd64e3a8d9483841ecc5338ee26d6e6fbd29cd373ed030db0240"}, - {file = "cytoolz-0.12.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba3f843aa89f35467b38c398ae5b980a824fdbdb94065adc6ec7c47a0a22f4c7"}, - {file = "cytoolz-0.12.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:582c22f97a380211fb36a7b65b1beeb84ea11d82015fa84b054be78580390082"}, - {file = "cytoolz-0.12.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47feb089506fc66e1593cd9ade3945693a9d089a445fbe9a11385cab200b9f22"}, - {file = "cytoolz-0.12.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ba9002d2f043943744a9dc8e50a47362bcb6e6f360dc0a1abcb19642584d87bb"}, - {file = "cytoolz-0.12.3.tar.gz", hash = "sha256:4503dc59f4ced53a54643272c61dc305d1dbbfbd7d6bdf296948de9f34c3a282"}, -] - -[package.dependencies] -toolz = ">=0.8.0" - -[package.extras] -cython = ["cython"] - -[[package]] -name = "ecdsa" -version = "0.19.0" -description = "ECDSA cryptographic signature library (pure python)" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" -files = [ - {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, - {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, -] - -[package.dependencies] -six = ">=1.9.0" - -[package.extras] -gmpy = ["gmpy"] -gmpy2 = ["gmpy2"] - -[[package]] -name = "eth-abi" -version = "5.1.0" -description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "eth_abi-5.1.0-py3-none-any.whl", hash = "sha256:84cac2626a7db8b7d9ebe62b0fdca676ab1014cc7f777189e3c0cd721a4c16d8"}, - {file = "eth_abi-5.1.0.tar.gz", hash = "sha256:33ddd756206e90f7ddff1330cc8cac4aa411a824fe779314a0a52abea2c8fc14"}, -] - -[package.dependencies] -eth-typing = ">=3.0.0" -eth-utils = ">=2.0.0" -parsimonious = ">=0.10.0,<0.11.0" - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-timeout (>=2.0.0)", "pytest-xdist (>=2.4.0)"] -tools = ["hypothesis (>=4.18.2,<5.0.0)"] - -[[package]] -name = "eth-account" -version = "0.13.3" -description = "eth-account: Sign Ethereum transactions and messages with local private keys" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "eth_account-0.13.3-py3-none-any.whl", hash = "sha256:c8f3dae3403b8647f386fcc081fb8c2a0970991cf3e00af7e7ebd73f95d6a319"}, - {file = "eth_account-0.13.3.tar.gz", hash = "sha256:03d6af5d314e64b3dd53283e15b24736c5caa24542e5edac0455d6ff87d8b1e0"}, -] - -[package.dependencies] -bitarray = ">=2.4.0" -ckzg = ">=2.0.0" -eth-abi = ">=4.0.0-b.2" -eth-keyfile = ">=0.7.0" -eth-keys = ">=0.4.0" -eth-rlp = ">=2.1.0" -eth-utils = ">=2.0.0" -hexbytes = ">=1.2.0" -pydantic = ">=2.0.0" -rlp = ">=1.0.0" - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "coverage", "hypothesis (>=4.18.0,<5)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "eth-hash" -version = "0.7.0" -description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" -optional = false -python-versions = ">=3.8, <4" -files = [ - {file = "eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a"}, - {file = "eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f"}, -] - -[package.dependencies] -pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -pycryptodome = ["pycryptodome (>=3.6.6,<4)"] -pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] -test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -description = "eth-keyfile: A library for handling the encrypted keyfiles used to store ethereum private keys" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64"}, - {file = "eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1"}, -] - -[package.dependencies] -eth-keys = ">=0.4.0" -eth-utils = ">=2" -pycryptodome = ">=3.6.6,<4" - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["towncrier (>=21,<22)"] -test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "eth-keys" -version = "0.5.1" -description = "eth-keys: Common API for Ethereum key operations" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "eth_keys-0.5.1-py3-none-any.whl", hash = "sha256:ad13d920a2217a49bed3a1a7f54fb0980f53caf86d3bbab2139fd3330a17b97e"}, - {file = "eth_keys-0.5.1.tar.gz", hash = "sha256:2b587e4bbb9ac2195215a7ab0c0fb16042b17d4ec50240ed670bbb8f53da7a48"}, -] - -[package.dependencies] -eth-typing = ">=3" -eth-utils = ">=2" - -[package.extras] -coincurve = ["coincurve (>=12.0.0)"] -dev = ["asn1tools (>=0.146.2)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "coincurve (>=12.0.0)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "ipython", "pre-commit (>=3.4.0)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["towncrier (>=21,<22)"] -test = ["asn1tools (>=0.146.2)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)"] - -[[package]] -name = "eth-rlp" -version = "2.1.0" -description = "eth-rlp: RLP definitions for common Ethereum objects in Python" -optional = false -python-versions = ">=3.8, <4" -files = [ - {file = "eth-rlp-2.1.0.tar.gz", hash = "sha256:d5b408a8cd20ed496e8e66d0559560d29bc21cee482f893936a1f05d0dddc4a0"}, - {file = "eth_rlp-2.1.0-py3-none-any.whl", hash = "sha256:6f476eb7e37d81feaba5d98aed887e467be92648778c44b19fe594aea209cde1"}, -] - -[package.dependencies] -eth-utils = ">=2.0.0" -hexbytes = ">=1.2.0" -rlp = ">=0.6.0" -typing-extensions = {version = ">=4.0.1", markers = "python_version <= \"3.10\""} - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "eth-typing" -version = "5.0.0" -description = "eth-typing: Common type annotations for ethereum python packages" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "eth_typing-5.0.0-py3-none-any.whl", hash = "sha256:c7ebc8595e7b65175bb4b4176c2b548ab21b13329f2058e84d4f8c289ba9f577"}, - {file = "eth_typing-5.0.0.tar.gz", hash = "sha256:87ce7cee75665c09d2dcff8de1b496609d5e32fcd2e2b1d8fc0370c29eedcdc0"}, -] - -[package.dependencies] -typing-extensions = ">=4.5.0" - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "eth-utils" -version = "5.0.0" -description = "eth-utils: Common utility functions for python code that interacts with Ethereum" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "eth_utils-5.0.0-py3-none-any.whl", hash = "sha256:99c44eca11db74dbb881a1d70b24cd80436fc62fe527d2f5c3e3cf7932aba7b2"}, - {file = "eth_utils-5.0.0.tar.gz", hash = "sha256:a5eb9555f43f4579eb83cb84f9dda9f3d6663bbd4a5a6b693f8d35045f305a1f"}, -] - -[package.dependencies] -cytoolz = {version = ">=0.10.1", markers = "implementation_name == \"cpython\""} -eth-hash = ">=0.3.1" -eth-typing = ">=5.0.0" -hexbytes = ">=1.0.0" -toolz = {version = ">0.8.2", markers = "implementation_name == \"pypy\""} - -[package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-hash[pycryptodome]", "hypothesis (>=4.43.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["hypothesis (>=4.43.0)", "mypy (==1.10.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "execnet" -version = "2.1.1" -description = "execnet: rapid multi-Python deployment" -optional = false -python-versions = ">=3.8" -files = [ - {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, - {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, -] - -[package.extras] -testing = ["hatch", "pre-commit", "pytest", "tox"] - -[[package]] -name = "fastecdsa" -version = "2.3.2" -description = "Fast elliptic curve digital signatures" -optional = false -python-versions = ">=3.7" -files = [ - {file = "fastecdsa-2.3.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:138278b123b6c519f24fe9043d857e2f92c421c4fe256ac80d57404a38dc1326"}, - {file = "fastecdsa-2.3.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5ba5eb5b33d4b861731108d0ac6e544fcdbdc1ab095a5e86e68081ba5713c958"}, - {file = "fastecdsa-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc7189b971bc434b4145c9e7084e4970a0817623927a647b70fb162060baaea2"}, - {file = "fastecdsa-2.3.2-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:08deada741efb94691873d50c0002b2b826bc41459f0d427fbc1a791176e7c2d"}, - {file = "fastecdsa-2.3.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:398448290a70bede54f1a8878e797865c40f359ca5840dd12fa33cab277b3b47"}, - {file = "fastecdsa-2.3.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:368f757403f191560d6e0757b8580a58c7b0b53d4db0fa8154b398c1de9f733d"}, - {file = "fastecdsa-2.3.2.tar.gz", hash = "sha256:f35255a6d3e41109166b5d4b08866d5acbb99f2e1e64d3a7e74c774664cda842"}, -] - -[[package]] -name = "frozendict" -version = "2.4.4" -description = "A simple immutable dictionary" -optional = false -python-versions = ">=3.6" -files = [ - {file = "frozendict-2.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4a59578d47b3949437519b5c39a016a6116b9e787bb19289e333faae81462e59"}, - {file = "frozendict-2.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12a342e439aef28ccec533f0253ea53d75fe9102bd6ea928ff530e76eac38906"}, - {file = "frozendict-2.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f79c26dff10ce11dad3b3627c89bb2e87b9dd5958c2b24325f16a23019b8b94"}, - {file = "frozendict-2.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2bd009cf4fc47972838a91e9b83654dc9a095dc4f2bb3a37c3f3124c8a364543"}, - {file = "frozendict-2.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:87ebcde21565a14fe039672c25550060d6f6d88cf1f339beac094c3b10004eb0"}, - {file = "frozendict-2.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:fefeb700bc7eb8b4c2dc48704e4221860d254c8989fb53488540bc44e44a1ac2"}, - {file = "frozendict-2.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:4297d694eb600efa429769125a6f910ec02b85606f22f178bafbee309e7d3ec7"}, - {file = "frozendict-2.4.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:812ab17522ba13637826e65454115a914c2da538356e85f43ecea069813e4b33"}, - {file = "frozendict-2.4.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fee9420475bb6ff357000092aa9990c2f6182b2bab15764330f4ad7de2eae49"}, - {file = "frozendict-2.4.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3148062675536724502c6344d7c485dd4667fdf7980ca9bd05e338ccc0c4471e"}, - {file = "frozendict-2.4.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:78c94991944dd33c5376f720228e5b252ee67faf3bac50ef381adc9e51e90d9d"}, - {file = "frozendict-2.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:1697793b5f62b416c0fc1d94638ec91ed3aa4ab277f6affa3a95216ecb3af170"}, - {file = "frozendict-2.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:199a4d32194f3afed6258de7e317054155bc9519252b568d9cfffde7e4d834e5"}, - {file = "frozendict-2.4.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85375ec6e979e6373bffb4f54576a68bf7497c350861d20686ccae38aab69c0a"}, - {file = "frozendict-2.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2d8536e068d6bf281f23fa835ac07747fb0f8851879dd189e9709f9567408b4d"}, - {file = "frozendict-2.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:259528ba6b56fa051bc996f1c4d8b57e30d6dd3bc2f27441891b04babc4b5e73"}, - {file = "frozendict-2.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:07c3a5dee8bbb84cba770e273cdbf2c87c8e035903af8f781292d72583416801"}, - {file = "frozendict-2.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6874fec816b37b6eb5795b00e0574cba261bf59723e2de607a195d5edaff0786"}, - {file = "frozendict-2.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8f92425686323a950337da4b75b4c17a3327b831df8c881df24038d560640d4"}, - {file = "frozendict-2.4.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d58d9a8d9e49662c6dafbea5e641f97decdb3d6ccd76e55e79818415362ba25"}, - {file = "frozendict-2.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:93a7b19afb429cbf99d56faf436b45ef2fa8fe9aca89c49eb1610c3bd85f1760"}, - {file = "frozendict-2.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b70b431e3a72d410a2cdf1497b3aba2f553635e0c0f657ce311d841bf8273b6"}, - {file = "frozendict-2.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:e1b941132d79ce72d562a13341d38fc217bc1ee24d8c35a20d754e79ff99e038"}, - {file = "frozendict-2.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc2228874eacae390e63fd4f2bb513b3144066a977dc192163c9f6c7f6de6474"}, - {file = "frozendict-2.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63aa49f1919af7d45fb8fd5dec4c0859bc09f46880bd6297c79bb2db2969b63d"}, - {file = "frozendict-2.4.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6bf9260018d653f3cab9bd147bd8592bf98a5c6e338be0491ced3c196c034a3"}, - {file = "frozendict-2.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6eb716e6a6d693c03b1d53280a1947716129f5ef9bcdd061db5c17dea44b80fe"}, - {file = "frozendict-2.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d13b4310db337f4d2103867c5a05090b22bc4d50ca842093779ef541ea9c9eea"}, - {file = "frozendict-2.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:b3b967d5065872e27b06f785a80c0ed0a45d1f7c9b85223da05358e734d858ca"}, - {file = "frozendict-2.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:4ae8d05c8d0b6134bfb6bfb369d5fa0c4df21eabb5ca7f645af95fdc6689678e"}, - {file = "frozendict-2.4.4-py311-none-any.whl", hash = "sha256:705efca8d74d3facbb6ace80ab3afdd28eb8a237bfb4063ed89996b024bc443d"}, - {file = "frozendict-2.4.4-py312-none-any.whl", hash = "sha256:d9647563e76adb05b7cde2172403123380871360a114f546b4ae1704510801e5"}, - {file = "frozendict-2.4.4.tar.gz", hash = "sha256:3f7c031b26e4ee6a3f786ceb5e3abf1181c4ade92dce1f847da26ea2c96008c7"}, -] - -[[package]] -name = "frozenlist" -version = "1.4.1" -description = "A list-like structure which implements collections.abc.MutableSequence" -optional = false -python-versions = ">=3.8" -files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, -] - -[[package]] -name = "gprof2dot" -version = "2024.6.6" -description = "Generate a dot graph from the output of several profilers." -optional = false -python-versions = ">=3.8" -files = [ - {file = "gprof2dot-2024.6.6-py2.py3-none-any.whl", hash = "sha256:45b14ad7ce64e299c8f526881007b9eb2c6b75505d5613e96e66ee4d5ab33696"}, - {file = "gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab"}, -] - -[[package]] -name = "hexbytes" -version = "1.2.1" -description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "hexbytes-1.2.1-py3-none-any.whl", hash = "sha256:e64890b203a31f4a23ef11470ecfcca565beaee9198df623047df322b757471a"}, - {file = "hexbytes-1.2.1.tar.gz", hash = "sha256:515f00dddf31053db4d0d7636dd16061c1d896c3109b8e751005db4ca46bcca7"}, -] - -[package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "idna" -version = "3.8" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.6" -files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "lark" -version = "1.2.2" -description = "a modern parsing library" -optional = false -python-versions = ">=3.8" -files = [ - {file = "lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c"}, - {file = "lark-1.2.2.tar.gz", hash = "sha256:ca807d0162cd16cef15a8feecb862d7319e7a09bdb13aef927968e45040fed80"}, -] - -[package.extras] -atomic-cache = ["atomicwrites"] -interegular = ["interegular (>=0.3.1,<0.4.0)"] -nearley = ["js2py"] -regex = ["regex"] - -[[package]] -name = "marshmallow" -version = "3.22.0" -description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -optional = false -python-versions = ">=3.8" -files = [ - {file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"}, - {file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"}, -] - -[package.dependencies] -packaging = ">=17.0" - -[package.extras] -dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] -tests = ["pytest", "pytz", "simplejson"] - -[[package]] -name = "marshmallow-dataclass" -version = "8.6.1" -description = "Python library to convert dataclasses into marshmallow schemas." -optional = false -python-versions = ">=3.6" -files = [ - {file = "marshmallow_dataclass-8.6.1-py3-none-any.whl", hash = "sha256:d941137bcb480729a14810e5f10d9bb79a498fb5b57c875aad6be37e97b98a5f"}, - {file = "marshmallow_dataclass-8.6.1.tar.gz", hash = "sha256:dca312c841f73f8f665b4434d23b3204e8cfbf50b8cbb57bb76f41a6ee8184c8"}, -] - -[package.dependencies] -marshmallow = ">=3.13.0,<4.0" -typing-extensions = {version = ">=4.2.0", markers = "python_version < \"3.11\" and python_version >= \"3.7\""} -typing-inspect = ">=0.8.0,<1.0" - -[package.extras] -dev = ["marshmallow (>=3.18.0,<4.0)", "marshmallow-enum", "pre-commit (>=2.17,<3.0)", "pytest (>=5.4)", "pytest-mypy-plugins (>=1.2.0)", "sphinx", "typeguard (>=2.4.1,<4.0.0)"] -docs = ["sphinx"] -enum = ["marshmallow (>=3.18.0,<4.0)", "marshmallow-enum"] -lint = ["pre-commit (>=2.17,<3.0)"] -tests = ["pytest (>=5.4)", "pytest-mypy-plugins (>=1.2.0)"] -union = ["typeguard (>=2.4.1,<4.0.0)"] - -[[package]] -name = "marshmallow-enum" -version = "1.5.1" -description = "Enum field for Marshmallow" -optional = false -python-versions = "*" -files = [ - {file = "marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58"}, - {file = "marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"}, -] - -[package.dependencies] -marshmallow = ">=2.0.0" - -[[package]] -name = "marshmallow-oneofschema" -version = "3.1.1" -description = "marshmallow multiplexing schema" -optional = false -python-versions = ">=3.8" -files = [ - {file = "marshmallow_oneofschema-3.1.1-py3-none-any.whl", hash = "sha256:ff4cb2a488785ee8edd521a765682c2c80c78b9dc48894124531bdfa1ec9303b"}, - {file = "marshmallow_oneofschema-3.1.1.tar.gz", hash = "sha256:68b4a57d0281a04ac25d4eb7a4c5865a57090a0a8fd30fd6362c8e833ac6a6d9"}, -] - -[package.dependencies] -marshmallow = ">=3.0.0,<4.0.0" - -[package.extras] -dev = ["marshmallow-oneofschema[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -tests = ["pytest"] - -[[package]] -name = "mpmath" -version = "1.3.0" -description = "Python library for arbitrary-precision floating-point arithmetic" -optional = false -python-versions = "*" -files = [ - {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, - {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, -] - -[package.extras] -develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] -docs = ["sphinx"] -gmpy = ["gmpy2 (>=2.1.0a4)"] -tests = ["pytest (>=4.6)"] - -[[package]] -name = "multidict" -version = "6.0.5" -description = "multidict implementation" -optional = false -python-versions = ">=3.7" -files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "numpy" -version = "2.1.0" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.10" -files = [ - {file = "numpy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6326ab99b52fafdcdeccf602d6286191a79fe2fda0ae90573c5814cd2b0bc1b8"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0937e54c09f7a9a68da6889362ddd2ff584c02d015ec92672c099b61555f8911"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:30014b234f07b5fec20f4146f69e13cfb1e33ee9a18a1879a0142fbb00d47673"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:899da829b362ade41e1e7eccad2cf274035e1cb36ba73034946fccd4afd8606b"}, - {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08801848a40aea24ce16c2ecde3b756f9ad756586fb2d13210939eb69b023f5b"}, - {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:398049e237d1aae53d82a416dade04defed1a47f87d18d5bd615b6e7d7e41d1f"}, - {file = "numpy-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0abb3916a35d9090088a748636b2c06dc9a6542f99cd476979fb156a18192b84"}, - {file = "numpy-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e2350aea18d04832319aac0f887d5fcec1b36abd485d14f173e3e900b83e33"}, - {file = "numpy-2.1.0-cp310-cp310-win32.whl", hash = "sha256:f6b26e6c3b98adb648243670fddc8cab6ae17473f9dc58c51574af3e64d61211"}, - {file = "numpy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:f505264735ee074250a9c78247ee8618292091d9d1fcc023290e9ac67e8f1afa"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, - {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, - {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, - {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, - {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, - {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, - {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15ef8b2177eeb7e37dd5ef4016f30b7659c57c2c0b57a779f1d537ff33a72c7b"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e5f0642cdf4636198a4990de7a71b693d824c56a757862230454629cf62e323d"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15976718c004466406342789f31b6673776360f3b1e3c575f25302d7e789575"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6c1de77ded79fef664d5098a66810d4d27ca0224e9051906e634b3f7ead134c2"}, - {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, -] - -[[package]] -name = "packaging" -version = "24.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -description = "(Soon to be) the fastest pure-Python PEG parser I could muster" -optional = false -python-versions = "*" -files = [ - {file = "parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f"}, - {file = "parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c"}, -] - -[package.dependencies] -regex = ">=2022.3.15" - -[[package]] -name = "pip" -version = "24.2" -description = "The PyPA recommended tool for installing Python packages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pip-24.2-py3-none-any.whl", hash = "sha256:2cd581cf58ab7fcfca4ce8efa6dcacd0de5bf8d0a3eb9ec927e07405f4d9e2a2"}, - {file = "pip-24.2.tar.gz", hash = "sha256:5b5e490b5e9cb275c879595064adce9ebd31b854e3e803740b72f9ccf34a45b8"}, -] - -[[package]] -name = "pipdeptree" -version = "2.23.1" -description = "Command line utility to show dependency tree of packages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pipdeptree-2.23.1-py3-none-any.whl", hash = "sha256:b610a1232eca8c2c0232fff03a88afe6fed01706c73a314615c368f023313a12"}, - {file = "pipdeptree-2.23.1.tar.gz", hash = "sha256:ebc9b232d7e8ca061826f1875fd4ccc823930f84f327d302019d2ca856f50973"}, -] - -[package.dependencies] -packaging = ">=23.1" -pip = ">=23.1.2" - -[package.extras] -graphviz = ["graphviz (>=0.20.1)"] -test = ["covdefaults (>=2.3)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-console-scripts (>=1.4.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "virtualenv (>=20.25,<21)"] - -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "prometheus-client" -version = "0.20.0" -description = "Python client for the Prometheus monitoring system." -optional = false -python-versions = ">=3.8" -files = [ - {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, - {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, -] - -[package.extras] -twisted = ["twisted"] - -[[package]] -name = "pycryptodome" -version = "3.20.0" -description = "Cryptographic library for Python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, - {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, - {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, - {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, - {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, - {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, - {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, - {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, -] - -[[package]] -name = "pydantic" -version = "2.8.2" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, - {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, -] - -[package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.20.1" -typing-extensions = [ - {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, - {version = ">=4.6.1", markers = "python_version < \"3.13\""}, -] - -[package.extras] -email = ["email-validator (>=2.0.0)"] - -[[package]] -name = "pydantic-core" -version = "2.20.1" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, - {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, - {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, - {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, - {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, - {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, - {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, - {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, - {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, - {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, - {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, - {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, - {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, - {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "pytest" -version = "8.3.2" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.5,<2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "0.24.0" -description = "Pytest support for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"}, - {file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"}, -] - -[package.dependencies] -pytest = ">=8.2,<9" - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] - -[[package]] -name = "pytest-profiling" -version = "1.7.0" -description = "Profiling plugin for py.test" -optional = false -python-versions = "*" -files = [ - {file = "pytest-profiling-1.7.0.tar.gz", hash = "sha256:93938f147662225d2b8bd5af89587b979652426a8a6ffd7e73ec4a23e24b7f29"}, - {file = "pytest_profiling-1.7.0-py2.py3-none-any.whl", hash = "sha256:999cc9ac94f2e528e3f5d43465da277429984a1c237ae9818f8cfd0b06acb019"}, -] - -[package.dependencies] -gprof2dot = "*" -pytest = "*" -six = "*" - -[package.extras] -tests = ["pytest-virtualenv"] - -[[package]] -name = "pytest-xdist" -version = "3.6.1" -description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, - {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, -] - -[package.dependencies] -execnet = ">=2.1" -pytest = ">=7.0.0" - -[package.extras] -psutil = ["psutil (>=3.0)"] -setproctitle = ["setproctitle"] -testing = ["filelock"] - -[[package]] -name = "pyunormalize" -version = "15.1.0" -description = "Unicode normalization forms (NFC, NFKC, NFD, NFKD). A library independent from the Python core Unicode database." -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyunormalize-15.1.0.tar.gz", hash = "sha256:cf4a87451a0f1cb76911aa97f432f4579e1f564a2f0c84ce488c73a73901b6c1"}, -] - -[[package]] -name = "pywin32" -version = "306" -description = "Python for Window Extensions" -optional = false -python-versions = "*" -files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, -] - -[[package]] -name = "regex" -version = "2024.7.24" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.8" -files = [ - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"}, - {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"}, - {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, - {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, - {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, - {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, - {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"}, - {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"}, - {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"}, - {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"}, - {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"}, - {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, -] - -[[package]] -name = "requests" -version = "2.32.3" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.8" -files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "rlp" -version = "4.0.1" -description = "rlp: A package for Recursive Length Prefix encoding and decoding" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "rlp-4.0.1-py3-none-any.whl", hash = "sha256:ff6846c3c27b97ee0492373aa074a7c3046aadd973320f4fffa7ac45564b0258"}, - {file = "rlp-4.0.1.tar.gz", hash = "sha256:bcefb11013dfadf8902642337923bd0c786dc8a27cb4c21da6e154e52869ecb1"}, -] - -[package.dependencies] -eth-utils = ">=2" - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "hypothesis (==5.19.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -rust-backend = ["rusty-rlp (>=0.2.1)"] -test = ["hypothesis (==5.19.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sympy" -version = "1.13.2" -description = "Computer algebra system (CAS) in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "sympy-1.13.2-py3-none-any.whl", hash = "sha256:c51d75517712f1aed280d4ce58506a4a88d635d6b5dd48b39102a7ae1f3fcfe9"}, - {file = "sympy-1.13.2.tar.gz", hash = "sha256:401449d84d07be9d0c7a46a64bd54fe097667d5e7181bfe67ec777be9e01cb13"}, -] - -[package.dependencies] -mpmath = ">=1.1.0,<1.4" - -[package.extras] -dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "toolz" -version = "0.12.1" -description = "List processing tools and functional utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85"}, - {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, -] - -[[package]] -name = "typeguard" -version = "2.13.3" -description = "Run-time type checker for Python" -optional = false -python-versions = ">=3.5.3" -files = [ - {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"}, - {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"}, -] - -[package.extras] -doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["mypy", "pytest", "typing-extensions"] - -[[package]] -name = "types-requests" -version = "2.32.0.20240712" -description = "Typing stubs for requests" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358"}, - {file = "types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3"}, -] - -[package.dependencies] -urllib3 = ">=2" - -[[package]] -name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, -] - -[[package]] -name = "typing-inspect" -version = "0.9.0" -description = "Runtime inspection utilities for typing module." -optional = false -python-versions = "*" -files = [ - {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, - {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, -] - -[package.dependencies] -mypy-extensions = ">=0.3.0" -typing-extensions = ">=3.7.4" - -[[package]] -name = "urllib3" -version = "2.2.2" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "web3" -version = "7.1.0" -description = "web3: A Python library for interacting with Ethereum" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "web3-7.1.0-py3-none-any.whl", hash = "sha256:74001c60ae684ef6e46e41f7b3f6b96296a2df64c8402130d1733e787b7ff878"}, - {file = "web3-7.1.0.tar.gz", hash = "sha256:9d4dd41deb47fee7610db542cf79b314826b25d2b1768feaca5a486b4f719d47"}, -] - -[package.dependencies] -aiohttp = ">=3.7.4.post0" -eth-abi = ">=5.0.1" -eth-account = ">=0.13.1" -eth-hash = {version = ">=0.5.1", extras = ["pycryptodome"]} -eth-typing = ">=5.0.0" -eth-utils = ">=5.0.0" -hexbytes = ">=1.2.0" -pydantic = ">=2.4.0" -pyunormalize = ">=15.0.0" -pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} -requests = ">=2.23.0" -types-requests = ">=2.0.0" -typing-extensions = ">=4.0.1" -websockets = ">=10.0.0" - -[package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-tester[py-evm] (>=0.11.0b1,<0.13.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=5.0.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-asyncio (>=0.21.2,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "setuptools (>=38.6.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "tqdm (>4.32)", "twine (>=1.13)", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-tester[py-evm] (>=0.11.0b1,<0.13.0b1)", "py-geth (>=5.0.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)"] - -[[package]] -name = "websockets" -version = "13.0.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"}, - {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"}, - {file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"}, - {file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"}, - {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d"}, - {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f"}, - {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"}, - {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"}, - {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"}, - {file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"}, - {file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"}, - {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"}, - {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"}, - {file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"}, - {file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"}, - {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e"}, - {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462"}, - {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"}, - {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"}, - {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"}, - {file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"}, - {file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"}, - {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"}, - {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"}, - {file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"}, - {file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"}, - {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c"}, - {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4"}, - {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"}, - {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"}, - {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"}, - {file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"}, - {file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"}, - {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"}, - {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"}, - {file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"}, - {file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"}, - {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553"}, - {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920"}, - {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"}, - {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"}, - {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"}, - {file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"}, - {file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"}, - {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"}, - {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"}, - {file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"}, - {file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"}, - {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d3a1f041360f029765d8704eae606781e673e8918e6b2c792e0775de51352f"}, - {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67648f5e50231b5a7f6d83b32f9c525e319f0ddc841be0de64f24928cd75a603"}, - {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"}, - {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"}, - {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"}, - {file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"}, - {file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"}, - {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"}, - {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"}, - {file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"}, - {file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"}, - {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d20516990d8ad557b5abeb48127b8b779b0b7e6771a265fa3e91767596d7d97"}, - {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a2e272d067030048e1fe41aa1ec8cfbbaabce733b3d634304fa2b19e5c897f"}, - {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"}, - {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"}, - {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"}, - {file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"}, - {file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa74a45d4cdc028561a7d6ab3272c8b3018e23723100b12e58be9dfa5a24491"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00fd961943b6c10ee6f0b1130753e50ac5dcd906130dcd77b0003c3ab797d026"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6716c087e4aa0b9260c4e579bb82e068f84faddb9bfba9906cb87726fa2e870"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e33505534f3f673270dd67f81e73550b11de5b538c56fe04435d63c02c3f26b5"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"}, - {file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"}, - {file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"}, -] - -[[package]] -name = "yarl" -version = "1.9.4" -description = "Yet another URL library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, -] - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" - -[metadata] -lock-version = "2.0" -python-versions = "^3.10" -content-hash = "ce6d930272ee6c6fc2b565180eeaf4ae23ea21bf2ca910dd13f4a9d5178ef6c4" diff --git a/pyproject.toml b/pyproject.toml index 2576aafa..492e105d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,138 @@ -[tool.poetry] -name = "cairo_programs" +[project] +name = "keth" version = "0.1.0" -description = "Integration of the Kakarot Ethereum execution layer in the Reth client." -authors = [] +description = "Add your description here" readme = "README.md" +requires-python = ">=3.10" +dependencies = [] -[tool.poetry.dependencies] -python = "^3.10" -cairo-lang = "^0.13.2" +[tool.uv.workspace] +members = ["cairo"] +[tool.pytest.ini_options] +filterwarnings = [ + "ignore:Using or importing the ABCs:DeprecationWarning", # from frozendict + "ignore:lexer_state will be removed in subsequent releases. Use lexer_thread instead.", # from lark + "ignore:abi:DeprecationWarning", # from web3 + "ignore::marshmallow.warnings.RemovedInMarshmallow4Warning", # from marshmallow +] +markers = [ + "ArithmeticOperations", + "ADD: Opcode Value 0x01 - Addition operation", + "MUL: Opcode Value 0x02 - Multiplication operation", + "SUB: Opcode Value 0x03 - Subtraction operation", + "DIV: Opcode Value 0x04 - Integer division operation", + "SDIV: Opcode Value 0x05 - Signed integer division operation (truncated)", + "MOD: Opcode Value 0x06 - Modulo remainder operation", + "SMOD: Opcode Value 0x07 - Signed modulo remainder operation", + "ADDMOD: Opcode Value 0x08 - Modulo addition operation", + "MULMOD: Opcode Value 0x09 - Modulo multiplication operation", + "EXP: Opcode Value 0x0a - Exponential operation", + "SIGNEXTEND: Opcode Value 0x0b - Extend length of two's complement signed integer", + "ComparisonBitwiseLogicOperations", + "LT: Opcode Value 0x10 - Less-than comparison", + "GT: Opcode Value 0x11 - Greater-than comparison", + "SLT: Opcode Value 0x12 - Signed less-than comparison", + "SGT: Opcode Value 0x13 - Signed greater-than comparison", + "EQ: Opcode Value 0x14 - Equality comparison", + "ISZERO: Opcode Value 0x15 - Simple not operator", + "AND: Opcode Value 0x16 - Bitwise AND operation", + "OR: Opcode Value 0x17 - Bitwise OR operation", + "NOT: Opcode Value 0x19 - Bitwise NOT operation", + "SHL: Opcode Value 0x1b - Shift left", + "SHR: Opcode Value 0x1c - Logical shift right", + "SAR: Opcode Value 0x1d - Arithmetic shift right", + "SHA3: Opcode Value 0x20 - Compute Keccak-256 hash", + "EnvironmentalInformation", + "ADDRESS: Opcode Value 0x30 - Get address of currently executing account", + "BALANCE: Opcode Value 0x31 - Get balance of the given account", + "ORIGIN: Opcode Value 0x32 - Get execution origination address", + "CALLER: Opcode Value 0x33 - Get caller address", + "CALLVALUE: Opcode Value 0x34 - Get deposited value by the instruction/transaction responsible for this execution", + "CALLDATALOAD: Opcode Value 0x35 - Get input data of current environment", + "CALLDATASIZE: Opcode Value 0x36 - Get size of input data in current environment", + "CALLDATACOPY: Opcode Value 0x37 - Copy input data in current environment to memory", + "CODESIZE: Opcode Value 0x38 - Get size of code running in current environment", + "CODECOPY: Opcode Value 0x39 - Copy code running in current environment to memory", + "RETURNDATASIZE: Opcode Value 0x3d - Get size of output data from the previous call from the current environment", + "BlockInformation", + "BLOCKHASH: Opcode Value 0x40 - Get the hash of one of the 256 most recent complete blocks", + "COINBASE: Opcode Value 0x41 - Get the block's beneficiary address", + "TIMESTAMP: Opcode Value 0x42 - Get the block's timestamp", + "NUMBER: Opcode Value 0x43 - Get the block's number", + "DIFFICULTY: Opcode Value 0x44 - Get the block's difficulty", + "GASLIMIT: Opcode Value 0x45 - Get the block's gas limit", + "CHAINID: Opcode Value 0x46 - Get the chain ID", + "SELFBALANCE: Opcode Value 0x47 - Get the balance of the current contract", + "BASEFEE: Opcode Value 0x48 - Get the base fee of the current block", + "BLOBHASH: Opcode Value 0x49 - Get the versioned hash at the requested index", + "BLOBBASEFEE: Opcode Value 0x4a - Get the blob base-fee of the current block", + "StackMemoryStorageFlowOperations", + "MLOAD: Opcode Value 0x51 - Load word from memory", + "MSTORE: Opcode Value 0x52 - Save word to memory", + "MSTORE8: Opcode Value 0x53 - Save byte to memory", + "SLOAD: Opcode Value 0x54 - Load word from storage", + "SSTORE: Opcode Value 0x55 - Save word to storage", + "JUMP: Opcode Value 0x56 - Alter the program counter", + "JUMPI: Opcode Value 0x57 - Conditionally alter the program counter", + "PC: Opcode Value 0x58 - Get the value of the program counter prior to the increment", + "MSIZE: Opcode Value 0x59 - Get the size of active memory in bytes", + "JUMPDEST: Opcode Value 0x5b - Mark a valid destination for jumps", + "TLOAD: Opcode Value 0x5c - Load word from transient storage", + "TSTORE: Opcode Value 0x5d - Save word to transient storage", + "MCOPY: Opcode Value 0x5e - Copy memory from one location to another", + "PushOperations", + "PUSH Opcodes 0x60 ~ 7f - Place n-byte item on stack", + "DuplicationOperations", + "DUP: Opcodes 0x80 ~ 8f - Duplicate nth stack item", + "ExchangeOperations", + "SWAP: Opcodes 0x90 ~ 9f - Exchange 1st and nth stack items", + "LoggingOperations", + "LOG: Opcodes 0xa0 ~ a4 - Append log record with n topics", + "SystemOperations", + "RETURN: Opcode Value 0xf3 - Halt execution returning output data", + "REVERT: Opcode value 0xfd - Halt execution reverting state changes", + "INVALID: Opcode Value 0xfe - Designated invalid instruction", + "Precompiles", + "EC_RECOVER: Precompile Value 0x01 - Elliptic curve digital signature algorithm (ECDSA) public key recovery function", + "SHA256: Precompile Value 0x02 - Hash function", + "RIPEMD160: Precompile Value 0x03 - Hash function", + "MOD_EXP: Precompile Value 0x05 - Modular exponentiation MVP - missing support for bigint", + "EC_ADD: Precompile Value 0x06 - Point addition (ADD) on the elliptic curve 'alt_bn128'", + "EC_MUL: Precompile Value 0x07 - Scalar multiplication (MUL) on the elliptic curve 'alt_bn128'", + "BLAKE2F: Precompile Value 0x09 - Blake2 compression function", + "Counter", + "PlainOpcodes", + "SolmateERC20", + "SolmateERC721", + "UniswapV2ERC20", + "UniswapV2Factory", + "RIP7212", + "CairoPrecompiles", + "UniswapV2Router", + "AccountContract", + "Utils", + "Safe", + "EFTests", + "SSTORE", + "SLOAD", + "NoCI", + "slow", +] -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +[tool.isort] +profile = "black" + +[tool.autoflake] +in_place = true +remove_unused_variables = true +remove_all_unused_imports = true + +[tool.codespell] +ignore-words = '.codespellignore' +skip = '.git' +check-filenames = '' +check-hidden = '' + +[tool.bandit] +exclude_dirs = ["tests"] diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..df296105 --- /dev/null +++ b/uv.lock @@ -0,0 +1,2167 @@ +version = 1 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version < '3.13'", + "python_full_version >= '3.13'", +] + +[manifest] +members = [ + "cairo", + "keth", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f7/22bba300a16fd1cad99da1a23793fe43963ee326d012fdf852d0b4035955/aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2", size = 16786 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/b6/58ea188899950d759a837f9a58b2aee1d1a380ea4d6211ce9b1823748851/aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd", size = 12155 }, +] + +[[package]] +name = "aiohttp" +version = "3.10.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/28/ca549838018140b92a19001a8628578b0f2a3b38c16826212cc6f706e6d4/aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691", size = 7524360 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/4a/b27dd9b88fe22dde88742b341fd10251746a6ffcfe1c0b8b15b4a8cbd7c1/aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3", size = 587010 }, + { url = "https://files.pythonhosted.org/packages/de/a9/0f7e2b71549c9d641086c423526ae7a10de3b88d03ba104a3df153574d0d/aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6", size = 397698 }, + { url = "https://files.pythonhosted.org/packages/3b/52/26baa486e811c25b0cd16a494038260795459055568713f841e78f016481/aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699", size = 389052 }, + { url = "https://files.pythonhosted.org/packages/33/df/71ba374a3e925539cb2f6e6d4f5326e7b6b200fabbe1b3cc5e6368f07ce7/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6", size = 1248615 }, + { url = "https://files.pythonhosted.org/packages/67/02/bb89c1eba08a27fc844933bee505d63d480caf8e2816c06961d2941cd128/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1", size = 1282930 }, + { url = "https://files.pythonhosted.org/packages/db/36/07d8cfcc37f39c039f93a4210cc71dadacca003609946c63af23659ba656/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f", size = 1317250 }, + { url = "https://files.pythonhosted.org/packages/9a/44/cabeac994bef8ba521b552ae996928afc6ee1975a411385a07409811b01f/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb", size = 1243212 }, + { url = "https://files.pythonhosted.org/packages/5a/11/23f1e31f5885ac72be52fd205981951dd2e4c87c5b1487cf82fde5bbd46c/aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91", size = 1213401 }, + { url = "https://files.pythonhosted.org/packages/3f/e7/6e69a0b0d896fbaf1192d492db4c21688e6c0d327486da610b0e8195bcc9/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f", size = 1212450 }, + { url = "https://files.pythonhosted.org/packages/a9/7f/a42f51074c723ea848254946aec118f1e59914a639dc8ba20b0c9247c195/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c", size = 1211324 }, + { url = "https://files.pythonhosted.org/packages/d5/43/c2f9d2f588ccef8f028f0a0c999b5ceafecbda50b943313faee7e91f3e03/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69", size = 1266838 }, + { url = "https://files.pythonhosted.org/packages/c1/a7/ff9f067ecb06896d859e4f2661667aee4bd9c616689599ff034b63cbd9d7/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3", size = 1285301 }, + { url = "https://files.pythonhosted.org/packages/9a/e3/dd56bb4c67d216046ce61d98dec0f3023043f1de48f561df1bf93dd47aea/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683", size = 1235806 }, + { url = "https://files.pythonhosted.org/packages/a7/64/90dcd42ac21927a49ba4140b2e4d50e1847379427ef6c43eb338ef9960e3/aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef", size = 360162 }, + { url = "https://files.pythonhosted.org/packages/f3/45/145d8b4853fc92c0c8509277642767e7726a085e390ce04353dc68b0f5b5/aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088", size = 379173 }, + { url = "https://files.pythonhosted.org/packages/f1/90/54ccb1e4eadfb6c95deff695582453f6208584431d69bf572782e9ae542b/aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2", size = 586455 }, + { url = "https://files.pythonhosted.org/packages/c3/7a/95e88c02756e7e718f054e1bb3ec6ad5d0ee4a2ca2bb1768c5844b3de30a/aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf", size = 397255 }, + { url = "https://files.pythonhosted.org/packages/07/4f/767387b39990e1ee9aba8ce642abcc286d84d06e068dc167dab983898f18/aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e", size = 388973 }, + { url = "https://files.pythonhosted.org/packages/61/46/0df41170a4d228c07b661b1ba9d87101d99a79339dc93b8b1183d8b20545/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77", size = 1326126 }, + { url = "https://files.pythonhosted.org/packages/af/20/da0d65e07ce49d79173fed41598f487a0a722e87cfbaa8bb7e078a7c1d39/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061", size = 1364538 }, + { url = "https://files.pythonhosted.org/packages/aa/20/b59728405114e57541ba9d5b96033e69d004e811ded299537f74237629ca/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697", size = 1399896 }, + { url = "https://files.pythonhosted.org/packages/2a/92/006690c31b830acbae09d2618e41308fe4c81c0679b3b33a3af859e0b7bf/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7", size = 1312914 }, + { url = "https://files.pythonhosted.org/packages/d4/71/1a253ca215b6c867adbd503f1e142117527ea8775e65962bc09b2fad1d2c/aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0", size = 1271301 }, + { url = "https://files.pythonhosted.org/packages/0a/ab/5d1d9ff9ce6cce8fa54774d0364e64a0f3cd50e512ff09082ced8e5217a1/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5", size = 1291652 }, + { url = "https://files.pythonhosted.org/packages/75/5f/f90510ea954b9ae6e7a53d2995b97a3e5c181110fdcf469bc9238445871d/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e", size = 1286289 }, + { url = "https://files.pythonhosted.org/packages/be/9e/1f523414237798660921817c82b9225a363af436458caf584d2fa6a2eb4a/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1", size = 1341848 }, + { url = "https://files.pythonhosted.org/packages/f6/36/443472ddaa85d7d80321fda541d9535b23ecefe0bf5792cc3955ea635190/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277", size = 1361619 }, + { url = "https://files.pythonhosted.org/packages/19/f6/3ecbac0bc4359c7d7ba9e85c6b10f57e20edaf1f97751ad2f892db231ad0/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058", size = 1320869 }, + { url = "https://files.pythonhosted.org/packages/34/7e/ed74ffb36e3a0cdec1b05d8fbaa29cb532371d5a20058b3a8052fc90fe7c/aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072", size = 359271 }, + { url = "https://files.pythonhosted.org/packages/98/1b/718901f04bc8c886a742be9e83babb7b93facabf7c475cc95e2b3ab80b4d/aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff", size = 379143 }, + { url = "https://files.pythonhosted.org/packages/d9/1c/74f9dad4a2fc4107e73456896283d915937f48177b99867b63381fadac6e/aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487", size = 583468 }, + { url = "https://files.pythonhosted.org/packages/12/29/68d090551f2b58ce76c2b436ced8dd2dfd32115d41299bf0b0c308a5483c/aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a", size = 394066 }, + { url = "https://files.pythonhosted.org/packages/8f/f7/971f88b4cdcaaa4622925ba7d86de47b48ec02a9040a143514b382f78da4/aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d", size = 389098 }, + { url = "https://files.pythonhosted.org/packages/f1/5a/fe3742efdce551667b2ddf1158b27c5b8eb1edc13d5e14e996e52e301025/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75", size = 1332742 }, + { url = "https://files.pythonhosted.org/packages/1a/52/a25c0334a1845eb4967dff279151b67ca32a948145a5812ed660ed900868/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178", size = 1372134 }, + { url = "https://files.pythonhosted.org/packages/96/3d/33c1d8efc2d8ec36bff9a8eca2df9fdf8a45269c6e24a88e74f2aa4f16bd/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e", size = 1414413 }, + { url = "https://files.pythonhosted.org/packages/64/74/0f1ddaa5f0caba1d946f0dd0c31f5744116e4a029beec454ec3726d3311f/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f", size = 1328107 }, + { url = "https://files.pythonhosted.org/packages/0a/32/c10118f0ad50e4093227234f71fd0abec6982c29367f65f32ee74ed652c4/aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73", size = 1280126 }, + { url = "https://files.pythonhosted.org/packages/c6/c9/77e3d648d97c03a42acfe843d03e97be3c5ef1b4d9de52e5bd2d28eed8e7/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf", size = 1292660 }, + { url = "https://files.pythonhosted.org/packages/7e/5d/99c71f8e5c8b64295be421b4c42d472766b263a1fe32e91b64bf77005bf2/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820", size = 1300988 }, + { url = "https://files.pythonhosted.org/packages/8f/2c/76d2377dd947f52fbe8afb19b18a3b816d66c7966755c04030f93b1f7b2d/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca", size = 1339268 }, + { url = "https://files.pythonhosted.org/packages/fd/e6/3d9d935cc705d57ed524d82ec5d6b678a53ac1552720ae41282caa273584/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91", size = 1366993 }, + { url = "https://files.pythonhosted.org/packages/fe/c2/f7eed4d602f3f224600d03ab2e1a7734999b0901b1c49b94dc5891340433/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6", size = 1329459 }, + { url = "https://files.pythonhosted.org/packages/ce/8f/27f205b76531fc592abe29e1ad265a16bf934a9f609509c02d765e6a8055/aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12", size = 356968 }, + { url = "https://files.pythonhosted.org/packages/39/8c/4f6c0b2b3629f6be6c81ab84d9d577590f74f01d4412bfc4067958eaa1e1/aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc", size = 377650 }, + { url = "https://files.pythonhosted.org/packages/7b/b9/03b4327897a5b5d29338fa9b514f1c2f66a3e4fc88a4e40fad478739314d/aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092", size = 576994 }, + { url = "https://files.pythonhosted.org/packages/67/1b/20c2e159cd07b8ed6dde71c2258233902fdf415b2fe6174bd2364ba63107/aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77", size = 390684 }, + { url = "https://files.pythonhosted.org/packages/4d/6b/ff83b34f157e370431d8081c5d1741963f4fb12f9aaddb2cacbf50305225/aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385", size = 386176 }, + { url = "https://files.pythonhosted.org/packages/4d/a1/6e92817eb657de287560962df4959b7ddd22859c4b23a0309e2d3de12538/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972", size = 1303310 }, + { url = "https://files.pythonhosted.org/packages/04/29/200518dc7a39c30ae6d5bc232d7207446536e93d3d9299b8e95db6e79c54/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16", size = 1340445 }, + { url = "https://files.pythonhosted.org/packages/8e/20/53f7bba841ba7b5bb5dea580fea01c65524879ba39cb917d08c845524717/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6", size = 1385121 }, + { url = "https://files.pythonhosted.org/packages/f1/b4/d99354ad614c48dd38fb1ee880a1a54bd9ab2c3bcad3013048d4a1797d3a/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa", size = 1299669 }, + { url = "https://files.pythonhosted.org/packages/51/39/ca1de675f2a5729c71c327e52ac6344e63f036bd37281686ae5c3fb13bfb/aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689", size = 1252638 }, + { url = "https://files.pythonhosted.org/packages/54/cf/a3ae7ff43138422d477348e309ef8275779701bf305ff6054831ef98b782/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57", size = 1266889 }, + { url = "https://files.pythonhosted.org/packages/6e/7a/c6027ad70d9fb23cf254a26144de2723821dade1a624446aa22cd0b6d012/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f", size = 1266249 }, + { url = "https://files.pythonhosted.org/packages/64/fd/ed136d46bc2c7e3342fed24662b4827771d55ceb5a7687847aae977bfc17/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599", size = 1311036 }, + { url = "https://files.pythonhosted.org/packages/76/9a/43eeb0166f1119256d6f43468f900db1aed7fbe32069d2a71c82f987db4d/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5", size = 1338756 }, + { url = "https://files.pythonhosted.org/packages/d5/bc/d01ff0810b3f5e26896f76d44225ed78b088ddd33079b85cd1a23514318b/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987", size = 1299976 }, + { url = "https://files.pythonhosted.org/packages/3e/c9/50a297c4f7ab57a949f4add2d3eafe5f3e68bb42f739e933f8b32a092bda/aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04", size = 355609 }, + { url = "https://files.pythonhosted.org/packages/65/28/aee9d04fb0b3b1f90622c338a08e54af5198e704a910e20947c473298fd0/aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022", size = 375697 }, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, +] + +[[package]] +name = "asn1crypto" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/cf/d547feed25b5244fcb9392e288ff9fdc3280b10260362fc45d37a798a6ee/asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c", size = 121080 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67", size = 105045 }, +] + +[[package]] +name = "asttokens" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/1d/f03bcb60c4a3212e15f99a56085d93093a497718adf828d050b9d675da81/asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0", size = 62284 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", size = 27764 }, +] + +[[package]] +name = "async-timeout" +version = "4.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 }, +] + +[[package]] +name = "attrs" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +] + +[[package]] +name = "bitarray" +version = "2.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/bf/25cf92a83e1fe4948d7935ae3c02f4c9ff9cb9c13e977fba8af11a5f642c/bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e", size = 132825 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/ce/d114d6cb2b00f2bdb038cf2fa739a8d9765042692d74fb66b7c91099c444/bitarray-2.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:917905de565d9576eb20f53c797c15ba88b9f4f19728acabec8d01eee1d3756a", size = 176818 }, + { url = "https://files.pythonhosted.org/packages/93/f1/1a2231056444ed39b6498f81cd1a390620458aca2faffed686d2bceec8c9/bitarray-2.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b35bfcb08b7693ab4bf9059111a6e9f14e07d57ac93cd967c420db58ab9b71e1", size = 128058 }, + { url = "https://files.pythonhosted.org/packages/2c/6c/e7130b7ece5b871dc9628c1c4c115cb6ee7076ec104b052a9bcd5f66920a/bitarray-2.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea1923d2e7880f9e1959e035da661767b5a2e16a45dfd57d6aa831e8b65ee1bf", size = 124494 }, + { url = "https://files.pythonhosted.org/packages/d6/60/4c7c08cd801f529e006e71992d2c70241501a73d8b02b8927cc1a5544b47/bitarray-2.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0b63a565e8a311cc8348ff1262d5784df0f79d64031d546411afd5dd7ef67d", size = 288132 }, + { url = "https://files.pythonhosted.org/packages/0c/9a/5c7f3f00b6fd54a28e64e24a683a8ea62371e71791fcf472adfd2041583b/bitarray-2.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf0620da2b81946d28c0b16f3e3704d38e9837d85ee4f0652816e2609aaa4fed", size = 303303 }, + { url = "https://files.pythonhosted.org/packages/ff/47/c4671b89af1fc1e774bfd8b47af47ee5806f14e72010a97bee5ac92fef01/bitarray-2.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a9b8b05f2876c7195a2b698c47528e86a73c61ea203394ff8e7a4434bda5c8", size = 305431 }, + { url = "https://files.pythonhosted.org/packages/e4/37/df70f878b8e4dbf95558eea8c7611db8bf14b0064992078c36339c529b84/bitarray-2.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:345c76b349ff145549652436235c5532e5bfe9db690db6f0a6ad301c62b9ef21", size = 288305 }, + { url = "https://files.pythonhosted.org/packages/89/8d/8a4b4c1fd75e9e84bb7aac0d6f97d8251a5f44fa6110ab27c85338f73c0d/bitarray-2.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e2936f090bf3f4d1771f44f9077ebccdbc0415d2b598d51a969afcb519df505", size = 278122 }, + { url = "https://files.pythonhosted.org/packages/52/05/2d4a978b164dacf748e1d5470552b123d62ab96a88968179b620b8adb28d/bitarray-2.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f9346e98fc2abcef90b942973087e2462af6d3e3710e82938078d3493f7fef52", size = 320446 }, + { url = "https://files.pythonhosted.org/packages/7e/f3/edce7e35845e75aadd9c8774ef3b2b61a560c921147d73a34e693841f53a/bitarray-2.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6ec283d4741befb86e8c3ea2e9ac1d17416c956d392107e45263e736954b1f7", size = 308271 }, + { url = "https://files.pythonhosted.org/packages/f6/3d/f2c66b0edfeb156b5a95e33bcb61dd151a491db671080fa9be8b45cb1cd9/bitarray-2.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:962892646599529917ef26266091e4cb3077c88b93c3833a909d68dcc971c4e3", size = 332969 }, + { url = "https://files.pythonhosted.org/packages/5b/06/ea5da65f846f806b638b11755d0f485566c931c4d49ef0383e43cf1771ee/bitarray-2.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e8da5355d7d75a52df5b84750989e34e39919ec7e59fafc4c104cc1607ab2d31", size = 338350 }, + { url = "https://files.pythonhosted.org/packages/fe/48/25fb3db98448184a4f6c1715850fd329f9583916eedfef8d4e0a07dafa9f/bitarray-2.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:603e7d640e54ad764d2b4da6b61e126259af84f253a20f512dd10689566e5478", size = 319179 }, + { url = "https://files.pythonhosted.org/packages/e9/a2/e1a13cb95c24e14a1bf1998ef925a62faea2e6a317b16d945e7c384ed380/bitarray-2.9.2-cp310-cp310-win32.whl", hash = "sha256:f00079f8e69d75c2a417de7961a77612bb77ef46c09bc74607d86de4740771ef", size = 118623 }, + { url = "https://files.pythonhosted.org/packages/ee/00/4bd8469ed3f9f9aa1495fc860b8a7481cdd0b38f19082745be06e5358468/bitarray-2.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:1bb33673e7f7190a65f0a940c1ef63266abdb391f4a3e544a47542d40a81f536", size = 126022 }, + { url = "https://files.pythonhosted.org/packages/32/86/a02960105c0a40e7e4cbc74933f070ab476312d20aa25f6959f4abe5095b/bitarray-2.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe71fd4b76380c2772f96f1e53a524da7063645d647a4fcd3b651bdd80ca0f2e", size = 177175 }, + { url = "https://files.pythonhosted.org/packages/8d/fd/ce16db75d5470f9676089428500ef0d473f4e2ff1dcbcf1f856bcd351ea2/bitarray-2.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d527172919cdea1e13994a66d9708a80c3d33dedcf2f0548e4925e600fef3a3a", size = 128273 }, + { url = "https://files.pythonhosted.org/packages/06/60/c1a419f8abd0c9d2641e3e570fc63ad3a87a63ef88a362900e3254f780bc/bitarray-2.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:052c5073bdcaa9dd10628d99d37a2f33ec09364b86dd1f6281e2d9f8d3db3060", size = 124642 }, + { url = "https://files.pythonhosted.org/packages/9e/af/bba89e6f9499fb9dba04b701c8106a1dcc94b5913f35ed20f089da8bea99/bitarray-2.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e064caa55a6ed493aca1eda06f8b3f689778bc780a75e6ad7724642ba5dc62f7", size = 296283 }, + { url = "https://files.pythonhosted.org/packages/8f/44/19e91ffc42a2ded4f1ee73f7923186cf1606cab1119b1d5df24c9cea763e/bitarray-2.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:508069a04f658210fdeee85a7a0ca84db4bcc110cbb1d21f692caa13210f24a7", size = 311309 }, + { url = "https://files.pythonhosted.org/packages/9f/76/eedaa1fcb60af30536af70f6659e3a86dcfdce3e413b188f7864513e4923/bitarray-2.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4da73ebd537d75fa7bccfc2228fcaedea0803f21dd9d0bf0d3b67fef3c4af294", size = 314220 }, + { url = "https://files.pythonhosted.org/packages/21/fa/9fb7266b28ce1c8778aaea650c75855640ea1ada91a80c47c90376994a59/bitarray-2.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb378eaa65cd43098f11ff5d27e48ee3b956d2c00d2d6b5bfc2a09fe183be47", size = 296519 }, + { url = "https://files.pythonhosted.org/packages/c4/ee/c9a92c123f9b0438498d0a8f9470439a43bdafbf042cbdceab7968e5bb1c/bitarray-2.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d14c790b91f6cbcd9b718f88ed737c78939980c69ac8c7f03dd7e60040c12951", size = 286784 }, + { url = "https://files.pythonhosted.org/packages/81/7f/0d9c16a7e321f5cb1d6c634acf4f8620513634776ceeee6f8f732b992fae/bitarray-2.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eea9318293bc0ea6447e9ebfba600a62f3428bea7e9c6d42170ae4f481dbab3", size = 328319 }, + { url = "https://files.pythonhosted.org/packages/2e/98/0730518cf071366633dd027e14e3fba91dc91dd8b4e60d6ae249cde3f53f/bitarray-2.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b76ffec27c7450b8a334f967366a9ebadaea66ee43f5b530c12861b1a991f503", size = 315614 }, + { url = "https://files.pythonhosted.org/packages/4c/b3/8f198444cd2312d520e0372f933932fff68b5900eb2dbab91725924aa7a1/bitarray-2.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:76b76a07d4ee611405045c6950a1e24c4362b6b44808d4ad6eea75e0dbc59af4", size = 340143 }, + { url = "https://files.pythonhosted.org/packages/b9/1a/78841fa855ea2dc13d8d61f231bd3a619732738d7d840b4b35d9d8f93e6e/bitarray-2.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c7d16beeaaab15b075990cd26963d6b5b22e8c5becd131781514a00b8bdd04bd", size = 345958 }, + { url = "https://files.pythonhosted.org/packages/b7/9f/aac87cd45cc4d7b7e50dde590327bde525601088e710c8ba00e8743ddb2b/bitarray-2.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60df43e868a615c7e15117a1e1c2e5e11f48f6457280eba6ddf8fbefbec7da99", size = 327122 }, + { url = "https://files.pythonhosted.org/packages/78/3e/5df523037f80cf95f99d0155ec921298f4fa2b1f7be10cb0c4daffb632da/bitarray-2.9.2-cp311-cp311-win32.whl", hash = "sha256:e788608ed7767b7b3bbde6d49058bccdf94df0de9ca75d13aa99020cc7e68095", size = 118627 }, + { url = "https://files.pythonhosted.org/packages/9c/0e/af070131ed7a4fd15cadc84e018d3c6d3b58070513934462b48a5ff9eb1e/bitarray-2.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:a23397da092ef0a8cfe729571da64c2fc30ac18243caa82ac7c4f965087506ff", size = 126013 }, + { url = "https://files.pythonhosted.org/packages/ef/7d/f489f2136cf5ea1af201be12d55bfc57b45731c4b7e3cc6e001efe62effb/bitarray-2.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:90e3a281ffe3897991091b7c46fca38c2675bfd4399ffe79dfeded6c52715436", size = 176636 }, + { url = "https://files.pythonhosted.org/packages/b8/b6/3e64b19e45b52837e0c4ec1c220bf24dd70dcbcd27e073e07837973f8c16/bitarray-2.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bed637b674db5e6c8a97a4a321e3e4d73e72d50b5c6b29950008a93069cc64cd", size = 127916 }, + { url = "https://files.pythonhosted.org/packages/23/c7/12b1e5cdd8678a6a47610a013fafdbe80d62226d49b73185619bd7361c53/bitarray-2.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e49066d251dbbe4e6e3a5c3937d85b589e40e2669ad0eef41a00f82ec17d844b", size = 124475 }, + { url = "https://files.pythonhosted.org/packages/77/e1/02dc3f03348808a77b26556a6c299f68dbbf0c4a27f340a69d574d2d2432/bitarray-2.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4344e96642e2211fb3a50558feff682c31563a4c64529a931769d40832ca79", size = 299121 }, + { url = "https://files.pythonhosted.org/packages/ea/f1/9cdb006c352b47b26532e7ee7798bd2dacf42774eb75e4a353a38a3ff2b3/bitarray-2.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aeb60962ec4813c539a59fbd4f383509c7222b62c3fb1faa76b54943a613e33a", size = 313486 }, + { url = "https://files.pythonhosted.org/packages/bb/79/98bdfea0f390d313fa04546578a3eee3c3a6dbba94973246438ea8c880aa/bitarray-2.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f7982f10581bb16553719e5e8f933e003f5b22f7d25a68bdb30fac630a6ff", size = 317527 }, + { url = "https://files.pythonhosted.org/packages/58/02/21a2038ee856649f03738828e3bc6c4cd9bfd31125a250c6e30d378067ff/bitarray-2.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71d1cabdeee0cdda4669168618f0e46b7dace207b29da7b63aaa1adc2b54081", size = 299885 }, + { url = "https://files.pythonhosted.org/packages/49/97/82c350256a22689fb50ed86af1a3a5509410332cfe55d644fd7ff5e46dbf/bitarray-2.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0ef2d0a6f1502d38d911d25609b44c6cc27bee0a4363dd295df78b075041b60", size = 289796 }, + { url = "https://files.pythonhosted.org/packages/09/69/ca799419b576d015331b19b42c70086b1208ba363f744c8bb7dc31a0bb6a/bitarray-2.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6f71d92f533770fb027388b35b6e11988ab89242b883f48a6fe7202d238c61f8", size = 334912 }, + { url = "https://files.pythonhosted.org/packages/fb/8a/dad9d48c72367f76b117957e3d718de07254667f33838d061856b238b576/bitarray-2.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba0734aa300757c924f3faf8148e1b8c247176a0ac8e16aefdf9c1eb19e868f7", size = 322790 }, + { url = "https://files.pythonhosted.org/packages/b7/f1/a4f723153e6b4c56a90275a1d6ad04860bd72d9966196eb331cd18b50a12/bitarray-2.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d91406f413ccbf4af6ab5ae7bc78f772a95609f9ddd14123db36ef8c37116d95", size = 346212 }, + { url = "https://files.pythonhosted.org/packages/7f/4f/55301544e90df8a7b798959bffa94e5694b29c964ed9e9e2a52d6cfac9c7/bitarray-2.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:87abb7f80c0a042f3fe8e5264da1a2756267450bb602110d5327b8eaff7682e7", size = 353044 }, + { url = "https://files.pythonhosted.org/packages/16/8b/363fdc21aff37ac99dba4ed41c0d535c37b416cd002351a9848173c738f1/bitarray-2.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b558ce85579b51a2e38703877d1e93b7728a7af664dd45a34e833534f0b755d", size = 334380 }, + { url = "https://files.pythonhosted.org/packages/66/58/f57a6420b363d2f0517d79b9af9fd608360ef174eb5d1d82cc5a26dbdbde/bitarray-2.9.2-cp312-cp312-win32.whl", hash = "sha256:dac2399ee2889fbdd3472bfc2ede74c34cceb1ccf29a339964281a16eb1d3188", size = 118738 }, + { url = "https://files.pythonhosted.org/packages/93/a9/b9462e2a3b4ee020c6caa1dccece324d6b0c7643b9f0a43d9ac8cd15c9d9/bitarray-2.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:48a30d718d1a6dfc22a49547450107abe8f4afdf2abdcbe76eb9ed88edc49498", size = 126202 }, + { url = "https://files.pythonhosted.org/packages/04/f8/68d0fda45f2c0e02773aa692ef113b3beb399e75033bd8f4aec7fa90f7f6/bitarray-2.9.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:43847799461d8ba71deb4d97b47250c2c2fb66d82cd3cb8b4caf52bb97c03034", size = 124138 }, + { url = "https://files.pythonhosted.org/packages/e5/cf/585d3e2bbb05928d3bcd3deb14ced5d62e90211cc3b2c5534579f602d194/bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f44381b0a4bdf64416082f4f0e7140377ae962c0ced6f983c6d7bbfc034040", size = 128828 }, + { url = "https://files.pythonhosted.org/packages/5d/cb/edc40ceedf7148c11afb44e43f7d6816d6e196044ab5cf5f12734cda8f8c/bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a484061616fb4b158b80789bd3cb511f399d2116525a8b29b6334c68abc2310f", size = 129614 }, + { url = "https://files.pythonhosted.org/packages/d1/f8/48020a48ffb72d4021826c801e4c73109dad0abbec03860f512b61162c65/bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ff9e38356cc803e06134cf8ae9758e836ccd1b793135ef3db53c7c5d71e93bc", size = 131448 }, + { url = "https://files.pythonhosted.org/packages/12/39/fea10d4aae1c2f63448c37308b8b6cd7dd34dbbc3dca7ebb5e9d98ae6fbe/bitarray-2.9.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b44105792fbdcfbda3e26ee88786790fda409da4c71f6c2b73888108cf8f062f", size = 126480 }, +] + +[[package]] +name = "cached-property" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/2c/d21c1c23c2895c091fa7a91a54b6872098fea913526932d21902088a7c41/cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", size = 12244 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/19/f2090f7dad41e225c7f2326e4cfe6fff49e57dedb5b53636c9551f86b069/cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0", size = 7573 }, +] + +[[package]] +name = "cachetools" +version = "5.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/38/a0f315319737ecf45b4319a8cd1f3a908e29d9277b46942263292115eee7/cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a", size = 27661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/07/14f8ad37f2d12a5ce41206c21820d8cb6561b728e51fad4530dff0552a67/cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292", size = 9524 }, +] + +[[package]] +name = "cairo" +version = "0.1.0" +source = { virtual = "cairo" } +dependencies = [ + { name = "cairo-lang" }, + { name = "ethereum" }, + { name = "python-dotenv" }, +] + +[package.dev-dependencies] +dev = [ + { name = "eth-abi" }, + { name = "eth-account" }, + { name = "eth-keys" }, + { name = "eth-utils" }, + { name = "hypothesis" }, + { name = "ipykernel" }, + { name = "protobuf" }, + { name = "pytest" }, + { name = "pytest-xdist" }, +] + +[package.metadata] +requires-dist = [ + { name = "cairo-lang", specifier = ">=0.13.2" }, + { name = "ethereum", git = "https://github.com/ethereum/execution-specs.git" }, + { name = "python-dotenv", specifier = ">=1.0.1" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "eth-abi", specifier = ">=5.1.0" }, + { name = "eth-account", specifier = ">=0.13.3" }, + { name = "eth-keys", specifier = ">=0.5.1" }, + { name = "eth-utils", specifier = ">=5.0.0" }, + { name = "hypothesis", specifier = ">=6.112.1" }, + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "protobuf", specifier = ">=5.28.1" }, + { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-xdist", specifier = ">=3.6.1" }, +] + +[[package]] +name = "cairo-lang" +version = "0.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "cachetools" }, + { name = "ecdsa" }, + { name = "eth-hash", extra = ["pycryptodome"] }, + { name = "execnet" }, + { name = "fastecdsa" }, + { name = "frozendict" }, + { name = "gprof2dot" }, + { name = "lark" }, + { name = "marshmallow" }, + { name = "marshmallow-dataclass" }, + { name = "marshmallow-enum" }, + { name = "marshmallow-oneofschema" }, + { name = "mpmath" }, + { name = "numpy" }, + { name = "pipdeptree" }, + { name = "prometheus-client" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-profiling" }, + { name = "pytest-xdist" }, + { name = "pyyaml" }, + { name = "sympy" }, + { name = "typeguard" }, + { name = "web3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/63/45c09047404fa896455e43c1e7e83ed6bc727ec4bbfe7f0ec9f518080c1f/cairo-lang-0.13.2.zip", hash = "sha256:46cc20f0053ef863263940fa9f86f52a29e9a7269dea45c3cbde4223e1c2e2e0", size = 10936647 } + +[[package]] +name = "certifi" +version = "2024.8.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, + { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, + { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, + { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, + { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, + { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, + { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, + { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, + { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, + { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, + { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, + { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, + { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, + { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/61/095a0aa1a84d1481998b534177c8566fdc50bb1233ea9a0478cd3cc075bd/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", size = 194219 }, + { url = "https://files.pythonhosted.org/packages/cc/94/f7cf5e5134175de79ad2059edf2adce18e0685ebdb9227ff0139975d0e93/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", size = 122521 }, + { url = "https://files.pythonhosted.org/packages/46/6a/d5c26c41c49b546860cc1acabdddf48b0b3fb2685f4f5617ac59261b44ae/charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", size = 120383 }, + { url = "https://files.pythonhosted.org/packages/b8/60/e2f67915a51be59d4539ed189eb0a2b0d292bf79270410746becb32bc2c3/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", size = 138223 }, + { url = "https://files.pythonhosted.org/packages/05/8c/eb854996d5fef5e4f33ad56927ad053d04dc820e4a3d39023f35cad72617/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", size = 148101 }, + { url = "https://files.pythonhosted.org/packages/f6/93/bb6cbeec3bf9da9b2eba458c15966658d1daa8b982c642f81c93ad9b40e1/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", size = 140699 }, + { url = "https://files.pythonhosted.org/packages/da/f1/3702ba2a7470666a62fd81c58a4c40be00670e5006a67f4d626e57f013ae/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", size = 142065 }, + { url = "https://files.pythonhosted.org/packages/3f/ba/3f5e7be00b215fa10e13d64b1f6237eb6ebea66676a41b2bcdd09fe74323/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", size = 144505 }, + { url = "https://files.pythonhosted.org/packages/33/c3/3b96a435c5109dd5b6adc8a59ba1d678b302a97938f032e3770cc84cd354/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", size = 139425 }, + { url = "https://files.pythonhosted.org/packages/43/05/3bf613e719efe68fb3a77f9c536a389f35b95d75424b96b426a47a45ef1d/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", size = 145287 }, + { url = "https://files.pythonhosted.org/packages/58/78/a0bc646900994df12e07b4ae5c713f2b3e5998f58b9d3720cce2aa45652f/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", size = 149929 }, + { url = "https://files.pythonhosted.org/packages/eb/5c/97d97248af4920bc68687d9c3b3c0f47c910e21a8ff80af4565a576bd2f0/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", size = 141605 }, + { url = "https://files.pythonhosted.org/packages/a8/31/47d018ef89f95b8aded95c589a77c072c55e94b50a41aa99c0a2008a45a4/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", size = 142646 }, + { url = "https://files.pythonhosted.org/packages/ae/d5/4fecf1d58bedb1340a50f165ba1c7ddc0400252d6832ff619c4568b36cc0/charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", size = 92846 }, + { url = "https://files.pythonhosted.org/packages/a2/a0/4af29e22cb5942488cf45630cbdd7cefd908768e69bdd90280842e4e8529/charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", size = 100343 }, + { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, + { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, + { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, + { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, + { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, + { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, + { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, + { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, + { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, + { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, + { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, + { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, + { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, + { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, + { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, + { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, + { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, + { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, + { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, + { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, + { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, + { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, + { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, + { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, + { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, + { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, + { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, + { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, + { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, + { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, +] + +[[package]] +name = "ckzg" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/80/4b6219a65634915efc4694fa606f38d4b893dcdc1e50b9bcf69b38ec82b0/ckzg-2.0.1.tar.gz", hash = "sha256:62c5adc381637affa7e1df465c57750b356a761b8a3164c3106589b02532b9c9", size = 1113747 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/3b/6c9e4a1b84bd4a8cab3277754a05816707d4fb873e7c2ee56a793fdb76dc/ckzg-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b7f9ba6d215f8981c5545f952aac84875bd564a63da02fb22a3d1321662ecdc0", size = 114745 }, + { url = "https://files.pythonhosted.org/packages/b5/19/9f8b9c35a00040ddbb9c33a4b9c03e4f3e18987fd098ab45b3c4ce67eb44/ckzg-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8fdec3ff96399acba9baeef9e1b0b5258c08f73245780e6c69f7b73def5e8d0a", size = 98693 }, + { url = "https://files.pythonhosted.org/packages/c8/88/706c97167ebf4a5acfcb32766bf55760db10d110757ca4776e80fe3a9063/ckzg-2.0.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1644369af9900a9f109d417d6760693edf134118f3100d0c68f56667de775b80", size = 174085 }, + { url = "https://files.pythonhosted.org/packages/02/85/ed6d01f8b54aba83d029208a5bca395401263d24e55ed33ce7d42b68cb1c/ckzg-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a2146f122d489ac7e67ae0c0743f8d0db1718e6aeed8f05717340594fe07dd", size = 160084 }, + { url = "https://files.pythonhosted.org/packages/e7/73/2883fc3a2e63a9b1b69b3abfba6fa6af00b02777f0f5c580840723316570/ckzg-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:979841be50f2782b447762db38e9bc927ae251f6ca86c54a26561a52068ee779", size = 168864 }, + { url = "https://files.pythonhosted.org/packages/55/b4/e377569c018c90f0028f2e73c8791e776ac526ecf09a35e0a1ab4d7a74b0/ckzg-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4516d86647ee4e8ea9470f4adf68fbebb6dc1bdedff7d9592c2504fe53145908", size = 170524 }, + { url = "https://files.pythonhosted.org/packages/cd/56/145b81f4650e7ca4eba58c24ca8bbdfbdc4cf5427c61895cbc0cd2eb17e4/ckzg-2.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:91866fc58a29b4829201efd9ffadfac3ffeca6359254a54a360ff6a189c34bf5", size = 185023 }, + { url = "https://files.pythonhosted.org/packages/d7/39/663dcd97cf4dac9baa59f3143187349c7dbd43628640a34cf1e04b97d8e0/ckzg-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed35508dac059b2c0a7994383bc7a92eaf35d0b9ce790016819e2619e0f4b8a9", size = 179076 }, + { url = "https://files.pythonhosted.org/packages/fe/05/c250fc209f30a4dea8eb92a12d720391a3bd657b55a5b6ab7ba16c56e092/ckzg-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:449c4fe38017351eca362106420eeb2d28d50b7e54aa8668b3af29a8ab780132", size = 98229 }, + { url = "https://files.pythonhosted.org/packages/56/eb/00e5978a32facf9203e2069d7905f8a5c262cafd6795adf9933531e7427f/ckzg-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:260608a22e2f2cadcd31f4495832d45d6460438c38faba9761b92df885a99d88", size = 114743 }, + { url = "https://files.pythonhosted.org/packages/b7/99/65015b5c6447293a3321112cb33d303ae07a5000302fa08c976819fcad64/ckzg-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1015f99c50215098751b07d7e459ba9a2790d3692ca81552eed29996128e90d", size = 98687 }, + { url = "https://files.pythonhosted.org/packages/92/ec/5d324b490b30e581888d8f7243c3259aad6a25913653ea6d8d673c84ec0d/ckzg-2.0.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dd350d97554c161dc5b8c7b32c2dc8e659632c374f60e2669fb3c9b5b294827", size = 174848 }, + { url = "https://files.pythonhosted.org/packages/71/50/40a6c567c15eb65c73cbc45c1ed9341a0f1ea77bf489078f56e40e0e4836/ckzg-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eec7724fa8dc4ae95757efe4a87e7b2d4b880cb348c72ce7355fc0c4f64bc298", size = 160846 }, + { url = "https://files.pythonhosted.org/packages/03/c9/044fbe6083fc0e8477b9545b193b82bf349a03f4b561f87870f0b2280f36/ckzg-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3fa0f4398fa67fb71f0a2b34a652cc89e6e0e6af1340b0dc771db1a5f3e089c", size = 169632 }, + { url = "https://files.pythonhosted.org/packages/ae/f5/54e736a969813c72c745c2f0c2906e973d63f89744d947c4e3429c81761d/ckzg-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f865a0297aabeeb638187a46f7df445763360417b9df4dea60560d512c2cda09", size = 171214 }, + { url = "https://files.pythonhosted.org/packages/f4/2f/0896c133021479c5fb57ffbddd584774bdebd7d8c966be732380aa1d62ac/ckzg-2.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b6ec738350771dbf5974fb70cc8bbb20a4df784af770f7e655922adc08a2171", size = 185708 }, + { url = "https://files.pythonhosted.org/packages/02/a8/513876410e9634f10ef933f6aae6e71afd3e0786817773c9d40908b6abd4/ckzg-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9b4b669fc77edeb16adc182efc32b3737b36f741a2e33a170d40619e8b171a94", size = 179787 }, + { url = "https://files.pythonhosted.org/packages/c4/b6/5fe04bdbcf881bf23626ff82145e0c077ee3bdb35c86d177bf37fa57832e/ckzg-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:decb97f4a17c7338b2130dcc4b045df4cc0e7785ece872c764b554c7c73a99ff", size = 98228 }, + { url = "https://files.pythonhosted.org/packages/6c/87/dcc62fc2f6651127b6306a37db492998c291ad1a09a6a0d18895882fec51/ckzg-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:285cf3121b8a8c5609c5b706314f68d2ba2784ab02c5bb7487c6ae1714ecb27f", size = 114776 }, + { url = "https://files.pythonhosted.org/packages/fd/99/2d3aa09ebf692c26e03d17b9e7426a34fd71fe4d9b2ff1acf482736cc8da/ckzg-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f927bc41c2551b0ef0056a649a7ebed29d9665680a10795f4cee5002c69ddb7", size = 98711 }, + { url = "https://files.pythonhosted.org/packages/50/b3/44a533895aa4257d0dcb2818f7dd9b1321664784cac2d381022ed8c40113/ckzg-2.0.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd9fb690c88919f30c9f3ab7cc46a7ecd734d5ff4c9ccea383c119b9b7cc4da", size = 175026 }, + { url = "https://files.pythonhosted.org/packages/54/a2/c594861665851f91ae81ec29cf90e38999de042aa95604737d4b779a8609/ckzg-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fabc3bd41b306d1c7025d561c3281a007c2aca8ceaf998582dc3894904d9c73e", size = 161039 }, + { url = "https://files.pythonhosted.org/packages/59/a0/96bb77fb8bf4cd4d51d8bd1d67d59d13f51fa2477b11b915ab6465aa92ce/ckzg-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb50c53efdb9c34f762bd0c8006cf79bc92a9daf47aa6b541e496988484124f", size = 169889 }, + { url = "https://files.pythonhosted.org/packages/68/c4/77d54a7e5f85d833e9664935f6278fbea7de30f4fde213d121f7fdbc27a0/ckzg-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7960cc62f959403293fb53a3c2404778369ae7cefc6d7f202e5e00567cf98c4b", size = 171378 }, + { url = "https://files.pythonhosted.org/packages/02/54/6520ab37c06680910f8ff99afdc473c945c37ab1016662288d98a028d775/ckzg-2.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d721bcd492294c70eca39da0b0a433c29b6a571dbac2f7084bab06334904af06", size = 185969 }, + { url = "https://files.pythonhosted.org/packages/d6/fa/16c3a4fd8353a3a9f95728f4141b2800b08e588522f7b5644c91308f6fe1/ckzg-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dde2391d025b5033ef0eeacf62b11ecfe446aea25682b5f547a907766ad0a8cb", size = 180093 }, + { url = "https://files.pythonhosted.org/packages/d5/ae/91d36445c247a8832bbb7a71bd75293c4c006731d03a2ccaa13e5506ac8a/ckzg-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fab8859d9420f6f7df4e094ee3639bc49d18c8dab0df81bee825e2363dd67a09", size = 98280 }, + { url = "https://files.pythonhosted.org/packages/79/92/4910b9131eb637c6f72e655c1535b9a9c72a5fb2bdf52742f50066cb9e6b/ckzg-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9747d92883199d4f8f3a3d7018134745fddcf692dfe67115434e4b32609ea785", size = 114793 }, + { url = "https://files.pythonhosted.org/packages/09/95/cb52623cbc4573b2e65bd924524f479e6a8611002c4634dfd6e9d490b403/ckzg-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b2cf58fb9e165da97f0ffe9f4a6efb73992645fac8e0fa223a6cc7ec486a434a", size = 98715 }, + { url = "https://files.pythonhosted.org/packages/27/05/3f246149a728b5d829dd8e0b75379fd6bce0d420de4042b8ca692083f96d/ckzg-2.0.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d25d006899d76bb8c9d3e8b27981dd6b66a78f9826e33c1bf981af6577a69a19", size = 175008 }, + { url = "https://files.pythonhosted.org/packages/5f/76/df568b24de6bdbb99fe2c48519744d01f1b9e152fa791ed84b43a2752e78/ckzg-2.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04bf0b32f04f5ea5e4b8518e292d3321bc05596fde95f9c3b4f504e5e4bc780", size = 161009 }, + { url = "https://files.pythonhosted.org/packages/7f/b5/8bbde8acb339a018c0456fb9af714fcca86ed9bf96114ece9556415afbac/ckzg-2.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0cf3dccd72376bff10e1833641cc9d642f34f60ca63972626d9dfcfdc8e77f", size = 169873 }, + { url = "https://files.pythonhosted.org/packages/5f/8f/9b9492f807acbfe791c4c447bbeb96e19160fda272328a9dc6700a2fcb08/ckzg-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:770809c7e93087470cc524724419b0f85590edb033c7c73ba94aef70b36ca18b", size = 171438 }, + { url = "https://files.pythonhosted.org/packages/f1/58/47d4ed23e338dbe1b06cca99e55ae49c3a539d88576c5893e8b589bf3ac6/ckzg-2.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e31b59b8124148d5e21f7e41b35532d7af98260c44a77c3917958adece84296d", size = 186020 }, + { url = "https://files.pythonhosted.org/packages/a5/f0/dc6f961b325d186af1a469e7119a0f48cdc36240f2aca6e10a5e5f91b8b8/ckzg-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:174f0c356df644d6e349ce03b7284d83dbec859e11ca5d1b1b3bace8b8fbc65d", size = 180132 }, + { url = "https://files.pythonhosted.org/packages/72/ca/44676731ca52e6d2289f7e9c74d836f59dc986e9b4182ddd2c7d0b14d88f/ckzg-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:30e375cd45142e56b5dbfdec05ce4deb2368d7f7dedfc7408ba37d5639af05ff", size = 98284 }, + { url = "https://files.pythonhosted.org/packages/d0/e7/9530e51d23d2ef3840aa8c18c3e7844a1c1465f0226befaef14b4270a9fa/ckzg-2.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a12e96f20dce35e5222f898a5c8355054ef7c5ee038eeb97dbb694640b57577b", size = 112463 }, + { url = "https://files.pythonhosted.org/packages/c5/31/463330808421319784a41667c8141a1912ed71abb6b55192186142502aaf/ckzg-2.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4e0ebc55253addaa24dd2cd871bbe3b8f57855f32b5f74e70bf2cb76b6f7da54", size = 95936 }, + { url = "https://files.pythonhosted.org/packages/fe/6e/84dc599aefcd4533298349bd468e3f56790b1dbd086ebd624184e0d8c6fb/ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f917a7bf363a3735db30559e1ed63cf1ccf414234433ba687fa72c007abd756", size = 125768 }, + { url = "https://files.pythonhosted.org/packages/51/2d/bdc7dd9d902bceb523d77e90f9d62a4692999dc8715a5795fb2817b1737f/ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f08c984286853271d4adae219e9ba87275a15047dbaa262ab8dd6c01be97b0", size = 102410 }, + { url = "https://files.pythonhosted.org/packages/f1/f8/c2a06ad4daf189057652ed2ec6ebb1cb29190f57bf67fd4f4309d5614947/ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fa1ea4888417e1f109fd5e57965788fb7f53b674329b937a65604a3c1ca1d03", size = 110686 }, + { url = "https://files.pythonhosted.org/packages/99/a9/ce3d5fd9df58da092c90ddc7b214fd313b54d5bc325770c488c8864ad17a/ckzg-2.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0b249914aeaf05cabc71c5c3797e3d6c126cb2c64192b7eb6755ef6aa5ab2f11", size = 98327 }, +] + +[[package]] +name = "coincurve" +version = "20.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asn1crypto" }, + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/4c/9e5e51e6c12cec6444c86697992f9c6ccffa19f84d042ff939c8b89206ff/coincurve-20.0.0.tar.gz", hash = "sha256:872419e404300302e938849b6b92a196fabdad651060b559dc310e52f8392829", size = 122865 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/0c/f6a8b06f461089aeab441824134ea5d5824dba3acaac0a9dbf8444cbe1d6/coincurve-20.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d559b22828638390118cae9372a1bb6f6594f5584c311deb1de6a83163a0919b", size = 1255634 }, + { url = "https://files.pythonhosted.org/packages/62/c2/0dbabd2c6648f49f730fdcbba84c53b5ffaf452fca85c750633141fe049c/coincurve-20.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d7f6ebd90fcc550f819f7f2cce2af525c342aac07f0ccda46ad8956ad9d99b", size = 1255532 }, + { url = "https://files.pythonhosted.org/packages/f5/77/c4fa50f8cb5d050a9bcab806503acdd1705b0dfb5c554eed15cc18bc12e8/coincurve-20.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22d70dd55d13fd427418eb41c20fde0a20a5e5f016e2b1bb94710701e759e7e0", size = 1191928 }, + { url = "https://files.pythonhosted.org/packages/a3/11/6254ea354a32a3a1d70722daf58f2ebf0f689f0940eaced5127233416553/coincurve-20.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f18d481eaae72c169f334cde1fd22011a884e0c9c6adc3fdc1fd13df8236a3", size = 1194364 }, + { url = "https://files.pythonhosted.org/packages/a7/a9/d8717d41eb02688691adc30d7348f7c5fdc78e977f4cea83ee84622050b5/coincurve-20.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de1ec57f43c3526bc462be58fb97910dc1fdd5acab6c71eda9f9719a5bd7489", size = 1204658 }, + { url = "https://files.pythonhosted.org/packages/55/13/40923832d99c18fb01a00f83e5f6f702156e71cc0eb5d6281535eee662af/coincurve-20.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a6f007c44c726b5c0b3724093c0d4fb8e294f6b6869beb02d7473b21777473a3", size = 1215298 }, + { url = "https://files.pythonhosted.org/packages/4d/87/646462a7a7810c7a3dcadae8969e1b78d535bcff072c26b17588e93a39b8/coincurve-20.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0ff1f3b81330db5092c24da2102e4fcba5094f14945b3eb40746456ceabdd6d9", size = 1204504 }, + { url = "https://files.pythonhosted.org/packages/01/58/fbb9a312d559aee701491435b691e409fb0efa12eabf269ff651d537fed4/coincurve-20.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82f7de97694d9343f26bd1c8e081b168e5f525894c12445548ce458af227f536", size = 1209298 }, + { url = "https://files.pythonhosted.org/packages/ee/d0/1d5679c000b31f3b32512632d98571f2bb752cd25c127d6f5bf3711b6eae/coincurve-20.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e905b4b084b4f3b61e5a5d58ac2632fd1d07b7b13b4c6d778335a6ca1dafd7a3", size = 1198934 }, + { url = "https://files.pythonhosted.org/packages/a3/f6/8c1499f730fac49ec13740fb1c015ce8082fa6b917790056988559f22212/coincurve-20.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:3657bb5ed0baf1cf8cf356e7d44aa90a7902cc3dd4a435c6d4d0bed0553ad4f7", size = 1193319 }, + { url = "https://files.pythonhosted.org/packages/24/a7/d60a41b3f0a546854c9b7ca65ab99a5fdf1c9e158ae264a580de8f23fd1c/coincurve-20.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:44087d1126d43925bf9a2391ce5601bf30ce0dba4466c239172dc43226696018", size = 1255635 }, + { url = "https://files.pythonhosted.org/packages/b7/4a/727fab66c0fbecfd7beeb38467910bd3652a77df649565e30160a9d2bae2/coincurve-20.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ccf0ba38b0f307a9b3ce28933f6c71dc12ef3a0985712ca09f48591afd597c8", size = 1255536 }, + { url = "https://files.pythonhosted.org/packages/0f/8b/25d4ae5bb60665023e6d71681fada88ee95b5010dae6fc0b44d8b23b8df1/coincurve-20.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566bc5986debdf8572b6be824fd4de03d533c49f3de778e29f69017ae3fe82d8", size = 1191928 }, + { url = "https://files.pythonhosted.org/packages/0d/86/8c32c512fa27bfe7cfe70329fd43ebac23c0c8cec202cf6e4f52854e7ce3/coincurve-20.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4d70283168e146f025005c15406086513d5d35e89a60cf4326025930d45013a", size = 1194365 }, + { url = "https://files.pythonhosted.org/packages/fe/74/fefbe512f54df7d02a7ea4821b87cf199a91b3565cdf0c94448b3f6b1af1/coincurve-20.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:763c6122dd7d5e7a81c86414ce360dbe9a2d4afa1ca6c853ee03d63820b3d0c5", size = 1204658 }, + { url = "https://files.pythonhosted.org/packages/09/68/05b29f881f628ce8e8468f5f7420f6c4d7c129f43964e81d15bf388ae67a/coincurve-20.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f00c361c356bcea386d47a191bb8ac60429f4b51c188966a201bfecaf306ff7f", size = 1215301 }, + { url = "https://files.pythonhosted.org/packages/ee/5d/d91549cf5a163797b0724dc2dcd551b908b6beddb6598b37743df7f6f3ec/coincurve-20.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4af57bdadd2e64d117dd0b33cfefe76e90c7a6c496a7b034fc65fd01ec249b15", size = 1204505 }, + { url = "https://files.pythonhosted.org/packages/37/0f/898022e08760fb57d281f3695576e859b0f8a8ac629670223d9066c3f60d/coincurve-20.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a26437b7cbde13fb6e09261610b788ca2a0ca2195c62030afd1e1e0d1a62e035", size = 1209305 }, + { url = "https://files.pythonhosted.org/packages/57/b9/643567d3f680ddf8d1bf10a56112ae7755296500d8eaaef498be637a8533/coincurve-20.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed51f8bba35e6c7676ad65539c3dbc35acf014fc402101fa24f6b0a15a74ab9e", size = 1198932 }, + { url = "https://files.pythonhosted.org/packages/b3/3a/898f5c12469b292042608dd0702bcb0420ec32bac6b1ca2a0dd790f922bd/coincurve-20.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:594b840fc25d74118407edbbbc754b815f1bba9759dbf4f67f1c2b78396df2d3", size = 1193318 }, + { url = "https://files.pythonhosted.org/packages/8f/24/e1bf259dd57186fbdc7cec51909db320884162cfad5ec72cbaa63573ff9d/coincurve-20.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4df4416a6c0370d777aa725a25b14b04e45aa228da1251c258ff91444643f688", size = 1255671 }, + { url = "https://files.pythonhosted.org/packages/0a/c5/1817f87d1cd5ff50d8537fe60fb96f66b76dd02da885d970952e6189a801/coincurve-20.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1ccc3e4db55abf3fc0e604a187fdb05f0702bc5952e503d9a75f4ae6eeb4cb3a", size = 1255565 }, + { url = "https://files.pythonhosted.org/packages/90/9f/35e15f993717ed1dcc4c26d9771f073a1054af26808a0f421783bb4cd7e0/coincurve-20.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8335b1658a2ef5b3eb66d52647742fe8c6f413ad5b9d5310d7ea6d8060d40f", size = 1191953 }, + { url = "https://files.pythonhosted.org/packages/4a/3d/6a9bc32e69b738b5e05f5027bace1da6722352a4a447e495d3c03a601d99/coincurve-20.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ac025e485a0229fd5394e0bf6b4a75f8a4f6cee0dcf6f0b01a2ef05c5210ff", size = 1194425 }, + { url = "https://files.pythonhosted.org/packages/1a/a6/15424973dc47fc7c87e3c0f8859f6f1b1032582ee9f1b85fdd5d1e33d630/coincurve-20.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e46e3f1c21b3330857bcb1a3a5b942f645c8bce912a8a2b252216f34acfe4195", size = 1204678 }, + { url = "https://files.pythonhosted.org/packages/6a/e7/71ddb4d66c11c4ad13e729362f8852e048ae452eba3dfcf57751842bb292/coincurve-20.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:df9ff9b17a1d27271bf476cf3fa92df4c151663b11a55d8cea838b8f88d83624", size = 1215395 }, + { url = "https://files.pythonhosted.org/packages/b9/7d/03e0a19cfff1d86f5d019afc69cfbff02caada701ed5a4a50abc63d4261c/coincurve-20.0.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4155759f071375699282e03b3d95fb473ee05c022641c077533e0d906311e57a", size = 1204552 }, + { url = "https://files.pythonhosted.org/packages/07/cd/e9bd4ca7d931653a35c74194da04191a9aecc54b8f48a554cd538dc810e4/coincurve-20.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0530b9dd02fc6f6c2916716974b79bdab874227f560c422801ade290e3fc5013", size = 1209392 }, + { url = "https://files.pythonhosted.org/packages/99/54/260053f14f74b99b645084231e1c76994134ded49407a3bba23a8ffc0ff6/coincurve-20.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:eacf9c0ce8739c84549a89c083b1f3526c8780b84517ee75d6b43d276e55f8a0", size = 1198932 }, + { url = "https://files.pythonhosted.org/packages/b4/b5/c465e09345dd38b9415f5d47ae7683b3f461db02fcc03e699b6b5687ab2b/coincurve-20.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:52a67bfddbd6224dfa42085c88ad176559801b57d6a8bd30d92ee040de88b7b3", size = 1193324 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "comm" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180 }, +] + +[[package]] +name = "cytoolz" +version = "0.12.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/d8/8df71050b214686591241a1826d2e6934b5c295c5bc57f643e4ed697f1eb/cytoolz-0.12.3.tar.gz", hash = "sha256:4503dc59f4ced53a54643272c61dc305d1dbbfbd7d6bdf296948de9f34c3a282", size = 625899 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/11/ebc8b85c77cc2247c169af808901a80e5d29429b3c9b0d114d4048ad2a5a/cytoolz-0.12.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bbe58e26c84b163beba0fbeacf6b065feabc8f75c6d3fe305550d33f24a2d346", size = 413462 }, + { url = "https://files.pythonhosted.org/packages/19/22/57f20a9f135a08a6fc9848744c324c4facca2b1370a1ae4e8333e274c707/cytoolz-0.12.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c51b66ada9bfdb88cf711bf350fcc46f82b83a4683cf2413e633c31a64df6201", size = 396040 }, + { url = "https://files.pythonhosted.org/packages/12/30/337a18b1182888bf5d59357095a83f537a88e2db32ee0381166a83deddda/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e70d9c615e5c9dc10d279d1e32e846085fe1fd6f08d623ddd059a92861f4e3dd", size = 1933264 }, + { url = "https://files.pythonhosted.org/packages/93/a3/c244bfacd046316cd0a4cffd2e245a8dd9b685168497c3b7c776bdb72c59/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a83f4532707963ae1a5108e51fdfe1278cc8724e3301fee48b9e73e1316de64f", size = 2014114 }, + { url = "https://files.pythonhosted.org/packages/a6/40/51bdfe7fd1cad802eabebb7bb742e694227db25c4806eebf4358229e3220/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d028044524ee2e815f36210a793c414551b689d4f4eda28f8bbb0883ad78bf5f", size = 1999458 }, + { url = "https://files.pythonhosted.org/packages/f7/0b/5973e0ceab96349f9cabb3b20ecc3a717a19e355f68d354dfa538bebb226/cytoolz-0.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c2875bcd1397d0627a09a4f9172fa513185ad302c63758efc15b8eb33cc2a98", size = 1956106 }, + { url = "https://files.pythonhosted.org/packages/d3/01/bb850ad1467f0d1dc5a21a05e3df6ad308a19d095f07583c4e65a85e2ba8/cytoolz-0.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:131ff4820e5d64a25d7ad3c3556f2d8aa65c66b3f021b03f8a8e98e4180dd808", size = 1861974 }, + { url = "https://files.pythonhosted.org/packages/c9/97/207e544a2c9c3d8735102403982a319c252c337e9cf792c2753c22cff1b6/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:04afa90d9d9d18394c40d9bed48c51433d08b57c042e0e50c8c0f9799735dcbd", size = 1937926 }, + { url = "https://files.pythonhosted.org/packages/76/1e/6cc756537caef16cd491de1550c1f25140528785e28263326bd3243a19ed/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dc1ca9c610425f9854323669a671fc163300b873731584e258975adf50931164", size = 1859141 }, + { url = "https://files.pythonhosted.org/packages/20/43/30819bbc4348cabb44d800ab0d0efb29a9d21db8f75060fd1199d5300953/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bfa3f8e01bc423a933f2e1c510cbb0632c6787865b5242857cc955cae220d1bf", size = 2013731 }, + { url = "https://files.pythonhosted.org/packages/bd/ab/cacabf2d0dfea006575fea900131eb491370ee1664783f80cb131f577001/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:f702e295dddef5f8af4a456db93f114539b8dc2a7a9bc4de7c7e41d169aa6ec3", size = 2015075 }, + { url = "https://files.pythonhosted.org/packages/79/6f/98eeee4f735bff536654625e0c38e50c4b01c13fbd9c744d3284dbccc54d/cytoolz-0.12.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0fbad1fb9bb47e827d00e01992a099b0ba79facf5e5aa453be066033232ac4b5", size = 1953391 }, + { url = "https://files.pythonhosted.org/packages/6a/81/80bcbc750e3c8f72d07f1e61c25597fdb23fec3c3d52542f220bff87372c/cytoolz-0.12.3-cp310-cp310-win32.whl", hash = "sha256:8587c3c3dbe78af90c5025288766ac10dc2240c1e76eb0a93a4e244c265ccefd", size = 320881 }, + { url = "https://files.pythonhosted.org/packages/45/9e/cce296c6da9404ce210c79700b85d9ba582a6e908ee88ec707efec09bcd9/cytoolz-0.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e45803d9e75ef90a2f859ef8f7f77614730f4a8ce1b9244375734567299d239", size = 362216 }, + { url = "https://files.pythonhosted.org/packages/98/8a/618a70326d4a52998a6bbb11ca019979891a51b85cbbfce8f9762eec5d2c/cytoolz-0.12.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ac4f2fb38bbc67ff1875b7d2f0f162a247f43bd28eb7c9d15e6175a982e558d", size = 416356 }, + { url = "https://files.pythonhosted.org/packages/bb/17/542f708b9116aa8d8c9c5551500bfa6ab1bddd3edc11457070599a97c197/cytoolz-0.12.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0cf1e1e96dd86829a0539baf514a9c8473a58fbb415f92401a68e8e52a34ecd5", size = 398412 }, + { url = "https://files.pythonhosted.org/packages/d6/9c/52a0460f2b59009da63794cfe11ad002d55fc88fced6ccc85f7ae10a3259/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08a438701c6141dd34eaf92e9e9a1f66e23a22f7840ef8a371eba274477de85d", size = 2090389 }, + { url = "https://files.pythonhosted.org/packages/c7/6d/284d4a1f88b1e63b8a1c80162244ca5d4e0b31647c4f56186f3385fd0d0e/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b6f11b0d7ed91be53166aeef2a23a799e636625675bb30818f47f41ad31821", size = 2187333 }, + { url = "https://files.pythonhosted.org/packages/3e/44/44efcf2acf824aefab5f3fdb97235d360c216c2425db391a8dee687f1774/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7fde09384d23048a7b4ac889063761e44b89a0b64015393e2d1d21d5c1f534a", size = 2173106 }, + { url = "https://files.pythonhosted.org/packages/6f/74/7c2d5af25d51f481e9be771bda2cf5496631cd0fba876d2cc0086caa732d/cytoolz-0.12.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d3bfe45173cc8e6c76206be3a916d8bfd2214fb2965563e288088012f1dabfc", size = 2098805 }, + { url = "https://files.pythonhosted.org/packages/e0/e5/9995bf66caee139459ab70d8b5820c37718d5f7e7380481adb85ef522e4d/cytoolz-0.12.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27513a5d5b6624372d63313574381d3217a66e7a2626b056c695179623a5cb1a", size = 1995956 }, + { url = "https://files.pythonhosted.org/packages/93/73/eee7a7f455d4691f1915b35d1713ba69c6851f940c6f8fffdd2efcbe4411/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d294e5e81ff094fe920fd545052ff30838ea49f9e91227a55ecd9f3ca19774a0", size = 2074891 }, + { url = "https://files.pythonhosted.org/packages/a3/c7/6f0c60bbb911ee3f33b243a695e2fc944285a1865bbb1dfefee1b7c35d62/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:727b01a2004ddb513496507a695e19b5c0cfebcdfcc68349d3efd92a1c297bf4", size = 1980228 }, + { url = "https://files.pythonhosted.org/packages/58/7c/d7524626b415d410208fd2774ff2824fab4dcbe4a496d53bdba85a1407df/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:fe1e1779a39dbe83f13886d2b4b02f8c4b10755e3c8d9a89b630395f49f4f406", size = 2147616 }, + { url = "https://files.pythonhosted.org/packages/a5/7b/9bdf8615e61958386f5c7108d857312214837ae3eacf3589873499d2f0aa/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:de74ef266e2679c3bf8b5fc20cee4fc0271ba13ae0d9097b1491c7a9bcadb389", size = 2148775 }, + { url = "https://files.pythonhosted.org/packages/45/91/b92ab0e29bf7cfaacfedc85391a0d0365a6ac74363f2532ba307a760db14/cytoolz-0.12.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e04d22049233394e0b08193aca9737200b4a2afa28659d957327aa780ddddf2", size = 2079810 }, + { url = "https://files.pythonhosted.org/packages/2f/33/8204d65871fa639d1d3ae788e3afc187f610126f53f2324d4aa37caf0630/cytoolz-0.12.3-cp311-cp311-win32.whl", hash = "sha256:20d36430d8ac809186736fda735ee7d595b6242bdb35f69b598ef809ebfa5605", size = 320212 }, + { url = "https://files.pythonhosted.org/packages/ab/e3/7ce2efaf243c9ee75fc730cd018981788b56e7ad3767f24e7a9cd14831ac/cytoolz-0.12.3-cp311-cp311-win_amd64.whl", hash = "sha256:780c06110f383344d537f48d9010d79fa4f75070d214fc47f389357dd4f010b6", size = 363570 }, + { url = "https://files.pythonhosted.org/packages/7f/57/b0feabefdff4707d0b96bf75e2298ecb209ba22c2e3fd15e5230dd68441a/cytoolz-0.12.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:86923d823bd19ce35805953b018d436f6b862edd6a7c8b747a13d52b39ed5716", size = 419825 }, + { url = "https://files.pythonhosted.org/packages/54/82/795aa9f91ee81818732b435755559857a76e16b7e435e1de434b47ce72b9/cytoolz-0.12.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3e61acfd029bfb81c2c596249b508dfd2b4f72e31b7b53b62e5fb0507dd7293", size = 401673 }, + { url = "https://files.pythonhosted.org/packages/23/f3/298f32b2e374f4f716ca74a9e46b64ee1df9f160de262391f7f9bc53ecca/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd728f4e6051af6af234651df49319da1d813f47894d4c3c8ab7455e01703a37", size = 2096352 }, + { url = "https://files.pythonhosted.org/packages/39/44/49929b33bd0cdccc98b281e4ca11f0836b2963c6fdec8ebb7891807ed908/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe8c6267caa7ec67bcc37e360f0d8a26bc3bdce510b15b97f2f2e0143bdd3673", size = 2161581 }, + { url = "https://files.pythonhosted.org/packages/e9/77/980a8bc123490dd7112e1e068da989932b7612504355ddd25593880c3156/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99462abd8323c52204a2a0ce62454ce8fa0f4e94b9af397945c12830de73f27e", size = 2178057 }, + { url = "https://files.pythonhosted.org/packages/23/d9/2f7a4db7f92eab4b567e56cc2fc147fed1ef35f7968e44cefcbbfb366980/cytoolz-0.12.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da125221b1fa25c690fcd030a54344cecec80074df018d906fc6a99f46c1e3a6", size = 2130881 }, + { url = "https://files.pythonhosted.org/packages/85/bf/1147229198a8fc3f2090d01263234d47b5b7f8c52c20090b1cceda0929cd/cytoolz-0.12.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c18e351956f70db9e2d04ff02f28e9a41839250d3f936a4c8a1eabd1c3094d2", size = 1979975 }, + { url = "https://files.pythonhosted.org/packages/5b/53/b730e9f428e74971f934bf73f0868099d325ffbf0c080a201bb16b6ab508/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:921e6d2440ac758c4945c587b1d1d9b781b72737ac0c0ca5d5e02ca1db8bded2", size = 2086861 }, + { url = "https://files.pythonhosted.org/packages/24/24/df510850c1c57ad69a23a2700083cfd285faf27d16e61f0e503eec122473/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1651a9bd591a8326329ce1d6336f3129161a36d7061a4d5ea9e5377e033364cf", size = 1973211 }, + { url = "https://files.pythonhosted.org/packages/b6/ad/a6e27924a6c8048b4f1ffbd8b9b0b871642bd94d3e457aa42a629c1f667b/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8893223b87c2782bd59f9c4bd5c7bf733edd8728b523c93efb91d7468b486528", size = 2133017 }, + { url = "https://files.pythonhosted.org/packages/26/a3/f9dfb406232d0a100994a86c123259cd2ab023aa8ae325b0d9926f80091f/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:e4d2961644153c5ae186db964aa9f6109da81b12df0f1d3494b4e5cf2c332ee2", size = 2156771 }, + { url = "https://files.pythonhosted.org/packages/fb/bf/ce2c6f6175a29c830904b23faee557de8c167255dbb2bb84e04d7cf5605a/cytoolz-0.12.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:71b6eb97f6695f7ba8ce69c49b707a351c5f46fd97f5aeb5f6f2fb0d6e72b887", size = 2121104 }, + { url = "https://files.pythonhosted.org/packages/bf/97/95a5fb2b5db9b1ea8856741a2a94741a71cb5640112403029beb7b3ef1df/cytoolz-0.12.3-cp312-cp312-win32.whl", hash = "sha256:cee3de65584e915053412cd178729ff510ad5f8f585c21c5890e91028283518f", size = 320537 }, + { url = "https://files.pythonhosted.org/packages/0a/11/3e69585342ce4e6b7f2f6139c8aa235dab5a4fe5c76a051fe01696618bd0/cytoolz-0.12.3-cp312-cp312-win_amd64.whl", hash = "sha256:9eef0d23035fa4dcfa21e570961e86c375153a7ee605cdd11a8b088c24f707f6", size = 363238 }, + { url = "https://files.pythonhosted.org/packages/00/8c/c58e2f14a88132722988ee0951b01ee6cc4880302384f064902d6e8fb048/cytoolz-0.12.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:55f9bd1ae6c2a27eda5abe2a0b65a83029d2385c5a1da7b8ef47af5905d7e905", size = 353101 }, + { url = "https://files.pythonhosted.org/packages/35/99/6ef817203004c7055370fa1ab3bb0dfc6b7ebd0b4942099ce86007614001/cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2d271393c378282727f1231d40391ae93b93ddc0997448acc21dd0cb6a1e56d", size = 385225 }, + { url = "https://files.pythonhosted.org/packages/a2/25/64e5907b15bd16f0f38e825762540ee3293b513f2eb4b9bb51b7f78d5457/cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee98968d6a66ee83a8ceabf31182189ab5d8598998c8ce69b6d5843daeb2db60", size = 405888 }, + { url = "https://files.pythonhosted.org/packages/17/c0/0e19ab05222cf2370d580e5500409c26266f89e853fa18b2b12c530f3957/cytoolz-0.12.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01cfb8518828c1189200c02a5010ea404407fb18fd5589e29c126e84bbeadd36", size = 396781 }, + { url = "https://files.pythonhosted.org/packages/5e/39/bee67e2b541ca3478a982c68d7d23b718fa7f2947bdfc0eecdba9c4e0882/cytoolz-0.12.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:456395d7aec01db32bf9e6db191d667347c78d8d48e77234521fa1078f60dabb", size = 340712 }, +] + +[[package]] +name = "debugpy" +version = "1.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/f9/61c325a10ded8dc3ddc3e7cd2ed58c0b15b2ef4bf8b4bf2930ee98ed59ee/debugpy-1.8.5.zip", hash = "sha256:b2112cfeb34b4507399d298fe7023a16656fc553ed5246536060ca7bd0e668d0", size = 4612118 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/36/0b423f94097cc86555f9a2c8717511863b2a680c9b44b5419d8ac1ff7bf2/debugpy-1.8.5-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7", size = 1711184 }, + { url = "https://files.pythonhosted.org/packages/57/0c/c2ec581541923a4d36cee4fd2419c1211c986849fc61097f87aa81fc6ad3/debugpy-1.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4413b7a3ede757dc33a273a17d685ea2b0c09dbd312cc03f5534a0fd4d40750a", size = 2997629 }, + { url = "https://files.pythonhosted.org/packages/a8/46/3072c2cd3b20f435968275d316f6aea7ddbb760386324e6578278bc2eb99/debugpy-1.8.5-cp310-cp310-win32.whl", hash = "sha256:dd3811bd63632bb25eda6bd73bea8e0521794cda02be41fa3160eb26fc29e7ed", size = 4764678 }, + { url = "https://files.pythonhosted.org/packages/38/25/e738d6f782beba924c0e10dfde2061152f1ea3608dff0e5a5bfb30c311e9/debugpy-1.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:b78c1250441ce893cb5035dd6f5fc12db968cc07f91cc06996b2087f7cefdd8e", size = 4788002 }, + { url = "https://files.pythonhosted.org/packages/ad/72/fd138a10dda16775607316d60dd440fcd23e7560e9276da53c597b5917e9/debugpy-1.8.5-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:606bccba19f7188b6ea9579c8a4f5a5364ecd0bf5a0659c8a5d0e10dcee3032a", size = 1786504 }, + { url = "https://files.pythonhosted.org/packages/e2/0e/d0e6af2d7bbf5ace847e4d3bd41f8f9d4a0764fcd8058f07a1c51618cbf2/debugpy-1.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db9fb642938a7a609a6c865c32ecd0d795d56c1aaa7a7a5722d77855d5e77f2b", size = 2642077 }, + { url = "https://files.pythonhosted.org/packages/f6/55/2a1dc192894ba9b368cdcce15315761a00f2d4cd7de4402179648840e480/debugpy-1.8.5-cp311-cp311-win32.whl", hash = "sha256:4fbb3b39ae1aa3e5ad578f37a48a7a303dad9a3d018d369bc9ec629c1cfa7408", size = 4702081 }, + { url = "https://files.pythonhosted.org/packages/7f/7f/942b23d64f4896e9f8776cf306dfd00feadc950a38d56398610a079b28b1/debugpy-1.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:345d6a0206e81eb68b1493ce2fbffd57c3088e2ce4b46592077a943d2b968ca3", size = 4715571 }, + { url = "https://files.pythonhosted.org/packages/9a/82/7d9e1f75fb23c876ab379008c7cf484a1cfa5ed47ccaac8ba37c75e6814e/debugpy-1.8.5-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:5b5c770977c8ec6c40c60d6f58cacc7f7fe5a45960363d6974ddb9b62dbee156", size = 1436398 }, + { url = "https://files.pythonhosted.org/packages/fd/b6/ee71d5e73712daf8307a9e85f5e39301abc8b66d13acd04dfff1702e672e/debugpy-1.8.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a65b00b7cdd2ee0c2cf4c7335fef31e15f1b7056c7fdbce9e90193e1a8c8cb", size = 1437465 }, + { url = "https://files.pythonhosted.org/packages/6c/d8/8e32bf1f2e0142f7e8a2c354338b493e87f2c44e77e233b3a140fb5efa03/debugpy-1.8.5-cp312-cp312-win32.whl", hash = "sha256:c9f7c15ea1da18d2fcc2709e9f3d6de98b69a5b0fff1807fb80bc55f906691f7", size = 4581313 }, + { url = "https://files.pythonhosted.org/packages/f7/be/2fbaffecb063de228b2b3b6a1750b0b745e5dc645eddd52be8b329933c0b/debugpy-1.8.5-cp312-cp312-win_amd64.whl", hash = "sha256:28ced650c974aaf179231668a293ecd5c63c0a671ae6d56b8795ecc5d2f48d3c", size = 4581209 }, + { url = "https://files.pythonhosted.org/packages/02/49/b595c34d7bc690e8d225a6641618a5c111c7e13db5d9e2b756c15ce8f8c6/debugpy-1.8.5-py2.py3-none-any.whl", hash = "sha256:55919dce65b471eff25901acf82d328bbd5b833526b6c1364bd5133754777a44", size = 4824118 }, +] + +[[package]] +name = "decorator" +version = "5.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, +] + +[[package]] +name = "ecdsa" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/d0/ec8ac1de7accdcf18cfe468653ef00afd2f609faf67c423efbd02491051b/ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8", size = 197791 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/e7/ed3243b30d1bec41675b6394a1daae46349dc2b855cb83be846a5a918238/ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a", size = 149266 }, +] + +[[package]] +name = "eth-abi" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-typing" }, + { name = "eth-utils" }, + { name = "parsimonious" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/f7/dc714b95d07ee825f60fc62c26822a5da44b4930d362f8f5ab69eb2d7403/eth_abi-5.1.0.tar.gz", hash = "sha256:33ddd756206e90f7ddff1330cc8cac4aa411a824fe779314a0a52abea2c8fc14", size = 49898 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/ec/f30f1cfeea8fd2a4b1b38c9b971014756fcc1cd1136e31dbda66c379b68e/eth_abi-5.1.0-py3-none-any.whl", hash = "sha256:84cac2626a7db8b7d9ebe62b0fdca676ab1014cc7f777189e3c0cd721a4c16d8", size = 29157 }, +] + +[[package]] +name = "eth-account" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "ckzg" }, + { name = "eth-abi" }, + { name = "eth-keyfile" }, + { name = "eth-keys" }, + { name = "eth-rlp" }, + { name = "eth-utils" }, + { name = "hexbytes" }, + { name = "pydantic" }, + { name = "rlp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/5f/aa105acb4b38919ccfd8e9b6b0044ebe28746fa898fff0b5139074a3a434/eth_account-0.13.3.tar.gz", hash = "sha256:03d6af5d314e64b3dd53283e15b24736c5caa24542e5edac0455d6ff87d8b1e0", size = 930245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/a5/45dcf568ec39f138597df708e4dbad8543ee7e29d4e14da6d7202da79832/eth_account-0.13.3-py3-none-any.whl", hash = "sha256:c8f3dae3403b8647f386fcc081fb8c2a0970991cf3e00af7e7ebd73f95d6a319", size = 580132 }, +] + +[[package]] +name = "eth-hash" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/b6/57c89b91cf2dbb02b3019337f97bf346167d06cd23d3bde43c9fe52cae7e/eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a", size = 12463 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/f0/a35e791bd73fa425838d8d0157754150ded141a94cf30d567dfeb9d57316/eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f", size = 8650 }, +] + +[package.optional-dependencies] +pycryptodome = [ + { name = "pycryptodome" }, +] + +[[package]] +name = "eth-keyfile" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-keys" }, + { name = "eth-utils" }, + { name = "pycryptodome" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510 }, +] + +[[package]] +name = "eth-keys" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-typing" }, + { name = "eth-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/89/127b102953f30068d6868183055d321a428d517184788a0f03afc209af0d/eth_keys-0.5.1.tar.gz", hash = "sha256:2b587e4bbb9ac2195215a7ab0c0fb16042b17d4ec50240ed670bbb8f53da7a48", size = 28969 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/4a/dda71126cc9f046b5c0102ec60c72aa359c87871ba95245023e66b19faa2/eth_keys-0.5.1-py3-none-any.whl", hash = "sha256:ad13d920a2217a49bed3a1a7f54fb0980f53caf86d3bbab2139fd3330a17b97e", size = 21190 }, +] + +[[package]] +name = "eth-rlp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-utils" }, + { name = "hexbytes" }, + { name = "rlp" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/4e/aae7407671a1a3cf9c4a1b0c735862112ed7fe409a6753ab2863788702c1/eth-rlp-2.1.0.tar.gz", hash = "sha256:d5b408a8cd20ed496e8e66d0559560d29bc21cee482f893936a1f05d0dddc4a0", size = 7345 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/fe/b8b909bf0cc55a8d7d4890bf3a2a37c445a63b194a36f4c6e936fc60a903/eth_rlp-2.1.0-py3-none-any.whl", hash = "sha256:6f476eb7e37d81feaba5d98aed887e467be92648778c44b19fe594aea209cde1", size = 5091 }, +] + +[[package]] +name = "eth-typing" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/0a/27010c2670f130019d787906038f43d4c0b2896d696d3bbc46e98c75ea61/eth_typing-5.0.0.tar.gz", hash = "sha256:87ce7cee75665c09d2dcff8de1b496609d5e32fcd2e2b1d8fc0370c29eedcdc0", size = 22595 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/fa/c44a9406dad56031acade4c5921cdaf4427082a3e49fec0f79b9e2564c86/eth_typing-5.0.0-py3-none-any.whl", hash = "sha256:c7ebc8595e7b65175bb4b4176c2b548ab21b13329f2058e84d4f8c289ba9f577", size = 20079 }, +] + +[[package]] +name = "eth-utils" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cytoolz", marker = "implementation_name == 'cpython'" }, + { name = "eth-hash" }, + { name = "eth-typing" }, + { name = "hexbytes" }, + { name = "toolz", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/c5/8409a2afe1bcd70fa63d7b4c54185f36ab959299767eb45d0b8ca0db77a6/eth_utils-5.0.0.tar.gz", hash = "sha256:a5eb9555f43f4579eb83cb84f9dda9f3d6663bbd4a5a6b693f8d35045f305a1f", size = 120193 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/2d/6557e000bb44529c4c7b2621f88bc344fcdbd0c46bd1b3f75b39f1bb19f5/eth_utils-5.0.0-py3-none-any.whl", hash = "sha256:99c44eca11db74dbb881a1d70b24cd80436fc62fe527d2f5c3e3cf7932aba7b2", size = 100489 }, +] + +[[package]] +name = "ethereum" +version = "0.1.0" +source = { git = "https://github.com/ethereum/execution-specs.git#51fac24740e662844446439ceeb96a460aae0ba0" } +dependencies = [ + { name = "coincurve" }, + { name = "py-ecc" }, + { name = "pycryptodome" }, + { name = "typing-extensions" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, +] + +[[package]] +name = "execnet" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612 }, +] + +[[package]] +name = "executing" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/e3/7d45f492c2c4a0e8e0fad57d081a7c8a0286cdd86372b070cca1ec0caa1e/executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab", size = 977485 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/fd/afcd0496feca3276f509df3dbd5dae726fcc756f1a08d9e25abe1733f962/executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", size = 25805 }, +] + +[[package]] +name = "fastecdsa" +version = "2.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/21/d5585856169c595d99a596dd8000afae40053f9f5c955d8ec8fb2ec3247c/fastecdsa-2.3.2.tar.gz", hash = "sha256:f35255a6d3e41109166b5d4b08866d5acbb99f2e1e64d3a7e74c774664cda842", size = 47729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/0a/b0e6dfcef078c35cab431e26c6236189a499e33482937a98418777c2063d/fastecdsa-2.3.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:138278b123b6c519f24fe9043d857e2f92c421c4fe256ac80d57404a38dc1326", size = 57872 }, + { url = "https://files.pythonhosted.org/packages/f0/56/6146872b905d8394a9c0ca7c158e99e207dd0d92dffaa5e7d61a415ddf8f/fastecdsa-2.3.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5ba5eb5b33d4b861731108d0ac6e544fcdbdc1ab095a5e86e68081ba5713c958", size = 57874 }, + { url = "https://files.pythonhosted.org/packages/1c/7d/37bf10fdcf600f4d2d0a3522cd67e1e821cd5a515211075facbf0d93b8dd/fastecdsa-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc7189b971bc434b4145c9e7084e4970a0817623927a647b70fb162060baaea2", size = 57957 }, +] + +[[package]] +name = "frozendict" +version = "2.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/38/00b0e401eeb1382b13d774522de6f30b5418a313cc0edbcb12e814eea7cd/frozendict-2.4.4.tar.gz", hash = "sha256:3f7c031b26e4ee6a3f786ceb5e3abf1181c4ade92dce1f847da26ea2c96008c7", size = 315923 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/02/cb9ea28ebeefd0b2075bcf811d15400f520f291c5ee0ee8b02df15e51445/frozendict-2.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4a59578d47b3949437519b5c39a016a6116b9e787bb19289e333faae81462e59", size = 37821 }, + { url = "https://files.pythonhosted.org/packages/f3/25/bfa8b5bc5a89e6dbc2d6ddf925b70f44131f708edf7185e49c77de34641b/frozendict-2.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12a342e439aef28ccec533f0253ea53d75fe9102bd6ea928ff530e76eac38906", size = 117526 }, + { url = "https://files.pythonhosted.org/packages/b8/b7/f88d020ceb4eab1ca7363184351116bc46b9aec04551516083f3431645bb/frozendict-2.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f79c26dff10ce11dad3b3627c89bb2e87b9dd5958c2b24325f16a23019b8b94", size = 117322 }, + { url = "https://files.pythonhosted.org/packages/b2/23/6b9e5aec0bf05a4bad2c34933c76b0a64e25025cf65a6ad90ba74ac2323e/frozendict-2.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2bd009cf4fc47972838a91e9b83654dc9a095dc4f2bb3a37c3f3124c8a364543", size = 119176 }, + { url = "https://files.pythonhosted.org/packages/92/22/8da48069d0ed1d74300218beeb9c2fe56b3a8f2bb86491a2329bf8d2d576/frozendict-2.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:87ebcde21565a14fe039672c25550060d6f6d88cf1f339beac094c3b10004eb0", size = 118511 }, + { url = "https://files.pythonhosted.org/packages/f2/ad/8881e55bcdc84ecf5d337f17fe0747b70f43f9dd93aaeb0c8fe169b8be5d/frozendict-2.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:fefeb700bc7eb8b4c2dc48704e4221860d254c8989fb53488540bc44e44a1ac2", size = 37256 }, + { url = "https://files.pythonhosted.org/packages/02/cd/b525900e87a6993386a86352cc2a067434eef9721752068f0b0093db3d1b/frozendict-2.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:4297d694eb600efa429769125a6f910ec02b85606f22f178bafbee309e7d3ec7", size = 33897 }, + { url = "https://files.pythonhosted.org/packages/6a/71/3656c00606e75e81f11721e6a1c973c3e03da8c7d8b665d20f78245384c6/frozendict-2.4.4-py311-none-any.whl", hash = "sha256:705efca8d74d3facbb6ace80ab3afdd28eb8a237bfb4063ed89996b024bc443d", size = 16021 }, + { url = "https://files.pythonhosted.org/packages/d5/a6/6c61e137d71b1452f200f31788fdb6f9e54465967fd15de3870dd4249b96/frozendict-2.4.4-py312-none-any.whl", hash = "sha256:d9647563e76adb05b7cde2172403123380871360a114f546b4ae1704510801e5", size = 16020 }, +] + +[[package]] +name = "frozenlist" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/3d/2102257e7acad73efc4a0c306ad3953f68c504c16982bbdfee3ad75d8085/frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", size = 37820 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/35/1328c7b0f780d34f8afc1d87ebdc2bb065a123b24766a0b475f0d67da637/frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", size = 94315 }, + { url = "https://files.pythonhosted.org/packages/f4/d6/ca016b0adcf8327714ccef969740688808c86e0287bf3a639ff582f24e82/frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", size = 53805 }, + { url = "https://files.pythonhosted.org/packages/ae/83/bcdaa437a9bd693ba658a0310f8cdccff26bd78e45fccf8e49897904a5cd/frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", size = 52163 }, + { url = "https://files.pythonhosted.org/packages/d4/e9/759043ab7d169b74fe05ebfbfa9ee5c881c303ebc838e308346204309cd0/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", size = 238595 }, + { url = "https://files.pythonhosted.org/packages/f8/ce/b9de7dc61e753dc318cf0de862181b484178210c5361eae6eaf06792264d/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", size = 262428 }, + { url = "https://files.pythonhosted.org/packages/36/ce/dc6f29e0352fa34ebe45421960c8e7352ca63b31630a576e8ffb381e9c08/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", size = 258867 }, + { url = "https://files.pythonhosted.org/packages/51/47/159ac53faf8a11ae5ee8bb9db10327575557504e549cfd76f447b969aa91/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", size = 229412 }, + { url = "https://files.pythonhosted.org/packages/ec/25/0c87df2e53c0c5d90f7517ca0ff7aca78d050a8ec4d32c4278e8c0e52e51/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", size = 239539 }, + { url = "https://files.pythonhosted.org/packages/97/94/a1305fa4716726ae0abf3b1069c2d922fcfd442538cb850f1be543f58766/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", size = 253379 }, + { url = "https://files.pythonhosted.org/packages/53/82/274e19f122e124aee6d113188615f63b0736b4242a875f482a81f91e07e2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", size = 245901 }, + { url = "https://files.pythonhosted.org/packages/b8/28/899931015b8cffbe155392fe9ca663f981a17e1adc69589ee0e1e7cdc9a2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", size = 263797 }, + { url = "https://files.pythonhosted.org/packages/6e/4f/b8a5a2f10c4a58c52a52a40cf6cf1ffcdbf3a3b64f276f41dab989bf3ab5/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", size = 264415 }, + { url = "https://files.pythonhosted.org/packages/b0/2c/7be3bdc59dbae444864dbd9cde82790314390ec54636baf6b9ce212627ad/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", size = 253964 }, + { url = "https://files.pythonhosted.org/packages/2e/ec/4fb5a88f6b9a352aed45ab824dd7ce4801b7bcd379adcb927c17a8f0a1a8/frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", size = 44559 }, + { url = "https://files.pythonhosted.org/packages/61/15/2b5d644d81282f00b61e54f7b00a96f9c40224107282efe4cd9d2bf1433a/frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", size = 50434 }, + { url = "https://files.pythonhosted.org/packages/01/bc/8d33f2d84b9368da83e69e42720cff01c5e199b5a868ba4486189a4d8fa9/frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", size = 97060 }, + { url = "https://files.pythonhosted.org/packages/af/b2/904500d6a162b98a70e510e743e7ea992241b4f9add2c8063bf666ca21df/frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", size = 55347 }, + { url = "https://files.pythonhosted.org/packages/5b/9c/f12b69997d3891ddc0d7895999a00b0c6a67f66f79498c0e30f27876435d/frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", size = 53374 }, + { url = "https://files.pythonhosted.org/packages/ac/6e/e0322317b7c600ba21dec224498c0c5959b2bce3865277a7c0badae340a9/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", size = 273288 }, + { url = "https://files.pythonhosted.org/packages/a7/76/180ee1b021568dad5b35b7678616c24519af130ed3fa1e0f1ed4014e0f93/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", size = 284737 }, + { url = "https://files.pythonhosted.org/packages/05/08/40159d706a6ed983c8aca51922a93fc69f3c27909e82c537dd4054032674/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", size = 280267 }, + { url = "https://files.pythonhosted.org/packages/e0/18/9f09f84934c2b2aa37d539a322267939770362d5495f37783440ca9c1b74/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", size = 258778 }, + { url = "https://files.pythonhosted.org/packages/b3/c9/0bc5ee7e1f5cc7358ab67da0b7dfe60fbd05c254cea5c6108e7d1ae28c63/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", size = 272276 }, + { url = "https://files.pythonhosted.org/packages/12/5d/147556b73a53ad4df6da8bbb50715a66ac75c491fdedac3eca8b0b915345/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", size = 272424 }, + { url = "https://files.pythonhosted.org/packages/83/61/2087bbf24070b66090c0af922685f1d0596c24bb3f3b5223625bdeaf03ca/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", size = 260881 }, + { url = "https://files.pythonhosted.org/packages/a8/be/a235bc937dd803258a370fe21b5aa2dd3e7bfe0287a186a4bec30c6cccd6/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", size = 282327 }, + { url = "https://files.pythonhosted.org/packages/5d/e7/b2469e71f082948066b9382c7b908c22552cc705b960363c390d2e23f587/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74", size = 281502 }, + { url = "https://files.pythonhosted.org/packages/db/1b/6a5b970e55dffc1a7d0bb54f57b184b2a2a2ad0b7bca16a97ca26d73c5b5/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", size = 272292 }, + { url = "https://files.pythonhosted.org/packages/1a/05/ebad68130e6b6eb9b287dacad08ea357c33849c74550c015b355b75cc714/frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", size = 44446 }, + { url = "https://files.pythonhosted.org/packages/b3/21/c5aaffac47fd305d69df46cfbf118768cdf049a92ee6b0b5cb029d449dcf/frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", size = 50459 }, + { url = "https://files.pythonhosted.org/packages/b4/db/4cf37556a735bcdb2582f2c3fa286aefde2322f92d3141e087b8aeb27177/frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", size = 93937 }, + { url = "https://files.pythonhosted.org/packages/46/03/69eb64642ca8c05f30aa5931d6c55e50b43d0cd13256fdd01510a1f85221/frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", size = 53656 }, + { url = "https://files.pythonhosted.org/packages/3f/ab/c543c13824a615955f57e082c8a5ee122d2d5368e80084f2834e6f4feced/frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", size = 51868 }, + { url = "https://files.pythonhosted.org/packages/a9/b8/438cfd92be2a124da8259b13409224d9b19ef8f5a5b2507174fc7e7ea18f/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", size = 280652 }, + { url = "https://files.pythonhosted.org/packages/54/72/716a955521b97a25d48315c6c3653f981041ce7a17ff79f701298195bca3/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", size = 286739 }, + { url = "https://files.pythonhosted.org/packages/65/d8/934c08103637567084568e4d5b4219c1016c60b4d29353b1a5b3587827d6/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", size = 289447 }, + { url = "https://files.pythonhosted.org/packages/70/bb/d3b98d83ec6ef88f9bd63d77104a305d68a146fd63a683569ea44c3085f6/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", size = 265466 }, + { url = "https://files.pythonhosted.org/packages/0b/f2/b8158a0f06faefec33f4dff6345a575c18095a44e52d4f10c678c137d0e0/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", size = 281530 }, + { url = "https://files.pythonhosted.org/packages/ea/a2/20882c251e61be653764038ece62029bfb34bd5b842724fff32a5b7a2894/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", size = 281295 }, + { url = "https://files.pythonhosted.org/packages/4c/f9/8894c05dc927af2a09663bdf31914d4fb5501653f240a5bbaf1e88cab1d3/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", size = 268054 }, + { url = "https://files.pythonhosted.org/packages/37/ff/a613e58452b60166507d731812f3be253eb1229808e59980f0405d1eafbf/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", size = 286904 }, + { url = "https://files.pythonhosted.org/packages/cc/6e/0091d785187f4c2020d5245796d04213f2261ad097e0c1cf35c44317d517/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", size = 290754 }, + { url = "https://files.pythonhosted.org/packages/a5/c2/e42ad54bae8bcffee22d1e12a8ee6c7717f7d5b5019261a8c861854f4776/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", size = 282602 }, + { url = "https://files.pythonhosted.org/packages/b6/61/56bad8cb94f0357c4bc134acc30822e90e203b5cb8ff82179947de90c17f/frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", size = 44063 }, + { url = "https://files.pythonhosted.org/packages/3e/dc/96647994a013bc72f3d453abab18340b7f5e222b7b7291e3697ca1fcfbd5/frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", size = 50452 }, + { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, +] + +[[package]] +name = "gprof2dot" +version = "2024.6.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/32/11/16fc5b985741378812223f2c6213b0a95cda333b797def622ac702d28e81/gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab", size = 36536 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/27/15c4d20871a86281e2bacde9e9f634225d1c2ed0db072f98acf201022411/gprof2dot-2024.6.6-py2.py3-none-any.whl", hash = "sha256:45b14ad7ce64e299c8f526881007b9eb2c6b75505d5613e96e66ee4d5ab33696", size = 34763 }, +] + +[[package]] +name = "hexbytes" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/51/06836a542b773bfc60ab871fa08d4a7963e7df6754ca57169e2654287cc1/hexbytes-1.2.1.tar.gz", hash = "sha256:515f00dddf31053db4d0d7636dd16061c1d896c3109b8e751005db4ca46bcca7", size = 7722 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/c6/20f25ea73e4ceffb3eb4e38347f2992cb25e5ff6eb644d52e753a7a72f57/hexbytes-1.2.1-py3-none-any.whl", hash = "sha256:e64890b203a31f4a23ef11470ecfcca565beaee9198df623047df322b757471a", size = 5160 }, +] + +[[package]] +name = "hypothesis" +version = "6.112.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/cf/21929f0c6a73c0607e6230d8a4c0cbdbd11216c3be6579e7a0f8565ae232/hypothesis-6.112.1.tar.gz", hash = "sha256:b070d7a1bb9bd84706c31885c9aeddc138e2b36a9c112a91984f49501c567856", size = 406705 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/25/f1fb5b3ec58ed3c6014385672d4298e2f0c7291bfcd9ffd06627a641470d/hypothesis-6.112.1-py3-none-any.whl", hash = "sha256:93631b1498b20d2c205ed304cbd41d50e9c069d78a9c773c1324ca094c5e30ce", size = 467475 }, +] + +[[package]] +name = "idna" +version = "3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/ac/e349c5e6d4543326c6883ee9491e3921e0d07b55fdf3cce184b40d63e72a/idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603", size = 189467 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", size = 66894 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "ipykernel" +version = "6.29.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "platform_system == 'Darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173 }, +] + +[[package]] +name = "ipython" +version = "8.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/24/d4fabaca03c8804bf0b8d994c8ae3a20e57e9330d277fb43d83e558dec5e/ipython-8.27.0.tar.gz", hash = "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e", size = 5494984 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a2/6c725958e6f135d8e5de081e69841bb2c1d84b3fc259d02eb092b8fc203a/ipython-8.27.0-py3-none-any.whl", hash = "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c", size = 818986 }, +] + +[[package]] +name = "jedi" +version = "0.19.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/99/99b493cec4bf43176b678de30f81ed003fd6a647a301b9c927280c600f0a/jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", size = 1227821 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0", size = 1569361 }, +] + +[[package]] +name = "jupyter-client" +version = "8.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/61/3cd51dea7878691919adc34ff6ad180f13bfe25fb8c7662a9ee6dc64e643/jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df", size = 341102 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/d3/c4bb02580bc0db807edb9a29b2d0c56031be1ef0d804336deb2699a470f6/jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f", size = 105901 }, +] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", size = 28965 }, +] + +[[package]] +name = "keth" +version = "0.1.0" +source = { virtual = "." } + +[[package]] +name = "lark" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/60/bc7622aefb2aee1c0b4ba23c1446d3e30225c8770b38d7aedbfb65ca9d5a/lark-1.2.2.tar.gz", hash = "sha256:ca807d0162cd16cef15a8feecb862d7319e7a09bdb13aef927968e45040fed80", size = 252132 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/00/d90b10b962b4277f5e64a78b6609968859ff86889f5b898c1a778c06ec00/lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c", size = 111036 }, +] + +[[package]] +name = "marshmallow" +version = "3.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/40/faa10dc4500bca85f41ca9d8cefab282dd23d0fcc7a9b5fab40691e72e76/marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e", size = 176836 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/78/c1de55eb3311f2c200a8b91724414b8d6f5ae78891c15d9d936ea43c3dba/marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9", size = 49334 }, +] + +[[package]] +name = "marshmallow-dataclass" +version = "8.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/2c/0a835792269c01cca3ad424b69a6f946c908334d6f155723d5faa5b22288/marshmallow_dataclass-8.6.1.tar.gz", hash = "sha256:dca312c841f73f8f665b4434d23b3204e8cfbf50b8cbb57bb76f41a6ee8184c8", size = 31519 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/96/1cc5b8d8d0b22f38ed4a95f34ba5c66b95949033b03d630657dcad31f492/marshmallow_dataclass-8.6.1-py3-none-any.whl", hash = "sha256:d941137bcb480729a14810e5f10d9bb79a498fb5b57c875aad6be37e97b98a5f", size = 18685 }, +] + +[[package]] +name = "marshmallow-enum" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/8c/ceecdce57dfd37913143087fffd15f38562a94f0d22823e3c66eac0dca31/marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58", size = 4013 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/59/ef3a3dc499be447098d4a89399beb869f813fee1b5a57d5d79dee2c1bf51/marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072", size = 4186 }, +] + +[[package]] +name = "marshmallow-oneofschema" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/35/75/8dd134f08375845910d134e50246fdfcab3f1d84ab3284bd09bb15f69be9/marshmallow_oneofschema-3.1.1.tar.gz", hash = "sha256:68b4a57d0281a04ac25d4eb7a4c5865a57090a0a8fd30fd6362c8e833ac6a6d9", size = 8684 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/81/3ef15337c19d3e3432945aad738081a5f54c16885277c7dff300b5f85b24/marshmallow_oneofschema-3.1.1-py3-none-any.whl", hash = "sha256:ff4cb2a488785ee8edd521a765682c2c80c78b9dc48894124531bdfa1ec9303b", size = 5726 }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, +] + +[[package]] +name = "multidict" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/68/259dee7fd14cf56a17c554125e534f6274c2860159692a414d0b402b9a6d/multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", size = 48628 }, + { url = "https://files.pythonhosted.org/packages/50/79/53ba256069fe5386a4a9e80d4e12857ced9de295baf3e20c68cdda746e04/multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", size = 29327 }, + { url = "https://files.pythonhosted.org/packages/ff/10/71f1379b05b196dae749b5ac062e87273e3f11634f447ebac12a571d90ae/multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", size = 29689 }, + { url = "https://files.pythonhosted.org/packages/71/45/70bac4f87438ded36ad4793793c0095de6572d433d98575a5752629ef549/multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", size = 126639 }, + { url = "https://files.pythonhosted.org/packages/80/cf/17f35b3b9509b4959303c05379c4bfb0d7dd05c3306039fc79cf035bbac0/multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", size = 134315 }, + { url = "https://files.pythonhosted.org/packages/ef/1f/652d70ab5effb33c031510a3503d4d6efc5ec93153562f1ee0acdc895a57/multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", size = 129471 }, + { url = "https://files.pythonhosted.org/packages/a6/64/2dd6c4c681688c0165dea3975a6a4eab4944ea30f35000f8b8af1df3148c/multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", size = 124585 }, + { url = "https://files.pythonhosted.org/packages/87/56/e6ee5459894c7e554b57ba88f7257dc3c3d2d379cb15baaa1e265b8c6165/multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", size = 116957 }, + { url = "https://files.pythonhosted.org/packages/36/9e/616ce5e8d375c24b84f14fc263c7ef1d8d5e8ef529dbc0f1df8ce71bb5b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db", size = 128609 }, + { url = "https://files.pythonhosted.org/packages/8c/4f/4783e48a38495d000f2124020dc96bacc806a4340345211b1ab6175a6cb4/multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", size = 123016 }, + { url = "https://files.pythonhosted.org/packages/3e/b3/4950551ab8fc39862ba5e9907dc821f896aa829b4524b4deefd3e12945ab/multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", size = 133542 }, + { url = "https://files.pythonhosted.org/packages/96/4d/f0ce6ac9914168a2a71df117935bb1f1781916acdecbb43285e225b484b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", size = 130163 }, + { url = "https://files.pythonhosted.org/packages/be/72/17c9f67e7542a49dd252c5ae50248607dfb780bcc03035907dafefb067e3/multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", size = 126832 }, + { url = "https://files.pythonhosted.org/packages/71/9f/72d719e248cbd755c8736c6d14780533a1606ffb3fbb0fbd77da9f0372da/multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", size = 26402 }, + { url = "https://files.pythonhosted.org/packages/04/5a/d88cd5d00a184e1ddffc82aa2e6e915164a6d2641ed3606e766b5d2f275a/multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", size = 28800 }, + { url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 }, + { url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 }, + { url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 }, + { url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 }, + { url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 }, + { url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 }, + { url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 }, + { url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 }, + { url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 }, + { url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 }, + { url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 }, + { url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 }, + { url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 }, + { url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 }, + { url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 }, + { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, + { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, + { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, + { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, + { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, + { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, + { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, + { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, + { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, + { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, + { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, + { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, + { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, + { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, + { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, + { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, + { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, + { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, + { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, + { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, + { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, + { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, + { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, + { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, + { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, + { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, + { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, + { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, + { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, + { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, + { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, +] + +[[package]] +name = "numpy" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/5f/9003bb3e632f2b58f5e3a3378902dcc73c5518070736c6740fe52454e8e1/numpy-2.1.1.tar.gz", hash = "sha256:d0cf7d55b1051387807405b3898efafa862997b4cba8aa5dbe657be794afeafd", size = 18874860 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/37/e3de47233b3ba458b1021a6f95029198b2f68a83eb886a862640b6ec3e9a/numpy-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8a0e34993b510fc19b9a2ce7f31cb8e94ecf6e924a40c0c9dd4f62d0aac47d9", size = 21150738 }, + { url = "https://files.pythonhosted.org/packages/69/30/f41c9b6dab4e1ec56b40d1daa81ce9f9f8d26da6d02af18768a883676bd5/numpy-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7dd86dfaf7c900c0bbdcb8b16e2f6ddf1eb1fe39c6c8cca6e94844ed3152a8fd", size = 13758247 }, + { url = "https://files.pythonhosted.org/packages/e1/30/d2f71d3419ada3b3735e2ce9cea7dfe22c268ac9fbb24e0b5ac5fc222633/numpy-2.1.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:5889dd24f03ca5a5b1e8a90a33b5a0846d8977565e4ae003a63d22ecddf6782f", size = 5353756 }, + { url = "https://files.pythonhosted.org/packages/84/64/879bd6877488441cfaa578c96bdc4b43710d7e3ae4f8260fbd04821da395/numpy-2.1.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:59ca673ad11d4b84ceb385290ed0ebe60266e356641428c845b39cd9df6713ab", size = 6886809 }, + { url = "https://files.pythonhosted.org/packages/cd/c4/869f8db87f5c9df86b93ca42036f58911ff162dd091a41e617977ab50d1f/numpy-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13ce49a34c44b6de5241f0b38b07e44c1b2dcacd9e36c30f9c2fcb1bb5135db7", size = 13977367 }, + { url = "https://files.pythonhosted.org/packages/7d/4b/a509d346fffede6120cc17610cc500819417ee9c3da7f08d9aaf15cab2a3/numpy-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913cc1d311060b1d409e609947fa1b9753701dac96e6581b58afc36b7ee35af6", size = 16326516 }, + { url = "https://files.pythonhosted.org/packages/4a/0c/fdba41b2ddeb7a052f84d85fb17d5e168af0e8034b3a2d6e369b7cc2966f/numpy-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:caf5d284ddea7462c32b8d4a6b8af030b6c9fd5332afb70e7414d7fdded4bfd0", size = 16702642 }, + { url = "https://files.pythonhosted.org/packages/bf/8d/a8da065a46515efdbcf81a92535b816ea17194ce5b767df1f13815c32179/numpy-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57eb525e7c2a8fdee02d731f647146ff54ea8c973364f3b850069ffb42799647", size = 14475522 }, + { url = "https://files.pythonhosted.org/packages/b9/d2/5b7cf5851af48c35a73b85750b41f9b622760ee11659665a688e6b3f7cb7/numpy-2.1.1-cp310-cp310-win32.whl", hash = "sha256:9a8e06c7a980869ea67bbf551283bbed2856915f0a792dc32dd0f9dd2fb56728", size = 6535211 }, + { url = "https://files.pythonhosted.org/packages/e5/6a/b1f7d73fec1942ded4b474a78c3fdd11c4fad5232143f41dd7e6ae166080/numpy-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d10c39947a2d351d6d466b4ae83dad4c37cd6c3cdd6d5d0fa797da56f710a6ae", size = 12865289 }, + { url = "https://files.pythonhosted.org/packages/f7/86/2c01070424a42b286ea0271203682c3d3e81e10ce695545b35768307b383/numpy-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d07841fd284718feffe7dd17a63a2e6c78679b2d386d3e82f44f0108c905550", size = 21154850 }, + { url = "https://files.pythonhosted.org/packages/ef/4e/d3426d9e620a18bbb979f28e4dc7f9a2c35eb7cf726ffcb33545ebdd3e6a/numpy-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5613cfeb1adfe791e8e681128f5f49f22f3fcaa942255a6124d58ca59d9528f", size = 13789477 }, + { url = "https://files.pythonhosted.org/packages/c6/6e/fb6b1b2da9f4c757f55b202f10b6af0fe4fee87ace6e830228a12ab8ae5d/numpy-2.1.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0b8cc2715a84b7c3b161f9ebbd942740aaed913584cae9cdc7f8ad5ad41943d0", size = 5351769 }, + { url = "https://files.pythonhosted.org/packages/58/9a/07c8a9dc7254f3265ae014e33768d1cfd8eb73ee6cf215f4ec3b497e4255/numpy-2.1.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b49742cdb85f1f81e4dc1b39dcf328244f4d8d1ded95dea725b316bd2cf18c95", size = 6890872 }, + { url = "https://files.pythonhosted.org/packages/08/4e/3b50fa3b1e045793056ed5a1fc6f89dd897ff9cb00900ca6377fe552d442/numpy-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d5f8a8e3bc87334f025194c6193e408903d21ebaeb10952264943a985066ca", size = 13984256 }, + { url = "https://files.pythonhosted.org/packages/d9/37/108d692f7e2544b9ae972c7bfa06c26717871c273ccec86470bc3132b04d/numpy-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d51fc141ddbe3f919e91a096ec739f49d686df8af254b2053ba21a910ae518bf", size = 16337778 }, + { url = "https://files.pythonhosted.org/packages/95/2d/df81a1be3be6d3a92fd12dfd6c26a0dc026b276136ec1056562342a484a2/numpy-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:98ce7fb5b8063cfdd86596b9c762bf2b5e35a2cdd7e967494ab78a1fa7f8b86e", size = 16710448 }, + { url = "https://files.pythonhosted.org/packages/8f/34/4b2e604c5c44bd64b6c85e89d88871b41e60233b3ddf97419b37ae5b0c72/numpy-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24c2ad697bd8593887b019817ddd9974a7f429c14a5469d7fad413f28340a6d2", size = 14489002 }, + { url = "https://files.pythonhosted.org/packages/9f/0d/67c04b6bfefd0abbe7f60f7e4f11e3aca15d688faec1d1df089966105a9a/numpy-2.1.1-cp311-cp311-win32.whl", hash = "sha256:397bc5ce62d3fb73f304bec332171535c187e0643e176a6e9421a6e3eacef06d", size = 6533215 }, + { url = "https://files.pythonhosted.org/packages/94/7a/4c00332a3ca79702bbc86228afd0e84e6f91b47222ec8cdf00677dd16481/numpy-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:ae8ce252404cdd4de56dcfce8b11eac3c594a9c16c231d081fb705cf23bd4d9e", size = 12870550 }, + { url = "https://files.pythonhosted.org/packages/36/11/c573ef66c004f991989c2c6218229d9003164525549409aec5ec9afc0285/numpy-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c803b7934a7f59563db459292e6aa078bb38b7ab1446ca38dd138646a38203e", size = 20884403 }, + { url = "https://files.pythonhosted.org/packages/6b/6c/a9fbef5fd2f9685212af2a9e47485cde9357c3e303e079ccf85127516f2d/numpy-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6435c48250c12f001920f0751fe50c0348f5f240852cfddc5e2f97e007544cbe", size = 13493375 }, + { url = "https://files.pythonhosted.org/packages/34/f2/1316a6b08ad4c161d793abe81ff7181e9ae2e357a5b06352a383b9f8e800/numpy-2.1.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3269c9eb8745e8d975980b3a7411a98976824e1fdef11f0aacf76147f662b15f", size = 5088823 }, + { url = "https://files.pythonhosted.org/packages/be/15/fabf78a6d4a10c250e87daf1cd901af05e71501380532ac508879cc46a7e/numpy-2.1.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fac6e277a41163d27dfab5f4ec1f7a83fac94e170665a4a50191b545721c6521", size = 6619825 }, + { url = "https://files.pythonhosted.org/packages/9f/8a/76ddef3e621541ddd6984bc24d256a4e3422d036790cbbe449e6cad439ee/numpy-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd8f556cdc8cfe35e70efb92463082b7f43dd7e547eb071ffc36abc0ca4699b", size = 13696705 }, + { url = "https://files.pythonhosted.org/packages/cb/22/2b840d297183916a95847c11f82ae11e248fa98113490b2357f774651e1d/numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b9cd92c8f8e7b313b80e93cedc12c0112088541dcedd9197b5dee3738c1201", size = 16041649 }, + { url = "https://files.pythonhosted.org/packages/c7/e8/6f4825d8f576cfd5e4d6515b9eec22bd618868bdafc8a8c08b446dcb65f0/numpy-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:afd9c680df4de71cd58582b51e88a61feed4abcc7530bcd3d48483f20fc76f2a", size = 16409358 }, + { url = "https://files.pythonhosted.org/packages/bf/f8/5edf1105b0dc24fd66fc3e9e7f3bca3d920cde571caaa4375ec1566073c3/numpy-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8661c94e3aad18e1ea17a11f60f843a4933ccaf1a25a7c6a9182af70610b2313", size = 14172488 }, + { url = "https://files.pythonhosted.org/packages/f4/c2/dddca3e69a024d2f249a5b68698328163cbdafb7e65fbf6d36373bbabf12/numpy-2.1.1-cp312-cp312-win32.whl", hash = "sha256:950802d17a33c07cba7fd7c3dcfa7d64705509206be1606f196d179e539111ed", size = 6237195 }, + { url = "https://files.pythonhosted.org/packages/b7/98/5640a09daa3abf0caeaefa6e7bf0d10c0aa28a77c84e507d6a716e0e23df/numpy-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fc5eabfc720db95d68e6646e88f8b399bfedd235994016351b1d9e062c4b270", size = 12568082 }, + { url = "https://files.pythonhosted.org/packages/6b/9e/8bc6f133bc6d359ccc9ec051853aded45504d217685191f31f46d36b7065/numpy-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:046356b19d7ad1890c751b99acad5e82dc4a02232013bd9a9a712fddf8eb60f5", size = 20834810 }, + { url = "https://files.pythonhosted.org/packages/32/1b/429519a2fa28681814c511574017d35f3aab7136d554cc65f4c1526dfbf5/numpy-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5a9cb2be39350ae6c8f79410744e80154df658d5bea06e06e0ac5bb75480d5", size = 13507739 }, + { url = "https://files.pythonhosted.org/packages/25/18/c732d7dd9896d11e4afcd487ac65e62f9fa0495563b7614eb850765361fa/numpy-2.1.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:d4c57b68c8ef5e1ebf47238e99bf27657511ec3f071c465f6b1bccbef12d4136", size = 5074465 }, + { url = "https://files.pythonhosted.org/packages/3e/37/838b7ae9262c370ab25312bab365492016f11810ffc03ebebbd54670b669/numpy-2.1.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8ae0fd135e0b157365ac7cc31fff27f07a5572bdfc38f9c2d43b2aff416cc8b0", size = 6606418 }, + { url = "https://files.pythonhosted.org/packages/8b/b9/7ff3bfb71e316a5b43a124c4b7a5881ab12f3c32636014bef1f757f19dbd/numpy-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981707f6b31b59c0c24bcda52e5605f9701cb46da4b86c2e8023656ad3e833cb", size = 13692464 }, + { url = "https://files.pythonhosted.org/packages/42/78/75bcf16e6737cd196ff7ecf0e1fd3f953293a34dff4fd93fb488e8308536/numpy-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca4b53e1e0b279142113b8c5eb7d7a877e967c306edc34f3b58e9be12fda8df", size = 16037763 }, + { url = "https://files.pythonhosted.org/packages/23/99/36bf5ffe034d06df307bc783e25cf164775863166dcd878879559fe0379f/numpy-2.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e097507396c0be4e547ff15b13dc3866f45f3680f789c1a1301b07dadd3fbc78", size = 16410374 }, + { url = "https://files.pythonhosted.org/packages/7f/16/04c5dab564887d4cd31a9ed30e51467fa70d52a4425f5a9bd1eed5b3d34c/numpy-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7506387e191fe8cdb267f912469a3cccc538ab108471291636a96a54e599556", size = 14169873 }, + { url = "https://files.pythonhosted.org/packages/09/e0/d1b5adbf1731886c4186c59a9fa208585df9452a43a2b60e79af7c649717/numpy-2.1.1-cp313-cp313-win32.whl", hash = "sha256:251105b7c42abe40e3a689881e1793370cc9724ad50d64b30b358bbb3a97553b", size = 6234118 }, + { url = "https://files.pythonhosted.org/packages/d0/9c/2391ee6e9ebe77232ddcab29d92662b545e99d78c3eb3b4e26d59b9ca1ca/numpy-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:f212d4f46b67ff604d11fff7cc62d36b3e8714edf68e44e9760e19be38c03eb0", size = 12561742 }, + { url = "https://files.pythonhosted.org/packages/38/0e/c4f754f9e73f9bb520e8bf418c646f2c4f70c5d5f2bc561e90f884593193/numpy-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:920b0911bb2e4414c50e55bd658baeb78281a47feeb064ab40c2b66ecba85553", size = 20858403 }, + { url = "https://files.pythonhosted.org/packages/32/fc/d69092b9171efa0cb8079577e71ce0cac0e08f917d33f6e99c916ed51d44/numpy-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bab7c09454460a487e631ffc0c42057e3d8f2a9ddccd1e60c7bb8ed774992480", size = 13519851 }, + { url = "https://files.pythonhosted.org/packages/14/2a/d7cf2cd9f15b23f623075546ea64a2c367cab703338ca22aaaecf7e704df/numpy-2.1.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:cea427d1350f3fd0d2818ce7350095c1a2ee33e30961d2f0fef48576ddbbe90f", size = 5115444 }, + { url = "https://files.pythonhosted.org/packages/8e/00/e87b2cb4afcecca3b678deefb8fa53005d7054f3b5c39596e5554e5d98f8/numpy-2.1.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:e30356d530528a42eeba51420ae8bf6c6c09559051887196599d96ee5f536468", size = 6628903 }, + { url = "https://files.pythonhosted.org/packages/ab/9d/337ae8721b3beec48c3413d71f2d44b2defbf3c6f7a85184fc18b7b61f4a/numpy-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8dfa9e94fc127c40979c3eacbae1e61fda4fe71d84869cc129e2721973231ef", size = 13665945 }, + { url = "https://files.pythonhosted.org/packages/c0/90/ee8668e84c5d5cc080ef3beb622c016adf19ca3aa51afe9dbdcc6a9baf59/numpy-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910b47a6d0635ec1bd53b88f86120a52bf56dcc27b51f18c7b4a2e2224c29f0f", size = 16023473 }, + { url = "https://files.pythonhosted.org/packages/38/a0/57c24b2131879183051dc698fbb53fd43b77c3fa85b6e6311014f2bc2973/numpy-2.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:13cc11c00000848702322af4de0147ced365c81d66053a67c2e962a485b3717c", size = 16400624 }, + { url = "https://files.pythonhosted.org/packages/bb/4c/14a41eb5c9548c6cee6af0936eabfd985c69230ffa2f2598321431a9aa0a/numpy-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53e27293b3a2b661c03f79aa51c3987492bd4641ef933e366e0f9f6c9bf257ec", size = 14155072 }, + { url = "https://files.pythonhosted.org/packages/94/9a/d6a5d138b53ccdc002fdf07f0d1a960326c510e66cbfff7180c88d37c482/numpy-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7be6a07520b88214ea85d8ac8b7d6d8a1839b0b5cb87412ac9f49fa934eb15d5", size = 20982055 }, + { url = "https://files.pythonhosted.org/packages/40/b5/78d8b5481aeef6d2aad3724c6aa5398045d2657038dfe54c055cae1fcf75/numpy-2.1.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:52ac2e48f5ad847cd43c4755520a2317f3380213493b9d8a4c5e37f3b87df504", size = 6750222 }, + { url = "https://files.pythonhosted.org/packages/eb/9a/59a548ad57df8c432bfac4556504a9fae5c082ffea53d108fcf7ce2956e4/numpy-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a95ca3560a6058d6ea91d4629a83a897ee27c00630aed9d933dff191f170cd", size = 16141236 }, + { url = "https://files.pythonhosted.org/packages/02/31/3cbba87e998748b2e33ca5bc6fcc5662c867037f980918e302aebdf139a2/numpy-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:99f4a9ee60eed1385a86e82288971a51e71df052ed0b2900ed30bc840c0f2e39", size = 12789681 }, +] + +[[package]] +name = "packaging" +version = "24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, +] + +[[package]] +name = "parsimonious" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427 }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, +] + +[[package]] +name = "pip" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/87/fb90046e096a03aeab235e139436b3fe804cdd447ed2093b0d70eba3f7f8/pip-24.2.tar.gz", hash = "sha256:5b5e490b5e9cb275c879595064adce9ebd31b854e3e803740b72f9ccf34a45b8", size = 1922041 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/55/90db48d85f7689ec6f81c0db0622d704306c5284850383c090e6c7195a5c/pip-24.2-py3-none-any.whl", hash = "sha256:2cd581cf58ab7fcfca4ce8efa6dcacd0de5bf8d0a3eb9ec927e07405f4d9e2a2", size = 1815170 }, +] + +[[package]] +name = "pipdeptree" +version = "2.23.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pip" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/4c/a9e8e5820f066185f392e64bd4a5335d5bdbe5d26871985f1122fb1c53ef/pipdeptree-2.23.3.tar.gz", hash = "sha256:3fcfd4e72de13a37b7921bc160af840d514738f9ea81c3f9ce080bc1e1f4eb5a", size = 39804 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/91/b55acfbeba957daff9a048557b31e02c6f3d4ee0774c844982b56fa6e7cc/pipdeptree-2.23.3-py3-none-any.whl", hash = "sha256:5115d6f9ea55be010bfff87da3cde32154cfe127b0cdfb4721ccf9d9d7cb6989", size = 32235 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a0/d7cab8409cdc7d39b037c85ac46d92434fb6595432e069251b38e5c8dd0e/platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c", size = 21276 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/8b/d497999c4017b80678017ddce745cf675489c110681ad3c84a55eddfd3e7/platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617", size = 18417 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "prometheus-client" +version = "0.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/39/3be07741a33356127c4fe633768ee450422c1231c6d34b951fee1458308d/prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89", size = 78278 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/98/745b810d822103adca2df8decd4c0bbe839ba7ad3511af3f0d09692fc0f0/prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7", size = 54474 }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.47" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/6d/0279b119dafc74c1220420028d490c4399b790fc1256998666e3a341879f/prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360", size = 425859 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/23/22750c4b768f09386d1c3cc4337953e8936f48a888fa6dddfb669b2c9088/prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", size = 386411 }, +] + +[[package]] +name = "protobuf" +version = "5.28.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/0b/7a997c8939f698d72bdea14d57116e43d3051fffb3b2964c30938c4a08e6/protobuf-5.28.1.tar.gz", hash = "sha256:42597e938f83bb7f3e4b35f03aa45208d49ae8d5bcb4bc10b9fc825e0ab5e423", size = 422422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/d6/6dedb8a2fbbeb4ac92bb9dd830f77800bbe353799eb8b11d2659beffb9f4/protobuf-5.28.1-cp310-abi3-win32.whl", hash = "sha256:fc063acaf7a3d9ca13146fefb5b42ac94ab943ec6e978f543cd5637da2d57957", size = 419673 }, + { url = "https://files.pythonhosted.org/packages/28/ff/6af7b6fad3bd85820f00f3753a2ebd6bdd9dbf29da5a4252e9f402bdfe2a/protobuf-5.28.1-cp310-abi3-win_amd64.whl", hash = "sha256:4c7f5cb38c640919791c9f74ea80c5b82314c69a8409ea36f2599617d03989af", size = 431486 }, + { url = "https://files.pythonhosted.org/packages/99/80/46b61e647a9386f5dc836e9660818f79afd80a4d5802535ec07a7c6aa16e/protobuf-5.28.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4304e4fceb823d91699e924a1fdf95cde0e066f3b1c28edb665bda762ecde10f", size = 414743 }, + { url = "https://files.pythonhosted.org/packages/b3/21/33dbf04427a11c2de5fb835bb37c5d1522e9d5556a92df0acd13644860a9/protobuf-5.28.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:0dfd86d2b5edf03d91ec2a7c15b4e950258150f14f9af5f51c17fa224ee1931f", size = 316526 }, + { url = "https://files.pythonhosted.org/packages/c0/be/bac52549cab1aaab112d380b3f2a80a348ba7083a80bf4ff4be4fb5a6729/protobuf-5.28.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:51f09caab818707ab91cf09cc5c156026599cf05a4520779ccbf53c1b352fb25", size = 316613 }, + { url = "https://files.pythonhosted.org/packages/51/3d/71fae0078424ba8ea70b222b6fa56ef771a9918ab91cee806c2abc9d57fa/protobuf-5.28.1-py3-none-any.whl", hash = "sha256:c529535e5c0effcf417682563719e5d8ac8d2b93de07a56108b4c2d436d7a29a", size = 169572 }, +] + +[[package]] +name = "psutil" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/66/78c9c3020f573c58101dc43a44f6855d01bbbd747e24da2f0c4491200ea3/psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", size = 249766 }, + { url = "https://files.pythonhosted.org/packages/e1/3f/2403aa9558bea4d3854b0e5e567bc3dd8e9fbc1fc4453c0aa9aafeb75467/psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", size = 253024 }, + { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 }, + { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 }, + { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 }, + { url = "https://files.pythonhosted.org/packages/cd/5f/60038e277ff0a9cc8f0c9ea3d0c5eb6ee1d2470ea3f9389d776432888e47/psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", size = 292046 }, + { url = "https://files.pythonhosted.org/packages/8b/20/2ff69ad9c35c3df1858ac4e094f20bd2374d33c8643cf41da8fd7cdcb78b/psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", size = 253560 }, + { url = "https://files.pythonhosted.org/packages/73/44/561092313ae925f3acfaace6f9ddc4f6a9c748704317bad9c8c8f8a36a79/psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", size = 257399 }, + { url = "https://files.pythonhosted.org/packages/7c/06/63872a64c312a24fb9b4af123ee7007a306617da63ff13bcc1432386ead7/psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0", size = 251988 }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, +] + +[[package]] +name = "py-ecc" +version = "7.0.1" +source = { git = "https://github.com/petertdavies/py_ecc.git?rev=127184f4c57b1812da959586d0fe8f43bb1a2389#127184f4c57b1812da959586d0fe8f43bb1a2389" } +dependencies = [ + { name = "cached-property" }, + { name = "eth-typing" }, + { name = "eth-utils" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pycryptodome" +version = "3.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/ed/19223a0a0186b8a91ebbdd2852865839237a21c74f1fbc4b8d5b62965239/pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7", size = 4794232 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/96/b0d494defb3346378086848a8ece5ddfd138a66c4a05e038fca873b2518c/pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044", size = 2427142 }, + { url = "https://files.pythonhosted.org/packages/24/80/56a04e2ae622d7f38c1c01aef46a26c6b73a2ad15c9705a8e008b5befb03/pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a", size = 1590045 }, + { url = "https://files.pythonhosted.org/packages/ea/94/82ebfa5c83d980907ceebf79b00909a569d258bdfd9b0264d621fa752cfd/pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2", size = 2061748 }, + { url = "https://files.pythonhosted.org/packages/af/20/5f29ec45462360e7f61e8688af9fe4a0afae057edfabdada662e11bf97e7/pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c", size = 2135687 }, + { url = "https://files.pythonhosted.org/packages/e5/1f/6bc4beb4adc07b847e5d3fddbec4522c2c3aa05df9e61b91dc4eff6a4946/pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25", size = 2164262 }, + { url = "https://files.pythonhosted.org/packages/30/4b/cbc67cda0efd55d7ddcc98374c4b9c853022a595ed1d78dd15c961bc7f6e/pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128", size = 2054347 }, + { url = "https://files.pythonhosted.org/packages/0d/08/01987ab75ca789247a88c8b2f0ce374ef7d319e79589e0842e316a272662/pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c", size = 2192762 }, + { url = "https://files.pythonhosted.org/packages/b5/bf/798630923b67f4201059c2d690105998f20a6a8fb9b5ab68d221985155b3/pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4", size = 2155230 }, + { url = "https://files.pythonhosted.org/packages/39/12/5fe7f5b9212dda9f5a26f842a324d6541fe1ca8059602124ff30db1e874b/pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72", size = 1723464 }, + { url = "https://files.pythonhosted.org/packages/1f/90/d131c0eb643290230dfa4108b7c2d135122d88b714ad241d77beb4782a76/pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9", size = 1759588 }, + { url = "https://files.pythonhosted.org/packages/17/87/c7153fcd400df0f4a67d7d92cdb6b5e43f309c22434374b8a61849dfb280/pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a", size = 1639310 }, + { url = "https://files.pythonhosted.org/packages/68/9a/88d984405b087e8c8dd9a9d4c81a6fa675454e5fcf2ae01d9553b3128637/pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e", size = 1708332 }, + { url = "https://files.pythonhosted.org/packages/c7/10/88fb67d2fa545ce2ac61cfda70947bcbb1769f1956315c4b919d79774897/pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04", size = 1565619 }, + { url = "https://files.pythonhosted.org/packages/a2/40/63dff38fa4f7888f812263494d4a745eeed180ff09dd7b8350a81eb09d21/pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3", size = 1606403 }, + { url = "https://files.pythonhosted.org/packages/8b/61/522235ca81d9dcfcf8b4cbc253b3a8a1f2231603d486369a8a02eb998f31/pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea", size = 1637284 }, + { url = "https://files.pythonhosted.org/packages/e9/a7/5aa0596f7fc710fd55b4e6bbb025fedacfec929465a618f20e61ebf7df76/pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b", size = 1741193 }, +] + +[[package]] +name = "pydantic" +version = "2.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/14/15/3d989541b9c8128b96d532cfd2dd10131ddcc75a807330c00feb3d42a5bd/pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2", size = 768511 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/28/fff23284071bc1ba419635c7e86561c8b9b8cf62a5bcb459b92d7625fd38/pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612", size = 434363 }, +] + +[[package]] +name = "pydantic-core" +version = "2.23.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/cc/07bec3fb337ff80eacd6028745bd858b9642f61ee58cfdbfb64451c1def0/pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690", size = 402277 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/fb/fc7077473d843fd70bd1e09177c3225be95621881765d6f7d123036fb9c7/pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6", size = 1845897 }, + { url = "https://files.pythonhosted.org/packages/92/8c/c6f1a0f72328c5687acc0847baf806c4cb31c1a9321de70c3cbcbb37cece/pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5", size = 1777037 }, + { url = "https://files.pythonhosted.org/packages/bd/fc/89e2a998218230ed8c38f0ba11d8f73947df90ac59a1e9f2fb4e1ba318a5/pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b", size = 1801481 }, + { url = "https://files.pythonhosted.org/packages/d7/f3/81a5f69ea1359633876ea2283728d0afe2ed62e028d91d747dcdfabc594e/pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700", size = 1807280 }, + { url = "https://files.pythonhosted.org/packages/7a/91/b20f5646d7ef7c2629744b49e6fb86f839aa676b1aa11fb3998371ac5860/pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01", size = 2003100 }, + { url = "https://files.pythonhosted.org/packages/89/71/59172c61f2ecd4b33276774512ef31912944429fabaa0f4483151f788a35/pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed", size = 2662832 }, + { url = "https://files.pythonhosted.org/packages/80/d1/c6f8e23987dc166976996a910876596635d71e529335b846880d856589fd/pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec", size = 2057218 }, + { url = "https://files.pythonhosted.org/packages/ae/f3/f4381383b65cf16392aead51643fd5fb3feeb69972226d276ce5c6cfb948/pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba", size = 1923455 }, + { url = "https://files.pythonhosted.org/packages/a1/8d/d845077d39e55763bdb99d64ef86f8961827f8896b6e58ce08ce6b255bde/pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee", size = 1966890 }, + { url = "https://files.pythonhosted.org/packages/53/f8/56355d7b1cf84df63f93b1a455ebb53fd9588edbb63a44fd4d801444a060/pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe", size = 2112163 }, + { url = "https://files.pythonhosted.org/packages/06/32/a0a7a3a318b4ae98a0e6b9e18db31fadbd3cfc46b31191e4ed4ca658e2d4/pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b", size = 1717086 }, + { url = "https://files.pythonhosted.org/packages/e3/31/38aebe234508fc30c80b4825661d3c1ef0d51b1c40a12e50855b108acd35/pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83", size = 1918933 }, + { url = "https://files.pythonhosted.org/packages/4a/60/ef8eaad365c1d94962d158633f66313e051f7b90cead647e65a96993da22/pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27", size = 1843251 }, + { url = "https://files.pythonhosted.org/packages/57/f4/20aa352e03379a3b5d6c2fb951a979f70718138ea747e3f756d63dda69da/pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45", size = 1776367 }, + { url = "https://files.pythonhosted.org/packages/f1/b9/e5482ac4ea2d128925759d905fb05a08ca98e67ed1d8ab7401861997c6c8/pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611", size = 1800135 }, + { url = "https://files.pythonhosted.org/packages/78/9f/387353f6b6b2ed023f973cffa4e2384bb2e52d15acf5680bc70c50f6c48f/pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61", size = 1805896 }, + { url = "https://files.pythonhosted.org/packages/4f/70/9a153f19394e2ef749f586273ebcdb3de97e2fa97e175b957a8e5a2a77f9/pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5", size = 2001492 }, + { url = "https://files.pythonhosted.org/packages/a5/1c/79d976846fcdcae0c657922d0f476ca287fa694e69ac1fc9d397b831e1cc/pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0", size = 2659827 }, + { url = "https://files.pythonhosted.org/packages/fd/89/cdd76ae363cabae23a4b70df50d603c81c517415ff9d5d65e72e35251cf6/pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8", size = 2055160 }, + { url = "https://files.pythonhosted.org/packages/1a/82/7d62c3dd4e2e101a81ac3fa138d986bfbad9727a6275fc2b4a5efb98bdbd/pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8", size = 1922282 }, + { url = "https://files.pythonhosted.org/packages/85/e6/ef09f395c974d08674464dd3d49066612fe7cc0466ef8ce9427cadf13e5b/pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48", size = 1965827 }, + { url = "https://files.pythonhosted.org/packages/a4/5e/e589474af850c77c3180b101b54bc98bf812ad09728ba2cff4989acc9734/pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5", size = 2110810 }, + { url = "https://files.pythonhosted.org/packages/e0/ff/626007d5b7ac811f9bcac6d8af3a574ccee4505c1f015d25806101842f0c/pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1", size = 1715479 }, + { url = "https://files.pythonhosted.org/packages/4f/ff/6dc33f3b71e34ef633e35d6476d245bf303fc3eaf18a00f39bb54f78faf3/pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa", size = 1918281 }, + { url = "https://files.pythonhosted.org/packages/8f/35/6d81bc4aa7d06e716f39e2bffb0eabcbcebaf7bab94c2f8278e277ded0ea/pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305", size = 1845250 }, + { url = "https://files.pythonhosted.org/packages/18/42/0821cd46f76406e0fe57df7a89d6af8fddb22cce755bcc2db077773c7d1a/pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb", size = 1769993 }, + { url = "https://files.pythonhosted.org/packages/e5/55/b969088e48bd8ea588548a7194d425de74370b17b385cee4d28f5a79013d/pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa", size = 1791250 }, + { url = "https://files.pythonhosted.org/packages/43/c1/1d460d09c012ac76b68b2a1fd426ad624724f93b40e24a9a993763f12c61/pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162", size = 1802530 }, + { url = "https://files.pythonhosted.org/packages/70/8e/fd3c9eda00fbdadca726f17a0f863ecd871a65b3a381b77277ae386d3bcd/pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801", size = 1997848 }, + { url = "https://files.pythonhosted.org/packages/f0/67/13fa22d7b09395e83721edc31bae2bd5c5e2c36a09d470c18f5d1de46958/pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb", size = 2662790 }, + { url = "https://files.pythonhosted.org/packages/fa/1b/1d689c53d15ab67cb0df1c3a2b1df873b50409581e93e4848289dce57e2f/pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326", size = 2074114 }, + { url = "https://files.pythonhosted.org/packages/3d/d9/b565048609db77760b9a0900f6e0a3b2f33be47cd3c4a433f49653a0d2b5/pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c", size = 1918153 }, + { url = "https://files.pythonhosted.org/packages/41/94/8ee55c51333ed8df3a6f1e73c6530c724a9a37d326e114c9e3b24faacff9/pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c", size = 1969019 }, + { url = "https://files.pythonhosted.org/packages/f7/49/0233bae5778a5526cef000447a93e8d462f4f13e2214c13c5b23d379cb25/pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab", size = 2121325 }, + { url = "https://files.pythonhosted.org/packages/42/a1/2f262db2fd6f9c2c9904075a067b1764cc6f71c014be5c6c91d9de52c434/pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c", size = 1725252 }, + { url = "https://files.pythonhosted.org/packages/9a/00/a57937080b49500df790c4853d3e7bc605bd0784e4fcaf1a159456f37ef1/pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b", size = 1920660 }, + { url = "https://files.pythonhosted.org/packages/e1/3c/32958c0a5d1935591b58337037a1695782e61261582d93d5a7f55441f879/pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f", size = 1845068 }, + { url = "https://files.pythonhosted.org/packages/92/a1/7e628e19b78e6ffdb2c92cccbb7eca84bfd3276cee4cafcae8833452f458/pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2", size = 1770095 }, + { url = "https://files.pythonhosted.org/packages/bb/17/d15fd8ce143cd1abb27be924eeff3c5c0fe3b0582f703c5a5273c11e67ce/pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791", size = 1790964 }, + { url = "https://files.pythonhosted.org/packages/24/cc/37feff1792f09dc33207fbad3897373229279d1973c211f9562abfdf137d/pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423", size = 1802384 }, + { url = "https://files.pythonhosted.org/packages/44/d8/ca9acd7f5f044d9ff6e43d7f35aab4b1d5982b4773761eabe3317fc68e30/pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63", size = 1997824 }, + { url = "https://files.pythonhosted.org/packages/35/0f/146269dba21b10d5bf86f9a7a7bbeab4ce1db06f466a1ab5ec3dec68b409/pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9", size = 2662907 }, + { url = "https://files.pythonhosted.org/packages/5a/7d/9573f006e39cd1a7b7716d1a264e3f4f353cf0a6042c04c01c6e31666f62/pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5", size = 2073953 }, + { url = "https://files.pythonhosted.org/packages/7e/a5/25200aaafd1e97e2ec3c1eb4b357669dd93911f2eba252bc60b6ba884fff/pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855", size = 1917822 }, + { url = "https://files.pythonhosted.org/packages/3e/b4/ac069c58e3cee70c69f03693222cc173fdf740d20d53167bceafc1efc7ca/pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4", size = 1968838 }, + { url = "https://files.pythonhosted.org/packages/d1/3d/9f96bbd6212b4b0a6dc6d037e446208d3420baba2b2b81e544094b18a859/pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d", size = 2121468 }, + { url = "https://files.pythonhosted.org/packages/ac/50/7399d536d6600d69059a87fff89861332c97a7b3471327a3663c7576e707/pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8", size = 1725373 }, + { url = "https://files.pythonhosted.org/packages/24/ba/9ac8744ab636c1161c598cc5e8261379b6b0f1d63c31242bf9d5ed41ed32/pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1", size = 1920594 }, + { url = "https://files.pythonhosted.org/packages/c0/2d/1f4ec8614225b516366f6c4c49d55ec42ebb93004c0bc9a3e0d21d0ed3c0/pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d", size = 1834597 }, + { url = "https://files.pythonhosted.org/packages/4d/f0/665d4cd60147992b1da0f5a9d1fd7f309c7f12999e3a494c4898165c64ab/pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4", size = 1721339 }, + { url = "https://files.pythonhosted.org/packages/a7/02/7b85ae2c3452e6b9f43b89482dc2a2ba771c31d86d93c2a5a250870b243b/pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211", size = 1794316 }, + { url = "https://files.pythonhosted.org/packages/61/09/f0fde8a9d66f37f3e08e03965a9833d71c4b5fb0287d8f625f88d79dfcd6/pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961", size = 1944713 }, + { url = "https://files.pythonhosted.org/packages/61/2b/0bfe144cac991700dbeaff620fed38b0565352acb342f90374ebf1350084/pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e", size = 1916385 }, + { url = "https://files.pythonhosted.org/packages/02/4f/7d1b8a28e4a1dd96cdde9e220627abd4d3a7860eb79cc682ccf828cf93e4/pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc", size = 1959666 }, + { url = "https://files.pythonhosted.org/packages/5d/9a/b2c520ef627001c68cf23990b2de42ba66eae58a3f56f13375ae9aecb88d/pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4", size = 2103742 }, + { url = "https://files.pythonhosted.org/packages/cd/43/b9a88a4e6454fcad63317e3dade687b68ae7d9f324c868411b1ea70218b3/pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b", size = 1916507 }, +] + +[[package]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + +[[package]] +name = "pytest" +version = "8.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, +] + +[[package]] +name = "pytest-profiling" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gprof2dot" }, + { name = "pytest" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/70/22a4b33739f07f1732a63e33bbfbf68e0fa58cfba9d200e76d01921eddbf/pytest-profiling-1.7.0.tar.gz", hash = "sha256:93938f147662225d2b8bd5af89587b979652426a8a6ffd7e73ec4a23e24b7f29", size = 30985 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/71/cdb746eaee0d3be65fd777b4ac821f5f051063f3084d4a200ecfd7f7ab40/pytest_profiling-1.7.0-py2.py3-none-any.whl", hash = "sha256:999cc9ac94f2e528e3f5d43465da277429984a1c237ae9818f8cfd0b06acb019", size = 8255 }, +] + +[[package]] +name = "pytest-xdist" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, +] + +[[package]] +name = "pyunormalize" +version = "15.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/5b/ddc89263363422c0d52fdc0a4d88a126621d5cb60359cd45679d3c0447fc/pyunormalize-15.1.0.tar.gz", hash = "sha256:cf4a87451a0f1cb76911aa97f432f4579e1f564a2f0c84ce488c73a73901b6c1", size = 515497 } + +[[package]] +name = "pywin32" +version = "306" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/dc/28c668097edfaf4eac4617ef7adf081b9cf50d254672fcf399a70f5efc41/pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", size = 8506422 }, + { url = "https://files.pythonhosted.org/packages/d3/d6/891894edec688e72c2e308b3243fad98b4066e1839fd2fe78f04129a9d31/pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", size = 9226392 }, + { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, + { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, + { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, + { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, + { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, + { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, + { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, + { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, + { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, + { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, + { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, + { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, + { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, + { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + +[[package]] +name = "pyzmq" +version = "26.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fd/05/bed626b9f7bb2322cdbbf7b4bd8f54b1b617b0d2ab2d3547d6e39428a48e/pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", size = 271975 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/a8/9837c39aba390eb7d01924ace49d761c8dbe7bc2d6082346d00c8332e431/pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629", size = 1340058 }, + { url = "https://files.pythonhosted.org/packages/a2/1f/a006f2e8e4f7d41d464272012695da17fb95f33b54342612a6890da96ff6/pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b", size = 1008818 }, + { url = "https://files.pythonhosted.org/packages/b6/09/b51b6683fde5ca04593a57bbe81788b6b43114d8f8ee4e80afc991e14760/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764", size = 673199 }, + { url = "https://files.pythonhosted.org/packages/c9/78/486f3e2e824f3a645238332bf5a4c4b4477c3063033a27c1e4052358dee2/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c", size = 911762 }, + { url = "https://files.pythonhosted.org/packages/5e/3b/2eb1667c9b866f53e76ee8b0c301b0469745a23bd5a87b7ee3d5dd9eb6e5/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a", size = 868773 }, + { url = "https://files.pythonhosted.org/packages/16/29/ca99b4598a9dc7e468b5417eda91f372b595be1e3eec9b7cbe8e5d3584e8/pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88", size = 868834 }, + { url = "https://files.pythonhosted.org/packages/ad/e5/9efaeb1d2f4f8c50da04144f639b042bc52869d3a206d6bf672ab3522163/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f", size = 1202861 }, + { url = "https://files.pythonhosted.org/packages/c3/62/c721b5608a8ac0a69bb83cbb7d07a56f3ff00b3991a138e44198a16f94c7/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282", size = 1515304 }, + { url = "https://files.pythonhosted.org/packages/87/84/e8bd321aa99b72f48d4606fc5a0a920154125bd0a4608c67eab742dab087/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea", size = 1414712 }, + { url = "https://files.pythonhosted.org/packages/cd/cd/420e3fd1ac6977b008b72e7ad2dae6350cc84d4c5027fc390b024e61738f/pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2", size = 578113 }, + { url = "https://files.pythonhosted.org/packages/5c/57/73930d56ed45ae0cb4946f383f985c855c9b3d4063f26416998f07523c0e/pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971", size = 641631 }, + { url = "https://files.pythonhosted.org/packages/61/d2/ae6ac5c397f1ccad59031c64beaafce7a0d6182e0452cc48f1c9c87d2dd0/pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa", size = 543528 }, + { url = "https://files.pythonhosted.org/packages/12/20/de7442172f77f7c96299a0ac70e7d4fb78cd51eca67aa2cf552b66c14196/pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218", size = 1340639 }, + { url = "https://files.pythonhosted.org/packages/98/4d/5000468bd64c7910190ed0a6c76a1ca59a68189ec1f007c451dc181a22f4/pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4", size = 1008710 }, + { url = "https://files.pythonhosted.org/packages/e1/bf/c67fd638c2f9fbbab8090a3ee779370b97c82b84cc12d0c498b285d7b2c0/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef", size = 673129 }, + { url = "https://files.pythonhosted.org/packages/86/94/99085a3f492aa538161cbf27246e8886ff850e113e0c294a5b8245f13b52/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317", size = 910107 }, + { url = "https://files.pythonhosted.org/packages/31/1d/346809e8a9b999646d03f21096428453465b1bca5cd5c64ecd048d9ecb01/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf", size = 867960 }, + { url = "https://files.pythonhosted.org/packages/ab/68/6fb6ae5551846ad5beca295b7bca32bf0a7ce19f135cb30e55fa2314e6b6/pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e", size = 869204 }, + { url = "https://files.pythonhosted.org/packages/0f/f9/18417771dee223ccf0f48e29adf8b4e25ba6d0e8285e33bcbce078070bc3/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37", size = 1203351 }, + { url = "https://files.pythonhosted.org/packages/e0/46/f13e67fe0d4f8a2315782cbad50493de6203ea0d744610faf4d5f5b16e90/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3", size = 1514204 }, + { url = "https://files.pythonhosted.org/packages/50/11/ddcf7343b7b7a226e0fc7b68cbf5a5bb56291fac07f5c3023bb4c319ebb4/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6", size = 1414339 }, + { url = "https://files.pythonhosted.org/packages/01/14/1c18d7d5b7be2708f513f37c61bfadfa62161c10624f8733f1c8451b3509/pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4", size = 576928 }, + { url = "https://files.pythonhosted.org/packages/3b/1b/0a540edd75a41df14ec416a9a500b9fec66e554aac920d4c58fbd5756776/pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5", size = 642317 }, + { url = "https://files.pythonhosted.org/packages/98/77/1cbfec0358078a4c5add529d8a70892db1be900980cdb5dd0898b3d6ab9d/pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003", size = 543834 }, + { url = "https://files.pythonhosted.org/packages/28/2f/78a766c8913ad62b28581777ac4ede50c6d9f249d39c2963e279524a1bbe/pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", size = 1343105 }, + { url = "https://files.pythonhosted.org/packages/b7/9c/4b1e2d3d4065be715e007fe063ec7885978fad285f87eae1436e6c3201f4/pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", size = 1008365 }, + { url = "https://files.pythonhosted.org/packages/4f/ef/5a23ec689ff36d7625b38d121ef15abfc3631a9aecb417baf7a4245e4124/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", size = 665923 }, + { url = "https://files.pythonhosted.org/packages/ae/61/d436461a47437d63c6302c90724cf0981883ec57ceb6073873f32172d676/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", size = 903400 }, + { url = "https://files.pythonhosted.org/packages/47/42/fc6d35ecefe1739a819afaf6f8e686f7f02a4dd241c78972d316f403474c/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", size = 860034 }, + { url = "https://files.pythonhosted.org/packages/07/3b/44ea6266a6761e9eefaa37d98fabefa112328808ac41aa87b4bbb668af30/pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", size = 860579 }, + { url = "https://files.pythonhosted.org/packages/38/6f/4df2014ab553a6052b0e551b37da55166991510f9e1002c89cab7ce3b3f2/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", size = 1196246 }, + { url = "https://files.pythonhosted.org/packages/38/9d/ee240fc0c9fe9817f0c9127a43238a3e28048795483c403cc10720ddef22/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", size = 1507441 }, + { url = "https://files.pythonhosted.org/packages/85/4f/01711edaa58d535eac4a26c294c617c9a01f09857c0ce191fd574d06f359/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", size = 1406498 }, + { url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 }, + { url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 }, + { url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 }, + { url = "https://files.pythonhosted.org/packages/04/a7/0f7e2f6c126fe6e62dbae0bc93b1bd3f1099cf7fea47a5468defebe3f39d/pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", size = 1006564 }, + { url = "https://files.pythonhosted.org/packages/31/b6/a187165c852c5d49f826a690857684333a6a4a065af0a6015572d2284f6a/pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", size = 1340447 }, + { url = "https://files.pythonhosted.org/packages/68/ba/f4280c58ff71f321602a6e24fd19879b7e79793fb8ab14027027c0fb58ef/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", size = 665485 }, + { url = "https://files.pythonhosted.org/packages/77/b5/c987a5c53c7d8704216f29fc3d810b32f156bcea488a940e330e1bcbb88d/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", size = 903484 }, + { url = "https://files.pythonhosted.org/packages/29/c9/07da157d2db18c72a7eccef8e684cefc155b712a88e3d479d930aa9eceba/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", size = 859981 }, + { url = "https://files.pythonhosted.org/packages/43/09/e12501bd0b8394b7d02c41efd35c537a1988da67fc9c745cae9c6c776d31/pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", size = 860334 }, + { url = "https://files.pythonhosted.org/packages/eb/ff/f5ec1d455f8f7385cc0a8b2acd8c807d7fade875c14c44b85c1bddabae21/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", size = 1196179 }, + { url = "https://files.pythonhosted.org/packages/ec/8a/bb2ac43295b1950fe436a81fc5b298be0b96ac76fb029b514d3ed58f7b27/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", size = 1507668 }, + { url = "https://files.pythonhosted.org/packages/a9/49/dbc284ebcfd2dca23f6349227ff1616a7ee2c4a35fe0a5d6c3deff2b4fed/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", size = 1406539 }, + { url = "https://files.pythonhosted.org/packages/00/68/093cdce3fe31e30a341d8e52a1ad86392e13c57970d722c1f62a1d1a54b6/pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", size = 575567 }, + { url = "https://files.pythonhosted.org/packages/92/ae/6cc4657148143412b5819b05e362ae7dd09fb9fe76e2a539dcff3d0386bc/pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", size = 637551 }, + { url = "https://files.pythonhosted.org/packages/6c/67/fbff102e201688f97c8092e4c3445d1c1068c2f27bbd45a578df97ed5f94/pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", size = 540378 }, + { url = "https://files.pythonhosted.org/packages/3f/fe/2d998380b6e0122c6c4bdf9b6caf490831e5f5e2d08a203b5adff060c226/pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", size = 1007378 }, + { url = "https://files.pythonhosted.org/packages/4a/f4/30d6e7157f12b3a0390bde94d6a8567cdb88846ed068a6e17238a4ccf600/pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", size = 1329532 }, + { url = "https://files.pythonhosted.org/packages/82/86/3fe917870e15ee1c3ad48229a2a64458e36036e64b4afa9659045d82bfa8/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", size = 653242 }, + { url = "https://files.pythonhosted.org/packages/50/2d/242e7e6ef6c8c19e6cb52d095834508cd581ffb925699fd3c640cdc758f1/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", size = 888404 }, + { url = "https://files.pythonhosted.org/packages/ac/11/7270566e1f31e4ea73c81ec821a4b1688fd551009a3d2bab11ec66cb1e8f/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", size = 845858 }, + { url = "https://files.pythonhosted.org/packages/91/d5/72b38fbc69867795c8711bdd735312f9fef1e3d9204e2f63ab57085434b9/pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", size = 847375 }, + { url = "https://files.pythonhosted.org/packages/dd/9a/10ed3c7f72b4c24e719c59359fbadd1a27556a28b36cdf1cd9e4fb7845d5/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", size = 1183489 }, + { url = "https://files.pythonhosted.org/packages/72/2d/8660892543fabf1fe41861efa222455811adac9f3c0818d6c3170a1153e3/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", size = 1492932 }, + { url = "https://files.pythonhosted.org/packages/7b/d6/32fd69744afb53995619bc5effa2a405ae0d343cd3e747d0fbc43fe894ee/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", size = 1392485 }, + { url = "https://files.pythonhosted.org/packages/53/fb/36b2b2548286e9444e52fcd198760af99fd89102b5be50f0660fcfe902df/pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", size = 906955 }, + { url = "https://files.pythonhosted.org/packages/77/8f/6ce54f8979a01656e894946db6299e2273fcee21c8e5fa57c6295ef11f57/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", size = 565701 }, + { url = "https://files.pythonhosted.org/packages/ee/1c/bf8cd66730a866b16db8483286078892b7f6536f8c389fb46e4beba0a970/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", size = 794312 }, + { url = "https://files.pythonhosted.org/packages/71/43/91fa4ff25bbfdc914ab6bafa0f03241d69370ef31a761d16bb859f346582/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca", size = 752775 }, + { url = "https://files.pythonhosted.org/packages/ec/d2/3b2ab40f455a256cb6672186bea95cd97b459ce4594050132d71e76f0d6f/pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", size = 550762 }, +] + +[[package]] +name = "regex" +version = "2024.9.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/38/148df33b4dbca3bd069b963acab5e0fa1a9dbd6820f8c322d0dd6faeff96/regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd", size = 399403 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/12/497bd6599ce8a239ade68678132296aec5ee25ebea45fc8ba91aa60fceec/regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408", size = 482488 }, + { url = "https://files.pythonhosted.org/packages/c1/24/595ddb9bec2a9b151cdaf9565b0c9f3da9f0cb1dca6c158bc5175332ddf8/regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d", size = 287443 }, + { url = "https://files.pythonhosted.org/packages/69/a8/b2fb45d9715b1469383a0da7968f8cacc2f83e9fbbcd6b8713752dd980a6/regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5", size = 284561 }, + { url = "https://files.pythonhosted.org/packages/88/87/1ce4a5357216b19b7055e7d3b0efc75a6e426133bf1e7d094321df514257/regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c", size = 783177 }, + { url = "https://files.pythonhosted.org/packages/3c/65/b9f002ab32f7b68e7d1dcabb67926f3f47325b8dbc22cc50b6a043e1d07c/regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8", size = 823193 }, + { url = "https://files.pythonhosted.org/packages/22/91/8339dd3abce101204d246e31bc26cdd7ec07c9f91598472459a3a902aa41/regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35", size = 809950 }, + { url = "https://files.pythonhosted.org/packages/cb/19/556638aa11c2ec9968a1da998f07f27ec0abb9bf3c647d7c7985ca0b8eea/regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71", size = 782661 }, + { url = "https://files.pythonhosted.org/packages/d1/e9/7a5bc4c6ef8d9cd2bdd83a667888fc35320da96a4cc4da5fa084330f53db/regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8", size = 772348 }, + { url = "https://files.pythonhosted.org/packages/f1/0b/29f2105bfac3ed08e704914c38e93b07c784a6655f8a015297ee7173e95b/regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a", size = 697460 }, + { url = "https://files.pythonhosted.org/packages/71/3a/52ff61054d15a4722605f5872ad03962b319a04c1ebaebe570b8b9b7dde1/regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d", size = 769151 }, + { url = "https://files.pythonhosted.org/packages/97/07/37e460ab5ca84be8e1e197c3b526c5c86993dcc9e13cbc805c35fc2463c1/regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137", size = 777478 }, + { url = "https://files.pythonhosted.org/packages/65/7b/953075723dd5ab00780043ac2f9de667306ff9e2a85332975e9f19279174/regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6", size = 845373 }, + { url = "https://files.pythonhosted.org/packages/40/b8/3e9484c6230b8b6e8f816ab7c9a080e631124991a4ae2c27a81631777db0/regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca", size = 845369 }, + { url = "https://files.pythonhosted.org/packages/b7/99/38434984d912edbd2e1969d116257e869578f67461bd7462b894c45ed874/regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a", size = 773935 }, + { url = "https://files.pythonhosted.org/packages/ab/67/43174d2b46fa947b7b9dfe56b6c8a8a76d44223f35b1d64645a732fd1d6f/regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0", size = 261624 }, + { url = "https://files.pythonhosted.org/packages/c4/2a/4f9c47d9395b6aff24874c761d8d620c0232f97c43ef3cf668c8b355e7a7/regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623", size = 274020 }, + { url = "https://files.pythonhosted.org/packages/86/a1/d526b7b6095a0019aa360948c143aacfeb029919c898701ce7763bbe4c15/regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df", size = 482483 }, + { url = "https://files.pythonhosted.org/packages/32/d9/bfdd153179867c275719e381e1e8e84a97bd186740456a0dcb3e7125c205/regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268", size = 287442 }, + { url = "https://files.pythonhosted.org/packages/33/c4/60f3370735135e3a8d673ddcdb2507a8560d0e759e1398d366e43d000253/regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad", size = 284561 }, + { url = "https://files.pythonhosted.org/packages/b1/51/91a5ebdff17f9ec4973cb0aa9d37635efec1c6868654bbc25d1543aca4ec/regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679", size = 791779 }, + { url = "https://files.pythonhosted.org/packages/07/4a/022c5e6f0891a90cd7eb3d664d6c58ce2aba48bff107b00013f3d6167069/regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4", size = 832605 }, + { url = "https://files.pythonhosted.org/packages/ac/1c/3793990c8c83ca04e018151ddda83b83ecc41d89964f0f17749f027fc44d/regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664", size = 818556 }, + { url = "https://files.pythonhosted.org/packages/e9/5c/8b385afbfacb853730682c57be56225f9fe275c5bf02ac1fc88edbff316d/regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50", size = 792808 }, + { url = "https://files.pythonhosted.org/packages/9b/8b/a4723a838b53c771e9240951adde6af58c829fb6a6a28f554e8131f53839/regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199", size = 781115 }, + { url = "https://files.pythonhosted.org/packages/83/5f/031a04b6017033d65b261259c09043c06f4ef2d4eac841d0649d76d69541/regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4", size = 778155 }, + { url = "https://files.pythonhosted.org/packages/fd/cd/4660756070b03ce4a66663a43f6c6e7ebc2266cc6b4c586c167917185eb4/regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd", size = 784614 }, + { url = "https://files.pythonhosted.org/packages/93/8d/65b9bea7df120a7be8337c415b6d256ba786cbc9107cebba3bf8ff09da99/regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f", size = 853744 }, + { url = "https://files.pythonhosted.org/packages/96/a7/fba1eae75eb53a704475baf11bd44b3e6ccb95b316955027eb7748f24ef8/regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96", size = 855890 }, + { url = "https://files.pythonhosted.org/packages/45/14/d864b2db80a1a3358534392373e8a281d95b28c29c87d8548aed58813910/regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1", size = 781887 }, + { url = "https://files.pythonhosted.org/packages/4d/a9/bfb29b3de3eb11dc9b412603437023b8e6c02fb4e11311863d9bf62c403a/regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9", size = 261644 }, + { url = "https://files.pythonhosted.org/packages/c7/ab/1ad2511cf6a208fde57fafe49829cab8ca018128ab0d0b48973d8218634a/regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf", size = 274033 }, + { url = "https://files.pythonhosted.org/packages/6e/92/407531450762bed778eedbde04407f68cbd75d13cee96c6f8d6903d9c6c1/regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7", size = 483590 }, + { url = "https://files.pythonhosted.org/packages/8e/a2/048acbc5ae1f615adc6cba36cc45734e679b5f1e4e58c3c77f0ed611d4e2/regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231", size = 288175 }, + { url = "https://files.pythonhosted.org/packages/8a/ea/909d8620329ab710dfaf7b4adee41242ab7c9b95ea8d838e9bfe76244259/regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d", size = 284749 }, + { url = "https://files.pythonhosted.org/packages/ca/fa/521eb683b916389b4975337873e66954e0f6d8f91bd5774164a57b503185/regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64", size = 795181 }, + { url = "https://files.pythonhosted.org/packages/28/db/63047feddc3280cc242f9c74f7aeddc6ee662b1835f00046f57d5630c827/regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42", size = 835842 }, + { url = "https://files.pythonhosted.org/packages/e3/94/86adc259ff8ec26edf35fcca7e334566c1805c7493b192cb09679f9c3dee/regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766", size = 823533 }, + { url = "https://files.pythonhosted.org/packages/29/52/84662b6636061277cb857f658518aa7db6672bc6d1a3f503ccd5aefc581e/regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a", size = 797037 }, + { url = "https://files.pythonhosted.org/packages/c3/2a/cd4675dd987e4a7505f0364a958bc41f3b84942de9efaad0ef9a2646681c/regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9", size = 784106 }, + { url = "https://files.pythonhosted.org/packages/6f/75/3ea7ec29de0bbf42f21f812f48781d41e627d57a634f3f23947c9a46e303/regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d", size = 782468 }, + { url = "https://files.pythonhosted.org/packages/d3/67/15519d69b52c252b270e679cb578e22e0c02b8dd4e361f2b04efcc7f2335/regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822", size = 790324 }, + { url = "https://files.pythonhosted.org/packages/9c/71/eff77d3fe7ba08ab0672920059ec30d63fa7e41aa0fb61c562726e9bd721/regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0", size = 860214 }, + { url = "https://files.pythonhosted.org/packages/81/11/e1bdf84a72372e56f1ea4b833dd583b822a23138a616ace7ab57a0e11556/regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a", size = 859420 }, + { url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 }, + { url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 }, + { url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 }, + { url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 }, + { url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 }, + { url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 }, + { url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 }, + { url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 }, + { url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 }, + { url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 }, + { url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 }, + { url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 }, + { url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 }, + { url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 }, + { url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 }, + { url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 }, + { url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 }, + { url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "rlp" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "eth-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/49/bcd4d3f9210ed78749eab04d236eeb98f98fbcc16977f308ee4637c1bad8/rlp-4.0.1.tar.gz", hash = "sha256:bcefb11013dfadf8902642337923bd0c786dc8a27cb4c21da6e154e52869ecb1", size = 33710 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/03/3ae09a1c43657d17530dd98de6e381cc66ac514daa67000ccf99afc808fc/rlp-4.0.1-py3-none-any.whl", hash = "sha256:ff6846c3c27b97ee0492373aa074a7c3046aadd973320f4fffa7ac45564b0258", size = 20639 }, +] + +[[package]] +name = "six" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, +] + +[[package]] +name = "sympy" +version = "1.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/15/4a041424c7187f41cce678f5a02189b244e9aac61a18b45cd415a3a470f3/sympy-1.13.2.tar.gz", hash = "sha256:401449d84d07be9d0c7a46a64bd54fe097667d5e7181bfe67ec777be9e01cb13", size = 7532926 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/f9/6845bf8fca0eaf847da21c5d5bc6cd92797364662824a11d3f836423a1a5/sympy-1.13.2-py3-none-any.whl", hash = "sha256:c51d75517712f1aed280d4ce58506a4a88d635d6b5dd48b39102a7ae1f3fcfe9", size = 6189289 }, +] + +[[package]] +name = "tomli" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", size = 15164 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", size = 12757 }, +] + +[[package]] +name = "toolz" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/bf/5e12db234df984f6df3c7f12f1428aa680ba4e101f63f4b8b3f9e8d2e617/toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d", size = 66550 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/8a/d82202c9f89eab30f9fc05380daae87d617e2ad11571ab23d7c13a29bb54/toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85", size = 56121 }, +] + +[[package]] +name = "tornado" +version = "6.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/66/398ac7167f1c7835406888a386f6d0d26ee5dbf197d8a571300be57662d3/tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9", size = 500623 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/d9/c33be3c1a7564f7d42d87a8d186371a75fd142097076767a5c27da941fef/tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8", size = 435924 }, + { url = "https://files.pythonhosted.org/packages/2e/0f/721e113a2fac2f1d7d124b3279a1da4c77622e104084f56119875019ffab/tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14", size = 433883 }, + { url = "https://files.pythonhosted.org/packages/13/cf/786b8f1e6fe1c7c675e79657448178ad65e41c1c9765ef82e7f6f765c4c5/tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4", size = 437224 }, + { url = "https://files.pythonhosted.org/packages/e4/8e/a6ce4b8d5935558828b0f30f3afcb2d980566718837b3365d98e34f6067e/tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842", size = 436597 }, + { url = "https://files.pythonhosted.org/packages/22/d4/54f9d12668b58336bd30defe0307e6c61589a3e687b05c366f804b7faaf0/tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3", size = 436797 }, + { url = "https://files.pythonhosted.org/packages/cf/3f/2c792e7afa7dd8b24fad7a2ed3c2f24a5ec5110c7b43a64cb6095cc106b8/tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f", size = 437516 }, + { url = "https://files.pythonhosted.org/packages/71/63/c8fc62745e669ac9009044b889fc531b6f88ac0f5f183cac79eaa950bb23/tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4", size = 436958 }, + { url = "https://files.pythonhosted.org/packages/94/d4/f8ac1f5bd22c15fad3b527e025ce219bd526acdbd903f52053df2baecc8b/tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698", size = 436882 }, + { url = "https://files.pythonhosted.org/packages/4b/3e/a8124c21cc0bbf144d7903d2a0cadab15cadaf683fa39a0f92bc567f0d4d/tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d", size = 438092 }, + { url = "https://files.pythonhosted.org/packages/d9/2f/3f2f05e84a7aff787a96d5fb06821323feb370fe0baed4db6ea7b1088f32/tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7", size = 438532 }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, +] + +[[package]] +name = "typeguard" +version = "2.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/38/c61bfcf62a7b572b5e9363a802ff92559cb427ee963048e1442e3aef7490/typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4", size = 40604 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/bb/d43e5c75054e53efce310e79d63df0ac3f25e34c926be5dffb7d283fb2a8/typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1", size = 17605 }, +] + +[[package]] +name = "types-requests" +version = "2.32.0.20240907" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/94/b6f90e5f09e1d621d5cd6d1057d5d28d4019d95f06eab205afa743ba1907/types-requests-2.32.0.20240907.tar.gz", hash = "sha256:ff33935f061b5e81ec87997e91050f7b4af4f82027a7a7a9d9aaea04a963fdf8", size = 18004 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/6e/425219be1dfc954c3e129b3ea70407abc78c1bd6414d0c7180df9940ca1f/types_requests-2.32.0.20240907-py3-none-any.whl", hash = "sha256:1d1e79faeaf9d42def77f3c304893dea17a97cae98168ac69f3cb465516ee8da", size = 15828 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827 }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, +] + +[[package]] +name = "web3" +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "eth-abi" }, + { name = "eth-account" }, + { name = "eth-hash", extra = ["pycryptodome"] }, + { name = "eth-typing" }, + { name = "eth-utils" }, + { name = "hexbytes" }, + { name = "pydantic" }, + { name = "pyunormalize" }, + { name = "pywin32", marker = "platform_system == 'Windows'" }, + { name = "requests" }, + { name = "types-requests" }, + { name = "typing-extensions" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/e0/358a08783fbe050ef27a186ed483ba4bd6e0da0ea7d7b86016b57f32b62f/web3-7.2.0.tar.gz", hash = "sha256:98bbee7e73dcdfa567633c694a80e62ce78a0a7b16a9c52027764db06b194be0", size = 2131978 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/c2/dd2daade545424815a1e95fadbd97907eb3961f39d45c3a1063ee126341a/web3-7.2.0-py3-none-any.whl", hash = "sha256:35def004dd652a7ee5b2321431797c4aa26697faec4e34196aa2a158e63005ff", size = 1321643 }, +] + +[[package]] +name = "websockets" +version = "13.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/1c/78687e0267b09412409ac134f10fd14d14ac6475da892a8b09a02d0f6ae2/websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e", size = 149769 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/bd/224fd6c4c0d60645444bb77cabf3633a6c14a47e2d03cdbc2136486c51f7/websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f", size = 150946 }, + { url = "https://files.pythonhosted.org/packages/44/5b/16f06fa678432d0cdbc55477bb6f0215c42b31615948bd63a884c294e0a5/websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c", size = 148600 }, + { url = "https://files.pythonhosted.org/packages/5a/33/c57b4ecdd26510ffcda37d30073097f1e9015b316fe21b513360bf2d8ee2/websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f", size = 148853 }, + { url = "https://files.pythonhosted.org/packages/71/a3/6a8a0e86c44fc39fab83fc6b946f9f7d53e5be6824916450dac637937086/websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543", size = 157935 }, + { url = "https://files.pythonhosted.org/packages/a0/58/ba14373234d2b7cce48031f7bd05ab2d23a11ffa0d35c3348d5729fa0527/websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d", size = 156949 }, + { url = "https://files.pythonhosted.org/packages/7d/8a/8e2319207bae70156d0505bf91e192de015ee91ccc5b1afb406bb7db3819/websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f", size = 157260 }, + { url = "https://files.pythonhosted.org/packages/03/cd/31ff415c4b0dc3c185bd87c412affdc5fab42c700b04d02b380bfb789310/websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8", size = 157661 }, + { url = "https://files.pythonhosted.org/packages/e8/58/a95d1dc6f589cbbfca0918d160ff27c920ab2e94637b750591c6f226cf27/websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b", size = 157078 }, + { url = "https://files.pythonhosted.org/packages/ce/02/207f49e1c22c8fad9e6353815de698e778d365609801dc2387e01e0f94a2/websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448", size = 157027 }, + { url = "https://files.pythonhosted.org/packages/3b/aa/e59d994712635e9e6bc883471e12cc493e3a704e4e22e9d4a59ff1491161/websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3", size = 151776 }, + { url = "https://files.pythonhosted.org/packages/7b/f9/83bc78788d6ce5492fa44133708584a885080aa7c790be2532f326948115/websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0", size = 152206 }, + { url = "https://files.pythonhosted.org/packages/20/95/e002ec55688b751d3c9cc131c1960af7e440d95e1954c441535b9da2bf36/websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7", size = 150948 }, + { url = "https://files.pythonhosted.org/packages/62/6b/85fb8c13b278db7d45e27ff6ee0db3009b0fadef7c37c85e6cb4a0fbf08e/websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4", size = 148599 }, + { url = "https://files.pythonhosted.org/packages/e8/2e/c80cafbab86f8c399ba8323efff298b7062055724146391443d266e9c49b/websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2", size = 148851 }, + { url = "https://files.pythonhosted.org/packages/2e/67/631d4b1f28fef6f12730c0cbe982203a9d6814768c2ab1e0a352d9a07a97/websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0", size = 158509 }, + { url = "https://files.pythonhosted.org/packages/9b/e8/ba740eab2a9c5b903ea94d9a2a448db63f0a296265aee976d17abf734758/websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e", size = 157507 }, + { url = "https://files.pythonhosted.org/packages/f8/4e/ffa2f1aad2da67e483fb7bad6c69f80c786f4e85d1942a39d7b275b084ed/websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462", size = 157881 }, + { url = "https://files.pythonhosted.org/packages/c0/85/0cbfe7b0e0dd3d885cd87b0523c6690ae7369feaf3aab5a23e95bdb4fefa/websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501", size = 158187 }, + { url = "https://files.pythonhosted.org/packages/39/29/d9df0a1daedebefaeea88fb8071539604df09fd0f1bfb73bf58333aa3eb6/websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418", size = 157626 }, + { url = "https://files.pythonhosted.org/packages/7d/9a/f88e186059f6b89f8bb08461d9fda7a26940b7b8897c7d7f02aead40b7e4/websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df", size = 157575 }, + { url = "https://files.pythonhosted.org/packages/cf/e4/ecdb8352ebab2e44c10b9d6f50008f95e30bb0a7ef0e6b66cb475d539d74/websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f", size = 151779 }, + { url = "https://files.pythonhosted.org/packages/12/40/46967d00640e6c3231b73d310617927a11c91bcc044dd5a0860a3c457c33/websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075", size = 152206 }, + { url = "https://files.pythonhosted.org/packages/4e/51/23ed2d239f1c3087c1431d41cfd159865df0bc35bb0c89973e3b6a0fff9b/websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a", size = 150953 }, + { url = "https://files.pythonhosted.org/packages/57/8d/814a7ef62b916b0f39108ad2e4d9b4cb0f8c640f8c30202fb63041598ada/websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956", size = 148610 }, + { url = "https://files.pythonhosted.org/packages/ad/8b/a378d21124011737e0e490a8a6ef778914b03e50c8d938de2f2170a20dbd/websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af", size = 148849 }, + { url = "https://files.pythonhosted.org/packages/46/d2/814a61226af313c1bc289cfe3a10f87bf426b6f2d9df0f927c47afab7612/websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf", size = 158772 }, + { url = "https://files.pythonhosted.org/packages/a1/7e/5987299eb7e131216c9027b05a65f149cbc2bde7c582e694d9eed6ec3d40/websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c", size = 157724 }, + { url = "https://files.pythonhosted.org/packages/94/6e/eaf95894042ba8a05a125fe8bcf9ee3572fef6edbcbf49478f4991c027cc/websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4", size = 158152 }, + { url = "https://files.pythonhosted.org/packages/ce/ba/a1315d569cc2dadaafda74a9cea16ab5d68142525937f1994442d969b306/websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab", size = 158442 }, + { url = "https://files.pythonhosted.org/packages/90/9b/59866695cfd05e785c90932fef3dae4682eb4e06e7076b7c53478f25faad/websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d", size = 157823 }, + { url = "https://files.pythonhosted.org/packages/9b/47/20af68a313b6453d2d094ccc497b7232e8475175d234e3e5bef5088521e5/websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237", size = 157818 }, + { url = "https://files.pythonhosted.org/packages/f8/bb/60aaedc80e388e978617dda1ff38788780c6b0f6e462b85368cb934131a5/websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185", size = 151785 }, + { url = "https://files.pythonhosted.org/packages/16/2e/e47692f569e1be2e66c1dbc5e85ea4d2cc93b80027fbafa28ae8b0dee52c/websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99", size = 152214 }, + { url = "https://files.pythonhosted.org/packages/46/37/d8ef4b68684d1fa368a5c64be466db07fc58b68163bc2496db2d4cc208ff/websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa", size = 150962 }, + { url = "https://files.pythonhosted.org/packages/95/49/78aeb3af08ec9887a9065e85cef9d7e199d6c6261fcd39eec087f3a62328/websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231", size = 148621 }, + { url = "https://files.pythonhosted.org/packages/31/0d/dc9b7cec8deaee452092a631ccda894bd7098859f71dd7639b4b5b9c615c/websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9", size = 148853 }, + { url = "https://files.pythonhosted.org/packages/16/bf/734cbd815d7bc94cffe35c934f4e08b619bf3b47df1c6c7af21c1d35bcfe/websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75", size = 158741 }, + { url = "https://files.pythonhosted.org/packages/af/9b/756f89b12fee8931785531a314e6f087b21774a7f8c60878e597c684f91b/websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553", size = 157690 }, + { url = "https://files.pythonhosted.org/packages/d3/37/31f97132d2262e666b797e250879ca833eab55115f88043b3952a2840eb8/websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920", size = 158132 }, + { url = "https://files.pythonhosted.org/packages/41/ce/59c8d44e148c002fec506a9527504fb4281676e2e75c2ee5a58180f1b99a/websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329", size = 158490 }, + { url = "https://files.pythonhosted.org/packages/1a/74/5b31ce0f318b902c0d70c031f8e1228ba1a4d95a46b2a24a2a5ac17f9cf0/websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7", size = 157879 }, + { url = "https://files.pythonhosted.org/packages/0d/a7/6eac4f04177644bbc98deb98d11770cc7fbc216f6f67ab187c150540fd52/websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2", size = 157873 }, + { url = "https://files.pythonhosted.org/packages/72/f6/b8b30a3b134dfdb4ccd1694befa48fddd43783957c988a1dab175732af33/websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb", size = 151782 }, + { url = "https://files.pythonhosted.org/packages/3e/88/d94ccc006c69583168aa9dd73b3f1885c8931f2c676f4bdd8cbfae91c7b6/websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b", size = 152212 }, + { url = "https://files.pythonhosted.org/packages/ae/d8/9d0e5c836f89147aa769b72e2d82217ae1c17ffd5f375de8d785e1e16870/websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89", size = 148629 }, + { url = "https://files.pythonhosted.org/packages/9c/ff/005a440db101d298b42cc7565579ed55a7e12ccc0c6ea0491e53bb073930/websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad", size = 148863 }, + { url = "https://files.pythonhosted.org/packages/9f/06/44d7c7d48e0beaecbacaf0020eafccd490741e496622da6b2a5626fe6689/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e", size = 150226 }, + { url = "https://files.pythonhosted.org/packages/48/6f/861ba99aa3c5cb54412c3870d5549e466d82d2f7c440b435e23ca6496865/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc", size = 149833 }, + { url = "https://files.pythonhosted.org/packages/8d/a0/9fb50648f69ed341e30096356a815c89c4f9daef24a32e9754dbdc3de8a8/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333", size = 149778 }, + { url = "https://files.pythonhosted.org/packages/f1/ba/48b5b8343e6f62a8a809ffe987d4d7c911cedcb1b8353f3da615f2609893/websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32", size = 152259 }, + { url = "https://files.pythonhosted.org/packages/fd/bd/d34c4b7918453506d2149208b175368738148ffc4ba256d7fd8708956732/websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817", size = 145262 }, +] + +[[package]] +name = "yarl" +version = "1.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/3d/4924f9ed49698bac5f112bc9b40aa007bbdcd702462c1df3d2e1383fb158/yarl-1.11.1.tar.gz", hash = "sha256:1bb2d9e212fb7449b8fb73bc461b51eaa17cc8430b4a87d87be7b25052d92f53", size = 162095 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/a3/4e67b1463c12ba178aace33b62468377473c77b33a95bcb12b67b2b93817/yarl-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00", size = 188473 }, + { url = "https://files.pythonhosted.org/packages/f3/86/c0c76e69a390fb43533783582714e8a58003f443b81cac1605ce71cade00/yarl-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d", size = 114362 }, + { url = "https://files.pythonhosted.org/packages/07/ef/e6bee78c1bf432de839148fe9fdc1cf5e7fbd6402d8b0b7d7a1522fb9733/yarl-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e", size = 112537 }, + { url = "https://files.pythonhosted.org/packages/37/f4/3406e76ed71e4d3023dbae4514513a387e2e753cb8a4cadd6ff9ba08a046/yarl-1.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc", size = 442573 }, + { url = "https://files.pythonhosted.org/packages/37/15/98b4951271a693142e551fea24bca1e96be71b5256b3091dbe8433532a45/yarl-1.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec", size = 468046 }, + { url = "https://files.pythonhosted.org/packages/88/1a/f10b88c4d8200708cbc799aad978a37a0ab15a4a72511c60bed11ee585c4/yarl-1.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf", size = 462124 }, + { url = "https://files.pythonhosted.org/packages/02/a3/97b527b5c4551c3b17fd095fe019435664330060b3879c8c1ae80985d4bc/yarl-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49", size = 446807 }, + { url = "https://files.pythonhosted.org/packages/40/06/da47aae54f1bb8ac0668d68bbdde40ba761643f253b2c16fdb4362af8ca3/yarl-1.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff", size = 431778 }, + { url = "https://files.pythonhosted.org/packages/ba/a1/54992cd68f61c11d975184f4c8a4c7f43a838e7c6ce183030a3fc0a257a6/yarl-1.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad", size = 443702 }, + { url = "https://files.pythonhosted.org/packages/5c/8b/adf290dc272a1a30a0e9dc04e2e62486be80f371bd9da2e9899f8e6181f3/yarl-1.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145", size = 448289 }, + { url = "https://files.pythonhosted.org/packages/fc/98/e6ad935fa009890b9ef2769266dc9dceaeee5a7f9a57bc7daf50b5b6c305/yarl-1.11.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd", size = 471660 }, + { url = "https://files.pythonhosted.org/packages/91/5d/1ad82849ce3c02661395f5097878c58ecabc4dac5d2d98e4f85949386448/yarl-1.11.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26", size = 469830 }, + { url = "https://files.pythonhosted.org/packages/e0/70/376046a7f69cfec814b97fb8bf1af6f16dcbe37fd0ef89a9f87b04156923/yarl-1.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46", size = 457671 }, + { url = "https://files.pythonhosted.org/packages/33/49/825f84f9a5d26d26fbf82531cee3923f356e2d8efc1819b85ada508fa91f/yarl-1.11.1-cp310-cp310-win32.whl", hash = "sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91", size = 101184 }, + { url = "https://files.pythonhosted.org/packages/b0/29/2a08a45b9f2eddd1b840813698ee655256f43b507c12f7f86df947cf5f8f/yarl-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998", size = 110175 }, + { url = "https://files.pythonhosted.org/packages/af/f1/f3e6be722461cab1e7c6aea657685897956d6e4743940d685d167914e31c/yarl-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68", size = 188410 }, + { url = "https://files.pythonhosted.org/packages/4b/c1/21cc66b263fdc2ec10b6459aed5b239f07eed91a77438d88f0e1bd70e202/yarl-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe", size = 114293 }, + { url = "https://files.pythonhosted.org/packages/31/7a/0ecab63a166a22357772f4a2852c859e2d5a7b02a5c58803458dd516e6b4/yarl-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675", size = 112548 }, + { url = "https://files.pythonhosted.org/packages/57/5d/78152026864475e841fdae816499345364c8e364b45ea6accd0814a295f0/yarl-1.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63", size = 485002 }, + { url = "https://files.pythonhosted.org/packages/d3/70/2e880d74aeb4908d45c6403e46bbd4aa866ae31ddb432318d9b8042fe0f6/yarl-1.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27", size = 504850 }, + { url = "https://files.pythonhosted.org/packages/06/58/5676a47b6d2751853f89d1d68b6a54d725366da6a58482f2410fa7eb38af/yarl-1.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5", size = 499291 }, + { url = "https://files.pythonhosted.org/packages/4d/e5/b56d535703a63a8d86ac82059e630e5ba9c0d5626d9c5ac6af53eed815c2/yarl-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92", size = 487818 }, + { url = "https://files.pythonhosted.org/packages/f3/b4/6b95e1e0983593f4145518980b07126a27e2a4938cb6afb8b592ce6fc2c9/yarl-1.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b", size = 470447 }, + { url = "https://files.pythonhosted.org/packages/a8/e5/5d349b7b04ed4247d4f717f271fce601a79d10e2ac81166c13f97c4973a9/yarl-1.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a", size = 484544 }, + { url = "https://files.pythonhosted.org/packages/fa/dc/ce90e9d85ef2233e81148a9658e4ea8372c6de070ce96c5c8bd3ff365144/yarl-1.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83", size = 482409 }, + { url = "https://files.pythonhosted.org/packages/4c/a1/17c0a03615b0cd213aee2e318a0fbd3d07259c37976d85af9eec6184c589/yarl-1.11.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff", size = 512970 }, + { url = "https://files.pythonhosted.org/packages/6c/ed/1e317799d54c79a3e4846db597510f5c84fb7643bb8703a3848136d40809/yarl-1.11.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c", size = 515203 }, + { url = "https://files.pythonhosted.org/packages/7a/37/9a4e2d73953956fa686fa0f0c4a0881245f39423fa75875d981b4f680611/yarl-1.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e", size = 497323 }, + { url = "https://files.pythonhosted.org/packages/a3/c3/a25ae9c85c0e50a8722aecc486ac5ba53b28d1384548df99b2145cb69862/yarl-1.11.1-cp311-cp311-win32.whl", hash = "sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6", size = 101226 }, + { url = "https://files.pythonhosted.org/packages/90/6d/c62ba0ae0232a0b0012706a7735a16b44a03216fedfb6ea0bcda79d1e12c/yarl-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b", size = 110471 }, + { url = "https://files.pythonhosted.org/packages/3b/05/379002019a0c9d5dc0c4cc6f71e324ea43461ae6f58e94ee87e07b8ffa90/yarl-1.11.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0", size = 189044 }, + { url = "https://files.pythonhosted.org/packages/23/d5/e62cfba5ceaaf92ee4f9af6f9c9ab2f2b47d8ad48687fa69570a93b0872c/yarl-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265", size = 114867 }, + { url = "https://files.pythonhosted.org/packages/b1/10/6abc0bd7e7fe7c6b9b9e9ce0ff558912c9ecae65a798f5442020ef9e4177/yarl-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867", size = 112737 }, + { url = "https://files.pythonhosted.org/packages/37/a5/ad026afde5efe1849f4f55bd9f9a2cb5b006511b324db430ae5336104fb3/yarl-1.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd", size = 482887 }, + { url = "https://files.pythonhosted.org/packages/f8/82/b8bee972617b800319b4364cfcd69bfaf7326db052e91a56e63986cc3e05/yarl-1.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef", size = 498635 }, + { url = "https://files.pythonhosted.org/packages/af/ad/ac688503b134e02e8505415f0b8e94dc8e92a97e82abdd9736658389b5ae/yarl-1.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8", size = 496198 }, + { url = "https://files.pythonhosted.org/packages/ce/f2/b6cae0ad1afed6e95f82ab2cb9eb5b63e41f1463ece2a80c39d80cf6167a/yarl-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870", size = 489068 }, + { url = "https://files.pythonhosted.org/packages/c8/f4/355e69b5563154b40550233ffba8f6099eac0c99788600191967763046cf/yarl-1.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2", size = 468286 }, + { url = "https://files.pythonhosted.org/packages/26/3d/3c37f3f150faf87b086f7915724f2fcb9ff2f7c9d3f6c0f42b7722bd9b77/yarl-1.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/94/ee/d591abbaea3b14e0f68bdec5cbcb75f27107190c51889d518bafe5d8f120/yarl-1.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa", size = 484947 }, + { url = "https://files.pythonhosted.org/packages/57/70/ad1c65a13315f03ff0c63fd6359dd40d8198e2a42e61bf86507602a0364f/yarl-1.11.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff", size = 505610 }, + { url = "https://files.pythonhosted.org/packages/4c/8c/6086dec0f8d7df16d136b38f373c49cf3d2fb94464e5a10bf788b36f3f54/yarl-1.11.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239", size = 515951 }, + { url = "https://files.pythonhosted.org/packages/49/79/e0479e9a3bbb7bdcb82779d89711b97cea30902a4bfe28d681463b7071ce/yarl-1.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45", size = 501273 }, + { url = "https://files.pythonhosted.org/packages/8e/85/eab962453e81073276b22f3d1503dffe6bfc3eb9cd0f31899970de05d490/yarl-1.11.1-cp312-cp312-win32.whl", hash = "sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447", size = 101139 }, + { url = "https://files.pythonhosted.org/packages/5d/de/618b3e5cab10af8a2ed3eb625dac61c1d16eb155d1f56f9fdb3500786c12/yarl-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639", size = 110504 }, + { url = "https://files.pythonhosted.org/packages/07/b7/948e4f427817e0178f3737adf6712fea83f76921e11e2092f403a8a9dc4a/yarl-1.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c", size = 185061 }, + { url = "https://files.pythonhosted.org/packages/f3/67/8d91ad79a3b907b4fef27fafa912350554443ba53364fff3c347b41105cb/yarl-1.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e", size = 113056 }, + { url = "https://files.pythonhosted.org/packages/a1/77/6b2348a753702fa87f435cc33dcec21981aaca8ef98a46566a7b29940b4a/yarl-1.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93", size = 110958 }, + { url = "https://files.pythonhosted.org/packages/8e/3e/6eadf32656741549041f549a392f3b15245d3a0a0b12a9bc22bd6b69621f/yarl-1.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d", size = 470326 }, + { url = "https://files.pythonhosted.org/packages/3d/a4/1b641a8c7899eeaceec45ff105a2e7206ec0eb0fb9d86403963cc8521c5e/yarl-1.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7", size = 484778 }, + { url = "https://files.pythonhosted.org/packages/8a/f5/80c142f34779a5c26002b2bf1f73b9a9229aa9e019ee6f9fd9d3e9704e78/yarl-1.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089", size = 485568 }, + { url = "https://files.pythonhosted.org/packages/f8/f2/6b40ffea2d5d3a11f514ab23c30d14f52600c36a3210786f5974b6701bb8/yarl-1.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5", size = 477801 }, + { url = "https://files.pythonhosted.org/packages/4c/1a/e60c116f3241e4842ed43c104eb2751abe02f6bac0301cdae69e4fda9c3a/yarl-1.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5", size = 455361 }, + { url = "https://files.pythonhosted.org/packages/b9/98/fe0aeee425a4bc5cd3ed86e867661d2bfa782544fa07a8e3dcd97d51ae3d/yarl-1.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786", size = 473893 }, + { url = "https://files.pythonhosted.org/packages/6b/9b/677455d146bd3cecd350673f0e4bb28854af66726493ace3b640e9c5552b/yarl-1.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318", size = 476407 }, + { url = "https://files.pythonhosted.org/packages/33/ca/ce85766247a9a9b56654428fb78a3e14ea6947a580a9c4e891b3aa7da322/yarl-1.11.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82", size = 490848 }, + { url = "https://files.pythonhosted.org/packages/6d/d6/717f0f19bcf2c4705ad95550b4b6319a0d8d1d4f137ea5e223207f00df50/yarl-1.11.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a", size = 501084 }, + { url = "https://files.pythonhosted.org/packages/14/b5/b93c70d9a462b802c8df65c64b85f49d86b4ba70c393fbad95cf7ec053cb/yarl-1.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da", size = 491776 }, + { url = "https://files.pythonhosted.org/packages/03/0f/5a52eaa402a6a93265ba82f42c6f6085ccbe483e1b058ad34207e75812b1/yarl-1.11.1-cp313-cp313-win32.whl", hash = "sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979", size = 485250 }, + { url = "https://files.pythonhosted.org/packages/dd/97/946d26a5d82706a6769399cabd472c59f9a3227ce1432afb4739b9c29572/yarl-1.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367", size = 492590 }, + { url = "https://files.pythonhosted.org/packages/5b/b3/841f7d706137bdc8b741c6826106b6f703155076d58f1830f244da857451/yarl-1.11.1-py3-none-any.whl", hash = "sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38", size = 38648 }, +]