Ethereum Virtual Machine (EVM) Arithmetic Instructions

Introduction

Implementations of the EVM Arithmetic instructions.

Module Contents

Functions

add

Adds the top two elements of the stack together, and pushes the result back

sub

Subtracts the top two elements of the stack, and pushes the result back

mul

Multiply the top two elements of the stack, and pushes the result back

div

Integer division of the top two elements of the stack. Pushes the result

sdiv

Signed integer division of the top two elements of the stack. Pushes the

mod

Modulo remainder of the top two elements of the stack. Pushes the result

smod

Signed modulo remainder of the top two elements of the stack. Pushes the

addmod

Modulo addition of the top 2 elements with the 3rd element. Pushes the

mulmod

Modulo multiplication of the top 2 elements with the 3rd element. Pushes

exp

Exponential operation of the top 2 elements. Pushes the result back on

signextend

Sign extend operation. In other words, extend a signed number which

Module Details

add

add(evm: ethereum.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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.dao_fork.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