2 *****************************************************************************
4 Implementation of interfaces for the knapsack gadget.
6 See knapsack_gadget.hpp .
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 *****************************************************************************/
14 #ifndef KNAPSACK_GADGET_TCC_
15 #define KNAPSACK_GADGET_TCC_
17 #include <libff/algebra/fields/field_utils.hpp>
18 #include <libff/common/rng.hpp>
23 template<typename 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;
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)
42 assert(input_block.bits.size() == input_len);
43 if (num_cached_coefficients < dimension * input_len) {
44 sample_randomness(input_len);
46 assert(output.size() == this->get_digest_len());
49 template<typename FieldT>
50 void knapsack_CRH_with_field_out_gadget<FieldT>::generate_r1cs_constraints()
52 for (size_t i = 0; i < dimension; ++i) {
53 this->pb.add_r1cs_constraint(
54 r1cs_constraint<FieldT>(
59 knapsack_coefficients.begin() + input_len * i,
60 knapsack_coefficients.begin() + input_len * (i + 1))),
62 FMT(this->annotation_prefix, " knapsack_%zu", i));
66 template<typename FieldT>
67 void knapsack_CRH_with_field_out_gadget<FieldT>::generate_r1cs_witness()
69 const libff::bit_vector input = input_block.get_block();
71 for (size_t i = 0; i < dimension; ++i) {
72 FieldT sum = FieldT::zero();
73 for (size_t k = 0; k < input_len; ++k) {
75 sum += knapsack_coefficients[input_len * i + k];
79 this->pb.lc_val(output[i]) = sum;
83 template<typename FieldT>
84 size_t knapsack_CRH_with_field_out_gadget<FieldT>::get_digest_len()
86 return knapsack_dimension<FieldT>::dimension;
89 template<typename FieldT>
90 size_t knapsack_CRH_with_field_out_gadget<FieldT>::get_block_len()
95 template<typename FieldT>
96 std::vector<FieldT> knapsack_CRH_with_field_out_gadget<FieldT>::get_hash(
97 const libff::bit_vector &input)
99 const size_t dimension = knapsack_dimension<FieldT>::dimension;
100 if (num_cached_coefficients < dimension * input.size()) {
101 sample_randomness(input.size());
104 std::vector<FieldT> result(dimension, FieldT::zero());
106 for (size_t i = 0; i < dimension; ++i) {
107 for (size_t k = 0; k < input.size(); ++k) {
109 result[i] += knapsack_coefficients[input.size() * i + k];
117 template<typename FieldT>
118 size_t knapsack_CRH_with_field_out_gadget<FieldT>::expected_constraints()
120 return knapsack_dimension<FieldT>::dimension;
123 template<typename FieldT>
124 void knapsack_CRH_with_field_out_gadget<FieldT>::sample_randomness(
125 const size_t input_len)
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);
134 num_cached_coefficients = num_coefficients;
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)
151 assert(output_digest.bits.size() == this->get_digest_len());
153 output.resize(dimension);
155 for (size_t i = 0; i < dimension; ++i) {
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())));
164 hasher.reset(new knapsack_CRH_with_field_out_gadget<FieldT>(
165 pb, input_len, input_block, output, FMT(annotation_prefix, " hasher")));
168 template<typename FieldT>
169 void knapsack_CRH_with_bit_out_gadget<FieldT>::generate_r1cs_constraints(
170 const bool enforce_bitness)
172 hasher->generate_r1cs_constraints();
174 if (enforce_bitness) {
175 for (size_t k = 0; k < output_digest.bits.size(); ++k) {
176 generate_boolean_r1cs_constraint<FieldT>(
178 output_digest.bits[k],
179 FMT(this->annotation_prefix, " output_digest_%zu", k));
184 template<typename FieldT>
185 void knapsack_CRH_with_bit_out_gadget<FieldT>::generate_r1cs_witness()
187 hasher->generate_r1cs_witness();
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]));
200 template<typename FieldT>
201 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::get_digest_len()
203 return knapsack_dimension<FieldT>::dimension * FieldT::size_in_bits();
206 template<typename FieldT>
207 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::get_block_len()
212 template<typename FieldT>
213 libff::bit_vector knapsack_CRH_with_bit_out_gadget<FieldT>::get_hash(
214 const libff::bit_vector &input)
216 const std::vector<FieldT> hash_elems =
217 knapsack_CRH_with_field_out_gadget<FieldT>::get_hash(input);
218 hash_value_type result;
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());
229 template<typename FieldT>
230 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::expected_constraints(
231 const bool enforce_bitness)
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;
239 template<typename FieldT>
240 void knapsack_CRH_with_bit_out_gadget<FieldT>::sample_randomness(
241 const size_t input_len)
243 knapsack_CRH_with_field_out_gadget<FieldT>::sample_randomness(input_len);
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)
252 assert(knapsack_dimension<FieldT>::dimension == dimension);
253 knapsack_CRH_with_bit_out_gadget<FieldT>::sample_randomness(
255 protoboard<FieldT> pb;
257 block_variable<FieldT> input_block(pb, input_bits.size(), "input_block");
258 digest_variable<FieldT> output_digest(
260 knapsack_CRH_with_bit_out_gadget<FieldT>::get_digest_len(),
262 knapsack_CRH_with_bit_out_gadget<FieldT> H(
263 pb, input_bits.size(), input_block, output_digest, "H");
265 input_block.generate_r1cs_witness(input_bits);
266 H.generate_r1cs_constraints();
267 H.generate_r1cs_witness();
269 assert(output_digest.get_digest().size() == digest_bits.size());
270 assert(pb.is_satisfied());
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);
278 libff::UNUSED(dimension);
279 libff::UNUSED(digest_bits);
280 libff::UNUSED(num_constraints);
281 libff::UNUSED(expected_constraints);
285 } // namespace libsnark
287 #endif // KNAPSACK_GADGET_TCC_