122 {
123
124 std::mt19937
r(0x11223344);
125
126 auto generate_random_bytes = [](std::mt19937& rand_eng, unsigned int num_bytes) {
127 std::vector<char> result(num_bytes);
128
130 for(int byte_pos = 0, end = result.size(); byte_pos < end; ++byte_pos) {
131 if ((byte_pos & 0x03) == 0) {
132 v = rand_eng();
133 }
134 result[byte_pos] = v & 0xFF;
135 v >>= 8;
136 }
137
138 return result;
139 };
140
141 static constexpr unsigned int num_trials = 10;
142
143 static_assert(num_trials > 0);
144
145 static constexpr unsigned int bit_calc_limit = 101;
146
147 static constexpr unsigned int start_num_bytes = 1;
148 static constexpr unsigned int end_num_bytes = 1 << ((bit_calc_limit + 7)/8);
149
150 static_assert(start_num_bytes <= end_num_bytes);
151
152 struct statistics {
153 unsigned int modulus_bit_size;
154 unsigned int exponent_bit_size;
158 };
159
160 std::vector<statistics> stats;
161
163 if (n <= 1) {
164 return 0;
165 }
166 return 32 - __builtin_clz(n - 1);
167 };
168
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);
178
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)
184 {
185 int64_t min_duration_ns = std::numeric_limits<int64_t>::max();
188
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);
193
194 auto start_time = std::chrono::steady_clock::now();
195
196 auto res =
fc::modexp(base, exponent, modulus);
197
198 auto end_time = std::chrono::steady_clock::now();
199
200 int64_t duration_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
201
202
203
204
205
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;
209 }
210
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),
217 });
218
219 const auto& stat = stats.back();
220
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)
226 );
227
228 }
229 }
230
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);
235 stats_output += ',';
236 stats_output += std::to_string(stat.exponent_bit_size);
237 stats_output += ',';
238 stats_output += std::to_string(stat.avg_time_ns);
239 stats_output += '\n';
240 }
241
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299