ethereum.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 |
|
82 | base_length : |
83 | Length of the array representing the base integer. |
84 |
|
85 | modulus_length : |
86 | Length of the array representing the modulus integer. |
87 |
|
88 | Returns |
89 | ------- |
90 |
|
91 | complexity : `Uint` |
92 | Complexity of performing the operation. |
93 | """ |
94 | max_length = max(Uint(base_length), Uint(modulus_length)) |
95 | words = (max_length + Uint(7)) // Uint(8) |
96 | complexity = Uint(16) |
97 | if max_length > Uint(32): |
98 | complexity = Uint(2) * words ** Uint(2) |
99 | 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:
103 | """ |
---|---|
104 | Calculate the number of iterations required to perform a modular |
105 | exponentiation. |
106 |
|
107 | Parameters |
108 | ---------- |
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 |
|
120 | iterations : `Uint` |
121 | Number of iterations. |
122 | """ |
123 | if exponent_length <= U256(32) and exponent_head == U256(0): |
124 | count = Uint(0) |
125 | elif exponent_length <= U256(32): |
126 | bit_length = exponent_head.bit_length() |
127 |
|
128 | if bit_length > Uint(0): |
129 | bit_length -= Uint(1) |
130 |
|
131 | count = bit_length |
132 | else: |
133 | length_part = Uint(16) * (Uint(exponent_length) - Uint(32)) |
134 | bits_part = exponent_head.bit_length() |
135 |
|
136 | if bits_part > Uint(0): |
137 | bits_part -= Uint(1) |
138 |
|
139 | count = length_part + bits_part |
140 | |
141 | 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:
150 | """ |
---|---|
151 | Calculate the gas cost of performing a modular exponentiation. |
152 |
|
153 | Parameters |
154 | ---------- |
155 |
|
156 | base_length : |
157 | Length of the array representing the base integer. |
158 |
|
159 | modulus_length : |
160 | Length of the array representing the modulus integer. |
161 |
|
162 | exponent_length : |
163 | Length of the array representing the exponent integer. |
164 |
|
165 | exponent_head : |
166 | First 32 bytes of the exponent (with leading zero padding if it is |
167 | shorter than 32 bytes), as a U256. |
168 |
|
169 | Returns |
170 | ------- |
171 |
|
172 | gas_cost : `Uint` |
173 | Gas required for performing the operation. |
174 | """ |
175 | multiplication_complexity = complexity(base_length, modulus_length) |
176 | iteration_count = iterations(exponent_length, exponent_head) |
177 | cost = multiplication_complexity * iteration_count |
178 | return max(Uint(500), cost) |