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