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 *****************************************************************************/
8 #ifndef KC_MULTIEXP_TCC_
9 #define KC_MULTIEXP_TCC_
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)
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));
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,
35 typename std::vector<FieldT>::const_iterator scalar_start,
36 typename std::vector<FieldT>::const_iterator scalar_end,
39 libff::enter_block("Process scalar vector");
41 std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx);
42 const size_t offset = index_it - vec.indices.begin();
44 auto value_it = vec.values.begin() + offset;
46 const FieldT zero = FieldT::zero();
47 const FieldT one = FieldT::one();
49 std::vector<FieldT> p;
50 std::vector<knowledge_commitment<T1, T2>> g;
52 knowledge_commitment<T1, T2> acc = knowledge_commitment<T1, T2>::zero();
59 const size_t scalar_length = std::distance(scalar_start, scalar_end);
61 libff::UNUSED(scalar_end);
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);
67 const FieldT scalar = *(scalar_start + scalar_position);
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);
77 acc.g = acc.g + value_it->g;
78 acc.h = acc.h + value_it->h;
82 p.emplace_back(scalar);
83 g.emplace_back(*value_it);
91 libff::print_indent();
93 "* Elements of w skipped: %zu (%0.2f%%)\n",
95 100. * num_skip / (num_skip + num_add + num_other));
96 libff::print_indent();
98 "* Elements of w processed with special addition: %zu (%0.2f%%)\n",
100 100. * num_add / (num_skip + num_add + num_other));
101 libff::print_indent();
103 "* Elements of w remaining: %zu (%0.2f%%)\n",
105 100. * num_other / (num_skip + num_add + num_other));
106 libff::leave_block("Process scalar vector");
108 return acc + libff::multi_exp<
109 knowledge_commitment<T1, T2>,
112 BaseForm>(g.begin(), g.end(), p.begin(), p.end(), chunks);
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)
129 knowledge_commitment_vector<T1, T2> res;
131 res.values.reserve(expected_size);
132 res.indices.reserve(expected_size);
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>(
138 scalar_size, T1_window, T1_table, T1_coeff * v[pos]),
140 scalar_size, T2_window, T2_table, T2_coeff * v[pos])));
141 res.indices.emplace_back(pos);
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,
161 knowledge_commitment_vector<T1, T2> res;
162 res.domain_size_ = v.size();
165 for (size_t i = 0; i < v.size(); ++i) {
166 nonzero += (v[i].is_zero() ? 0 : 1);
169 const size_t num_chunks =
170 std::max((size_t)1, std::min(nonzero, suggested_num_chunks));
172 if (!libff::inhibit_profiling_info) {
173 libff::print_indent();
175 "Non-zero coordinate count: %zu/%zu (%0.2f%%)\n",
178 100. * nonzero / v.size());
181 std::vector<knowledge_commitment_vector<T1, T2>> tmp(num_chunks);
182 std::vector<size_t> chunk_pos(num_chunks + 1);
184 const size_t chunk_size = nonzero / num_chunks;
185 const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1);
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;
201 chunk_pos[num_chunks] = v.size();
204 #pragma omp parallel for
206 for (size_t i = 0; i < num_chunks; ++i) {
207 tmp[i] = kc_batch_exp_internal<T1, T2, FieldT>(
218 i == num_chunks - 1 ? last_chunk : chunk_size);
219 if (output_special) {
220 libff::batch_to_special<knowledge_commitment<T1, T2>>(
225 if (num_chunks == 1) {
226 tmp[0].domain_size_ = v.size();
229 for (size_t i = 0; i < num_chunks; ++i) {
231 res.values.end(), tmp[i].values.begin(), tmp[i].values.end());
234 tmp[i].indices.begin(),
235 tmp[i].indices.end());
241 } // namespace libsnark
243 #endif // KC_MULTIEXP_TCC_