Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
knapsack_gadget.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for the knapsack gadget.
5 
6  See knapsack_gadget.hpp .
7 
8  *****************************************************************************
9  * @author This file is part of libsnark, developed by SCIPR Lab
10  * and contributors (see AUTHORS).
11  * @copyright MIT license (see LICENSE file)
12  *****************************************************************************/
13 
14 #ifndef KNAPSACK_GADGET_TCC_
15 #define KNAPSACK_GADGET_TCC_
16 
17 #include <libff/algebra/fields/field_utils.hpp>
18 #include <libff/common/rng.hpp>
19 
20 namespace libsnark
21 {
22 
23 template<typename FieldT>
24 std::vector<FieldT>
25  knapsack_CRH_with_field_out_gadget<FieldT>::knapsack_coefficients;
26 template<typename FieldT>
27 size_t knapsack_CRH_with_field_out_gadget<FieldT>::num_cached_coefficients;
28 
29 template<typename FieldT>
30 knapsack_CRH_with_field_out_gadget<FieldT>::knapsack_CRH_with_field_out_gadget(
31  protoboard<FieldT> &pb,
32  const size_t input_len,
33  const block_variable<FieldT> &input_block,
34  const pb_linear_combination_array<FieldT> &output,
35  const std::string &annotation_prefix)
36  : gadget<FieldT>(pb, annotation_prefix)
37  , input_len(input_len)
38  , dimension(knapsack_dimension<FieldT>::dimension)
39  , input_block(input_block)
40  , output(output)
41 {
42  assert(input_block.bits.size() == input_len);
43  if (num_cached_coefficients < dimension * input_len) {
44  sample_randomness(input_len);
45  }
46  assert(output.size() == this->get_digest_len());
47 }
48 
49 template<typename FieldT>
50 void knapsack_CRH_with_field_out_gadget<FieldT>::generate_r1cs_constraints()
51 {
52  for (size_t i = 0; i < dimension; ++i) {
53  this->pb.add_r1cs_constraint(
54  r1cs_constraint<FieldT>(
55  1,
56  pb_coeff_sum<FieldT>(
57  input_block.bits,
58  std::vector<FieldT>(
59  knapsack_coefficients.begin() + input_len * i,
60  knapsack_coefficients.begin() + input_len * (i + 1))),
61  output[i]),
62  FMT(this->annotation_prefix, " knapsack_%zu", i));
63  }
64 }
65 
66 template<typename FieldT>
67 void knapsack_CRH_with_field_out_gadget<FieldT>::generate_r1cs_witness()
68 {
69  const libff::bit_vector input = input_block.get_block();
70 
71  for (size_t i = 0; i < dimension; ++i) {
72  FieldT sum = FieldT::zero();
73  for (size_t k = 0; k < input_len; ++k) {
74  if (input[k]) {
75  sum += knapsack_coefficients[input_len * i + k];
76  }
77  }
78 
79  this->pb.lc_val(output[i]) = sum;
80  }
81 }
82 
83 template<typename FieldT>
84 size_t knapsack_CRH_with_field_out_gadget<FieldT>::get_digest_len()
85 {
86  return knapsack_dimension<FieldT>::dimension;
87 }
88 
89 template<typename FieldT>
90 size_t knapsack_CRH_with_field_out_gadget<FieldT>::get_block_len()
91 {
92  return 0;
93 }
94 
95 template<typename FieldT>
96 std::vector<FieldT> knapsack_CRH_with_field_out_gadget<FieldT>::get_hash(
97  const libff::bit_vector &input)
98 {
99  const size_t dimension = knapsack_dimension<FieldT>::dimension;
100  if (num_cached_coefficients < dimension * input.size()) {
101  sample_randomness(input.size());
102  }
103 
104  std::vector<FieldT> result(dimension, FieldT::zero());
105 
106  for (size_t i = 0; i < dimension; ++i) {
107  for (size_t k = 0; k < input.size(); ++k) {
108  if (input[k]) {
109  result[i] += knapsack_coefficients[input.size() * i + k];
110  }
111  }
112  }
113 
114  return result;
115 }
116 
117 template<typename FieldT>
118 size_t knapsack_CRH_with_field_out_gadget<FieldT>::expected_constraints()
119 {
120  return knapsack_dimension<FieldT>::dimension;
121 }
122 
123 template<typename FieldT>
124 void knapsack_CRH_with_field_out_gadget<FieldT>::sample_randomness(
125  const size_t input_len)
126 {
127  const size_t num_coefficients =
128  knapsack_dimension<FieldT>::dimension * input_len;
129  if (num_coefficients > num_cached_coefficients) {
130  knapsack_coefficients.resize(num_coefficients);
131  for (size_t i = num_cached_coefficients; i < num_coefficients; ++i) {
132  knapsack_coefficients[i] = libff::SHA512_rng<FieldT>(i);
133  }
134  num_cached_coefficients = num_coefficients;
135  }
136 }
137 
138 template<typename FieldT>
139 knapsack_CRH_with_bit_out_gadget<FieldT>::knapsack_CRH_with_bit_out_gadget(
140  protoboard<FieldT> &pb,
141  const size_t input_len,
142  const block_variable<FieldT> &input_block,
143  const digest_variable<FieldT> &output_digest,
144  const std::string &annotation_prefix)
145  : gadget<FieldT>(pb, annotation_prefix)
146  , input_len(input_len)
147  , dimension(knapsack_dimension<FieldT>::dimension)
148  , input_block(input_block)
149  , output_digest(output_digest)
150 {
151  assert(output_digest.bits.size() == this->get_digest_len());
152 
153  output.resize(dimension);
154 
155  for (size_t i = 0; i < dimension; ++i) {
156  output[i].assign(
157  pb,
158  pb_packing_sum<FieldT>(pb_variable_array<FieldT>(
159  output_digest.bits.begin() + i * FieldT::size_in_bits(),
160  output_digest.bits.begin() +
161  (i + 1) * FieldT::size_in_bits())));
162  }
163 
164  hasher.reset(new knapsack_CRH_with_field_out_gadget<FieldT>(
165  pb, input_len, input_block, output, FMT(annotation_prefix, " hasher")));
166 }
167 
168 template<typename FieldT>
169 void knapsack_CRH_with_bit_out_gadget<FieldT>::generate_r1cs_constraints(
170  const bool enforce_bitness)
171 {
172  hasher->generate_r1cs_constraints();
173 
174  if (enforce_bitness) {
175  for (size_t k = 0; k < output_digest.bits.size(); ++k) {
176  generate_boolean_r1cs_constraint<FieldT>(
177  this->pb,
178  output_digest.bits[k],
179  FMT(this->annotation_prefix, " output_digest_%zu", k));
180  }
181  }
182 }
183 
184 template<typename FieldT>
185 void knapsack_CRH_with_bit_out_gadget<FieldT>::generate_r1cs_witness()
186 {
187  hasher->generate_r1cs_witness();
188 
189  /* do unpacking in place */
190  const libff::bit_vector input = input_block.bits.get_bits(this->pb);
191  for (size_t i = 0; i < dimension; ++i) {
192  pb_variable_array<FieldT> va(
193  output_digest.bits.begin() + i * FieldT::size_in_bits(),
194  output_digest.bits.begin() + (i + 1) * FieldT::size_in_bits());
195  va.fill_with_bits_of_field_element(
196  this->pb, this->pb.lc_val(output[i]));
197  }
198 }
199 
200 template<typename FieldT>
201 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::get_digest_len()
202 {
203  return knapsack_dimension<FieldT>::dimension * FieldT::size_in_bits();
204 }
205 
206 template<typename FieldT>
207 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::get_block_len()
208 {
209  return 0;
210 }
211 
212 template<typename FieldT>
213 libff::bit_vector knapsack_CRH_with_bit_out_gadget<FieldT>::get_hash(
214  const libff::bit_vector &input)
215 {
216  const std::vector<FieldT> hash_elems =
217  knapsack_CRH_with_field_out_gadget<FieldT>::get_hash(input);
218  hash_value_type result;
219 
220  for (const FieldT &elt : hash_elems) {
221  libff::bit_vector elt_bits =
222  libff::convert_field_element_to_bit_vector<FieldT>(elt);
223  result.insert(result.end(), elt_bits.begin(), elt_bits.end());
224  }
225 
226  return result;
227 }
228 
229 template<typename FieldT>
230 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::expected_constraints(
231  const bool enforce_bitness)
232 {
233  const size_t hasher_constraints =
234  knapsack_CRH_with_field_out_gadget<FieldT>::expected_constraints();
235  const size_t bitness_constraints = (enforce_bitness ? get_digest_len() : 0);
236  return hasher_constraints + bitness_constraints;
237 }
238 
239 template<typename FieldT>
240 void knapsack_CRH_with_bit_out_gadget<FieldT>::sample_randomness(
241  const size_t input_len)
242 {
243  knapsack_CRH_with_field_out_gadget<FieldT>::sample_randomness(input_len);
244 }
245 
246 template<typename FieldT>
247 void test_knapsack_CRH_with_bit_out_gadget_internal(
248  const size_t dimension,
249  const libff::bit_vector &input_bits,
250  const libff::bit_vector &digest_bits)
251 {
252  assert(knapsack_dimension<FieldT>::dimension == dimension);
253  knapsack_CRH_with_bit_out_gadget<FieldT>::sample_randomness(
254  input_bits.size());
255  protoboard<FieldT> pb;
256 
257  block_variable<FieldT> input_block(pb, input_bits.size(), "input_block");
258  digest_variable<FieldT> output_digest(
259  pb,
260  knapsack_CRH_with_bit_out_gadget<FieldT>::get_digest_len(),
261  "output_digest");
262  knapsack_CRH_with_bit_out_gadget<FieldT> H(
263  pb, input_bits.size(), input_block, output_digest, "H");
264 
265  input_block.generate_r1cs_witness(input_bits);
266  H.generate_r1cs_constraints();
267  H.generate_r1cs_witness();
268 
269  assert(output_digest.get_digest().size() == digest_bits.size());
270  assert(pb.is_satisfied());
271 
272  const size_t num_constraints = pb.num_constraints();
273  const size_t expected_constraints =
274  knapsack_CRH_with_bit_out_gadget<FieldT>::expected_constraints();
275  assert(num_constraints == expected_constraints);
276 
277 #ifdef NDEBUG
278  libff::UNUSED(dimension);
279  libff::UNUSED(digest_bits);
280  libff::UNUSED(num_constraints);
281  libff::UNUSED(expected_constraints);
282 #endif
283 }
284 
285 } // namespace libsnark
286 
287 #endif // KNAPSACK_GADGET_TCC_