ethereum.forks.osaka.vm.precompiled_contracts.modexp

Ethereum Virtual Machine (EVM) MODEXP PRECOMPILED CONTRACT.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementation of the MODEXP precompiled contract.

modexp

Calculates (base**exp) % modulus for arbitrary sized base, exp and. modulus. The return value is the same length as the modulus.

def modexp(evm: Evm) -> None:
24
    """
25
    Calculates `(base**exp) % modulus` for arbitrary sized `base`, `exp` and.
26
    `modulus`. The return value is the same length as the modulus.
27
    """
28
    data = evm.message.data
29
30
    # GAS
31
    base_length = U256.from_be_bytes(buffer_read(data, U256(0), U256(32)))
32
    if base_length > U256(1024):
33
        raise ExceptionalHalt("Mod-exp base length is too large")
34
35
    exp_length = U256.from_be_bytes(buffer_read(data, U256(32), U256(32)))
36
    if exp_length > U256(1024):
37
        raise ExceptionalHalt("Mod-exp exponent length is too large")
38
39
    modulus_length = U256.from_be_bytes(buffer_read(data, U256(64), U256(32)))
40
    if modulus_length > U256(1024):
41
        raise ExceptionalHalt("Mod-exp modulus length is too large")
42
43
    exp_start = U256(96) + base_length
44
45
    exp_head = U256.from_be_bytes(
46
        buffer_read(data, exp_start, min(U256(32), exp_length))
47
    )
48
49
    charge_gas(
50
        evm,
51
        gas_cost(base_length, modulus_length, exp_length, exp_head),
52
    )
53
54
    # OPERATION
55
    if base_length == 0 and modulus_length == 0:
56
        evm.output = Bytes()
57
        return
58
59
    base = Uint.from_be_bytes(buffer_read(data, U256(96), base_length))
60
    exp = Uint.from_be_bytes(buffer_read(data, exp_start, exp_length))
61
62
    modulus_start = exp_start + exp_length
63
    modulus = Uint.from_be_bytes(
64
        buffer_read(data, modulus_start, modulus_length)
65
    )
66
67
    if modulus == 0:
68
        evm.output = Bytes(b"\x00") * modulus_length
69
    else:
70
        evm.output = pow(base, exp, modulus).to_bytes(
71
            Uint(modulus_length), "big"
72
        )

complexity

Estimate the complexity of performing a modular exponentiation.

Parameters

base_length : Length of the array representing the base integer.

modulus_length : Length of the array representing the modulus integer.

Returns

complexity : Uint Complexity of performing the operation.

def complexity(base_length: U256, ​​modulus_length: U256) -> Uint:
76
    """
77
    Estimate the complexity of performing a modular exponentiation.
78
79
    Parameters
80
    ----------
81
    base_length :
82
        Length of the array representing the base integer.
83
84
    modulus_length :
85
        Length of the array representing the modulus integer.
86
87
    Returns
88
    -------
89
    complexity : `Uint`
90
        Complexity of performing the operation.
91
92
    """
93
    max_length = max(Uint(base_length), Uint(modulus_length))
94
    words = (max_length + Uint(7)) // Uint(8)
95
    complexity = Uint(16)
96
    if max_length > Uint(32):
97
        complexity = Uint(2) * words ** Uint(2)
98
    return complexity

iterations

Calculate the number of iterations required to perform a modular exponentiation.

Parameters

exponent_length : Length of the array representing the exponent integer.

exponent_head : First 32 bytes of the exponent (with leading zero padding if it is shorter than 32 bytes), as a U256.

Returns

iterations : Uint Number of iterations.

def iterations(exponent_length: U256, ​​exponent_head: U256) -> Uint:
102
    """
103
    Calculate the number of iterations required to perform a modular
104
    exponentiation.
105
106
    Parameters
107
    ----------
108
    exponent_length :
109
        Length of the array representing the exponent integer.
110
111
    exponent_head :
112
        First 32 bytes of the exponent (with leading zero padding if it is
113
        shorter than 32 bytes), as a U256.
114
115
    Returns
116
    -------
117
    iterations : `Uint`
118
        Number of iterations.
119
120
    """
121
    if exponent_length <= U256(32) and exponent_head == U256(0):
122
        count = Uint(0)
123
    elif exponent_length <= U256(32):
124
        bit_length = exponent_head.bit_length()
125
126
        if bit_length > Uint(0):
127
            bit_length -= Uint(1)
128
129
        count = bit_length
130
    else:
131
        length_part = Uint(16) * (Uint(exponent_length) - Uint(32))
132
        bits_part = exponent_head.bit_length()
133
134
        if bits_part > Uint(0):
135
            bits_part -= Uint(1)
136
137
        count = length_part + bits_part
138
139
    return max(count, Uint(1))

gas_cost

Calculate the gas cost of performing a modular exponentiation.

Parameters

base_length : Length of the array representing the base integer.

modulus_length : Length of the array representing the modulus integer.

exponent_length : Length of the array representing the exponent integer.

exponent_head : First 32 bytes of the exponent (with leading zero padding if it is shorter than 32 bytes), as a U256.

Returns

gas_cost : Uint Gas required for performing the operation.

def gas_cost(base_length: U256, ​​modulus_length: U256, ​​exponent_length: U256, ​​exponent_head: U256) -> Uint:
148
    """
149
    Calculate the gas cost of performing a modular exponentiation.
150
151
    Parameters
152
    ----------
153
    base_length :
154
        Length of the array representing the base integer.
155
156
    modulus_length :
157
        Length of the array representing the modulus integer.
158
159
    exponent_length :
160
        Length of the array representing the exponent integer.
161
162
    exponent_head :
163
        First 32 bytes of the exponent (with leading zero padding if it is
164
        shorter than 32 bytes), as a U256.
165
166
    Returns
167
    -------
168
    gas_cost : `Uint`
169
        Gas required for performing the operation.
170
171
    """
172
    multiplication_complexity = complexity(base_length, modulus_length)
173
    iteration_count = iterations(exponent_length, exponent_head)
174
    cost = multiplication_complexity * iteration_count
175
    return max(Uint(500), cost)