benes_components.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 Benes routing component.
26 //
27 // The component verifies that the outputs are a permutation of the inputs,
28 // by use of a Benes network.
29 //---------------------------------------------------------------------------//
30 
31 #ifndef CRYPTO3_ZK_BLUEPRINT_BENES_ROUTING_COMPONENT_HPP
32 #define CRYPTO3_ZK_BLUEPRINT_BENES_ROUTING_COMPONENT_HPP
33 
35 
38 
39 namespace nil {
40  namespace crypto3 {
41  namespace zk {
42  namespace components {
43 
44  template<typename FieldType>
45  class benes_routing_component : public component<FieldType> {
46  private:
47  /*
48  Indexing conventions:
49 
50  routed_packets[column_idx][packet_idx][subpacket_idx]
51  pack_inputs/unpack_outputs[packet_idx]
52  benes_switch_bits[column_idx][row_idx]
53 
54  Where column_idx ranges is in range 0 .. 2*dimension
55  (2*dimension-1 for switch bits/topology) and packet_idx is in
56  range 0 .. num_packets-1.
57  */
58  std::vector<std::vector<blueprint_variable_vector<FieldType>>> routed_packets;
59  std::vector<multipacking_component<FieldType>> pack_inputs, unpack_outputs;
60 
61  /*
62  If #packets = 1 then we can route without explicit routing bits
63  (and save half the constraints); in this case benes_switch_bits will
64  be unused.
65 
66  For benes_switch_bits 0 corresponds to straight edge and 1
67  corresponds to cross edge.
68  */
69  std::vector<blueprint_variable_vector<FieldType>> benes_switch_bits;
70  benes_topology neighbors;
71 
72  public:
73  const std::size_t num_packets;
74  const std::size_t num_columns;
75 
76  const std::vector<blueprint_variable_vector<FieldType>> routing_input_bits;
77  const std::vector<blueprint_variable_vector<FieldType>> routing_output_bits;
78  std::size_t lines_to_unpack;
79 
80  const std::size_t packet_size, num_subpackets;
81 
84  const std::size_t num_packets,
87  const std::size_t lines_to_unpack) :
88  component<FieldType>(bp),
92  num_subpackets((packet_size + FieldType::capacity() - 1) / FieldType::capacity()) {
93  assert(lines_to_unpack <= routing_input_bits.size());
94  assert(num_packets == 1ul << static_cast<std::size_t>(std::ceil(std::log2(num_packets))));
95  assert(routing_input_bits.size() == num_packets);
96 
98 
99  routed_packets.resize(num_columns + 1);
100  for (std::size_t column_idx = 0; column_idx <= num_columns; ++column_idx) {
101  routed_packets[column_idx].resize(num_packets);
102  for (std::size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
103  routed_packets[column_idx][packet_idx].allocate(bp, num_subpackets);
104  }
105  }
106 
107  pack_inputs.reserve(num_packets);
108  unpack_outputs.reserve(num_packets);
109 
110  for (std::size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
111  pack_inputs.emplace_back(multipacking_component<FieldType>(
112  bp,
114  routing_input_bits[packet_idx].end()),
115  routed_packets[0][packet_idx],
116  FieldType::capacity()));
117  if (packet_idx < lines_to_unpack) {
118  unpack_outputs.emplace_back(multipacking_component<FieldType>(
119  bp,
121  routing_output_bits[packet_idx].end()),
122  routed_packets[num_columns][packet_idx],
123  FieldType::capacity()));
124  }
125  }
126 
127  if (num_subpackets > 1) {
128  benes_switch_bits.resize(num_columns);
129  for (std::size_t column_idx = 0; column_idx < num_columns; ++column_idx) {
130  benes_switch_bits[column_idx].allocate(bp, num_packets);
131  }
132  }
133  }
134 
136  /* packing/unpacking */
137  for (std::size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
138  pack_inputs[packet_idx].generate_r1cs_constraints(false);
139  if (packet_idx < lines_to_unpack) {
140  unpack_outputs[packet_idx].generate_r1cs_constraints(true);
141  } else {
142  for (std::size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) {
143  this->bp.add_r1cs_constraint(snark::r1cs_constraint<FieldType>(
144  1, routed_packets[0][packet_idx][subpacket_idx],
145  routed_packets[num_columns][packet_idx][subpacket_idx]));
146  }
147  }
148  }
149 
150  /* actual routing constraints */
151  for (std::size_t column_idx = 0; column_idx < num_columns; ++column_idx) {
152  for (std::size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
153  const std::size_t straight_edge = neighbors[column_idx][packet_idx].first;
154  const std::size_t cross_edge = neighbors[column_idx][packet_idx].second;
155 
156  if (num_subpackets == 1) {
157  /* easy case: (cur-next)*(cur-cross) = 0 */
158  this->bp.add_r1cs_constraint(snark::r1cs_constraint<FieldType>(
159  routed_packets[column_idx][packet_idx][0] -
160  routed_packets[column_idx + 1][straight_edge][0],
161  routed_packets[column_idx][packet_idx][0] -
162  routed_packets[column_idx + 1][cross_edge][0],
163  0));
164  } else {
165  /* routing bit must be boolean */
166  generate_boolean_r1cs_constraint<FieldType>(
167  this->bp, benes_switch_bits[column_idx][packet_idx]);
168 
169  /* route forward according to routing bits */
170  for (std::size_t subpacket_idx = 0; subpacket_idx < num_subpackets;
171  ++subpacket_idx) {
172  /*
173  (1-switch_bit) * (cur-straight_edge) + switch_bit * (cur-cross_edge) = 0
174  switch_bit * (cross_edge-straight_edge) = cur-straight_edge
175  */
176  this->bp.add_r1cs_constraint(snark::r1cs_constraint<FieldType>(
177  benes_switch_bits[column_idx][packet_idx],
178  routed_packets[column_idx + 1][cross_edge][subpacket_idx] -
179  routed_packets[column_idx + 1][straight_edge][subpacket_idx],
180  routed_packets[column_idx][packet_idx][subpacket_idx] -
181  routed_packets[column_idx + 1][straight_edge][subpacket_idx]));
182  }
183  }
184  }
185  }
186  }
187 
188  void generate_r1cs_witness(const integer_permutation &permutation) {
189  /* pack inputs */
190  for (std::size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
191  pack_inputs[packet_idx].generate_r1cs_witness_from_bits();
192  }
193 
194  /* do the routing */
195  const benes_routing routing = get_benes_routing(permutation);
196 
197  for (std::size_t column_idx = 0; column_idx < num_columns; ++column_idx) {
198  for (std::size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
199  const std::size_t straight_edge = neighbors[column_idx][packet_idx].first;
200  const std::size_t cross_edge = neighbors[column_idx][packet_idx].second;
201 
202  if (num_subpackets > 1) {
203  this->bp.val(benes_switch_bits[column_idx][packet_idx]) =
204  typename FieldType::value_type(routing[column_idx][packet_idx] ? 1 : 0);
205  }
206 
207  for (std::size_t subpacket_idx = 0; subpacket_idx < num_subpackets; ++subpacket_idx) {
208  this->bp.val(routing[column_idx][packet_idx] ?
209  routed_packets[column_idx + 1][cross_edge][subpacket_idx] :
210  routed_packets[column_idx + 1][straight_edge][subpacket_idx]) =
211  this->bp.val(routed_packets[column_idx][packet_idx][subpacket_idx]);
212  }
213  }
214  }
215 
216  /* unpack outputs */
217  for (std::size_t packet_idx = 0; packet_idx < lines_to_unpack; ++packet_idx) {
218  unpack_outputs[packet_idx].generate_r1cs_witness_from_packed();
219  }
220  }
221  };
222 
223  } // namespace components
224  } // namespace zk
225  } // namespace crypto3
226 } // namespace nil
227 
228 #endif // CRYPTO3_ZK_BLUEPRINT_BENES_ROUTING_COMPONENT_HPP
void generate_r1cs_constraints()
Definition: benes_components.hpp:135
std::size_t lines_to_unpack
Definition: benes_components.hpp:78
const std::size_t num_subpackets
Definition: benes_components.hpp:80
const std::vector< blueprint_variable_vector< FieldType > > routing_output_bits
Definition: benes_components.hpp:77
const std::size_t num_packets
Definition: benes_components.hpp:73
void generate_r1cs_witness(const integer_permutation &permutation)
Definition: benes_components.hpp:188
const std::vector< blueprint_variable_vector< FieldType > > routing_input_bits
Definition: benes_components.hpp:76
const std::size_t packet_size
Definition: benes_components.hpp:80
const std::size_t num_columns
Definition: benes_components.hpp:74
benes_routing_component(blueprint< FieldType > &bp, const std::size_t num_packets, const std::vector< blueprint_variable_vector< FieldType >> &routing_input_bits, const std::vector< blueprint_variable_vector< FieldType >> &routing_output_bits, const std::size_t lines_to_unpack)
Definition: benes_components.hpp:82
Definition: blueprint_variable.hpp:57
Definition: blueprint.hpp:46
Definition: component.hpp:37
blueprint< FieldType > & bp
Definition: component.hpp:39
vector(T, U...) -> vector< std::enable_if_t<(std::is_same_v< T, U > &&...), T >, 1+sizeof...(U)>
deduction guide for uniform initialization
benes_routing get_benes_routing(const integer_permutation &permutation)
Definition: benes.hpp:344
std::vector< std::vector< std::pair< std::size_t, std::size_t > > > benes_topology
Definition: benes.hpp:67
std::size_t benes_num_columns(std::size_t num_packets)
Definition: benes.hpp:203
std::vector< std::vector< bool > > benes_routing
Definition: benes.hpp:77
benes_topology generate_benes_topology(std::size_t num_packets)
Definition: benes.hpp:210
Definition: pair.hpp:31