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