r1cs_to_qap.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 // @file Declaration of interfaces for a R1CS-to-QAP reduction, that is, constructing
26 // a QAP ("Quadratic Arithmetic Program") from a R1CS ("Rank-1 Constraint System").
27 //
28 // QAPs are defined in \[GGPR13], and constructed for R1CS also in \[GGPR13].
29 //
30 // The implementation of the reduction follows, extends, and optimizes
31 // the efficient approach described in Appendix E of \[BCGTV13].
32 //
33 // References:
34 //
35 // \[BCGTV13]
36 // "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge",
37 // Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza,
38 // CRYPTO 2013,
39 // <http://eprint.iacr.org/2013/507>
40 //
41 // \[GGPR13]:
42 // "Quadratic span programs and succinct NIZKs without PCPs",
43 // Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova,
44 // EUROCRYPT 2013,
45 // <http://eprint.iacr.org/2012/215>
46 //---------------------------------------------------------------------------//
47 
48 #ifndef CRYPTO3_ZK_R1CS_TO_QAP_BASIC_POLICY_HPP
49 #define CRYPTO3_ZK_R1CS_TO_QAP_BASIC_POLICY_HPP
50 
54 
57 
59 
60 namespace nil {
61  namespace crypto3 {
62  namespace zk {
63  namespace snark {
64  namespace reductions {
65  template<typename FieldType>
66  struct r1cs_to_qap {
67  typedef FieldType field_type;
68 
82 
83  const std::shared_ptr<math::evaluation_domain<FieldType>> domain =
84  math::make_evaluation_domain<FieldType>(cs.num_constraints() + cs.num_inputs() + 1);
85 
86  std::vector<std::map<std::size_t, typename FieldType::value_type>> A_in_Lagrange_basis(
87  cs.num_variables() + 1);
88  std::vector<std::map<std::size_t, typename FieldType::value_type>> B_in_Lagrange_basis(
89  cs.num_variables() + 1);
90  std::vector<std::map<std::size_t, typename FieldType::value_type>> C_in_Lagrange_basis(
91  cs.num_variables() + 1);
92 
98  for (std::size_t i = 0; i <= cs.num_inputs(); ++i) {
99  A_in_Lagrange_basis[i][cs.num_constraints() + i] = FieldType::value_type::one();
100  }
101  /* process all other constraints */
102  for (std::size_t i = 0; i < cs.num_constraints(); ++i) {
103  for (std::size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) {
104  A_in_Lagrange_basis[cs.constraints[i].a.terms[j].index][i] +=
105  cs.constraints[i].a.terms[j].coeff;
106  }
107 
108  for (std::size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) {
109  B_in_Lagrange_basis[cs.constraints[i].b.terms[j].index][i] +=
110  cs.constraints[i].b.terms[j].coeff;
111  }
112 
113  for (std::size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) {
114  C_in_Lagrange_basis[cs.constraints[i].c.terms[j].index][i] +=
115  cs.constraints[i].c.terms[j].coeff;
116  }
117  }
118 
120  domain, cs.num_variables(), domain->m, cs.num_inputs(), std::move(A_in_Lagrange_basis),
121  std::move(B_in_Lagrange_basis), std::move(C_in_Lagrange_basis));
122  }
123 
141  const typename FieldType::value_type &t) {
142  const std::shared_ptr<math::evaluation_domain<FieldType>> domain =
143  math::make_evaluation_domain<FieldType>(cs.num_constraints() + cs.num_inputs() + 1);
144 
145  std::vector<typename FieldType::value_type> At, Bt, Ct, Ht;
146 
147  At.resize(cs.num_variables() + 1, FieldType::value_type::zero());
148  Bt.resize(cs.num_variables() + 1, FieldType::value_type::zero());
149  Ct.resize(cs.num_variables() + 1, FieldType::value_type::zero());
150  Ht.reserve(domain->m + 1);
151 
152  const typename FieldType::value_type Zt = domain->compute_vanishing_polynomial(t);
153 
154  const std::vector<typename FieldType::value_type> u =
155  domain->evaluate_all_lagrange_polynomials(t);
161  for (std::size_t i = 0; i <= cs.num_inputs(); ++i) {
162  At[i] = u[cs.num_constraints() + i];
163  }
164  /* process all other constraints */
165  for (std::size_t i = 0; i < cs.num_constraints(); ++i) {
166  for (std::size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) {
167  At[cs.constraints[i].a.terms[j].index] += u[i] * cs.constraints[i].a.terms[j].coeff;
168  }
169 
170  for (std::size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) {
171  Bt[cs.constraints[i].b.terms[j].index] += u[i] * cs.constraints[i].b.terms[j].coeff;
172  }
173 
174  for (std::size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) {
175  Ct[cs.constraints[i].c.terms[j].index] += u[i] * cs.constraints[i].c.terms[j].coeff;
176  }
177  }
178 
179  typename FieldType::value_type ti = FieldType::value_type::one();
180  for (std::size_t i = 0; i < domain->m + 1; ++i) {
181  Ht.emplace_back(ti);
182  ti *= t;
183  }
184 
185  return qap_instance_evaluation<FieldType>(domain, cs.num_variables(), domain->m,
186  cs.num_inputs(), t, std::move(At), std::move(Bt),
187  std::move(Ct), std::move(Ht), Zt);
188  }
189 
222  const r1cs_primary_input<FieldType> &primary_input,
223  const r1cs_auxiliary_input<FieldType> &auxiliary_input,
224  const typename FieldType::value_type &d1,
225  const typename FieldType::value_type &d2,
226  const typename FieldType::value_type &d3) {
227  /* sanity check */
228  assert(cs.is_satisfied(primary_input, auxiliary_input));
229 
230  const std::shared_ptr<math::evaluation_domain<FieldType>> domain =
231  math::make_evaluation_domain<FieldType>(cs.num_constraints() + cs.num_inputs() + 1);
232 
233  r1cs_variable_assignment<FieldType> full_variable_assignment = primary_input;
234  full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(),
235  auxiliary_input.end());
236 
237  std::vector<typename FieldType::value_type> aA(domain->m, FieldType::value_type::zero()),
238  aB(domain->m, FieldType::value_type::zero());
239 
240  /* account for the additional constraints input_i * 0 = 0 */
241  for (std::size_t i = 0; i <= cs.num_inputs(); ++i) {
242  aA[i + cs.num_constraints()] =
243  (i > 0 ? full_variable_assignment[i - 1] : FieldType::value_type::one());
244  }
245  /* account for all other constraints */
246  for (std::size_t i = 0; i < cs.num_constraints(); ++i) {
247  aA[i] += cs.constraints[i].a.evaluate(full_variable_assignment);
248  aB[i] += cs.constraints[i].b.evaluate(full_variable_assignment);
249  }
250 
251  domain->inverse_fft(aA);
252 
253  domain->inverse_fft(aB);
254 
255  std::vector<typename FieldType::value_type> coefficients_for_H(
256  domain->m + 1, FieldType::value_type::zero());
257 #ifdef MULTICORE
258 #pragma omp parallel for
259 #endif
260  /* add coefficients of the polynomial (d2*A + d1*B - d3) + d1*d2*Z */
261  for (std::size_t i = 0; i < domain->m; ++i) {
262  coefficients_for_H[i] = d2 * aA[i] + d1 * aB[i];
263  }
264  coefficients_for_H[0] -= d3;
265  domain->add_poly_z(d1 * d2, coefficients_for_H);
266 
268  aA,
269  typename FieldType::value_type(
271  domain->fft(aA);
272 
274  aB,
275  typename FieldType::value_type(
277  domain->fft(aB);
278 
279  std::vector<typename FieldType::value_type> &H_tmp = aA;
280  // can overwrite aA because it is not used later
281 #ifdef MULTICORE
282 #pragma omp parallel for
283 #endif
284  for (std::size_t i = 0; i < domain->m; ++i) {
285  H_tmp[i] = aA[i] * aB[i];
286  }
287  std::vector<typename FieldType::value_type>().swap(aB); // destroy aB
288 
289  std::vector<typename FieldType::value_type> aC(domain->m, FieldType::value_type::zero());
290  for (std::size_t i = 0; i < cs.num_constraints(); ++i) {
291  aC[i] += cs.constraints[i].c.evaluate(full_variable_assignment);
292  }
293 
294  domain->inverse_fft(aC);
295 
297  aC,
298  typename FieldType::value_type(
300  domain->fft(aC);
301 
302 #ifdef MULTICORE
303 #pragma omp parallel for
304 #endif
305  for (std::size_t i = 0; i < domain->m; ++i) {
306  H_tmp[i] = (H_tmp[i] - aC[i]);
307  }
308 
309  domain->divide_by_z_on_coset(H_tmp);
310 
311  domain->inverse_fft(H_tmp);
312 
313  multiply_by_coset(H_tmp,
314  typename FieldType::value_type(
316  .inversed());
317 #ifdef MULTICORE
318 #pragma omp parallel for
319 #endif
320  for (std::size_t i = 0; i < domain->m; ++i) {
321  coefficients_for_H[i] += H_tmp[i];
322  }
323 
324  return qap_witness<FieldType>(cs.num_variables(), domain->m, cs.num_inputs(), d1, d2, d3,
325  full_variable_assignment, std::move(coefficients_for_H));
326  }
327  };
328  } // namespace reductions
329  } // namespace snark
330  } // namespace zk
331  } // namespace crypto3
332 } // namespace nil
333 
334 #endif // CRYPTO3_ZK_R1CS_TO_QAP_BASIC_POLICY_HPP
OutputIterator move(const SinglePassRange &rng, OutputIterator result)
Definition: move.hpp:45
void multiply_by_coset(Range &a, const FieldValueType &g)
Definition: coset.hpp:37
std::vector< typename FieldType::value_type > r1cs_auxiliary_input
Definition: r1cs.hpp:104
std::vector< typename FieldType::value_type > r1cs_primary_input
Definition: r1cs.hpp:101
std::vector< typename FieldType::value_type > r1cs_variable_assignment
Definition: r1cs.hpp:107
Definition: pair.hpp:31
Definition: fields/params.hpp:58
bool is_satisfied(const r1cs_primary_input< FieldType > &primary_input, const r1cs_auxiliary_input< FieldType > &auxiliary_input) const
Definition: r1cs.hpp:162
std::vector< r1cs_constraint< FieldType > > constraints
Definition: r1cs.hpp:130
std::size_t num_constraints() const
Definition: r1cs.hpp:143
std::size_t num_inputs() const
Definition: r1cs.hpp:135
std::size_t num_variables() const
Definition: r1cs.hpp:139
FieldType field_type
Definition: r1cs_to_qap.hpp:67
static qap_instance_evaluation< FieldType > instance_map_with_evaluation(const r1cs_constraint_system< FieldType > &cs, const typename FieldType::value_type &t)
Definition: r1cs_to_qap.hpp:140
static qap_instance< FieldType > instance_map(const r1cs_constraint_system< FieldType > &cs)
Definition: r1cs_to_qap.hpp:81
static qap_witness< FieldType > witness_map(const r1cs_constraint_system< FieldType > &cs, const r1cs_primary_input< FieldType > &primary_input, const r1cs_auxiliary_input< FieldType > &auxiliary_input, const typename FieldType::value_type &d1, const typename FieldType::value_type &d2, const typename FieldType::value_type &d3)
Definition: r1cs_to_qap.hpp:221