2 *****************************************************************************
4 Implementation of interfaces for a USCS-to-SSP reduction.
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 *****************************************************************************/
14 #ifndef USCS_TO_SSP_TCC_
15 #define USCS_TO_SSP_TCC_
17 #include <libff/common/profiling.hpp>
18 #include <libff/common/utils.hpp>
19 #include <libfqfft/evaluation_domain/get_evaluation_domain.hpp>
25 * Instance map for the USCS-to-SSP reduction.
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.
31 template<typename FieldT>
32 ssp_instance<FieldT> uscs_to_ssp_instance_map(
33 const uscs_constraint_system<FieldT> &cs)
35 libff::enter_block("Call to uscs_to_ssp_instance_map");
37 const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> domain =
38 libfqfft::get_evaluation_domain<FieldT>(cs.num_constraints());
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;
49 for (size_t i = cs.num_constraints(); i < domain->m; ++i) {
50 V_in_Lagrange_basis[0][i] += FieldT::one();
52 libff::leave_block("Compute polynomials V in Lagrange basis");
54 libff::leave_block("Call to uscs_to_ssp_instance_map");
56 return ssp_instance<FieldT>(
61 std::move(V_in_Lagrange_basis));
65 * Instance map for the USCS-to-SSP reduction followed by evaluation of the
66 * resulting SSP instance.
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"
74 * m = number of variables of the SSP
75 * n = degree of the SSP
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)
81 libff::enter_block("Call to uscs_to_ssp_instance_map_with_evaluation");
83 const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> domain =
84 libfqfft::get_evaluation_domain<FieldT>(cs.num_constraints());
86 std::vector<FieldT> Vt(cs.num_variables() + 1, FieldT::zero());
87 std::vector<FieldT> Ht(domain->m + 1);
89 const FieldT Zt = domain->compute_vanishing_polynomial(t);
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;
99 for (size_t i = cs.num_constraints(); i < domain->m; ++i) {
100 /* dummy constraint: 1^2 = 1 */
103 FieldT ti = FieldT::one();
104 for (size_t i = 0; i < domain->m + 1; ++i) {
108 libff::leave_block("Compute evaluations of V and H at t");
110 libff::leave_block("Call to uscs_to_ssp_instance_map_with_evaluation");
112 return ssp_instance_evaluation<FieldT>(
124 * Witness map for the USCS-to-SSP reduction.
126 * The witness map takes zero knowledge into account when d is random.
128 * More precisely, compute the coefficients
131 * H(z) := (V(z)^2-1)/Z(z)
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"
136 * m = number of variables of the SSP
137 * n = degree of the SSP
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) )
148 * The code below is not as simple as the above high-level description due to
149 * some reshuffling to save space.
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,
158 libff::enter_block("Call to uscs_to_ssp_witness_map");
162 assert(cs.is_satisfied(primary_input, auxiliary_input));
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());
170 const std::shared_ptr<libfqfft::evaluation_domain<FieldT>> domain =
171 libfqfft::get_evaluation_domain<FieldT>(cs.num_constraints());
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);
179 for (size_t i = cs.num_constraints(); i < domain->m; ++i) {
180 aA[i] += FieldT::one();
182 libff::leave_block("Compute evaluation of polynomial V on set S");
184 libff::enter_block("Compute coefficients of polynomial V");
186 libff::leave_block("Compute coefficients of polynomial V");
188 libff::enter_block("Compute ZK-patch");
189 std::vector<FieldT> coefficients_for_H(domain->m + 1, FieldT::zero());
191 #pragma omp parallel for
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];
197 domain->add_poly_Z(d.squared(), coefficients_for_H);
198 libff::leave_block("Compute ZK-patch");
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");
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
208 #pragma omp parallel for
210 for (size_t i = 0; i < domain->m; ++i) {
211 H_tmp[i] = aA[i].squared() - FieldT::one();
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");
218 libff::leave_block("Compute evaluation of polynomial H on set T");
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");
224 libff::enter_block("Compute sum of H and ZK-patch");
226 #pragma omp parallel for
228 for (size_t i = 0; i < domain->m; ++i) {
229 coefficients_for_H[i] += H_tmp[i];
231 libff::leave_block("Compute sum of H and ZK-patch");
233 libff::leave_block("Call to uscs_to_ssp_witness_map");
235 return ssp_witness<FieldT>(
240 full_variable_assignment,
241 std::move(coefficients_for_H));
244 } // namespace libsnark
246 #endif // USCS_TO_SSP_TCC_