Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
Typedefs | Functions | Variables
profile_multiexp.cpp File Reference
#include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include "libff/algebra/curves/curve_serialization.hpp"
#include "libff/algebra/scalar_multiplication/multiexp.hpp"
#include "libff/algebra/scalar_multiplication/multiexp_stream.hpp"
#include "libff/common/profiling.hpp"
#include "libff/common/rng.hpp"
#include <cstdio>
#include <fstream>
#include <sys/stat.h>
#include <vector>
Include dependency graph for profile_multiexp.cpp:

Go to the source code of this file.

Typedefs

template<typename GroupT >
using run_result_t = std::pair< long long, GroupT >
 
template<typename T >
using test_instances_t = std::vector< T >
 

Functions

template<typename GroupT >
test_instances_t< GroupT > generate_group_elements (size_t num_elements)
 
template<typename FieldT >
test_instances_t< FieldT > generate_scalars (size_t num_elements)
 
template<form_t Form, compression_t Comp>
std::string base_elements_filename (const std::string &tag, const size_t num_elements, const size_t precompute_c=0)
 
template<form_t Form, compression_t Comp, typename GroupT >
void create_base_element_file_for_config (const std::string &tag, const test_instances_t< GroupT > &base_elements)
 
template<form_t Form, compression_t Comp, typename GroupT >
void create_precompute_file_for_config (const std::string &tag, const test_instances_t< GroupT > &base_elements)
 
template<typename GroupT >
void create_base_element_files (const std::string &tag, const size_t num_elements)
 
template<typename GroupT >
test_instances_t< GroupT > read_group_elements (const std::string &tag, const size_t num_elements)
 
template<typename GroupT , typename FieldT , multi_exp_method Method, multi_exp_base_form BaseForm = multi_exp_base_form_normal>
run_result_t< GroupT > profile_multiexp (test_instances_t< GroupT > group_elements, test_instances_t< FieldT > scalars)
 
template<form_t Form, compression_t Comp, typename GroupT , typename FieldT >
run_result_t< GroupT > profile_multiexp_stream (const std::string &tag, const std::vector< FieldT > &scalars)
 
template<form_t Form, compression_t Comp, typename GroupT , typename FieldT >
run_result_t< GroupT > profile_multiexp_stream_with_precompute (const std::string &tag, const std::vector< FieldT > &scalars)
 
template<typename GroupT , typename FieldT >
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)
 
int main (void)
 

Variables

constexpr size_t NUM_ITERATIONS = 10
 
constexpr size_t NUM_DIFFERENT_ELEMENTS = 32
 
constexpr form_t FORM = form_montgomery
 
constexpr compression_t COMP = compression_off
 

Typedef Documentation

◆ run_result_t

template<typename GroupT >
using run_result_t = std::pair<long long, GroupT>

Definition at line 20 of file profile_multiexp.cpp.

◆ test_instances_t

template<typename T >
using test_instances_t = std::vector<T>

Definition at line 22 of file profile_multiexp.cpp.

Function Documentation

◆ base_elements_filename()

template<form_t Form, compression_t Comp>
std::string base_elements_filename ( const std::string &  tag,
const size_t  num_elements,
const size_t  precompute_c = 0 
)

Definition at line 87 of file profile_multiexp.cpp.

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 }

◆ create_base_element_file_for_config()

template<form_t Form, compression_t Comp, typename GroupT >
void create_base_element_file_for_config ( const std::string &  tag,
const test_instances_t< GroupT > &  base_elements 
)

Definition at line 101 of file profile_multiexp.cpp.

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 }

◆ create_base_element_files()

template<typename GroupT >
void create_base_element_files ( const std::string &  tag,
const size_t  num_elements 
)

Definition at line 153 of file profile_multiexp.cpp.

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 }

◆ create_precompute_file_for_config()

template<form_t Form, compression_t Comp, typename GroupT >
void create_precompute_file_for_config ( const std::string &  tag,
const test_instances_t< GroupT > &  base_elements 
)

Definition at line 121 of file profile_multiexp.cpp.

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 }

◆ generate_group_elements()

template<typename GroupT >
test_instances_t<GroupT> generate_group_elements ( size_t  num_elements)

Definition at line 25 of file profile_multiexp.cpp.

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 }

◆ generate_scalars()

template<typename FieldT >
test_instances_t<FieldT> generate_scalars ( size_t  num_elements)

Definition at line 53 of file profile_multiexp.cpp.

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 }

◆ main()

int main ( void  )

Definition at line 401 of file profile_multiexp.cpp.

402 {
404 
405  alt_bn128_pp::init_public_params();
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 }
Here is the call graph for this function:

◆ print_performance_csv()

template<typename GroupT , typename FieldT >
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 at line 276 of file profile_multiexp.cpp.

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 }
Here is the call graph for this function:

◆ profile_multiexp()

template<typename GroupT , typename FieldT , multi_exp_method Method, multi_exp_base_form BaseForm = multi_exp_base_form_normal>
run_result_t<GroupT> profile_multiexp ( test_instances_t< GroupT >  group_elements,
test_instances_t< FieldT >  scalars 
)

Definition at line 189 of file profile_multiexp.cpp.

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 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ profile_multiexp_stream()

template<form_t Form, compression_t Comp, typename GroupT , typename FieldT >
run_result_t<GroupT> profile_multiexp_stream ( const std::string &  tag,
const std::vector< FieldT > &  scalars 
)

Definition at line 210 of file profile_multiexp.cpp.

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 }
Here is the call graph for this function:

◆ profile_multiexp_stream_with_precompute()

template<form_t Form, compression_t Comp, typename GroupT , typename FieldT >
run_result_t<GroupT> profile_multiexp_stream_with_precompute ( const std::string &  tag,
const std::vector< FieldT > &  scalars 
)

Definition at line 242 of file profile_multiexp.cpp.

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 }
Here is the caller graph for this function:

◆ read_group_elements()

template<typename GroupT >
test_instances_t<GroupT> read_group_elements ( const std::string &  tag,
const size_t  num_elements 
)

Definition at line 163 of file profile_multiexp.cpp.

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 }

Variable Documentation

◆ COMP

constexpr compression_t COMP = compression_off
constexpr

Definition at line 18 of file profile_multiexp.cpp.

◆ FORM

constexpr form_t FORM = form_montgomery
constexpr

Definition at line 17 of file profile_multiexp.cpp.

◆ NUM_DIFFERENT_ELEMENTS

constexpr size_t NUM_DIFFERENT_ELEMENTS = 32
constexpr

Definition at line 15 of file profile_multiexp.cpp.

◆ NUM_ITERATIONS

constexpr size_t NUM_ITERATIONS = 10
constexpr

Definition at line 14 of file profile_multiexp.cpp.

libff::start_time
long long start_time
Definition: profiling.cpp:62
libff::multi_exp_base_form_special
@ multi_exp_base_form_special
Definition: multiexp.hpp:50
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
libff::get_nsec_time
long long get_nsec_time()
Definition: profiling.cpp:32
libff::compression_on
@ compression_on
Definition: serialization.hpp:33
libff::Fr
typename EC_ppT::Fp_type Fr
Definition: public_params.hpp:75
test_instances_t
std::vector< T > test_instances_t
Definition: profile_multiexp.cpp:22
FORM
constexpr form_t FORM
Definition: profile_multiexp.cpp:17
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
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::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
run_result_t
std::pair< long long, GroupT > run_result_t
Definition: profile_multiexp.cpp:20