Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
kzg10.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  * @author This file is part of libff, developed by Clearmatics Ltd
4  * (originally developed by SCIPR Lab) and contributors
5  * (see AUTHORS).
6  * @copyright MIT license (see LICENSE file)
7  *****************************************************************************/
8 
9 #ifndef __LIBSNARK_POLYNOMIAL_COMMITMENTS_KZG10_TCC__
10 #define __LIBSNARK_POLYNOMIAL_COMMITMENTS_KZG10_TCC__
11 
12 #include "libsnark/polynomial_commitments/kzg10.hpp"
13 
14 #include <libff/algebra/scalar_multiplication/multiexp.hpp>
15 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
16 #include <libfqfft/polynomial_arithmetic/basic_operations.hpp>
17 #include <libfqfft/polynomial_arithmetic/naive_evaluate.hpp>
18 
19 namespace libsnark
20 {
21 
22 template<typename ppT>
23 kzg10<ppT>::srs::srs(
24  std::vector<libff::G1<ppT>> &&alpha_powers_g1,
25  const libff::G2<ppT> &alpha_g2)
26  : alpha_powers_g1(alpha_powers_g1), alpha_g2(alpha_g2)
27 {
28 }
29 
30 template<typename ppT>
31 typename kzg10<ppT>::srs kzg10<ppT>::setup_from_secret(
32  size_t max_degree, const Field &alpha)
33 {
34  const libff::bigint<Field::num_limbs> alpha_bigint = alpha.as_bigint();
35  const size_t window_size = std::max(
36  libff::wnaf_opt_window_size<libff::G1<ppT>>(alpha_bigint.num_bits()),
37  1ul);
38  const std::vector<long> naf =
39  libff::find_wnaf<Field::num_limbs>(window_size, alpha_bigint);
40 
41  // TODO: perform in concurrent batches?
42  std::vector<libff::G1<ppT>> alpha_powers_g1;
43  alpha_powers_g1.reserve(max_degree + 1);
44  libff::G1<ppT> alpha_i_g1 = libff::G1<ppT>::one();
45  alpha_powers_g1.push_back(alpha_i_g1);
46  for (size_t i = 1; i < max_degree + 1; ++i) {
47  alpha_i_g1 = libff::fixed_window_wnaf_exp<libff::G1<ppT>>(
48  window_size, alpha_i_g1, naf);
49  alpha_powers_g1.push_back(alpha_i_g1);
50  }
51 
52  // assert((libff::G1<ppT> * alpha.pow(max_degree)) ==
53  // alpha_powers_g1[max_degree]);
54  return srs(std::move(alpha_powers_g1), alpha * libff::G2<ppT>::one());
55 }
56 
57 template<typename ppT>
58 typename kzg10<ppT>::srs kzg10<ppT>::setup(size_t max_degree)
59 {
60  const Field alpha = Field::random_element();
61  return setup_from_secret(max_degree, alpha);
62 }
63 
64 template<typename ppT>
65 typename kzg10<ppT>::commitment kzg10<ppT>::commit(
66  const srs &srs, const polynomial<libff::Fr<ppT>> &phi)
67 {
68  const size_t num_coefficients = phi.size();
69 
70  // Caller is responsible for checking this.
71  assert(num_coefficients <= srs.alpha_powers_g1.size());
72 
73 #ifdef MULTICORE
74  const size_t chunks = omp_get_max_threads();
75 #else
76  const size_t chunks = 1;
77 #endif
78 
79  // The commitment is the encoding [ \phi(\alpha) ]_1. This is computed
80  // using the elements [ \alpha^t ]_1 for t=0, ..., max_degree from the srs.
81  return libff::multi_exp<
82  libff::G1<ppT>,
83  libff::Fr<ppT>,
84  libff::multi_exp_method_BDLO12_signed>(
85  srs.alpha_powers_g1.begin(),
86  srs.alpha_powers_g1.begin() + num_coefficients,
87  phi.begin(),
88  phi.end(),
89  chunks);
90 }
91 
92 template<typename ppT>
93 bool kzg10<ppT>::verify_poly(
94  const typename kzg10<ppT>::srs &srs,
95  typename kzg10<ppT>::commitment C,
96  const polynomial<libff::Fr<ppT>> &phi)
97 {
98  return C == commit(srs, phi);
99 }
100 
101 template<typename ppT>
102 libff::Fr<ppT> kzg10<ppT>::evaluate_polynomial(
103  const polynomial<libff::Fr<ppT>> &phi, const libff::Fr<ppT> i)
104 {
105  const size_t num_coefficients = phi.size();
106  return libfqfft::evaluate_polynomial(num_coefficients, phi, i);
107 }
108 
109 template<typename ppT>
110 typename kzg10<ppT>::evaluation_witness kzg10<ppT>::create_evaluation_witness(
111  const polynomial<libff::Fr<ppT>> &phi,
112  const libff::Fr<ppT> &i,
113  const libff::Fr<ppT> &evaluation,
114  const typename kzg10<ppT>::srs &srs)
115 {
116  // The witness is:
117  // w_i = [ \psi_i(\alpha) ]_1
118  // where:
119  // \psi_i(x) = (\phi(x) - \phi(i)) / (x - i)
120  // (see [KZG10] Section 3.2)
121 
122  // TODO: Find a more optimal way to compute the special case of dividing by
123  // (x - i).
124  std::vector<Field> psi;
125  std::vector<Field> remainder;
126 
127  std::vector<Field> phi_minus_phi_i = phi;
128  phi_minus_phi_i[0] -= evaluation;
129  libfqfft::_polynomial_division(psi, remainder, phi_minus_phi_i, {-i, 1});
130  if (!libfqfft::_is_zero(remainder)) {
131  throw std::invalid_argument(
132  "invalid evaluation point (poly div faild)");
133  }
134  return commit(srs, psi);
135 }
136 
137 template<typename ppT>
138 bool kzg10<ppT>::verify_evaluation(
139  const Field &i,
140  const Field &evaluation,
141  const typename kzg10<ppT>::srs &srs,
142  const evaluation_witness &witness,
143  const typename kzg10<ppT>::commitment &C)
144 {
145  // Verify the equality:
146  //
147  // \psi(\alpha) (\alpha - i) = \phi(\alpha) - \phi(i)
148  // = commit - phi_i
149  // via the pairing equality:
150  //
151  // e([\psi(\alpha)]_1, [\alpha - i]_2) = e(C - [phi_i]_1, [1]_2)
152  //
153  // which (multiplying both sides by e(C - [phi_i]_1, [1]_2)^{-1}) holds iff:
154  //
155  // id_T
156  // = e([\psi(\alpha)]_1, [\alpha - i]_2) * e(C - [phi_i]_1, [1]_2)^{-1}
157  // = e([\psi(\alpha)]_1, [\alpha - i]_2) * e([phi_i]_1 - C, [1]_2)
158  // = e([\psi(\alpha)]_1, [\alpha]_2 - [i]_2) * e([phi_i]_1 - C, [1]_2)
159  //
160  // where id_T is the identity of the group GT (GT::one()). This
161  // last line can now be computed in terms of available variables:
162  //
163  // e(_A = witness.w, _B = srs.alpha_g2 - i * G2::one()) *
164  // e(_C = witness.phi_i * G1::one() - C, _D = G2::one())
165 
166  // See Section 3: https://eprint.iacr.org/2019/953.pdf for further
167  // details.
168 
169  const libff::G1_precomp<ppT> _A = ppT::precompute_G1(witness);
170  const libff::G2_precomp<ppT> _B =
171  ppT::precompute_G2(srs.alpha_g2 - i * libff::G2<ppT>::one());
172  const libff::G1_precomp<ppT> _C =
173  ppT::precompute_G1(evaluation * libff::G1<ppT>::one() - C);
174  const libff::G2_precomp<ppT> _D = ppT::precompute_G2(libff::G2<ppT>::one());
175 
176  const libff::Fqk<ppT> miller_result =
177  ppT::double_miller_loop(_A, _B, _C, _D);
178  const libff::GT<ppT> result = ppT::final_exponentiation(miller_result);
179  return result == libff::GT<ppT>::one();
180 }
181 
182 } // namespace libsnark
183 
184 #endif // __LIBSNARK_POLYNOMIAL_COMMITMENTS_KZG10_TCC__