|
30 | 30 | from ethereum_test_tools.vm.opcode import Opcodes as Op
|
31 | 31 | from ethereum_test_types import TransactionType
|
32 | 32 | from ethereum_test_vm.opcode import Opcode
|
| 33 | +from tests.byzantium.eip198_modexp_precompile.test_modexp import ModExpInput |
33 | 34 | from tests.cancun.eip4844_blobs.spec import Spec as BlobsSpec
|
34 | 35 | from tests.istanbul.eip152_blake2.common import Blake2bInput
|
35 | 36 | from tests.istanbul.eip152_blake2.spec import Spec as Blake2bSpec
|
@@ -494,40 +495,109 @@ def test_worst_precompile_only_data_input(
|
494 | 495 |
|
495 | 496 |
|
496 | 497 | @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") |
500 | 587 |
|
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, |
516 | 592 | )
|
517 | 593 |
|
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() |
526 | 595 |
|
527 | 596 | tx = Transaction(
|
528 |
| - to=code_address, |
| 597 | + to=pre.deploy_contract(code=code), |
529 | 598 | gas_limit=env.gas_limit,
|
530 | 599 | sender=pre.fund_eoa(),
|
| 600 | + input=calldata, |
531 | 601 | )
|
532 | 602 |
|
533 | 603 | state_test(
|
|
0 commit comments