ethereum.forks.paris.vm.instructions.arithmeticethereum.forks.shanghai.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:
25
    """
26
    Adds the top two elements of the stack together, and pushes the result back
27
    on the stack.
28
29
    Parameters
30
    ----------
31
    evm :
32
        The current EVM frame.
33
34
    """
35
    # STACK
36
    x = pop(evm.stack)
37
    y = pop(evm.stack)
38
39
    # GAS
40
    charge_gas(evm, GasCosts.OPCODE_ADD)
41
42
    # OPERATION
43
    result = x.wrapping_add(y)
44
45
    push(evm.stack, result)
46
47
    # PROGRAM COUNTER
48
    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:
52
    """
53
    Subtracts the top two elements of the stack, and pushes the result back
54
    on the stack.
55
56
    Parameters
57
    ----------
58
    evm :
59
        The current EVM frame.
60
61
    """
62
    # STACK
63
    x = pop(evm.stack)
64
    y = pop(evm.stack)
65
66
    # GAS
67
    charge_gas(evm, GasCosts.OPCODE_SUB)
68
69
    # OPERATION
70
    result = x.wrapping_sub(y)
71
72
    push(evm.stack, result)
73
74
    # PROGRAM COUNTER
75
    evm.pc += Uint(1)

mul

Multiplies 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:
79
    """
80
    Multiplies the top two elements of the stack, and pushes the result back
81
    on the stack.
82
83
    Parameters
84
    ----------
85
    evm :
86
        The current EVM frame.
87
88
    """
89
    # STACK
90
    x = pop(evm.stack)
91
    y = pop(evm.stack)
92
93
    # GAS
94
    charge_gas(evm, GasCosts.OPCODE_MUL)
95
96
    # OPERATION
97
    result = x.wrapping_mul(y)
98
99
    push(evm.stack, result)
100
101
    # PROGRAM COUNTER
102
    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:
106
    """
107
    Integer division of the top two elements of the stack. Pushes the result
108
    back on the stack.
109
110
    Parameters
111
    ----------
112
    evm :
113
        The current EVM frame.
114
115
    """
116
    # STACK
117
    dividend = pop(evm.stack)
118
    divisor = pop(evm.stack)
119
120
    # GAS
121
    charge_gas(evm, GasCosts.OPCODE_DIV)
122
123
    # OPERATION
124
    if divisor == 0:
125
        quotient = U256(0)
126
    else:
127
        quotient = dividend // divisor
128
129
    push(evm.stack, quotient)
130
131
    # PROGRAM COUNTER
132
    evm.pc += Uint(1)

U255_CEIL_VALUE

135
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:
139
    """
140
    Signed integer division of the top two elements of the stack. Pushes the
141
    result back on the stack.
142
143
    Parameters
144
    ----------
145
    evm :
146
        The current EVM frame.
147
148
    """
149
    # STACK
150
    dividend = pop(evm.stack).to_signed()
151
    divisor = pop(evm.stack).to_signed()
152
153
    # GAS
154
    charge_gas(evm, GasCosts.OPCODE_SDIV)
155
156
    # OPERATION
157
    if divisor == 0:
158
        quotient = 0
159
    elif dividend == -U255_CEIL_VALUE and divisor == -1:
160
        quotient = -U255_CEIL_VALUE
161
    else:
162
        sign = get_sign(dividend * divisor)
163
        quotient = sign * (abs(dividend) // abs(divisor))
164
165
    push(evm.stack, U256.from_signed(quotient))
166
167
    # PROGRAM COUNTER
168
    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:
172
    """
173
    Modulo remainder of the top two elements of the stack. Pushes the result
174
    back on the stack.
175
176
    Parameters
177
    ----------
178
    evm :
179
        The current EVM frame.
180
181
    """
182
    # STACK
183
    x = pop(evm.stack)
184
    y = pop(evm.stack)
185
186
    # GAS
187
    charge_gas(evm, GasCosts.OPCODE_MOD)
188
189
    # OPERATION
190
    if y == 0:
191
        remainder = U256(0)
192
    else:
193
        remainder = x % y
194
195
    push(evm.stack, remainder)
196
197
    # PROGRAM COUNTER
198
    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:
202
    """
203
    Signed modulo remainder of the top two elements of the stack. Pushes the
204
    result back on the stack.
205
206
    Parameters
207
    ----------
208
    evm :
209
        The current EVM frame.
210
211
    """
212
    # STACK
213
    x = pop(evm.stack).to_signed()
214
    y = pop(evm.stack).to_signed()
215
216
    # GAS
217
    charge_gas(evm, GasCosts.OPCODE_SMOD)
218
219
    # OPERATION
220
    if y == 0:
221
        remainder = 0
222
    else:
223
        remainder = get_sign(x) * (abs(x) % abs(y))
224
225
    push(evm.stack, U256.from_signed(remainder))
226
227
    # PROGRAM COUNTER
228
    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:
232
    """
233
    Modulo addition of the top 2 elements with the 3rd element. Pushes the
234
    result back on the stack.
235
236
    Parameters
237
    ----------
238
    evm :
239
        The current EVM frame.
240
241
    """
242
    # STACK
243
    x = Uint(pop(evm.stack))
244
    y = Uint(pop(evm.stack))
245
    z = Uint(pop(evm.stack))
246
247
    # GAS
248
    charge_gas(evm, GasCosts.OPCODE_ADDMOD)
249
250
    # OPERATION
251
    if z == 0:
252
        result = U256(0)
253
    else:
254
        result = U256((x + y) % z)
255
256
    push(evm.stack, result)
257
258
    # PROGRAM COUNTER
259
    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:
263
    """
264
    Modulo multiplication of the top 2 elements with the 3rd element. Pushes
265
    the result back on the stack.
266
267
    Parameters
268
    ----------
269
    evm :
270
        The current EVM frame.
271
272
    """
273
    # STACK
274
    x = Uint(pop(evm.stack))
275
    y = Uint(pop(evm.stack))
276
    z = Uint(pop(evm.stack))
277
278
    # GAS
279
    charge_gas(evm, GasCosts.OPCODE_MULMOD)
280
281
    # OPERATION
282
    if z == 0:
283
        result = U256(0)
284
    else:
285
        result = U256((x * y) % z)
286
287
    push(evm.stack, result)
288
289
    # PROGRAM COUNTER
290
    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:
294
    """
295
    Exponential operation of the top 2 elements. Pushes the result back on
296
    the stack.
297
298
    Parameters
299
    ----------
300
    evm :
301
        The current EVM frame.
302
303
    """
304
    # STACK
305
    base = Uint(pop(evm.stack))
306
    exponent = Uint(pop(evm.stack))
307
308
    # GAS
309
    # This is equivalent to 1 + floor(log(y, 256)). But in python the log
310
    # function is inaccurate leading to wrong results.
311
    exponent_bits = exponent.bit_length()
312
    exponent_bytes = (exponent_bits + Uint(7)) // Uint(8)
313
    charge_gas(
314
        evm,
315
        GasCosts.OPCODE_EXP_BASE
316
        + GasCosts.OPCODE_EXP_PER_BYTE * exponent_bytes,
317
    )
318
319
    # OPERATION
320
    result = U256(pow(base, exponent, Uint(U256.MAX_VALUE) + Uint(1)))
321
322
    push(evm.stack, result)
323
324
    # PROGRAM COUNTER
325
    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:
329
    """
330
    Sign extend operation. In other words, extend a signed number which
331
    fits in N bytes to 32 bytes.
332
333
    Parameters
334
    ----------
335
    evm :
336
        The current EVM frame.
337
338
    """
339
    # STACK
340
    byte_num = pop(evm.stack)
341
    value = pop(evm.stack)
342
343
    # GAS
344
    charge_gas(evm, GasCosts.OPCODE_SIGNEXTEND)
345
346
    # OPERATION
347
    if byte_num > U256(31):
348
        # Can't extend any further
349
        result = value
350
    else:
351
        # U256(0).to_be_bytes() gives b'' instead of b'\x00'.
352
        value_bytes = Bytes(value.to_be_bytes32())
353
        # Now among the obtained value bytes, consider only
354
        # N `least significant bytes`, where N is `byte_num + 1`.
355
        value_bytes = value_bytes[31 - int(byte_num) :]
356
        sign_bit = value_bytes[0] >> 7
357
        if sign_bit == 0:
358
            result = U256.from_be_bytes(value_bytes)
359
        else:
360
            num_bytes_prepend = U256(32) - (byte_num + U256(1))
361
            result = U256.from_be_bytes(
362
                bytearray([0xFF] * num_bytes_prepend) + value_bytes
363
            )
364
365
    push(evm.stack, result)
366
367
    # PROGRAM COUNTER
368
    evm.pc += Uint(1)