Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
pb_variable.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 PB_VARIABLE_TCC_
9 #define PB_VARIABLE_TCC_
10 #include <cassert>
11 #include <libff/common/utils.hpp>
12 #include <libsnark/gadgetlib1/protoboard.hpp>
13 
14 namespace libsnark
15 {
16 
17 template<typename FieldT>
18 void pb_variable<FieldT>::allocate(
19  protoboard<FieldT> &pb, const std::string &annotation)
20 {
21  this->index = pb.allocate_var_index(annotation);
22 }
23 
24 /* allocates pb_variable<FieldT> array in MSB->LSB order */
25 template<typename FieldT>
26 void pb_variable_array<FieldT>::allocate(
27  protoboard<FieldT> &pb,
28  const size_t n,
29  const std::string &annotation_prefix)
30 {
31  // The DEBUG variable controls whether or not the FMT macro actually
32  // performs string concatenation or simply returns "". Therefore, even
33  // though gadget code may always set an annotation, it may appear as ""
34  // unless DEBUG is set.
35  //
36  // TODO: control annotations via a variable such as
37  // LIBSNARK_ENABLE_ANNOTATIONS.
38 #ifdef DEBUG
39  assert(annotation_prefix != "");
40 #endif
41  (*this).resize(n);
42 
43  for (size_t i = 0; i < n; ++i) {
44  (*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i));
45  }
46 }
47 
48 template<typename FieldT>
49 void pb_variable_array<FieldT>::fill_with_field_elements(
50  protoboard<FieldT> &pb, const std::vector<FieldT> &vals) const
51 {
52  assert(this->size() == vals.size());
53  for (size_t i = 0; i < vals.size(); ++i) {
54  pb.val((*this)[i]) = vals[i];
55  }
56 }
57 
58 template<typename FieldT>
59 void pb_variable_array<FieldT>::fill_with_bits(
60  protoboard<FieldT> &pb, const libff::bit_vector &bits) const
61 {
62  assert(this->size() == bits.size());
63  for (size_t i = 0; i < bits.size(); ++i) {
64  pb.val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero());
65  }
66 }
67 
68 template<typename FieldT>
69 void pb_variable_array<FieldT>::fill_with_bits_of_field_element(
70  protoboard<FieldT> &pb, const FieldT &r) const
71 {
72  const libff::bigint<FieldT::num_limbs> rint = r.as_bigint();
73  for (size_t i = 0; i < this->size(); ++i) {
74  pb.val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero();
75  }
76 }
77 
78 template<typename FieldT>
79 void pb_variable_array<FieldT>::fill_with_bits_of_ulong(
80  protoboard<FieldT> &pb, const unsigned long i) const
81 {
82  this->fill_with_bits_of_field_element(pb, FieldT(i, true));
83 }
84 
85 template<typename FieldT>
86 std::vector<FieldT> pb_variable_array<FieldT>::get_vals(
87  const protoboard<FieldT> &pb) const
88 {
89  std::vector<FieldT> result(this->size());
90  for (size_t i = 0; i < this->size(); ++i) {
91  result[i] = pb.val((*this)[i]);
92  }
93  return result;
94 }
95 
96 template<typename FieldT>
97 libff::bit_vector pb_variable_array<FieldT>::get_bits(
98  const protoboard<FieldT> &pb) const
99 {
100  libff::bit_vector result;
101  for (size_t i = 0; i < this->size(); ++i) {
102  const FieldT v = pb.val((*this)[i]);
103  assert(v == FieldT::zero() || v == FieldT::one());
104  result.push_back(v == FieldT::one());
105  }
106  return result;
107 }
108 
109 template<typename FieldT>
110 FieldT pb_variable_array<FieldT>::get_field_element_from_bits(
111  const protoboard<FieldT> &pb) const
112 {
113  FieldT result = FieldT::zero();
114 
115  for (size_t i = 0; i < this->size(); ++i) {
116  /* push in the new bit */
117  const FieldT v = pb.val((*this)[this->size() - 1 - i]);
118  assert(v == FieldT::zero() || v == FieldT::one());
119  result += result + v;
120  }
121 
122  return result;
123 }
124 
125 template<typename FieldT> pb_linear_combination<FieldT>::pb_linear_combination()
126 {
127  this->is_variable = false;
128 }
129 
130 template<typename FieldT>
131 pb_linear_combination<FieldT>::pb_linear_combination(
132  const pb_variable<FieldT> &var)
133 {
134  this->is_variable = true;
135  this->index = var.index;
136  this->terms.emplace_back(linear_term<FieldT>(var));
137 }
138 
139 template<typename FieldT>
140 void pb_linear_combination<FieldT>::assign(
141  protoboard<FieldT> &pb, const linear_combination<FieldT> &lc)
142 {
143  assert(this->is_variable == false);
144  this->index = pb.allocate_lc_index();
145  this->terms = lc.terms;
146 }
147 
148 template<typename FieldT>
149 void pb_linear_combination<FieldT>::evaluate(protoboard<FieldT> &pb) const
150 {
151  if (this->is_variable) {
152  return; // do nothing
153  }
154 
155  FieldT sum = 0;
156  for (auto term : this->terms) {
157  sum += term.coeff * pb.val(pb_variable<FieldT>(term.index));
158  }
159 
160  pb.lc_val(*this) = sum;
161 }
162 
163 template<typename FieldT>
164 bool pb_linear_combination<FieldT>::is_constant() const
165 {
166  if (is_variable) {
167  return (index == 0);
168  } else {
169  for (auto term : this->terms) {
170  if (term.index != 0) {
171  return false;
172  }
173  }
174 
175  return true;
176  }
177 }
178 
179 template<typename FieldT>
180 FieldT pb_linear_combination<FieldT>::constant_term() const
181 {
182  if (is_variable) {
183  return (index == 0 ? FieldT::one() : FieldT::zero());
184  } else {
185  FieldT result = FieldT::zero();
186  for (auto term : this->terms) {
187  if (term.index == 0) {
188  result += term.coeff;
189  }
190  }
191  return result;
192  }
193 }
194 
195 template<typename FieldT>
196 void pb_linear_combination_array<FieldT>::evaluate(protoboard<FieldT> &pb) const
197 {
198  for (size_t i = 0; i < this->size(); ++i) {
199  (*this)[i].evaluate(pb);
200  }
201 }
202 
203 template<typename FieldT>
204 void pb_linear_combination_array<FieldT>::fill_with_field_elements(
205  protoboard<FieldT> &pb, const std::vector<FieldT> &vals) const
206 {
207  assert(this->size() == vals.size());
208  for (size_t i = 0; i < vals.size(); ++i) {
209  pb.lc_val((*this)[i]) = vals[i];
210  }
211 }
212 
213 template<typename FieldT>
214 void pb_linear_combination_array<FieldT>::fill_with_bits(
215  protoboard<FieldT> &pb, const libff::bit_vector &bits) const
216 {
217  assert(this->size() == bits.size());
218  for (size_t i = 0; i < bits.size(); ++i) {
219  pb.lc_val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero());
220  }
221 }
222 
223 template<typename FieldT>
224 void pb_linear_combination_array<FieldT>::fill_with_bits_of_field_element(
225  protoboard<FieldT> &pb, const FieldT &r) const
226 {
227  const libff::bigint<FieldT::num_limbs> rint = r.as_bigint();
228  for (size_t i = 0; i < this->size(); ++i) {
229  pb.lc_val((*this)[i]) =
230  rint.test_bit(i) ? FieldT::one() : FieldT::zero();
231  }
232 }
233 
234 template<typename FieldT>
235 void pb_linear_combination_array<FieldT>::fill_with_bits_of_ulong(
236  protoboard<FieldT> &pb, const unsigned long i) const
237 {
238  this->fill_with_bits_of_field_element(pb, FieldT(i));
239 }
240 
241 template<typename FieldT>
242 std::vector<FieldT> pb_linear_combination_array<FieldT>::get_vals(
243  const protoboard<FieldT> &pb) const
244 {
245  std::vector<FieldT> result(this->size());
246  for (size_t i = 0; i < this->size(); ++i) {
247  result[i] = pb.lc_val((*this)[i]);
248  }
249  return result;
250 }
251 
252 template<typename FieldT>
253 libff::bit_vector pb_linear_combination_array<FieldT>::get_bits(
254  const protoboard<FieldT> &pb) const
255 {
256  libff::bit_vector result;
257  for (size_t i = 0; i < this->size(); ++i) {
258  const FieldT v = pb.lc_val((*this)[i]);
259  assert(v == FieldT::zero() || v == FieldT::one());
260  result.push_back(v == FieldT::one());
261  }
262  return result;
263 }
264 
265 template<typename FieldT>
266 FieldT pb_linear_combination_array<FieldT>::get_field_element_from_bits(
267  const protoboard<FieldT> &pb) const
268 {
269  FieldT result = FieldT::zero();
270 
271  for (size_t i = 0; i < this->size(); ++i) {
272  /* push in the new bit */
273  const FieldT v = pb.lc_val((*this)[this->size() - 1 - i]);
274  assert(v == FieldT::zero() || v == FieldT::one());
275  result += result + v;
276  }
277 
278  return result;
279 }
280 
281 template<typename FieldT>
282 pb_variable<FieldT> pb_variable_allocate(
283  protoboard<FieldT> &pb, const std::string &annotation)
284 {
285  pb_variable<FieldT> var;
286  var.allocate(pb, annotation);
287  return var;
288 }
289 
290 template<typename FieldT>
291 linear_combination<FieldT> pb_sum(const pb_linear_combination_array<FieldT> &v)
292 {
293  linear_combination<FieldT> result;
294  for (auto &term : v) {
295  result = result + term;
296  }
297 
298  return result;
299 }
300 
301 template<typename FieldT>
302 linear_combination<FieldT> pb_packing_sum(
303  const pb_linear_combination_array<FieldT> &v)
304 {
305  FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration
306  std::vector<linear_term<FieldT>> all_terms;
307  for (auto &lc : v) {
308  for (auto &term : lc.terms) {
309  all_terms.emplace_back(twoi * term);
310  }
311  twoi += twoi;
312  }
313 
314  return linear_combination<FieldT>(all_terms);
315 }
316 
317 template<typename FieldT>
318 linear_combination<FieldT> pb_coeff_sum(
319  const pb_linear_combination_array<FieldT> &v,
320  const std::vector<FieldT> &coeffs)
321 {
322  assert(v.size() == coeffs.size());
323  std::vector<linear_term<FieldT>> all_terms;
324 
325  auto coeff_it = coeffs.begin();
326  for (auto &lc : v) {
327  for (auto &term : lc.terms) {
328  all_terms.emplace_back((*coeff_it) * term);
329  }
330  ++coeff_it;
331  }
332 
333  return linear_combination<FieldT>(all_terms);
334 }
335 
336 } // namespace libsnark
337 #endif // PB_VARIABLE_TCC