Skip to content

Commit 43b6217

Browse files
chfastmarioevz
authored andcommitted
feat(tests): add more worst-case modexp benchmarks (ethereum#1701)
* feat(tests): add more worst-case modexp benchmarks This refactors the `test_worst_modexp()` with parametrized precompile inputs. It adds inputs consting ~500 gas for the EIP-7883 review. * Add more cases --------- Co-authored-by: Mario Vega <marioevz@gmail.com>
1 parent 58df655 commit 43b6217

File tree

1 file changed

+97
-27
lines changed

1 file changed

+97
-27
lines changed

tests/zkevm/test_worst_compute.py

Lines changed: 97 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from ethereum_test_tools.vm.opcode import Opcodes as Op
3131
from ethereum_test_types import TransactionType
3232
from ethereum_test_vm.opcode import Opcode
33+
from tests.byzantium.eip198_modexp_precompile.test_modexp import ModExpInput
3334
from tests.cancun.eip4844_blobs.spec import Spec as BlobsSpec
3435
from tests.istanbul.eip152_blake2.common import Blake2bInput
3536
from tests.istanbul.eip152_blake2.spec import Spec as Blake2bSpec
@@ -494,40 +495,109 @@ def test_worst_precompile_only_data_input(
494495

495496

496497
@pytest.mark.valid_from("Cancun")
497-
def test_worst_modexp(state_test: StateTestFiller, pre: Alloc, fork: Fork):
498-
"""Test running a block with as many MODEXP calls as possible."""
499-
env = Environment()
498+
@pytest.mark.parametrize(
499+
["mod_exp_input"],
500+
[
501+
pytest.param(
502+
ModExpInput(
503+
base=8 * "ff",
504+
exponent=112 * "ff",
505+
modulus=7 * "ff" + "00",
506+
),
507+
id="mod_even_8b_exp_896",
508+
),
509+
pytest.param(
510+
ModExpInput(
511+
base=16 * "ff",
512+
exponent=40 * "ff",
513+
modulus=15 * "ff" + "00",
514+
),
515+
id="mod_even_16b_exp_320",
516+
),
517+
pytest.param(
518+
ModExpInput(
519+
base=24 * "ff",
520+
exponent=21 * "ff",
521+
modulus=23 * "ff" + "00",
522+
),
523+
id="mod_even_24b_exp_168",
524+
),
525+
pytest.param(
526+
ModExpInput(
527+
base=32 * "ff",
528+
exponent=5 * "ff",
529+
modulus=31 * "ff" + "00",
530+
),
531+
id="mod_even_32b_exp_40",
532+
),
533+
pytest.param(
534+
ModExpInput(
535+
base=32 * "ff",
536+
exponent=12 * "ff",
537+
modulus=31 * "ff" + "00",
538+
),
539+
id="mod_even_32b_exp_96",
540+
),
541+
pytest.param(
542+
ModExpInput(
543+
base=32 * "ff",
544+
exponent=32 * "ff",
545+
modulus=31 * "ff" + "00",
546+
),
547+
id="mod_even_32b_exp_256",
548+
),
549+
pytest.param(
550+
ModExpInput(
551+
base=32 * "ff",
552+
exponent=12 * "ff",
553+
modulus=31 * "ff" + "01",
554+
),
555+
id="mod_odd_32b_exp_96",
556+
),
557+
pytest.param(
558+
ModExpInput(
559+
base=32 * "ff",
560+
exponent=32 * "ff",
561+
modulus=31 * "ff" + "01",
562+
),
563+
id="mod_odd_32b_exp_256",
564+
),
565+
pytest.param(
566+
ModExpInput(
567+
base=32 * "ff",
568+
exponent=8 * "12345670",
569+
modulus=31 * "ff" + "01",
570+
),
571+
id="mod_odd_32b_exp_cover_windows",
572+
),
573+
],
574+
)
575+
def test_worst_modexp(
576+
state_test: StateTestFiller,
577+
pre: Alloc,
578+
fork: Fork,
579+
mod_exp_input: ModExpInput,
580+
):
581+
"""
582+
Test running a block with as many calls to the MODEXP (5) precompile as possible.
583+
All the calls have the same parametrized input.
584+
"""
585+
# Skip the trailing zeros from the input to make EVM work even harder.
586+
calldata = bytes(mod_exp_input).rstrip(b"\x00")
500587

501-
base_mod_length = 32
502-
exp_length = 32
503-
504-
base = 2 ** (8 * base_mod_length) - 1
505-
mod = 2 ** (8 * base_mod_length) - 2 # Prevents base == mod
506-
exp = 2 ** (8 * exp_length) - 1
507-
508-
# MODEXP calldata
509-
calldata = (
510-
Op.MSTORE(0 * 32, base_mod_length)
511-
+ Op.MSTORE(1 * 32, exp_length)
512-
+ Op.MSTORE(2 * 32, base_mod_length)
513-
+ Op.MSTORE(3 * 32, base)
514-
+ Op.MSTORE(4 * 32, exp)
515-
+ Op.MSTORE(5 * 32, mod)
588+
code = code_loop_precompile_call(
589+
Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE), # Copy the input to the memory.
590+
Op.POP(Op.STATICCALL(Op.GAS, 0x5, Op.PUSH0, Op.CALLDATASIZE, Op.PUSH0, Op.PUSH0)),
591+
fork,
516592
)
517593

518-
# EIP-2565
519-
mul_complexity = math.ceil(base_mod_length / 8) ** 2
520-
iter_complexity = exp.bit_length() - 1
521-
gas_cost = math.floor((mul_complexity * iter_complexity) / 3)
522-
attack_block = Op.POP(Op.STATICCALL(gas_cost, 0x5, 0, 32 * 6, 0, 0))
523-
code = code_loop_precompile_call(calldata, attack_block, fork)
524-
525-
code_address = pre.deploy_contract(code=code)
594+
env = Environment()
526595

527596
tx = Transaction(
528-
to=code_address,
597+
to=pre.deploy_contract(code=code),
529598
gas_limit=env.gas_limit,
530599
sender=pre.fund_eoa(),
600+
input=calldata,
531601
)
532602

533603
state_test(

0 commit comments

Comments
 (0)