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)