Ethereum Virtual Machine (EVM) Arithmetic Instructions
Table of Contents
Introduction
Implementations of the EVM Arithmetic instructions.
Module Contents
Functions
Adds the top two elements of the stack together, and pushes the result back |
|
Subtracts the top two elements of the stack, and pushes the result back |
|
Multiply the top two elements of the stack, and pushes the result back |
|
Integer division of the top two elements of the stack. Pushes the result |
|
Signed integer division of the top two elements of the stack. Pushes the |
|
Modulo remainder of the top two elements of the stack. Pushes the result |
|
Signed modulo remainder of the top two elements of the stack. Pushes the |
|
Modulo addition of the top 2 elements with the 3rd element. Pushes the |
|
Modulo multiplication of the top 2 elements with the 3rd element. Pushes |
|
Exponential operation of the top 2 elements. Pushes the result back on |
|
Sign extend operation. In other words, extend a signed number which |
Module Details
add
- add(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = pop(evm.stack)
y = pop(evm.stack)
# GAS
charge_gas(evm, GAS_VERY_LOW)
# OPERATION
result = x.wrapping_add(y)
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1
sub
- sub(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = pop(evm.stack)
y = pop(evm.stack)
# GAS
charge_gas(evm, GAS_VERY_LOW)
# OPERATION
result = x.wrapping_sub(y)
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1
mul
- mul(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = pop(evm.stack)
y = pop(evm.stack)
# GAS
charge_gas(evm, GAS_LOW)
# OPERATION
result = x.wrapping_mul(y)
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1
div
- div(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
dividend = pop(evm.stack)
divisor = pop(evm.stack)
# GAS
charge_gas(evm, GAS_LOW)
# OPERATION
if divisor == 0:
quotient = U256(0)
else:
quotient = dividend // divisor
push(evm.stack, quotient)
# PROGRAM COUNTER
evm.pc += 1
sdiv
- sdiv(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
dividend = pop(evm.stack).to_signed()
divisor = pop(evm.stack).to_signed()
# GAS
charge_gas(evm, GAS_LOW)
# OPERATION
if divisor == 0:
quotient = 0
elif dividend == -U255_CEIL_VALUE and divisor == -1:
quotient = -U255_CEIL_VALUE
else:
sign = get_sign(dividend * divisor)
quotient = sign * (abs(dividend) // abs(divisor))
push(evm.stack, U256.from_signed(quotient))
# PROGRAM COUNTER
evm.pc += 1
mod
- mod(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = pop(evm.stack)
y = pop(evm.stack)
# GAS
charge_gas(evm, GAS_LOW)
# OPERATION
if y == 0:
remainder = U256(0)
else:
remainder = x % y
push(evm.stack, remainder)
# PROGRAM COUNTER
evm.pc += 1
smod
- smod(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = pop(evm.stack).to_signed()
y = pop(evm.stack).to_signed()
# GAS
charge_gas(evm, GAS_LOW)
# OPERATION
if y == 0:
remainder = 0
else:
remainder = get_sign(x) * (abs(x) % abs(y))
push(evm.stack, U256.from_signed(remainder))
# PROGRAM COUNTER
evm.pc += 1
addmod
- addmod(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = Uint(pop(evm.stack))
y = Uint(pop(evm.stack))
z = Uint(pop(evm.stack))
# GAS
charge_gas(evm, GAS_MID)
# OPERATION
if z == 0:
result = U256(0)
else:
result = U256((x + y) % z)
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1
mulmod
- mulmod(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
x = Uint(pop(evm.stack))
y = Uint(pop(evm.stack))
z = Uint(pop(evm.stack))
# GAS
charge_gas(evm, GAS_MID)
# OPERATION
if z == 0:
result = U256(0)
else:
result = U256((x * y) % z)
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1
exp
- exp(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
base = Uint(pop(evm.stack))
exponent = Uint(pop(evm.stack))
# GAS
# This is equivalent to 1 + floor(log(y, 256)). But in python the log
# function is inaccurate leading to wrong results.
exponent_bits = exponent.bit_length()
exponent_bytes = (exponent_bits + 7) // 8
charge_gas(
evm, GAS_EXPONENTIATION + GAS_EXPONENTIATION_PER_BYTE * exponent_bytes
)
# OPERATION
result = U256(pow(base, exponent, U256_CEIL_VALUE))
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1
signextend
- signextend(evm: ethereum.paris.vm.Evm) → None
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:
# STACK
byte_num = pop(evm.stack)
value = pop(evm.stack)
# GAS
charge_gas(evm, GAS_LOW)
# OPERATION
if byte_num > 31:
# Can't extend any further
result = value
else:
# U256(0).to_be_bytes() gives b'' instead b'\x00'.
value_bytes = bytes(value.to_be_bytes32())
# Now among the obtained value bytes, consider only
# N `least significant bytes`, where N is `byte_num + 1`.
value_bytes = value_bytes[31 - int(byte_num) :]
sign_bit = value_bytes[0] >> 7
if sign_bit == 0:
result = U256.from_be_bytes(value_bytes)
else:
num_bytes_prepend = 32 - (byte_num + 1)
result = U256.from_be_bytes(
bytearray([0xFF] * num_bytes_prepend) + value_bytes
)
push(evm.stack, result)
# PROGRAM COUNTER
evm.pc += 1