124 std::mt19937
r(0x11223344);
126 auto generate_random_bytes = [](std::mt19937& rand_eng,
unsigned int num_bytes) {
127 std::vector<char> result(num_bytes);
130 for(
int byte_pos = 0, end = result.size(); byte_pos < end; ++byte_pos) {
131 if ((byte_pos & 0x03) == 0) {
134 result[byte_pos] = v & 0xFF;
141 static constexpr unsigned int num_trials = 10;
143 static_assert(num_trials > 0);
145 static constexpr unsigned int bit_calc_limit = 101;
147 static constexpr unsigned int start_num_bytes = 1;
148 static constexpr unsigned int end_num_bytes = 1 << ((bit_calc_limit + 7)/8);
150 static_assert(start_num_bytes <= end_num_bytes);
153 unsigned int modulus_bit_size;
154 unsigned int exponent_bit_size;
160 std::vector<statistics> stats;
166 return 32 - __builtin_clz(n - 1);
169 BOOST_CHECK(ceil_log2(0) == 0);
170 BOOST_CHECK(ceil_log2(1) == 0);
171 BOOST_CHECK(ceil_log2(2) == 1);
172 BOOST_CHECK(ceil_log2(3) == 2);
173 BOOST_CHECK(ceil_log2(4) == 2);
174 BOOST_CHECK(ceil_log2(5) == 3);
175 BOOST_CHECK(ceil_log2(15) == 4);
176 BOOST_CHECK(ceil_log2(16) == 4);
177 BOOST_CHECK(ceil_log2(17) == 5);
179 for (
unsigned int n = start_num_bytes; n <= end_num_bytes; n *= 2) {
180 unsigned int bit_calc = 8 * ceil_log2(n);
181 for (
unsigned int exponent_num_bytes = 1;
182 exponent_num_bytes <= 2*n && bit_calc <= bit_calc_limit;
183 exponent_num_bytes *= 2, bit_calc += 5)
185 int64_t min_duration_ns = std::numeric_limits<int64_t>::max();
189 for (
unsigned int trial = 0; trial < num_trials; ++trial) {
190 auto base = generate_random_bytes(
r, n);
191 auto exponent = generate_random_bytes(
r, exponent_num_bytes);
192 auto modulus = generate_random_bytes(
r, n);
194 auto start_time = std::chrono::steady_clock::now();
196 auto res =
fc::modexp(base, exponent, modulus);
198 auto end_time = std::chrono::steady_clock::now();
200 int64_t duration_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
206 min_duration_ns = std::min(min_duration_ns, duration_ns);
207 max_duration_ns = std::max(max_duration_ns, duration_ns);
208 total_duration_ns += duration_ns;
211 stats.push_back(statistics{
212 .modulus_bit_size = n * 8,
213 .exponent_bit_size = exponent_num_bytes * 8,
214 .min_time_ns = min_duration_ns,
215 .max_time_ns = max_duration_ns,
216 .avg_time_ns = (total_duration_ns / num_trials),
219 const auto& stat = stats.back();
221 ilog(
"Completed random runs of mod_exp with ${bit_width}-bit width base and modulus values and "
222 "${exp_bit_width}-bit width exponent values. "
223 "Min time: ${min} ns; Average time: ${avg} ns; Max time: ${max} ns.",
224 (
"bit_width", stat.modulus_bit_size)(
"exp_bit_width", stat.exponent_bit_size)
225 (
"min", stat.min_time_ns)(
"avg", stat.avg_time_ns)(
"max", stat.max_time_ns)
231 std::string stats_output =
"Table (in csv format) summarizing statistics from runs:\n";
232 stats_output +=
"Modulus/Base Bit Size,Exponent Bit Size,Average Time (ns)\n";
233 for (
const auto& stat : stats) {
234 stats_output += std::to_string(stat.modulus_bit_size);
236 stats_output += std::to_string(stat.exponent_bit_size);
238 stats_output += std::to_string(stat.avg_time_ns);
239 stats_output +=
'\n';