2 *****************************************************************************
4 Declaration of interfaces for:
6 - a R1CS variable assignment, and
7 - a R1CS constraint system.
11 *****************************************************************************
12 * @author This file is part of libsnark, developed by SCIPR Lab
13 * and contributors (see AUTHORS).
14 * @copyright MIT license (see LICENSE file)
15 *****************************************************************************/
22 #include <libff/algebra/fields/bigint.hpp>
23 #include <libff/common/profiling.hpp>
24 #include <libff/common/utils.hpp>
30 template<typename FieldT>
31 r1cs_constraint<FieldT>::r1cs_constraint(
32 const linear_combination<FieldT> &a,
33 const linear_combination<FieldT> &b,
34 const linear_combination<FieldT> &c)
39 template<typename FieldT>
40 r1cs_constraint<FieldT>::r1cs_constraint(
41 const std::initializer_list<linear_combination<FieldT>> &A,
42 const std::initializer_list<linear_combination<FieldT>> &B,
43 const std::initializer_list<linear_combination<FieldT>> &C)
46 a.terms.insert(a.terms.end(), lc_A.terms.begin(), lc_A.terms.end());
49 b.terms.insert(b.terms.end(), lc_B.terms.begin(), lc_B.terms.end());
52 c.terms.insert(c.terms.end(), lc_C.terms.begin(), lc_C.terms.end());
56 template<typename FieldT>
57 bool r1cs_constraint<FieldT>::operator==(
58 const r1cs_constraint<FieldT> &other) const
60 return (this->a == other.a && this->b == other.b && this->c == other.c);
63 template<typename FieldT>
64 std::ostream &operator<<(std::ostream &out, const r1cs_constraint<FieldT> &c)
73 template<typename FieldT>
74 std::istream &operator>>(std::istream &in, r1cs_constraint<FieldT> &c)
83 template<typename FieldT>
84 size_t r1cs_constraint_system<FieldT>::num_inputs() const
86 return primary_input_size;
89 template<typename FieldT>
90 size_t r1cs_constraint_system<FieldT>::num_variables() const
92 return primary_input_size + auxiliary_input_size;
95 template<typename FieldT>
96 size_t r1cs_constraint_system<FieldT>::num_constraints() const
98 return constraints.size();
101 template<typename FieldT> bool r1cs_constraint_system<FieldT>::is_valid() const
103 if (this->num_inputs() > this->num_variables())
106 for (size_t c = 0; c < constraints.size(); ++c) {
107 if (!(constraints[c].a.is_valid(this->num_variables()) &&
108 constraints[c].b.is_valid(this->num_variables()) &&
109 constraints[c].c.is_valid(this->num_variables()))) {
117 template<typename FieldT>
118 void dump_r1cs_constraint(
119 const r1cs_constraint<FieldT> &constraint,
120 const r1cs_variable_assignment<FieldT> &full_variable_assignment,
121 const std::map<size_t, std::string> &variable_annotations)
123 printf("terms for a:\n");
124 constraint.a.print_with_assignment(
125 full_variable_assignment, variable_annotations);
126 printf("terms for b:\n");
127 constraint.b.print_with_assignment(
128 full_variable_assignment, variable_annotations);
129 printf("terms for c:\n");
130 constraint.c.print_with_assignment(
131 full_variable_assignment, variable_annotations);
134 template<typename FieldT>
135 bool r1cs_constraint_system<FieldT>::is_satisfied(
136 const r1cs_primary_input<FieldT> &primary_input,
137 const r1cs_auxiliary_input<FieldT> &auxiliary_input) const
139 assert(primary_input.size() == num_inputs());
140 assert(primary_input.size() + auxiliary_input.size() == num_variables());
142 r1cs_variable_assignment<FieldT> full_variable_assignment = primary_input;
143 full_variable_assignment.insert(
144 full_variable_assignment.end(),
145 auxiliary_input.begin(),
146 auxiliary_input.end());
148 for (size_t c = 0; c < constraints.size(); ++c) {
149 const FieldT ares = constraints[c].a.evaluate(full_variable_assignment);
150 const FieldT bres = constraints[c].b.evaluate(full_variable_assignment);
151 const FieldT cres = constraints[c].c.evaluate(full_variable_assignment);
153 if (!(ares * bres == cres)) {
155 auto it = constraint_annotations.find(c);
157 "constraint %zu (%s) unsatisfied\n",
159 (it == constraint_annotations.end() ? "no annotation"
160 : it->second.c_str()));
161 printf("<a,(1,x)> = ");
163 printf("<b,(1,x)> = ");
165 printf("<c,(1,x)> = ");
167 printf("constraint was:\n");
168 dump_r1cs_constraint(
169 constraints[c], full_variable_assignment, variable_annotations);
178 template<typename FieldT>
179 void r1cs_constraint_system<FieldT>::add_constraint(
180 const r1cs_constraint<FieldT> &c)
182 constraints.emplace_back(c);
185 template<typename FieldT>
186 void r1cs_constraint_system<FieldT>::add_constraint(
187 const r1cs_constraint<FieldT> &c, const std::string &annotation)
190 constraint_annotations[constraints.size()] = annotation;
192 libff::UNUSED(annotation);
194 constraints.emplace_back(c);
197 template<typename FieldT>
198 void r1cs_constraint_system<FieldT>::swap_AB_if_beneficial()
200 libff::enter_block("Call to r1cs_constraint_system::swap_AB_if_beneficial");
202 libff::enter_block("Estimate densities");
203 libff::bit_vector touched_by_A(this->num_variables() + 1, false),
204 touched_by_B(this->num_variables() + 1, false);
206 for (size_t i = 0; i < this->constraints.size(); ++i) {
207 for (size_t j = 0; j < this->constraints[i].a.terms.size(); ++j) {
208 touched_by_A[this->constraints[i].a.terms[j].index] = true;
211 for (size_t j = 0; j < this->constraints[i].b.terms.size(); ++j) {
212 touched_by_B[this->constraints[i].b.terms[j].index] = true;
216 size_t non_zero_A_count = 0, non_zero_B_count = 0;
217 for (size_t i = 0; i < this->num_variables() + 1; ++i) {
218 non_zero_A_count += touched_by_A[i] ? 1 : 0;
219 non_zero_B_count += touched_by_B[i] ? 1 : 0;
222 if (!libff::inhibit_profiling_info) {
223 libff::print_indent();
224 printf("* Non-zero A-count (estimate): %zu\n", non_zero_A_count);
225 libff::print_indent();
226 printf("* Non-zero B-count (estimate): %zu\n", non_zero_B_count);
228 libff::leave_block("Estimate densities");
230 if (non_zero_B_count > non_zero_A_count) {
231 libff::enter_block("Perform the swap");
232 for (size_t i = 0; i < this->constraints.size(); ++i) {
233 std::swap(this->constraints[i].a, this->constraints[i].b);
235 libff::leave_block("Perform the swap");
237 libff::print_indent();
238 printf("Swap is not beneficial, not performing\n");
241 libff::leave_block("Call to r1cs_constraint_system::swap_AB_if_beneficial");
244 template<typename FieldT>
245 bool r1cs_constraint_system<FieldT>::operator==(
246 const r1cs_constraint_system<FieldT> &other) const
249 this->constraints == other.constraints &&
250 this->primary_input_size == other.primary_input_size &&
251 this->auxiliary_input_size == other.auxiliary_input_size);
254 template<typename FieldT>
255 std::ostream &operator<<(
256 std::ostream &out, const r1cs_constraint_system<FieldT> &cs)
258 out << cs.primary_input_size << "\n";
259 out << cs.auxiliary_input_size << "\n";
261 out << cs.num_constraints() << "\n";
262 for (const r1cs_constraint<FieldT> &c : cs.constraints) {
269 template<typename FieldT>
270 std::istream &operator>>(std::istream &in, r1cs_constraint_system<FieldT> &cs)
272 in >> cs.primary_input_size;
273 in >> cs.auxiliary_input_size;
275 cs.constraints.clear();
283 cs.constraints.reserve(s);
285 for (size_t i = 0; i < s; ++i) {
286 r1cs_constraint<FieldT> c;
288 cs.constraints.emplace_back(c);
294 template<typename FieldT>
295 void r1cs_constraint_system<FieldT>::report_linear_constraint_statistics() const
298 for (size_t i = 0; i < constraints.size(); ++i) {
299 auto &constr = constraints[i];
300 bool a_is_const = true;
301 for (auto &t : constr.a.terms) {
302 a_is_const = a_is_const && (t.index == 0);
305 bool b_is_const = true;
306 for (auto &t : constr.b.terms) {
307 b_is_const = b_is_const && (t.index == 0);
310 if (a_is_const || b_is_const) {
311 auto it = constraint_annotations.find(i);
314 (it == constraint_annotations.end()
315 ? FMT("", "constraint_%zu", i)
323 } // namespace libsnark