knowledge_commitment_multiexp.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 
26 #ifndef CRYPTO3_ZK_KC_MULTIEXP_HPP
27 #define CRYPTO3_ZK_KC_MULTIEXP_HPP
28 
29 /*
30  Split out from multiexp to prevent cyclical
31  dependencies. I.e. previously multiexp dependend on
32  commitments, which dependend on sparse_vector, which
33  dependend on multiexp (to do accumulate).
34 
35  Will probably go away in more general exp refactoring.
36 */
37 
39 
41 
42 namespace nil {
43  namespace crypto3 {
44  namespace zk {
45  namespace snark {
46  template<typename T1, typename T2, typename Backend,
47  multiprecision::expression_template_option ExpressionTemplates>
50  const multiprecision::number<Backend, ExpressionTemplates> &scalar,
51  const std::size_t scalar_bits) {
53  opt_window_wnaf_exp(base.g, scalar, scalar_bits),
54  opt_window_wnaf_exp(base.h, scalar, scalar_bits));
55  }
56 
57  template<typename MultiexpMethod, typename T1, typename T2, typename InputFieldIterator>
60  const std::size_t min_idx, const std::size_t max_idx,
61  InputFieldIterator scalar_start, InputFieldIterator scalar_end,
62  const std::size_t chunks) {
63  typedef typename std::iterator_traits<InputFieldIterator>::value_type field_value_type;
64  typedef typename std::iterator_traits<InputFieldIterator>::value_type::field_type field_type;
65 
66  const size_t scalar_length = std::distance(scalar_start, scalar_end);
67  assert((size_t)(scalar_length) <= vec.domain_size_);
68 
69  auto index_it = std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx);
70  const std::size_t offset = index_it - vec.indices.begin();
71 
72  auto value_it = vec.values.begin() + offset;
73 
74  const field_value_type zero = field_value_type::zero();
75  const field_value_type one = field_value_type::one();
76 
77  std::vector<field_value_type> p;
78  std::vector<typename knowledge_commitment<T1, T2>::value_type> g;
79 
82 
83  while (index_it != vec.indices.end() && *index_it < max_idx) {
84  const std::size_t scalar_position = (*index_it) - min_idx;
85  assert(scalar_position < scalar_length);
86 
87  const field_value_type scalar = *(scalar_start + scalar_position);
88 
89  if (scalar == zero) {
90  // do nothing
91  } else if (scalar == one) {
92 #ifdef USE_MIXED_ADDITION
93  acc.g = acc.g.mixed_add(value_it->g);
94  acc.h = acc.h.mixed_add(value_it->h);
95 #else
96  acc.g = acc.g + value_it->g;
97  acc.h = acc.h + value_it->h;
98 #endif
99  } else {
100  p.emplace_back(scalar);
101  g.emplace_back(*value_it);
102  }
103 
104  ++index_it;
105  ++value_it;
106  }
107 
108  return acc + algebra::multiexp<MultiexpMethod>(g.begin(), g.end(), p.begin(), p.end(), chunks);
109  }
110 
111  template<typename T1, typename T2, typename FieldType>
112  knowledge_commitment_vector<T1, T2>
113  kc_batch_exp_internal(const std::size_t scalar_size,
114  const std::size_t T1_window,
115  const std::size_t T2_window,
116  const algebra::window_table<T1> &T1_table,
117  const algebra::window_table<T2> &T2_table,
118  const typename FieldType::value_type &T1_coeff,
119  const typename FieldType::value_type &T2_coeff,
120  const std::vector<typename FieldType::value_type> &v,
121  const std::size_t start_pos,
122  const std::size_t end_pos,
123  const std::size_t expected_size) {
125 
126  res.values.reserve(expected_size);
127  res.indices.reserve(expected_size);
128 
129  for (std::size_t pos = start_pos; pos != end_pos; ++pos) {
130  if (!v[pos].is_zero()) {
131  res.values.emplace_back(typename knowledge_commitment<T1, T2>::value_type(
132  algebra::windowed_exp<T1, FieldType>(scalar_size, T1_window, T1_table, T1_coeff * v[pos]),
133  algebra::windowed_exp<T2, FieldType>(scalar_size, T2_window, T2_table, T2_coeff * v[pos])));
134  res.indices.emplace_back(pos);
135  }
136  }
137 
138  return res;
139  }
140 
141  template<typename T1, typename T2, typename FieldType>
142  knowledge_commitment_vector<T1, T2> kc_batch_exp(const std::size_t scalar_size,
143  const std::size_t T1_window,
144  const std::size_t T2_window,
145  const algebra::window_table<T1> &T1_table,
146  const algebra::window_table<T2> &T2_table,
147  const typename FieldType::value_type &T1_coeff,
148  const typename FieldType::value_type &T2_coeff,
149  const std::vector<typename FieldType::value_type> &v,
150  const std::size_t suggested_num_chunks) {
152  res.domain_size_ = v.size();
153 
154  std::size_t nonzero = 0;
155  for (std::size_t i = 0; i < v.size(); ++i) {
156  nonzero += (v[i].is_zero() ? 0 : 1);
157  }
158 
159  const std::size_t num_chunks = std::max((std::size_t)1, std::min(nonzero, suggested_num_chunks));
160 
161  std::vector<knowledge_commitment_vector<T1, T2>> tmp(num_chunks);
162  std::vector<std::size_t> chunk_pos(num_chunks + 1);
163 
164  const std::size_t chunk_size = nonzero / num_chunks;
165  const std::size_t last_chunk = nonzero - chunk_size * (num_chunks - 1);
166 
167  chunk_pos[0] = 0;
168 
169  std::size_t cnt = 0;
170  std::size_t chunkno = 1;
171 
172  for (std::size_t i = 0; i < v.size(); ++i) {
173  cnt += (v[i].is_zero() ? 0 : 1);
174  if (cnt == chunk_size && chunkno < num_chunks) {
175  chunk_pos[chunkno] = i;
176  cnt = 0;
177  ++chunkno;
178  }
179  }
180 
181  chunk_pos[num_chunks] = v.size();
182 
183 #ifdef MULTICORE
184 #pragma omp parallel for
185 #endif
186  for (std::size_t i = 0; i < num_chunks; ++i) {
187  tmp[i] = kc_batch_exp_internal<T1, T2, FieldType>(
188  scalar_size, T1_window, T2_window, T1_table, T2_table, T1_coeff, T2_coeff, v, chunk_pos[i],
189  chunk_pos[i + 1], i == num_chunks - 1 ? last_chunk : chunk_size);
190 #ifdef USE_MIXED_ADDITION
191  algebra::batch_to_special<typename commitments<T1, T2>::value_type>(tmp[i].values);
192 #endif
193  }
194 
195  if (num_chunks == 1) {
196  tmp[0].domain_size_ = v.size();
197  return tmp[0];
198  } else {
199  for (std::size_t i = 0; i < num_chunks; ++i) {
200  res.values.insert(res.values.end(), tmp[i].values.begin(), tmp[i].values.end());
201  res.indices.insert(res.indices.end(), tmp[i].indices.begin(), tmp[i].indices.end());
202  }
203  return res;
204  }
205  }
206  } // namespace snark
207  } // namespace zk
208  } // namespace crypto3
209 } // namespace nil
210 
211 #endif // KC_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
constexpr T max(const vector< T, N > &v)
computes the maximum valued element
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:146
std::vector< std::vector< typename GroupType::value_type > > window_table
Definition: multiexp.hpp:116
bool is_zero(const Range &a)
Definition: basic_operations.hpp:43
knowledge_commitment< T1, T2 >::value_type opt_window_wnaf_exp(const typename knowledge_commitment< T1, T2 >::value_type &base, const multiprecision::number< Backend, ExpressionTemplates > &scalar, const std::size_t scalar_bits)
Definition: knowledge_commitment_multiexp.hpp:49
knowledge_commitment< T1, T2 >::value_type kc_multiexp_with_mixed_addition(const knowledge_commitment_vector< T1, T2 > &vec, const std::size_t min_idx, const std::size_t max_idx, InputFieldIterator scalar_start, InputFieldIterator scalar_end, const std::size_t chunks)
Definition: knowledge_commitment_multiexp.hpp:59
knowledge_commitment_vector< T1, T2 > kc_batch_exp(const std::size_t scalar_size, const std::size_t T1_window, const std::size_t T2_window, const algebra::window_table< T1 > &T1_table, const algebra::window_table< T2 > &T2_table, const typename FieldType::value_type &T1_coeff, const typename FieldType::value_type &T2_coeff, const std::vector< typename FieldType::value_type > &v, const std::size_t suggested_num_chunks)
Definition: knowledge_commitment_multiexp.hpp:142
knowledge_commitment_vector< T1, T2 > kc_batch_exp_internal(const std::size_t scalar_size, const std::size_t T1_window, const std::size_t T2_window, const algebra::window_table< T1 > &T1_table, const algebra::window_table< T2 > &T2_table, const typename FieldType::value_type &T1_coeff, const typename FieldType::value_type &T2_coeff, const std::vector< typename FieldType::value_type > &v, const std::size_t start_pos, const std::size_t end_pos, const std::size_t expected_size)
Definition: knowledge_commitment_multiexp.hpp:113
Definition: pair.hpp:31
Definition: element_knowledge_commitment.hpp:54
Type1::value_type g
Definition: element_knowledge_commitment.hpp:58
Type2::value_type h
Definition: element_knowledge_commitment.hpp:59
static element_kc zero()
Definition: element_knowledge_commitment.hpp:97
detail::element_kc< Type1, Type2 > value_type
Definition: knowledge_commitment.hpp:52
Definition: sparse_vector.hpp:48
std::vector< underlying_value_type > values
Definition: sparse_vector.hpp:58
std::vector< std::size_t > indices
Definition: sparse_vector.hpp:57
std::size_t domain_size_
Definition: sparse_vector.hpp:59