knapsack_component.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 // @file Declaration of interfaces for the knapsack component.
26 //
27 // The component checks the correct execution of a knapsack (modular subset-sum) over
28 // the field specified in the template parameter. With suitable choices of parameters
29 // such knapsacks are collision-resistant hashes (CRHs). See \[Ajt96] and \[GGH96].
30 //
31 // Given two positive integers m (the input length) and d (the dimension),
32 // and a matrix M over the field F and of dimension dxm, the hash H_M maps {0,1}^m
33 // to F^d by sending x to M*x. Security of the function (very roughly) depends on
34 // d*log(|F|).
35 //
36 // Below, we give two different components:
37 // - knapsack_crh_with_field_out_component, which verifies H_M
38 // - knapsack_crh_with_bit_out_component, which verifies H_M when its output is "expanded" to bits.
39 // In both cases, a method ("sample_randomness") allows to sample M.
40 //
41 // The parameter d (the dimension) is fixed at compile time in the struct
42 // knapsack_dimension below. The parameter m (the input length) can be chosen
43 // at run time (in either component).
44 //
45 //
46 // References:
47 //
48 // \[Ajt96]:
49 // "Generating hard instances of lattice problems",
50 // Miklos Ajtai,
51 // STOC 1996
52 //
53 // \[GGH96]:
54 // "Collision-free hashing from lattice problems",
55 // Oded Goldreich, Shafi Goldwasser, Shai Halevi,
56 // ECCC TR95-042
57 //---------------------------------------------------------------------------//
58 
59 #ifndef CRYPTO3_ZK_BLUEPRINT_KNAPSACK_COMPONENT_HPP
60 #define CRYPTO3_ZK_BLUEPRINT_KNAPSACK_COMPONENT_HPP
61 
63 
64 #include <nil/crypto3/random/hash.hpp>
65 
67 
70 
71 namespace nil {
72  namespace crypto3 {
73  namespace zk {
74  namespace components {
75 
76  /************************** Choice of dimension ******************************/
77 
78  template<typename FieldType>
80  // the size of typename FieldType::value_type should be (approximately) at least 200 bits
81  static const std::size_t dimension = 1;
82  };
83 
84  /*********************** Knapsack with field output **************************/
85 
86  template<typename FieldType>
88  private:
89  static std::vector<typename FieldType::value_type> knapsack_coefficients;
90  static std::size_t num_cached_coefficients;
91 
92  public:
93  typedef std::vector<typename FieldType::value_type> hash_value_type;
95  std::size_t input_len;
96  std::size_t dimension;
97 
100 
103  std::size_t input_len,
106  component<FieldType>(bp),
109  BOOST_ASSERT(input_block.bits.size() == input_len);
110  if (num_cached_coefficients < dimension * input_len) {
112  }
113  BOOST_ASSERT(output.size() == this->get_digest_len());
114  }
116  for (std::size_t i = 0; i < dimension; ++i) {
117  this->bp.add_r1cs_constraint(snark::r1cs_constraint<FieldType>(
118  1,
119  blueprint_coeff_sum<FieldType>(
120  input_block.bits,
121  std::vector<typename FieldType::value_type>(
122  knapsack_coefficients.begin() + input_len * i,
123  knapsack_coefficients.begin() + input_len * (i + 1))),
124  output[i]));
125  }
126  }
128  const std::vector<bool> input = input_block.get_block();
129 
130  for (std::size_t i = 0; i < dimension; ++i) {
131  typename FieldType::value_type sum = FieldType::value_type::zero();
132  for (std::size_t k = 0; k < input_len; ++k) {
133  if (input[k]) {
134  sum += knapsack_coefficients[input_len * i + k];
135  }
136  }
137 
138  this->bp.lc_val(output[i]) = sum;
139  }
140  }
141 
142  static std::size_t get_digest_len() {
144  }
145 
146  /* return 0 as block length, as the hash function is variable-input */
147  static std::size_t get_block_len() {
148  return 0;
149  }
150 
151  static std::vector<typename FieldType::value_type> get_hash(const std::vector<bool> &input) {
153  if (num_cached_coefficients < dimension * input.size()) {
154  sample_randomness(input.size());
155  }
156 
157  std::vector<typename FieldType::value_type> result(dimension, FieldType::value_type::zero());
158 
159  for (std::size_t i = 0; i < dimension; ++i) {
160  for (std::size_t k = 0; k < input.size(); ++k) {
161  if (input[k]) {
162  result[i] += knapsack_coefficients[input.size() * i + k];
163  }
164  }
165  }
166 
167  return result;
168  }
169 
170  static void sample_randomness(std::size_t input_len) {
171  const std::size_t num_coefficients = knapsack_dimension<FieldType>::dimension * input_len;
172  random::hash<hashes::sha2<512>, typename FieldType::value_type> rng;
173 
174  if (num_coefficients > num_cached_coefficients) {
175  knapsack_coefficients.resize(num_coefficients);
176  for (std::size_t i = num_cached_coefficients; i < num_coefficients; ++i) {
177  rng.seed(i);
178  knapsack_coefficients[i] = rng();
179  }
180  num_cached_coefficients = num_coefficients;
181  }
182  }
183 
184  /* for debugging */
185  static std::size_t expected_constraints() {
187  }
188  };
189 
190  /********************** Knapsack with binary output **************************/
191 
192  template<typename FieldType>
193  class knapsack_crh_with_bit_out_component : public component<FieldType> {
194  public:
195  typedef std::vector<bool> hash_value_type;
198 
199  std::size_t input_len;
200  std::size_t dimension;
201 
203 
204  std::shared_ptr<knapsack_crh_with_field_out_component<FieldType>> hasher;
205 
208 
210  std::size_t input_len,
213  component<FieldType>(bp),
216  BOOST_ASSERT(output_digest.bits.size() == this->get_digest_len());
217 
218  output.resize(dimension);
219 
220  for (std::size_t i = 0; i < dimension; ++i) {
221  output[i].assign(bp,
222  blueprint_packing_sum<FieldType>(blueprint_variable_vector<FieldType>(
223  output_digest.bits.begin() + i * FieldType::value_bits,
224  output_digest.bits.begin() + (i + 1) * FieldType::value_bits)));
225  }
226 
227  hasher.reset(
229  }
230 
231  void generate_r1cs_constraints(bool enforce_bitness = true) {
232  hasher->generate_r1cs_constraints();
233 
234  if (enforce_bitness) {
235  for (std::size_t k = 0; k < output_digest.bits.size(); ++k) {
236  generate_boolean_r1cs_constraint<FieldType>(this->bp, output_digest.bits[k]);
237  }
238  }
239  }
240 
242  hasher->generate_r1cs_witness();
243 
244  /* do unpacking in place */
245  const std::vector<bool> input = input_block.bits.get_bits(this->bp);
246  for (std::size_t i = 0; i < dimension; ++i) {
248  output_digest.bits.begin() + i * FieldType::value_bits,
249  output_digest.bits.begin() + (i + 1) * FieldType::value_bits);
250  va.fill_with_bits_of_field_element(this->bp, this->bp.lc_val(output[i]));
251  }
252  }
253 
254  static std::size_t get_digest_len() {
255  return knapsack_dimension<FieldType>::dimension * FieldType::value_bits;
256  }
257 
258  /* return 0 as block length, as the hash function is variable-input */
259  static std::size_t get_block_len() {
260  return 0;
261  }
262  static hash_value_type get_hash(const std::vector<bool> &input) {
263  const std::vector<typename FieldType::value_type> hash_elems =
265  hash_value_type result;
266 
267  typedef nil::crypto3::multiprecision::number<
268  nil::crypto3::multiprecision::backends::cpp_int_backend<>>
269  integral_type;
270 
271  for (const typename FieldType::value_type &elt : hash_elems) {
272  // std::vector<std::uint8_t> elt_bytes;
273  std::vector<bool> elt_bits(FieldType::modulus_bits);
274 
275  std::vector<bool>::iterator write_iter = elt_bits.begin();
276  // little-endian, to preserve compatibility with blueprint_packing_sum.
277  auto end = ::nil::crypto3::multiprecision::export_bits(
278  integral_type(elt.data), write_iter, 1, false);
279 
280  result.insert(result.end(), elt_bits.begin(), elt_bits.end());
281  }
282 
283  return result;
284  }
285 
286  static void sample_randomness(std::size_t input_len) {
288  }
289 
290  /* for debugging */
291  static std::size_t expected_constraints(bool enforce_bitness = true) {
292  const std::size_t hasher_constraints =
294  const std::size_t bitness_constraints = (enforce_bitness ? get_digest_len() : 0);
295  return hasher_constraints + bitness_constraints;
296  }
297  };
298 
299  template<typename FieldType>
300  std::vector<typename FieldType::value_type>
301  knapsack_crh_with_field_out_component<FieldType>::knapsack_coefficients;
302  template<typename FieldType>
303  std::size_t knapsack_crh_with_field_out_component<FieldType>::num_cached_coefficients;
304  } // namespace components
305  } // namespace zk
306  } // namespace crypto3
307 } // namespace nil
308 
309 #endif // CRYPTO3_ZK_BLUEPRINT_KNAPSACK_COMPONENT_HPP
Definition: blueprint_linear_combination.hpp:115
Definition: blueprint_variable.hpp:57
void fill_with_bits_of_field_element(blueprint< field_type > &bp, const field_value_type &r) const
Definition: blueprint_variable.hpp:118
Definition: blueprint.hpp:46
Definition: component.hpp:37
blueprint< FieldType > & bp
Definition: component.hpp:39
blueprint_variable_vector< FieldType > bits
Definition: hash_io.hpp:46
blueprint_linear_combination_vector< FieldType > output
Definition: knapsack_component.hpp:202
block_variable< FieldType > input_block
Definition: knapsack_component.hpp:206
digest_variable< FieldType > output_digest
Definition: knapsack_component.hpp:207
static std::size_t get_digest_len()
Definition: knapsack_component.hpp:254
std::size_t input_len
Definition: knapsack_component.hpp:199
void generate_r1cs_constraints(bool enforce_bitness=true)
Definition: knapsack_component.hpp:231
snark::merkle_authentication_path merkle_authentication_path_type
Definition: knapsack_component.hpp:197
digest_variable< FieldType > hash_variable_type
Definition: knapsack_component.hpp:196
void generate_r1cs_witness()
Definition: knapsack_component.hpp:241
std::shared_ptr< knapsack_crh_with_field_out_component< FieldType > > hasher
Definition: knapsack_component.hpp:204
static std::size_t get_block_len()
Definition: knapsack_component.hpp:259
std::vector< bool > hash_value_type
Definition: knapsack_component.hpp:195
knapsack_crh_with_bit_out_component(blueprint< FieldType > &bp, std::size_t input_len, const block_variable< FieldType > &input_block, const digest_variable< FieldType > &output_digest)
Definition: knapsack_component.hpp:209
std::size_t dimension
Definition: knapsack_component.hpp:200
static std::size_t expected_constraints(bool enforce_bitness=true)
Definition: knapsack_component.hpp:291
static void sample_randomness(std::size_t input_len)
Definition: knapsack_component.hpp:286
static hash_value_type get_hash(const std::vector< bool > &input)
Definition: knapsack_component.hpp:262
blueprint_linear_combination_vector< FieldType > hash_variable_type
Definition: knapsack_component.hpp:94
block_variable< FieldType > input_block
Definition: knapsack_component.hpp:98
std::size_t input_len
Definition: knapsack_component.hpp:95
static std::size_t get_digest_len()
Definition: knapsack_component.hpp:142
static void sample_randomness(std::size_t input_len)
Definition: knapsack_component.hpp:170
static std::size_t expected_constraints()
Definition: knapsack_component.hpp:185
void generate_r1cs_witness()
Definition: knapsack_component.hpp:127
std::size_t dimension
Definition: knapsack_component.hpp:96
std::vector< typename FieldType::value_type > hash_value_type
Definition: knapsack_component.hpp:93
knapsack_crh_with_field_out_component(blueprint< FieldType > &bp, std::size_t input_len, const block_variable< FieldType > &input_block, const blueprint_linear_combination_vector< FieldType > &output)
Definition: knapsack_component.hpp:101
static std::size_t get_block_len()
Definition: knapsack_component.hpp:147
blueprint_linear_combination_vector< FieldType > output
Definition: knapsack_component.hpp:99
static std::vector< typename FieldType::value_type > get_hash(const std::vector< bool > &input)
Definition: knapsack_component.hpp:151
void generate_r1cs_constraints()
Definition: knapsack_component.hpp:115
constexpr T sum(const vector< T, N > &v)
computes the sum of elements
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:124
std::vector< merkle_authentication_node > merkle_authentication_path
Definition: blueprint/include/nil/crypto3/zk/merkle_tree.hpp:66
Definition: pair.hpp:31
Definition: knapsack_component.hpp:79
static const std::size_t dimension
Definition: knapsack_component.hpp:81