2 *****************************************************************************
4 Implementation of interfaces for:
5 - a BACS variable assignment,
7 - a BACS primary input,
8 - a BACS auxiliary input,
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 *****************************************************************************/
23 #include <libff/common/profiling.hpp>
24 #include <libff/common/utils.hpp>
29 template<typename FieldT>
30 FieldT bacs_gate<FieldT>::evaluate(
31 const bacs_variable_assignment<FieldT> &input) const
33 return lhs.evaluate(input) * rhs.evaluate(input);
36 template<typename FieldT>
37 void bacs_gate<FieldT>::print(
38 const std::map<size_t, std::string> &variable_annotations) const
41 lhs.print(variable_annotations);
43 rhs.print(variable_annotations);
45 auto it = variable_annotations.find(output.index);
49 (it == variable_annotations.end() ? "no annotation"
50 : it->second.c_str()),
51 (is_circuit_output ? "circuit output" : "internal wire"));
54 template<typename FieldT>
55 bool bacs_gate<FieldT>::operator==(const bacs_gate<FieldT> &other) const
58 this->lhs == other.lhs && this->rhs == other.rhs &&
59 this->output == other.output &&
60 this->is_circuit_output == other.is_circuit_output);
63 template<typename FieldT>
64 std::ostream &operator<<(std::ostream &out, const bacs_gate<FieldT> &g)
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";
74 template<typename FieldT>
75 std::istream &operator>>(std::istream &in, bacs_gate<FieldT> &g)
79 libff::consume_newline(in);
80 g.is_circuit_output = (tmp != 0 ? true : false);
82 libff::consume_OUTPUT_NEWLINE(in);
84 libff::consume_OUTPUT_NEWLINE(in);
86 libff::consume_newline(in);
91 template<typename FieldT> size_t bacs_circuit<FieldT>::num_inputs() const
93 return primary_input_size + auxiliary_input_size;
96 template<typename FieldT> size_t bacs_circuit<FieldT>::num_gates() const
101 template<typename FieldT> size_t bacs_circuit<FieldT>::num_wires() const
103 return num_inputs() + num_gates();
106 template<typename FieldT>
107 std::vector<size_t> bacs_circuit<FieldT>::wire_depths() const
109 std::vector<size_t> depths;
110 depths.emplace_back(0);
111 depths.resize(num_inputs() + 1, 1);
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]);
119 for (auto &t : g.rhs) {
120 max_depth = std::max(max_depth, depths[t.index]);
123 depths.emplace_back(max_depth + 1);
129 template<typename FieldT> size_t bacs_circuit<FieldT>::depth() const
131 std::vector<size_t> all_depths = this->wire_depths();
132 return *(std::max_element(all_depths.begin(), all_depths.end()));
135 template<typename FieldT> bool bacs_circuit<FieldT>::is_valid() const
137 for (size_t i = 0; i < num_gates(); ++i) {
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.)
142 if (gates[i].output.index != 1 + num_inputs() + i) {
147 * Gates must be topologically sorted.
149 if (!gates[i].lhs.is_valid(gates[i].output.index) ||
150 !gates[i].rhs.is_valid(gates[i].output.index)) {
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
163 assert(primary_input.size() == primary_input_size);
164 assert(auxiliary_input.size() == auxiliary_input_size);
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());
170 assert(result.size() == num_inputs());
172 for (auto &g : gates) {
173 const FieldT gate_output = g.evaluate(result);
174 result.emplace_back(gate_output);
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
185 const bacs_variable_assignment<FieldT> all_wires =
186 get_all_wires(primary_input, auxiliary_input);
188 bacs_variable_assignment<FieldT> all_outputs;
190 for (auto &g : gates) {
191 if (g.is_circuit_output) {
192 all_outputs.emplace_back(all_wires[g.output.index - 1]);
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
204 const bacs_variable_assignment<FieldT> all_outputs =
205 get_all_outputs(primary_input, auxiliary_input);
207 for (size_t i = 0; i < all_outputs.size(); ++i) {
208 if (!all_outputs[i].is_zero()) {
216 template<typename FieldT>
217 void bacs_circuit<FieldT>::add_gate(const bacs_gate<FieldT> &g)
219 assert(g.output.index == num_wires() + 1);
220 gates.emplace_back(g);
223 template<typename FieldT>
224 void bacs_circuit<FieldT>::add_gate(
225 const bacs_gate<FieldT> &g, const std::string &annotation)
227 libff::UNUSED(annotation);
228 assert(g.output.index == num_wires() + 1);
229 gates.emplace_back(g);
231 gate_annotations[g.output.index] = annotation;
235 template<typename FieldT>
236 bool bacs_circuit<FieldT>::operator==(const bacs_circuit<FieldT> &other) const
239 this->primary_input_size == other.primary_input_size &&
240 this->auxiliary_input_size == other.auxiliary_input_size &&
241 this->gates == other.gates);
244 template<typename FieldT>
245 std::ostream &operator<<(std::ostream &out, const bacs_circuit<FieldT> &circuit)
247 out << circuit.primary_input_size << "\n";
248 out << circuit.auxiliary_input_size << "\n";
249 libff::operator<<(out, circuit.gates);
250 out << OUTPUT_NEWLINE;
255 template<typename FieldT>
256 std::istream &operator>>(std::istream &in, bacs_circuit<FieldT> &circuit)
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);
268 template<typename FieldT> void bacs_circuit<FieldT>::print() const
270 libff::print_indent();
271 printf("General information about the circuit:\n");
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";
278 auto it = gate_annotations.find(i);
279 if (it != gate_annotations.end()) {
280 annotation = it->second;
283 printf("Gate %zu (%s):\n", i, annotation.c_str());
285 gates[i].print(variable_annotations);
292 template<typename FieldT> void bacs_circuit<FieldT>::print_info() const
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());
304 } // namespace libsnark