@@ -100,63 +100,77 @@ PrecompileAnalysis expmod_analyze(bytes_view input, evmc_revision rev) noexcept
100100{
101101 using namespace intx ;
102102
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 adjusted_len = [input](size_t offset, uint32_t len) {
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{};
113109
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);
126110 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 =
128112 (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])) :
131115 0 ;
132116
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 });
136120 };
137121
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 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
141126 };
142- static constexpr auto mult_complexity_eip198 = [](const uint256& x) noexcept {
127+ static constexpr auto mult_complexity_eip198 = [](uint32_t y) noexcept {
128+ const auto x = uint64_t {y};
143129 const auto xx = x * x;
144130 if (x <= 64 )
145131 return xx;
146132 else if (x <= 1024 )
147- return ( xx >> 2 ) + 96 * x - 3072 ;
133+ return xx / 4 + 96 * x - 3072 ;
148134 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 (*mult_complexity)(uint32_t y) noexcept ;
150143 };
144+ static constexpr Params byzantium_params{0 , 20 , mult_complexity_eip198};
145+ static constexpr Params berlin_params{200 , 3 , mult_complexity_eip2565};
146+ const auto & [min_gas, final_divisor, 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);
151168
169+ const auto adjusted_exp_len = adjusted_len (sizeof (input_header) + base_len, exp_len);
152170 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 (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};
160174}
161175
162176PrecompileAnalysis point_evaluation_analyze (bytes_view, evmc_revision) noexcept
0 commit comments