Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
bacs.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for:
5  - a BACS variable assignment,
6  - a BACS gate,
7  - a BACS primary input,
8  - a BACS auxiliary input,
9  - a BACS circuit.
10 
11  See bacs.hpp .
12 
13  *****************************************************************************
14  * @author This file is part of libsnark, developed by SCIPR Lab
15  * and contributors (see AUTHORS).
16  * @copyright MIT license (see LICENSE file)
17  *****************************************************************************/
18 
19 #ifndef BACS_TCC_
20 #define BACS_TCC_
21 
22 #include <algorithm>
23 #include <libff/common/profiling.hpp>
24 #include <libff/common/utils.hpp>
25 
26 namespace libsnark
27 {
28 
29 template<typename FieldT>
30 FieldT bacs_gate<FieldT>::evaluate(
31  const bacs_variable_assignment<FieldT> &input) const
32 {
33  return lhs.evaluate(input) * rhs.evaluate(input);
34 }
35 
36 template<typename FieldT>
37 void bacs_gate<FieldT>::print(
38  const std::map<size_t, std::string> &variable_annotations) const
39 {
40  printf("(\n");
41  lhs.print(variable_annotations);
42  printf(")\n *\n(\n");
43  rhs.print(variable_annotations);
44  printf(")\n -> \n");
45  auto it = variable_annotations.find(output.index);
46  printf(
47  " x_%zu (%s) (%s)\n",
48  output.index,
49  (it == variable_annotations.end() ? "no annotation"
50  : it->second.c_str()),
51  (is_circuit_output ? "circuit output" : "internal wire"));
52 }
53 
54 template<typename FieldT>
55 bool bacs_gate<FieldT>::operator==(const bacs_gate<FieldT> &other) const
56 {
57  return (
58  this->lhs == other.lhs && this->rhs == other.rhs &&
59  this->output == other.output &&
60  this->is_circuit_output == other.is_circuit_output);
61 }
62 
63 template<typename FieldT>
64 std::ostream &operator<<(std::ostream &out, const bacs_gate<FieldT> &g)
65 {
66  out << (g.is_circuit_output ? 1 : 0) << "\n";
67  out << g.lhs << OUTPUT_NEWLINE;
68  out << g.rhs << OUTPUT_NEWLINE;
69  out << g.output.index << "\n";
70 
71  return out;
72 }
73 
74 template<typename FieldT>
75 std::istream &operator>>(std::istream &in, bacs_gate<FieldT> &g)
76 {
77  size_t tmp;
78  in >> tmp;
79  libff::consume_newline(in);
80  g.is_circuit_output = (tmp != 0 ? true : false);
81  in >> g.lhs;
82  libff::consume_OUTPUT_NEWLINE(in);
83  in >> g.rhs;
84  libff::consume_OUTPUT_NEWLINE(in);
85  in >> g.output.index;
86  libff::consume_newline(in);
87 
88  return in;
89 }
90 
91 template<typename FieldT> size_t bacs_circuit<FieldT>::num_inputs() const
92 {
93  return primary_input_size + auxiliary_input_size;
94 }
95 
96 template<typename FieldT> size_t bacs_circuit<FieldT>::num_gates() const
97 {
98  return gates.size();
99 }
100 
101 template<typename FieldT> size_t bacs_circuit<FieldT>::num_wires() const
102 {
103  return num_inputs() + num_gates();
104 }
105 
106 template<typename FieldT>
107 std::vector<size_t> bacs_circuit<FieldT>::wire_depths() const
108 {
109  std::vector<size_t> depths;
110  depths.emplace_back(0);
111  depths.resize(num_inputs() + 1, 1);
112 
113  for (auto &g : gates) {
114  size_t max_depth = 0;
115  for (auto &t : g.lhs) {
116  max_depth = std::max(max_depth, depths[t.index]);
117  }
118 
119  for (auto &t : g.rhs) {
120  max_depth = std::max(max_depth, depths[t.index]);
121  }
122 
123  depths.emplace_back(max_depth + 1);
124  }
125 
126  return depths;
127 }
128 
129 template<typename FieldT> size_t bacs_circuit<FieldT>::depth() const
130 {
131  std::vector<size_t> all_depths = this->wire_depths();
132  return *(std::max_element(all_depths.begin(), all_depths.end()));
133 }
134 
135 template<typename FieldT> bool bacs_circuit<FieldT>::is_valid() const
136 {
137  for (size_t i = 0; i < num_gates(); ++i) {
138  /**
139  * The output wire of gates[i] must have index 1+num_inputs+i.
140  * (The '1+' accounts for the the index of the constant wire.)
141  */
142  if (gates[i].output.index != 1 + num_inputs() + i) {
143  return false;
144  }
145 
146  /**
147  * Gates must be topologically sorted.
148  */
149  if (!gates[i].lhs.is_valid(gates[i].output.index) ||
150  !gates[i].rhs.is_valid(gates[i].output.index)) {
151  return false;
152  }
153  }
154 
155  return true;
156 }
157 
158 template<typename FieldT>
159 bacs_variable_assignment<FieldT> bacs_circuit<FieldT>::get_all_wires(
160  const bacs_primary_input<FieldT> &primary_input,
161  const bacs_auxiliary_input<FieldT> &auxiliary_input) const
162 {
163  assert(primary_input.size() == primary_input_size);
164  assert(auxiliary_input.size() == auxiliary_input_size);
165 
166  bacs_variable_assignment<FieldT> result;
167  result.insert(result.end(), primary_input.begin(), primary_input.end());
168  result.insert(result.end(), auxiliary_input.begin(), auxiliary_input.end());
169 
170  assert(result.size() == num_inputs());
171 
172  for (auto &g : gates) {
173  const FieldT gate_output = g.evaluate(result);
174  result.emplace_back(gate_output);
175  }
176 
177  return result;
178 }
179 
180 template<typename FieldT>
181 bacs_variable_assignment<FieldT> bacs_circuit<FieldT>::get_all_outputs(
182  const bacs_primary_input<FieldT> &primary_input,
183  const bacs_auxiliary_input<FieldT> &auxiliary_input) const
184 {
185  const bacs_variable_assignment<FieldT> all_wires =
186  get_all_wires(primary_input, auxiliary_input);
187 
188  bacs_variable_assignment<FieldT> all_outputs;
189 
190  for (auto &g : gates) {
191  if (g.is_circuit_output) {
192  all_outputs.emplace_back(all_wires[g.output.index - 1]);
193  }
194  }
195 
196  return all_outputs;
197 }
198 
199 template<typename FieldT>
200 bool bacs_circuit<FieldT>::is_satisfied(
201  const bacs_primary_input<FieldT> &primary_input,
202  const bacs_auxiliary_input<FieldT> &auxiliary_input) const
203 {
204  const bacs_variable_assignment<FieldT> all_outputs =
205  get_all_outputs(primary_input, auxiliary_input);
206 
207  for (size_t i = 0; i < all_outputs.size(); ++i) {
208  if (!all_outputs[i].is_zero()) {
209  return false;
210  }
211  }
212 
213  return true;
214 }
215 
216 template<typename FieldT>
217 void bacs_circuit<FieldT>::add_gate(const bacs_gate<FieldT> &g)
218 {
219  assert(g.output.index == num_wires() + 1);
220  gates.emplace_back(g);
221 }
222 
223 template<typename FieldT>
224 void bacs_circuit<FieldT>::add_gate(
225  const bacs_gate<FieldT> &g, const std::string &annotation)
226 {
227  libff::UNUSED(annotation);
228  assert(g.output.index == num_wires() + 1);
229  gates.emplace_back(g);
230 #ifdef DEBUG
231  gate_annotations[g.output.index] = annotation;
232 #endif
233 }
234 
235 template<typename FieldT>
236 bool bacs_circuit<FieldT>::operator==(const bacs_circuit<FieldT> &other) const
237 {
238  return (
239  this->primary_input_size == other.primary_input_size &&
240  this->auxiliary_input_size == other.auxiliary_input_size &&
241  this->gates == other.gates);
242 }
243 
244 template<typename FieldT>
245 std::ostream &operator<<(std::ostream &out, const bacs_circuit<FieldT> &circuit)
246 {
247  out << circuit.primary_input_size << "\n";
248  out << circuit.auxiliary_input_size << "\n";
249  libff::operator<<(out, circuit.gates);
250  out << OUTPUT_NEWLINE;
251 
252  return out;
253 }
254 
255 template<typename FieldT>
256 std::istream &operator>>(std::istream &in, bacs_circuit<FieldT> &circuit)
257 {
258  in >> circuit.primary_input_size;
259  libff::consume_newline(in);
260  in >> circuit.auxiliary_input_size;
261  libff::consume_newline(in);
262  libff::operator>>(in, circuit.gates);
263  libff::consume_OUTPUT_NEWLINE(in);
264 
265  return in;
266 }
267 
268 template<typename FieldT> void bacs_circuit<FieldT>::print() const
269 {
270  libff::print_indent();
271  printf("General information about the circuit:\n");
272  this->print_info();
273  libff::print_indent();
274  printf("All gates:\n");
275  for (size_t i = 0; i < gates.size(); ++i) {
276  std::string annotation = "no annotation";
277 #ifdef DEBUG
278  auto it = gate_annotations.find(i);
279  if (it != gate_annotations.end()) {
280  annotation = it->second;
281  }
282 #endif
283  printf("Gate %zu (%s):\n", i, annotation.c_str());
284 #ifdef DEBUG
285  gates[i].print(variable_annotations);
286 #else
287  gates[i].print();
288 #endif
289  }
290 }
291 
292 template<typename FieldT> void bacs_circuit<FieldT>::print_info() const
293 {
294  libff::print_indent();
295  printf("* Number of inputs: %zu\n", this->num_inputs());
296  libff::print_indent();
297  printf("* Number of gates: %zu\n", this->num_gates());
298  libff::print_indent();
299  printf("* Number of wires: %zu\n", this->num_wires());
300  libff::print_indent();
301  printf("* Depth: %zu\n", this->depth());
302 }
303 
304 } // namespace libsnark
305 
306 #endif // BACS_TCC_