@@ -100,63 +100,77 @@ PrecompileAnalysis expmod_analyze(bytes_view input, evmc_revision rev) noexcept
100
100
{
101
101
using namespace intx ;
102
102
103
- static constexpr size_t INPUT_HEADER_REQUIRED_SIZE = 3 * sizeof (uint256);
104
- const int64_t min_gas = (rev >= EVMC_BERLIN) ? 200 : 0 ;
105
-
106
- uint8_t input_header[INPUT_HEADER_REQUIRED_SIZE]{};
107
- // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
108
- std::copy_n (input.data (), std::min (input.size (), INPUT_HEADER_REQUIRED_SIZE), input_header);
109
-
110
- const auto base_len = be::unsafe::load<uint256>(&input_header[0 ]);
111
- const auto exp_len = be::unsafe::load<uint256>(&input_header[32 ]);
112
- const auto mod_len = be::unsafe::load<uint256>(&input_header[64 ]);
103
+ const auto calc_adjusted_exp_len = [input](size_t offset, uint32_t len) noexcept {
104
+ const auto head_len = std::min (size_t {len}, size_t {32 });
105
+ const auto head_explicit_bytes =
106
+ offset < input.size () ?
107
+ input.substr (offset, std::min (head_len, input.size () - offset)) :
108
+ bytes_view{};
113
109
114
- if (base_len == 0 && mod_len == 0 )
115
- return {min_gas, 0 };
116
-
117
- static constexpr auto LEN_LIMIT = std::numeric_limits<size_t >::max ();
118
- if (base_len > LEN_LIMIT || exp_len > LEN_LIMIT || mod_len > LEN_LIMIT)
119
- return {GasCostMax, 0 };
120
-
121
- const auto adjusted_len = [input](size_t offset, size_t len) {
122
- const auto head_len = std::min (len, size_t {32 });
123
- const auto head_explicit_len =
124
- std::max (std::min (offset + head_len, input.size ()), offset) - offset;
125
- const bytes_view head_explicit_bytes (&input[offset], head_explicit_len);
126
110
const auto top_byte_index = head_explicit_bytes.find_first_not_of (uint8_t {0 });
127
- const size_t exp_bit_width =
111
+ const auto exp_bit_width =
128
112
(top_byte_index != bytes_view::npos) ?
129
- (head_len - top_byte_index - 1 ) * 8 +
130
- static_cast <size_t >(std::bit_width (head_explicit_bytes[top_byte_index])) :
113
+ 8 * (head_len - top_byte_index - 1 ) +
114
+ static_cast <unsigned >(std::bit_width (head_explicit_bytes[top_byte_index])) :
131
115
0 ;
132
116
133
- return std::max (
134
- 8 * ( std::max (len, size_t { 32 }) - 32 ) + ( std::max ( exp_bit_width, size_t {1 }) - 1 ),
135
- size_t {1 });
117
+ const auto tail_len = len - head_len;
118
+ const auto head_bits = std::max (exp_bit_width, size_t {1 }) - 1 ;
119
+ return std::max ( 8 * uint64_t {tail_len} + uint64_t {head_bits}, uint64_t {1 });
136
120
};
137
121
138
- static constexpr auto mult_complexity_eip2565 = [](const uint256& x) noexcept {
139
- const auto w = (x + 7 ) >> 3 ;
140
- return w * w;
122
+ static constexpr auto calc_mult_complexity_eip2565 = [](uint32_t y) noexcept {
123
+ const auto x = uint64_t {y};
124
+ const auto w = (x + 7 ) / 8 ;
125
+ return w * w; // max value: 0x04000000'00000000
141
126
};
142
- static constexpr auto mult_complexity_eip198 = [](const uint256& x) noexcept {
127
+ static constexpr auto calc_mult_complexity_eip198 = [](uint32_t y) noexcept {
128
+ const auto x = uint64_t {y};
143
129
const auto xx = x * x;
144
130
if (x <= 64 )
145
131
return xx;
146
132
else if (x <= 1024 )
147
- return ( xx >> 2 ) + 96 * x - 3072 ;
133
+ return xx / 4 + 96 * x - 3072 ;
148
134
else
149
- return (xx >> 4 ) + 480 * x - 199680 ;
135
+ return xx / 16 + 480 * x - 199680 ; // max value: 0x100001df'dffcf220
136
+ };
137
+
138
+ struct Params
139
+ {
140
+ int64_t min_gas;
141
+ unsigned final_divisor;
142
+ uint64_t (*calc_mult_complexity)(uint32_t y) noexcept ;
150
143
};
144
+ static constexpr Params byzantium_params{0 , 20 , calc_mult_complexity_eip198};
145
+ static constexpr Params berlin_params{200 , 3 , calc_mult_complexity_eip2565};
146
+ const auto & [min_gas, final_divisor, calc_mult_complexity] =
147
+ (rev >= EVMC_BERLIN) ? berlin_params : byzantium_params;
148
+
149
+ static constexpr size_t INPUT_HEADER_REQUIRED_SIZE = 3 * sizeof (uint256);
150
+ uint8_t input_header[INPUT_HEADER_REQUIRED_SIZE]{};
151
+ // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
152
+ std::copy_n (input.data (), std::min (input.size (), INPUT_HEADER_REQUIRED_SIZE), input_header);
153
+
154
+ const auto base_len256 = be::unsafe::load<uint256>(&input_header[0 ]);
155
+ const auto exp_len256 = be::unsafe::load<uint256>(&input_header[32 ]);
156
+ const auto mod_len256 = be::unsafe::load<uint256>(&input_header[64 ]);
157
+
158
+ if (base_len256 == 0 && mod_len256 == 0 )
159
+ return {min_gas, 0 };
160
+
161
+ static constexpr auto LEN_LIMIT = std::numeric_limits<uint32_t >::max ();
162
+ if (base_len256 > LEN_LIMIT || exp_len256 > LEN_LIMIT || mod_len256 > LEN_LIMIT)
163
+ return {GasCostMax, 0 };
164
+
165
+ const auto base_len = static_cast <uint32_t >(base_len256);
166
+ const auto exp_len = static_cast <uint32_t >(exp_len256);
167
+ const auto mod_len = static_cast <uint32_t >(mod_len256);
151
168
169
+ const auto adjusted_exp_len = calc_adjusted_exp_len (sizeof (input_header) + base_len, exp_len);
152
170
const auto max_len = std::max (mod_len, base_len);
153
- const auto adjusted_exp_len = adjusted_len (
154
- sizeof (input_header) + static_cast <size_t >(base_len), static_cast <size_t >(exp_len));
155
- const auto gas = (rev >= EVMC_BERLIN) ?
156
- mult_complexity_eip2565 (max_len) * adjusted_exp_len / 3 :
157
- mult_complexity_eip198 (max_len) * adjusted_exp_len / 20 ;
158
- return {std::max (min_gas, static_cast <int64_t >(std::min (gas, uint256{GasCostMax}))),
159
- static_cast <size_t >(mod_len)};
171
+ const auto gas = umul (calc_mult_complexity (max_len), adjusted_exp_len) / final_divisor;
172
+ const auto gas_clamped = std::clamp<uint128>(gas, min_gas, GasCostMax);
173
+ return {static_cast <int64_t >(gas_clamped), mod_len};
160
174
}
161
175
162
176
PrecompileAnalysis point_evaluation_analyze (bytes_view, evmc_revision) noexcept
0 commit comments