ethereum.london.vm.instructions.arithmetic
Ethereum Virtual Machine (EVM) Arithmetic Instructions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. contents:: Table of Contents :backlinks: none :local:
Introduction
Implementations of the EVM Arithmetic instructions.
add
Adds the top two elements of the stack together, and pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def add(evm: Evm) -> None:
31 | """ |
---|---|
32 | Adds the top two elements of the stack together, and pushes the result back |
33 | on the stack. |
34 |
|
35 | Parameters |
36 | ---------- |
37 | evm : |
38 | The current EVM frame. |
39 |
|
40 | """ |
41 | # STACK |
42 | x = pop(evm.stack) |
43 | y = pop(evm.stack) |
44 | |
45 | # GAS |
46 | charge_gas(evm, GAS_VERY_LOW) |
47 | |
48 | # OPERATION |
49 | result = x.wrapping_add(y) |
50 | |
51 | push(evm.stack, result) |
52 | |
53 | # PROGRAM COUNTER |
54 | evm.pc += 1 |
sub
Subtracts the top two elements of the stack, and pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def sub(evm: Evm) -> None:
58 | """ |
---|---|
59 | Subtracts the top two elements of the stack, and pushes the result back |
60 | on the stack. |
61 |
|
62 | Parameters |
63 | ---------- |
64 | evm : |
65 | The current EVM frame. |
66 |
|
67 | """ |
68 | # STACK |
69 | x = pop(evm.stack) |
70 | y = pop(evm.stack) |
71 | |
72 | # GAS |
73 | charge_gas(evm, GAS_VERY_LOW) |
74 | |
75 | # OPERATION |
76 | result = x.wrapping_sub(y) |
77 | |
78 | push(evm.stack, result) |
79 | |
80 | # PROGRAM COUNTER |
81 | evm.pc += 1 |
mul
Multiply the top two elements of the stack, and pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def mul(evm: Evm) -> None:
85 | """ |
---|---|
86 | Multiply the top two elements of the stack, and pushes the result back |
87 | on the stack. |
88 |
|
89 | Parameters |
90 | ---------- |
91 | evm : |
92 | The current EVM frame. |
93 |
|
94 | """ |
95 | # STACK |
96 | x = pop(evm.stack) |
97 | y = pop(evm.stack) |
98 | |
99 | # GAS |
100 | charge_gas(evm, GAS_LOW) |
101 | |
102 | # OPERATION |
103 | result = x.wrapping_mul(y) |
104 | |
105 | push(evm.stack, result) |
106 | |
107 | # PROGRAM COUNTER |
108 | evm.pc += 1 |
div
Integer division of the top two elements of the stack. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def div(evm: Evm) -> None:
112 | """ |
---|---|
113 | Integer division of the top two elements of the stack. Pushes the result |
114 | back on the stack. |
115 |
|
116 | Parameters |
117 | ---------- |
118 | evm : |
119 | The current EVM frame. |
120 |
|
121 | """ |
122 | # STACK |
123 | dividend = pop(evm.stack) |
124 | divisor = pop(evm.stack) |
125 | |
126 | # GAS |
127 | charge_gas(evm, GAS_LOW) |
128 | |
129 | # OPERATION |
130 | if divisor == 0: |
131 | quotient = U256(0) |
132 | else: |
133 | quotient = dividend // divisor |
134 | |
135 | push(evm.stack, quotient) |
136 | |
137 | # PROGRAM COUNTER |
138 | evm.pc += 1 |
sdiv
Signed integer division of the top two elements of the stack. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def sdiv(evm: Evm) -> None:
142 | """ |
---|---|
143 | Signed integer division of the top two elements of the stack. Pushes the |
144 | result back on the stack. |
145 |
|
146 | Parameters |
147 | ---------- |
148 | evm : |
149 | The current EVM frame. |
150 |
|
151 | """ |
152 | # STACK |
153 | dividend = pop(evm.stack).to_signed() |
154 | divisor = pop(evm.stack).to_signed() |
155 | |
156 | # GAS |
157 | charge_gas(evm, GAS_LOW) |
158 | |
159 | # OPERATION |
160 | if divisor == 0: |
161 | quotient = 0 |
162 | elif dividend == -U255_CEIL_VALUE and divisor == -1: |
163 | quotient = -U255_CEIL_VALUE |
164 | else: |
165 | sign = get_sign(dividend * divisor) |
166 | quotient = sign * (abs(dividend) // abs(divisor)) |
167 | |
168 | push(evm.stack, U256.from_signed(quotient)) |
169 | |
170 | # PROGRAM COUNTER |
171 | evm.pc += 1 |
mod
Modulo remainder of the top two elements of the stack. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def mod(evm: Evm) -> None:
175 | """ |
---|---|
176 | Modulo remainder of the top two elements of the stack. Pushes the result |
177 | back on the stack. |
178 |
|
179 | Parameters |
180 | ---------- |
181 | evm : |
182 | The current EVM frame. |
183 |
|
184 | """ |
185 | # STACK |
186 | x = pop(evm.stack) |
187 | y = pop(evm.stack) |
188 | |
189 | # GAS |
190 | charge_gas(evm, GAS_LOW) |
191 | |
192 | # OPERATION |
193 | if y == 0: |
194 | remainder = U256(0) |
195 | else: |
196 | remainder = x % y |
197 | |
198 | push(evm.stack, remainder) |
199 | |
200 | # PROGRAM COUNTER |
201 | evm.pc += 1 |
smod
Signed modulo remainder of the top two elements of the stack. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def smod(evm: Evm) -> None:
205 | """ |
---|---|
206 | Signed modulo remainder of the top two elements of the stack. Pushes the |
207 | result back on the stack. |
208 |
|
209 | Parameters |
210 | ---------- |
211 | evm : |
212 | The current EVM frame. |
213 |
|
214 | """ |
215 | # STACK |
216 | x = pop(evm.stack).to_signed() |
217 | y = pop(evm.stack).to_signed() |
218 | |
219 | # GAS |
220 | charge_gas(evm, GAS_LOW) |
221 | |
222 | # OPERATION |
223 | if y == 0: |
224 | remainder = 0 |
225 | else: |
226 | remainder = get_sign(x) * (abs(x) % abs(y)) |
227 | |
228 | push(evm.stack, U256.from_signed(remainder)) |
229 | |
230 | # PROGRAM COUNTER |
231 | evm.pc += 1 |
addmod
Modulo addition of the top 2 elements with the 3rd element. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def addmod(evm: Evm) -> None:
235 | """ |
---|---|
236 | Modulo addition of the top 2 elements with the 3rd element. Pushes the |
237 | result back on the stack. |
238 |
|
239 | Parameters |
240 | ---------- |
241 | evm : |
242 | The current EVM frame. |
243 |
|
244 | """ |
245 | # STACK |
246 | x = Uint(pop(evm.stack)) |
247 | y = Uint(pop(evm.stack)) |
248 | z = Uint(pop(evm.stack)) |
249 | |
250 | # GAS |
251 | charge_gas(evm, GAS_MID) |
252 | |
253 | # OPERATION |
254 | if z == 0: |
255 | result = U256(0) |
256 | else: |
257 | result = U256((x + y) % z) |
258 | |
259 | push(evm.stack, result) |
260 | |
261 | # PROGRAM COUNTER |
262 | evm.pc += 1 |
mulmod
Modulo multiplication of the top 2 elements with the 3rd element. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def mulmod(evm: Evm) -> None:
266 | """ |
---|---|
267 | Modulo multiplication of the top 2 elements with the 3rd element. Pushes |
268 | the result back on the stack. |
269 |
|
270 | Parameters |
271 | ---------- |
272 | evm : |
273 | The current EVM frame. |
274 |
|
275 | """ |
276 | # STACK |
277 | x = Uint(pop(evm.stack)) |
278 | y = Uint(pop(evm.stack)) |
279 | z = Uint(pop(evm.stack)) |
280 | |
281 | # GAS |
282 | charge_gas(evm, GAS_MID) |
283 | |
284 | # OPERATION |
285 | if z == 0: |
286 | result = U256(0) |
287 | else: |
288 | result = U256((x * y) % z) |
289 | |
290 | push(evm.stack, result) |
291 | |
292 | # PROGRAM COUNTER |
293 | evm.pc += 1 |
exp
Exponential operation of the top 2 elements. Pushes the result back on the stack.
Parameters
evm : The current EVM frame.
def exp(evm: Evm) -> None:
297 | """ |
---|---|
298 | Exponential operation of the top 2 elements. Pushes the result back on |
299 | the stack. |
300 |
|
301 | Parameters |
302 | ---------- |
303 | evm : |
304 | The current EVM frame. |
305 |
|
306 | """ |
307 | # STACK |
308 | base = Uint(pop(evm.stack)) |
309 | exponent = Uint(pop(evm.stack)) |
310 | |
311 | # GAS |
312 | # This is equivalent to 1 + floor(log(y, 256)). But in python the log |
313 | # function is inaccurate leading to wrong results. |
314 | exponent_bits = exponent.bit_length() |
315 | exponent_bytes = (exponent_bits + 7) // 8 |
316 | charge_gas( |
317 | evm, GAS_EXPONENTIATION + GAS_EXPONENTIATION_PER_BYTE * exponent_bytes |
318 | ) |
319 | |
320 | # OPERATION |
321 | result = U256(pow(base, exponent, U256_CEIL_VALUE)) |
322 | |
323 | push(evm.stack, result) |
324 | |
325 | # PROGRAM COUNTER |
326 | evm.pc += 1 |
signextend
Sign extend operation. In other words, extend a signed number which fits in N bytes to 32 bytes.
Parameters
evm : The current EVM frame.
def signextend(evm: Evm) -> None:
330 | """ |
---|---|
331 | Sign extend operation. In other words, extend a signed number which |
332 | fits in N bytes to 32 bytes. |
333 |
|
334 | Parameters |
335 | ---------- |
336 | evm : |
337 | The current EVM frame. |
338 |
|
339 | """ |
340 | # STACK |
341 | byte_num = pop(evm.stack) |
342 | value = pop(evm.stack) |
343 | |
344 | # GAS |
345 | charge_gas(evm, GAS_LOW) |
346 | |
347 | # OPERATION |
348 | if byte_num > 31: |
349 | # Can't extend any further |
350 | result = value |
351 | else: |
352 | # U256(0).to_be_bytes() gives b'' instead b'\x00'. |
353 | value_bytes = bytes(value.to_be_bytes32()) |
354 | # Now among the obtained value bytes, consider only |
355 | # N `least significant bytes`, where N is `byte_num + 1`. |
356 | value_bytes = value_bytes[31 - int(byte_num) :] |
357 | sign_bit = value_bytes[0] >> 7 |
358 | if sign_bit == 0: |
359 | result = U256.from_be_bytes(value_bytes) |
360 | else: |
361 | num_bytes_prepend = 32 - (byte_num + 1) |
362 | result = U256.from_be_bytes( |
363 | bytearray([0xFF] * num_bytes_prepend) + value_bytes |
364 | ) |
365 | |
366 | push(evm.stack, result) |
367 | |
368 | # PROGRAM COUNTER |
369 | evm.pc += 1 |