ethereum.forks.london.vm.precompiled_contracts.modexpethereum.forks.arrow_glacier.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(3) |
|---|
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 | <snip> |
|---|---|
| 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.
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:
| 92 | <snip> |
|---|---|
| 111 | if exponent_length <= U256(32) and exponent_head == U256(0): |
| 112 | count = Uint(0) |
| 113 | elif exponent_length <= U256(32): |
| 114 | bit_length = exponent_head.bit_length() |
| 115 | |
| 116 | if bit_length > Uint(0): |
| 117 | bit_length -= Uint(1) |
| 118 | |
| 119 | count = bit_length |
| 120 | else: |
| 121 | length_part = Uint(8) * (Uint(exponent_length) - Uint(32)) |
| 122 | bits_part = exponent_head.bit_length() |
| 123 | |
| 124 | if bits_part > Uint(0): |
| 125 | bits_part -= Uint(1) |
| 126 | |
| 127 | count = length_part + bits_part |
| 128 | |
| 129 | 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:
| 138 | <snip> |
|---|---|
| 162 | multiplication_complexity = complexity(base_length, modulus_length) |
| 163 | iteration_count = iterations(exponent_length, exponent_head) |
| 164 | cost = multiplication_complexity * iteration_count |
| 165 | cost //= GQUADDIVISOR |
| 166 | return max(Uint(200), cost) |