Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
profile_multiexp.cpp
Go to the documentation of this file.
6 #include "libff/common/rng.hpp"
7 
8 #include <cstdio>
9 #include <fstream>
10 #include <sys/stat.h>
11 #include <vector>
12 using namespace libff;
13 
14 constexpr size_t NUM_ITERATIONS = 10;
15 constexpr size_t NUM_DIFFERENT_ELEMENTS = 32;
16 
19 
20 template<typename GroupT> using run_result_t = std::pair<long long, GroupT>;
21 
22 template<typename T> using test_instances_t = std::vector<T>;
23 
24 template<typename GroupT>
26 {
28  result.reserve(num_elements);
29  assert(result.size() == 0);
30 
31  // Generating a random group element is expensive, so for now we only
32  // generate NUM_DIFFERENT_ELEMENTS, and repeat them. Note, some methods
33  // require input to be in special form.
34 
35  size_t i;
36  for (i = 0; i < NUM_DIFFERENT_ELEMENTS; ++i) {
37  GroupT x = GroupT::random_element();
38  x.to_special();
39  result.push_back(x);
40  }
41  assert(result.size() == NUM_DIFFERENT_ELEMENTS);
42 
43  for (; i < num_elements; ++i) {
44  assert(result.size() == i);
45  result.push_back(result[i % NUM_DIFFERENT_ELEMENTS]);
46  }
47 
48  assert(result.size() == num_elements);
49  return result;
50 }
51 
52 template<typename FieldT>
54 {
55  // Use SHA512_rng because it is much faster than FieldT::random_element()
57  result.reserve(num_elements);
58  for (size_t i = 0; i < num_elements; i++) {
59  result.push_back(SHA512_rng<FieldT>(i));
60  }
61 
62  assert(result.size() == num_elements);
63  return result;
64 }
65 
66 // template<typename GroupT, typename FieldT>
67 // run_result_t<GroupT> profile_multiexp(
68 // test_instances_t<GroupT> group_elements,
69 // test_instances_t<FieldT> scalars)
70 // {
71 // long long start_time = get_nsec_time();
72 
73 // std::vector<GroupT> answers;
74 // for (size_t i = 0; i < group_elements.size(); i++) {
75 // answers.push_back(multi_exp<GroupT, FieldT, Method>(
76 // group_elements[i].cbegin(), group_elements[i].cend(),
77 // scalars[i].cbegin(), scalars[i].cend(),
78 // 1));
79 // }
80 
81 // long long time_delta = get_nsec_time() - start_time;
82 
83 // return run_result_t<GroupT>(time_delta, answers);
84 // }
85 
86 template<form_t Form, compression_t Comp>
88  const std::string &tag,
89  const size_t num_elements,
90  const size_t precompute_c = 0)
91 {
92  return std::string("multiexp_base_elements_") + tag +
93  ((Form == form_plain) ? "_plain_" : "_montgomery_") +
94  ((Comp == compression_on) ? "compressed_" : "uncompressed_") +
95  std::to_string(num_elements) +
96  ((precompute_c) ? ("_" + std::to_string(precompute_c)) : "") +
97  ".bin";
98 }
99 
100 template<form_t Form, compression_t Comp, typename GroupT>
102  const std::string &tag, const test_instances_t<GroupT> &base_elements)
103 {
104  const std::string filename =
105  base_elements_filename<Form, Comp>(tag, base_elements.size());
106 
107  std::cout << "Writing file '" << filename << "' ...";
108  std::flush(std::cout);
109 
110  std::ofstream out_s(
111  filename.c_str(), std::ios_base::out | std::ios_base::binary);
112  for (const GroupT &el : base_elements) {
113  group_write<encoding_binary, Form, Comp>(el, out_s);
114  }
115  out_s.close();
116 
117  std::cout << " DONE\n";
118 }
119 
120 template<form_t Form, compression_t Comp, typename GroupT>
122  const std::string &tag, const test_instances_t<GroupT> &base_elements)
123 {
124  using Field = typename GroupT::scalar_field;
125  const size_t c = bdlo12_signed_optimal_c(base_elements.size());
126  const size_t entries_per_base_element = (Field::num_bits + c - 1) / c;
127 
128  const std::string filename =
129  base_elements_filename<Form, Comp>(tag, base_elements.size(), c);
130 
131  std::cout << "Writing file '" << filename << "' ...";
132  std::flush(std::cout);
133 
134  std::ofstream out_s(
135  filename.c_str(), std::ios_base::out | std::ios_base::binary);
136  for (GroupT el : base_elements) {
137  // Write the base element itself, followed by each factor
138  group_write<encoding_binary, Form, Comp>(el, out_s);
139  for (size_t i = 0; i < entries_per_base_element - 1; ++i) {
140  // Multiply the base element by 2^c, and write
141  for (size_t j = 0; j < c; ++j) {
142  el = el.dbl();
143  }
144  group_write<encoding_binary, Form, Comp>(el, out_s);
145  }
146  }
147  out_s.close();
148 
149  std::cout << " DONE\n";
150 }
151 
152 template<typename GroupT>
154  const std::string &tag, const size_t num_elements)
155 {
156  test_instances_t<GroupT> base_elements =
157  generate_group_elements<GroupT>(num_elements);
158  create_base_element_file_for_config<FORM, COMP>(tag, base_elements);
159  create_precompute_file_for_config<FORM, COMP>(tag, base_elements);
160 }
161 
162 template<typename GroupT>
164  const std::string &tag, const size_t num_elements)
165 {
166  const std::string filename =
167  base_elements_filename<FORM, COMP>(tag, num_elements);
168 
169  test_instances_t<GroupT> elements;
170  elements.reserve(num_elements);
171 
172  std::ifstream in_s;
173  in_s.exceptions(std::ifstream::badbit | std::ifstream::failbit);
174  in_s.open(filename, std::ios_base::in | std::ios_base::binary);
175  for (size_t i = 0; i < num_elements; ++i) {
176  GroupT v;
177  group_read<encoding_binary, FORM, COMP>(v, in_s);
178  elements.push_back(v);
179  }
180 
181  return elements;
182 }
183 
184 template<
185  typename GroupT,
186  typename FieldT,
187  multi_exp_method Method,
190  test_instances_t<GroupT> group_elements, test_instances_t<FieldT> scalars)
191 {
192  long long start_time = get_nsec_time();
193 
194  GroupT answer;
195  for (size_t iter = 0; iter < NUM_ITERATIONS; ++iter) {
196  answer = multi_exp<GroupT, FieldT, Method, BaseForm>(
197  group_elements.cbegin(),
198  group_elements.cend(),
199  scalars.cbegin(),
200  scalars.cend(),
201  1);
202  }
203 
204  long long time_delta = get_nsec_time() - start_time;
205 
206  return run_result_t<GroupT>(time_delta, answer);
207 }
208 
209 template<form_t Form, compression_t Comp, typename GroupT, typename FieldT>
211  const std::string &tag, const std::vector<FieldT> &scalars)
212 {
213  const size_t num_elements = scalars.size();
214  const std::string filename =
215  base_elements_filename<Form, Comp>(tag, num_elements);
216 
217  struct stat s;
218  if (stat(filename.c_str(), &s)) {
219  throw std::ifstream::failure("no file: " + filename);
220  }
221 
222  std::ifstream in_s(
223  filename.c_str(), std::ios_base::in | std::ios_base::binary);
224  in_s.exceptions(
225  std::ios_base::eofbit | std::ios_base::badbit | std::ios_base::failbit);
226 
227  GroupT answer;
228 
229  long long start_time = get_nsec_time();
230 
231  for (size_t iter = 0; iter < NUM_ITERATIONS; ++iter) {
232  in_s.seekg(0llu);
233  answer = multi_exp_stream<Form, Comp, GroupT, FieldT>(in_s, scalars);
234  }
235 
236  long long time_delta = get_nsec_time() - start_time;
237 
238  return run_result_t<GroupT>(time_delta, answer);
239 }
240 
241 template<form_t Form, compression_t Comp, typename GroupT, typename FieldT>
243  const std::string &tag, const std::vector<FieldT> &scalars)
244 {
245  const size_t num_elements = scalars.size();
246  const size_t c = bdlo12_signed_optimal_c(num_elements);
247  const std::string filename =
248  base_elements_filename<Form, Comp>(tag, num_elements, c);
249 
250  struct stat s;
251  if (stat(filename.c_str(), &s)) {
252  throw std::ifstream::failure("no file: " + filename);
253  }
254 
255  std::ifstream in_s(
256  filename.c_str(), std::ios_base::in | std::ios_base::binary);
257  in_s.exceptions(
258  std::ios_base::eofbit | std::ios_base::badbit | std::ios_base::failbit);
259 
260  GroupT answer;
261 
262  long long start_time = get_nsec_time();
263 
264  for (size_t iter = 0; iter < NUM_ITERATIONS; ++iter) {
265  in_s.seekg(0llu);
266  answer = multi_exp_stream_with_precompute<Form, Comp, GroupT, FieldT>(
267  in_s, scalars, c);
268  }
269 
270  long long time_delta = get_nsec_time() - start_time;
271 
272  return run_result_t<GroupT>(time_delta, answer);
273 }
274 
275 template<typename GroupT, typename FieldT>
277  const std::string &tag,
278  size_t expn_start,
279  size_t expn_end_fast,
280  size_t expn_end_naive,
281  bool compare_answers)
282 {
283  std::cout << "Profiling " << tag << "\n";
284  printf(
285  "\t%16s\t%16s\t%16s\t%16s\t%16s\t%16s\t%16s\n",
286  "bos-coster",
287  "djb",
288  "djb_signed",
289  "djb_signed_mixed",
290  "from_stream",
291  "from_stream_precompute",
292  "naive");
293  for (size_t expn = expn_start; expn <= expn_end_fast; expn++) {
294  printf("%ld", expn);
295  fflush(stdout);
296 
297  try {
298  test_instances_t<GroupT> group_elements =
299  read_group_elements<GroupT>(tag, 1 << expn);
300 
301  test_instances_t<FieldT> scalars =
302  generate_scalars<FieldT>(1 << expn);
303 
304  run_result_t<GroupT> result_bos_coster =
305  profile_multiexp<GroupT, FieldT, multi_exp_method_bos_coster>(
306  group_elements, scalars);
307  printf("\t%16lld", result_bos_coster.first);
308  fflush(stdout);
309 
310  run_result_t<GroupT> result_djb =
311  profile_multiexp<GroupT, FieldT, multi_exp_method_BDLO12>(
312  group_elements, scalars);
313  printf("\t%16lld", result_djb.first);
314  fflush(stdout);
315 
316  if (compare_answers &&
317  (result_bos_coster.second != result_djb.second)) {
318  fprintf(stderr, "Answers NOT MATCHING (bos coster != djb)\n");
319  }
320 
321  run_result_t<GroupT> result_djb_signed = profile_multiexp<
322  GroupT,
323  FieldT,
324  multi_exp_method_BDLO12_signed>(group_elements, scalars);
325  printf("\t%16lld", result_djb_signed.first);
326  fflush(stdout);
327 
328  if (compare_answers &&
329  (result_djb.second != result_djb_signed.second)) {
330  fprintf(stderr, "Answers NOT MATCHING (djb != djb_signed)\n");
331  }
332 
333  run_result_t<GroupT> result_djb_signed_mixed = profile_multiexp<
334  GroupT,
335  FieldT,
337  multi_exp_base_form_special>(group_elements, scalars);
338  printf("\t%16lld", result_djb_signed_mixed.first);
339  fflush(stdout);
340 
341  if (compare_answers &&
342  (result_djb_signed.second != result_djb_signed_mixed.second)) {
343  fprintf(
344  stderr,
345  "Answers NOT MATCHING (djb_signed != djb_signed_mixed)\n");
346  }
347 
348  run_result_t<GroupT> result_stream =
349  profile_multiexp_stream<FORM, COMP, GroupT, FieldT>(
350  tag, scalars);
351  printf("\t%16lld", result_stream.first);
352  fflush(stdout);
353 
354  if (compare_answers &&
355  (result_djb_signed_mixed.second != result_stream.second)) {
356  fprintf(
357  stderr,
358  "Answers NOT MATCHING (djb_signed_mixed != stream)\n");
359  }
360 
361  run_result_t<GroupT> result_stream_precomp =
363  FORM,
364  COMP,
365  GroupT,
366  FieldT>(tag, scalars);
367  printf("\t%16lld", result_stream_precomp.first);
368  fflush(stdout);
369 
370  if (compare_answers &&
371  (result_stream.second != result_stream_precomp.second)) {
372  fprintf(
373  stderr,
374  "Answers NOT MATCHING (stream != stream_precomp)\n");
375  }
376 
377  if (expn <= expn_end_naive) {
378  run_result_t<GroupT> result_naive =
379  profile_multiexp<GroupT, FieldT, multi_exp_method_naive>(
380  group_elements, scalars);
381  printf("\t%16lld", result_naive.first);
382  fflush(stdout);
383 
384  if (compare_answers &&
385  (result_bos_coster.second != result_naive.second)) {
386  fprintf(
387  stderr, "Answers NOT MATCHING (bos coster != naive)\n");
388  }
389  }
390 
391  printf("\n");
392 
393  } catch (const std::ifstream::failure &e) {
394  std::cout << "(Generating files for 1<<" << expn << ")\n";
395  create_base_element_files<GroupT>(tag, 1 << expn);
396  continue;
397  }
398  }
399 }
400 
401 int main(void)
402 {
404 
406 
407  print_performance_csv<G1<alt_bn128_pp>, Fr<alt_bn128_pp>>(
408  "alt_bn128_g1", 8, 20, 14, true);
409 
410  print_performance_csv<G2<alt_bn128_pp>, Fr<alt_bn128_pp>>(
411  "alt_bn128_g2", 8, 20, 14, true);
412 
413  return 0;
414 }
libff::form_t
form_t
Encodings for (de)serialization.
Definition: serialization.hpp:25
rng.hpp
main
int main(void)
Definition: profile_multiexp.cpp:401
libff::start_time
long long start_time
Definition: profiling.cpp:62
libff::compression_t
compression_t
Enable / disable compression in (de)serialization.
Definition: serialization.hpp:31
libff
Definition: ffi.cpp:8
generate_scalars
test_instances_t< FieldT > generate_scalars(size_t num_elements)
Definition: profile_multiexp.cpp:53
libff::multi_exp_base_form_special
@ multi_exp_base_form_special
Definition: multiexp.hpp:50
base_elements_filename
std::string base_elements_filename(const std::string &tag, const size_t num_elements, const size_t precompute_c=0)
Definition: profile_multiexp.cpp:87
create_base_element_file_for_config
void create_base_element_file_for_config(const std::string &tag, const test_instances_t< GroupT > &base_elements)
Definition: profile_multiexp.cpp:101
libff::form_montgomery
@ form_montgomery
Definition: serialization.hpp:27
profile_multiexp_stream_with_precompute
run_result_t< GroupT > profile_multiexp_stream_with_precompute(const std::string &tag, const std::vector< FieldT > &scalars)
Definition: profile_multiexp.cpp:242
profile_multiexp
run_result_t< GroupT > profile_multiexp(test_instances_t< GroupT > group_elements, test_instances_t< FieldT > scalars)
Definition: profile_multiexp.cpp:189
print_performance_csv
void print_performance_csv(const std::string &tag, size_t expn_start, size_t expn_end_fast, size_t expn_end_naive, bool compare_answers)
Definition: profile_multiexp.cpp:276
libff::multi_exp_method
multi_exp_method
Definition: multiexp.hpp:21
generate_group_elements
test_instances_t< GroupT > generate_group_elements(size_t num_elements)
Definition: profile_multiexp.cpp:25
libff::alt_bn128_pp::init_public_params
static void init_public_params()
Definition: alt_bn128_pp.cpp:15
libff::multi_exp_base_form_normal
@ multi_exp_base_form_normal
Incoming base elements are not in special form.
Definition: multiexp.hpp:47
profile_multiexp_stream
run_result_t< GroupT > profile_multiexp_stream(const std::string &tag, const std::vector< FieldT > &scalars)
Definition: profile_multiexp.cpp:210
alt_bn128_pp.hpp
libff::get_nsec_time
long long get_nsec_time()
Definition: profiling.cpp:32
read_group_elements
test_instances_t< GroupT > read_group_elements(const std::string &tag, const size_t num_elements)
Definition: profile_multiexp.cpp:163
libff::compression_on
@ compression_on
Definition: serialization.hpp:33
libff::Fr
typename EC_ppT::Fp_type Fr
Definition: public_params.hpp:75
libff::compression_off
@ compression_off
Definition: serialization.hpp:32
test_instances_t
std::vector< T > test_instances_t
Definition: profile_multiexp.cpp:22
FORM
constexpr form_t FORM
Definition: profile_multiexp.cpp:17
create_precompute_file_for_config
void create_precompute_file_for_config(const std::string &tag, const test_instances_t< GroupT > &base_elements)
Definition: profile_multiexp.cpp:121
libff::form_plain
@ form_plain
Definition: serialization.hpp:26
COMP
constexpr compression_t COMP
Definition: profile_multiexp.cpp:18
NUM_ITERATIONS
constexpr size_t NUM_ITERATIONS
Definition: profile_multiexp.cpp:14
multiexp.hpp
profiling.hpp
libff::multi_exp_method_BDLO12_signed
@ multi_exp_method_BDLO12_signed
Similar to multi_exp_method_BDLO12, but using signed digits.
Definition: multiexp.hpp:41
libff::multi_exp_base_form
multi_exp_base_form
Form of base elements passed to multi_exp routines.
Definition: multiexp.hpp:45
create_base_element_files
void create_base_element_files(const std::string &tag, const size_t num_elements)
Definition: profile_multiexp.cpp:153
libff::print_compilation_info
void print_compilation_info()
Definition: profiling.cpp:375
NUM_DIFFERENT_ELEMENTS
constexpr size_t NUM_DIFFERENT_ELEMENTS
Definition: profile_multiexp.cpp:15
curve_serialization.hpp
run_result_t
std::pair< long long, GroupT > run_result_t
Definition: profile_multiexp.cpp:20
multiexp_stream.hpp