multiexp.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Pavel Kharitonov <ipavrus@nil.foundation>
4 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
5 //
6 // MIT License
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 // SOFTWARE.
25 //---------------------------------------------------------------------------//
26 
27 #ifndef CRYPTO3_ALGEBRA_MULTIEXP_HPP
28 #define CRYPTO3_ALGEBRA_MULTIEXP_HPP
29 
30 #include <vector>
31 
32 #include <nil/crypto3/multiprecision/number.hpp>
33 #include <nil/crypto3/multiprecision/cpp_int.hpp>
34 
37 
38 namespace nil {
39  namespace crypto3 {
40  namespace algebra {
41  template<typename MultiexpMethod, typename InputBaseIterator, typename InputFieldIterator>
42  typename std::iterator_traits<InputBaseIterator>::value_type
43  multiexp(InputBaseIterator vec_start, InputBaseIterator vec_end, InputFieldIterator scalar_start,
44  InputFieldIterator scalar_end, const std::size_t chunks_count) {
45 
46  typedef typename std::iterator_traits<InputBaseIterator>::value_type base_value_type;
47  typedef typename std::iterator_traits<InputFieldIterator>::value_type field_value_type;
48 
49  const std::size_t total_size = std::distance(vec_start, vec_end);
50 
51  if ((total_size < chunks_count) || (chunks_count == 1)) {
52  // no need to split into "chunks_count", can call implementation directly
53  return MultiexpMethod::process(vec_start, vec_end, scalar_start, scalar_end);
54  }
55 
56  const std::size_t one_chunk_size = total_size / chunks_count;
57 
58  base_value_type result = base_value_type::zero();
59 
60  for (std::size_t i = 0; i < chunks_count; ++i) {
61  result =
62  result + MultiexpMethod::process(
63  vec_start + i * one_chunk_size,
64  (i == chunks_count - 1 ? vec_end : vec_start + (i + 1) * one_chunk_size),
65  scalar_start + i * one_chunk_size,
66  (i == chunks_count - 1 ? scalar_end : scalar_start + (i + 1) * one_chunk_size));
67  }
68 
69  return result;
70  }
71 
72  template<typename MultiexpMethod, typename InputBaseIterator, typename InputFieldIterator>
73  typename std::iterator_traits<InputBaseIterator>::value_type
74  multiexp_with_mixed_addition(InputBaseIterator vec_start, InputBaseIterator vec_end,
75  InputFieldIterator scalar_start, InputFieldIterator scalar_end,
76  const std::size_t chunks_count) {
77 
78  typedef typename std::iterator_traits<InputBaseIterator>::value_type base_value_type;
79  typedef typename std::iterator_traits<InputFieldIterator>::value_type field_value_type;
80 
81  typedef MultiexpMethod method_type;
82 
83  BOOST_ASSERT(std::distance(vec_start, vec_end) == std::distance(scalar_start, scalar_end));
84 
85  InputBaseIterator vec_it = vec_start;
86  InputFieldIterator scalar_it = scalar_start;
87 
88  const field_value_type zero = field_value_type::zero();
89  const field_value_type one = field_value_type::one();
90  std::vector<field_value_type> p;
91  std::vector<base_value_type> g;
92 
93  base_value_type acc = base_value_type::zero();
94 
95  for (; scalar_it != scalar_end; ++scalar_it, ++vec_it) {
96  if (*scalar_it == one) {
97 #ifdef USE_MIXED_ADDITION
98  acc = acc.mixed_add(*vec_it);
99 #else
100  acc = acc + (*vec_it);
101 #endif
102  } else if (*scalar_it != zero) {
103  p.emplace_back(*scalar_it);
104  g.emplace_back(*vec_it);
105  }
106  }
107 
108  return acc + multiexp<method_type>(g.begin(), g.end(), p.begin(), p.end(), chunks_count);
109  }
110 
115  template<typename GroupType>
116  using window_table = std::vector<std::vector<typename GroupType::value_type>>;
117 
118  template<typename GroupType>
119  std::size_t get_exp_window_size(const std::size_t num_scalars) {
121 #ifdef LOWMEM
122  return 14;
123 #else
124  return 17;
125 #endif
126  }
127 
128  std::size_t window = 1;
129 
130  for (std::size_t i = curves::multiexp_params<GroupType>::fixed_base_exp_window_table.size() - 1; i >= 0;
131  --i) {
134  window = i + 1;
135  break;
136  }
137  }
138 
139 #ifdef LOWMEM
140  window = std::min((std::size_t)14, window);
141 #endif
142  return window;
143  }
144 
145  template<typename GroupType>
146  window_table<GroupType> get_window_table(const std::size_t scalar_size,
147  const std::size_t window,
148  const typename GroupType::value_type &g) {
149  const std::size_t in_window = 1ul << window;
150  const std::size_t outerc = (scalar_size + window - 1) / window;
151  const std::size_t last_in_window = 1ul << (scalar_size - (outerc - 1) * window);
152 
153  window_table<GroupType> powers_of_g(
154  outerc, std::vector<typename GroupType::value_type>(in_window, GroupType::value_type::zero()));
155 
156  typename GroupType::value_type gouter = g;
157 
158  for (std::size_t outer = 0; outer < outerc; ++outer) {
159  typename GroupType::value_type ginner = GroupType::value_type::zero();
160  std::size_t cur_in_window = outer == outerc - 1 ? last_in_window : in_window;
161  for (std::size_t inner = 0; inner < cur_in_window; ++inner) {
162  powers_of_g[outer][inner] = ginner;
163  ginner = ginner + gouter;
164  }
165 
166  for (std::size_t i = 0; i < window; ++i) {
167  gouter = gouter.doubled();
168  }
169  }
170 
171  return powers_of_g;
172  }
173 
174  //
175  template<typename GroupType, typename FieldType>
176  typename GroupType::value_type windowed_exp(const std::size_t scalar_size,
177  const std::size_t window,
178  const window_table<GroupType> &powers_of_g,
179  const typename FieldType::value_type &pow) {
180 
181  typedef typename FieldType::modular_type modular_type;
182 
183  const std::size_t outerc = (scalar_size + window - 1) / window;
184  const modular_type pow_val = pow.data;
185  /* exp */
186  typename GroupType::value_type res = powers_of_g[0][0];
187 
188  for (std::size_t outer = 0; outer < outerc; ++outer) {
189  std::size_t inner = 0;
190  for (std::size_t i = 0; i < window; ++i) {
191  if (multiprecision::bit_test(pow_val, outer * window + i)) {
192  inner |= 1u << i;
193  }
194  }
195 
196  res = res + powers_of_g[outer][inner];
197  }
198 
199  return res;
200  }
201 
202  template<typename GroupType, typename FieldType, typename InputRange,
203  typename = typename std::enable_if<
204  std::is_same<typename InputRange::value_type, typename FieldType::value_type>::value>::type>
205  std::vector<typename GroupType::value_type> batch_exp(const std::size_t scalar_size,
206  const std::size_t window,
207  const window_table<GroupType> &table,
208  const InputRange &v) {
209  std::vector<typename GroupType::value_type> res(std::distance(v.begin(), v.end()), table[0][0]);
210 
211  for (std::size_t i = 0; i < v.size(); ++i) {
212  res[i] = windowed_exp<GroupType, FieldType>(scalar_size, window, table, v[i]);
213  }
214 
215  return res;
216  }
217 
218  template<typename GroupType, typename FieldType, typename InputRange,
219  typename = typename std::enable_if<
220  std::is_same<typename InputRange::value_type, typename FieldType::value_type>::value>::type>
221  std::vector<typename GroupType::value_type>
222  batch_exp_with_coeff(const std::size_t scalar_size,
223  const std::size_t window,
224  const window_table<GroupType> &table,
225  const typename FieldType::value_type &coeff,
226  const InputRange &v) {
227  std::vector<typename GroupType::value_type> res(std::distance(v.begin(), v.end()), table[0][0]);
228 
229  for (std::size_t i = 0; i < v.size(); ++i) {
230  res[i] = windowed_exp<GroupType, FieldType>(scalar_size, window, table, coeff * v[i]);
231  }
232 
233  return res;
234  }
235 
236  template<typename GroupType, typename InputRange>
237  typename std::enable_if<
238  std::is_same<typename InputRange::value_type, typename GroupType::value_type>::value, void>::type
239  batch_to_special(InputRange &vec) {
240 
241  std::vector<typename GroupType::value_type> non_zero_vec;
242  for (std::size_t i = 0; i < vec.size(); ++i) {
243  if (!vec[i].is_zero()) {
244  non_zero_vec.emplace_back(vec[i]);
245  }
246  }
247 
248  GroupType::batch_to_special_all_non_zeros(non_zero_vec);
249  typename std::vector<typename GroupType::value_type>::const_iterator it = non_zero_vec.begin();
250  typename GroupType::value_type zero_special = GroupType::value_type::zero().to_projective();
251 
252  for (std::size_t i = 0; i < vec.size(); ++i) {
253  if (!vec[i].is_zero()) {
254  vec[i] = *it;
255  ++it;
256  } else {
257  vec[i] = zero_special;
258  }
259  }
260  }
261  } // namespace algebra
262  } // namespace crypto3
263 } // namespace nil
264 
265 #endif // CRYPTO3_ALGEBRA_MULTIEXP_HPP
constexpr T min(const vector< T, N > &v)
computes the minimum valued element
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:135
std::vector< std::vector< typename GroupType::value_type > > window_table
Definition: multiexp.hpp:116
window_table< GroupType > get_window_table(const std::size_t scalar_size, const std::size_t window, const typename GroupType::value_type &g)
Definition: multiexp.hpp:146
std::vector< typename GroupType::value_type > batch_exp_with_coeff(const std::size_t scalar_size, const std::size_t window, const window_table< GroupType > &table, const typename FieldType::value_type &coeff, const InputRange &v)
Definition: multiexp.hpp:222
std::iterator_traits< InputBaseIterator >::value_type multiexp_with_mixed_addition(InputBaseIterator vec_start, InputBaseIterator vec_end, InputFieldIterator scalar_start, InputFieldIterator scalar_end, const std::size_t chunks_count)
Definition: multiexp.hpp:74
std::iterator_traits< InputBaseIterator >::value_type multiexp(InputBaseIterator vec_start, InputBaseIterator vec_end, InputFieldIterator scalar_start, InputFieldIterator scalar_end, const std::size_t chunks_count)
Definition: multiexp.hpp:43
std::vector< typename GroupType::value_type > batch_exp(const std::size_t scalar_size, const std::size_t window, const window_table< GroupType > &table, const InputRange &v)
Definition: multiexp.hpp:205
std::size_t get_exp_window_size(const std::size_t num_scalars)
Definition: multiexp.hpp:119
GroupType::value_type windowed_exp(const std::size_t scalar_size, const std::size_t window, const window_table< GroupType > &powers_of_g, const typename FieldType::value_type &pow)
Definition: multiexp.hpp:176
std::enable_if< std::is_same< typename InputRange::value_type, typename GroupType::value_type >::value, void >::type batch_to_special(InputRange &vec)
Definition: multiexp.hpp:239
constexpr T pow(T x, U n)
Definition: static_pow.hpp:32
bool is_zero(const Range &a)
Definition: basic_operations.hpp:43
Definition: pair.hpp:31
Definition: curves/params/multiexp/alt_bn128.hpp:39