Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
uscs_to_ssp.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for a USCS-to-SSP reduction.
5 
6  See uscs_to_ssp.hpp .
7 
8  *****************************************************************************
9  * @author This file is part of libsnark, developed by SCIPR Lab
10  * and contributors (see AUTHORS).
11  * @copyright MIT license (see LICENSE file)
12  *****************************************************************************/
13 
14 #ifndef USCS_TO_SSP_TCC_
15 #define USCS_TO_SSP_TCC_
16 
17 #include <libff/common/profiling.hpp>
18 #include <libff/common/utils.hpp>
19 #include <libfqfft/evaluation_domain/get_evaluation_domain.hpp>
20 
21 namespace libsnark
22 {
23 
24 /**
25  * Instance map for the USCS-to-SSP reduction.
26  *
27  * Namely, given a USCS constraint system cs, construct a SSP instance for
28  * which: V := (V_0(z),V_1(z),...,V_m(z)) where m = number of variables of the
29  * SSP and each V_i is expressed in the Lagrange basis.
30  */
31 template<typename FieldT>
32 ssp_instance<FieldT> uscs_to_ssp_instance_map(
33  const uscs_constraint_system<FieldT> &cs)
34 {
35  libff::enter_block("Call to uscs_to_ssp_instance_map");
36 
37  const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> domain =
38  libfqfft::get_evaluation_domain<FieldT>(cs.num_constraints());
39 
40  libff::enter_block("Compute polynomials V in Lagrange basis");
41  std::vector<std::map<size_t, FieldT>> V_in_Lagrange_basis(
42  cs.num_variables() + 1);
43  for (size_t i = 0; i < cs.num_constraints(); ++i) {
44  for (size_t j = 0; j < cs.constraints[i].terms.size(); ++j) {
45  V_in_Lagrange_basis[cs.constraints[i].terms[j].index][i] +=
46  cs.constraints[i].terms[j].coeff;
47  }
48  }
49  for (size_t i = cs.num_constraints(); i < domain->m; ++i) {
50  V_in_Lagrange_basis[0][i] += FieldT::one();
51  }
52  libff::leave_block("Compute polynomials V in Lagrange basis");
53 
54  libff::leave_block("Call to uscs_to_ssp_instance_map");
55 
56  return ssp_instance<FieldT>(
57  domain,
58  cs.num_variables(),
59  domain->m,
60  cs.num_inputs(),
61  std::move(V_in_Lagrange_basis));
62 }
63 
64 /**
65  * Instance map for the USCS-to-SSP reduction followed by evaluation of the
66  * resulting SSP instance.
67  *
68  * Namely, given a USCS constraint system cs and a field element t, construct
69  * a SSP instance (evaluated at t) for which:
70  * Vt := (V_0(t),V_1(t),...,V_m(t))
71  * Ht := (1,t,t^2,...,t^n)
72  * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t"
73  * where
74  * m = number of variables of the SSP
75  * n = degree of the SSP
76  */
77 template<typename FieldT>
78 ssp_instance_evaluation<FieldT> uscs_to_ssp_instance_map_with_evaluation(
79  const uscs_constraint_system<FieldT> &cs, const FieldT &t)
80 {
81  libff::enter_block("Call to uscs_to_ssp_instance_map_with_evaluation");
82 
83  const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> domain =
84  libfqfft::get_evaluation_domain<FieldT>(cs.num_constraints());
85 
86  std::vector<FieldT> Vt(cs.num_variables() + 1, FieldT::zero());
87  std::vector<FieldT> Ht(domain->m + 1);
88 
89  const FieldT Zt = domain->compute_vanishing_polynomial(t);
90 
91  libff::enter_block("Compute evaluations of V and H at t");
92  const std::vector<FieldT> u = domain->evaluate_all_lagrange_polynomials(t);
93  for (size_t i = 0; i < cs.num_constraints(); ++i) {
94  for (size_t j = 0; j < cs.constraints[i].terms.size(); ++j) {
95  Vt[cs.constraints[i].terms[j].index] +=
96  u[i] * cs.constraints[i].terms[j].coeff;
97  }
98  }
99  for (size_t i = cs.num_constraints(); i < domain->m; ++i) {
100  /* dummy constraint: 1^2 = 1 */
101  Vt[0] += u[i];
102  }
103  FieldT ti = FieldT::one();
104  for (size_t i = 0; i < domain->m + 1; ++i) {
105  Ht[i] = ti;
106  ti *= t;
107  }
108  libff::leave_block("Compute evaluations of V and H at t");
109 
110  libff::leave_block("Call to uscs_to_ssp_instance_map_with_evaluation");
111 
112  return ssp_instance_evaluation<FieldT>(
113  domain,
114  cs.num_variables(),
115  domain->m,
116  cs.num_inputs(),
117  t,
118  std::move(Vt),
119  std::move(Ht),
120  Zt);
121 }
122 
123 /**
124  * Witness map for the USCS-to-SSP reduction.
125  *
126  * The witness map takes zero knowledge into account when d is random.
127  *
128  * More precisely, compute the coefficients
129  * h_0,h_1,...,h_n
130  * of the polynomial
131  * H(z) := (V(z)^2-1)/Z(z)
132  * where
133  * V(z) := V_0(z) + \sum_{k=1}^{m} w_k V_k(z) + d * Z(z)
134  * Z(z) := "vanishing polynomial of set S"
135  * and
136  * m = number of variables of the SSP
137  * n = degree of the SSP
138  *
139  * This is done as follows:
140  * (1) compute evaluations of V on S = {sigma_1,...,sigma_n}
141  * (2) compute coefficients of V
142  * (3) compute evaluations of V on T = "coset of S"
143  * (4) compute evaluation of H on T
144  * (5) compute coefficients of H
145  * (6) patch H to account for d (i.e., add coefficients of the polynomial
146  * 2*d*V(z) + d*d*Z(z) )
147  *
148  * The code below is not as simple as the above high-level description due to
149  * some reshuffling to save space.
150  */
151 template<typename FieldT>
152 ssp_witness<FieldT> uscs_to_ssp_witness_map(
153  const uscs_constraint_system<FieldT> &cs,
154  const uscs_primary_input<FieldT> &primary_input,
155  const uscs_auxiliary_input<FieldT> &auxiliary_input,
156  const FieldT &d)
157 {
158  libff::enter_block("Call to uscs_to_ssp_witness_map");
159 
160  /* sanity check */
161 
162  assert(cs.is_satisfied(primary_input, auxiliary_input));
163 
164  uscs_variable_assignment<FieldT> full_variable_assignment = primary_input;
165  full_variable_assignment.insert(
166  full_variable_assignment.end(),
167  auxiliary_input.begin(),
168  auxiliary_input.end());
169 
170  const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> domain =
171  libfqfft::get_evaluation_domain<FieldT>(cs.num_constraints());
172 
173  libff::enter_block("Compute evaluation of polynomial V on set S");
174  std::vector<FieldT> aA(domain->m, FieldT::zero());
175  assert(domain->m >= cs.num_constraints());
176  for (size_t i = 0; i < cs.num_constraints(); ++i) {
177  aA[i] += cs.constraints[i].evaluate(full_variable_assignment);
178  }
179  for (size_t i = cs.num_constraints(); i < domain->m; ++i) {
180  aA[i] += FieldT::one();
181  }
182  libff::leave_block("Compute evaluation of polynomial V on set S");
183 
184  libff::enter_block("Compute coefficients of polynomial V");
185  domain->iFFT(aA);
186  libff::leave_block("Compute coefficients of polynomial V");
187 
188  libff::enter_block("Compute ZK-patch");
189  std::vector<FieldT> coefficients_for_H(domain->m + 1, FieldT::zero());
190 #ifdef MULTICORE
191 #pragma omp parallel for
192 #endif
193  /* add coefficients of the polynomial 2*d*V(z) + d*d*Z(z) */
194  for (size_t i = 0; i < domain->m; ++i) {
195  coefficients_for_H[i] = FieldT(2) * d * aA[i];
196  }
197  domain->add_poly_Z(d.squared(), coefficients_for_H);
198  libff::leave_block("Compute ZK-patch");
199 
200  libff::enter_block("Compute evaluation of polynomial V on set T");
201  domain->cosetFFT(aA, FieldT::multiplicative_generator);
202  libff::leave_block("Compute evaluation of polynomial V on set T");
203 
204  libff::enter_block("Compute evaluation of polynomial H on set T");
205  std::vector<FieldT> &H_tmp =
206  aA; // can overwrite aA because it is not used later
207 #ifdef MULTICORE
208 #pragma omp parallel for
209 #endif
210  for (size_t i = 0; i < domain->m; ++i) {
211  H_tmp[i] = aA[i].squared() - FieldT::one();
212  }
213 
214  libff::enter_block("Divide by Z on set T");
215  domain->divide_by_Z_on_coset(H_tmp);
216  libff::leave_block("Divide by Z on set T");
217 
218  libff::leave_block("Compute evaluation of polynomial H on set T");
219 
220  libff::enter_block("Compute coefficients of polynomial H");
221  domain->icosetFFT(H_tmp, FieldT::multiplicative_generator);
222  libff::leave_block("Compute coefficients of polynomial H");
223 
224  libff::enter_block("Compute sum of H and ZK-patch");
225 #ifdef MULTICORE
226 #pragma omp parallel for
227 #endif
228  for (size_t i = 0; i < domain->m; ++i) {
229  coefficients_for_H[i] += H_tmp[i];
230  }
231  libff::leave_block("Compute sum of H and ZK-patch");
232 
233  libff::leave_block("Call to uscs_to_ssp_witness_map");
234 
235  return ssp_witness<FieldT>(
236  cs.num_variables(),
237  domain->m,
238  cs.num_inputs(),
239  d,
240  full_variable_assignment,
241  std::move(coefficients_for_H));
242 }
243 
244 } // namespace libsnark
245 
246 #endif // USCS_TO_SSP_TCC_