ethereum.paris.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