ethereum.forks.bpo5.vm.instructions.arithmeticethereum.forks.amsterdam.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:
26
    <snip>
36
    # STACK
37
    x = pop(evm.stack)
38
    y = pop(evm.stack)
39
40
    # GAS
41
    charge_gas(evm, GasCosts.OPCODE_ADD)
42
43
    # OPERATION
44
    result = x.wrapping_add(y)
45
46
    push(evm.stack, result)
47
48
    # PROGRAM COUNTER
49
    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:
53
    <snip>
63
    # STACK
64
    x = pop(evm.stack)
65
    y = pop(evm.stack)
66
67
    # GAS
68
    charge_gas(evm, GasCosts.OPCODE_SUB)
69
70
    # OPERATION
71
    result = x.wrapping_sub(y)
72
73
    push(evm.stack, result)
74
75
    # PROGRAM COUNTER
76
    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:
80
    <snip>
90
    # STACK
91
    x = pop(evm.stack)
92
    y = pop(evm.stack)
93
94
    # GAS
95
    charge_gas(evm, GasCosts.OPCODE_MUL)
96
97
    # OPERATION
98
    result = x.wrapping_mul(y)
99
100
    push(evm.stack, result)
101
102
    # PROGRAM COUNTER
103
    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:
107
    <snip>
117
    # STACK
118
    dividend = pop(evm.stack)
119
    divisor = pop(evm.stack)
120
121
    # GAS
122
    charge_gas(evm, GasCosts.OPCODE_DIV)
123
124
    # OPERATION
125
    if divisor == 0:
126
        quotient = U256(0)
127
    else:
128
        quotient = dividend // divisor
129
130
    push(evm.stack, quotient)
131
132
    # PROGRAM COUNTER
133
    evm.pc += Uint(1)

U255_CEIL_VALUE

136
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:
140
    <snip>
150
    # STACK
151
    dividend = pop(evm.stack).to_signed()
152
    divisor = pop(evm.stack).to_signed()
153
154
    # GAS
155
    charge_gas(evm, GasCosts.OPCODE_SDIV)
156
157
    # OPERATION
158
    if divisor == 0:
159
        quotient = 0
160
    elif dividend == -U255_CEIL_VALUE and divisor == -1:
161
        quotient = -U255_CEIL_VALUE
162
    else:
163
        sign = get_sign(dividend * divisor)
164
        quotient = sign * (abs(dividend) // abs(divisor))
165
166
    push(evm.stack, U256.from_signed(quotient))
167
168
    # PROGRAM COUNTER
169
    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:
173
    <snip>
183
    # STACK
184
    x = pop(evm.stack)
185
    y = pop(evm.stack)
186
187
    # GAS
188
    charge_gas(evm, GasCosts.OPCODE_MOD)
189
190
    # OPERATION
191
    if y == 0:
192
        remainder = U256(0)
193
    else:
194
        remainder = x % y
195
196
    push(evm.stack, remainder)
197
198
    # PROGRAM COUNTER
199
    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:
203
    <snip>
213
    # STACK
214
    x = pop(evm.stack).to_signed()
215
    y = pop(evm.stack).to_signed()
216
217
    # GAS
218
    charge_gas(evm, GasCosts.OPCODE_SMOD)
219
220
    # OPERATION
221
    if y == 0:
222
        remainder = 0
223
    else:
224
        remainder = get_sign(x) * (abs(x) % abs(y))
225
226
    push(evm.stack, U256.from_signed(remainder))
227
228
    # PROGRAM COUNTER
229
    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:
233
    <snip>
243
    # STACK
244
    x = Uint(pop(evm.stack))
245
    y = Uint(pop(evm.stack))
246
    z = Uint(pop(evm.stack))
247
248
    # GAS
249
    charge_gas(evm, GasCosts.OPCODE_ADDMOD)
250
251
    # OPERATION
252
    if z == 0:
253
        result = U256(0)
254
    else:
255
        result = U256((x + y) % z)
256
257
    push(evm.stack, result)
258
259
    # PROGRAM COUNTER
260
    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:
264
    <snip>
274
    # STACK
275
    x = Uint(pop(evm.stack))
276
    y = Uint(pop(evm.stack))
277
    z = Uint(pop(evm.stack))
278
279
    # GAS
280
    charge_gas(evm, GasCosts.OPCODE_MULMOD)
281
282
    # OPERATION
283
    if z == 0:
284
        result = U256(0)
285
    else:
286
        result = U256((x * y) % z)
287
288
    push(evm.stack, result)
289
290
    # PROGRAM COUNTER
291
    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:
295
    <snip>
305
    # STACK
306
    base = Uint(pop(evm.stack))
307
    exponent = Uint(pop(evm.stack))
308
309
    # GAS
310
    # This is equivalent to 1 + floor(log(y, 256)). But in python the log
311
    # function is inaccurate leading to wrong results.
312
    exponent_bits = exponent.bit_length()
313
    exponent_bytes = (exponent_bits + Uint(7)) // Uint(8)
314
    charge_gas(
315
        evm,
315
        GasCosts.OPCODE_EXP_BASE
316
        + GasCosts.OPCODE_EXP_PER_BYTE * exponent_bytes,
316
        ExecutionGas(
317
            GasCosts.OPCODE_EXP_BASE
318
            + GasCosts.OPCODE_EXP_PER_BYTE * exponent_bytes
319
        ),
320
    )
321
322
    # OPERATION
323
    result = U256(pow(base, exponent, Uint(U256.MAX_VALUE) + Uint(1)))
324
325
    push(evm.stack, result)
326
327
    # PROGRAM COUNTER
328
    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:
332
    <snip>
342
    # STACK
343
    byte_num = pop(evm.stack)
344
    value = pop(evm.stack)
345
346
    # GAS
347
    charge_gas(evm, GasCosts.OPCODE_SIGNEXTEND)
348
349
    # OPERATION
350
    if byte_num > U256(31):
351
        # Can't extend any further
352
        result = value
353
    else:
354
        # U256(0).to_be_bytes() gives b'' instead of b'\x00'.
355
        value_bytes = Bytes(value.to_be_bytes32())
356
        # Now among the obtained value bytes, consider only
357
        # N `least significant bytes`, where N is `byte_num + 1`.
358
        value_bytes = value_bytes[31 - int(byte_num) :]
359
        sign_bit = value_bytes[0] >> 7
360
        if sign_bit == 0:
361
            result = U256.from_be_bytes(value_bytes)
362
        else:
363
            num_bytes_prepend = U256(32) - (byte_num + U256(1))
364
            result = U256.from_be_bytes(
365
                bytearray([0xFF] * num_bytes_prepend) + value_bytes
366
            )
367
368
    push(evm.stack, result)
369
370
    # PROGRAM COUNTER
371
    evm.pc += Uint(1)