packing.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 
26 #ifndef CRYPTO3_ZK_BLUEPRINT_BASIC_COMPONENTS_HPP
27 #define CRYPTO3_ZK_BLUEPRINT_BASIC_COMPONENTS_HPP
28 
29 #include <cassert>
30 #include <memory>
31 
33 
34 #include <nil/crypto3/multiprecision/number.hpp>
36 
37 namespace nil {
38  namespace crypto3 {
39  namespace zk {
40  namespace components {
41 
42  /* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */
43  template<typename FieldType>
47  }
48 
49  template<typename FieldType>
52  const typename FieldType::value_type &c) {
54  }
55 
56  template<typename FieldType>
57  class packing_component : public component<FieldType> {
58  private:
59  /* no internal variables */
60  public:
63 
67  component<FieldType>(bp),
68  bits(bits), packed(packed) {
69  }
70 
71  /* adds constraint result = \sum bits[i] * 2^i */
72  void generate_r1cs_constraints(bool enforce_bitness) {
73  this->bp.add_r1cs_constraint(
74  snark::r1cs_constraint<FieldType>(1, blueprint_packing_sum<FieldType>(bits), packed));
75 
76  if (enforce_bitness) {
77  for (std::size_t i = 0; i < bits.size(); ++i) {
78  generate_boolean_r1cs_constraint<FieldType>(this->bp, bits[i]);
79  }
80  }
81  }
82 
84  packed.evaluate(this->bp);
85  auto lc_val = this->bp.lc_val(packed).data;
86 
87  // assert(lc_val == 0 ||
88  // multiprecision::msb(lc_val) + 1 <=
89  // bits.size()); // `bits` is large enough to represent this packed value
90  bits.fill_with_bits_of_field_element(this->bp, this->bp.lc_val(packed));
91  }
92 
94  bits.evaluate(this->bp);
95  this->bp.lc_val(packed) = bits.get_field_element_from_bits(this->bp);
96  }
97  };
98 
99  template<typename FieldType>
100  class multipacking_component : public component<FieldType> {
101  private:
102  std::vector<packing_component<FieldType>> packers;
103 
104  public:
107 
108  const std::size_t chunk_size;
109  const std::size_t num_chunks;
110  // const std::size_t last_chunk_size;
111 
112  // last_chunk_size(bits.size() - (num_chunks-1) * chunk_size)
116  std::size_t chunk_size) :
117  component<FieldType>(bp),
119  num_chunks((bits.size() + (chunk_size - 1)) / chunk_size) {
120 
121  assert(packed_vars.size() == num_chunks);
122  for (std::size_t i = 0; i < num_chunks; ++i) {
123  packers.emplace_back(packing_component<FieldType>(
124  this->bp,
126  bits.begin() + i * chunk_size,
127  bits.begin() + std::min((i + 1) * chunk_size, bits.size())),
128  packed_vars[i]));
129  }
130  }
131 
132  void generate_r1cs_constraints(bool enforce_bitness) {
133  for (std::size_t i = 0; i < num_chunks; ++i) {
134  packers[i].generate_r1cs_constraints(enforce_bitness);
135  }
136  }
137 
139  for (std::size_t i = 0; i < num_chunks; ++i) {
140  packers[i].generate_r1cs_witness_from_packed();
141  }
142  }
143 
145  for (std::size_t i = 0; i < num_chunks; ++i) {
146  packers[i].generate_r1cs_witness_from_bits();
147  }
148  }
149  };
150 
151  template<typename FieldType>
152  class field_vector_copy_component : public component<FieldType> {
153  public:
157 
162  component<FieldType>(bp),
164 
165  assert(source.size() == target.size());
166  }
168  for (std::size_t i = 0; i < source.size(); ++i) {
169  this->bp.add_r1cs_constraint(
171  }
172  }
173 
175  do_copy.evaluate(this->bp);
176  assert(this->bp.lc_val(do_copy) == FieldType::value_type::one() ||
177  this->bp.lc_val(do_copy) == FieldType::value_type::zero());
178  if (this->bp.lc_val(do_copy) != FieldType::value_type::zero()) {
179  for (std::size_t i = 0; i < source.size(); ++i) {
180  this->bp.val(target[i]) = this->bp.val(source[i]);
181  }
182  }
183  }
184  };
185 
186  template<typename FieldType>
187  class bit_vector_copy_component : public component<FieldType> {
188  public:
192 
195 
196  std::shared_ptr<multipacking_component<FieldType>> pack_source;
197  std::shared_ptr<multipacking_component<FieldType>> pack_target;
198  std::shared_ptr<field_vector_copy_component<FieldType>> copier;
199 
200  const std::size_t chunk_size;
201  const std::size_t num_chunks;
202 
207  std::size_t chunk_size) :
208  component<FieldType>(bp),
210  num_chunks((source_bits.size() + (chunk_size - 1)) / chunk_size) {
211 
212  assert(source_bits.size() == target_bits.size());
213 
214  packed_source.allocate(bp, num_chunks);
215  pack_source.reset(
217 
218  packed_target.allocate(bp, num_chunks);
219  pack_target.reset(
221 
222  copier.reset(
224  }
225 
226  void generate_r1cs_constraints(bool enforce_source_bitness, bool enforce_target_bitness) {
227  pack_source->generate_r1cs_constraints(enforce_source_bitness);
228  pack_target->generate_r1cs_constraints(enforce_target_bitness);
229 
230  copier->generate_r1cs_constraints();
231  }
232 
234  do_copy.evaluate(this->bp);
235  assert(this->bp.lc_val(do_copy) == FieldType::value_type::zero() ||
236  this->bp.lc_val(do_copy) == FieldType::value_type::one());
237  if (this->bp.lc_val(do_copy) == FieldType::value_type::one()) {
238  for (std::size_t i = 0; i < source_bits.size(); ++i) {
239  this->bp.val(target_bits[i]) = this->bp.val(source_bits[i]);
240  }
241  }
242 
243  pack_source->generate_r1cs_witness_from_bits();
244  pack_target->generate_r1cs_witness_from_bits();
245  }
246  };
247 
248  template<typename FieldType>
249  class dual_variable_component : public component<FieldType> {
250  private:
251  std::shared_ptr<packing_component<FieldType>> consistency_check;
252 
253  public:
256 
257  dual_variable_component(blueprint<FieldType> &bp, std::size_t width) : component<FieldType>(bp) {
258  packed.allocate(bp);
259  bits.allocate(bp, width);
260  consistency_check.reset(new packing_component<FieldType>(bp, bits, packed));
261  }
262 
265  component<FieldType>(bp),
266  bits(bits) {
267  packed.allocate(bp);
268  consistency_check.reset(new packing_component<FieldType>(bp, bits, packed));
269  }
270 
272  std::size_t width) :
273  component<FieldType>(bp),
274  packed(packed) {
275  bits.allocate(bp, width);
276  consistency_check.reset(new packing_component<FieldType>(bp, bits, packed));
277  }
278 
279  void generate_r1cs_constraints(bool enforce_bitness) {
280  consistency_check->generate_r1cs_constraints(enforce_bitness);
281  }
282 
284  consistency_check->generate_r1cs_witness_from_packed();
285  }
287  consistency_check->generate_r1cs_witness_from_bits();
288  }
289  };
290 
291  template<typename FieldType, typename VarT>
294  const std::vector<typename FieldType::value_type> &base,
295  const std::vector<std::pair<VarT, typename FieldType::value_type>> &v,
296  const VarT &target) {
297 
298  for (std::size_t i = 0; i < base.size(); ++i) {
300 
303 
304  for (auto &p : v) {
305  b.add_term(p.first.all_vars[i], p.second);
306  }
307 
308  c.add_term(target.all_vars[i]);
309 
311  }
312  }
313 
314  template<typename FieldType, typename VarT>
317  const std::vector<typename FieldType::value_type> &base,
318  const std::vector<std::pair<VarT, typename FieldType::value_type>> &v,
319  const VarT &target) {
320  for (std::size_t i = 0; i < base.size(); ++i) {
321  bp.val(target.all_vars[i]) = base[i];
322 
323  for (auto &p : v) {
324  bp.val(target.all_vars[i]) += p.second * bp.val(p.first.all_vars[i]);
325  }
326  }
327  }
328 
329  template<typename FieldType>
330  std::size_t multipacking_num_chunks(const std::size_t num_bits) {
331  return (num_bits + (FieldType::capacity()) - 1) / FieldType::capacity();
332  }
333 
334  } // namespace components
335  } // namespace zk
336  } // namespace crypto3
337 } // namespace nil
338 #endif // CRYPTO3_ZK_BLUEPRINT_BASIC_COMPONENTS_HPP
const std::size_t chunk_size
Definition: packing.hpp:200
bit_vector_copy_component(blueprint< FieldType > &bp, const blueprint_variable_vector< FieldType > &source_bits, const blueprint_variable_vector< FieldType > &target_bits, const blueprint_linear_combination< FieldType > &do_copy, std::size_t chunk_size)
Definition: packing.hpp:203
blueprint_variable_vector< FieldType > packed_source
Definition: packing.hpp:193
std::shared_ptr< multipacking_component< FieldType > > pack_target
Definition: packing.hpp:197
const blueprint_linear_combination< FieldType > do_copy
Definition: packing.hpp:191
void generate_r1cs_constraints(bool enforce_source_bitness, bool enforce_target_bitness)
Definition: packing.hpp:226
const std::size_t num_chunks
Definition: packing.hpp:201
blueprint_variable_vector< FieldType > packed_target
Definition: packing.hpp:194
std::shared_ptr< multipacking_component< FieldType > > pack_source
Definition: packing.hpp:196
const blueprint_variable_vector< FieldType > target_bits
Definition: packing.hpp:190
void generate_r1cs_witness()
Definition: packing.hpp:233
std::shared_ptr< field_vector_copy_component< FieldType > > copier
Definition: packing.hpp:198
const blueprint_variable_vector< FieldType > source_bits
Definition: packing.hpp:189
Definition: blueprint_linear_combination.hpp:115
Definition: blueprint_linear_combination.hpp:47
Definition: blueprint_variable.hpp:57
Definition: blueprint_variable.hpp:46
Definition: blueprint.hpp:46
FieldType::value_type & val(const blueprint_variable< FieldType > &var)
Definition: blueprint.hpp:70
void add_r1cs_constraint(const snark::r1cs_constraint< FieldType > &constr)
Definition: blueprint.hpp:98
Definition: component.hpp:37
blueprint< FieldType > & bp
Definition: component.hpp:39
void generate_r1cs_constraints(bool enforce_bitness)
Definition: packing.hpp:279
dual_variable_component(blueprint< FieldType > &bp, const blueprint_variable< FieldType > &packed, std::size_t width)
Definition: packing.hpp:271
void generate_r1cs_witness_from_bits()
Definition: packing.hpp:286
blueprint_variable< FieldType > packed
Definition: packing.hpp:254
void generate_r1cs_witness_from_packed()
Definition: packing.hpp:283
dual_variable_component(blueprint< FieldType > &bp, std::size_t width)
Definition: packing.hpp:257
blueprint_variable_vector< FieldType > bits
Definition: packing.hpp:255
dual_variable_component(blueprint< FieldType > &bp, const blueprint_variable_vector< FieldType > &bits)
Definition: packing.hpp:263
const blueprint_linear_combination< FieldType > do_copy
Definition: packing.hpp:156
const blueprint_variable_vector< FieldType > source
Definition: packing.hpp:154
const blueprint_variable_vector< FieldType > target
Definition: packing.hpp:155
field_vector_copy_component(blueprint< FieldType > &bp, const blueprint_variable_vector< FieldType > &source, const blueprint_variable_vector< FieldType > &target, const blueprint_linear_combination< FieldType > &do_copy)
Definition: packing.hpp:158
void generate_r1cs_witness()
Definition: packing.hpp:174
void generate_r1cs_constraints()
Definition: packing.hpp:167
multipacking_component(blueprint< FieldType > &bp, const blueprint_linear_combination_vector< FieldType > &bits, const blueprint_linear_combination_vector< FieldType > &packed_vars, std::size_t chunk_size)
Definition: packing.hpp:113
void generate_r1cs_constraints(bool enforce_bitness)
Definition: packing.hpp:132
const std::size_t num_chunks
Definition: packing.hpp:109
const blueprint_linear_combination_vector< FieldType > packed_vars
Definition: packing.hpp:106
void generate_r1cs_witness_from_bits()
Definition: packing.hpp:144
const blueprint_linear_combination_vector< FieldType > bits
Definition: packing.hpp:105
void generate_r1cs_witness_from_packed()
Definition: packing.hpp:138
const std::size_t chunk_size
Definition: packing.hpp:108
const blueprint_linear_combination< FieldType > packed
Definition: packing.hpp:62
void generate_r1cs_witness_from_bits()
Definition: packing.hpp:93
const blueprint_linear_combination_vector< FieldType > bits
Definition: packing.hpp:61
packing_component(blueprint< FieldType > &bp, const blueprint_linear_combination_vector< FieldType > &bits, const blueprint_linear_combination< FieldType > &packed)
Definition: packing.hpp:64
void generate_r1cs_constraints(bool enforce_bitness)
Definition: packing.hpp:72
void generate_r1cs_witness_from_packed()
Definition: packing.hpp:83
constexpr T min(const vector< T, N > &v)
computes the minimum valued element
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:135
vector(T, U...) -> vector< std::enable_if_t<(std::is_same_v< T, U > &&...), T >, 1+sizeof...(U)>
deduction guide for uniform initialization
void generate_r1cs_equals_const_constraint(blueprint< FieldType > &bp, const blueprint_linear_combination< FieldType > &lc, const typename FieldType::value_type &c)
Definition: packing.hpp:50
void create_linear_combination_constraints(blueprint< FieldType > &bp, const std::vector< typename FieldType::value_type > &base, const std::vector< std::pair< VarT, typename FieldType::value_type >> &v, const VarT &target)
Definition: packing.hpp:292
std::size_t multipacking_num_chunks(const std::size_t num_bits)
Definition: packing.hpp:330
void create_linear_combination_witness(blueprint< FieldType > &bp, const std::vector< typename FieldType::value_type > &base, const std::vector< std::pair< VarT, typename FieldType::value_type >> &v, const VarT &target)
Definition: packing.hpp:315
void generate_boolean_r1cs_constraint(blueprint< FieldType > &bp, const blueprint_linear_combination< FieldType > &lc)
Definition: packing.hpp:44
Definition: pair.hpp:31
void add_term(const variable< FieldType > &var)
Definition: variable.hpp:277