Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
benes_routing_algorithm.cpp
Go to the documentation of this file.
1 
14 #include <cassert>
16 
17 namespace libsnark
18 {
19 
37 size_t benes_cross_edge_mask(const size_t dimension, const size_t column_idx)
38 {
39  return (
40  column_idx < dimension ? 1ul << (dimension - 1 - column_idx)
41  : 1ul << (column_idx - dimension));
42 }
43 
60  const size_t dimension,
61  const size_t column_idx,
62  const size_t row_idx,
63  const bool use_top)
64 {
65  const size_t mask = benes_cross_edge_mask(dimension, column_idx);
66  return (use_top ? row_idx & ~mask : row_idx | mask);
67 }
68 
85  const size_t dimension,
86  const size_t column_idx,
87  const size_t row_idx,
88  const bool use_top)
89 {
91  dimension, column_idx - 1, row_idx, use_top); /* by symmetry */
92 }
93 
100  const size_t dimension,
101  const size_t column_idx,
102  const size_t row_idx,
103  const bool use_top)
104 {
105  return (
106  row_idx !=
107  benes_lhs_packet_destination(dimension, column_idx, row_idx, use_top));
108 }
109 
117  const size_t dimension, const size_t column_idx, const size_t row_idx)
118 {
119  const size_t mask = benes_cross_edge_mask(dimension, column_idx);
120  return row_idx ^ mask;
121 }
122 
130  const size_t dimension, const size_t column_idx, const size_t packet_idx)
131 {
133  dimension, column_idx - 1, packet_idx); /* by symmetry */
134 }
135 
136 size_t benes_num_columns(const size_t num_packets)
137 {
138  const size_t dimension = libff::log2(num_packets);
139  assert(num_packets == 1ul << dimension);
140 
141  return 2 * dimension;
142 }
143 
144 benes_topology generate_benes_topology(const size_t num_packets)
145 {
146  const size_t num_columns = benes_num_columns(num_packets);
147  const size_t dimension = libff::log2(num_packets);
148  assert(num_packets == 1ul << dimension);
149 
150  benes_topology result(num_columns);
151 
152  for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) {
153  result[column_idx].resize(num_packets);
154  for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
155  result[column_idx][packet_idx].first = packet_idx;
156  result[column_idx][packet_idx].second =
158  dimension, column_idx, packet_idx);
159  }
160  }
161 
162  return result;
163 }
164 
177  const size_t dimension,
178  const integer_permutation &permutation,
179  const integer_permutation &permutation_inv,
180  const size_t column_idx_start,
181  const size_t column_idx_end,
182  const size_t subnetwork_offset,
183  const size_t subnetwork_size,
184  benes_routing &routing)
185 {
186 #ifdef DEBUG
187  assert(permutation.size() == subnetwork_size);
188  assert(permutation.is_valid());
189  assert(permutation.inverse() == permutation_inv);
190 #endif
191 
192  if (column_idx_start == column_idx_end) {
193  /* nothing to route */
194  return;
195  }
196  // adjusted by subnetwork_offset
197  libff::bit_vector lhs_routed(subnetwork_size, false);
198 
199  // left-hand-side vertex to be routed.
200  size_t w = subnetwork_offset;
201  size_t last_unrouted = subnetwork_offset;
202 
203  integer_permutation new_permutation(
204  subnetwork_offset, subnetwork_offset + subnetwork_size - 1);
205  integer_permutation new_permutation_inv(
206  subnetwork_offset, subnetwork_offset + subnetwork_size - 1);
207 
208  while (true) {
215  /* route w to its target on RHS, wprime = pi[w], using upper network */
216  size_t wprime = permutation.get(w);
217 
218  /* route (column_idx_start, w) forward via top subnetwork */
219  routing[column_idx_start][w] = benes_get_switch_setting_from_subnetwork(
220  dimension, column_idx_start, w, true);
221  new_permutation.set(
222  benes_lhs_packet_destination(dimension, column_idx_start, w, true),
223  benes_rhs_packet_source(dimension, column_idx_end, wprime, true));
224  lhs_routed[w - subnetwork_offset] = true;
225 
226  /* route (column_idx_end, wprime) backward via top subnetwork */
227  routing[column_idx_end - 1][benes_rhs_packet_source(
228  dimension, column_idx_end, wprime, true)] =
230  dimension, column_idx_end - 1, wprime, true);
231  new_permutation_inv.set(
232  benes_rhs_packet_source(dimension, column_idx_end, wprime, true),
233  benes_lhs_packet_destination(dimension, column_idx_start, w, true));
234 
235  /* now the other neighbor of wprime must be back-routed via the lower
236  * network, so get vprime, the neighbor on RHS and v, its target on LHS
237  */
238  const size_t vprime =
239  benes_packet_cross_source(dimension, column_idx_end, wprime);
240  const size_t v = permutation_inv.get(vprime);
241  assert(!lhs_routed[v - subnetwork_offset]);
242 
243  /* back-route (column_idx_end, vprime) using the lower subnetwork */
244  routing[column_idx_end - 1][benes_rhs_packet_source(
245  dimension, column_idx_end, vprime, false)] =
247  dimension, column_idx_end - 1, vprime, false);
248  new_permutation_inv.set(
249  benes_rhs_packet_source(dimension, column_idx_end, vprime, false),
251  dimension, column_idx_start, v, false));
252 
253  /* forward-route (column_idx_start, v) using the lower subnetwork */
254  routing[column_idx_start][v] = benes_get_switch_setting_from_subnetwork(
255  dimension, column_idx_start, v, false);
256  new_permutation.set(
257  benes_lhs_packet_destination(dimension, column_idx_start, v, false),
258  benes_rhs_packet_source(dimension, column_idx_end, vprime, false));
259  lhs_routed[v - subnetwork_offset] = true;
260 
261  /* if the other neighbor of v is not routed, route it; otherwise, find
262  * the next unrouted node */
263  if (!lhs_routed
265  dimension, column_idx_start, v) -
266  subnetwork_offset]) {
267  w = benes_packet_cross_destination(dimension, column_idx_start, v);
268  } else {
269  while ((last_unrouted < subnetwork_offset + subnetwork_size) &&
270  lhs_routed[last_unrouted - subnetwork_offset]) {
271  ++last_unrouted;
272  }
273 
274  if (last_unrouted == subnetwork_offset + subnetwork_size) {
275  // all routed!
276  break;
277  } else {
278  w = last_unrouted;
279  }
280  }
281  }
282 
283  const integer_permutation new_permutation_upper = new_permutation.slice(
284  subnetwork_offset, subnetwork_offset + subnetwork_size / 2 - 1);
285  const integer_permutation new_permutation_lower = new_permutation.slice(
286  subnetwork_offset + subnetwork_size / 2,
287  subnetwork_offset + subnetwork_size - 1);
288 
289  const integer_permutation new_permutation_inv_upper =
290  new_permutation_inv.slice(
291  subnetwork_offset, subnetwork_offset + subnetwork_size / 2 - 1);
292  const integer_permutation new_permutation_inv_lower =
293  new_permutation_inv.slice(
294  subnetwork_offset + subnetwork_size / 2,
295  subnetwork_offset + subnetwork_size - 1);
296 
297  /* route upper part */
299  dimension,
300  new_permutation_upper,
301  new_permutation_inv_upper,
302  column_idx_start + 1,
303  column_idx_end - 1,
304  subnetwork_offset,
305  subnetwork_size / 2,
306  routing);
307 
308  /* route lower part */
310  dimension,
311  new_permutation_lower,
312  new_permutation_inv_lower,
313  column_idx_start + 1,
314  column_idx_end - 1,
315  subnetwork_offset + subnetwork_size / 2,
316  subnetwork_size / 2,
317  routing);
318 }
319 
321 {
322  const size_t num_packets = permutation.size();
323  const size_t num_columns = benes_num_columns(num_packets);
324  const size_t dimension = libff::log2(num_packets);
325 
326  benes_routing routing(num_columns, libff::bit_vector(num_packets));
327 
329  dimension,
330  permutation,
331  permutation.inverse(),
332  0,
333  num_columns,
334  0,
335  num_packets,
336  routing);
337 
338  return routing;
339 }
340 
341 /* auxiliary function that is used in valid_benes_routing below */
342 template<typename T>
343 std::vector<std::vector<T>> route_by_benes(
344  const benes_routing &routing, const std::vector<T> &start)
345 {
346  const size_t num_packets = start.size();
347  const size_t num_columns = benes_num_columns(num_packets);
348  const size_t dimension = libff::log2(num_packets);
349 
350  std::vector<std::vector<T>> res(
351  num_columns + 1, std::vector<T>(num_packets));
352  res[0] = start;
353 
354  for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) {
355  const size_t mask = benes_cross_edge_mask(dimension, column_idx);
356 
357  for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
358  size_t next_packet_idx = (routing[column_idx][packet_idx] == false)
359  ? packet_idx
360  : packet_idx ^ mask;
361  res[column_idx + 1][next_packet_idx] = res[column_idx][packet_idx];
362  }
363  }
364 
365  return res;
366 }
367 
369  const integer_permutation &permutation, const benes_routing &routing)
370 {
371  const size_t num_packets = permutation.size();
372  const size_t num_columns = benes_num_columns(num_packets);
373 
374  std::vector<size_t> input_packets(num_packets);
375  for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
376  input_packets[packet_idx] = packet_idx;
377  }
378 
379  const std::vector<std::vector<size_t>> routed_packets =
380  route_by_benes(routing, input_packets);
381 
382  for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
383  if (routed_packets[num_columns][permutation.get(packet_idx)] !=
384  input_packets[packet_idx]) {
385  return false;
386  }
387  }
388 
389  return true;
390 }
391 
392 } // namespace libsnark
libsnark::integer_permutation::inverse
integer_permutation inverse() const
Definition: integer_permutation.cpp:82
libsnark::integer_permutation::is_valid
bool is_valid() const
Definition: integer_permutation.cpp:66
libsnark::benes_packet_cross_source
size_t benes_packet_cross_source(const size_t dimension, const size_t column_idx, const size_t packet_idx)
Definition: benes_routing_algorithm.cpp:129
libsnark
Definition: accumulation_vector.hpp:18
libsnark::benes_topology
std::vector< std::vector< std::pair< size_t, size_t > > > benes_topology
Definition: benes_routing_algorithm.hpp:51
libsnark::valid_benes_routing
bool valid_benes_routing(const integer_permutation &permutation, const benes_routing &routing)
Definition: benes_routing_algorithm.cpp:368
libsnark::benes_rhs_packet_source
size_t benes_rhs_packet_source(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top)
Definition: benes_routing_algorithm.cpp:84
libsnark::benes_cross_edge_mask
size_t benes_cross_edge_mask(const size_t dimension, const size_t column_idx)
Definition: benes_routing_algorithm.cpp:37
benes_routing_algorithm.hpp
libsnark::integer_permutation::get
size_t get(const size_t position) const
Definition: integer_permutation.cpp:60
libsnark::integer_permutation::set
void set(const size_t position, const size_t value)
Definition: integer_permutation.cpp:54
libsnark::benes_routing
std::vector< libff::bit_vector > benes_routing
Definition: benes_routing_algorithm.hpp:61
libsnark::benes_num_columns
size_t benes_num_columns(const size_t num_packets)
Definition: benes_routing_algorithm.cpp:136
libsnark::integer_permutation::size
size_t size() const
Definition: integer_permutation.cpp:41
libsnark::integer_permutation
Definition: integer_permutation.hpp:22
libsnark::benes_lhs_packet_destination
size_t benes_lhs_packet_destination(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top)
Definition: benes_routing_algorithm.cpp:59
libsnark::integer_permutation::slice
integer_permutation slice(const size_t slice_min_element, const size_t slice_max_element) const
Definition: integer_permutation.cpp:98
libsnark::benes_packet_cross_destination
size_t benes_packet_cross_destination(const size_t dimension, const size_t column_idx, const size_t row_idx)
Definition: benes_routing_algorithm.cpp:116
libsnark::get_benes_routing
benes_routing get_benes_routing(const integer_permutation &permutation)
Definition: benes_routing_algorithm.cpp:320
libsnark::generate_benes_topology
benes_topology generate_benes_topology(const size_t num_packets)
Definition: benes_routing_algorithm.cpp:144
libsnark::route_by_benes
std::vector< std::vector< T > > route_by_benes(const benes_routing &routing, const std::vector< T > &start)
Definition: benes_routing_algorithm.cpp:343
libsnark::route_benes_inner
void route_benes_inner(const size_t dimension, const integer_permutation &permutation, const integer_permutation &permutation_inv, const size_t column_idx_start, const size_t column_idx_end, const size_t subnetwork_offset, const size_t subnetwork_size, benes_routing &routing)
Definition: benes_routing_algorithm.cpp:176
libsnark::benes_get_switch_setting_from_subnetwork
bool benes_get_switch_setting_from_subnetwork(const size_t dimension, const size_t column_idx, const size_t row_idx, const bool use_top)
Definition: benes_routing_algorithm.cpp:99