ethereum.forks.byzantium.vm.precompiled_contracts.modexpethereum.forks.constantinople.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 | <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.
def complexity(base_length: U256, modulus_length: U256) -> Uint:
| 69 | <snip> |
|---|---|
| 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 | <snip> |
|---|---|
| 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 | <snip> |
|---|---|
| 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 |