diff --git a/src/ethereum_test_benchmark/benchmark_code_generator.py b/src/ethereum_test_benchmark/benchmark_code_generator.py index 311b4132c3b..7061acdd0f3 100644 --- a/src/ethereum_test_benchmark/benchmark_code_generator.py +++ b/src/ethereum_test_benchmark/benchmark_code_generator.py @@ -3,43 +3,42 @@ optimized bytecode patterns. """ +from dataclasses import dataclass + +from ethereum_test_base_types import Address from ethereum_test_forks import Fork from ethereum_test_specs.benchmark import BenchmarkCodeGenerator -from ethereum_test_types import Alloc, Transaction -from ethereum_test_vm import Bytecode +from ethereum_test_types import Alloc from ethereum_test_vm.opcodes import Opcodes as Op +@dataclass(kw_only=True) class JumpLoopGenerator(BenchmarkCodeGenerator): """Generates bytecode that loops execution using JUMP operations.""" - def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: + def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: """Deploy the looping contract.""" # Benchmark Test Structure: - # setup + JUMPDEST + attack + attack + ... + - # attack + JUMP(setup_length) - code = self.generate_repeated_code(self.attack_block, self.setup, fork) - self._contract_address = pre.deploy_contract(code=code) - - def generate_transaction(self, pre: Alloc, gas_limit: int, fork: Fork) -> Transaction: - """Generate transaction that executes the looping contract.""" - if not hasattr(self, "_contract_address"): - raise ValueError("deploy_contracts must be called before generate_transaction") - - return Transaction( - to=self._contract_address, - gas_limit=gas_limit, - sender=pre.fund_eoa(), + # setup + JUMPDEST + + # attack + attack + ... + attack + + # cleanup + JUMP(setup_length) + code = self.generate_repeated_code( + repeated_code=self.attack_block, setup=self.setup, cleanup=self.cleanup, fork=fork ) + self._contract_address = pre.deploy_contract(code=code) + return self._contract_address +@dataclass(kw_only=True) class ExtCallGenerator(BenchmarkCodeGenerator): """ Generates bytecode that fills the contract to maximum allowed code size. """ - def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: + contract_balance: int = 0 + + def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: """Deploy both target and caller contracts.""" # Benchmark Test Structure: # There are two contracts: @@ -53,7 +52,8 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: # Deploy target contract that contains the actual attack block self._target_contract_address = pre.deploy_contract( - code=self.attack_block * max_iterations + code=self.setup + self.attack_block * max_iterations, + balance=self.contract_balance, ) # Create caller contract that repeatedly calls the target contract @@ -65,16 +65,8 @@ def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: # JUMP(setup_length) code_sequence = Op.POP(Op.STATICCALL(Op.GAS, self._target_contract_address, 0, 0, 0, 0)) - caller_code = self.generate_repeated_code(code_sequence, Bytecode(), fork) - self._contract_address = pre.deploy_contract(code=caller_code) - - def generate_transaction(self, pre: Alloc, gas_limit: int, fork: Fork) -> Transaction: - """Generate transaction that executes the caller contract.""" - if not hasattr(self, "_contract_address"): - raise ValueError("deploy_contracts must be called before generate_transaction") - - return Transaction( - to=self._contract_address, - gas_limit=gas_limit, - sender=pre.fund_eoa(), + caller_code = self.generate_repeated_code( + repeated_code=code_sequence, cleanup=self.cleanup, fork=fork ) + self._contract_address = pre.deploy_contract(code=caller_code) + return self._contract_address diff --git a/src/ethereum_test_specs/benchmark.py b/src/ethereum_test_specs/benchmark.py index c6fdd1b644b..94e13be3494 100644 --- a/src/ethereum_test_specs/benchmark.py +++ b/src/ethereum_test_specs/benchmark.py @@ -3,13 +3,13 @@ import math from abc import ABC, abstractmethod from dataclasses import dataclass, field -from typing import Callable, ClassVar, Dict, Generator, List, Sequence, Type +from typing import Any, Callable, ClassVar, Dict, Generator, List, Sequence, Type import pytest from pydantic import ConfigDict, Field from ethereum_clis import TransitionTool -from ethereum_test_base_types import HexNumber +from ethereum_test_base_types import Address, HexNumber from ethereum_test_exceptions import BlockException, TransactionException from ethereum_test_execution import ( BaseExecute, @@ -40,19 +40,34 @@ class BenchmarkCodeGenerator(ABC): attack_block: Bytecode setup: Bytecode = field(default_factory=Bytecode) + cleanup: Bytecode = field(default_factory=Bytecode) + tx_kwargs: Dict[str, Any] = field(default_factory=dict) + _contract_address: Address | None = None @abstractmethod - def deploy_contracts(self, pre: Alloc, fork: Fork) -> None: + def deploy_contracts(self, *, pre: Alloc, fork: Fork) -> Address: """Deploy any contracts needed for the benchmark.""" ... - @abstractmethod - def generate_transaction(self, pre: Alloc, gas_limit: int, fork: Fork) -> Transaction: - """Generate a transaction with the specified gas limit.""" - ... + def generate_transaction(self, *, pre: Alloc, gas_benchmark_value: int) -> Transaction: + """Generate transaction that executes the looping contract.""" + assert self._contract_address is not None + if "gas_limit" not in self.tx_kwargs: + self.tx_kwargs["gas_limit"] = gas_benchmark_value + + return Transaction( + to=self._contract_address, + sender=pre.fund_eoa(), + **self.tx_kwargs, + ) def generate_repeated_code( - self, repeated_code: Bytecode, setup: Bytecode, fork: Fork + self, + *, + repeated_code: Bytecode, + setup: Bytecode | None = None, + cleanup: Bytecode | None = None, + fork: Fork, ) -> Bytecode: """ Calculate the maximum number of iterations that @@ -60,12 +75,17 @@ def generate_repeated_code( """ assert len(repeated_code) > 0, "repeated_code cannot be empty" max_code_size = fork.max_code_size() - - overhead = len(setup) + len(Op.JUMPDEST) + len(Op.JUMP(len(setup))) + if setup is None: + setup = Bytecode() + if cleanup is None: + cleanup = Bytecode() + overhead = len(setup) + len(Op.JUMPDEST) + len(cleanup) + len(Op.JUMP(len(setup))) available_space = max_code_size - overhead max_iterations = available_space // len(repeated_code) - code = setup + Op.JUMPDEST + repeated_code * max_iterations + Op.JUMP(len(setup)) + # TODO: Unify the PUSH0 and PUSH1 usage. + code = setup + Op.JUMPDEST + repeated_code * max_iterations + cleanup + code += Op.JUMP(len(setup)) if len(setup) > 0 else Op.PUSH0 + Op.JUMP self._validate_code_size(code, fork) return code @@ -84,7 +104,7 @@ class BenchmarkTest(BaseTest): model_config = ConfigDict(extra="forbid") - pre: Alloc + pre: Alloc = Field(default_factory=Alloc) post: Alloc = Field(default_factory=Alloc) tx: Transaction | None = None blocks: List[Block] | None = None @@ -115,6 +135,14 @@ class BenchmarkTest(BaseTest): "blockchain_test_only": "Only generate a blockchain test fixture", } + def model_post_init(self, __context: Any, /) -> None: + """ + Model post-init to assert that the custom pre-allocation was + provided and the default was not used. + """ + super().model_post_init(__context) + assert "pre" in self.model_fields_set, "pre allocation was not provided" + @classmethod def pytest_parameter_name(cls) -> str: """ @@ -175,9 +203,11 @@ def generate_blocks_from_code_generator(self, fork: Fork) -> List[Block]: if self.code_generator is None: raise Exception("Code generator is not set") - self.code_generator.deploy_contracts(self.pre, fork) + self.code_generator.deploy_contracts(pre=self.pre, fork=fork) gas_limit = fork.transaction_gas_limit_cap() or self.gas_benchmark_value - benchmark_tx = self.code_generator.generate_transaction(self.pre, gas_limit, fork) + benchmark_tx = self.code_generator.generate_transaction( + pre=self.pre, gas_benchmark_value=gas_limit + ) execution_txs = self.split_transaction(benchmark_tx, gas_limit) execution_block = Block(txs=execution_txs) diff --git a/tests/benchmark/test_worst_blocks.py b/tests/benchmark/test_worst_blocks.py index 35b5150510d..9e59c8b28f1 100755 --- a/tests/benchmark/test_worst_blocks.py +++ b/tests/benchmark/test_worst_blocks.py @@ -2,6 +2,7 @@ Tests that benchmark EVMs in worst-case block scenarios. """ +import math import random from typing import Generator, Tuple @@ -14,11 +15,10 @@ Address, Alloc, AuthorizationTuple, + BenchmarkTestFiller, Block, BlockchainTestFiller, - Environment, Hash, - StateTestFiller, Transaction, ) from ethereum_test_vm import Opcodes as Op @@ -114,15 +114,13 @@ def ether_transfer_case( ["a_to_a", "a_to_b", "diff_acc_to_b", "a_to_diff_acc", "diff_acc_to_diff_acc"], ) def test_block_full_of_ether_transfers( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - env: Environment, case_id: str, ether_transfer_case: Tuple[Generator[Address, None, None], Generator[Address, None, None]], iteration_count: int, transfer_amount: int, intrinsic_cost: int, - gas_benchmark_value: int, ) -> None: """ Single test for ether transfer scenarios. @@ -158,8 +156,7 @@ def test_block_full_of_ether_transfers( else {receiver: Account(balance=balance) for receiver, balance in balances.items()} ) - blockchain_test( - genesis_environment=env, + benchmark_test( pre=pre, post=post_state, blocks=[Block(txs=txs)], @@ -179,18 +176,13 @@ def total_cost_standard_per_token() -> int: return 4 -@pytest.mark.parametrize("zero_byte", [True, False]) -def test_block_full_data( - state_test: StateTestFiller, - pre: Alloc, - zero_byte: bool, - intrinsic_cost: int, +def calldata_generator( + gas_amount: int, + zero_byte: int, total_cost_floor_per_token: int, - gas_benchmark_value: int, -) -> None: - """Test a block with empty payload.""" - # Gas cost calculation based on EIP-7683: - # (https://eips.ethereum.org/EIPS/eip-7683) +) -> bytes: + """Calculate the calldata based on the gas amount and zero byte.""" + # Gas cost calculation based on EIP-7683: (https://eips.ethereum.org/EIPS/eip-7683) # # tx.gasUsed = 21000 + max( # STANDARD_TOKEN_COST * tokens_in_calldata @@ -215,123 +207,160 @@ def test_block_full_data( # # So we calculate how many bytes we can fit into calldata based on # available gas. - - gas_available = gas_benchmark_value - intrinsic_cost - - # Calculate the token_in_calldata - max_tokens_in_calldata = gas_available // total_cost_floor_per_token - # Calculate the number of bytes that can be stored in the calldata + max_tokens_in_calldata = gas_amount // total_cost_floor_per_token num_of_bytes = max_tokens_in_calldata if zero_byte else max_tokens_in_calldata // 4 byte_data = b"\x00" if zero_byte else b"\xff" + return byte_data * num_of_bytes - tx = Transaction( - to=pre.fund_eoa(), - data=byte_data * num_of_bytes, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - state_test( - pre=pre, - post={}, - tx=tx, +@pytest.mark.parametrize("zero_byte", [True, False]) +def test_block_full_data( + benchmark_test: BenchmarkTestFiller, + pre: Alloc, + zero_byte: bool, + intrinsic_cost: int, + total_cost_floor_per_token: int, + gas_benchmark_value: int, + tx_gas_limit_cap: int, + total_cost_standard_per_token: int, + fork: Fork, +) -> None: + """Test a block with empty payload.""" + iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) + + gas_remaining = gas_benchmark_value + total_gas_used = 0 + txs = [] + for _ in range(iteration_count): + gas_available = min(tx_gas_limit_cap, gas_remaining) - intrinsic_cost + data = calldata_generator( + gas_available, + zero_byte, + total_cost_floor_per_token, + ) + + total_gas_used += fork.transaction_intrinsic_cost_calculator()(calldata=data) + gas_remaining -= gas_available + intrinsic_cost + + txs.append( + Transaction( + to=pre.fund_eoa(), + data=data, + gas_limit=gas_available + intrinsic_cost, + sender=pre.fund_eoa(), + ) + ) + + benchmark_test( + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=total_gas_used, ) def test_block_full_access_list_and_data( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, intrinsic_cost: int, total_cost_standard_per_token: int, fork: Fork, gas_benchmark_value: int, + tx_gas_limit_cap: int, ) -> None: """ Test a block with access lists (60% gas) and calldata (40% gas) using random mixed bytes. """ - attack_gas_limit = gas_benchmark_value - gas_available = attack_gas_limit - intrinsic_cost + iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) - # Split available gas: 60% for access lists, 40% for calldata - gas_for_access_list = int(gas_available * 0.6) - gas_for_calldata = int(gas_available * 0.4) + gas_remaining = gas_benchmark_value + total_gas_used = 0 - # Access list gas costs from fork's gas_costs - gas_costs = fork.gas_costs() - gas_per_address = gas_costs.G_ACCESS_LIST_ADDRESS - gas_per_storage_key = gas_costs.G_ACCESS_LIST_STORAGE - - # Calculate number of storage keys we can fit - gas_after_address = gas_for_access_list - gas_per_address - num_storage_keys = gas_after_address // gas_per_storage_key - - # Create access list with 1 address and many storage keys - access_address = Address("0x1234567890123456789012345678901234567890") - storage_keys = [] - for i in range(num_storage_keys): - # Generate random-looking storage keys - storage_keys.append(Hash(i)) - - access_list = [ - AccessList( - address=access_address, - storage_keys=storage_keys, - ) - ] + txs = [] + for _ in range(iteration_count): + gas_available = min(tx_gas_limit_cap, gas_remaining) - intrinsic_cost + + # Split available gas: 60% for access lists, 40% for calldata + gas_for_access_list = int(gas_available * 0.6) + gas_for_calldata = int(gas_available * 0.4) + + # Access list gas costs from fork's gas_costs + gas_costs = fork.gas_costs() + gas_per_address = gas_costs.G_ACCESS_LIST_ADDRESS + gas_per_storage_key = gas_costs.G_ACCESS_LIST_STORAGE + + # Calculate number of storage keys we can fit + gas_after_address = gas_for_access_list - gas_per_address + num_storage_keys = gas_after_address // gas_per_storage_key + + # Create access list with 1 address and many storage keys + access_address = Address("0x1234567890123456789012345678901234567890") + storage_keys = [] + for i in range(num_storage_keys): + # Generate random-looking storage keys + storage_keys.append(Hash(i)) + + access_list = [ + AccessList( + address=access_address, + storage_keys=storage_keys, + ) + ] - # Calculate calldata with 29% of gas for zero bytes and 71% for non-zero - # bytes - # Token accounting: tokens_in_calldata = zero_bytes + 4 * non_zero_bytes - # We want to split the gas budget: - # - 29% of gas_for_calldata for zero bytes - # - 71% of gas_for_calldata for non-zero bytes + # Calculate calldata with 29% of gas for zero bytes and 71% for + # non-zero bytes + # Token accounting: tokens_in_calldata = zero_bytes + 4 * + # non_zero_bytes + # We want to split the gas budget: + # - 29% of gas_for_calldata for zero bytes + # - 71% of gas_for_calldata for non-zero bytes - max_tokens_in_calldata = gas_for_calldata // total_cost_standard_per_token + max_tokens_in_calldata = gas_for_calldata // total_cost_standard_per_token - # Calculate how many tokens to allocate to each type - tokens_for_zero_bytes = int(max_tokens_in_calldata * 0.29) - tokens_for_non_zero_bytes = max_tokens_in_calldata - tokens_for_zero_bytes + # Calculate how many tokens to allocate to each type + tokens_for_zero_bytes = int(max_tokens_in_calldata * 0.29) + tokens_for_non_zero_bytes = max_tokens_in_calldata - tokens_for_zero_bytes - # Convert tokens to actual byte counts - # Zero bytes: 1 token per byte - # Non-zero bytes: 4 tokens per byte - num_zero_bytes = tokens_for_zero_bytes # 1 token = 1 zero byte - # 4 tokens = 1 non-zero byte - num_non_zero_bytes = tokens_for_non_zero_bytes // 4 + # Convert tokens to actual byte counts + # Zero bytes: 1 token per byte + # Non-zero bytes: 4 tokens per byte + num_zero_bytes = tokens_for_zero_bytes # 1 token = 1 zero byte + num_non_zero_bytes = tokens_for_non_zero_bytes // 4 # 4 tokens = 1 non-zero byte - # Create calldata with mixed bytes - calldata = bytearray() + # Create calldata with mixed bytes + calldata = bytearray() - # Add zero bytes - calldata.extend(b"\x00" * num_zero_bytes) + # Add zero bytes + calldata.extend(b"\x00" * num_zero_bytes) - # Add non-zero bytes (random values from 0x01 to 0xff) - rng = random.Random(42) # For reproducibility - for _ in range(num_non_zero_bytes): - calldata.append(rng.randint(1, 255)) + # Add non-zero bytes (random values from 0x01 to 0xff) + rng = random.Random(42) # For reproducibility + for _ in range(num_non_zero_bytes): + calldata.append(rng.randint(1, 255)) - # Shuffle the bytes to mix zero and non-zero bytes - calldata_list = list(calldata) - rng.shuffle(calldata_list) - shuffled_calldata = bytes(calldata_list) + # Shuffle the bytes to mix zero and non-zero bytes + calldata_list = list(calldata) + rng.shuffle(calldata_list) + shuffled_calldata = bytes(calldata_list) - tx = Transaction( - to=pre.fund_eoa(amount=0), - data=shuffled_calldata, - gas_limit=attack_gas_limit, - sender=pre.fund_eoa(), - access_list=access_list, - ) + txs.append( + Transaction( + to=pre.fund_eoa(amount=0), + data=shuffled_calldata, + gas_limit=gas_available + intrinsic_cost, + sender=pre.fund_eoa(), + access_list=access_list, + ) + ) - state_test( - pre=pre, - post={}, - tx=tx, - expected_benchmark_gas_used=fork.transaction_intrinsic_cost_calculator()( + gas_remaining -= gas_for_access_list + intrinsic_cost + total_gas_used += fork.transaction_intrinsic_cost_calculator()( calldata=shuffled_calldata, access_list=access_list, - ), + ) + + benchmark_test( + blocks=[Block(txs=txs)], + expected_benchmark_gas_used=total_gas_used, ) diff --git a/tests/benchmark/test_worst_bytecode.py b/tests/benchmark/test_worst_bytecode.py index 6340b2c49e4..612940a4394 100755 --- a/tests/benchmark/test_worst_bytecode.py +++ b/tests/benchmark/test_worst_bytecode.py @@ -6,16 +6,17 @@ import pytest +from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( Account, Alloc, + BenchmarkTestFiller, Block, BlockchainTestFiller, Bytecode, Environment, Hash, - StateTestFiller, Transaction, While, compute_create2_address, @@ -23,8 +24,6 @@ from ethereum_test_types.helpers import compute_create_address from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -245,11 +244,9 @@ def test_worst_bytecode_single_opcode( ids=lambda x: x.hex(), ) def test_worst_initcode_jumpdest_analysis( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, fork: Fork, pattern: Bytecode, - gas_benchmark_value: int, ) -> None: """ Test the jumpdest analysis performance of the initcode. @@ -261,7 +258,6 @@ def test_worst_initcode_jumpdest_analysis( is modified by mixing-in the returned create address between CREATE invocations to prevent caching. """ - max_code_size = fork.max_code_size() initcode_size = fork.max_initcode_size() # Expand the initcode pattern to the transaction data so it can be used in @@ -291,35 +287,20 @@ def test_worst_initcode_jumpdest_analysis( # Make sure the last opcode in the initcode is JUMPDEST. code_prepare_initcode += Op.MSTORE(initcode_size - 32, Op.PUSH32[bytes(Op.JUMPDEST) * 32]) - code_invoke_create = ( + attack_block = ( Op.PUSH1[len(initcode_prefix)] + Op.MSTORE + Op.CREATE(value=Op.PUSH0, offset=Op.PUSH0, size=Op.MSIZE) ) - initial_random = Op.PUSH0 - code_prefix = code_prepare_initcode + initial_random - code_loop_header = Op.JUMPDEST - code_loop_footer = Op.JUMP(len(code_prefix)) - code_loop_body_len = ( - max_code_size - len(code_prefix) - len(code_loop_header) - len(code_loop_footer) - ) - - code_loop_body = (code_loop_body_len // len(code_invoke_create)) * bytes(code_invoke_create) - code = code_prefix + code_loop_header + code_loop_body + code_loop_footer - assert (max_code_size - len(code_invoke_create)) < len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=code), - data=tx_data, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + setup = code_prepare_initcode + Op.PUSH0 - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + tx_kwargs={"data": tx_data}, + ), ) @@ -349,14 +330,13 @@ def test_worst_initcode_jumpdest_analysis( ], ) def test_worst_create( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, max_code_size_ratio: float, non_zero_data: bool, value: int, - gas_benchmark_value: int, ) -> None: """ Test the CREATE and CREATE2 performance with different configurations. @@ -394,7 +374,7 @@ def test_worst_create( # ... # JUMP(#) # ``` - code_prefix = ( + setup = ( Op.PUSH3(code_size) + Op.PUSH1(value) + Op.EXTCODECOPY( @@ -405,7 +385,7 @@ def test_worst_create( if opcode == Op.CREATE2: # For CREATE2, we provide an initial salt. - code_prefix = code_prefix + Op.PUSH1(42) + setup += Op.PUSH1(42) attack_block = ( # For CREATE: @@ -420,20 +400,18 @@ def test_worst_create( # - DUP3 is targeting the EXTCODESIZE value pushed in code_prefix. else Op.DUP3 + Op.PUSH0 + Op.DUP4 + Op.CREATE2 ) - code = code_loop_precompile_call(code_prefix, attack_block, fork) + + code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( + repeated_code=attack_block, setup=setup, fork=fork + ) tx = Transaction( # Set enough balance in the pre-alloc for `value > 0` configurations. to=pre.deploy_contract(code=code, balance=1_000_000_000 if value > 0 else 0), - gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -444,7 +422,7 @@ def test_worst_create( ], ) def test_worst_creates_collisions( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, @@ -475,14 +453,12 @@ def test_worst_creates_collisions( # The CALL to the proxy contract needs at a minimum gas corresponding to # the CREATE(2) plus extra required PUSH0s for arguments. min_gas_required = gas_costs.G_CREATE + gas_costs.G_BASE * (3 if opcode == Op.CREATE else 4) - code_prefix = Op.PUSH20(proxy_contract) + Op.PUSH3(min_gas_required) + setup = Op.PUSH20(proxy_contract) + Op.PUSH3(min_gas_required) attack_block = Op.POP( # DUP7 refers to the PUSH3 above. # DUP7 refers to the proxy contract address. Op.CALL(gas=Op.DUP7, address=Op.DUP7) ) - code = code_loop_precompile_call(code_prefix, attack_block, fork) - tx_target = pre.deploy_contract(code=code) # (**) We deploy the contract that CREATE(2) will attempt to create so any # attempt will fail. @@ -496,14 +472,6 @@ def test_worst_creates_collisions( addr = compute_create_address(address=proxy_contract, nonce=nonce) pre.deploy_contract(address=addr, code=Op.INVALID) - tx = Transaction( - to=tx_target, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) diff --git a/tests/benchmark/test_worst_compute.py b/tests/benchmark/test_worst_compute.py index 7f4d132892c..c1610c027fd 100755 --- a/tests/benchmark/test_worst_compute.py +++ b/tests/benchmark/test_worst_compute.py @@ -6,23 +6,21 @@ import operator import random from enum import Enum, auto -from typing import Any, cast +from typing import Any, Dict, cast import pytest +from _pytest.mark import ParameterSet from py_ecc.bn128 import G1, G2, multiply from ethereum_test_base_types.base_types import Bytes -from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator +from ethereum_test_benchmark import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( Address, Alloc, BenchmarkTestFiller, Block, - BlockchainTestFiller, Bytecode, - Environment, - StateTestFiller, Transaction, add_kzg_version, ) @@ -38,7 +36,6 @@ from ..osaka.eip7951_p256verify_precompiles.spec import FieldElement from ..prague.eip2537_bls_12_381_precompiles import spec as bls12381_spec from ..prague.eip2537_bls_12_381_precompiles.spec import BytesConcatenation -from .helpers import code_loop_precompile_call REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -82,75 +79,40 @@ def make_dup(index: int) -> Opcode: ], ) def test_worst_zero_param( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, opcode: Op, - fork: Fork, - gas_benchmark_value: int, ) -> None: """Test running a block with as many zero-parameter opcodes as possible.""" - opcode_sequence = opcode * fork.max_stack_height() - target_contract_address = pre.deploy_contract(code=opcode_sequence) - - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( + benchmark_test( pre=pre, post={}, - tx=tx, + code_generator=ExtCallGenerator(attack_block=opcode), ) @pytest.mark.parametrize("calldata_length", [0, 1_000, 10_000]) def test_worst_calldatasize( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, calldata_length: int, - gas_benchmark_value: int, ) -> None: """Test running a block with as many CALLDATASIZE as possible.""" - max_code_size = fork.max_code_size() - - code_prefix = Op.JUMPDEST - iter_loop = Op.POP(Op.CALLDATASIZE) - code_suffix = Op.PUSH0 + Op.JUMP - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=bytes(code)), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - data=b"\x00" * calldata_length, - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + attack_block=Op.POP(Op.CALLDATASIZE), + tx_kwargs={"data": b"\x00" * calldata_length}, + ), ) @pytest.mark.parametrize("non_zero_value", [True, False]) @pytest.mark.parametrize("from_origin", [True, False]) def test_worst_callvalue( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, non_zero_value: bool, from_origin: bool, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many CALLVALUE opcodes as possible. @@ -159,15 +121,9 @@ def test_worst_callvalue( value. The `from_origin` parameter controls whether the call frame is the immediate from the transaction or a previous CALL. """ - max_code_size = fork.max_code_size() - - code_prefix = Op.JUMPDEST - iter_loop = Op.POP(Op.CALLVALUE) - code_suffix = Op.PUSH0 + Op.JUMP - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - code_address = pre.deploy_contract(code=bytes(code)) + code_address = JumpLoopGenerator(attack_block=Op.POP(Op.CALLVALUE)).deploy_contracts( + pre=pre, fork=fork + ) if from_origin: tx_to = code_address @@ -181,16 +137,11 @@ def test_worst_callvalue( tx = Transaction( to=tx_to, - gas_limit=gas_benchmark_value, value=1 if non_zero_value and from_origin else 0, sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) class ReturnDataStyle(Enum): @@ -211,12 +162,10 @@ class ReturnDataStyle(Enum): ) @pytest.mark.parametrize("returned_size", [1, 0]) def test_worst_returndatasize_nonzero( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, returned_size: int, return_data_style: ReturnDataStyle, - gas_benchmark_value: int, ) -> None: """ Test running a block which execute as many RETURNDATASIZE opcodes which @@ -226,11 +175,9 @@ def test_worst_returndatasize_nonzero( buffer. The `return_data_style` indicates how returned data is produced for the opcode caller. """ - max_code_size = fork.max_code_size() - - dummy_contract_call = Bytecode() + setup = Bytecode() if return_data_style != ReturnDataStyle.IDENTITY: - dummy_contract_call = Op.STATICCALL( + setup += Op.STATICCALL( address=pre.deploy_contract( code=Op.REVERT(0, returned_size) if return_data_style == ReturnDataStyle.REVERT @@ -238,107 +185,47 @@ def test_worst_returndatasize_nonzero( ) ) else: - dummy_contract_call = Op.MSTORE8(0, 1) + Op.STATICCALL( + setup += Op.MSTORE8(0, 1) + Op.STATICCALL( address=0x04, # Identity precompile args_size=returned_size, ) - code_prefix = dummy_contract_call + Op.JUMPDEST - iter_loop = Op.POP(Op.RETURNDATASIZE) - code_suffix = Op.JUMP(len(code_prefix) - 1) - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=bytes(code)), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=setup, attack_block=Op.POP(Op.RETURNDATASIZE)), ) -def test_worst_returndatasize_zero( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, - gas_benchmark_value: int, -) -> None: +def test_worst_returndatasize_zero(benchmark_test: BenchmarkTestFiller) -> None: """ - Test running a block with as many RETURNDATASIZE opcodes as possible with a - zero buffer. + Test running a block with as many RETURNDATASIZE opcodes as possible with + a zero buffer. """ - max_code_size = fork.max_code_size() - - dummy_contract_call = Bytecode() - - code_prefix = dummy_contract_call + Op.JUMPDEST - iter_loop = Op.POP(Op.RETURNDATASIZE) - code_suffix = Op.JUMP(len(code_prefix) - 1) - code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop) - code = code_prefix + iter_loop * code_iter_len + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=bytes(code)), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=ExtCallGenerator(attack_block=Op.RETURNDATASIZE), ) @pytest.mark.parametrize("mem_size", [0, 1, 1_000, 100_000, 1_000_000]) def test_worst_msize( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, mem_size: int, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many MSIZE opcodes as possible. The `mem_size` parameter indicates by how much the memory is expanded. """ - max_stack_height = fork.max_stack_height() - - code_sequence = Op.MLOAD(Op.CALLVALUE) + Op.POP + Op.MSIZE * max_stack_height - target_address = pre.deploy_contract(code=code_sequence) - - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= fork.max_code_size() - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - value=mem_size, - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=ExtCallGenerator( + setup=Op.MLOAD(Op.CALLVALUE) + Op.POP, + attack_block=Op.MSIZE, + tx_kwargs={"value": mem_size}, + ), ) def test_worst_keccak( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, fork: Fork, gas_benchmark_value: int, ) -> None: @@ -350,11 +237,10 @@ def test_worst_keccak( gsc = fork.gas_costs() mem_exp_gas_calculator = fork.memory_expansion_gas_calculator() - max_code_size = fork.max_code_size() - - # Discover the optimal input size to maximize keccak-permutations, not - # keccak calls. The complication of the discovery arises from the non- - # linear gas cost of memory expansion. + # Discover the optimal input size to maximize keccak-permutations, + # not to maximize keccak calls. + # The complication of the discovery arises from + # the non-linear gas cost of memory expansion. max_keccak_perm_per_block = 0 optimal_input_length = 0 for i in range(1, 1_000_000, 32): @@ -385,32 +271,17 @@ def test_worst_keccak( # The loop structure is: JUMPDEST + [attack iteration] + PUSH0 + JUMP # # Now calculate available gas for [attack iteration]: - # Numerator = max_code_size-3. The -3 is for the JUMPDEST, PUSH0 and JUMP - # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + PUSHN_DATA - # + # Numerator = max_code_size-3. (JUMPDEST, PUSH0 and JUMP) + # Denominator = (PUSHN + PUSH1 + KECCAK256 + POP) + PUSH1_DATA + + # PUSHN_DATA # TODO: the testing framework uses PUSH1(0) instead of PUSH0 which is - # suboptimal for the attack, whenever this is fixed adjust accordingly. - start_code = Op.JUMPDEST + Op.PUSH20[optimal_input_length] - loop_code = Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)) - end_code = Op.POP + Op.JUMP(Op.PUSH0) - max_iters_loop = (max_code_size - (len(start_code) + len(end_code))) // len(loop_code) - code = start_code + (loop_code * max_iters_loop) + end_code - if len(code) > max_code_size: - # Must never happen, but keep it as a sanity check. - raise ValueError(f"Code size {len(code)} exceeds maximum code size {max_code_size}") - - code_address = pre.deploy_contract(code=bytes(code)) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + # suboptimal for the + # attack, whenever this is fixed adjust accordingly. + benchmark_test( + code_generator=JumpLoopGenerator( + setup=Op.PUSH20[optimal_input_length], + attack_block=Op.POP(Op.SHA3(Op.PUSH0, Op.DUP1)), + ), ) @@ -423,8 +294,7 @@ def test_worst_keccak( ], ) def test_worst_precompile_only_data_input( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, fork: Fork, address: Address, static_cost: int, @@ -478,886 +348,375 @@ def test_worst_precompile_only_data_input( max_work = total_work optimal_input_length = input_length - calldata = Op.CODECOPY(0, 0, optimal_input_length) attack_block = Op.POP(Op.STATICCALL(Op.GAS, address, 0, optimal_input_length, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - - code_address = pre.deploy_contract(code=code) - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, - ) - - -@pytest.mark.parametrize( - ["mod_exp_input"], - [ - pytest.param( - ModExpInput( - base=8 * "ff", - exponent=112 * "ff", - modulus=7 * "ff" + "00", - ), - id="mod_even_8b_exp_896", - ), - pytest.param( - ModExpInput( - base=16 * "ff", - exponent=40 * "ff", - modulus=15 * "ff" + "00", - ), - id="mod_even_16b_exp_320", - ), - pytest.param( - ModExpInput( - base=24 * "ff", - exponent=21 * "ff", - modulus=23 * "ff" + "00", - ), - id="mod_even_24b_exp_168", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=5 * "ff", - modulus=31 * "ff" + "00", - ), - id="mod_even_32b_exp_40", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=12 * "ff", - modulus=31 * "ff" + "00", - ), - id="mod_even_32b_exp_96", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=32 * "ff", - modulus=31 * "ff" + "00", - ), - id="mod_even_32b_exp_256", - ), - pytest.param( - ModExpInput( - base=64 * "ff", - exponent=64 * "ff", - modulus=63 * "ff" + "00", - ), - id="mod_even_64b_exp_512", - ), - pytest.param( - ModExpInput( - base=128 * "ff", - exponent=128 * "ff", - modulus=127 * "ff" + "00", - ), - id="mod_even_128b_exp_1024", - ), - pytest.param( - ModExpInput( - base=256 * "ff", - exponent=128 * "ff", - modulus=255 * "ff" + "00", - ), - id="mod_even_256b_exp_1024", - ), - pytest.param( - ModExpInput( - base=512 * "ff", - exponent=128 * "ff", - modulus=511 * "ff" + "00", - ), - id="mod_even_512b_exp_1024", - ), - pytest.param( - ModExpInput( - base=1024 * "ff", - exponent=128 * "ff", - modulus=1023 * "ff" + "00", - ), - id="mod_even_1024b_exp_1024", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=12 * "ff", - modulus=31 * "ff" + "01", - ), - id="mod_odd_32b_exp_96", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=32 * "ff", - modulus=31 * "ff" + "01", - ), - id="mod_odd_32b_exp_256", - ), - pytest.param( - ModExpInput( - base=64 * "ff", - exponent=64 * "ff", - modulus=63 * "ff" + "01", - ), - id="mod_odd_64b_exp_512", - ), - pytest.param( - ModExpInput( - base=128 * "ff", - exponent=128 * "ff", - modulus=127 * "ff" + "01", - ), - id="mod_odd_128b_exp_1024", - ), - pytest.param( - ModExpInput( - base=256 * "ff", - exponent=128 * "ff", - modulus=255 * "ff" + "01", - ), - id="mod_odd_256b_exp_1024", - ), - pytest.param( - ModExpInput( - base=512 * "ff", - exponent=128 * "ff", - modulus=511 * "ff" + "01", - ), - id="mod_odd_512b_exp_1024", - ), - pytest.param( - ModExpInput( - base=1024 * "ff", - exponent=128 * "ff", - modulus=1023 * "ff" + "01", - ), - id="mod_odd_1024b_exp_1024", - ), - pytest.param( - ModExpInput( - base=32 * "ff", - exponent=8 * "12345670", - modulus=31 * "ff" + "01", - ), - id="mod_odd_32b_exp_cover_windows", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L38 - pytest.param( - ModExpInput( - base=192 * "FF", - exponent="03", - modulus=6 * ("00" + 31 * "FF"), - ), - id="mod_min_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L40 - pytest.param( - ModExpInput( - base=8 * "FF", - exponent="07" + 75 * "FF", - modulus=7 * "FF", - ), - id="mod_min_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L42 - pytest.param( - ModExpInput( - base=40 * "FF", - exponent="01" + 3 * "FF", - modulus="00" + 38 * "FF", - ), - id="mod_min_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L44 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=5 * "FF", - modulus=("00" + 31 * "FF"), - ), - id="mod_exp_208_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L46 - pytest.param( - ModExpInput( - base=8 * "FF", - exponent=81 * "FF", - modulus=7 * "FF", - ), - id="mod_exp_215_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L48 - pytest.param( - ModExpInput( - base=8 * "FF", - exponent=112 * "FF", - modulus=7 * "FF", - ), - id="mod_exp_298_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L50 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent=40 * "FF", - modulus=15 * "FF", - ), - id="mod_pawel_2", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L52 - pytest.param( - ModExpInput( - base=24 * "FF", - exponent=21 * "FF", - modulus=23 * "FF", - ), - id="mod_pawel_3", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L54 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=12 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_pawel_4", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L56 - pytest.param( - ModExpInput( - base=280 * "FF", - exponent="03", - modulus=8 * ("00" + 31 * "FF") + 23 * "FF", - ), - id="mod_408_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L58 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent="15" + 37 * "FF", - modulus=15 * "FF", - ), - id="mod_400_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L60 - pytest.param( - ModExpInput( - base=48 * "FF", - exponent="07" + 4 * "FF", - modulus="00" + 46 * "FF", - ), - id="mod_408_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L62 - pytest.param( - ModExpInput( - base=344 * "FF", - exponent="03", - modulus=10 * ("00" + 31 * "FF") + 23 * "FF", - ), - id="mod_616_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L64 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent="07" + 56 * "FF", - modulus=15 * "FF", - ), - id="mod_600_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L66 - pytest.param( - ModExpInput( - base=48 * "FF", - exponent="07" + 6 * "FF", - modulus="00" + 46 * "FF", - ), - id="mod_600_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L68 - pytest.param( - ModExpInput( - base=392 * "FF", - exponent="03", - modulus=12 * ("00" + 31 * "FF") + 7 * "FF", - ), - id="mod_800_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L70 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent="01" + 75 * "FF", - modulus=15 * "FF", - ), - id="mod_800_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L72 - pytest.param( - ModExpInput( - base=56 * "FF", - exponent=6 * "FF", - modulus="00" + 54 * "FF", - ), - id="mod_767_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L74 - pytest.param( - ModExpInput( - base=16 * "FF", - exponent=80 * "FF", - modulus=15 * "FF", - ), - id="mod_852_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L76 - pytest.param( - ModExpInput( - base=408 * "FF", - exponent="03", - modulus=12 * ("00" + 31 * "FF") + 23 * "FF", - ), - id="mod_867_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L78 - pytest.param( - ModExpInput( - base=56 * "FF", - exponent="2b" + 7 * "FF", - modulus="00" + 54 * "FF", - ), - id="mod_996_gas_balanced", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L80 - pytest.param( - ModExpInput( - base=448 * "FF", - exponent="03", - modulus=14 * ("00" + 31 * "FF"), - ), - id="mod_1045_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L82 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=16 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_677_gas_base_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L84 - pytest.param( - ModExpInput( - base=24 * "FF", - exponent=32 * "FF", - modulus=23 * "FF", - ), - id="mod_765_gas_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L86 - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=32 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_1360_gas_balanced", - ), - pytest.param( - ModExpInput( - base=8 * "FF", - exponent=81 * "FF", - modulus=7 * "FF", - ), - id="mod_8_exp_648", - ), - pytest.param( - ModExpInput( - base=8 * "FF", - exponent="FF" + 111 * "FF", - modulus=7 * "FF", - ), - id="mod_8_exp_896", - ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=4 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_32", - ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent="0D" + 4 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_36", + benchmark_test( + code_generator=JumpLoopGenerator( + setup=Op.CODECOPY(0, 0, optimal_input_length), attack_block=attack_block + ), + ) + + +def create_modexp_test_cases() -> list[ParameterSet]: + """Create test cases for the MODEXP precompile.""" + test_cases = [ + # (base, exponent, modulus, test_id) + (8 * "ff", 112 * "ff", 7 * "ff" + "00", "mod_even_8b_exp_896"), + (16 * "ff", 40 * "ff", 15 * "ff" + "00", "mod_even_16b_exp_320"), + (24 * "ff", 21 * "ff", 23 * "ff" + "00", "mod_even_24b_exp_168"), + (32 * "ff", 5 * "ff", 31 * "ff" + "00", "mod_even_32b_exp_40"), + (32 * "ff", 12 * "ff", 31 * "ff" + "00", "mod_even_32b_exp_96"), + (32 * "ff", 32 * "ff", 31 * "ff" + "00", "mod_even_32b_exp_256"), + (64 * "ff", 64 * "ff", 63 * "ff" + "00", "mod_even_64b_exp_512"), + (128 * "ff", 128 * "ff", 127 * "ff" + "00", "mod_even_128b_exp_1024"), + (256 * "ff", 128 * "ff", 255 * "ff" + "00", "mod_even_256b_exp_1024"), + (512 * "ff", 128 * "ff", 511 * "ff" + "00", "mod_even_512b_exp_1024"), + (1024 * "ff", 128 * "ff", 1023 * "ff" + "00", "mod_even_1024b_exp_1024"), + (32 * "ff", 12 * "ff", 31 * "ff" + "01", "mod_odd_32b_exp_96"), + (32 * "ff", 32 * "ff", 31 * "ff" + "01", "mod_odd_32b_exp_256"), + (64 * "ff", 64 * "ff", 63 * "ff" + "01", "mod_odd_64b_exp_512"), + (128 * "ff", 128 * "ff", 127 * "ff" + "01", "mod_odd_128b_exp_1024"), + (256 * "ff", 128 * "ff", 255 * "ff" + "01", "mod_odd_256b_exp_1024"), + (512 * "ff", 128 * "ff", 511 * "ff" + "01", "mod_odd_512b_exp_1024"), + (1024 * "ff", 128 * "ff", 1023 * "ff" + "01", "mod_odd_1024b_exp_1024"), + (32 * "ff", 8 * "12345670", 31 * "ff" + "01", "mod_odd_32b_exp_cover_windows"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L38 + (192 * "FF", "03", 6 * ("00" + 31 * "FF"), "mod_min_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L40 + (8 * "FF", "07" + 75 * "FF", 7 * "FF", "mod_min_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L42 + (40 * "FF", "01" + 3 * "FF", "00" + 38 * "FF", "mod_min_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L44 + (32 * "FF", 5 * "FF", ("00" + 31 * "FF"), "mod_exp_208_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L46 + (8 * "FF", 81 * "FF", 7 * "FF", "mod_exp_215_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L48 + (8 * "FF", 112 * "FF", 7 * "FF", "mod_exp_298_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L50 + (16 * "FF", 40 * "FF", 15 * "FF", "mod_pawel_2"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L52 + (24 * "FF", 21 * "FF", 23 * "FF", "mod_pawel_3"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L54 + (32 * "FF", 12 * "FF", "00" + 31 * "FF", "mod_pawel_4"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L56 + (280 * "FF", "03", 8 * ("00" + 31 * "FF") + 23 * "FF", "mod_408_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L58 + (16 * "FF", "15" + 37 * "FF", 15 * "FF", "mod_400_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L60 + (48 * "FF", "07" + 4 * "FF", "00" + 46 * "FF", "mod_408_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L62 + (344 * "FF", "03", 10 * ("00" + 31 * "FF") + 23 * "FF", "mod_616_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L64 + (16 * "FF", "07" + 56 * "FF", 15 * "FF", "mod_600_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L66 + (48 * "FF", "07" + 6 * "FF", "00" + 46 * "FF", "mod_600_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L68 + (392 * "FF", "03", 12 * ("00" + 31 * "FF") + 7 * "FF", "mod_800_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L70 + (16 * "FF", "01" + 75 * "FF", 15 * "FF", "mod_800_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L72 + (56 * "FF", 6 * "FF", "00" + 54 * "FF", "mod_767_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L74 + (16 * "FF", 80 * "FF", 15 * "FF", "mod_852_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L76 + (408 * "FF", "03", 12 * ("00" + 31 * "FF") + 23 * "FF", "mod_867_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L78 + (56 * "FF", "2b" + 7 * "FF", "00" + 54 * "FF", "mod_996_gas_balanced"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L80 + (448 * "FF", "03", 14 * ("00" + 31 * "FF"), "mod_1045_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L82 + (32 * "FF", 16 * "FF", "00" + 31 * "FF", "mod_677_gas_base_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L84 + (24 * "FF", 32 * "FF", 23 * "FF", "mod_765_gas_exp_heavy"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/Modexp.cs#L86 + (32 * "FF", 32 * "FF", "00" + 31 * "FF", "mod_1360_gas_balanced"), + (8 * "FF", 81 * "FF", 7 * "FF", "mod_8_exp_648"), + (8 * "FF", "FF" + 111 * "FF", 7 * "FF", "mod_8_exp_896"), + (32 * "FF", 4 * "FF", "00" + 31 * "FF", "mod_32_exp_32"), + (32 * "FF", "0D" + 4 * "FF", "00" + 31 * "FF", "mod_32_exp_36"), + (32 * "FF", 5 * "FF", "00" + 31 * "FF", "mod_32_exp_40"), + (32 * "FF", 8 * "FF", "00" + 31 * "FF", "mod_32_exp_64"), + (32 * "FF", "01" + 8 * "FF", "00" + 31 * "FF", "mod_32_exp_65"), + (32 * "FF", 16 * "FF", "00" + 31 * "FF", "mod_32_exp_128"), + (256 * "FF", "03" + 0 * "FF", 8 * ("00" + 31 * "FF"), "mod_256_exp_2"), + (264 * "FF", "03" + 0 * "FF", 8 * ("00" + 31 * "FF") + 7 * "FF", "mod_264_exp_2"), + (1024 * "FF", "03", 32 * ("00" + 31 * "FF"), "mod_1024_exp_2"), + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L122 + ( + "03", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "mod_vul_example_1", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=5 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_40", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L124 + ( + "", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "mod_vul_example_2", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=8 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_64", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L126 + ( + "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", + "02", + "fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "mod_vul_nagydani_1_square", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent="01" + 8 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_65", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L128 + ( + "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", + "03", + "fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "mod_vul_nagydani_1_qube", ), - pytest.param( - ModExpInput( - base=32 * "FF", - exponent=16 * "FF", - modulus="00" + 31 * "FF", - ), - id="mod_32_exp_128", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L130 + ( + "e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", + "010001", + "fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "mod_vul_nagydani_1_pow_0x10001", ), - pytest.param( - ModExpInput( - base=256 * "FF", - exponent="03" + 0 * "FF", - modulus=8 * ("00" + 31 * "FF"), - ), - id="mod_256_exp_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L132 + ( + "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", + "02", + "e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "mod_vul_nagydani_2_square", ), - pytest.param( - ModExpInput( - base=264 * "FF", - exponent="03" + 0 * "FF", - modulus=8 * ("00" + 31 * "FF") + 7 * "FF", - ), - id="mod_264_exp_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L134 + ( + "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", + "03", + "e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "mod_vul_nagydani_2_qube", ), - pytest.param( - ModExpInput( - base=1024 * "FF", - exponent="03", - modulus=32 * ("00" + 31 * "FF"), - ), - id="mod_1024_exp_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L136 + ( + "cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", + "010001", + "e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "mod_vul_nagydani_2_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L122 - pytest.param( - ModExpInput( - base="03", - exponent="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", - modulus="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ), - id="mod_vul_example_1", + ( + "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", + "02", + "d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "mod_vul_nagydani_3_square", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L124 - pytest.param( - ModExpInput( - base="", - exponent="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", - modulus="fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ), - id="mod_vul_example_2", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L140 + ( + "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", + "03", + "d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "mod_vul_nagydani_3_qube", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L126 - pytest.param( - ModExpInput( - base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", - exponent="02", - modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", - ), - id="mod_vul_nagydani_1_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L142 + ( + "c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", + "010001", + "d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "mod_vul_nagydani_3_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L128 - pytest.param( - ModExpInput( - base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", - exponent="03", - modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", - ), - id="mod_vul_nagydani_1_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L144 + ( + "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", + "02", + "df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "mod_vul_nagydani_4_square", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L130 - pytest.param( - ModExpInput( - base="e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5", - exponent="010001", - modulus="fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", - ), - id="mod_vul_nagydani_1_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L146 + ( + "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", + "03", + "df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "mod_vul_nagydani_4_qube", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L132 - pytest.param( - ModExpInput( - base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", - exponent="02", - modulus="e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", - ), - id="mod_vul_nagydani_2_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L148 + ( + "db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", + "010001", + "df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "mod_vul_nagydani_4_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L134 - pytest.param( - ModExpInput( - base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", - exponent="03", - modulus="e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", - ), - id="mod_vul_nagydani_2_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L150 + ( + "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", + "02", + "e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "mod_vul_nagydani_5_square", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L136 - pytest.param( - ModExpInput( - base="cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51", - exponent="010001", - modulus="e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", - ), - id="mod_vul_nagydani_2_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L152 + ( + "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", + "03", + "e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "mod_vul_nagydani_5_qube", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L138 - pytest.param( - ModExpInput( - base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", - exponent="02", - modulus="d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", - ), - id="mod_vul_nagydani_3_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L154 + ( + "c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", + "010001", + "e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "mod_vul_nagydani_5_pow_0x10001", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L140 - pytest.param( - ModExpInput( - base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", - exponent="03", - modulus="d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", - ), - id="mod_vul_nagydani_3_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L156 + ( + "ffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000007d7d7d83828282348286877d7d827d407d797d7d7d7d7d7d7d7d7d7d7d5b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000000000000cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4000007d7d", + "7d83828282348286877d7d82", + "mod_vul_marius_1_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L142 - pytest.param( - ModExpInput( - base="c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb", - exponent="010001", - modulus="d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", - ), - id="mod_vul_nagydani_3_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L158 + ( + "ffffffffffffffff76ffffffffffffff", + "1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7ffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffff", + "ffffff3f000000000000000000000000", + "mod_vul_guido_1_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L144 - pytest.param( - ModExpInput( - base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", - exponent="02", - modulus="df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", - ), - id="mod_vul_nagydani_4_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L160 + ( + "e0060000a921212121212121ff000021", + "2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f00feffff212121212121ffffffff1fe1e0e0e01e1f1f169f1f1f1f490afcefffffffffffffffff82828282828282828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1fffffffffff0afceffffff7ffffffffff7c8282828282a1828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1fd11f1f1f1f1f1f1f1f1f1f1fffffffffffffffff21212121212121fb2121212121ffff1f1f1f1f1f1f1f1fffaf", + "82828282828200ffff28ff2b21828200", + "mod_vul_guido_2_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L146 - pytest.param( - ModExpInput( - base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", - exponent="03", - modulus="df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", - ), - id="mod_vul_nagydani_4_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L162 + ( + "0193585a48e18aad777e9c1b54221a0f58140392e4f091cd5f42b2e8644a9384fbd58ae1edec2477ebf7edbf7c0a3f8bd21d1890ee87646feab3c47be716f842cc3da9b940af312dc54450a960e3fc0b86e56abddd154068e10571a96fff6259431632bc15695c6c8679057e66c2c25c127e97e64ee5de6ea1fc0a4a0e431343fed1daafa072c238a45841da86a9806680bc9f298411173210790359209cd454b5af7b4d5688b4403924e5f863d97e2c5349e1a04b54fcf385b1e9d7714bab8fbf5835f6ff9ed575e77dff7af5cbb641db5d537933bae1fa6555d6c12d6fb31ca27b57771f4aebfbe0bf95e8990c0108ffe7cbdaf370be52cf3ade594543af75ad9329d2d11a402270b5b9a6bf4b83307506e118fca4862749d04e916fc7a039f0d13f2a02e0eedb800199ec95df15b4ccd8669b52586879624d51219e72102fad810b5909b1e372ddf33888fb9beb09b416e4164966edbabd89e4a286be36277fc576ed519a15643dac602e92b63d0b9121f0491da5b16ef793a967f096d80b6c81ecaaffad7e3f06a4a5ac2796f1ed9f68e6a0fd5cf191f0c5c2eec338952ff8d31abc68bf760febeb57e088995ba1d7726a2fdd6d8ca28a181378b8b4ab699bfd4b696739bbf17a9eb2df6251143046137fdbbfacac312ebf67a67da9741b59600000000000", + "04", + "19a2917c61722b0713d3b00a2f0e1dd5aebbbe09615de424700eea3c3020fe6e9ea5de9fa1ace781df28b21f746d2ab61d0da496e08473c90ff7dfe25b43bcde76f4bafb82e0975bea75f5a0591dba80ba2fff80a07d8853bea5be13ab326ba70c57b153acc646151948d1cf061ca31b02d4719fac710e7c723ca44f5b1737824b7ccc74ba5bff980aabdbf267621cafc3d6dcc29d0ca9c16839a92ed34de136da7900aa3ee43d21aa57498981124357cf0ca9b86f9a8d3f9c604ca00c726e48f7a9945021ea6dfff92d6b2d6514693169ca133e993541bfa4c4c191de806aa80c48109bcfc9901eccfdeb2395ab75fe63c67de900829d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "mod_vul_guido_3_even", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L148 - pytest.param( - ModExpInput( - base="db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81", - exponent="010001", - modulus="df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", - ), - id="mod_vul_nagydani_4_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L166 + ( + "ffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffff", + "mod_vul_pawel_1_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L150 - pytest.param( - ModExpInput( - base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", - exponent="02", - modulus="e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", - ), - id="mod_vul_nagydani_5_square", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L168 + ( + "ffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffff", + "mod_vul_pawel_2_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L152 - pytest.param( - ModExpInput( - base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", - exponent="03", - modulus="e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", - ), - id="mod_vul_nagydani_5_qube", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L170 + ( + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "mod_vul_pawel_3_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L154 - pytest.param( - ModExpInput( - base="c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf", - exponent="010001", - modulus="e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", - ), - id="mod_vul_nagydani_5_pow_0x10001", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L172 + ( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "mod_vul_pawel_4_exp_heavy", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L156 - pytest.param( - ModExpInput( - base="ffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000007d7d7d83828282348286877d7d827d407d797d7d7d7d7d7d7d7d7d7d7d5b00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000000000000cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4000007d7d", - modulus="7d83828282348286877d7d82", - ), - id="mod_vul_marius_1_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L174 + ( + "29356abadad68ad986c416de6f620bda0e1818b589e84f853a97391694d35496", + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f", + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + "mod_vul_common_1360n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L158 - pytest.param( - ModExpInput( - base="ffffffffffffffff76ffffffffffffff", - exponent="1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7ffffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffffffffffffc7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c76ec7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7ffff", - modulus="ffffff3f000000000000000000000000", - ), - id="mod_vul_guido_1_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L176 + ( + "d41afaeaea32f7409827761b68c41b6e535da4ede1f0800bfb4a6aed18394f6b", + "ffffffff00000001000000000000000000000000fffffffffffffffffffffffd", + "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "mod_vul_common_1360n2", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L160 - pytest.param( - ModExpInput( - base="e0060000a921212121212121ff000021", - exponent="2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f00feffff212121212121ffffffff1fe1e0e0e01e1f1f169f1f1f1f490afcefffffffffffffffff82828282828282828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1fffffffffff0afceffffff7ffffffffff7c8282828282a1828282828282828282828282828200ffff28ff2b212121ffff1f1f1f1f1f1fd11f1f1f1f1f1f1f1f1f1f1fffffffffffffffff21212121212121fb2121212121ffff1f1f1f1f1f1f1f1fffaf", - modulus="82828282828200ffff28ff2b21828200", - ), - id="mod_vul_guido_2_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L178 + ( + "1a5be8fae3b3fda9ea329494ae8689c04fae4978ecccfa6a6bfb9f04b25846c0", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_1349n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L162 - pytest.param( - ModExpInput( - base="0193585a48e18aad777e9c1b54221a0f58140392e4f091cd5f42b2e8644a9384fbd58ae1edec2477ebf7edbf7c0a3f8bd21d1890ee87646feab3c47be716f842cc3da9b940af312dc54450a960e3fc0b86e56abddd154068e10571a96fff6259431632bc15695c6c8679057e66c2c25c127e97e64ee5de6ea1fc0a4a0e431343fed1daafa072c238a45841da86a9806680bc9f298411173210790359209cd454b5af7b4d5688b4403924e5f863d97e2c5349e1a04b54fcf385b1e9d7714bab8fbf5835f6ff9ed575e77dff7af5cbb641db5d537933bae1fa6555d6c12d6fb31ca27b57771f4aebfbe0bf95e8990c0108ffe7cbdaf370be52cf3ade594543af75ad9329d2d11a402270b5b9a6bf4b83307506e118fca4862749d04e916fc7a039f0d13f2a02e0eedb800199ec95df15b4ccd8669b52586879624d51219e72102fad810b5909b1e372ddf33888fb9beb09b416e4164966edbabd89e4a286be36277fc576ed519a15643dac602e92b63d0b9121f0491da5b16ef793a967f096d80b6c81ecaaffad7e3f06a4a5ac2796f1ed9f68e6a0fd5cf191f0c5c2eec338952ff8d31abc68bf760febeb57e088995ba1d7726a2fdd6d8ca28a181378b8b4ab699bfd4b696739bbf17a9eb2df6251143046137fdbbfacac312ebf67a67da9741b59600000000000", - exponent="04", - modulus="19a2917c61722b0713d3b00a2f0e1dd5aebbbe09615de424700eea3c3020fe6e9ea5de9fa1ace781df28b21f746d2ab61d0da496e08473c90ff7dfe25b43bcde76f4bafb82e0975bea75f5a0591dba80ba2fff80a07d8853bea5be13ab326ba70c57b153acc646151948d1cf061ca31b02d4719fac710e7c723ca44f5b1737824b7ccc74ba5bff980aabdbf267621cafc3d6dcc29d0ca9c16839a92ed34de136da7900aa3ee43d21aa57498981124357cf0ca9b86f9a8d3f9c604ca00c726e48f7a9945021ea6dfff92d6b2d6514693169ca133e993541bfa4c4c191de806aa80c48109bcfc9901eccfdeb2395ab75fe63c67de900829d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - ), - id="mod_vul_guido_3_even", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L182 + ( + "0000000000000000000000000000000000000000000000000000000000000003", + "0000000001000000000000022000000000000000000000000000000000000000", + "0800000000000011000000000000000000000000000000000000000000000001", + "mod_vul_common_1152n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L166 - pytest.param( - ModExpInput( - base="ffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - modulus="ffffffffffffffff", - ), - id="mod_vul_pawel_1_exp_heavy", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L184 + ( + "1fb473dd1171cf88116aa77ab3612c2c7d2cf466cc2386cc456130e2727c70b4", + "0000000000000000000000000000000000000000000000000000000001000000", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_200n1", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L168 - pytest.param( - ModExpInput( - base="ffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - modulus="ffffffffffffffffffffffffffffffff", - ), - id="mod_vul_pawel_2_exp_heavy", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L186 + ( + "1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb", + "0000000000000000000000000000000000000000000000000000000000ffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_200n2", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L170 - pytest.param( - ModExpInput( - base="ffffffffffffffffffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffff", - modulus="ffffffffffffffffffffffffffffffffffffffffffffffff", - ), - id="mod_vul_pawel_3_exp_heavy", + # Ported from https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L188 + ( + "288254ba43e713afbe36c9f03b54c00fae4c0a82df1cf165eb46a21c20a48ca2", + "0000000000000000000000000000000000000000000000000000000000ffffff", + "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + "mod_vul_common_200n3", ), + ( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + "mod_vul_zkevm_worst_case", + ), + ] + + special_cases = [ pytest.param( ModExpInput.from_bytes( "000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000017bffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffe" ), id="mod_vul_pawel_3_exp_8", ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L172 - pytest.param( - ModExpInput( - base="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffff", - modulus="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ), - id="mod_vul_pawel_4_exp_heavy", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L174 - pytest.param( - ModExpInput( - base="29356abadad68ad986c416de6f620bda0e1818b589e84f853a97391694d35496", - exponent="ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f", - modulus="ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - ), - id="mod_vul_common_1360n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L176 - pytest.param( - ModExpInput( - base="d41afaeaea32f7409827761b68c41b6e535da4ede1f0800bfb4a6aed18394f6b", - exponent="ffffffff00000001000000000000000000000000fffffffffffffffffffffffd", - modulus="ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - ), - id="mod_vul_common_1360n2", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L178 - pytest.param( - ModExpInput( - base="1a5be8fae3b3fda9ea329494ae8689c04fae4978ecccfa6a6bfb9f04b25846c0", - exponent="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_1349n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L182 - pytest.param( - ModExpInput( - base="0000000000000000000000000000000000000000000000000000000000000003", - exponent="0000000001000000000000022000000000000000000000000000000000000000", - modulus="0800000000000011000000000000000000000000000000000000000000000001", - ), - id="mod_vul_common_1152n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L184 - pytest.param( - ModExpInput( - base="1fb473dd1171cf88116aa77ab3612c2c7d2cf466cc2386cc456130e2727c70b4", - exponent="0000000000000000000000000000000000000000000000000000000001000000", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_200n1", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L186 - pytest.param( - ModExpInput( - base="1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb", - exponent="0000000000000000000000000000000000000000000000000000000000ffffff", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_200n2", - ), - # Ported from - # https://github.com/NethermindEth/nethermind/blob/ceb8d57b8530ce8181d7427c115ca593386909d6/tools/EngineRequestsGenerator/TestCases/ModexpVulnerability.cs#L188 - pytest.param( - ModExpInput( - base="288254ba43e713afbe36c9f03b54c00fae4c0a82df1cf165eb46a21c20a48ca2", - exponent="0000000000000000000000000000000000000000000000000000000000ffffff", - modulus="30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", - ), - id="mod_vul_common_200n3", - ), + ] + + regular_cases = [ pytest.param( ModExpInput( - base="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - exponent="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - modulus="fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + base=base, + exponent=exponent, + modulus=modulus, ), - id="mod_vul_zkevm_worst_case", - ), - ], + id=test_id, + ) + for base, exponent, modulus, test_id in test_cases + ] + + return regular_cases + special_cases + + +@pytest.mark.parametrize( + ["mod_exp_input"], + create_modexp_test_cases(), ) def test_worst_modexp( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, mod_exp_input: ModExpInput, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many calls to the MODEXP (5) precompile as possible. All the calls have the same parametrized input. """ - # Skip the trailing zeros from the input to make EVM work even harder. - calldata = bytes(mod_exp_input).rstrip(b"\x00") - - code = code_loop_precompile_call( - Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), # Copy the input to the - # memory. - Op.POP(Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0)), - fork, - ) - - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - input=calldata, + attack_block = Op.POP( + Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0) ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), + attack_block=attack_block, + tx_kwargs={"data": bytes(mod_exp_input).rstrip(b"\x00")}, + ), ) @@ -1786,12 +1145,10 @@ def test_worst_modexp( ], ) def test_worst_precompile_fixed_cost( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, fork: Fork, precompile_address: Address, parameters: list[str] | list[BytesConcatenation] | list[bytes], - gas_benchmark_value: int, ) -> None: """Test running a block filled with a precompile with fixed cost.""" if precompile_address not in fork.precompiles(): @@ -1816,122 +1173,61 @@ def test_worst_precompile_fixed_cost( padding_length = (32 - (len(concatenated_bytes) % 32)) % 32 input_bytes = concatenated_bytes + b"\x00" * padding_length - calldata = Bytecode() + setup = Bytecode() for i in range(0, len(input_bytes), 32): chunk = input_bytes[i : i + 32] value_to_store = int.from_bytes(chunk, "big") - calldata += Op.MSTORE(i, value_to_store) + setup += Op.MSTORE(i, value_to_store) attack_block = Op.POP( Op.STATICCALL(Op.GAS, precompile_address, 0, len(concatenated_bytes), 0, 0) ) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=bytes(code)) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) def test_worst_jumps( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - gas_benchmark_value: int, ) -> None: """Test running a JUMP-intensive contract.""" - jumps_code = Op.JUMPDEST + Op.JUMP(Op.PUSH0) - jumps_address = pre.deploy_contract(jumps_code) - tx = Transaction( - to=jumps_address, - gas_limit=gas_benchmark_value, + to=pre.deploy_contract(code=(Op.JUMPDEST + Op.JUMP(Op.PUSH0))), sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) def test_worst_jumpi_fallthrough( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, - gas_benchmark_value: int, + benchmark_test: BenchmarkTestFiller, ) -> None: """Test running a JUMPI-intensive contract with fallthrough.""" - max_code_size = fork.max_code_size() - - def jumpi_seq() -> Bytecode: - return Op.JUMPI(Op.PUSH0, Op.PUSH0) - - prefix_seq = Op.JUMPDEST - suffix_seq = Op.JUMP(Op.PUSH0) - bytes_per_seq = len(jumpi_seq()) - seqs_per_call = (max_code_size - len(prefix_seq) - len(suffix_seq)) // bytes_per_seq - - # Create and deploy the jumpi-intensive contract - jumpis_code = prefix_seq + jumpi_seq() * seqs_per_call + suffix_seq - assert len(jumpis_code) <= max_code_size - - jumpis_address = pre.deploy_contract(code=bytes(jumpis_code)) - - tx = Transaction( - to=jumpis_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(attack_block=Op.JUMPI(Op.PUSH0, Op.PUSH0)), ) def test_worst_jumpis( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - gas_benchmark_value: int, ) -> None: """Test running a JUMPI-intensive contract.""" - jumpi_code = Op.JUMPDEST + Op.JUMPI(Op.PUSH0, Op.NUMBER) - jumpi_address = pre.deploy_contract(jumpi_code) - tx = Transaction( - to=jumpi_address, - gas_limit=gas_benchmark_value, + to=pre.deploy_contract(code=(Op.JUMPDEST + Op.JUMPI(Op.PUSH0, Op.NUMBER))), sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) -@pytest.mark.slow def test_worst_jumpdests( benchmark_test: BenchmarkTestFiller, - pre: Alloc, ) -> None: """Test running a JUMPDEST-intensive contract.""" - benchmark_test( - pre=pre, - post={}, - code_generator=JumpLoopGenerator(attack_block=Op.JUMPDEST), - ) + benchmark_test(code_generator=JumpLoopGenerator(attack_block=Op.JUMPDEST)) DEFAULT_BINOP_ARGS = ( @@ -2083,74 +1379,41 @@ def test_worst_jumpdests( ids=lambda param: "" if isinstance(param, tuple) else param, ) def test_worst_binop_simple( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, opcode: Op, - fork: Fork, opcode_args: tuple[int, int], - gas_benchmark_value: int, ) -> None: """ Test running a block with as many binary instructions (takes two args, produces one value) as possible. The execution starts with two initial values on the stack, and the stack is balanced by the DUP2 instruction. """ - max_code_size = fork.max_code_size() - tx_data = b"".join(arg.to_bytes(32, byteorder="big") for arg in opcode_args) - code_prefix = Op.JUMPDEST + Op.CALLDATALOAD(0) + Op.CALLDATALOAD(32) - code_suffix = Op.POP + Op.POP + Op.PUSH0 + Op.JUMP - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_body = (Op.DUP2 + opcode) * (code_body_len // 2) - code = code_prefix + code_body + code_suffix - assert len(code) == max_code_size - 1 - - tx = Transaction( - to=pre.deploy_contract(code=code), - data=tx_data, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + setup = Op.CALLDATALOAD(0) + Op.CALLDATALOAD(32) + Op.DUP2 + Op.DUP2 + attack_block = Op.DUP2 + opcode + cleanup = Op.POP + Op.POP + Op.DUP2 + Op.DUP2 + benchmark_test( + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + cleanup=cleanup, + tx_kwargs={"data": tx_data}, + ), ) @pytest.mark.parametrize("opcode", [Op.ISZERO, Op.NOT]) def test_worst_unop( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, opcode: Op, - fork: Fork, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many unary instructions (takes one arg, produces one value) as possible. """ - max_code_size = fork.max_code_size() - - code_prefix = Op.JUMPDEST + Op.PUSH0 # Start with the arg 0. - code_suffix = Op.POP + Op.PUSH0 + Op.JUMP - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_body = opcode * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) == max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=Op.PUSH0, attack_block=opcode), ) @@ -2160,103 +1423,71 @@ def test_worst_unop( # key changes. @pytest.mark.parametrize("val_mut", [True, False]) def test_worst_tload( - state_test: StateTestFiller, - fork: Fork, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, key_mut: bool, val_mut: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many TLOAD calls as possible.""" - max_code_size = fork.max_code_size() - start_key = 41 code_key_mut = Bytecode() code_val_mut = Bytecode() + setup = Bytecode() if key_mut and val_mut: - code_prefix = Op.PUSH1(start_key) + Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.DUP1)) + setup = Op.PUSH1(start_key) + attack_block = Op.POP(Op.TLOAD(Op.DUP1)) code_key_mut = Op.POP + Op.GAS code_val_mut = Op.TSTORE(Op.DUP2, Op.GAS) if key_mut and not val_mut: - code_prefix = Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.GAS)) + attack_block = Op.POP(Op.TLOAD(Op.GAS)) if not key_mut and val_mut: - code_prefix = Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.CALLVALUE)) - code_val_mut = Op.TSTORE(Op.CALLVALUE, Op.GAS) # CALLVALUE configured - # in the tx + attack_block = Op.POP(Op.TLOAD(Op.CALLVALUE)) + code_val_mut = Op.TSTORE(Op.CALLVALUE, Op.GAS) # CALLVALUE configured in the tx if not key_mut and not val_mut: - code_prefix = Op.JUMPDEST - loop_iter = Op.POP(Op.TLOAD(Op.CALLVALUE)) + attack_block = Op.POP(Op.TLOAD(Op.CALLVALUE)) - code_suffix = code_key_mut + code_val_mut + Op.JUMP(len(code_prefix) - 1) - - code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) - code_body = loop_iter * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - value=start_key if not key_mut and val_mut else 0, - ) + cleanup = code_key_mut + code_val_mut + tx_value = start_key if not key_mut and val_mut else 0 - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + cleanup=cleanup, + tx_kwargs={ + "value": tx_value, + }, + ), ) @pytest.mark.parametrize("key_mut", [True, False]) @pytest.mark.parametrize("dense_val_mut", [True, False]) def test_worst_tstore( - state_test: StateTestFiller, - fork: Fork, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, key_mut: bool, dense_val_mut: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many TSTORE calls as possible.""" - max_code_size = fork.max_code_size() - init_key = 42 - code_prefix = Op.PUSH1(init_key) + Op.JUMPDEST - - # If `key_mut` is True, we mutate the key on every iteration of the big - # loop. - code_key_mut = Op.POP + Op.GAS if key_mut else Bytecode() - code_suffix = code_key_mut + Op.JUMP(len(code_prefix) - 1) - - # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a - # different value than the previous one. - loop_iter = Op.TSTORE(Op.DUP2, Op.GAS if dense_val_mut else Op.DUP1) + setup = Op.PUSH1(init_key) - code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) - code_body = loop_iter * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size + # If `dense_val_mut` is set, we use GAS as a cheap way of always + # storing a different value than + # the previous one. + attack_block = Op.TSTORE(Op.DUP2, Op.GAS if dense_val_mut else Op.DUP1) - tx = Transaction( - to=pre.deploy_contract(code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + # If `key_mut` is True, we mutate the key on every iteration of the + # big loop. + cleanup = Op.POP + Op.GAS if key_mut else Bytecode() - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block, cleanup=cleanup), ) @pytest.mark.parametrize("shift_right", [Op.SHR, Op.SAR]) def test_worst_shifts( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, shift_right: Op, @@ -2333,11 +1564,7 @@ def select_shift_amount(shift_fn: Any, v: Any) -> Any: sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -2351,67 +1578,34 @@ def select_shift_amount(shift_fn: Any, v: Any) -> Any: ) def test_worst_blobhash( fork: Fork, - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, blob_index: int, blobs_present: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many BLOBHASH instructions as possible.""" - max_code_size = fork.max_code_size() - max_stack_height = fork.max_stack_height() - - # Contract that contains a collection of BLOBHASH instructions. - opcode_sequence = Op.BLOBHASH(blob_index) * max_stack_height - assert len(opcode_sequence) <= max_code_size - - target_contract_address = pre.deploy_contract(code=opcode_sequence) - - # Contract that contains a loop of STATICCALLs to the target contract. - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= max_code_size - - code_address = pre.deploy_contract(code=code) - - # Create blob transaction if blobs are present. - tx_type = TransactionType.LEGACY - blob_versioned_hashes = None - max_fee_per_blob_gas = None + tx_kwargs: Dict[str, Any] = {} if blobs_present > 0: - tx_type = TransactionType.BLOB_TRANSACTION - max_fee_per_blob_gas = fork.min_base_fee_per_blob_gas() - blob_versioned_hashes = add_kzg_version( + tx_kwargs["ty"] = TransactionType.BLOB_TRANSACTION + tx_kwargs["max_fee_per_blob_gas"] = fork.min_base_fee_per_blob_gas() + tx_kwargs["blob_versioned_hashes"] = add_kzg_version( [i.to_bytes() * 32 for i in range(blobs_present)], BlobsSpec.BLOB_COMMITMENT_VERSION_KZG, ) - tx = Transaction( - ty=tx_type, - to=code_address, - gas_limit=gas_benchmark_value, - max_fee_per_blob_gas=max_fee_per_blob_gas, - blob_versioned_hashes=blob_versioned_hashes, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=ExtCallGenerator( + attack_block=Op.BLOBHASH(blob_index), + tx_kwargs=tx_kwargs, + ), ) @pytest.mark.parametrize("mod_bits", [255, 191, 127, 63]) @pytest.mark.parametrize("op", [Op.MOD, Op.SMOD]) def test_worst_mod( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, mod_bits: int, op: Op, - gas_benchmark_value: int, ) -> None: """ Test running a block with as many MOD instructions with arguments of the @@ -2428,11 +1622,11 @@ def test_worst_mod( The order of accessing the numerators is selected in a way the mod value remains in the range as long as possible. """ - max_code_size = fork.max_code_size() - - # For SMOD we negate both numerator and modulus. The underlying computation - # is the same, just the SMOD implementation will have to additionally - # handle the sign bits. The result stays negative. + # For SMOD we negate both numerator and modulus. The underlying + # computation is the same, + # just the SMOD implementation will have to additionally handle the + # sign bits. + # The result stays negative. should_negate = op == Op.SMOD num_numerators = 15 @@ -2503,35 +1697,20 @@ def test_worst_mod( seed += 1 print(f"{seed=}") - # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal push - # opcode. - code_constant_pool = sum((Op.PUSH32[n] for n in numerators), Bytecode()) - code_prefix = code_constant_pool + Op.JUMPDEST - code_suffix = Op.JUMP(len(code_constant_pool)) - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_segment = ( + # TODO: Don't use fixed PUSH32. Let Bytecode helpers to select optimal + # push opcode. + setup = sum((Op.PUSH32[n] for n in numerators), Bytecode()) + attack_block = ( Op.CALLDATALOAD(0) + sum(make_dup(len(numerators) - i) + op for i in indexes) + Op.POP ) - code = ( - code_prefix - # TODO: Add int * Bytecode support - + sum(code_segment for _ in range(code_body_len // len(code_segment))) - + code_suffix - ) - assert (max_code_size - len(code_segment)) < len(code) <= max_code_size input_value = initial_mod if not should_negate else neg(initial_mod) - tx = Transaction( - to=pre.deploy_contract(code=code), - data=input_value.to_bytes(32, byteorder="big"), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + tx_kwargs={"data": input_value.to_bytes(32, byteorder="big")}, + ), ) @@ -2540,50 +1719,31 @@ def test_worst_mod( @pytest.mark.parametrize("offset_initialized", [True, False]) @pytest.mark.parametrize("big_memory_expansion", [True, False]) def test_worst_memory_access( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, opcode: Op, offset: int, offset_initialized: bool, big_memory_expansion: bool, - gas_benchmark_value: int, ) -> None: """ - Test running a block with as many memory access instructions as possible. + Test running a block with as many memory access instructions as + possible. """ - max_code_size = fork.max_code_size() - mem_exp_code = Op.MSTORE8(10 * 1024, 1) if big_memory_expansion else Bytecode() offset_set_code = Op.MSTORE(offset, 43) if offset_initialized else Bytecode() - code_prefix = mem_exp_code + offset_set_code + Op.PUSH1(42) + Op.PUSH1(offset) + Op.JUMPDEST - - code_suffix = Op.JUMP(len(code_prefix) - 1) + setup = mem_exp_code + offset_set_code + Op.PUSH1(42) + Op.PUSH1(offset) - loop_iter = Op.POP(Op.MLOAD(Op.DUP1)) if opcode == Op.MLOAD else opcode(Op.DUP2, Op.DUP2) - - code_body_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(loop_iter) - code_body = loop_iter * code_body_len - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + attack_block = Op.POP(Op.MLOAD(Op.DUP1)) if opcode == Op.MLOAD else opcode(Op.DUP2, Op.DUP2) - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) @pytest.mark.parametrize("mod_bits", [255, 191, 127, 63]) @pytest.mark.parametrize("op", [Op.ADDMOD, Op.MULMOD]) def test_worst_modarith( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, mod_bits: int, @@ -2682,29 +1842,21 @@ def test_worst_modarith( sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) def test_empty_block( - blockchain_test: BlockchainTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, ) -> None: """Test running an empty block as a baseline for fixed proving costs.""" - blockchain_test( - pre=pre, - post={}, + benchmark_test( blocks=[Block(txs=[])], expected_benchmark_gas_used=0, ) def test_amortized_bn128_pairings( - state_test: StateTestFiller, - pre: Alloc, + benchmark_test: BenchmarkTestFiller, fork: Fork, gas_benchmark_value: int, ) -> None: @@ -2750,23 +1902,15 @@ def test_amortized_bn128_pairings( max_pairings = num_pairings_done optimal_per_call_num_pairings = i - calldata = Op.CALLDATACOPY(size=Op.CALLDATASIZE) + setup = Op.CALLDATACOPY(size=Op.CALLDATASIZE) attack_block = Op.POP(Op.STATICCALL(Op.GAS, 0x08, 0, Op.CALLDATASIZE, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - data=_generate_bn128_pairs(optimal_per_call_num_pairings, 42), - sender=pre.fund_eoa(), - ) - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=setup, + attack_block=attack_block, + tx_kwargs={"data": _generate_bn128_pairs(optimal_per_call_num_pairings, 42)}, + ), ) @@ -2809,34 +1953,16 @@ def _generate_bn128_pairs(n: int, seed: int = 0) -> Bytes: ], ) def test_worst_calldataload( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, calldata: bytes, - gas_benchmark_value: int, ) -> None: """Test running a block with as many CALLDATALOAD as possible.""" - max_code_size = fork.max_code_size() - - code_prefix = Op.PUSH0 + Op.JUMPDEST - code_suffix = Op.PUSH1(1) + Op.JUMP - code_body_len = max_code_size - len(code_prefix) - len(code_suffix) - code_loop_iter = Op.CALLDATALOAD - code_body = code_loop_iter * (code_body_len // len(code_loop_iter)) - code = code_prefix + code_body + code_suffix - assert len(code) <= max_code_size - - tx = Transaction( - to=pre.deploy_contract(code=code), - data=calldata, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=Op.PUSH0, + attack_block=Op.CALLDATALOAD, + tx_kwargs={"data": calldata}, + ), ) @@ -2863,13 +1989,10 @@ def test_worst_calldataload( ) def test_worst_swap( benchmark_test: BenchmarkTestFiller, - pre: Alloc, opcode: Opcode, ) -> None: """Test running a block with as many SWAP as possible.""" benchmark_test( - pre=pre, - post={}, code_generator=JumpLoopGenerator( attack_block=opcode, setup=Op.PUSH0 * opcode.min_stack_height ), @@ -2898,36 +2021,22 @@ def test_worst_swap( ], ) def test_worst_dup( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, - gas_benchmark_value: int, ) -> None: """Test running a block with as many DUP as possible.""" max_stack_height = fork.max_stack_height() min_stack_height = opcode.min_stack_height - code_prefix = Op.PUSH0 * min_stack_height - opcode_sequence = opcode * (max_stack_height - min_stack_height) - target_contract_address = pre.deploy_contract(code=code_prefix + opcode_sequence) + code = Op.PUSH0 * min_stack_height + opcode * (max_stack_height - min_stack_height) + target_contract_address = pre.deploy_contract(code=code) - calldata = Bytecode() attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0)) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(attack_block=attack_block), ) @@ -2970,40 +2079,14 @@ def test_worst_dup( ], ) def test_worst_push( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, opcode: Op, - gas_benchmark_value: int, ) -> None: """Test running a block with as many PUSH as possible.""" - op = opcode[1] if opcode.has_data_portion() else opcode - - op_seq = Bytecode() - for _ in range(fork.max_stack_height()): - if len(op_seq) + len(op) > fork.max_code_size(): - break - op_seq += op - - target_contract_address = pre.deploy_contract(code=op_seq) - - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_contract_address, 0, 0, 0, 0)) - - code = code_loop_precompile_call(calldata, attack_block, fork) - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=ExtCallGenerator( + attack_block=opcode[1] if opcode.has_data_portion() else opcode + ), ) @@ -3022,13 +2105,12 @@ def test_worst_push( ], ) def test_worst_return_revert( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, return_size: int, return_non_zero_data: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many RETURN or REVERT as possible.""" max_code_size = fork.max_code_size() @@ -3051,78 +2133,32 @@ def test_worst_return_revert( code += Op.INVALID * (max_code_size - len(executable_code)) target_contract_address = pre.deploy_contract(code=code) - calldata = Bytecode() attack_block = Op.POP(Op.STATICCALL(address=target_contract_address)) - code = code_loop_precompile_call(calldata, attack_block, fork) - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(attack_block=attack_block), ) @pytest.mark.valid_from("Osaka") -def test_worst_clz_same_input( - blockchain_test: BlockchainTestFiller, - pre: Alloc, - fork: Fork, - gas_benchmark_value: int, - env: Environment, -) -> None: +def test_worst_clz_same_input(benchmark_test: BenchmarkTestFiller) -> None: """Test running a block with as many CLZ with same input as possible.""" - tx_gas_limit = fork.transaction_gas_limit_cap() or env.gas_limit - magic_value = 248 # CLZ(248) = 248 - - calldata = Op.PUSH1(magic_value) - attack_block = Op.CLZ - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= fork.max_code_size() - - code_address = pre.deploy_contract(code=code) - - sender = pre.fund_eoa() - tx_count = gas_benchmark_value // tx_gas_limit - remainder_gas = gas_benchmark_value % tx_gas_limit - - txs = [ - Transaction( - to=code_address, - gas_limit=tx_gas_limit if i < tx_count else remainder_gas, - nonce=i, - sender=sender, - ) - for i in range(tx_count + 1) - ] - - blockchain_test( - genesis_environment=env, - pre=pre, - post={}, - blocks=[Block(txs=txs)], + benchmark_test( + code_generator=JumpLoopGenerator(setup=Op.PUSH1(magic_value), attack_block=Op.CLZ), ) @pytest.mark.valid_from("Osaka") def test_worst_clz_diff_input( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, - gas_benchmark_value: int, - env: Environment, ) -> None: """ - Test running a block with as many CLZ with different input as possible. + Test running a block with as many CLZ with different input as + possible. """ - tx_gas_limit = fork.transaction_gas_limit_cap() or env.gas_limit max_code_size = fork.max_code_size() code_prefix = Op.JUMPDEST @@ -3142,24 +2178,9 @@ def test_worst_clz_diff_input( attack_code = code_prefix + code_seq + code_suffix assert len(attack_code) <= max_code_size - code_address = pre.deploy_contract(code=attack_code) - - sender = pre.fund_eoa() - tx_count = gas_benchmark_value // tx_gas_limit - remainder_gas = gas_benchmark_value % tx_gas_limit - txs = [ - Transaction( - to=code_address, - gas_limit=tx_gas_limit if i < tx_count else remainder_gas, - nonce=i, - sender=sender, - ) - for i in range(tx_count + 1) - ] - - blockchain_test( - genesis_environment=env, - pre=pre, - post={}, - blocks=[Block(txs=txs)], + tx = Transaction( + to=pre.deploy_contract(code=attack_code), + sender=pre.fund_eoa(), ) + + benchmark_test(tx=tx) diff --git a/tests/benchmark/test_worst_memory.py b/tests/benchmark/test_worst_memory.py index 551bcd1a77d..70667521e2e 100755 --- a/tests/benchmark/test_worst_memory.py +++ b/tests/benchmark/test_worst_memory.py @@ -2,20 +2,21 @@ Tests that benchmark EVMs in the worst-case memory opcodes. """ +from enum import auto + import pytest from ethereum_test_base_types.base_types import Bytes +from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_forks import Fork from ethereum_test_tools import ( Alloc, + BenchmarkTestFiller, Bytecode, - StateTestFiller, Transaction, ) from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -23,8 +24,8 @@ class CallDataOrigin: """Enum for calldata origins.""" - TRANSACTION = 1 - CALL = 2 + TRANSACTION = auto() + CALL = auto() @pytest.mark.parametrize( @@ -58,7 +59,7 @@ class CallDataOrigin: ], ) def test_worst_calldatacopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, origin: CallDataOrigin, @@ -83,16 +84,20 @@ def test_worst_calldatacopy( # We create the contract that will be doing the CALLDATACOPY multiple # times. - # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy length. - # Otherwise, since we don't send zero data explicitly via calldata, PUSH - # the target size and use DUP1 to copy it. - prefix = Bytecode() if non_zero_data or size == 0 else Op.PUSH3(size) + # + # If `non_zero_data` is True, we leverage CALLDATASIZE for the copy + # length. Otherwise, since we + # don't send zero data explicitly via calldata, PUSH the target size and + # use DUP1 to copy it. + setup = Bytecode() if non_zero_data or size == 0 else Op.PUSH3(size) src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.CALLDATACOPY( src_dst, src_dst, Op.CALLDATASIZE if non_zero_data or size == 0 else Op.DUP1 ) - code = code_loop_precompile_call(prefix, attack_block, fork) - code_address = pre.deploy_contract(code=code) + + code_address = JumpLoopGenerator(setup=setup, attack_block=attack_block).deploy_contracts( + pre=pre, fork=fork + ) tx_target = code_address @@ -101,15 +106,17 @@ def test_worst_calldatacopy( if origin == CallDataOrigin.CALL: # If `non_zero_data` is False we leverage just using zeroed memory. # Otherwise, we copy the calldata received from the transaction. - prefix = ( + setup = ( Op.CALLDATACOPY(Op.PUSH0, Op.PUSH0, Op.CALLDATASIZE) if non_zero_data else Bytecode() ) + Op.JUMPDEST arg_size = Op.CALLDATASIZE if non_zero_data else size - code = prefix + Op.STATICCALL( + attack_block = Op.STATICCALL( address=code_address, args_offset=Op.PUSH0, args_size=arg_size ) - code += Op.JUMP(len(prefix) - 1) - tx_target = pre.deploy_contract(code=code) + + tx_target = JumpLoopGenerator(setup=setup, attack_block=attack_block).deploy_contracts( + pre=pre, fork=fork + ) tx = Transaction( to=tx_target, @@ -118,11 +125,7 @@ def test_worst_calldatacopy( sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -143,42 +146,41 @@ def test_worst_calldatacopy( ], ) def test_worst_codecopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, max_code_size_ratio: float, fixed_src_dst: bool, - gas_benchmark_value: int, ) -> None: """Test running a block filled with CODECOPY executions.""" max_code_size = fork.max_code_size() size = int(max_code_size * max_code_size_ratio) - code_prefix = Op.PUSH32(size) + setup = Op.PUSH32(size) src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) attack_block = Op.CODECOPY(src_dst, src_dst, Op.DUP1) # DUP1 copies size. - code = code_loop_precompile_call(code_prefix, attack_block, fork) - # The code generated above is not guaranteed to be of max_code_size, so we - # pad it since a test parameter targets CODECOPYing a contract with max - # code size. Padded bytecode values are not relevant. - code = code + Op.INVALID * (max_code_size - len(code)) + code = JumpLoopGenerator(setup=setup, attack_block=attack_block).generate_repeated_code( + repeated_code=attack_block, setup=setup, fork=fork + ) + + # The code generated above is not guaranteed to be of max_code_size, so + # we pad it since + # a test parameter targets CODECOPYing a contract with max code size. + # Padded bytecode values + # are not relevant. + code += Op.INVALID * (max_code_size - len(code)) assert len(code) == max_code_size, ( f"Code size {len(code)} is not equal to max code size {max_code_size}." ) tx = Transaction( to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize( @@ -198,20 +200,17 @@ def test_worst_codecopy( ], ) def test_worst_returndatacopy( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, size: int, fixed_dst: bool, - gas_benchmark_value: int, ) -> None: """Test running a block filled with RETURNDATACOPY executions.""" - max_code_size = fork.max_code_size() - # Create the contract that will RETURN the data that will be used for - # RETURNDATACOPY. Random-ish data is injected at different points in memory - # to avoid making the content predictable. If `size` is 0, this helper - # contract won't be used. + # RETURNDATACOPY. + # Random-ish data is injected at different points in memory to avoid + # making the content + # predictable. If `size` is 0, this helper contract won't be used. code = ( Op.MSTORE8(0, Op.GAS) + Op.MSTORE8(size // 2, Op.GAS) @@ -220,14 +219,14 @@ def test_worst_returndatacopy( ) helper_contract = pre.deploy_contract(code=code) + returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() + dst = 0 if fixed_dst else Op.MOD(Op.GAS, 7) + # We create the contract that will be doing the RETURNDATACOPY multiple # times. returndata_gen = Op.STATICCALL(address=helper_contract) if size > 0 else Bytecode() - dst = 0 if fixed_dst else Op.MOD(Op.GAS, 7) - attack_iter = Op.RETURNDATACOPY(dst, Op.PUSH0, Op.RETURNDATASIZE) + attack_block = Op.RETURNDATACOPY(dst, Op.PUSH0, Op.RETURNDATASIZE) - jumpdest = Op.JUMPDEST - jump_back = Op.JUMP(len(returndata_gen)) # The attack loop is constructed as: # ``` # JUMPDEST(#) @@ -238,31 +237,13 @@ def test_worst_returndatacopy( # JUMP(#) # ``` # The goal is that once per (big) loop iteration, the helper contract is - # called to generate fresh returndata to continue calling RETURNDATACOPY. - max_iters_loop = ( - max_code_size - 2 * len(returndata_gen) - len(jumpdest) - len(jump_back) - ) // len(attack_iter) - code = ( - returndata_gen - + jumpdest - + sum([attack_iter] * max_iters_loop) - + returndata_gen - + jump_back - ) - assert len(code) <= max_code_size, ( - f"Code size {len(code)} is not equal to max code size {max_code_size}." - ) + # called to + # generate fresh returndata to continue calling RETURNDATACOPY. - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=returndata_gen, attack_block=attack_block, cleanup=returndata_gen + ), ) @@ -283,42 +264,21 @@ def test_worst_returndatacopy( ], ) def test_worst_mcopy( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, size: int, fixed_src_dst: bool, - gas_benchmark_value: int, ) -> None: """Test running a block filled with MCOPY executions.""" - max_code_size = fork.max_code_size() + src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) + attack_block = Op.MCOPY(src_dst, src_dst, size) mem_touch = ( Op.MSTORE8(0, Op.GAS) + Op.MSTORE8(size // 2, Op.GAS) + Op.MSTORE8(size - 1, Op.GAS) if size > 0 else Bytecode() ) - src_dst = 0 if fixed_src_dst else Op.MOD(Op.GAS, 7) - attack_block = Op.MCOPY(src_dst, src_dst, size) - - jumpdest = Op.JUMPDEST - jump_back = Op.JUMP(len(mem_touch)) - max_iters_loop = (max_code_size - 2 * len(mem_touch) - len(jumpdest) - len(jump_back)) // len( - attack_block - ) - code = mem_touch + jumpdest + sum([attack_block] * max_iters_loop) + mem_touch + jump_back - assert len(code) <= max_code_size, ( - f"Code size {len(code)} is not equal to max code size {max_code_size}." - ) - - tx = Transaction( - to=pre.deploy_contract(code=code), - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator( + setup=mem_touch, attack_block=attack_block, cleanup=mem_touch + ), ) diff --git a/tests/benchmark/test_worst_opcode.py b/tests/benchmark/test_worst_opcode.py index 4a220875c36..f632d56bc82 100755 --- a/tests/benchmark/test_worst_opcode.py +++ b/tests/benchmark/test_worst_opcode.py @@ -4,18 +4,14 @@ import pytest -from ethereum_test_forks import Fork +from ethereum_test_benchmark.benchmark_code_generator import JumpLoopGenerator from ethereum_test_tools import ( - Alloc, + BenchmarkTestFiller, Bytecode, - StateTestFiller, - Transaction, ) from ethereum_test_vm import Opcode from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - @pytest.mark.parametrize( "opcode", @@ -40,30 +36,25 @@ ) @pytest.mark.parametrize("fixed_offset", [True, False]) def test_worst_log_opcodes( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, + benchmark_test: BenchmarkTestFiller, opcode: Opcode, zeros_topic: bool, size: int, fixed_offset: bool, non_zero_data: bool, - gas_benchmark_value: int, ) -> None: """Test running a block with as many LOG opcodes as possible.""" - max_code_size = fork.max_code_size() - - calldata = Bytecode() + setup = Bytecode() # For non-zero data, load into memory. if non_zero_data: - calldata += Op.CODECOPY(dest_offset=0, offset=0, size=Op.CODESIZE) + setup += Op.CODECOPY(dest_offset=0, offset=0, size=Op.CODESIZE) # Push the size value onto the stack and access it using the DUP opcode. - calldata += Op.PUSH3(size) + setup += Op.PUSH3(size) # For non-zeros topic, push a non-zero value for topic. - calldata += Op.PUSH0 if zeros_topic else Op.PUSH32(2**256 - 1) + setup += Op.PUSH0 if zeros_topic else Op.PUSH32(2**256 - 1) topic_count = len(opcode.kwargs or []) - 2 offset = Op.PUSH0 if fixed_offset else Op.MOD(Op.GAS, 7) @@ -72,21 +63,8 @@ def test_worst_log_opcodes( # 0 topics -> DUP1, 1 topic -> DUP2, N topics -> DUP(N+1) size_op = getattr(Op, f"DUP{topic_count + 2}") - code_sequence = Op.DUP1 * topic_count + size_op + offset + opcode - - code = code_loop_precompile_call(calldata, code_sequence, fork) - assert len(code) <= max_code_size - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) + attack_block = Op.DUP1 * topic_count + size_op + offset + opcode - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) diff --git a/tests/benchmark/test_worst_stateful_opcodes.py b/tests/benchmark/test_worst_stateful_opcodes.py index 95162625102..10f29289f34 100755 --- a/tests/benchmark/test_worst_stateful_opcodes.py +++ b/tests/benchmark/test_worst_stateful_opcodes.py @@ -3,20 +3,23 @@ """ import math +from enum import auto import pytest +from ethereum_test_base_types import HexNumber +from ethereum_test_benchmark.benchmark_code_generator import ExtCallGenerator, JumpLoopGenerator from ethereum_test_forks import Fork +from ethereum_test_specs import StateTestFiller +from ethereum_test_specs.benchmark import BenchmarkTestFiller from ethereum_test_tools import ( Account, Address, Alloc, Block, - BlockchainTestFiller, Bytecode, Environment, Hash, - StateTestFiller, Transaction, While, compute_create2_address, @@ -24,8 +27,6 @@ ) from ethereum_test_vm import Opcodes as Op -from .helpers import code_loop_precompile_call - REFERENCE_SPEC_GIT_PATH = "TODO" REFERENCE_SPEC_VERSION = "TODO" @@ -44,7 +45,7 @@ ], ) def test_worst_address_state_cold( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, opcode: Op, @@ -107,11 +108,9 @@ def test_worst_address_state_cold( ) blocks.append(Block(txs=[op_tx])) - blockchain_test( - pre=pre, + benchmark_test( post=post, blocks=blocks, - exclude_full_post_state_in_output=True, ) @@ -135,20 +134,15 @@ def test_worst_address_state_cold( ], ) def test_worst_address_state_warm( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, - fork: Fork, opcode: Op, absent_target: bool, - gas_benchmark_value: int, ) -> None: """ - Test running a block with as many stateful opcodes doing warm access for an - account. + Test running a block with as many stateful opcodes doing warm access + for an account. """ - max_code_size = fork.max_code_size() - attack_gas_limit = gas_benchmark_value - # Setup target_addr = Address(100_000) post = {} @@ -158,45 +152,28 @@ def test_worst_address_state_warm( post[target_addr] = Account(balance=100, code=code) # Execution - prep = Op.MSTORE(0, target_addr) - jumpdest = Op.JUMPDEST - jump_back = Op.JUMP(len(prep)) - iter_block = Op.POP(opcode(address=Op.MLOAD(0))) - max_iters_loop = (max_code_size - len(prep) - len(jumpdest) - len(jump_back)) // len( - iter_block - ) - op_code = prep + jumpdest + sum([iter_block] * max_iters_loop) + jump_back - if len(op_code) > max_code_size: - # Must never happen, but keep it as a sanity check. - raise ValueError(f"Code size {len(op_code)} exceeds maximum code size {max_code_size}") - op_address = pre.deploy_contract(code=op_code) - tx = Transaction( - to=op_address, - gas_limit=attack_gas_limit, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, + setup = Op.MSTORE(0, target_addr) + attack_block = Op.POP(opcode(address=Op.MLOAD(0))) + benchmark_test( post=post, - tx=tx, + code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block), ) class StorageAction: """Enum for storage actions.""" - READ = 1 - WRITE_SAME_VALUE = 2 - WRITE_NEW_VALUE = 3 + READ = auto() + WRITE_SAME_VALUE = auto() + WRITE_NEW_VALUE = auto() class TransactionResult: """Enum for the possible transaction outcomes.""" - SUCCESS = 1 - OUT_OF_GAS = 2 - REVERT = 3 + SUCCESS = auto() + OUT_OF_GAS = auto() + REVERT = auto() @pytest.mark.parametrize( @@ -247,7 +224,7 @@ class TransactionResult: ], ) def test_worst_storage_access_cold( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, fork: Fork, storage_action: StorageAction, @@ -261,7 +238,6 @@ def test_worst_storage_access_cold( """ gas_costs = fork.gas_costs() intrinsic_gas_cost_calc = fork.transaction_intrinsic_cost_calculator() - attack_gas_limit = gas_benchmark_value loop_cost = gas_costs.G_COLD_SLOAD # All accesses are always cold if storage_action == StorageAction.WRITE_NEW_VALUE: @@ -311,7 +287,7 @@ def test_worst_storage_access_cold( ) num_target_slots = ( - attack_gas_limit - intrinsic_gas_cost_calc() - prefix_cost - suffix_cost + gas_benchmark_value - intrinsic_gas_cost_calc() - prefix_cost - suffix_cost ) // loop_cost if tx_result == TransactionResult.OUT_OF_GAS: # Add an extra slot to make it run out-of-gas @@ -369,18 +345,15 @@ def test_worst_storage_access_cold( op_tx = Transaction( to=contract_address, - gas_limit=attack_gas_limit, + gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) blocks.append(Block(txs=[op_tx])) - blockchain_test( - pre=pre, - post={}, + benchmark_test( blocks=blocks, - exclude_full_post_state_in_output=True, expected_benchmark_gas_used=( - total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else attack_gas_limit + total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else gas_benchmark_value ), ) @@ -394,17 +367,16 @@ def test_worst_storage_access_cold( ], ) def test_worst_storage_access_warm( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, storage_action: StorageAction, - env: Environment, gas_benchmark_value: int, + env: Environment, ) -> None: """ - Test running a block with as many warm storage slot accesses as possible. + Test running a block with as many warm storage slot accesses as + possible. """ - attack_gas_limit = gas_benchmark_value - blocks = [] # The target storage slot for the warm access is storage slot 0. @@ -447,22 +419,20 @@ def test_worst_storage_access_warm( op_tx = Transaction( to=contract_address, - gas_limit=attack_gas_limit, + gas_limit=gas_benchmark_value, sender=pre.fund_eoa(), ) blocks.append(Block(txs=[op_tx])) - blockchain_test( - pre=pre, - post={}, - blocks=blocks, - ) + benchmark_test(blocks=blocks) def test_worst_blockhash( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, + fork: Fork, gas_benchmark_value: int, + tx_gas_limit_cap: int, ) -> None: """ Test running a block with as many blockhash accessing oldest allowed block @@ -471,55 +441,44 @@ def test_worst_blockhash( # Create 256 dummy blocks to fill the blockhash window. blocks = [Block()] * 256 - # Always ask for the oldest allowed BLOCKHASH block. - execution_code = Op.PUSH1(1) + While( - body=Op.POP(Op.BLOCKHASH(Op.DUP1)), + code = ExtCallGenerator(attack_block=Op.BLOCKHASH(1)).generate_repeated_code( + repeated_code=Op.BLOCKHASH(1), + fork=fork, ) - execution_code_address = pre.deploy_contract(code=execution_code) - op_tx = Transaction( - to=execution_code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - blocks.append(Block(txs=[op_tx])) - blockchain_test( - pre=pre, - post={}, + iteration_count = math.ceil(gas_benchmark_value / tx_gas_limit_cap) + code_address = pre.deploy_contract(code=code) + + gas_remaining = gas_benchmark_value + txs = [] + for _ in range(iteration_count): + tx_gas_limit = min(tx_gas_limit_cap, gas_remaining) + gas_remaining -= tx_gas_limit + tx = Transaction( + to=code_address, + gas_limit=HexNumber(tx_gas_limit), + sender=pre.fund_eoa(), + ) + txs.append(tx) + blocks.append(Block(txs=txs)) + + benchmark_test( blocks=blocks, + expected_benchmark_gas_used=gas_benchmark_value, ) +@pytest.mark.parametrize("contract_balance", [0, 1]) def test_worst_selfbalance( - state_test: StateTestFiller, - pre: Alloc, - fork: Fork, - gas_benchmark_value: int, + benchmark_test: BenchmarkTestFiller, + contract_balance: int, ) -> None: """Test running a block with as many SELFBALANCE opcodes as possible.""" - max_stack_height = fork.max_stack_height() - - code_sequence = Op.SELFBALANCE * max_stack_height - target_address = pre.deploy_contract(code=code_sequence) - - calldata = Bytecode() - attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0)) - - code = code_loop_precompile_call(calldata, attack_block, fork) - assert len(code) <= fork.max_code_size() - - code_address = pre.deploy_contract(code=code) - - tx = Transaction( - to=code_address, - gas_limit=gas_benchmark_value, - sender=pre.fund_eoa(), - ) - - state_test( - pre=pre, - post={}, - tx=tx, + benchmark_test( + code_generator=ExtCallGenerator( + attack_block=Op.SELFBALANCE, + contract_balance=contract_balance, + ), ) @@ -532,7 +491,7 @@ def test_worst_selfbalance( ], ) def test_worst_extcodecopy_warm( - state_test: StateTestFiller, + benchmark_test: BenchmarkTestFiller, pre: Alloc, copied_size: int, gas_benchmark_value: int, @@ -556,16 +515,12 @@ def test_worst_extcodecopy_warm( sender=pre.fund_eoa(), ) - state_test( - pre=pre, - post={}, - tx=tx, - ) + benchmark_test(tx=tx) @pytest.mark.parametrize("value_bearing", [True, False]) def test_worst_selfdestruct_existing( - blockchain_test: BlockchainTestFiller, + benchmark_test: BenchmarkTestFiller, fork: Fork, pre: Alloc, value_bearing: bool, @@ -696,14 +651,12 @@ def test_worst_selfdestruct_existing( post[deployed_contract_address] = Account(nonce=1) deployed_contract_addresses.append(deployed_contract_address) - blockchain_test( - pre=pre, + benchmark_test( post=post, blocks=[ Block(txs=[contracts_deployment_tx]), Block(txs=[opcode_tx], fee_recipient=fee_recipient), ], - exclude_full_post_state_in_output=True, expected_benchmark_gas_used=expected_benchmark_gas_used, ) @@ -800,7 +753,6 @@ def test_worst_selfdestruct_created( post = {code_addr: Account(storage={0: 42})} # Check for successful # execution. state_test( - env=env, pre=pre, post=post, tx=code_tx, @@ -886,7 +838,6 @@ def test_worst_selfdestruct_initcode( post = {code_addr: Account(storage={0: 42})} # Check for successful # execution. state_test( - env=env, pre=pre, post=post, tx=code_tx,