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 PB_VARIABLE_TCC_
9 #define PB_VARIABLE_TCC_
11 #include <libff/common/utils.hpp>
12 #include <libsnark/gadgetlib1/protoboard.hpp>
17 template<typename FieldT>
18 void pb_variable<FieldT>::allocate(
19 protoboard<FieldT> &pb, const std::string &annotation)
21 this->index = pb.allocate_var_index(annotation);
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,
29 const std::string &annotation_prefix)
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.
36 // TODO: control annotations via a variable such as
37 // LIBSNARK_ENABLE_ANNOTATIONS.
39 assert(annotation_prefix != "");
43 for (size_t i = 0; i < n; ++i) {
44 (*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i));
48 template<typename FieldT>
49 void pb_variable_array<FieldT>::fill_with_field_elements(
50 protoboard<FieldT> &pb, const std::vector<FieldT> &vals) const
52 assert(this->size() == vals.size());
53 for (size_t i = 0; i < vals.size(); ++i) {
54 pb.val((*this)[i]) = vals[i];
58 template<typename FieldT>
59 void pb_variable_array<FieldT>::fill_with_bits(
60 protoboard<FieldT> &pb, const libff::bit_vector &bits) const
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());
68 template<typename FieldT>
69 void pb_variable_array<FieldT>::fill_with_bits_of_field_element(
70 protoboard<FieldT> &pb, const FieldT &r) const
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();
78 template<typename FieldT>
79 void pb_variable_array<FieldT>::fill_with_bits_of_ulong(
80 protoboard<FieldT> &pb, const unsigned long i) const
82 this->fill_with_bits_of_field_element(pb, FieldT(i, true));
85 template<typename FieldT>
86 std::vector<FieldT> pb_variable_array<FieldT>::get_vals(
87 const protoboard<FieldT> &pb) const
89 std::vector<FieldT> result(this->size());
90 for (size_t i = 0; i < this->size(); ++i) {
91 result[i] = pb.val((*this)[i]);
96 template<typename FieldT>
97 libff::bit_vector pb_variable_array<FieldT>::get_bits(
98 const protoboard<FieldT> &pb) const
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());
109 template<typename FieldT>
110 FieldT pb_variable_array<FieldT>::get_field_element_from_bits(
111 const protoboard<FieldT> &pb) const
113 FieldT result = FieldT::zero();
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;
125 template<typename FieldT> pb_linear_combination<FieldT>::pb_linear_combination()
127 this->is_variable = false;
130 template<typename FieldT>
131 pb_linear_combination<FieldT>::pb_linear_combination(
132 const pb_variable<FieldT> &var)
134 this->is_variable = true;
135 this->index = var.index;
136 this->terms.emplace_back(linear_term<FieldT>(var));
139 template<typename FieldT>
140 void pb_linear_combination<FieldT>::assign(
141 protoboard<FieldT> &pb, const linear_combination<FieldT> &lc)
143 assert(this->is_variable == false);
144 this->index = pb.allocate_lc_index();
145 this->terms = lc.terms;
148 template<typename FieldT>
149 void pb_linear_combination<FieldT>::evaluate(protoboard<FieldT> &pb) const
151 if (this->is_variable) {
152 return; // do nothing
156 for (auto term : this->terms) {
157 sum += term.coeff * pb.val(pb_variable<FieldT>(term.index));
160 pb.lc_val(*this) = sum;
163 template<typename FieldT>
164 bool pb_linear_combination<FieldT>::is_constant() const
169 for (auto term : this->terms) {
170 if (term.index != 0) {
179 template<typename FieldT>
180 FieldT pb_linear_combination<FieldT>::constant_term() const
183 return (index == 0 ? FieldT::one() : FieldT::zero());
185 FieldT result = FieldT::zero();
186 for (auto term : this->terms) {
187 if (term.index == 0) {
188 result += term.coeff;
195 template<typename FieldT>
196 void pb_linear_combination_array<FieldT>::evaluate(protoboard<FieldT> &pb) const
198 for (size_t i = 0; i < this->size(); ++i) {
199 (*this)[i].evaluate(pb);
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
207 assert(this->size() == vals.size());
208 for (size_t i = 0; i < vals.size(); ++i) {
209 pb.lc_val((*this)[i]) = vals[i];
213 template<typename FieldT>
214 void pb_linear_combination_array<FieldT>::fill_with_bits(
215 protoboard<FieldT> &pb, const libff::bit_vector &bits) const
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());
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
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();
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
238 this->fill_with_bits_of_field_element(pb, FieldT(i));
241 template<typename FieldT>
242 std::vector<FieldT> pb_linear_combination_array<FieldT>::get_vals(
243 const protoboard<FieldT> &pb) const
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]);
252 template<typename FieldT>
253 libff::bit_vector pb_linear_combination_array<FieldT>::get_bits(
254 const protoboard<FieldT> &pb) const
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());
265 template<typename FieldT>
266 FieldT pb_linear_combination_array<FieldT>::get_field_element_from_bits(
267 const protoboard<FieldT> &pb) const
269 FieldT result = FieldT::zero();
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;
281 template<typename FieldT>
282 pb_variable<FieldT> pb_variable_allocate(
283 protoboard<FieldT> &pb, const std::string &annotation)
285 pb_variable<FieldT> var;
286 var.allocate(pb, annotation);
290 template<typename FieldT>
291 linear_combination<FieldT> pb_sum(const pb_linear_combination_array<FieldT> &v)
293 linear_combination<FieldT> result;
294 for (auto &term : v) {
295 result = result + term;
301 template<typename FieldT>
302 linear_combination<FieldT> pb_packing_sum(
303 const pb_linear_combination_array<FieldT> &v)
305 FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration
306 std::vector<linear_term<FieldT>> all_terms;
308 for (auto &term : lc.terms) {
309 all_terms.emplace_back(twoi * term);
314 return linear_combination<FieldT>(all_terms);
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)
322 assert(v.size() == coeffs.size());
323 std::vector<linear_term<FieldT>> all_terms;
325 auto coeff_it = coeffs.begin();
327 for (auto &term : lc.terms) {
328 all_terms.emplace_back((*coeff_it) * term);
333 return linear_combination<FieldT>(all_terms);
336 } // namespace libsnark
337 #endif // PB_VARIABLE_TCC