Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
kc_multiexp.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  * @author This file is part of libsnark, developed by SCIPR Lab
4  * and contributors (see AUTHORS).
5  * @copyright MIT license (see LICENSE file)
6  *****************************************************************************/
7 
8 #ifndef KC_MULTIEXP_TCC_
9 #define KC_MULTIEXP_TCC_
10 
11 namespace libsnark
12 {
13 
14 template<typename T1, typename T2, mp_size_t n>
15 knowledge_commitment<T1, T2> opt_window_wnaf_exp(
16  const knowledge_commitment<T1, T2> &base,
17  const libff::bigint<n> &scalar,
18  const size_t scalar_bits)
19 {
20  return knowledge_commitment<T1, T2>(
21  opt_window_wnaf_exp(base.g, scalar, scalar_bits),
22  opt_window_wnaf_exp(base.h, scalar, scalar_bits));
23 }
24 
25 template<
26  typename T1,
27  typename T2,
28  typename FieldT,
29  libff::multi_exp_method Method,
30  libff::multi_exp_base_form BaseForm>
31 knowledge_commitment<T1, T2> kc_multi_exp_with_mixed_addition(
32  const knowledge_commitment_vector<T1, T2> &vec,
33  const size_t min_idx,
34  const size_t max_idx,
35  typename std::vector<FieldT>::const_iterator scalar_start,
36  typename std::vector<FieldT>::const_iterator scalar_end,
37  const size_t chunks)
38 {
39  libff::enter_block("Process scalar vector");
40  auto index_it =
41  std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx);
42  const size_t offset = index_it - vec.indices.begin();
43 
44  auto value_it = vec.values.begin() + offset;
45 
46  const FieldT zero = FieldT::zero();
47  const FieldT one = FieldT::one();
48 
49  std::vector<FieldT> p;
50  std::vector<knowledge_commitment<T1, T2>> g;
51 
52  knowledge_commitment<T1, T2> acc = knowledge_commitment<T1, T2>::zero();
53 
54  size_t num_skip = 0;
55  size_t num_add = 0;
56  size_t num_other = 0;
57 
58 #ifndef NDEBUG
59  const size_t scalar_length = std::distance(scalar_start, scalar_end);
60 #else
61  libff::UNUSED(scalar_end);
62 #endif
63  while (index_it != vec.indices.end() && *index_it < max_idx) {
64  const size_t scalar_position = (*index_it) - min_idx;
65  assert(scalar_position < scalar_length);
66 
67  const FieldT scalar = *(scalar_start + scalar_position);
68 
69  if (scalar == zero) {
70  // do nothing
71  ++num_skip;
72  } else if (scalar == one) {
73  if (BaseForm == libff::multi_exp_base_form_special) {
74  acc.g = acc.g.mixed_add(value_it->g);
75  acc.h = acc.h.mixed_add(value_it->h);
76  } else {
77  acc.g = acc.g + value_it->g;
78  acc.h = acc.h + value_it->h;
79  }
80  ++num_add;
81  } else {
82  p.emplace_back(scalar);
83  g.emplace_back(*value_it);
84  ++num_other;
85  }
86 
87  ++index_it;
88  ++value_it;
89  }
90 
91  libff::print_indent();
92  printf(
93  "* Elements of w skipped: %zu (%0.2f%%)\n",
94  num_skip,
95  100. * num_skip / (num_skip + num_add + num_other));
96  libff::print_indent();
97  printf(
98  "* Elements of w processed with special addition: %zu (%0.2f%%)\n",
99  num_add,
100  100. * num_add / (num_skip + num_add + num_other));
101  libff::print_indent();
102  printf(
103  "* Elements of w remaining: %zu (%0.2f%%)\n",
104  num_other,
105  100. * num_other / (num_skip + num_add + num_other));
106  libff::leave_block("Process scalar vector");
107 
108  return acc + libff::multi_exp<
109  knowledge_commitment<T1, T2>,
110  FieldT,
111  Method,
112  BaseForm>(g.begin(), g.end(), p.begin(), p.end(), chunks);
113 }
114 
115 template<typename T1, typename T2, typename FieldT>
116 knowledge_commitment_vector<T1, T2> kc_batch_exp_internal(
117  const size_t scalar_size,
118  const size_t T1_window,
119  const size_t T2_window,
120  const libff::window_table<T1> &T1_table,
121  const libff::window_table<T2> &T2_table,
122  const FieldT &T1_coeff,
123  const FieldT &T2_coeff,
124  const std::vector<FieldT> &v,
125  const size_t start_pos,
126  const size_t end_pos,
127  const size_t expected_size)
128 {
129  knowledge_commitment_vector<T1, T2> res;
130 
131  res.values.reserve(expected_size);
132  res.indices.reserve(expected_size);
133 
134  for (size_t pos = start_pos; pos != end_pos; ++pos) {
135  if (!v[pos].is_zero()) {
136  res.values.emplace_back(knowledge_commitment<T1, T2>(
137  windowed_exp(
138  scalar_size, T1_window, T1_table, T1_coeff * v[pos]),
139  windowed_exp(
140  scalar_size, T2_window, T2_table, T2_coeff * v[pos])));
141  res.indices.emplace_back(pos);
142  }
143  }
144 
145  return res;
146 }
147 
148 template<typename T1, typename T2, typename FieldT>
149 knowledge_commitment_vector<T1, T2> kc_batch_exp(
150  const size_t scalar_size,
151  const size_t T1_window,
152  const size_t T2_window,
153  const libff::window_table<T1> &T1_table,
154  const libff::window_table<T2> &T2_table,
155  const FieldT &T1_coeff,
156  const FieldT &T2_coeff,
157  const std::vector<FieldT> &v,
158  const size_t suggested_num_chunks,
159  bool output_special)
160 {
161  knowledge_commitment_vector<T1, T2> res;
162  res.domain_size_ = v.size();
163 
164  size_t nonzero = 0;
165  for (size_t i = 0; i < v.size(); ++i) {
166  nonzero += (v[i].is_zero() ? 0 : 1);
167  }
168 
169  const size_t num_chunks =
170  std::max((size_t)1, std::min(nonzero, suggested_num_chunks));
171 
172  if (!libff::inhibit_profiling_info) {
173  libff::print_indent();
174  printf(
175  "Non-zero coordinate count: %zu/%zu (%0.2f%%)\n",
176  nonzero,
177  v.size(),
178  100. * nonzero / v.size());
179  }
180 
181  std::vector<knowledge_commitment_vector<T1, T2>> tmp(num_chunks);
182  std::vector<size_t> chunk_pos(num_chunks + 1);
183 
184  const size_t chunk_size = nonzero / num_chunks;
185  const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1);
186 
187  chunk_pos[0] = 0;
188 
189  size_t cnt = 0;
190  size_t chunkno = 1;
191 
192  for (size_t i = 0; i < v.size(); ++i) {
193  cnt += (v[i].is_zero() ? 0 : 1);
194  if (cnt == chunk_size && chunkno < num_chunks) {
195  chunk_pos[chunkno] = i;
196  cnt = 0;
197  ++chunkno;
198  }
199  }
200 
201  chunk_pos[num_chunks] = v.size();
202 
203 #ifdef MULTICORE
204 #pragma omp parallel for
205 #endif
206  for (size_t i = 0; i < num_chunks; ++i) {
207  tmp[i] = kc_batch_exp_internal<T1, T2, FieldT>(
208  scalar_size,
209  T1_window,
210  T2_window,
211  T1_table,
212  T2_table,
213  T1_coeff,
214  T2_coeff,
215  v,
216  chunk_pos[i],
217  chunk_pos[i + 1],
218  i == num_chunks - 1 ? last_chunk : chunk_size);
219  if (output_special) {
220  libff::batch_to_special<knowledge_commitment<T1, T2>>(
221  tmp[i].values);
222  }
223  }
224 
225  if (num_chunks == 1) {
226  tmp[0].domain_size_ = v.size();
227  return tmp[0];
228  } else {
229  for (size_t i = 0; i < num_chunks; ++i) {
230  res.values.insert(
231  res.values.end(), tmp[i].values.begin(), tmp[i].values.end());
232  res.indices.insert(
233  res.indices.end(),
234  tmp[i].indices.begin(),
235  tmp[i].indices.end());
236  }
237  return res;
238  }
239 }
240 
241 } // namespace libsnark
242 
243 #endif // KC_MULTIEXP_TCC_