Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
as_waksman_routing_algorithm.cpp
Go to the documentation of this file.
1 
16 
17 #include <cassert>
18 
19 namespace libsnark
20 {
21 
25 size_t as_waksman_top_height(const size_t num_packets)
26 {
27  return num_packets / 2;
28 }
29 
42  const size_t num_packets,
43  const size_t row_offset,
44  const size_t row_idx,
45  const bool use_top)
46 {
47  size_t relpos = row_idx - row_offset;
48  assert(relpos % 2 == 0 && relpos + 1 < num_packets);
49  return row_offset + (relpos / 2) +
50  (use_top ? 0 : as_waksman_top_height(num_packets));
51 }
52 
60  const size_t num_packets,
61  const size_t row_offset,
62  const size_t row_idx,
63  const bool use_top)
64 {
65  /* Due to symmetry, this function equals as_waksman_switch_output. */
66  return as_waksman_switch_output(num_packets, row_offset, row_idx, use_top);
67 }
68 
69 size_t as_waksman_num_columns(const size_t num_packets)
70 {
71  return (num_packets > 1 ? 2 * libff::log2(num_packets) - 1 : 0);
72 }
73 
88  const size_t left,
89  const size_t right,
90  const size_t lo,
91  const size_t hi,
92  const std::vector<size_t> rhs_dests,
93  as_waksman_topology &neighbors)
94 {
95  if (left > right) {
96  return;
97  }
98 
99  const size_t subnetwork_size = (hi - lo + 1);
100  assert(rhs_dests.size() == subnetwork_size);
101  const size_t subnetwork_width = as_waksman_num_columns(subnetwork_size);
102  assert(right - left + 1 >= subnetwork_width);
103 
104  if (right - left + 1 > subnetwork_width) {
109  for (size_t packet_idx = lo; packet_idx <= hi; ++packet_idx) {
110  neighbors[left][packet_idx].first =
111  neighbors[left][packet_idx].second = packet_idx;
112  neighbors[right][packet_idx].first =
113  neighbors[right][packet_idx].second =
114  rhs_dests[packet_idx - lo];
115  }
116 
117  std::vector<size_t> new_rhs_dests(subnetwork_size, -1);
118  for (size_t packet_idx = lo; packet_idx <= hi; ++packet_idx) {
119  new_rhs_dests[packet_idx - lo] = packet_idx;
120  }
121 
123  left + 1, right - 1, lo, hi, new_rhs_dests, neighbors);
124  } else if (subnetwork_size == 2) {
125  /* Non-trivial base case: routing a 2-element permutation. */
126  neighbors[left][lo].first = neighbors[left][hi].second = rhs_dests[0];
127  neighbors[left][lo].second = neighbors[left][hi].first = rhs_dests[1];
128  } else {
133  std::vector<size_t> new_rhs_dests(subnetwork_size, -1);
134 
142  for (size_t row_idx = lo;
143  row_idx < (subnetwork_size % 2 == 1 ? hi : hi + 1);
144  row_idx += 2) {
145  neighbors[left][row_idx].first =
146  neighbors[left][row_idx + 1].second = as_waksman_switch_output(
147  subnetwork_size, lo, row_idx, true);
148  neighbors[left][row_idx].second =
149  neighbors[left][row_idx + 1].first = as_waksman_switch_output(
150  subnetwork_size, lo, row_idx, false);
151 
152  new_rhs_dests
153  [as_waksman_switch_input(subnetwork_size, lo, row_idx, true) -
154  lo] = row_idx;
155  new_rhs_dests
156  [as_waksman_switch_input(subnetwork_size, lo, row_idx, false) -
157  lo] = row_idx + 1;
158 
159  neighbors[right][row_idx].first =
160  neighbors[right][row_idx + 1].second = rhs_dests[row_idx - lo];
161  neighbors[right][row_idx].second =
162  neighbors[right][row_idx + 1].first =
163  rhs_dests[row_idx + 1 - lo];
164  }
165 
166  if (subnetwork_size % 2 == 1) {
172  neighbors[left][hi].first = neighbors[left][hi].second = hi;
173  neighbors[right][hi].first = neighbors[right][hi].second =
174  rhs_dests[hi - lo];
175  new_rhs_dests[hi - lo] = hi;
176  } else {
182  neighbors[left][hi - 1].second = neighbors[left][hi - 1].first;
183  neighbors[left][hi].second = neighbors[left][hi].first;
184  }
185 
186  const size_t d = as_waksman_top_height(subnetwork_size);
187  const std::vector<size_t> new_rhs_dests_top(
188  new_rhs_dests.begin(), new_rhs_dests.begin() + d);
189  const std::vector<size_t> new_rhs_dests_bottom(
190  new_rhs_dests.begin() + d, new_rhs_dests.end());
191 
193  left + 1, right - 1, lo, lo + d - 1, new_rhs_dests_top, neighbors);
195  left + 1, right - 1, lo + d, hi, new_rhs_dests_bottom, neighbors);
196  }
197 }
198 
200 {
201  assert(num_packets > 1);
202  const size_t width = as_waksman_num_columns(num_packets);
203 
204  as_waksman_topology neighbors(
205  width,
206  std::vector<std::pair<size_t, size_t>>(
207  num_packets, std::make_pair<size_t, size_t>(-1, -1)));
208 
209  std::vector<size_t> rhs_dests(num_packets);
210  for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
211  rhs_dests[packet_idx] = packet_idx;
212  }
213 
215  0, width - 1, 0, num_packets - 1, rhs_dests, neighbors);
216 
217  return neighbors;
218 }
219 
228  const size_t row_offset, const size_t row_idx)
229 {
230  /* translate back relative to row_offset, clear LSB, and then translate
231  * forward */
232  return (((row_idx - row_offset) & ~1) + row_offset);
233 }
234 
246  const size_t row_offset, const size_t packet_idx, const bool use_top)
247 {
248  const size_t row_idx =
249  as_waksman_get_canonical_row_idx(row_offset, packet_idx);
250  return (packet_idx == row_idx) ^ use_top;
251 }
252 
264  const size_t row_offset, const size_t packet_idx, const bool switch_setting)
265 {
266  const size_t row_idx =
267  as_waksman_get_canonical_row_idx(row_offset, packet_idx);
268  return (row_idx == packet_idx) ^ switch_setting;
269 }
270 
276  const size_t row_offset, const size_t packet_idx)
277 {
278  const size_t row_idx =
279  as_waksman_get_canonical_row_idx(row_offset, packet_idx);
280  return (1 - (packet_idx - row_idx)) + row_idx;
281 }
282 
288  const size_t row_offset, const size_t packet_idx)
289 {
290  /* Due to symmetry, this function equals as_waksman_other_output_position.
291  */
292  return as_waksman_other_output_position(row_offset, packet_idx);
293 }
294 
309  const size_t left,
310  const size_t right,
311  const size_t lo,
312  const size_t hi,
313  const integer_permutation &permutation,
314  const integer_permutation &permutation_inv,
315  as_waksman_routing &routing)
316 {
317  if (left > right) {
318  return;
319  }
320 
321  const size_t subnetwork_size = (hi - lo + 1);
322  const size_t subnetwork_width = as_waksman_num_columns(subnetwork_size);
323  assert(right - left + 1 >= subnetwork_width);
324 
325 #ifdef DEBUG
326  assert(permutation.min_element == lo);
327  assert(permutation.max_element == hi);
328  assert(permutation.size() == subnetwork_size);
329  assert(permutation.is_valid());
330  assert(permutation.inverse() == permutation_inv);
331 #endif
332 
333  if (right - left + 1 > subnetwork_width) {
340  left + 1, right - 1, lo, hi, permutation, permutation_inv, routing);
341  } else if (subnetwork_size == 2) {
345  assert(permutation.get(lo) == lo || permutation.get(lo) == lo + 1);
346  assert(
347  permutation.get(lo + 1) == lo || permutation.get(lo + 1) == lo + 1);
348  assert(permutation.get(lo) != permutation.get(lo + 1));
349 
350  routing[left][lo] = (permutation.get(lo) != lo);
351  } else {
359  integer_permutation new_permutation(lo, hi);
360  integer_permutation new_permutation_inv(lo, hi);
361  // offset by lo, i.e. lhs_routed[packet_idx-lo] is set if
362  // packet packet_idx is routed
363  std::vector<bool> lhs_routed(subnetwork_size, false);
364 
365  size_t to_route;
366  size_t max_unrouted;
367  bool route_left;
368 
369  if (subnetwork_size % 2 == 1) {
375  if (permutation.get(hi) == hi) {
380  new_permutation.set(hi, hi);
381  new_permutation_inv.set(hi, hi);
382  to_route = hi - 1;
383  route_left = true;
384  } else {
390  const size_t rhs_switch =
391  as_waksman_get_canonical_row_idx(lo, permutation.get(hi));
392  const bool rhs_switch_setting =
394  lo, permutation.get(hi), false);
395  routing[right][rhs_switch] = rhs_switch_setting;
396  size_t tprime = as_waksman_switch_input(
397  subnetwork_size, lo, rhs_switch, false);
398  new_permutation.set(hi, tprime);
399  new_permutation_inv.set(tprime, hi);
400 
401  to_route =
402  as_waksman_other_output_position(lo, permutation.get(hi));
403  route_left = false;
404  }
405 
406  lhs_routed[hi - lo] = true;
407  max_unrouted = hi - 1;
408  } else {
413  routing[left][hi - 1] = false;
414  to_route = hi;
415  route_left = true;
416  max_unrouted = hi;
417  }
418 
419  while (1) {
424  if (route_left) {
425  // If switch value has not been assigned, assign it arbitrarily.
426  const size_t lhs_switch =
427  as_waksman_get_canonical_row_idx(lo, to_route);
428  if (routing[left].find(lhs_switch) == routing[left].end()) {
429  routing[left][lhs_switch] = false;
430  }
431  const bool lhs_switch_setting = routing[left][lhs_switch];
432  const bool use_top =
434  lo, to_route, lhs_switch_setting);
435  const size_t t = as_waksman_switch_output(
436  subnetwork_size, lo, lhs_switch, use_top);
437  if (permutation.get(to_route) == hi) {
442  new_permutation.set(t, hi);
443  new_permutation_inv.set(hi, t);
444  lhs_routed[to_route - lo] = true;
445  to_route = max_unrouted;
446  route_left = true;
447  } else {
448  const size_t rhs_switch = as_waksman_get_canonical_row_idx(
449  lo, permutation.get(to_route));
455  assert(
456  routing[right].find(rhs_switch) ==
457  routing[right].end());
458  routing[right][rhs_switch] =
460  lo, permutation.get(to_route), use_top);
461  const size_t tprime = as_waksman_switch_input(
462  subnetwork_size, lo, rhs_switch, use_top);
463  new_permutation.set(t, tprime);
464  new_permutation_inv.set(tprime, t);
465 
466  lhs_routed[to_route - lo] = true;
468  lo, permutation.get(to_route));
469  route_left = false;
470  }
471  } else {
476  const size_t rhs_switch =
477  as_waksman_get_canonical_row_idx(lo, to_route);
478  const size_t lhs_switch = as_waksman_get_canonical_row_idx(
479  lo, permutation_inv.get(to_route));
480  assert(routing[right].find(rhs_switch) != routing[right].end());
481  const bool rhs_switch_setting = routing[right][rhs_switch];
482  const bool use_top =
484  lo, to_route, rhs_switch_setting);
485  const bool lhs_switch_setting =
487  lo, permutation_inv.get(to_route), use_top);
488 
489  /* The value on the left-hand side is either the same or not
490  * set. */
491 #ifndef NDEBUG
492  auto it = routing[left].find(lhs_switch);
493 #endif
494  assert(
495  it == routing[left].end() ||
496  it->second == lhs_switch_setting);
497  routing[left][lhs_switch] = lhs_switch_setting;
498 
499  const size_t t = as_waksman_switch_input(
500  subnetwork_size, lo, rhs_switch, use_top);
501  const size_t tprime = as_waksman_switch_output(
502  subnetwork_size, lo, lhs_switch, use_top);
503  new_permutation.set(tprime, t);
504  new_permutation_inv.set(t, tprime);
505 
506  lhs_routed[permutation_inv.get(to_route) - lo] = true;
508  lo, permutation_inv.get(to_route));
509  route_left = true;
510  }
511 
512  /* If the next packet to be routed hasn't been routed before, then
513  * try routing it. */
514  if (!route_left || !lhs_routed[to_route - lo]) {
515  continue;
516  }
517 
518  /* Otherwise just find the next unrouted packet. */
519  while (max_unrouted > lo && lhs_routed[max_unrouted - lo]) {
520  --max_unrouted;
521  }
522 
523  // lhs_routed[0] = corresponds to lo shifted by lo
524  if (max_unrouted < lo || (max_unrouted == lo && lhs_routed[0])) {
525  // All routed!
526  break;
527  } else {
528  to_route = max_unrouted;
529  route_left = true;
530  }
531  }
532 
533  if (subnetwork_size % 2 == 0) {
534  /* Remove the AS-Waksman switch with the fixed value. */
535  routing[left].erase(hi - 1);
536  }
537 
538  const size_t d = as_waksman_top_height(subnetwork_size);
539  const integer_permutation new_permutation_upper =
540  new_permutation.slice(lo, lo + d - 1);
541  const integer_permutation new_permutation_lower =
542  new_permutation.slice(lo + d, hi);
543 
544  const integer_permutation new_permutation_inv_upper =
545  new_permutation_inv.slice(lo, lo + d - 1);
546  const integer_permutation new_permutation_inv_lower =
547  new_permutation_inv.slice(lo + d, hi);
548 
550  left + 1,
551  right - 1,
552  lo,
553  lo + d - 1,
554  new_permutation_upper,
555  new_permutation_inv_upper,
556  routing);
558  left + 1,
559  right - 1,
560  lo + d,
561  hi,
562  new_permutation_lower,
563  new_permutation_inv_lower,
564  routing);
565  }
566 }
567 
569  const integer_permutation &permutation)
570 {
571  const size_t num_packets = permutation.size();
572  const size_t width = as_waksman_num_columns(num_packets);
573 
574  as_waksman_routing routing(width);
576  0,
577  width - 1,
578  0,
579  num_packets - 1,
580  permutation,
581  permutation.inverse(),
582  routing);
583  return routing;
584 }
585 
587  const integer_permutation &permutation, const as_waksman_routing &routing)
588 {
589  const size_t num_packets = permutation.size();
590  const size_t width = as_waksman_num_columns(num_packets);
591  as_waksman_topology neighbors = generate_as_waksman_topology(num_packets);
592 
593  integer_permutation curperm(num_packets);
594 
595  for (size_t column_idx = 0; column_idx < width; ++column_idx) {
596  integer_permutation nextperm(num_packets);
597  for (size_t packet_idx = 0; packet_idx < num_packets; ++packet_idx) {
598  size_t routed_packet_idx;
599  if (neighbors[column_idx][packet_idx].first ==
600  neighbors[column_idx][packet_idx].second) {
601  routed_packet_idx = neighbors[column_idx][packet_idx].first;
602  } else {
603  auto it = routing[column_idx].find(packet_idx);
604  auto it2 = routing[column_idx].find(packet_idx - 1);
605  assert(
606  (it != routing[column_idx].end()) ^
607  (it2 != routing[column_idx].end()));
608  const bool switch_setting =
609  (it != routing[column_idx].end() ? it->second
610  : it2->second);
611 
612  routed_packet_idx =
613  (switch_setting ? neighbors[column_idx][packet_idx].second
614  : neighbors[column_idx][packet_idx].first);
615  }
616 
617  nextperm.set(routed_packet_idx, curperm.get(packet_idx));
618  }
619 
620  curperm = nextperm;
621  }
622 
623  return (curperm == permutation.inverse());
624 }
625 
626 } // namespace libsnark
libsnark::generate_as_waksman_topology
as_waksman_topology generate_as_waksman_topology(const size_t num_packets)
Definition: as_waksman_routing_algorithm.cpp:199
libsnark::integer_permutation::inverse
integer_permutation inverse() const
Definition: integer_permutation.cpp:82
libsnark::as_waksman_switch_input
size_t as_waksman_switch_input(const size_t num_packets, const size_t row_offset, const size_t row_idx, const bool use_top)
Definition: as_waksman_routing_algorithm.cpp:59
libsnark::integer_permutation::is_valid
bool is_valid() const
Definition: integer_permutation.cpp:66
libsnark::as_waksman_topology
std::vector< std::vector< std::pair< size_t, size_t > > > as_waksman_topology
Definition: as_waksman_routing_algorithm.hpp:83
libsnark::as_waksman_get_top_bottom_decision_from_switch_setting
bool as_waksman_get_top_bottom_decision_from_switch_setting(const size_t row_offset, const size_t packet_idx, const bool switch_setting)
Definition: as_waksman_routing_algorithm.cpp:263
libsnark
Definition: accumulation_vector.hpp:18
libsnark::as_waksman_other_output_position
size_t as_waksman_other_output_position(const size_t row_offset, const size_t packet_idx)
Definition: as_waksman_routing_algorithm.cpp:275
libsnark::integer_permutation::max_element
size_t max_element
Definition: integer_permutation.hpp:29
libsnark::as_waksman_get_switch_setting_from_top_bottom_decision
bool as_waksman_get_switch_setting_from_top_bottom_decision(const size_t row_offset, const size_t packet_idx, const bool use_top)
Definition: as_waksman_routing_algorithm.cpp:245
libsnark::integer_permutation::min_element
size_t min_element
Definition: integer_permutation.hpp:28
libsnark::as_waksman_top_height
size_t as_waksman_top_height(const size_t num_packets)
Definition: as_waksman_routing_algorithm.cpp:25
libsnark::as_waksman_switch_output
size_t as_waksman_switch_output(const size_t num_packets, const size_t row_offset, const size_t row_idx, const bool use_top)
Definition: as_waksman_routing_algorithm.cpp:41
libsnark::get_as_waksman_routing
as_waksman_routing get_as_waksman_routing(const integer_permutation &permutation)
Definition: as_waksman_routing_algorithm.cpp:568
libsnark::integer_permutation::get
size_t get(const size_t position) const
Definition: integer_permutation.cpp:60
libsnark::as_waksman_get_canonical_row_idx
size_t as_waksman_get_canonical_row_idx(const size_t row_offset, const size_t row_idx)
Definition: as_waksman_routing_algorithm.cpp:227
libsnark::integer_permutation::set
void set(const size_t position, const size_t value)
Definition: integer_permutation.cpp:54
libsnark::integer_permutation::size
size_t size() const
Definition: integer_permutation.cpp:41
libsnark::integer_permutation
Definition: integer_permutation.hpp:22
libsnark::as_waksman_other_input_position
size_t as_waksman_other_input_position(const size_t row_offset, const size_t packet_idx)
Definition: as_waksman_routing_algorithm.cpp:287
libsnark::as_waksman_route_inner
void as_waksman_route_inner(const size_t left, const size_t right, const size_t lo, const size_t hi, const integer_permutation &permutation, const integer_permutation &permutation_inv, as_waksman_routing &routing)
Definition: as_waksman_routing_algorithm.cpp:308
libsnark::construct_as_waksman_inner
void construct_as_waksman_inner(const size_t left, const size_t right, const size_t lo, const size_t hi, const std::vector< size_t > rhs_dests, as_waksman_topology &neighbors)
Definition: as_waksman_routing_algorithm.cpp:87
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::as_waksman_routing
std::vector< std::map< size_t, bool > > as_waksman_routing
Definition: as_waksman_routing_algorithm.hpp:102
libsnark::as_waksman_num_columns
size_t as_waksman_num_columns(const size_t num_packets)
Definition: as_waksman_routing_algorithm.cpp:69
libsnark::valid_as_waksman_routing
bool valid_as_waksman_routing(const integer_permutation &permutation, const as_waksman_routing &routing)
Definition: as_waksman_routing_algorithm.cpp:586
as_waksman_routing_algorithm.hpp