@@ -103,3 +103,70 @@ def test_worst_keccak(
103
103
post = {},
104
104
blocks = [Block (txs = [tx ])],
105
105
)
106
+
107
+
108
+ @pytest .mark .zkevm
109
+ @pytest .mark .valid_from ("Cancun" )
110
+ @pytest .mark .parametrize (
111
+ "gas_limit" ,
112
+ [
113
+ Environment ().gas_limit ,
114
+ ],
115
+ )
116
+ def test_worst_modexp (
117
+ blockchain_test : BlockchainTestFiller ,
118
+ pre : Alloc ,
119
+ fork : Fork ,
120
+ gas_limit : int ,
121
+ ):
122
+ """Test running a block with as many MODEXP calls as possible."""
123
+ env = Environment (gas_limit = gas_limit )
124
+
125
+ base_mod_length = 32
126
+ exp_length = 32
127
+
128
+ base = 2 ** (8 * base_mod_length ) - 1
129
+ mod = 2 ** (8 * base_mod_length ) - 2 # Prevents base == mod
130
+ exp = 2 ** (8 * exp_length ) - 1
131
+
132
+ # MODEXP calldata
133
+ calldata = (
134
+ Op .MSTORE (0 * 32 , base_mod_length )
135
+ + Op .MSTORE (1 * 32 , exp_length )
136
+ + Op .MSTORE (2 * 32 , base_mod_length )
137
+ + Op .MSTORE (3 * 32 , base )
138
+ + Op .MSTORE (4 * 32 , exp )
139
+ + Op .MSTORE (5 * 32 , mod )
140
+ )
141
+
142
+ # EIP-2565
143
+ mul_complexity = math .ceil (base_mod_length / 8 ) ** 2
144
+ iter_complexity = exp .bit_length () - 1
145
+ gas_cost = math .floor ((mul_complexity * iter_complexity ) / 3 )
146
+ attack_block = Op .POP (Op .STATICCALL (gas_cost , 0x5 , 0 , 32 * 6 , 0 , 0 ))
147
+
148
+ # The attack contract is: JUMPDEST + [attack_block]* + PUSH0 + JUMP
149
+ jumpdest = Op .JUMPDEST
150
+ jump_back = Op .JUMP (len (calldata ))
151
+ max_iters_loop = (MAX_CODE_SIZE - len (calldata ) - len (jumpdest ) - len (jump_back )) // len (
152
+ attack_block
153
+ )
154
+ code = calldata + jumpdest + sum ([attack_block ] * max_iters_loop ) + jump_back
155
+ if len (code ) > MAX_CODE_SIZE :
156
+ # Must never happen, but keep it as a sanity check.
157
+ raise ValueError (f"Code size { len (code )} exceeds maximum code size { MAX_CODE_SIZE } " )
158
+
159
+ code_address = pre .deploy_contract (code = code )
160
+
161
+ tx = Transaction (
162
+ to = code_address ,
163
+ gas_limit = gas_limit ,
164
+ sender = pre .fund_eoa (),
165
+ )
166
+
167
+ blockchain_test (
168
+ env = env ,
169
+ pre = pre ,
170
+ post = {},
171
+ blocks = [Block (txs = [tx ])],
172
+ )
0 commit comments