ethereum.forks.constantinople.vm.precompiled_contracts.modexpethereum.forks.istanbul.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.

GQUADDIVISOR

21
GQUADDIVISOR = Uint(20)

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

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:
69
    """
70
    Estimate the complexity of performing a modular exponentiation.
71
72
    Parameters
73
    ----------
74
    base_length :
75
        Length of the array representing the base integer.
76
77
    modulus_length :
78
        Length of the array representing the modulus integer.
79
80
    Returns
81
    -------
82
    complexity : `Uint`
83
        Complexity of performing the operation.
84
85
    """
86
    max_length = max(Uint(base_length), Uint(modulus_length))
87
    if max_length <= Uint(64):
88
        return max_length ** Uint(2)
89
    elif max_length <= Uint(1024):
90
        return (
91
            max_length ** Uint(2) // Uint(4)
92
            + Uint(96) * max_length
93
            - Uint(3072)
94
        )
95
    else:
96
        return (
97
            max_length ** Uint(2) // Uint(16)
98
            + Uint(480) * max_length
99
            - Uint(199680)
100
        )

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:
104
    """
105
    Calculate the number of iterations required to perform a modular
106
    exponentiation.
107
108
    Parameters
109
    ----------
110
    exponent_length :
111
        Length of the array representing the exponent integer.
112
113
    exponent_head :
114
        First 32 bytes of the exponent (with leading zero padding if it is
115
        shorter than 32 bytes), as a U256.
116
117
    Returns
118
    -------
119
    iterations : `Uint`
120
        Number of iterations.
121
122
    """
123
    if exponent_length < U256(32):
124
        adjusted_exp_length = Uint(max(0, int(exponent_head.bit_length()) - 1))
125
    else:
126
        adjusted_exp_length = Uint(
127
            8 * (int(exponent_length) - 32)
128
            + max(0, int(exponent_head.bit_length()) - 1)
129
        )
130
131
    return max(adjusted_exp_length, 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:
140
    """
141
    Calculate the gas cost of performing a modular exponentiation.
142
143
    Parameters
144
    ----------
145
    base_length :
146
        Length of the array representing the base integer.
147
148
    modulus_length :
149
        Length of the array representing the modulus integer.
150
151
    exponent_length :
152
        Length of the array representing the exponent integer.
153
154
    exponent_head :
155
        First 32 bytes of the exponent (with leading zero padding if it is
156
        shorter than 32 bytes), as a U256.
157
158
    Returns
159
    -------
160
    gas_cost : `Uint`
161
        Gas required for performing the operation.
162
163
    """
164
    multiplication_complexity = complexity(base_length, modulus_length)
165
    iteration_count = iterations(exponent_length, exponent_head)
166
    cost = multiplication_complexity * iteration_count
167
    cost //= GQUADDIVISOR
168
    return cost