26
26
vectors_from_file ("vectors.json" ),
27
27
ids = lambda v : v .name ,
28
28
)
29
- def test_vectors_from_file (
29
+ def test_vectors_from_eip (
30
30
state_test : StateTestFiller ,
31
31
pre : Alloc ,
32
32
tx : Transaction ,
@@ -99,47 +99,48 @@ def test_modexp_invalid_inputs(
99
99
)
100
100
101
101
102
- def create_boundary_modexp_case (
103
- base : str = "FF" , exponent : str = "FF" , modulus : str = "FF" , case_id : str = ""
104
- ):
105
- """
106
- Create a single boundary ModExp test case.
107
-
108
- Args:
109
- base: Base data (hex string)
110
- exponent: Exponent data (hex string)
111
- modulus: Modulus data (hex string)
112
- case_id: Test case identifier
113
-
114
- Returns:
115
- pytest.param for the test case
116
-
117
- """
118
- modexp_input = ModExpInput (
119
- base = base ,
120
- exponent = exponent ,
121
- modulus = modulus ,
122
- )
123
- return pytest .param (modexp_input , Spec .modexp_error , False , id = case_id )
124
-
125
-
126
102
@pytest .mark .parametrize (
127
103
"modexp_input,modexp_expected,call_succeeds" ,
128
104
[
129
- create_boundary_modexp_case (
130
- base = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ), case_id = "base-too-long"
105
+ pytest .param (
106
+ ModExpInput (
107
+ base = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
108
+ exponent = "FF" ,
109
+ modulus = "FF" ,
110
+ ),
111
+ Spec .modexp_error ,
112
+ False ,
113
+ id = "base-too-long" ,
131
114
),
132
- create_boundary_modexp_case (
133
- exponent = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ), case_id = "exponent-too-long"
115
+ pytest .param (
116
+ ModExpInput (
117
+ base = "FF" ,
118
+ exponent = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
119
+ modulus = "FF" ,
120
+ ),
121
+ Spec .modexp_error ,
122
+ False ,
123
+ id = "exponent-too-long" ,
134
124
),
135
- create_boundary_modexp_case (
136
- modulus = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ), case_id = "modulus-too-long"
125
+ pytest .param (
126
+ ModExpInput (
127
+ base = "FF" ,
128
+ exponent = "FF" ,
129
+ modulus = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
130
+ ),
131
+ Spec .modexp_error ,
132
+ False ,
133
+ id = "modulus-too-long" ,
137
134
),
138
- create_boundary_modexp_case (
139
- base = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
140
- exponent = "FF" ,
141
- modulus = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
142
- case_id = "base-modulus-too-long" ,
135
+ pytest .param (
136
+ ModExpInput (
137
+ base = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
138
+ exponent = "FF" ,
139
+ modulus = "FF" * (Spec .MAX_LENGTH_BYTES + 1 ),
140
+ ),
141
+ Spec .modexp_error ,
142
+ False ,
143
+ id = "base-modulus-too-long" ,
143
144
),
144
145
],
145
146
)
@@ -219,13 +220,13 @@ def test_modexp_call_operations(
219
220
@EIPChecklist .Precompile .Test .ValueTransfer .Fee .Over
220
221
@EIPChecklist .Precompile .Test .ValueTransfer .Fee .Exact
221
222
@EIPChecklist .Precompile .Test .ValueTransfer .Fee .Under
222
- def test_modexp_gas_usage (
223
+ def test_modexp_gas_usage_contract_wrapper (
223
224
state_test : StateTestFiller ,
224
225
pre : Alloc ,
225
226
tx : Transaction ,
226
227
post : Dict ,
227
228
):
228
- """Test ModExp gas cost with different precompile gas modifiers."""
229
+ """Test ModExp gas cost with different gas modifiers using contract wrapper calls ."""
229
230
state_test (pre = pre , tx = tx , post = post )
230
231
231
232
@@ -255,14 +256,14 @@ def test_modexp_gas_usage(
255
256
),
256
257
],
257
258
)
258
- def test_modexp_entry_points (
259
+ def test_modexp_used_in_transaction_entry_points (
259
260
state_test : StateTestFiller ,
260
261
pre : Alloc ,
261
262
tx : Transaction ,
262
263
modexp_input : bytes ,
263
264
tx_gas_limit : int ,
264
265
):
265
- """Test ModExp entry points with different precompile gas modifiers."""
266
+ """Test ModExp using in transaction entry points with different precompile gas modifiers."""
266
267
tx = Transaction (
267
268
to = Spec .MODEXP_ADDRESS ,
268
269
sender = pre .fund_eoa (),
@@ -296,6 +297,34 @@ def create_modexp_variable_gas_test_cases():
296
297
("01" * 40 , "00" * 39 + "01" , "02" * 40 , "01" * 40 , "L3" ),
297
298
("01" * 48 , "01" , "02" * 16 , "01" * 16 , "L4" ),
298
299
("01" * 16 , "00" * 40 , "02" * 48 , "00" * 47 + "01" , "L5" ),
300
+ # Critical 32-byte boundary cases
301
+ ("01" * 31 , "01" , "02" * 33 , "00" * 2 + "01" * 31 , "B1" ),
302
+ ("01" * 33 , "01" , "02" * 31 , "00" * 29 + "01" * 2 , "B2" ),
303
+ ("01" * 33 , "01" , "02" * 33 , "01" * 33 , "B4" ),
304
+ # Zero value edge cases
305
+ ("00" * 32 , "00" * 32 , "01" * 32 , "00" * 31 + "01" , "Z1" ),
306
+ ("01" * 32 , "00" * 32 , "00" * 32 , "00" * 32 , "Z2" ),
307
+ ("00" * 32 , "01" * 32 , "02" * 32 , "00" * 32 , "Z3" ),
308
+ # Maximum value stress tests
309
+ ("FF" * 64 , "FF" * 64 , "FF" * 64 , "00" * 64 , "M1" ),
310
+ ("FF" * 32 , "01" , "FF" * 32 , "00" * 32 , "M2" ),
311
+ ("01" , "FF" * 64 , "FF" * 64 , "00" * 63 + "01" , "M3" ),
312
+ # Tiny maximum values
313
+ ("FF" , "FE" , "FD" , "47" , "T2" ),
314
+ # Bit pattern cases
315
+ ("01" * 32 , "80" * 32 , "02" * 32 , "01" * 32 , "P2" ),
316
+ ("01" * 33 , "00" * 31 + "80" + "00" , "02" * 33 , "01" * 33 , "P3" ),
317
+ # Asymmetric length cases
318
+ ("01" , "00" * 64 , "02" * 64 , "00" * 63 + "01" , "A1" ),
319
+ ("01" * 64 , "01" , "02" , "01" , "A2" ),
320
+ ("01" * 64 , "00" * 64 , "02" , "01" , "A3" ),
321
+ # Word boundary case
322
+ ("01" * 8 , "01" , "02" * 8 , "0101010101010101" , "W2" ),
323
+ # Exponent edge cases
324
+ ("01" * 16 , "00" * 32 + "01" , "02" * 16 , "01" * 16 , "E1" ),
325
+ ("01" * 16 , "80" + "00" * 31 , "02" * 16 , "01" * 16 , "E2" ),
326
+ ("01" * 16 , "00" * 31 + "80" , "02" * 16 , "01" * 16 , "E3" ),
327
+ ("01" * 16 , "7F" + "FF" * 31 , "02" * 16 , "01" * 16 , "E4" ),
299
328
]
300
329
301
330
# Gas calculation parameters:
@@ -318,25 +347,44 @@ def create_modexp_variable_gas_test_cases():
318
347
# - Clamp: True if raw gas < 500 (clamped to 500), False if raw gas ≥ 500 (no clamping)
319
348
320
349
# Test case coverage table:
321
- # ┌─────┬──────┬─────┬──────┬───────┬─────────┬─────────────────────────────────────────────┐
322
- # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description │
323
- # ├─────┼──────┼─────┼──────┼───────┼─────────┼─────────────────────────────────────────────┤
324
- # │ Z0 │ - │ - │ - │ - │ 500 │ Zero case - empty inputs │
325
- # │ S0 │ S │ = │ A │ True │ 500 │ Small, equal, zero exponent, clamped │
326
- # │ S1 │ S │ = │ B │ True │ 500 │ Small, equal, small exp, clamped │
327
- # │ S2 │ S │ = │ B │ False │ 4080 │ Small, equal, large exp, unclamped │
328
- # │ S3 │ S │ = │ C │ False │ 2032 │ Small, equal, large exp+zero low256 │
329
- # │ S4 │ S │ = │ D │ False │ 2048 │ Small, equal, large exp+non-zero low256 │
330
- # │ S5 │ S │ > │ A │ True │ 500 │ Small, base>mod, zero exp, clamped │
331
- # │ S6 │ S │ < │ B │ True │ 500 │ Small, base<mod, small exp, clamped │
332
- # │ L0 │ L │ = │ A │ True │ 500 │ Large, equal, zero exp, clamped │
333
- # │ L1 │ L │ = │ B │ False │ 12750 │ Large, equal, large exp, unclamped │
334
- # │ L2 │ L │ = │ C │ False │ 6350 │ Large, equal, large exp+zero low256 │
335
- # │ L3 │ L │ = │ D │ False │ 6400 │ Large, equal, large exp+non-zero low256 │
336
- # │ L4 │ L │ > │ B │ True │ 500 │ Large, base>mod, small exp, clamped │
337
- # │ L5 │ L │ < │ C │ False │ 9144 │ Large, base<mod, large exp+zero low256 │
338
- # └─────┴──────┴─────┴──────┴───────┴─────────┴─────────────────────────────────────────────┘
339
-
350
+ # ┌─────┬──────┬─────┬──────┬───────┬─────────┬───────────────────────────────────────────────┐
351
+ # │ ID │ Comp │ Rel │ Iter │ Clamp │ Gas │ Description │
352
+ # ├─────┼──────┼─────┼──────┼───────┼─────────┼───────────────────────────────────────────────┤
353
+ # │ Z0 │ - │ - │ - │ - │ 500 │ Zero case – empty inputs │
354
+ # │ S0 │ S │ = │ A │ True │ 500 │ Small, equal, zero exp, clamped │
355
+ # │ S1 │ S │ = │ B │ True │ 500 │ Small, equal, small exp, clamped │
356
+ # │ S2 │ S │ = │ B │ False │ 4080 │ Small, equal, large exp, unclamped │
357
+ # │ S3 │ S │ = │ C │ False │ 2032 │ Small, equal, large exp + zero low256 │
358
+ # │ S4 │ S │ = │ D │ False │ 2048 │ Small, equal, large exp + non-zero low256 │
359
+ # │ S5 │ S │ > │ A │ True │ 500 │ Small, base > mod, zero exp, clamped │
360
+ # │ S6 │ S │ < │ B │ True │ 500 │ Small, base < mod, small exp, clamped │
361
+ # │ L0 │ L │ = │ A │ True │ 500 │ Large, equal, zero exp, clamped │
362
+ # │ L1 │ L │ = │ B │ False │ 12750 │ Large, equal, large exp, unclamped │
363
+ # │ L2 │ L │ = │ C │ False │ 6350 │ Large, equal, large exp + zero low256 │
364
+ # │ L3 │ L │ = │ D │ False │ 6400 │ Large, equal, large exp + non-zero low256 │
365
+ # │ L4 │ L │ > │ B │ True │ 500 │ Large, base > mod, small exp, clamped │
366
+ # │ L5 │ L │ < │ C │ False │ 9144 │ Large, base < mod, large exp + zero low256 │
367
+ # │ B1 │ L │ < │ B │ True │ 500 │ Cross 32-byte boundary (31/33) │
368
+ # │ B2 │ L │ > │ B │ True │ 500 │ Cross 32-byte boundary (33/31) │
369
+ # │ B4 │ L │ = │ B │ True │ 500 │ Just over 32-byte boundary │
370
+ # │ Z1 │ S │ = │ A │ True │ 500 │ All zeros except modulus │
371
+ # │ Z2 │ S │ = │ A │ True │ 500 │ Zero modulus special case │
372
+ # │ Z3 │ S │ = │ B │ False │ 3968 │ Zero base, large exponent │
373
+ # │ M1 │ L │ = │ D │ False │ 98176 │ Maximum values stress test │
374
+ # │ M2 │ S │ = │ B │ True │ 500 │ Max base/mod, small exponent │
375
+ # │ M3 │ L │ < │ D │ False │ 98176 │ Small base, max exponent/mod │
376
+ # │ T2 │ S │ = │ B │ True │ 500 │ Tiny maximum values │
377
+ # │ P2 │ S │ = │ B │ False │ 4080 │ High bit in exponent │
378
+ # │ P3 │ L │ = │ D │ False │ 1550 │ Specific bit pattern in large exponent │
379
+ # │ A1 │ L │ < │ C │ False │ 65408 │ Asymmetric: tiny base, large exp/mod │
380
+ # │ A2 │ L │ > │ B │ True │ 500 │ Asymmetric: large base, tiny exp/mod │
381
+ # │ A3 │ L │ > │ C │ False │ 65408 │ Asymmetric: large base/exp, tiny modulus │
382
+ # │ W2 │ S │ = │ B │ True │ 500 │ Exactly 8-byte words │
383
+ # │ E1 │ S │ = │ D │ True │ 500 │ Exponent exactly 33 bytes │
384
+ # │ E2 │ S │ = │ B │ False │ 4080 │ High bit in exponent first byte │
385
+ # │ E3 │ S │ = │ B │ True │ 500 │ High bit in exponent last byte │
386
+ # │ E4 │ S │ = │ B │ False │ 4064 │ Maximum 32-byte exponent │
387
+ # └─────┴──────┴─────┴──────┴───────┴─────────┴───────────────────────────────────────────────┘
340
388
for base , exponent , modulus , expected_result , test_id in test_cases :
341
389
yield pytest .param (
342
390
ModExpInput (base = base , exponent = exponent , modulus = modulus ),
0 commit comments