From bf4fe6c0612e184677056a45b6a6347a87870f26 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 24 Jun 2022 16:47:22 +0100 Subject: [PATCH 001/154] added TAGS to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 24199bfe8..6d887f0ab 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark build *~ +TAGS +.dir-locals.el From cd4336c01885a137a46c0f773dfc22f97105d0c6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 24 Jun 2022 16:47:57 +0100 Subject: [PATCH 002/154] added BLS12-381 curve to CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e22a19f8f..8e20f9dcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ set( "BN128" CACHE STRING - "Default curve: one of ALT_BN128, BN128, EDWARDS, MNT4, MNT6" + "Default curve: one of ALT_BN128, BN128, EDWARDS, MNT4, MNT6, BLS12_381" ) option( From 9e83435d32d26375438f03173e9190a218208e80 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 24 Jun 2022 16:48:53 +0100 Subject: [PATCH 003/154] added test for plonk in CMakeLists.txt --- libsnark/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libsnark/CMakeLists.txt b/libsnark/CMakeLists.txt index 1d3e0e29a..8b554fff8 100644 --- a/libsnark/CMakeLists.txt +++ b/libsnark/CMakeLists.txt @@ -205,6 +205,7 @@ if ("${IS_LIBSNARK_PARENT}") libsnark_test(test_r1cs_ppzksnark_verifier_gadget gadgetlib1/tests/test_r1cs_ppzksnark_verifier_gadget.cpp) libsnark_test(test_r1cs_gg_ppzksnark_verifier_gadget gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp) libsnark_test(test_kzg10_verifier_gadget gadgetlib1/tests/test_kzg10_verifier_gadget.cpp) + libsnark_test(test_plonk zk_proof_systems/plonk/tests/test_plonk.cpp) # TODO (howardwu): Resolve runtime on targets: # libsnark_test(zk_proof_systems_uscs_ppzksnark_test zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp) From e7e208ce0475a5963d5925bfc4825bbdee9398d5 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:49:46 +0100 Subject: [PATCH 004/154] plonk: implemented common untility functions --- libsnark/zk_proof_systems/plonk/plonk.hpp | 242 +++++++++++++ libsnark/zk_proof_systems/plonk/plonk.tcc | 418 ++++++++++++++++++++++ 2 files changed, 660 insertions(+) create mode 100644 libsnark/zk_proof_systems/plonk/plonk.hpp create mode 100644 libsnark/zk_proof_systems/plonk/plonk.tcc diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp new file mode 100644 index 000000000..ee3ca38ad --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -0,0 +1,242 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ + +#include +#include +#include + +// enable debug checks. in particular enable comparisons to test +// vector values. +#define DEBUG +//#undef DEBUG + +/// Declaration of common untility functions for ppzkSNARK proof +/// system Plonk. The implementation instantiates the protocol of +/// PlonK \[GWC19], +/// +/// References: +/// - \[GWC19]: +/// Title: "Plonk: Permutations over lagrange-bases for oecumenical +/// noninteractive arguments of knowledge", Ariel Gabizon, Zachary +/// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, +/// Report 2019/953, 2019, + +/// maximum degree of the encoded monomials in the usrs +const size_t MAX_DEGREE = 254; + +/// number of generators for H, Hk1, Hk2 +const size_t NUM_HGEN = 3; + +namespace libsnark +{ + +enum W_polys_id { a, b, c }; +enum Q_polys_id { L, R, M, O, C }; +enum t_polys_id { lo, mid, hi }; +enum omega_id { base, base_k1, base_k2 }; + +template using polynomial = std::vector; + +/***************************** Main algorithms *******************************/ + +/// print the elements of a vector +template void print_vector(const std::vector &v); + +/// Compute the Lagrange basis polynomials for interpolating sets of +/// n points +/// +/// INPUT: +/// +/// \param[in] npoints - number of points +/// +/// OUTPUT: +/// +/// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of +/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, +/// a1, ..., a_{n-1}] is a vector representing the +/// coefficients of the i-th Lagrange polynomial L_i(x) = +/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 +/// and L_i(x\neq{omega_i)})=0 +/// +/// Note: uses libfqfft iFFT for the interpolation +template +void plonk_compute_lagrange_basis( + const size_t npoints, std::vector> &L); + +/// Interpolate a polynomial from a set of points through inverse FFT +/// +/// INPUT: +/// +/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), +/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], +/// ... which we want to interpolate as a polynomial +/// +/// OUTPUT: +/// +/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] +/// of the polynomial f(x) interpolating the set of points +/// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., +/// a_{n-1}] then this represents the polynomial f(x) = +/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that +/// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} +/// are the n roots of unity. +/// +/// \note uses libfqfft iFFT for the interpolation +template +void plonk_interpolate_polynomial_from_points( + const std::vector &f_points, polynomial &f_poly); + +/// Interpolate a polynomial from a set of points over Lagrange basis +/// +/// INPUT: +/// +/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), +/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], +/// ... which we want to interpolate as a polynomial +/// +/// \param[in] L[0..n-1][0..n-1]: Lagrange basis over the n roots of +/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, +/// a1, ..., a_{n-1}] is a vector representing the +/// coefficients of the i-th Lagrange polynomial L_i(x) = +/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 +/// and L_i(x\neq{omega_i)})=0 +/// +/// OUTPUT: +/// +/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., +/// a_{n-1}] of the polynomial f(x) interpolating the set +/// of points f_points over the Lagrange basis. For +/// example if f_poly[0..n-1] = [a0, a1, ..., a_{n-1}] +/// then this represents the polynomial f(x) = +/// \sum^{n-1}_{i=0} f_vec[i] * L[i] = +/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that +/// f(omega_i)=f_vec[i]. +template +void plonk_interpolate_over_lagrange_basis( + const std::vector &f_points, + const std::vector> &L, + polynomial &f_poly); + +/// Compute the selector polynomials of the given circuit (also +/// called here "q-polynomials"). See Sect. 8.1. The matrix +/// gates_matrix_transpose has 5 rows, each corresponding to the +/// values L, R, M, O and C for each gate; the number of columns is +/// equal to the number of gates. L_basis is the Lagrange basis. +template +void plonk_compute_selector_polynomials( + const std::vector> &gates_matrix_transpose, + const std::vector> &L_basis, + std::vector> &Q_polys); + +/// output: omega[0] are the n roots of unity, omega[1] are +/// omega[0]*k1, omega[2] are omega[0]*k2; k1 H is a coset of H with +/// generator omega_k1 distinct from H; k2 H is a coset of H with +/// generator omega_k2, distinct from H and k1 H +template +void plonk_compute_roots_of_unity_omega( + const FieldT k1, const FieldT k2, std::vector> &omega); + +/// copy the roots of unity omega[base], omega[k1] and omega[k2] into +/// a single vector H_gen representing the multiplicative subgroups +/// H, k1 H and k2 H (see [GWC19] Sect. 8); \see +/// plonk_compute_roots_of_unity_omega +template +void plonk_roots_of_unity_omega_to_subgroup_H( + const std::vector> &omega, std::vector &H_gen); + +/// permute the multiplicative subgroup H according to the wire +/// permutation: (see [GWC19] Sect. 8), \see +/// plonk_compute_roots_of_unity_omega, \see +/// plonk_roots_of_unity_omega_to_subgroup_H +template +void plonk_permute_subgroup_H( + const std::vector &H_gen, + const std::vector &wire_permutation, + std::vector &H_gen_permute); + +/// compute the permutation polynomials S_sigma_1, S_sigma_2, +/// S_sigma_2 (see [GWC19], Sect. 8.1) +template +void plonk_compute_permutation_polynomials( + const std::vector &H_gen_permute, + const size_t num_gates, + std::vector> &S_polys); + +// A wrapper for multi_exp_method_BDLO12_signed() dot-product a +// vector of group elements in G1 (curve points) with a vector of +// scalar elements in Fr +template +libff::G1 plonk_multi_exp_G1( + const std::vector> &curve_points, + const std::vector> &scalar_elements); + +/// Evaluate a polynomial F at the encrypted secret input +/// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i +/// +/// INPUT +/// +/// \param[in] secret_powers_g1: \secret^i*G1: +/// 0\le{i} +libff::G1 plonk_evaluate_poly_at_secret_G1( + const std::vector> &secret_powers_g1, + const polynomial> &f_poly); + +/// Evaluate a list of polynomials in the encrypted secret input: see +/// plonk_evaluate_poly_at_secret_G1 +template +void plonk_evaluate_polys_at_secret_G1( + const std::vector> &secret_powers_g1, + const std::vector>> &Q_polys, + std::vector> &Q_polys_at_secret_g1); + +/// Compute the factors in the product of the permutation polynomial +/// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], +/// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], +/// H_gen_permute[i-1]m etc. +template +FieldT plonk_compute_accumulator_factor( + const size_t i, + const size_t n, // nconstraimts + const FieldT beta, + const FieldT gamma, + const std::vector &witness, + const std::vector &H_gen, // H, Hk1, Hk2 + const std::vector &H_gen_permute, + const std::vector &A); + +/// A: accumulatro vector +template +void plonk_compute_accumulator( + const size_t n, // num_gates + const FieldT beta, + const FieldT gamma, + const std::vector &witness, + const std::vector &H_gen, // H, Hk1, Hk2 + const std::vector &H_gen_permute, + std::vector &A); + +/// check that the input is an element of the field +template bool check_field_element(const FieldT x); + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/plonk.tcc" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc new file mode 100644 index 000000000..4d2a71ae8 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -0,0 +1,418 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ + +/// Implementation of interfaces for a ppzkSNARK for Plonk. See +/// plonk.hpp . + +namespace libsnark +{ + +/// print the elements of a vector +template void print_vector(const std::vector &v) +{ + for (size_t i = 0; i < v.size(); ++i) { + printf("[%2d]: ", (int)i); + v[i].print(); + } +} + +/// Compute the Lagrange basis polynomials for interpolating sets of +/// n points +/// +/// INPUT: +/// +/// \param[in] npoints - number of points +/// +/// OUTPUT: +/// +/// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of +/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, +/// a1, ..., a_{n-1}] is a vector representing the +/// coefficients of the i-th Lagrange polynomial L_i(x) = +/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 +/// and L_i(x\neq{omega_i)})=0 +/// +/// \note uses libfqfft iFFT for the interpolation +template +void plonk_compute_lagrange_basis( + const size_t npoints, std::vector> &L) +{ + assert(L.size() != 0); + assert(L.size() == L[0].size()); + assert(L.size() == npoints); + + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(npoints); + for (size_t i = 0; i < npoints; ++i) { + polynomial u(npoints, FieldT(0)); + u[i] = FieldT(1); + // compute i-th Lagrange basis vector via inverse FFT + domain->iFFT(u); + L[i] = u; + } +} + +/// Interpolate a polynomial from a set of points through inverse FFT +/// +/// INPUT: +/// +/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), +/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], +/// ... which we want to interpolate as a polynomial +/// +/// OUTPUT: +/// +/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] +/// of the polynomial f(x) interpolating the set of points +/// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., +/// a_{n-1}] then this represents the polynomial f(x) = +/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that +/// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} +/// are the n roots of unity. +/// +/// \note uses libfqfft iFFT for the interpolation +template +void plonk_interpolate_polynomial_from_points( + const std::vector &f_points, polynomial &f_poly) +{ + size_t npoints = f_points.size(); + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(npoints); + polynomial u = f_points; + domain->iFFT(u); + f_poly = u; +} + +/// Interpolate a polynomial from a set of points over Lagrange basis +/// +/// INPUT: +/// +/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), +/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], +/// ... which we want to interpolate as a polynomial +/// +/// \param[in] L[0..n-1][0..n-1]: Lagrange basis over the n roots of +/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, +/// a1, ..., a_{n-1}] is a vector representing the +/// coefficients of the i-th Lagrange polynomial L_i(x) = +/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 +/// and L_i(x\neq{omega_i)})=0 +/// +/// OUTPUT: +/// +/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., +/// a_{n-1}] of the polynomial f(x) interpolating the set +/// of points f_points over the Lagrange basis. For +/// example if f_poly[0..n-1] = [a0, a1, ..., a_{n-1}] +/// then this represents the polynomial f(x) = +/// \sum^{n-1}_{i=0} f_vec[i] * L[i] = +/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that +/// f(omega_i)=f_vec[i]. +template +void plonk_interpolate_over_lagrange_basis( + const std::vector &f_points, + const std::vector> &L, + polynomial &f_poly) +{ + assert(L.size() != 0); + assert(L.size() == L[0].size()); + assert(L.size() == f_points.size()); + + size_t num_gates = L.size(); + + // initialize f_poly + std::fill(f_poly.begin(), f_poly.end(), FieldT(0)); + + // the num_gates components of f_poly. each components is + // a polynomial that is the multiplication of the i-th element of + // f_points to the i-th polynomial in the lagrange basis L[i]: + // f_poly_component[i] = f_points[i] * L[i] + for (size_t i = 0; i < num_gates; ++i) { + polynomial f_poly_component_i; + // represent the scalar f_points[i] as an all-zero vector with + // only the first element set to f_points[i]. this is done in + // order to use libfqfft multiplication function as a function + // for multiply vector by scalar. + std::vector f_points_coeff_i(num_gates, FieldT(0)); + f_points_coeff_i[0] = f_points[i]; + // f_poly_component[i] = f_points[i] * L[i] + libfqfft::_polynomial_multiplication( + f_poly_component_i, f_points_coeff_i, L[i]); + // accumulate the i-th component to f_poly + libfqfft::_polynomial_addition( + f_poly, f_poly, f_poly_component_i); + } +} + +/// Compute the selector polynomials of the given circuit (also +/// called here "q-polynomials"). See Sect. 8.1. The matrix +/// gates_matrix_transpose has 5 rows, each corresponding to the +/// values L, R, M, O and C for each gate; the number of columns is +/// equal to the number of gates. L_basis is the Lagrange basis. +template +void plonk_compute_selector_polynomials( + const std::vector> &gates_matrix_transpose, + const std::vector> &L_basis, + std::vector> &Q_polys) +{ + assert(gates_matrix_transpose.size() == Q_polys.size()); + assert(gates_matrix_transpose[0].size() == Q_polys[0].size()); + assert(gates_matrix_transpose[0].size() == L_basis.size()); + size_t num_qpolys = gates_matrix_transpose.size(); + for (size_t i = 0; i < num_qpolys; ++i) { + std::vector q_vec = gates_matrix_transpose[i]; + plonk_interpolate_polynomial_from_points(q_vec, Q_polys[i]); + } +}; + +template +void plonk_compute_public_input_polynomial( + const std::vector &PI_points, + const std::vector> &L_basis, + polynomial &PI_poly) +{ + assert(PI_points.size() == L_basis.size()); + plonk_interpolate_polynomial_from_points(PI_points, PI_poly); +}; + +/// output: omega[0] are the n roots of unity, omega[1] are +/// omega[0]*k1, omega[2] are omega[0]*k2; k1 H is a coset of H with +/// generator omega_k1 distinct from H; k2 H is a coset of H with +/// generator omega_k2, distinct from H and k1 H +template +void plonk_compute_roots_of_unity_omega( + const FieldT k1, const FieldT k2, std::vector> &omega) +{ + assert(omega.size() == NUM_HGEN); + assert(omega[0].size() > 0); + size_t num_gates = omega[0].size(); + // Get the n-th root of unity omega in Fq (n=8 is the number of + // constraints in the example). omega is a generator of the + // multiplicative subgroup H. Example (2**32)-th primitive root + // of unity in the base field Fq of bls12-381 i.e. such that + // omega_base**(2**32) = 1. The bls12-381 prime q is such that any + // power of 2 divides (q-1). In particular 2**32|(q-1) and so the + // 2**32-th root of unity exists. + FieldT omega_base = libff::get_root_of_unity(num_gates); + for (size_t i = 0; i < num_gates; ++i) { + FieldT omega_i = libff::power(omega_base, libff::bigint<1>(i)); + omega[base][i] = omega_i; + FieldT omega_k1_i = omega[base][i] * k1; + FieldT omega_k2_i = omega[base][i] * k2; + omega[base_k1][i] = omega_k1_i; + omega[base_k2][i] = omega_k2_i; + } +} + +/// copy the roots of unity omega[base], omega[k1] and omega[k2] into +/// a single vector H_gen representing the multiplicative subgroups +/// H, k1 H and k2 H (see [GWC19] Sect. 8); \see +/// plonk_compute_roots_of_unity_omega +template +void plonk_roots_of_unity_omega_to_subgroup_H( + const std::vector> &omega, std::vector &H_gen) +{ + assert(omega.size() == NUM_HGEN); + assert(omega[0].size() > 0); + std::copy(omega[base].begin(), omega[base].end(), back_inserter(H_gen)); + std::copy( + omega[base_k1].begin(), omega[base_k1].end(), back_inserter(H_gen)); + std::copy( + omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_gen)); +} + +/// permute the multiplicative subgroup H according to the wire +/// permutation: (see [GWC19] Sect. 8), \see +/// plonk_compute_roots_of_unity_omega, \see +/// plonk_roots_of_unity_omega_to_subgroup_H +template +void plonk_permute_subgroup_H( + const std::vector &H_gen, + const std::vector &wire_permutation, + std::vector &H_gen_permute) +{ + assert(H_gen.size() > 0); + for (size_t i = 0; i < H_gen.size(); ++i) { + H_gen_permute[i] = H_gen[wire_permutation[i] - 1]; + } +} + +/// compute the permutation polynomials S_sigma_1, S_sigma_2, +/// S_sigma_2 (see [GWC19], Sect. 8.1) +template +void plonk_compute_permutation_polynomials( + const std::vector &H_gen_permute, + const size_t num_gates, + std::vector> &S_polys) +{ + assert(S_polys.size() == NUM_HGEN); + assert(S_polys[0].size() == num_gates); + assert(H_gen_permute.size() == (NUM_HGEN * num_gates)); + for (size_t i = 0; i < NUM_HGEN; ++i) { + typename std::vector::const_iterator begin = + H_gen_permute.begin() + (i * num_gates); + typename std::vector::const_iterator end = + H_gen_permute.begin() + (i * num_gates) + (num_gates); + std::vector S_points(begin, end); + plonk_interpolate_polynomial_from_points(S_points, S_polys[i]); + } +} + +// A wrapper for multi_exp_method_BDLO12_signed() dot-product a +// vector of group elements in G1 (curve points) with a vector of +// scalar elements in Fr +template +libff::G1 plonk_multi_exp_G1( + const std::vector> &curve_points, + const std::vector> &scalar_elements) +{ + assert(curve_points.size() == scalar_elements.size()); + const size_t chunks = 1; + libff::G1 product = libff::multi_exp< + libff::G1, + libff::Fr, + libff::multi_exp_method_BDLO12_signed>( + curve_points.begin(), + curve_points.end(), + scalar_elements.begin(), + scalar_elements.end(), + chunks); + return product; +} + +/// Evaluate a polynomial F at the encrypted secret input +/// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i +/// +/// INPUT +/// +/// \param[in] secret_powers_g1: \secret^i*G1: +/// 0\le{i} +libff::G1 plonk_evaluate_poly_at_secret_G1( + const std::vector> &secret_powers_g1, + const polynomial> &f_poly) +{ + assert(f_poly.size() <= secret_powers_g1.size()); + const size_t chunks = 1; + const size_t num_coefficients = f_poly.size(); + libff::G1 f_poly_at_secret_g1 = libff::multi_exp< + libff::G1, + libff::Fr, + libff::multi_exp_method_BDLO12_signed>( + secret_powers_g1.begin(), + secret_powers_g1.begin() + num_coefficients, + f_poly.begin(), + f_poly.end(), + chunks); + return f_poly_at_secret_g1; +} + +/// Evaluate a list of polynomials in the encrypted secret input: see +/// plonk_evaluate_poly_at_secret_G1 +template +void plonk_evaluate_polys_at_secret_G1( + const std::vector> &secret_powers_g1, + const std::vector>> &Q_polys, + std::vector> &Q_polys_at_secret_g1) +{ + assert(secret_powers_g1.size()); + assert(Q_polys.size()); + assert(Q_polys.size() <= secret_powers_g1.size()); + const size_t npolys = Q_polys.size(); + for (size_t i = 0; i < npolys; ++i) { + Q_polys_at_secret_g1[i] = + plonk_evaluate_poly_at_secret_G1(secret_powers_g1, Q_polys[i]); + } +} + +/// Compute the factors in the product of the permutation polynomial +/// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], +/// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], +/// H_gen_permute[i-1]m etc. +template +FieldT plonk_compute_accumulator_factor( + const size_t i, + const size_t n, // nconstraimts + const FieldT beta, + const FieldT gamma, + const std::vector &witness, + const std::vector &H_gen, // H, Hk1, Hk2 + const std::vector &H_gen_permute, + const std::vector &A) +{ + assert(n); + assert((i >= 0) && (i < n)); + assert(witness.size() == (3 * n)); + assert(H_gen.size() == (3 * n)); + assert(H_gen_permute.size() == (3 * n)); + assert(A.size() == n); + FieldT res = FieldT(1); + if (i > 0) { + FieldT nom_1 = witness[i - 1] + (beta * H_gen[i - 1]) + gamma; + FieldT den_1 = witness[i - 1] + (beta * H_gen_permute[i - 1]) + gamma; + + FieldT nom_2 = witness[n + i - 1] + (beta * H_gen[n + i - 1]) + gamma; + FieldT den_2 = + witness[n + i - 1] + (beta * H_gen_permute[n + i - 1]) + gamma; + + FieldT nom_3 = + witness[2 * n + i - 1] + (beta * H_gen[2 * n + i - 1]) + gamma; + FieldT den_3 = witness[2 * n + i - 1] + + (beta * H_gen_permute[2 * n + i - 1]) + gamma; + + FieldT nom = nom_1 * nom_2 * nom_3; + FieldT den = den_1 * den_2 * den_3; + + res = nom * den.inverse() * A[i - 1]; + } + return res; +} + +// - A: accumulatro vector +template +void plonk_compute_accumulator( + const size_t n, // num_gates + const FieldT beta, + const FieldT gamma, + const std::vector &witness, + const std::vector &H_gen, // H, Hk1, Hk2 + const std::vector &H_gen_permute, + std::vector &A) +{ + assert(n); + assert(witness.size() == (3 * n)); + assert(H_gen.size() == (3 * n)); + assert(H_gen_permute.size() == (3 * n)); + assert(A.size() == n); + for (size_t i = 0; i < n; ++i) { + A[i] = plonk_compute_accumulator_factor( + i, n, beta, gamma, witness, H_gen, H_gen_permute, A); + } +} + +/// check that the input is an element of the field +template bool check_field_element(const FieldT x) +{ + bool b_valid = (typeid(x) == typeid(FieldT)); + return b_valid; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ From 46f89a25e2d9fc2b77fccda5e676c3d6eb310dfe Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:50:40 +0100 Subject: [PATCH 005/154] plonk: implemented circuit description class --- libsnark/zk_proof_systems/plonk/circuit.hpp | 68 ++++++++++ libsnark/zk_proof_systems/plonk/circuit.tcc | 131 ++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 libsnark/zk_proof_systems/plonk/circuit.hpp create mode 100644 libsnark/zk_proof_systems/plonk/circuit.tcc diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp new file mode 100644 index 000000000..9fada7254 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -0,0 +1,68 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ + +#include + +/// Declaration of Common Preprocessed Input interfaces for ppzkSNARK +/// proof system Plonk. +/// +/// This includes: +/// - class for common preprocessed input +/// +/// Reference: +/// - \[GWC19]: +/// Title: "Plonk: Permutations over lagrange-bases for oecumenical +/// noninteractive arguments of knowledge", Ariel Gabizon, Zachary +/// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, +/// Report 2019/953, 2019, + +namespace libsnark +{ + +/// Plonk circuit-specific data +template struct circuit_t { + using Field = libff::Fr; + /// number of gates / constraints + size_t num_gates; + /// number of selector polynomials (q-polynomials) (= 5 in the + /// vanilla Plonk proposal [GWC19]) + size_t num_qpolys; + /// Lagrange basis + std::vector> L_basis; + /// Public input polynomial + polynomial PI_poly; + /// Circuit selector polynomials (Q-polynomials) + std::vector> Q_polys; + /// Permutation polynomials S_sigma_1, S_sigma_2, S_sigma_2 (see + /// [GWC19], Sect. 8.1) + std::vector> S_polys; + /// omega[0] are the n roots of unity, omega[1] are omega[0]*k1, + /// omega[2] are omega[0]*k2 + std::vector> omega_roots; + /// H_gen contains the generators of H, k1 H and k2 H in one place + /// ie. omega, omega_k1 and omega_k2 + std::vector H_gen; + /// H_gen permuted according to the wire permutation + std::vector H_gen_permute; + /// constants for H, k1 H, k2 H + libff::Fr k1; + libff::Fr k2; +}; + +template +circuit_t plonk_curcuit_description_from_example( + const plonk_example example); + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/circuit.tcc" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc new file mode 100644 index 000000000..60531cdc1 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -0,0 +1,131 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ + +/// Implementation of Common Preprocessed Input interfaces for a +/// ppzkSNARK for Plonk. See circuit.hpp . + +namespace libsnark +{ + +/// Compute or fill-in ciruit specific data from example. +template +circuit_t plonk_curcuit_description_from_example( + const plonk_example example) +{ + using Field = libff::Fr; + + circuit_t circuit; + + // public input (PI) + Field PI_value = example.public_input; + // index of the row of the PI in the non-transposed gates_matrix + int PI_index = example.public_input_index; + // Transposed gates matrix: each row is a q-vector + std::vector> gates_matrix_transpose = + example.gates_matrix_transpose; + // wire permutation + std::vector wire_permutation = example.wire_permutation; + // Generate domains on which to evaluate the witness + // polynomials. k1,k2 can be random, but we fix them for debug to + // match against the test vector values + circuit.k1 = example.k1; + circuit.k2 = example.k2; +#ifdef DEBUG + printf("[%s:%d] k1 ", __FILE__, __LINE__); + circuit.k1.print(); + printf("[%s:%d] k2 ", __FILE__, __LINE__); + circuit.k2.print(); +#endif // #ifdef DEBUG + + circuit.num_gates = example.num_gates; + // TODO: throw exception +#ifdef DEBUG + // ensure that num_gates is not 0 + assert(circuit.num_gates); + // ensure num_gates is power of 2 + bool b_is_power2 = ((circuit.num_gates & (circuit.num_gates - 1)) == 0); + assert(b_is_power2); +#endif // #ifdef DEBUG + + circuit.num_qpolys = example.num_qpolys; + + // We represent the constraints q_L, q_R, q_O, q_M, q_C and the + // witness w_L, w_R, w_O as polynomials in the roots of unity + // e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 + // compute Lagrange basis + circuit.L_basis.resize( + circuit.num_gates, polynomial(circuit.num_gates)); + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + plonk_compute_lagrange_basis(circuit.num_gates, circuit.L_basis); + + // compute public input (PI) polynomial + std::vector PI_points(circuit.num_gates, Field(0)); + PI_points[PI_index] = Field(-PI_value); + plonk_compute_public_input_polynomial( + PI_points, circuit.L_basis, circuit.PI_poly); + + // compute the selector polynomials (q-polynomials) from the + // transposed gates matrix over the Lagrange basis q_poly = \sum_i + // q[i] * L[i] where q[i] is a coefficient (a scalar Field + // element) and L[i] is a polynomial with Field coefficients + circuit.Q_polys.resize( + circuit.num_qpolys, polynomial(circuit.num_gates)); + plonk_compute_selector_polynomials( + gates_matrix_transpose, circuit.L_basis, circuit.Q_polys); + + // number of generators for H, Hk1, Hk2 + int num_hgen = NUM_HGEN; + // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, + // omega[2] are omega[0]*k2 + // std::vector> omega; + circuit.omega_roots.resize(num_hgen, std::vector(circuit.num_gates)); + plonk_compute_roots_of_unity_omega( + circuit.k1, circuit.k2, circuit.omega_roots); + // H_gen contains the generators of H, k1 H and k2 H in one place + // ie. circuit.omega_roots, circuit.omega_roots_k1 and + // circuit.omega_roots_k2 + plonk_roots_of_unity_omega_to_subgroup_H( + circuit.omega_roots, circuit.H_gen); + // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H +#ifdef DEBUG + printf("[%s:%d] circuit.H_gen\n", __FILE__, __LINE__); + print_vector(circuit.H_gen); + for (int i = 0; i < (int)circuit.H_gen.size(); ++i) { + assert(circuit.H_gen[i] == example.H_gen[i]); + } +#endif // #ifdef DEBUG + + // permute circuit.H_gen according to the wire permutation + circuit.H_gen_permute.resize(num_hgen * circuit.num_gates, Field(0)); + plonk_permute_subgroup_H( + circuit.H_gen, wire_permutation, circuit.H_gen_permute); + // TODO: write unit test for plonk_permute_subgroup_H +#ifdef DEBUG + printf("[%s:%d] circuit.H_gen_permute\n", __FILE__, __LINE__); + print_vector(circuit.H_gen_permute); + for (size_t i = 0; i < circuit.H_gen_permute.size(); ++i) { + assert(circuit.H_gen_permute[i] == example.H_gen_permute[i]); + } +#endif // #ifdef DEBUG + + // compute the permutation polynomials S_sigma_1, S_sigma_2, + // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) + circuit.S_polys.resize(num_hgen, polynomial(circuit.num_gates)); + plonk_compute_permutation_polynomials( + circuit.H_gen_permute, circuit.num_gates, circuit.S_polys); + + return circuit; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ From 591ec92b67c7615c06fd884d29e518e6c3b8b44c Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:51:18 +0100 Subject: [PATCH 006/154] plonk: implemented srs class --- libsnark/zk_proof_systems/plonk/srs.hpp | 195 ++++++++++++++++++++++++ libsnark/zk_proof_systems/plonk/srs.tcc | 104 +++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 libsnark/zk_proof_systems/plonk/srs.hpp create mode 100644 libsnark/zk_proof_systems/plonk/srs.tcc diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp new file mode 100644 index 000000000..e86769491 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -0,0 +1,195 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_HPP_ + +/// Declaration of SRS interfaces for ppzkSNARK proof system Plonk. This +/// includes: +/// +/// - class usrs +/// - class srs +/// - class for proving key (TODO: not implemented) +/// - class for verification key (TODO: not implemented) +/// - class for key pair (proving key & verification key) (TODO: not +/// implemented) +/// +/// Reference: +/// - \[GWC19]: +/// Title: "Plonk: Permutations over lagrange-bases for oecumenical +/// noninteractive arguments of knowledge", Ariel Gabizon, Zachary +/// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, +/// Report 2019/953, 2019, + +namespace libsnark +{ + +/// +/// A note on the distinction between an srs and a universal srs. +/// +/// A universal srs (usrs) is composed *only* of monomials i.e. encoded +/// powers of the secret value in the group generator. Therefore a usrs +/// is independent of any particular circuit. +/// +/// The (plain) srs is a specialization of the usrs for one particular +/// circuit and is derived from the usrs e.g. as +/// +/// usrs = +/// srs = (proving_key, verificataion_key) = derive(usrs, circuit_description) +/// + +/// Universal srs (usrs). Contains secret encoded monomials with +/// maximum degree MAX_DEGREE and is so independent of any particular +/// circuit. +template class usrs +{ +public: + /// Array of powers of secret \secret, encoded in G1: + /// [1]_1, [\secret]_1, [\secret^2]_1, ..., [\secret^{n+2}]_1 + std::vector> secret_powers_g1; + + /// Array of powers of secret \secret, encoded in G2: + /// [1]_2, [\secret]_2 + std::vector> secret_powers_g2; + + usrs( + std::vector> &&secret_powers_g1, + std::vector> &&secret_powers_g2) + : secret_powers_g1(secret_powers_g1), secret_powers_g2(secret_powers_g2) + { + } +}; + +template +usrs plonk_usrs_derive_from_secret(const libff::Fr &secret); + +/// Plain (i.e. non-universal srs). Contains secret encoded monomials +/// with maximum degree equal to the number of gates of the analyzed +/// circuit + 2, plus circuit description. Dependent on the circuit. +template class srs +{ +public: + using Field = libff::Fr; + /// number of gates in the analyzed circuit, denoted by "n" in + /// [GWC19] + size_t num_gates; + /// number of selector polynomials (q-polynomials) (= 5 in the + /// vanilla Plonk proposal [GWC19]) + size_t num_qpolys; + /// Lagrange basis + std::vector> L_basis; + /// Public input polynomial + polynomial PI_poly; + /// Circuit selector polynomials (Q-polynomials) + std::vector> Q_polys; + /// Permutation polynomials S_sigma_1, S_sigma_2, S_sigma_2 (see + /// [GWC19], Sect. 8.1) + std::vector> S_polys; + /// omega[0] are the n roots of unity, omega[1] are omega[0]*k1, + /// omega[2] are omega[0]*k2 + std::vector> omega_roots; + /// H_gen contains the generators of H, k1 H and k2 H in one place + /// ie. omega, omega_k1 and omega_k2 + std::vector H_gen; + /// H_gen permuted according to the wire permutation + std::vector H_gen_permute; + /// constants for H, k1 H, k2 H + libff::Fr k1; + libff::Fr k2; + + /// Array of powers of secret \alpha, encoded in G1: [1]_1, + /// [\alpha]_1, [\alpha^2]_1, ..., [\alpha^{n+2}]_1 + std::vector> secret_powers_g1; + + /// Array of powers of secret \alpha, encoded in G2: [1]_2, + /// [\alpha]_2 + std::vector> secret_powers_g2; + + srs(const size_t &num_gates, + const size_t &num_qpolys, + const std::vector> &L_basis, + const polynomial &PI_poly, + const std::vector> &Q_polys, + const std::vector> &S_polys, + const std::vector> &omega_roots, + const std::vector &H_gen, + const std::vector &H_gen_permute, + const libff::Fr &k1, + const libff::Fr &k2, + std::vector> &&secret_powers_g1, + std::vector> &&secret_powers_g2) + : num_gates(num_gates) + , num_qpolys(num_qpolys) + , L_basis(L_basis) + , PI_poly(PI_poly) + , Q_polys(Q_polys) + , S_polys(S_polys) + , omega_roots(omega_roots) + , H_gen(H_gen) + , H_gen_permute(H_gen_permute) + , k1(k1) + , k2(k2) + , secret_powers_g1(secret_powers_g1) + , secret_powers_g2(secret_powers_g2) + { + } +}; + +template +srs plonk_srs_derive_from_usrs( + const usrs &usrs, const circuit_t &circuit); + +/// A proving key for Plonk +template class plonk_proving_key +{ +public: + /// Array of powers of secret \alpha, encoded in G1: [1]_1, + /// [\alpha]_1, [\alpha^2]_1, ..., [\alpha^{n+2}]_1 + std::vector> secret_powers_g1; + + plonk_proving_key(){}; + plonk_proving_key(std::vector> &&secret_powers_g1) + : secret_powers_g1(std::move(secret_powers_g1)){}; +}; + +/// A verification key for Plonk +template class plonk_verification_key +{ +public: + /// Array of powers of secret \alpha, encoded in G2: [1]_2, + /// [\alpha]_2 + std::vector> secret_powers_g2; + + plonk_verification_key(); + plonk_verification_key(std::vector> &&secret_powers_g2) + : secret_powers_g2(std::move(secret_powers_g2)){}; +}; + +/// A key pair for Plonk, which consists of a proving key and a +/// verification key. +template class plonk_keypair +{ +public: + plonk_proving_key pk; + plonk_verification_key vk; + + plonk_keypair() = default; + plonk_keypair(const plonk_keypair &other) = default; + plonk_keypair(plonk_proving_key &&pk, plonk_verification_key &&vk) + : pk(std::move(pk)), vk(std::move(vk)) + { + } + + plonk_keypair(plonk_keypair &&other) = default; +}; + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/srs.tcc" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc new file mode 100644 index 000000000..42f26e15f --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -0,0 +1,104 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ + +/// Implementation of SRS interfaces for a ppzkSNARK for Plonk. See +/// srs.hpp . + +namespace libsnark +{ + +/// Compute a universal srs (usrs). It is composed *only* of encoded +/// powers of the secret value in the group generator. Therefore a usrs +/// is independent of any particular circuit. +/// +/// \note only for debug +template +usrs plonk_usrs_derive_from_secret(const libff::Fr &secret) +{ + // compute powers of secret times G1: 1*G1, secret^1*G1, secret^2*G1, ... + const libff::bigint::num_limbs> secret_bigint = + secret.as_bigint(); + const size_t window_size = std::max( + libff::wnaf_opt_window_size>(secret_bigint.num_bits()), + 1ul); + const std::vector naf = + libff::find_wnaf::num_limbs>(window_size, secret_bigint); + + std::vector> secret_powers_g1; + secret_powers_g1.reserve(MAX_DEGREE); + libff::G1 secret_i_g1 = libff::G1::one(); + secret_powers_g1.push_back(secret_i_g1); + for (size_t i = 1; i < MAX_DEGREE; ++i) { + // secret^i * G1 + secret_i_g1 = libff::fixed_window_wnaf_exp>( + window_size, secret_i_g1, naf); + secret_powers_g1.push_back(secret_i_g1); + } + + // compute powers of secret times G2: 1*G2, secret^1*G2 + // Note: in Plonk we *always* have 2 encoded elemnts in G2 + std::vector> secret_powers_g2; + secret_powers_g2.reserve(2); + // secret^0 * G2 = G2 + libff::G2 secret_0_g2 = libff::G2::one(); + secret_powers_g2.push_back(secret_0_g2); + // secret^1 * G2 + libff::G2 secret_1_g2 = secret * libff::G2::one(); + secret_powers_g2.push_back(secret_1_g2); + + return usrs(std::move(secret_powers_g1), std::move(secret_powers_g2)); +} + +/// Derive the (plain) SRS from the circuit description and the +/// USRS. The (plain) SRS is a specialization of the USRS for one +/// particular circuit i.e. +/// +/// usrs = +/// srs = (proving_key, verificataion_key) = derive(usrs, circuit_description) +template +srs plonk_srs_derive_from_usrs( + const usrs &usrs, const circuit_t &circuit) +{ + assert(circuit.num_gates <= MAX_DEGREE); + // secret^i * G1 + std::vector> secret_powers_g1; + secret_powers_g1.reserve(circuit.num_gates + 3); + for (size_t i = 0; i < (circuit.num_gates + 3); ++i) { + secret_powers_g1.push_back(usrs.secret_powers_g1[i]); + } + // secret^i * G2 + std::vector> secret_powers_g2; + secret_powers_g2.reserve(2); + for (size_t i = 0; i < 2; ++i) { + secret_powers_g2.push_back(usrs.secret_powers_g2[i]); + } + + srs srs( + circuit.num_gates, + circuit.num_qpolys, + circuit.L_basis, + circuit.PI_poly, + circuit.Q_polys, + circuit.S_polys, + circuit.omega_roots, + circuit.H_gen, + circuit.H_gen_permute, + circuit.k1, + circuit.k2, + std::move(secret_powers_g1), + std::move(secret_powers_g2)); + + return srs; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ From 6ecf05603029e15aa901a5e7e73b4524f492ad32 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:52:07 +0100 Subject: [PATCH 007/154] plonk: implemented prover class --- libsnark/zk_proof_systems/plonk/prover.hpp | 510 +++++++++ libsnark/zk_proof_systems/plonk/prover.tcc | 1140 ++++++++++++++++++++ 2 files changed, 1650 insertions(+) create mode 100644 libsnark/zk_proof_systems/plonk/prover.hpp create mode 100644 libsnark/zk_proof_systems/plonk/prover.tcc diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp new file mode 100644 index 000000000..afedd3ee9 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -0,0 +1,510 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_HPP_ + +#include + +/// Declaration of Prover interfaces for ppzkSNARK proof system Plonk.This +/// includes: +/// +/// - class for proof +/// - class for prover +/// +/// Reference: +/// - \[GWC19]: +/// Title: "Plonk: Permutations over lagrange-bases for oecumenical +/// noninteractive arguments of knowledge", Ariel Gabizon, Zachary +/// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, +/// Report 2019/953, 2019, + +namespace libsnark +{ + +/// A proof for the Plonk GG-ppzkSNARK. +template class plonk_proof +{ +public: + using Field = libff::Fr; + + /// Plonk proof Pi + /// + /// Pi ([a]_1, [b]_1, [c]_1, [z]_1, + /// [t_lo]_1, [t_mi]_1, [t_hi]_1, + /// \bar{a}, \bar{b}, \bar{c}, + /// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, + /// [W_zeta]_1, [W_{zeta omega_roots}]_1 + /// r_zeta (*)) + + /// [a]_1, [b]_1, [c]_1 + std::vector> W_polys_blinded_at_secret_g1; + /// [z]_1, + libff::G1 z_poly_at_secret_g1; + /// [t_lo]_1, [t_mi]_1, [t_hi]_1 + std::vector> t_poly_at_secret_g1; + /// \bar{a}, \bar{b}, \bar{c}, + Field a_zeta; + Field b_zeta; + Field c_zeta; + /// \bar{S_sigma1}, \bar{S_sigma2}, + Field S_0_zeta; + Field S_1_zeta; + /// \bar{z_w} + Field z_poly_xomega_zeta; + /// [W_zeta]_1, [W_{zeta omega_roots}]_1 + libff::G1 W_zeta_at_secret; + libff::G1 W_zeta_omega_at_secret; + /// r_zeta (*) + Field r_zeta; + + plonk_proof( + std::vector> &W_polys_blinded_at_secret_g1, + libff::G1 &z_poly_at_secret_g1, + std::vector> &t_poly_at_secret_g1, + Field &a_zeta, + Field &b_zeta, + Field &c_zeta, + Field &S_0_zeta, + Field &S_1_zeta, + Field &z_poly_xomega_zeta, + libff::G1 &W_zeta_at_secret, + libff::G1 &W_zeta_omega_at_secret, + Field &r_zeta) + : W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) + , z_poly_at_secret_g1(z_poly_at_secret_g1) + , t_poly_at_secret_g1(t_poly_at_secret_g1) + , a_zeta(a_zeta) + , b_zeta(b_zeta) + , c_zeta(c_zeta) + , S_0_zeta(S_0_zeta) + , S_1_zeta(S_1_zeta) + , z_poly_xomega_zeta(z_poly_xomega_zeta) + , W_zeta_at_secret(W_zeta_at_secret) + , W_zeta_omega_at_secret(W_zeta_omega_at_secret) + , r_zeta(r_zeta) + { + } +}; + +/// Prover round 0 output +template struct round_zero_out_t { + /// - zh_poly: vanishing polynomial Zh (from round 0) + std::vector> zh_poly; + /// - null_poly: 0 polynomial (from round 0) + polynomial> null_poly; + /// - neg_one_poly: -1 polynomial (from round 0) + polynomial> neg_one_poly; + /// stuct constructor + round_zero_out_t( + const std::vector> &&zh_poly, + const polynomial> &&null_poly, + const polynomial> &&neg_one_poly) + : zh_poly(zh_poly), null_poly(null_poly), neg_one_poly(neg_one_poly) + { + } +}; + +/// Prover round 1 output +template struct round_one_out_t { + /// - blind_scalars: blinding scalars b1, b2, ..., b9 (only + /// b1-b6 used in round 1) + std::vector> blind_scalars; + /// - W_polys: witness polynomials (Lagrange interpolation of the + /// witness values) + std::vector>> W_polys; + /// - W_polys_blinded: blinded witness polynomials + std::vector>> W_polys_blinded; + /// - W_polys_blinded_at_secret_g1: the blinded witness polynomials + /// evaluated at the secret input denoted [a]_1, [b]_1, [c]_1 in + /// [GWC19] + std::vector> W_polys_blinded_at_secret_g1; + /// stuct constructor + round_one_out_t( + const std::vector> &&blind_scalars, + const std::vector>> &&W_polys, + const std::vector>> &&W_polys_blinded, + const std::vector> &&W_polys_blinded_at_secret_g1) + : blind_scalars(blind_scalars) + , W_polys(W_polys) + , W_polys_blinded(W_polys_blinded) + , W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) + { + } +}; + +/// Prover round 2 output +template struct round_two_out_t { + /// - beta: permutation challenge -- hash of transcript + libff::Fr beta; + /// - gamma: permutation challenge -- hash of transcript + libff::Fr gamma; + /// - z_poly: blinded accumulator poly z(x) + polynomial> z_poly; + /// - z_poly_at_secret_g1: blinded accumulator poly z(x) evaluated at + /// secret + libff::G1 z_poly_at_secret_g1; + /// stuct constructor + round_two_out_t( + libff::Fr &&beta, + libff::Fr &&gamma, + polynomial> &&z_poly, + libff::G1 &&z_poly_at_secret_g1) + : beta(beta) + , gamma(gamma) + , z_poly(z_poly) + , z_poly_at_secret_g1(z_poly_at_secret_g1) + { + } +}; + +/// Prover round 3 output +template struct round_three_out_t { + /// - alpha: quotient challenge -- hash of transcript + libff::Fr alpha; + /// - z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted by w + std::vector> z_poly_xomega; + /// - t_poly: t(x) divided in three parts t(x) = t_lo(x) + t_mid(x) x^n + /// + t_hi(x) x^{2n} + std::vector>> t_poly; + /// - t_poly_long: the quotient polynomial t(x) (see Round 3, pp28 + /// [GWC19]) + polynomial> t_poly_long; + /// - t_poly_at_secret_g1: t(x) evaluated at the secret input zeta + /// i.e. t(zeta) + std::vector> t_poly_at_secret_g1; + /// stuct constructor + round_three_out_t( + libff::Fr &&alpha, + std::vector> &&z_poly_xomega, + std::vector>> &&t_poly, + polynomial> &&t_poly_long, + std::vector> &&t_poly_at_secret_g1) + : alpha(alpha) + , z_poly_xomega(z_poly_xomega) + , t_poly(t_poly) + , t_poly_long(t_poly_long) + , t_poly_at_secret_g1(t_poly_at_secret_g1) + { + } +}; + +/// Prover round 4 output +template struct round_four_out_t { + /// - zeta: evaluation challenge -- hash of transcript + libff::Fr zeta; + /// - a_zeta, b_zeta, c_zeta: the blinded witness polynomials a(x), + /// b(x), c(x) (denoted by W_polys_blinded[] output from Round 1) + /// evaluated at x=zeta i.e. a(z), b(z), c(z) + libff::Fr a_zeta; + libff::Fr b_zeta; + libff::Fr c_zeta; + /// - S_0_zeta, S_1_zeta: the permutation polynomials S_sigma_1(x), + /// S_sigma_2(x) from the common preprocessed input (see [GWC19], + /// Sect. 8.1) evaluated at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) + libff::Fr S_0_zeta; + libff::Fr S_1_zeta; + /// - z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) shifted by w + /// (output from Round 3) evaluated at x=zeta i.e. z(zeta*w) + libff::Fr z_poly_xomega_zeta; + /// - t_zeta: the quotient polynomial t(x) output from Round 3, see + /// pp28 [GWC19]) evaluated at x=zeta i.e. t(z). IMPORTANT! the + /// original Plonk proposal [GWC19] does not output this parameter + /// t_zeta. The Python reference implementation does, so we do the + /// same in order to match the test vectors. TODO can remove t_zeta + /// in the future + libff::Fr t_zeta; + /// stuct constructor + round_four_out_t( + libff::Fr &&zeta, + libff::Fr &&a_zeta, + libff::Fr &&b_zeta, + libff::Fr &&c_zeta, + libff::Fr &&S_0_zeta, + libff::Fr &&S_1_zeta, + libff::Fr &&z_poly_xomega_zeta, + libff::Fr &&t_zeta) + : zeta(zeta) + , a_zeta(a_zeta) + , b_zeta(b_zeta) + , c_zeta(c_zeta) + , S_0_zeta(S_0_zeta) + , S_1_zeta(S_1_zeta) + , z_poly_xomega_zeta(z_poly_xomega_zeta) + , t_zeta(t_zeta) + { + } +}; + +/// Prover round 5 output +template struct round_five_out_t { + /// - nu: opening challenge -- hash of transcript (denoted by v in + /// [GWC19]) + libff::Fr nu; + /// - r_zeta: linearisation polynomial r(x) evaluated at x=zeta + /// ie. r(zeta) + libff::Fr r_zeta; + /// - W_zeta_at_secret: commitment to opening proof polynomial + /// W_zeta(x) at secert input i.e. [W_zeta(secret)]_1 + libff::G1 W_zeta_at_secret; + /// - W_zeta_omega_at_secret: commitment to opening proof polynomial + /// W_{zeta omega}(x) at secert input i.e. [W_{zeta omega}(secret)]_1 + libff::G1 W_zeta_omega_at_secret; + /// - u: multipoint evaluation challenge -- hash of transcript + libff::Fr u; + /// struct constructor + round_five_out_t( + libff::Fr &&nu, + libff::Fr &&r_zeta, + libff::G1 &&W_zeta_at_secret, + libff::G1 &&W_zeta_omega_at_secret, + libff::Fr &&u) + : nu(nu) + , r_zeta(r_zeta) + , W_zeta_at_secret(W_zeta_at_secret) + , W_zeta_omega_at_secret(W_zeta_omega_at_secret) + , u(u) + { + } +}; + +/// Plonk prover. Computes object of class plonk_proof. +template class plonk_prover +{ + using Field = libff::Fr; + +public: + /// Prover Round 0 initialization + /// + /// Initialization + /// + /// INPUT + /// \param[in] srs: structured reference string containing also + /// circuit-specific + /// information + /// + /// OUTPUT + /// \param[out] W_polys: Lagrange interpolation of the witness values + /// \param[out] zh_poly: vanishing polynomial + /// \param[out] null_poly: 0 polynomial + /// \param[out] neg_one_poly: -1 polynomial + static round_zero_out_t round_zero(const srs srs); + + /// Prover Round 1 + /// + /// INPUT + /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) + /// \param[in] null_poly: 0 polynomial (from round 0) + /// \param[in] neg_one_poly: -1 polynomial (from round 0) + /// \param[in] witness: witness values + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] blind_scalars: blinding scalars b1, b2, ..., b9 (only + /// b1-b6 used in round 1) + /// \param[out] W_polys: witness polynomials (Lagrange interpolation + /// of the witness values) + /// \param[out] W_polys_blinded: blinded witness polynomials + /// \param[out] W_polys_blinded_at_secret_g1: the blinded witness + /// polynomials evaluated at the secret input denoted + /// [a]_1, [b]_1, [c]_1 in [GWC19] + static round_one_out_t round_one( + const round_zero_out_t &round_zero_out, + const std::vector> &witness, + const srs &srs); + + /// Prover Round 2 + /// + /// INPUT + /// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only + /// b7,b8,b9 used in round 2) (from round 1) + /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) + /// \param[in] witness: witness values + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] beta, gamma: permutation challenges -- hashes of + /// transcript + /// \param[out] z_poly: blinded accumulator poly z(x) + /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) + /// evaluated at secret + static round_two_out_t round_two( + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const std::vector> &witness, + const srs &srs); + + /// Prover Round 3 + /// + /// INPUT + /// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) + /// \param[in] W_polys_blinded: blinded witness polynomials (from + /// Round 1) + /// \param[in] beta, gamma: permutation challenges -- hashes of + /// transcript (from round 2) + /// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] alpha: quotinet challenge -- hash of transcript + /// \param[out] t_poly_long: the quotient polynomial t(x) (see Round + /// 3, pp28 [GWC19]) + /// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + + /// t_mid(x) x^n + t_hi(x) x^{2n} + /// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret + /// input zeta i.e. t(zeta) + /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted + /// by w + static round_three_out_t round_three( + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const round_two_out_t &round_two_out, + const srs &srs); + + /// Prover Round 4 + /// + /// INPUT + /// \param[in] W_polys_blinded: blinded witness polynomials (from + /// Round 1) + /// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted + /// by w (from Round 3) + /// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, + /// pp28 [GWC19]) (from Round 3) + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] zeta: evaluation challenge -- hash of transcript + /// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness + /// polynomials a(x), b(x), c(x) (denoted by + /// W_polys_blinded[] output from Round 1) evaluated at + /// x=zeta i.e. a(z), b(z), c(z) + /// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials + /// S_sigma_1(x), S_sigma_2(x) from the common + /// preprocessed input (see [GWC19], Sect. 8.1) evaluated + /// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) + /// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) + /// shifted by w (output from Round 3) evaluated at x=zeta + /// i.e. z(zeta*w) + /// \param[out] t_zeta: the quotient polynomial t(x) output from Round + /// 3, see pp28 [GWC19]) evaluated at x=zeta + /// i.e. t(z). IMPORTANT! the original Plonk proposal + /// [GWC19] does not output this parameter t_zeta. The + /// Python reference implementation does, so we do the + /// same in order to match the test vectors. TODO can + /// remove t_zeta in the future + static round_four_out_t round_four( + const round_one_out_t &round_one_out, + const round_three_out_t &round_three_out, + const srs &srs); + + /// Prover Round 5 + /// + /// INPUT + /// \param[in] beta, gamma: permutation challenges -- hashes of + /// transcript (from round 2) + /// \param[in] alpha: quotinet challenge -- hash of transcript (from + /// round 3) + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// round 4) + /// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials + /// a(x), b(x), c(x) (denoted by W_polys_blinded[] output + /// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) + /// (from round 4) + /// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials + /// S_sigma_1(x), S_sigma_2(x) from the common preprocessed + /// input (see [GWC19], Sect. 8.1) evaluated at x=zeta + /// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) + /// \param[in] t_zeta: the quotient polynomial t(x) output from Round + /// 3, see pp28 [GWC19]) evaluated at x=zeta + /// i.e. t(z). IMPORTANT! the original Plonk proposal + /// [GWC19] does not output this parameter t_zeta. The + /// Python reference implementation does, so we do the same + /// in order to match the test vectors. TODO can remove + /// t_zeta in the future (from round 4) + /// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) + /// shifted by w (output from Round 3) evaluated at x=zeta + /// i.e. z(zeta*w) (from round 4) + /// \param[in] W_polys_blinded: blinded witness polynomials (from + /// round 1) + /// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + + /// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) + /// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] nu: opening challenge -- hash of transcript (denoted + /// by v in [GWC19]) + /// \param[out] u: multipoint evaluation challenge -- hash of + /// transcript + /// \param[out] r_zeta: linearisation polynomial r(x) evaluated at + /// x=zeta ie. r(zeta) + /// \param[out] W_zeta_at_secret: commitment to opening proof + /// polynomial W_zeta(x) at secert input + /// i.e. [W_zeta(secret)]_1 + /// \param[out] W_zeta_omega_at_secret: commitment to opening proof + /// polynomial W_{zeta omega}(x) at secert input + /// i.e. [W_{zeta omega}(secret)]_1 + static round_five_out_t round_five( + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const round_two_out_t &round_two_out, + const round_three_out_t &round_three_out, + const round_four_out_t &round_four_out, + const srs &srs); + + /// Prover compute SNARK proof + /// + /// Pi ([a]_1, [b]_1, [c]_1, [z]_1, + /// [t_lo]_1, [t_mi]_1, [t_hi]_1, + /// \bar{a}, \bar{b}, \bar{c}, + /// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, + /// [W_zeta]_1, [W_{zeta omega}]_1 + /// r_zeta) + /// + /// \note in the reference Python implementation, r_zeta (the + /// evaluation of the linearlization polynomial r(X) at zeta from + /// Prover round 5) is added to the pi-SNARK proof. In the paper this + /// is omitted, which seems to make the proof shorter by 1 element at + /// the epxense of a slightly heavier computation on the verifier's + /// side. Here we follow the reference implementation to make sure we + /// match the test values. TODO: once all test vectors are verified, + /// we may remove r_zeta from the proof to be fully compliant with the + /// paper. + /// + /// Mapping code-to-paper quantities + /// + /// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 + /// (from Round 1) + /// \param z_poly_at_secret_g1: [z]_1 (from Round 2) + /// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, + /// [t_hi]_1 (from Round 3) + /// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, + /// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, + /// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) + /// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, + /// [W_{zeta omega}]_1 (from Round 5) + /// + /// INPUT + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] proof: SNARK proof Pi (see above) + static plonk_proof compute_proof(const srs &srs); +}; + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/prover.tcc" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc new file mode 100644 index 000000000..63c0317fb --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -0,0 +1,1140 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ + +/// Implementation of Prover interfaces for a ppzkSNARK for Plonk. See +/// prover.hpp . + +namespace libsnark +{ + +/// Prover Round 0 initialization +/// +/// Initialization +/// +/// INPUT +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] W_polys: Lagrange interpolation of the witness values +/// \param[out] zh_poly: vanishing polynomial +/// \param[out] null_poly: 0 polynomial +/// \param[out] neg_one_poly: -1 polynomial +template +round_zero_out_t plonk_prover::round_zero(const srs srs) +{ + using Field = libff::Fr; + + // output from round 0 + std::vector> zh_poly; + polynomial> null_poly; + polynomial> neg_one_poly; + + // vanishing polynomial zh_poly(X) = x^n-1. vanishes on all n + // roots of unity srs.omega_roots + zh_poly.resize(srs.num_gates + 1, Field(0)); + zh_poly[0] = Field(-1); + zh_poly[srs.num_gates] = Field(1); + + null_poly = {Field(0)}; + neg_one_poly = {-Field("1")}; + + round_zero_out_t round_zero_out( + std::move(zh_poly), std::move(null_poly), std::move(neg_one_poly)); + + return round_zero_out; +} + +/// Prover Round 1 +/// +/// INPUT +/// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +/// \param[in] null_poly: 0 polynomial (from round 0) +/// \param[in] neg_one_poly: -1 polynomial (from round 0) +/// \param[in] witness: witness values +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] blind_scalars: blinding scalars b1, b2, ..., b9 (only +/// b1-b6 used in round 1) +/// \param[out] W_polys: witness polynomials (Lagrange interpolation +/// of the witness values) +/// \param[out] W_polys_blinded: blinded witness polynomials +/// \param[out] W_polys_blinded_at_secret_g1: the blinded witness +/// polynomials evaluated at the secret input denoted +/// [a]_1, [b]_1, [c]_1 in [GWC19] +template +round_one_out_t plonk_prover::round_one( + const round_zero_out_t &round_zero_out, + const std::vector> &witness, + const srs &srs) +{ + using Field = libff::Fr; + int nwitness = 3; + + // initialize hard-coded values from example circuit + plonk_example example; + + // output from round 1 + std::vector> blind_scalars; + std::vector>> W_polys; + std::vector>> W_polys_blinded; + std::vector> W_polys_blinded_at_secret_g1; + + // compute witness polynomials via Lagrange interpolation + W_polys.resize(nwitness, polynomial(srs.num_gates)); + for (int i = 0; i < nwitness; ++i) { + typename std::vector::const_iterator begin = + witness.begin() + (i * srs.num_gates); + typename std::vector::const_iterator end = + witness.begin() + (i * srs.num_gates) + (srs.num_gates); + std::vector W_points(begin, end); + plonk_interpolate_polynomial_from_points(W_points, W_polys[i]); + } + // TODO: move to unit test for + // plonk_interpolate_polynomial_from_points +#ifdef DEBUG + for (int i = 0; i < nwitness; ++i) { + printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, i); + print_vector(W_polys[i]); + assert(W_polys[i] == example.W_polys[i]); + } +#endif // #ifdef DEBUG + + // hard-coded values for the "random" blinding constants from + // example circuit + blind_scalars = example.prover_blind_scalars; + // represent the blinding scalars b1, b2, ..., b9 as polynomials + std::vector> blind_polys{ + {blind_scalars[1], blind_scalars[0]}, // b1 + b0 X + {blind_scalars[3], blind_scalars[2]}, // b3 + b2 X + {blind_scalars[5], blind_scalars[4]} // b5 + b4 X + }; + + // compute blinded witness polynomials e.g. a_poly = + // blind_polys[0] * zh_poly + W_polys[0] + W_polys_blinded.resize(nwitness); + for (int i = 0; i < nwitness; ++i) { + libfqfft::_polynomial_multiplication( + W_polys_blinded[i], blind_polys[i], round_zero_out.zh_poly); + libfqfft::_polynomial_addition( + W_polys_blinded[i], W_polys_blinded[i], W_polys[i]); + } + // evaluate blinded witness polynomials at the secret input + W_polys_blinded_at_secret_g1.resize(W_polys_blinded.size()); + plonk_evaluate_polys_at_secret_G1( + srs.secret_powers_g1, W_polys_blinded, W_polys_blinded_at_secret_g1); + + round_one_out_t round_one_out( + std::move(blind_scalars), + std::move(W_polys), + std::move(W_polys_blinded), + std::move(W_polys_blinded_at_secret_g1)); + + return round_one_out; +} + +/// Prover Round 2 +/// +/// INPUT +/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +/// b7,b8,b9 used in round 2) (from round 1) +/// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +/// \param[in] witness: witness values +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] beta, gamma: permutation challenges -- hashes of +/// transcript +/// \param[out] z_poly: blinded accumulator poly z(x) +/// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) +/// evaluated at secret +template +round_two_out_t plonk_prover::round_two( + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const std::vector> &witness, + const srs &srs) +{ + using Field = libff::Fr; + // initialize hard-coded values from example circuit + plonk_example example; + + // output from round 2 + libff::Fr beta; + libff::Fr gamma; + polynomial> z_poly; + libff::G1 z_poly_at_secret_g1; + + // permutation challenges (hashes of transcript); fixed to test + // values + beta = example.beta; + gamma = example.gamma; + + // compute permutation polynomial + + // blinding polynomial: b8 + b7 X + b6 X^2 + std::vector z1_blind_poly{round_one_out.blind_scalars[8], + round_one_out.blind_scalars[7], + round_one_out.blind_scalars[6]}; + // multiply by the vanishing polynomial: z1 = z1 * this->zh_poly + libfqfft::_polynomial_multiplication( + z1_blind_poly, z1_blind_poly, round_zero_out.zh_poly); + + // A[0] = 1; ... A[i] = computed from (i-1) + std::vector A_vector(srs.num_gates, Field(0)); + plonk_compute_accumulator( + srs.num_gates, + beta, + gamma, + witness, + srs.H_gen, + srs.H_gen_permute, + A_vector); + + polynomial A_poly(srs.num_gates); + plonk_interpolate_polynomial_from_points(A_vector, A_poly); + // TODO: move to unit test for + // plonk_interpolate_polynomial_from_points +#ifdef DEBUG + printf("[%s:%d] A_poly\n", __FILE__, __LINE__); + print_vector(A_poly); + assert(A_poly == example.A_poly); +#endif // #ifdef DEBUG + + // add blinding polynomial z_1 to the accumulator polynomial A_poly + libfqfft::_polynomial_addition(z_poly, z1_blind_poly, A_poly); + z_poly_at_secret_g1 = + plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, z_poly); + + round_two_out_t round_two_out( + std::move(beta), + std::move(gamma), + std::move(z_poly), + std::move(z_poly_at_secret_g1)); + + return round_two_out; +} + +/// Prover Round 3 +/// +/// INPUT +/// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) +/// \param[in] W_polys_blinded: blinded witness polynomials (from +/// Round 1) +/// \param[in] beta, gamma: permutation challenges -- hashes of +/// transcript (from round 2) +/// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] alpha: quotinet challenge -- hash of transcript +/// \param[out] t_poly_long: the quotient polynomial t(x) (see Round +/// 3, pp28 [GWC19]) +/// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + +/// t_mid(x) x^n + t_hi(x) x^{2n} +/// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret +/// input zeta i.e. t(zeta) +/// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted +/// by w +template +round_three_out_t plonk_prover::round_three( + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const round_two_out_t &round_two_out, + const srs &srs) +{ + using Field = libff::Fr; + int num_hgen = NUM_HGEN; + + // initialize hard-coded values from example circuit + plonk_example example; + + // output from round 3 + libff::Fr alpha; + std::vector> z_poly_xomega; + std::vector>> t_poly; + polynomial> t_poly_long; + std::vector> t_poly_at_secret_g1; + + // quotient challenge (hash of transcript); fixed to test value + alpha = example.alpha; + + // Computing the polynomial z(x*w) i.e. z(x) shifted by w where + // w=srs.omega_roots is the base root of unity and z is + // z_poly. we do this by multiplying the coefficients of z by w + z_poly_xomega.resize(round_two_out.z_poly.size()); + std::fill(z_poly_xomega.begin(), z_poly_xomega.end(), Field(0)); + for (size_t i = 0; i < round_two_out.z_poly.size(); ++i) { + // omega_roots^i + Field omega_roots_i = + libff::power(srs.omega_roots[base][1], libff::bigint<1>(i)); + z_poly_xomega[i] = round_two_out.z_poly[i] * omega_roots_i; + } + + // start computation of polynomial t(X) in round 3. we break t + // into 4 parts which we compute separately. each of the 4 parts + // is multiplied by 1/zh_poly in the paper + std::vector> t_part(4); + + // --- Computation of t_part[0] + + // a(x)b(x)q_M(x) + polynomial abqM; + libfqfft::_polynomial_multiplication( + abqM, + round_one_out.W_polys_blinded[a], + round_one_out.W_polys_blinded[b]); + libfqfft::_polynomial_multiplication(abqM, abqM, srs.Q_polys[M]); + // a(x)q_L(x) + polynomial aqL; + libfqfft::_polynomial_multiplication( + aqL, round_one_out.W_polys_blinded[a], srs.Q_polys[L]); + // b(x)q_R(x) + polynomial bqR; + libfqfft::_polynomial_multiplication( + bqR, round_one_out.W_polys_blinded[b], srs.Q_polys[R]); + // c(x)q_O(x) + polynomial cqO; + libfqfft::_polynomial_multiplication( + cqO, round_one_out.W_polys_blinded[c], srs.Q_polys[O]); + // t_part[0](x) = a(x)b(x)q_M(x) + a(x)q_L(x) + b(x)q_R(x) + c(x)q_O(x) + + // PI(x) + q_C(x) + polynomial poly_null{Field(0)}; + libfqfft::_polynomial_addition(t_part[0], poly_null, abqM); + libfqfft::_polynomial_addition(t_part[0], t_part[0], aqL); + libfqfft::_polynomial_addition(t_part[0], t_part[0], bqR); + libfqfft::_polynomial_addition(t_part[0], t_part[0], cqO); + libfqfft::_polynomial_addition(t_part[0], t_part[0], srs.PI_poly); + libfqfft::_polynomial_addition(t_part[0], t_part[0], srs.Q_polys[C]); + + // --- Computation of t_part[1] + + // X*beta as polynomial in X + std::vector> xbeta_poly{ + {Field(0), round_two_out.beta}, // X*beta + {Field(0), round_two_out.beta * srs.k1}, // X*beta*k1 + {Field(0), round_two_out.beta * srs.k2} // X*beta*k2 + }; + // represent gamma as polynomial in X, needed for prover Round 3 + polynomial gamma_poly{round_two_out.gamma}; // gamma + // represent alpha as polynomial in X, needed for prover Round 3 + polynomial alpha_poly{alpha}; // alpha + + // a(x) + beta*x + gamma + polynomial a_xbeta_gamma; + libfqfft::_polynomial_addition( + a_xbeta_gamma, round_one_out.W_polys_blinded[a], xbeta_poly[base]); + libfqfft::_polynomial_addition( + a_xbeta_gamma, a_xbeta_gamma, gamma_poly); + // b(x) + beta_k1*x + gamma + polynomial b_xbeta_gamma_k1; + libfqfft::_polynomial_addition( + b_xbeta_gamma_k1, + round_one_out.W_polys_blinded[b], + xbeta_poly[base_k1]); + libfqfft::_polynomial_addition( + b_xbeta_gamma_k1, b_xbeta_gamma_k1, gamma_poly); + // c(x) + beta_k1*x + gamma + polynomial c_xbeta_gamma_k2; + libfqfft::_polynomial_addition( + c_xbeta_gamma_k2, + round_one_out.W_polys_blinded[c], + xbeta_poly[base_k2]); + libfqfft::_polynomial_addition( + c_xbeta_gamma_k2, c_xbeta_gamma_k2, gamma_poly); + // t_part[1] = (a(x) + beta*x + gamma)*(b(x) + beta_k1*x + + // gamma)*(c(x) + beta_k1*x + gamma)*z(x)*alpha + libfqfft::_polynomial_multiplication( + t_part[1], a_xbeta_gamma, b_xbeta_gamma_k1); + libfqfft::_polynomial_multiplication( + t_part[1], t_part[1], c_xbeta_gamma_k2); + libfqfft::_polynomial_multiplication( + t_part[1], t_part[1], round_two_out.z_poly); + libfqfft::_polynomial_multiplication( + t_part[1], t_part[1], alpha_poly); + + // --- Computation of t_part[2] + + // represent beta as polynomial in X, needed for prover Round 3 + polynomial beta_poly{round_two_out.beta}; + // S*beta as polynomial + // S_sigma1(x)*beta, S_sigma2(x)*beta, S_sigma3(x)*beta + std::vector> sbeta_poly(num_hgen); + for (int i = 0; i < num_hgen; ++i) { + libfqfft::_polynomial_multiplication( + sbeta_poly[i], srs.S_polys[i], beta_poly); + } + // a(x) + S_sigma1(x)*beta + gamma + polynomial a_sbeta_gamma; + libfqfft::_polynomial_addition( + a_sbeta_gamma, round_one_out.W_polys_blinded[a], sbeta_poly[base]); + libfqfft::_polynomial_addition( + a_sbeta_gamma, a_sbeta_gamma, gamma_poly); + // b(x) + S_sigma2(x)*beta + gamma + polynomial b_sbeta_gamma_k1; + libfqfft::_polynomial_addition( + b_sbeta_gamma_k1, + round_one_out.W_polys_blinded[b], + sbeta_poly[base_k1]); + libfqfft::_polynomial_addition( + b_sbeta_gamma_k1, b_sbeta_gamma_k1, gamma_poly); + // b(x) + S_sigma2(x)*beta + gamma + polynomial c_sbeta_gamma_k2; + libfqfft::_polynomial_addition( + c_sbeta_gamma_k2, + round_one_out.W_polys_blinded[c], + sbeta_poly[base_k2]); + libfqfft::_polynomial_addition( + c_sbeta_gamma_k2, c_sbeta_gamma_k2, gamma_poly); + // t_part[2] = (a(x) + S_sigma1(x)*beta + gamma)*(b(x) + + // S_sigma2(x)*beta + gamma)*(b(x) + S_sigma2(x)*beta + + // gamma)*z(x*srs.omega_roots)*alpha + libfqfft::_polynomial_multiplication( + t_part[2], a_sbeta_gamma, b_sbeta_gamma_k1); + libfqfft::_polynomial_multiplication( + t_part[2], t_part[2], c_sbeta_gamma_k2); + libfqfft::_polynomial_multiplication( + t_part[2], t_part[2], z_poly_xomega); + libfqfft::_polynomial_multiplication( + t_part[2], t_part[2], alpha_poly); + // -t_part[2] + polynomial neg_one_poly = {-Field("1")}; + libfqfft::_polynomial_multiplication( + t_part[2], t_part[2], neg_one_poly); + + // --- Computation of t_part[3] + + // z(x) - 1 + polynomial z_neg_one; + libfqfft::_polynomial_addition( + z_neg_one, round_two_out.z_poly, neg_one_poly); + // (z(x)-1) * L_1(x) + libfqfft::_polynomial_multiplication( + t_part[3], z_neg_one, srs.L_basis[0]); + // (z(x)-1) * L_1(x) * alpha + libfqfft::_polynomial_multiplication( + t_part[3], t_part[3], alpha_poly); + // (z(x)-1) * L_1(x) * alpha * alpha + libfqfft::_polynomial_multiplication( + t_part[3], t_part[3], alpha_poly); + + // --- computation of t(x) + + // t(x) = (t[0] + t[1] + (-t[2]) + t[3]) / zh(x) + t_poly_long = {Field(0)}; + libfqfft::_polynomial_addition(t_poly_long, t_poly_long, t_part[0]); + libfqfft::_polynomial_addition(t_poly_long, t_poly_long, t_part[1]); + libfqfft::_polynomial_addition(t_poly_long, t_poly_long, t_part[2]); + libfqfft::_polynomial_addition(t_poly_long, t_poly_long, t_part[3]); + // t(x) = t(x) / zh(x): A/B = (Q, R) st. A = (Q * B) + R. + polynomial remainder; + libfqfft::_polynomial_division( + t_poly_long, remainder, t_poly_long, round_zero_out.zh_poly); + + // TODO: move to unit test for round_three() +#ifdef DEBUG + printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); + print_vector(t_poly_long); + assert(t_poly_long == example.t_poly_long); + printf("[%s:%d] remainder\n", __FILE__, __LINE__); + print_vector(remainder); +#endif // #ifdef DEBUG + assert(libfqfft::_is_zero(remainder)); + + // break this->t_poly_long into three parts: lo, mid, hi, each of degree + // 7. note: (srs.num_gates+3) is the length of the CRS = + // (srs.num_gates+2) powers of G1 + 1 power of G2 + t_poly.resize(num_hgen); + for (int i = 0; i < num_hgen; ++i) { + typename std::vector::iterator begin = + t_poly_long.begin() + (i * (srs.num_gates + 2)); + typename std::vector::iterator end = t_poly_long.begin() + + (i * (srs.num_gates + 2)) + + (srs.num_gates + 2); + std::vector tmp(begin, end); + t_poly[i] = tmp; + } + // TODO: move to unit test for round_three() +#ifdef DEBUG + for (int i = 0; i < num_hgen; ++i) { + printf("[%s:%d] t_poly[%d]\n", __FILE__, __LINE__, i); + print_vector(t_poly[i]); + assert(t_poly[i] == example.t_poly[i]); + } +#endif // #ifdef DEBUG + // evaluate each part of t_poly in the secret input + t_poly_at_secret_g1.resize(num_hgen); + for (int i = 0; i < num_hgen; ++i) { + t_poly_at_secret_g1[i] = plonk_evaluate_poly_at_secret_G1( + srs.secret_powers_g1, t_poly[i]); + } + + round_three_out_t round_three_out( + std::move(alpha), + std::move(z_poly_xomega), + std::move(t_poly), + std::move(t_poly_long), + std::move(t_poly_at_secret_g1)); + + return round_three_out; +} + +/// Prover Round 4 +/// +/// INPUT +/// \param[in] W_polys_blinded: blinded witness polynomials (from +/// Round 1) +/// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted +/// by w (from Round 3) +/// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, +/// pp28 [GWC19]) (from Round 3) +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] zeta: evaluation challenge -- hash of transcript +/// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness +/// polynomials a(x), b(x), c(x) (denoted by +/// W_polys_blinded[] output from Round 1) evaluated at +/// x=zeta i.e. a(z), b(z), c(z) +/// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials +/// S_sigma_1(x), S_sigma_2(x) from the common +/// preprocessed input (see [GWC19], Sect. 8.1) evaluated +/// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) +/// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) +/// shifted by w (output from Round 3) evaluated at x=zeta +/// i.e. z(zeta*w) +/// \param[out] t_zeta: the quotient polynomial t(x) output from Round +/// 3, see pp28 [GWC19]) evaluated at x=zeta +/// i.e. t(z). IMPORTANT! the original Plonk proposal +/// [GWC19] does not output this parameter t_zeta. The +/// Python reference implementation does, so we do the +/// same in order to match the test vectors. TODO can +/// remove t_zeta in the future +template +round_four_out_t plonk_prover::round_four( + const round_one_out_t &round_one_out, + const round_three_out_t &round_three_out, + const srs &srs) +{ + using Field = libff::Fr; + // initialize hard-coded values from example circuit + plonk_example example; + + // output from round 4 + libff::Fr zeta; + libff::Fr a_zeta; + libff::Fr b_zeta; + libff::Fr c_zeta; + libff::Fr S_0_zeta; + libff::Fr S_1_zeta; + libff::Fr z_poly_xomega_zeta; + libff::Fr t_zeta; + + // evaluation challenge (hash of transcript); fixed to test value + zeta = example.zeta; + + a_zeta = libfqfft::evaluate_polynomial( + srs.num_gates + 2, round_one_out.W_polys_blinded[a], zeta); + b_zeta = libfqfft::evaluate_polynomial( + srs.num_gates + 2, round_one_out.W_polys_blinded[b], zeta); + c_zeta = libfqfft::evaluate_polynomial( + srs.num_gates + 2, round_one_out.W_polys_blinded[c], zeta); + S_0_zeta = libfqfft::evaluate_polynomial( + srs.num_gates, srs.S_polys[0], zeta); + S_1_zeta = libfqfft::evaluate_polynomial( + srs.num_gates, srs.S_polys[1], zeta); + t_zeta = libfqfft::evaluate_polynomial( + round_three_out.t_poly_long.size(), round_three_out.t_poly_long, zeta); + z_poly_xomega_zeta = libfqfft::evaluate_polynomial( + round_three_out.z_poly_xomega.size(), + round_three_out.z_poly_xomega, + zeta); + + round_four_out_t round_four_out( + std::move(zeta), + std::move(a_zeta), + std::move(b_zeta), + std::move(c_zeta), + std::move(S_0_zeta), + std::move(S_1_zeta), + std::move(z_poly_xomega_zeta), + std::move(t_zeta)); + + return round_four_out; +} + +/// Prover Round 5 +/// +/// INPUT +/// \param[in] beta, gamma: permutation challenges -- hashes of +/// transcript (from round 2) +/// \param[in] alpha: quotinet challenge -- hash of transcript (from +/// round 3) +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// round 4) +/// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials +/// a(x), b(x), c(x) (denoted by W_polys_blinded[] output +/// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) +/// (from round 4) +/// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials +/// S_sigma_1(x), S_sigma_2(x) from the common preprocessed +/// input (see [GWC19], Sect. 8.1) evaluated at x=zeta +/// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) +/// \param[in] t_zeta: the quotient polynomial t(x) output from Round +/// 3, see pp28 [GWC19]) evaluated at x=zeta +/// i.e. t(z). IMPORTANT! the original Plonk proposal +/// [GWC19] does not output this parameter t_zeta. The +/// Python reference implementation does, so we do the same +/// in order to match the test vectors. TODO can remove +/// t_zeta in the future (from round 4) +/// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) +/// shifted by w (output from Round 3) evaluated at x=zeta +/// i.e. z(zeta*w) (from round 4) +/// \param[in] W_polys_blinded: blinded witness polynomials (from +/// round 1) +/// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + +/// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) +/// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] nu: opening challenge -- hash of transcript (denoted +/// by v in [GWC19]) +/// \param[out] u: multipoint evaluation challenge -- hash of +/// transcript +/// \param[out] r_zeta: linearisation polynomial r(x) evaluated at +/// x=zeta ie. r(zeta) +/// \param[out] W_zeta_at_secret: commitment to opening proof +/// polynomial W_zeta(x) at secert input +/// i.e. [W_zeta(secret)]_1 +/// \param[out] W_zeta_omega_at_secret: commitment to opening proof +/// polynomial W_{zeta omega}(x) at secert input +/// i.e. [W_{zeta omega}(secret)]_1 +template +round_five_out_t plonk_prover::round_five( + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const round_two_out_t &round_two_out, + const round_three_out_t &round_three_out, + const round_four_out_t &round_four_out, + const srs &srs) +{ + using Field = libff::Fr; + polynomial remainder; + + // initialize hard-coded values from example circuit + plonk_example example; + + // output from round 5 + libff::Fr nu; + libff::Fr r_zeta; + libff::G1 W_zeta_at_secret; + libff::G1 W_zeta_omega_at_secret; + libff::Fr u; + + // openinig challenge (hash of transcript); fixed to test value + // (note: denoted v in [GWZ19]) + nu = example.nu; + + // compute linerisation polynomial r in five parts + std::vector> r_part(5); + + // --- Computation of r_part[0] + + // represent values as constant term polynomials in orderto use + // the functions in the libfqfft library on polynomials + polynomial a_zeta_poly{round_four_out.a_zeta}; + polynomial b_zeta_poly{round_four_out.b_zeta}; + polynomial c_zeta_poly{round_four_out.c_zeta}; + // a(z)b(z)q_M(x) + polynomial abqM_zeta; + libfqfft::_polynomial_multiplication( + abqM_zeta, srs.Q_polys[M], a_zeta_poly); + libfqfft::_polynomial_multiplication( + abqM_zeta, abqM_zeta, b_zeta_poly); + // a(z)q_L(x) + polynomial aqL_zeta; + libfqfft::_polynomial_multiplication( + aqL_zeta, srs.Q_polys[L], a_zeta_poly); + // b(z)q_R(x) + polynomial bqR_zeta; + libfqfft::_polynomial_multiplication( + bqR_zeta, srs.Q_polys[R], b_zeta_poly); + // c(z)q_O(x) + polynomial cqO_zeta; + libfqfft::_polynomial_multiplication( + cqO_zeta, srs.Q_polys[O], c_zeta_poly); + // a(z)b(z)q_M(x) + a(z)q_L(x) + b(z)q_R(x) + c(z)q_O(x) + q_C(x) + libfqfft::_polynomial_addition( + r_part[0], round_zero_out.null_poly, abqM_zeta); + libfqfft::_polynomial_addition(r_part[0], r_part[0], aqL_zeta); + libfqfft::_polynomial_addition(r_part[0], r_part[0], bqR_zeta); + libfqfft::_polynomial_addition(r_part[0], r_part[0], cqO_zeta); + libfqfft::_polynomial_addition(r_part[0], r_part[0], srs.Q_polys[C]); + + // --- Computation of r_part[1] + + polynomial r1_const_poly{ + (round_four_out.a_zeta + (round_two_out.beta * round_four_out.zeta) + + round_two_out.gamma) * + (round_four_out.b_zeta + + (round_two_out.beta * srs.k1 * round_four_out.zeta) + + round_two_out.gamma) * + (round_four_out.c_zeta + + (round_two_out.beta * srs.k2 * round_four_out.zeta) + + round_two_out.gamma) * + round_three_out.alpha}; + libfqfft::_polynomial_multiplication( + r_part[1], r1_const_poly, round_two_out.z_poly); + + // --- Computation of r_part[2] + + polynomial r2_const_poly{ + (round_four_out.a_zeta + + (round_two_out.beta * round_four_out.S_0_zeta) + round_two_out.gamma) * + (round_four_out.b_zeta + + (round_two_out.beta * round_four_out.S_1_zeta) + round_two_out.gamma) * + (round_three_out.alpha * round_two_out.beta * + round_four_out.z_poly_xomega_zeta)}; + libfqfft::_polynomial_multiplication( + r_part[2], r2_const_poly, srs.S_polys[2]); + // -r_part[2] + libfqfft::_polynomial_multiplication( + r_part[2], r_part[2], round_zero_out.neg_one_poly); + + // --- Computation of r_part[3] + + // r3 = accumulator_poly_ext3 * eval_poly(L_1, [zeta])[0] * alpha ** 2 + polynomial L_0_zeta_poly{libfqfft::evaluate_polynomial( + srs.L_basis[0].size(), srs.L_basis[0], round_four_out.zeta)}; + polynomial alpha_power2_poly{ + libff::power(round_three_out.alpha, libff::bigint<1>(2))}; + libfqfft::_polynomial_multiplication( + r_part[3], round_two_out.z_poly, L_0_zeta_poly); + libfqfft::_polynomial_multiplication( + r_part[3], r_part[3], alpha_power2_poly); + + // --- Computation of r_poly = (r0+r1-r2+r3) + + // Note: here the reference Python implementation differs from the + // paper where: + // + // r(x) = r(x) - zh(zeta) (t_lo(x) + zeta^n t_mid(x) + zeta^2n t_hi(x)) + // + // In the reference implementation, the missing term is added in + // the computation of the W_zeta(x) polynomial + // + // linearisation polynomial r(x) + polynomial r_poly; + libfqfft::_polynomial_addition( + r_poly, round_zero_out.null_poly, r_part[0]); + libfqfft::_polynomial_addition(r_poly, r_poly, r_part[1]); + libfqfft::_polynomial_addition(r_poly, r_poly, r_part[2]); + libfqfft::_polynomial_addition(r_poly, r_poly, r_part[3]); + + // TODO: move to unit test for compyting r_poly +#ifdef DEBUG + assert(r_poly == example.r_poly); +#endif // #ifdef DEBUG + + // Evaluate the r-polynomial at zeta. Note: in the reference + // implementation, r_zeta is added to the pi-SNARK proof. In the + // paper this is omitted, which makes the proof shorter at the + // epxense of a slightly heavier computation on the verifier's + // side + r_zeta = libfqfft::evaluate_polynomial( + r_poly.size(), r_poly, round_four_out.zeta); + + // TODO: move to unit test for compyting r_zeta +#ifdef DEBUG + assert(r_zeta == example.r_zeta); +#endif // #ifdef DEBUG + + // W_zeta polynomial is of degree 6 in the random element nu and + // hence has 7 terms + std::vector> W_zeta_part(7); + + // --- compute W_zeta_part[0] + + // t_lo(x) + polynomial t_lo{round_three_out.t_poly[lo]}; + // t_mid(x) * zeta^(n+2) + polynomial t_mid_zeta_n; + polynomial zeta_powern_poly{ + libff::power(round_four_out.zeta, libff::bigint<1>(srs.num_gates + 2))}; + libfqfft::_polynomial_multiplication( + t_mid_zeta_n, round_three_out.t_poly[mid], zeta_powern_poly); + // t_hi(x) * zeta^(2(n+1)) + polynomial t_hi_zeta_2n; + polynomial zeta_power2n_poly{libff::power( + round_four_out.zeta, libff::bigint<1>(2 * (srs.num_gates + 2)))}; + libfqfft::_polynomial_multiplication( + t_hi_zeta_2n, round_three_out.t_poly[hi], zeta_power2n_poly); + // -t_zeta as constant term polynomial + polynomial t_zeta_poly{-round_four_out.t_zeta}; + // t_lo(x) + (t_mid(x) * zeta^n) + (t_hi(x) * zeta^2n) + t_zeta_poly + libfqfft::_polynomial_addition( + W_zeta_part[0], round_zero_out.null_poly, t_lo); + libfqfft::_polynomial_addition( + W_zeta_part[0], W_zeta_part[0], t_mid_zeta_n); + libfqfft::_polynomial_addition( + W_zeta_part[0], W_zeta_part[0], t_hi_zeta_2n); + libfqfft::_polynomial_addition( + W_zeta_part[0], W_zeta_part[0], t_zeta_poly); + + // --- compute W_zeta_part[1] + + // -r_zeta as constant term polynomial + polynomial r_zeta_poly{-r_zeta}; + // r(x) - r_zeta + polynomial r_sub_rzeta; + libfqfft::_polynomial_addition(r_sub_rzeta, r_poly, r_zeta_poly); + // (r(x) - r_zeta) * nu + polynomial nu_poly{nu}; + libfqfft::_polynomial_multiplication( + W_zeta_part[1], r_sub_rzeta, nu_poly); + + // --- compute W_zeta_part[2] + + // -a_zeta as constant term polynomial + polynomial a_zeta_poly_neg; + libfqfft::_polynomial_multiplication( + a_zeta_poly_neg, a_zeta_poly, round_zero_out.neg_one_poly); + // a(x) - a_zeta + polynomial a_sub_azeta; + libfqfft::_polynomial_addition( + a_sub_azeta, round_one_out.W_polys_blinded[a], a_zeta_poly_neg); + // (a(x) - a_zeta) * nu^2 + Field nu2 = libff::power(nu, libff::bigint<1>(2)); + polynomial nu2_poly{nu2}; + libfqfft::_polynomial_multiplication( + W_zeta_part[2], a_sub_azeta, nu2_poly); + + // -b_zeta as constant term polynomial + polynomial b_zeta_poly_neg; + libfqfft::_polynomial_multiplication( + b_zeta_poly_neg, b_zeta_poly, round_zero_out.neg_one_poly); + // (b(x) - b_zeta) + polynomial b_sub_bzeta; + libfqfft::_polynomial_addition( + b_sub_bzeta, round_one_out.W_polys_blinded[b], b_zeta_poly_neg); + // (b(x) - b_zeta) * nu^3 + Field nu3 = libff::power(nu, libff::bigint<1>(3)); + polynomial nu3_poly{nu3}; + libfqfft::_polynomial_multiplication( + W_zeta_part[3], b_sub_bzeta, nu3_poly); + + // -c_zeta as constant term polynomial + polynomial c_zeta_poly_neg; + libfqfft::_polynomial_multiplication( + c_zeta_poly_neg, c_zeta_poly, round_zero_out.neg_one_poly); + // (c(x) - c_zeta) + polynomial c_sub_czeta; + libfqfft::_polynomial_addition( + c_sub_czeta, round_one_out.W_polys_blinded[c], c_zeta_poly_neg); + // (c(x) - c_zeta) * nu^4 + Field nu4 = libff::power(nu, libff::bigint<1>(4)); + polynomial nu4_poly{nu4}; + libfqfft::_polynomial_multiplication( + W_zeta_part[4], c_sub_czeta, nu4_poly); + + // -S_0_zeta as constant term polynomial + polynomial S_0_zeta_poly_neg{-round_four_out.S_0_zeta}; + // libfqfft::_polynomial_multiplication(S_0_zeta_poly_neg, + // S_0_zeta_poly, round_zero_out.neg_one_poly); + // (S0(x) - S_0_zeta) + polynomial S0_sub_szeta; + libfqfft::_polynomial_addition( + S0_sub_szeta, srs.S_polys[0], S_0_zeta_poly_neg); + // (S0(x) - S_0_zeta) * nu^5 + Field nu5 = libff::power(nu, libff::bigint<1>(5)); + polynomial nu5_poly{nu5}; + libfqfft::_polynomial_multiplication( + W_zeta_part[5], S0_sub_szeta, nu5_poly); + + // -S_1_zeta as constant term polynomial + polynomial S_1_zeta_poly_neg{-round_four_out.S_1_zeta}; + // libfqfft::_polynomial_multiplication(S_1_zeta_poly_neg, + // S_1_zeta_poly, neg_one_poly); + // (S1(x) - S_1_zeta) + polynomial S1_sub_szeta; + libfqfft::_polynomial_addition( + S1_sub_szeta, srs.S_polys[1], S_1_zeta_poly_neg); + // (S1(x) - S_1_zeta) * nu^6 + Field nu6 = libff::power(nu, libff::bigint<1>(6)); + polynomial nu6_poly{nu6}; + libfqfft::_polynomial_multiplication( + W_zeta_part[6], S1_sub_szeta, nu6_poly); + + // compute full zeta polynomial W_zeta = \sum W_zeta_part[i] + int nzeta = 7; + polynomial W_zeta(round_zero_out.null_poly); + for (int i = 0; i < nzeta; ++i) { + libfqfft::_polynomial_addition(W_zeta, W_zeta, W_zeta_part[i]); + } + + // compute 1/(X-zeta) * W_zeta + polynomial x_sub_zeta_poly{-round_four_out.zeta, Field(1)}; + libfqfft::_polynomial_division(W_zeta, remainder, W_zeta, x_sub_zeta_poly); + assert(libfqfft::_is_zero(remainder)); + + // Compute opening proof: + // W_zeta_omega = z(X) - z(zeta*srs.omega_roots) / X - + // (zeta*srs.omega_roots) + polynomial W_zeta_omega{round_zero_out.null_poly}; + + // -z(zeta*srs.omega_roots) + polynomial z_poly_xomega_zeta_neg{ + -round_four_out.z_poly_xomega_zeta}; + // z(X) - z(zeta*srs.omega_roots) + libfqfft::_polynomial_addition( + W_zeta_omega, round_two_out.z_poly, z_poly_xomega_zeta_neg); + // -zeta*srs.omega_roots; srs.omega_roots[base][1] = + // srs.omega_roots_base + polynomial x_sub_zeta_omega_roots{ + -(round_four_out.zeta * srs.omega_roots[base][1]), Field(1)}; + + // z(X) - z(zeta*srs.omega_roots) / X - + // (zeta*srs.omega_roots) + libfqfft::_polynomial_division( + W_zeta_omega, remainder, W_zeta_omega, x_sub_zeta_omega_roots); + assert(libfqfft::_is_zero(remainder)); + + // TODO: move to unit test for round_five +#ifdef DEBUG + assert(W_zeta == example.W_zeta); + assert(W_zeta_omega == example.W_zeta_omega); +#endif // #ifdef DEBUG + + // Evaluate polynomials W_zeta and W_zeta_omega at the seceret + // input + W_zeta_at_secret = + plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, W_zeta); + W_zeta_omega_at_secret = plonk_evaluate_poly_at_secret_G1( + srs.secret_powers_g1, W_zeta_omega); + + // Hashes of transcript (Fiat-Shamir heuristic) -- fixed to match + // the test vectors + u = example.u; + + round_five_out_t round_five_out( + std::move(nu), + std::move(r_zeta), + std::move(W_zeta_at_secret), + std::move(W_zeta_omega_at_secret), + std::move(u)); + + return round_five_out; +} + +/// Prover compute SNARK proof +/// +/// Pi ([a]_1, [b]_1, [c]_1, [z]_1, +/// [t_lo]_1, [t_mi]_1, [t_hi]_1, +/// \bar{a}, \bar{b}, \bar{c}, +/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, +/// [W_zeta]_1, [W_{zeta omega}]_1 +/// r_zeta) +/// +/// \note in the reference Python implementation, r_zeta (the +/// evaluation of the linearlization polynomial r(X) at zeta from +/// Prover round 5) is added to the pi-SNARK proof. In the paper this +/// is omitted, which seems to make the proof shorter by 1 element at +/// the epxense of a slightly heavier computation on the verifier's +/// side. Here we follow the reference implementation to make sure we +/// match the test values. TODO: once all test vectors are verified, +/// we may remove r_zeta from the proof to be fully compliant with the +/// paper. +/// +/// Mapping code-to-paper quantities +/// +/// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 +/// (from Round 1) +/// \param z_poly_at_secret_g1: [z]_1 (from Round 2) +/// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, +/// [t_hi]_1 (from Round 3) +/// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, +/// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, +/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) +/// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, +/// [W_{zeta omega}]_1 (from Round 5) +/// +/// INPUT +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] proof: SNARK proof Pi (see above) +template +plonk_proof plonk_prover::compute_proof(const srs &srs) +{ + using Field = libff::Fr; + + // initialize hard-coded values from example circuit + plonk_example example; + std::vector witness = example.witness; + + // Prover Round 0 (initialization) + printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); + round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); + + // Prover Round 1 + printf("[%s:%d] Prover Round 1...\n", __FILE__, __LINE__); + round_one_out_t round_one_out = + plonk_prover::round_one(round_zero_out, witness, srs); + // Prover Round 1 output check against test vectors + // TODO: move to unit test for round 1 +#ifdef DEBUG + for (int i = 0; i < (int)NUM_HGEN; ++i) { + printf("[%s:%d] W_polys_blinded[%d]\n", __FILE__, __LINE__, i); + print_vector(round_one_out.W_polys_blinded[i]); + assert(round_one_out.W_polys_blinded[i] == example.W_polys_blinded[i]); + } + printf("[%s:%d] Output from Round 1\n", __FILE__, __LINE__); + for (int i = 0; i < (int)NUM_HGEN; ++i) { + printf("W_polys_at_secret_g1[%d]\n", i); + round_one_out.W_polys_blinded_at_secret_g1[i].print(); + libff::G1 W_polys_blinded_at_secret_g1_i( + round_one_out.W_polys_blinded_at_secret_g1[i]); + W_polys_blinded_at_secret_g1_i.to_affine_coordinates(); + assert( + W_polys_blinded_at_secret_g1_i.X == + example.W_polys_blinded_at_secret_g1[i][0]); + assert( + W_polys_blinded_at_secret_g1_i.Y == + example.W_polys_blinded_at_secret_g1[i][1]); + } +#endif // #ifdef DEBUG + + printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); + round_two_out_t round_two_out = + plonk_prover::round_two(round_zero_out, round_one_out, witness, srs); + // Prover Round 2 output check against test vectors + // TODO: move to unit test for round 2 +#ifdef DEBUG + printf("[%s:%d] z_poly\n", __FILE__, __LINE__); + print_vector(round_two_out.z_poly); + assert(round_two_out.z_poly == example.z_poly); + printf("[%s:%d] Output from Round 2\n", __FILE__, __LINE__); + printf("[%s:%d] z_poly_at_secret_g1\n", __FILE__, __LINE__); + round_two_out.z_poly_at_secret_g1.print(); + libff::G1 z_poly_at_secret_g1_aff(round_two_out.z_poly_at_secret_g1); + z_poly_at_secret_g1_aff.to_affine_coordinates(); + assert(z_poly_at_secret_g1_aff.X == example.z_poly_at_secret_g1[0]); + assert(z_poly_at_secret_g1_aff.Y == example.z_poly_at_secret_g1[1]); +#endif // #ifdef DEBUG + + printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); + round_three_out_t round_three_out = plonk_prover::round_three( + round_zero_out, round_one_out, round_two_out, srs); + // Prover Round 3 output check against test vectors + // TODO: move to unit test for round 3 +#ifdef DEBUG + printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); + for (int i = 0; i < (int)NUM_HGEN; ++i) { + printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); + round_three_out.t_poly_at_secret_g1[i].print(); + libff::G1 t_poly_at_secret_g1_i( + round_three_out.t_poly_at_secret_g1[i]); + t_poly_at_secret_g1_i.to_affine_coordinates(); + assert(t_poly_at_secret_g1_i.X == example.t_poly_at_secret_g1[i][0]); + assert(t_poly_at_secret_g1_i.Y == example.t_poly_at_secret_g1[i][1]); + } +#endif // #ifdef DEBUG + + printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); + round_four_out_t round_four_out = + plonk_prover::round_four(round_one_out, round_three_out, srs); + // Prover Round 4 output check against test vectors + // TODO: move to unit test for round 4 +#ifdef DEBUG + printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); + printf("a_zeta "); + round_four_out.a_zeta.print(); + assert(round_four_out.a_zeta == example.a_zeta); + printf("b_zeta "); + round_four_out.b_zeta.print(); + assert(round_four_out.b_zeta == example.b_zeta); + printf("c_zeta "); + round_four_out.c_zeta.print(); + assert(round_four_out.c_zeta == example.c_zeta); + printf("S_0_zeta "); + round_four_out.S_0_zeta.print(); + assert(round_four_out.S_0_zeta == example.S_0_zeta); + printf("S_1_zeta "); + round_four_out.S_1_zeta.print(); + assert(round_four_out.S_1_zeta == example.S_1_zeta); + printf("t_zeta "); + round_four_out.t_zeta.print(); + assert(round_four_out.t_zeta == example.t_zeta); + printf("z_poly_xomega_zeta "); + round_four_out.z_poly_xomega_zeta.print(); + assert(round_four_out.z_poly_xomega_zeta == example.z_poly_xomega_zeta); +#endif // #ifdef DEBUG + + printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); + round_five_out_t round_five_out = plonk_prover::round_five( + round_zero_out, + round_one_out, + round_two_out, + round_three_out, + round_four_out, + srs); + // Prover Round 5 output check against test vectors + // TODO: move to unit test for round 5 +#ifdef DEBUG + printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); + printf("r_zeta "); + round_five_out.r_zeta.print(); + assert(round_five_out.r_zeta == example.r_zeta); + printf("[%s:%d] W_zeta_at_secret \n", __FILE__, __LINE__); + round_five_out.W_zeta_at_secret.print(); + libff::G1 W_zeta_at_secret_aff(round_five_out.W_zeta_at_secret); + W_zeta_at_secret_aff.to_affine_coordinates(); + assert(W_zeta_at_secret_aff.X == example.W_zeta_at_secret[0]); + assert(W_zeta_at_secret_aff.Y == example.W_zeta_at_secret[1]); + printf("[%s:%d] W_zeta_omega_at_secret \n", __FILE__, __LINE__); + round_five_out.W_zeta_omega_at_secret.print(); + libff::G1 W_zeta_omega_at_secret_aff( + round_five_out.W_zeta_omega_at_secret); + W_zeta_omega_at_secret_aff.to_affine_coordinates(); + assert(W_zeta_omega_at_secret_aff.X == example.W_zeta_omega_at_secret[0]); + assert(W_zeta_omega_at_secret_aff.Y == example.W_zeta_omega_at_secret[1]); +#endif // #ifdef DEBUG + + // construct proof + plonk_proof proof( + round_one_out.W_polys_blinded_at_secret_g1, + round_two_out.z_poly_at_secret_g1, + round_three_out.t_poly_at_secret_g1, + round_four_out.a_zeta, + round_four_out.b_zeta, + round_four_out.c_zeta, + round_four_out.S_0_zeta, + round_four_out.S_1_zeta, + round_four_out.z_poly_xomega_zeta, + round_five_out.W_zeta_at_secret, + round_five_out.W_zeta_omega_at_secret, + round_five_out.r_zeta); + + // return proof + return proof; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ From 55f0f12b125da28155228d3c0750b351ddaead1d Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:52:57 +0100 Subject: [PATCH 008/154] plonk: implemented verifier class --- libsnark/zk_proof_systems/plonk/verifier.hpp | 415 +++++++++++ libsnark/zk_proof_systems/plonk/verifier.tcc | 694 +++++++++++++++++++ 2 files changed, 1109 insertions(+) create mode 100644 libsnark/zk_proof_systems/plonk/verifier.hpp create mode 100644 libsnark/zk_proof_systems/plonk/verifier.tcc diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp new file mode 100644 index 000000000..28033abf1 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -0,0 +1,415 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_HPP_ + +/// Declaration of Verifier interfaces for ppzkSNARK proof system Plonk. This +/// includes: +/// +/// - class for verifier +/// +/// References: +/// +/// - \[GWC19]: +/// Title: "Plonk: Permutations over lagrange-bases for oecumenical +/// noninteractive arguments of knowledge", Ariel Gabizon, Zachary +/// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, +/// Report 2019/953, 2019, + +namespace libsnark +{ + +/// SNARK proof +/// +/// (\see plonk_prover::compute_proof) +/// +/// Pi ([a]_1, [b]_1, [c]_1, [z]_1, +/// [t_lo]_1, [t_mi]_1, [t_hi]_1, +/// \bar{a}, \bar{b}, \bar{c}, +/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, +/// [W_zeta]_1, [W_{zeta omega}]_1 +/// r_zeta (*)) +/// +/// Mapping code-to-paper quantities (code: paper) +/// +/// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 +/// (from Round 1) +/// \param z_poly_at_secret_g1: [z]_1 (from Round 2) +/// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, +/// [t_hi]_1 (from Round 3) +/// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, +/// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, +/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) +/// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, +/// [W_{zeta omega}]_1 (from Round 5) +/// +/// Verifier preprocessed input +/// +/// \param Q_polys_at_secret_g1[0..3]: [q_M]_1, [q_L]_1, [q_R]_1, +/// [q_O]_1 +/// \param S_polys_at_secret_g1[0..2]: [S_sigma1]_1, [S_sigma2]_1, +/// [S_sigma3]_1 +/// \param srs.secret_powers_g2[1]: [secret]_2 = secret^1 * G2 +/// +/// Public input polynomial +/// +/// srs.PI_poly: w_i, 0\le{i} struct verifier_preprocessed_input_t { + std::vector> Q_polys_at_secret_g1; + std::vector> S_polys_at_secret_g1; +}; + +/// Verifier step 4 output +template struct step_four_out_t { + libff::Fr beta; + libff::Fr gamma; + libff::Fr alpha; + libff::Fr zeta; + libff::Fr nu; + libff::Fr u; + step_four_out_t( + libff::Fr &&beta, + libff::Fr &&gamma, + libff::Fr &&alpha, + libff::Fr &&zeta, + libff::Fr &&nu, + libff::Fr &&u) + : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) + { + } +}; + +/// Verifier step 5 output +template struct step_five_out_t { + /// evaluation of vanishing polynomial Zh at x=zeta i.e. Zh(zeta) + libff::Fr zh_zeta; + step_five_out_t(libff::Fr &&zh_zeta) : zh_zeta(zh_zeta) {} +}; + +/// Verifier step 6 output +template struct step_six_out_t { + /// Lagrange polynomial evaluation of polynomial L1 at x=zeta + /// i.e. L1(zeta) + libff::Fr L_0_zeta; + step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) {} +}; + +/// Verifier step 7 output +template struct step_seven_out_t { + /// Public input polynomial PI evaluated at x=zeta .e. PI(zeta) + libff::Fr PI_zeta; + step_seven_out_t(libff::Fr &&PI_zeta) : PI_zeta(PI_zeta) {} +}; + +/// Verifier step 8 output +template struct step_eight_out_t { + /// compute quotient polynomial evaluation r'(zeta) = r(zeta) - r0, + /// where r0 is a constant term Note: + libff::Fr r_prime_zeta; + step_eight_out_t(libff::Fr &&r_prime_zeta) : r_prime_zeta(r_prime_zeta) + { + } +}; + +/// Verifier step 9 output +template struct step_nine_out_t { + /// first part of batched polynomial commitment [D]_1 + libff::G1 D1; + step_nine_out_t(libff::G1 &&D1) : D1(D1) {} +}; + +/// Verifier step 10 output +template struct step_ten_out_t { + /// full batched polynomial commitment [F]_1 = [D]_1 + v [a]_1 + v^2 + /// [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + v^5 [s_sigma_2]_1 + libff::G1 F1; + step_ten_out_t(libff::G1 &&F1) : F1(F1) {} +}; + +/// Verifier step 11 output +template struct step_eleven_out_t { + /// group-encoded batch evaluation [E]_1 + libff::G1 E1; + step_eleven_out_t(libff::G1 &&E1) : E1(E1) {} +}; + +/// Plonk verifier. Verifies object of class plonk_proof. +template class plonk_verifier +{ + using Field = libff::Fr; + +public: + /// Verifier precomputation + /// + /// INPUT + /// \param[in] srs: structured reference string + /// + /// OUTPUT + /// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q + /// evaluated at + /// the secret input + /// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at + /// the + /// secret input + static verifier_preprocessed_input_t preprocessed_input( + const srs &srs); + + /// Verifier Step 1: validate that elements belong to group G1 + /// + /// \attention This validation MUST be done by the caller. Empty + /// function here for consistency with the description in [GWC19] + static void step_one(const plonk_proof &proof); + /// Verifier Step 2: validate that elements belong to scalar field Fr + /// + /// \attention This validation MUST be done by the caller. Empty + /// function here for consistency with the description in [GWC19] + static void step_two(const plonk_proof &proof); + /// Verifier Step 3: validate that the public input belongs to scalar + /// field Fr + /// + /// \attention This validation MUST be done by the caller. Empty + /// function here for consistency with the description in [GWC19] + static void step_three(const srs &srs); + /// Verifier Step 4: compute challenges hashed transcript as in prover + /// description, from the common inputs, public input, and elements of + /// pi-SNARK. TODO: fixed to the test vectors for now + /// + /// OUTPUT + /// \param[out] beta, gamma: permutation challenges - hashes of + /// transcript + /// \param[out] alpha: quotinet challenge - hash of transcript + /// \param[out] zeta: evaluation challenge - hash of transcript + /// \param[out] nu: opening challenge - hash of transcript (denoted by + /// v in [GWC19]) + /// \param[out] u: multipoint evaluation challenge - hash of + /// transcript + static step_four_out_t step_four(); + /// Verifier Step 5: compute zero polynomial evaluation + /// + /// INPUT + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at + /// x=zeta i.e. Zh(zeta) + static step_five_out_t step_five( + const step_four_out_t &step_four_out, const srs &srs); + /// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) + /// Note: the paper counts the L-polynomials from 1; we count from 0 + /// + /// INPUT + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial + /// L1 at x=zeta i.e. L1(zeta) + static step_six_out_t step_six( + const step_four_out_t &step_four_out, const srs &srs); + /// Verifier Step 7: compute public input polynomial evaluation + /// PI(zeta) + /// + /// INPUT + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] PI_zeta: public input polynomial PI evaluated at + /// x=zeta i.e. PI(zeta) + static step_seven_out_t step_seven( + const step_four_out_t &step_four_out, const srs &srs); + /// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = + /// r(zeta) - r0, where r0 is a constant term \note follows the Python + /// reference implementation, which slightly deviates from the paper + /// due to the presence of the r_zeta term in the proof (not present + /// in the paper). In particular, the reference code computes and + /// uses r'(zeta) in step 8, while the paper uses r0. In addition, the + /// reference code divides r'(zeta) by the vanishing polynomial at + /// zeta zh_zeta, while the paper does not do that (see also Step 9). + /// + /// INPUT + /// \param[in] beta, gamma: permutation challenges -- hashes of + /// transcript (from step 4) + /// \param[in] alpha: quotinet challenge -- hash of transcript (from + /// step 4) + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at + /// x=zeta i.e. Zh(zeta) (from step 5) + /// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial + /// L1 at x=zeta i.e. L1(zeta) (from step 6) + /// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta + /// i.e. PI(zeta) (from step 7) + /// \param[in] proof: SNARK proof produced by the prover + /// + /// OUTPUT + /// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) + /// = r(zeta) - r0, where r0 is a constant term + static step_eight_out_t step_eight( + const step_four_out_t &step_four_out, + const step_five_out_t &step_five_out, + const step_six_out_t &step_six_out, + const step_seven_out_t &step_seven_out, + const plonk_proof &proof); + /// Verifier Step 9: compute first part of batched polynomial + /// commitment [D]_1 Note: the reference implemention differs from the + /// paper -- it does not add the following term to D1, but to F1 (Step + /// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n + /// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n + /// [t_hi]_1) is added to F1 in Step 10 and the multiplication by + /// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in + /// Step 8. + /// + /// INPUT + /// \param[in] beta, gamma: permutation challenges -- hashes of + /// transcript (from step 4) + /// \param[in] alpha: quotinet challenge -- hash of transcript (from + /// step 4) + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] nu: opening challenge -- hash of transcript (denoted by + /// v in [GWC19]) (from step 4) + /// \param[in] u: multipoint evaluation challenge -- hash of + /// transcript (from step 4) + /// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial + /// L1 at x=zeta i.e. L1(zeta) (from step 6) + /// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q + /// evaluated at the secret input (from verifier + /// preprocessed input) + /// \param[in] S_polys_at_secret_g1: permutation polynomials S + /// evaluated at the secret input (from verifier + /// preprocessed input) + /// \param[in] proof: SNARK proof produced by the prover + /// \param[in] preprocessed_input: verifier preprocessed input + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] D1: first part of batched polynomial commitment [D]_1 + static step_nine_out_t step_nine( + const step_four_out_t &step_four_out, + const step_six_out_t &step_six_out, + const plonk_proof &proof, + const verifier_preprocessed_input_t &preprocessed_input, + const srs &srs); + /// Verifier Step 10: compute full batched polynomial commitment [F]_1 + /// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + + /// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the + /// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is + /// addedto [D]_1 in the paper (see commenst to Steps 8,9) + /// + /// INPUT + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] nu: opening challenge -- hash of transcript (denoted by + /// v in [GWC19]) (from step 4) + /// \param[in] u: multipoint evaluation challenge -- hash of + /// transcript (from step 4) + /// \param[in] D1: first part of batched polynomial commitment [D]_1 + /// (from step 9) + /// \param[in] S_polys_at_secret_g1: permutation polynomials S + /// evaluated at the secret input (from verifier + /// preprocessed input) + /// \param[in] proof: SNARK proof produced by the prover + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] F1: full batched polynomial commitment [F]_1 + static step_ten_out_t step_ten( + const step_four_out_t &step_four_out, + const step_nine_out_t &step_nine_out, + const plonk_proof &proof, + const verifier_preprocessed_input_t &preprocessed_input, + const srs &srs); + /// Verifier Step 11: compute group-encoded batch evaluation [E]_1 + /// + /// INPUT + /// \param[in] nu: opening challenge -- hash of transcript (denoted by + /// v in [GWC19]) (from step 4) + /// \param[in] u: multipoint evaluation challenge -- hash of + /// transcript (from step 4) + /// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = + /// r(zeta) - r0, where r0 is a constant term (from step 8) + /// \param[in] proof: SNARK proof produced by the prover + /// + /// OUTPUT + /// \param[out] E1: group-encoded batch evaluation [E]_1 + static step_eleven_out_t step_eleven( + const step_four_out_t &step_four_out, + const step_eight_out_t &step_eight_out, + const plonk_proof &proof); + /// Verifier Step 12: batch validate all evaluations + /// + /// Checks the following equality + /// + /// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta + /// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 + /// - [F]_1 + [E]_1, [1]_2 ) = Field(1) + /// + /// Denoted as: + /// + /// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 + /// + /// INPUT + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// step 4) + /// \param[in] u: multipoint evaluation challenge -- hash of + /// transcript (from step 4) + /// \param[in] F1: full batched polynomial commitment [F]_1 (from step + /// 10) + /// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) + /// \param[in] proof: SNARK proof produced by the prover + /// \param[in] srs: structured reference string + /// \param[in] srs: structured reference string containing also + /// circuit-specific information + /// + /// OUTPUT + /// \param[out] boolean 1/0 = valid/invalid proof + static bool step_twelve( + const step_four_out_t &step_four_out, + const step_ten_out_t &step_ten_out, + const step_eleven_out_t &step_eleven_out, + const plonk_proof &proof, + const srs &srs); + /// \attention The first three steps (as given in [GWC19] -- see + /// below) MUST be executed by the caller: + /// + /// Verifier Step 1: validate that elements belong to group G1 + /// Verifier Step 2: validate that elements belong to scalar field Fr + /// Verifier Step 3: validate that the public input belongs to scalar field + /// Fr + /// + /// Therefore verification starts from Step 4 of [GWC19] + /// + /// INPUT + /// \param[in] proof: SNARK proof produced by the prover + /// \param[in] srs: structured reference string containing also + /// circuit-specific + /// information + /// + /// OUTPUT + /// \param[out] boolean 1/0 = valid/invalid proof + bool verify_proof(const plonk_proof &proof, const srs &srs); +}; + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/verifier.tcc" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc new file mode 100644 index 000000000..c382b8c72 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -0,0 +1,694 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ + +/// Implementation of Verifier interfaces for a ppzkSNARK for Plonk. See +/// verifier.hpp . + +namespace libsnark +{ + +/// Verifier precomputation +/// +/// INPUT +/// \param[in] srs: structured reference string +/// +/// OUTPUT +/// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated +/// at +/// the secret input +/// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the +/// secret input +template +verifier_preprocessed_input_t plonk_verifier::preprocessed_input( + const srs &srs) +{ + verifier_preprocessed_input_t preprocessed_input; + preprocessed_input.Q_polys_at_secret_g1.resize(srs.Q_polys.size()); + plonk_evaluate_polys_at_secret_G1( + srs.secret_powers_g1, + srs.Q_polys, + preprocessed_input.Q_polys_at_secret_g1); + + preprocessed_input.S_polys_at_secret_g1.resize(srs.S_polys.size()); + plonk_evaluate_polys_at_secret_G1( + srs.secret_powers_g1, + srs.S_polys, + preprocessed_input.S_polys_at_secret_g1); + return preprocessed_input; +} + +/// Verifier Step 1: validate that elements belong to group G1 +/// +/// \attention This validation MUST be done by the caller. Empty +/// function here for consistency with the description in [GWC19] +template +void plonk_verifier::step_one(const plonk_proof &proof) +{ +} + +/// Verifier Step 2: validate that elements belong to scalar field Fr +/// +/// \attention This validation MUST be done by the caller. Empty +/// function here for consistency with the description in [GWC19] +template +void plonk_verifier::step_two(const plonk_proof &proof) +{ +} + +/// Verifier Step 3: validate that the public input belongs to scalar +/// field Fr +/// +/// \attention This validation MUST be done by the caller. Empty +/// function here for consistency with the description in [GWC19] +template void plonk_verifier::step_three(const srs &srs) +{ +} + +/// Verifier Step 4: compute challenges hashed transcript as in prover +/// description, from the common inputs, public input, and elements of +/// pi-SNARK. TODO: fixed to the test vectors for now +/// +/// OUTPUT +/// \param[out] beta, gamma: permutation challenges - hashes of +/// transcript +/// \param[out] alpha: quotinet challenge - hash of transcript +/// \param[out] zeta: evaluation challenge - hash of transcript +/// \param[out] nu: opening challenge - hash of transcript (denoted by +/// v in [GWC19]) +/// \param[out] u: multipoint evaluation challenge - hash of +/// transcript +template step_four_out_t plonk_verifier::step_four() +{ + // load challenges from example for debug + plonk_example example; + // step 4 output + libff::Fr beta; + libff::Fr gamma; + libff::Fr alpha; + libff::Fr zeta; + libff::Fr nu; + libff::Fr u; + + beta = example.beta; + gamma = example.gamma; + alpha = example.alpha; + zeta = example.zeta; + nu = example.nu; + u = example.u; + + step_four_out_t step_four_out( + std::move(beta), + std::move(gamma), + std::move(alpha), + std::move(zeta), + std::move(nu), + std::move(u)); + + return step_four_out; +} + +/// Verifier Step 5: compute zero polynomial evaluation +/// +/// INPUT +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at +/// x=zeta i.e. Zh(zeta) +template +step_five_out_t plonk_verifier::step_five( + const step_four_out_t &step_four_out, const srs &srs) +{ + libff::Fr zh_zeta; + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(srs.num_gates); + zh_zeta = domain->compute_vanishing_polynomial(step_four_out.zeta); + step_five_out_t step_five_out(std::move(zh_zeta)); + return step_five_out; +} + +/// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) +/// Note: the paper counts the L-polynomials from 1; we count from 0 +/// +/// INPUT +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial +/// L1 at x=zeta i.e. L1(zeta) +template +step_six_out_t plonk_verifier::step_six( + const step_four_out_t &step_four_out, const srs &srs) +{ + libff::Fr L_0_zeta; + L_0_zeta = libfqfft::evaluate_polynomial( + srs.L_basis[0].size(), srs.L_basis[0], step_four_out.zeta); + step_six_out_t step_six_out(std::move(L_0_zeta)); + return step_six_out; +} + +/// Verifier Step 7: compute public input polynomial evaluation +/// PI(zeta) +/// +/// INPUT +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] PI_zeta: public input polynomial PI evaluated at +/// x=zeta i.e. PI(zeta) +template +step_seven_out_t plonk_verifier::step_seven( + const step_four_out_t &step_four_out, const srs &srs) +{ + libff::Fr PI_zeta; + PI_zeta = libfqfft::evaluate_polynomial( + srs.PI_poly.size(), srs.PI_poly, step_four_out.zeta); + step_seven_out_t step_seven_out(std::move(PI_zeta)); + return step_seven_out; +} + +/// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = +/// r(zeta) - r0, where r0 is a constant term \note follows the Python +/// reference implementation, which slightly deviates from the paper +/// due to the presence of the r_zeta term in the proof (not present +/// in the paper). In particular, the reference code computes and +/// uses r'(zeta) in step 8, while the paper uses r0. In addition, the +/// reference code divides r'(zeta) by the vanishing polynomial at +/// zeta zh_zeta, while the paper does not do that (see also Step 9). +/// +/// INPUT +/// \param[in] beta, gamma: permutation challenges -- hashes of +/// transcript (from step 4) +/// \param[in] alpha: quotinet challenge -- hash of transcript (from +/// step 4) +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at +/// x=zeta i.e. Zh(zeta) (from step 5) +/// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial +/// L1 at x=zeta i.e. L1(zeta) (from step 6) +/// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta +/// i.e. PI(zeta) (from step 7) +/// \param[in] proof: SNARK proof produced by the prover +/// +/// OUTPUT +/// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) +/// = r(zeta) - r0, where r0 is a constant term +template +step_eight_out_t plonk_verifier::step_eight( + const step_four_out_t &step_four_out, + const step_five_out_t &step_five_out, + const step_six_out_t &step_six_out, + const step_seven_out_t &step_seven_out, + const plonk_proof &proof) +{ + libff::Fr r_prime_zeta; + Field alpha_power2 = libff::power(step_four_out.alpha, libff::bigint<1>(2)); + + // compute polynomial r'(zeta) = r(zeta) - r_0 + std::vector r_prime_parts(5); + r_prime_parts[0] = proof.r_zeta + step_seven_out.PI_zeta; + r_prime_parts[1] = + (proof.a_zeta + (step_four_out.beta * proof.S_0_zeta) + + step_four_out.gamma); + r_prime_parts[2] = + (proof.b_zeta + (step_four_out.beta * proof.S_1_zeta) + + step_four_out.gamma); + r_prime_parts[3] = (proof.c_zeta + step_four_out.gamma) * + proof.z_poly_xomega_zeta * step_four_out.alpha; + r_prime_parts[4] = (step_six_out.L_0_zeta * alpha_power2); + r_prime_zeta = (r_prime_parts[0] - + (r_prime_parts[1] * r_prime_parts[2] * r_prime_parts[3]) - + r_prime_parts[4]) * + step_five_out.zh_zeta.inverse(); + + step_eight_out_t step_eight_out(std::move(r_prime_zeta)); + return step_eight_out; +} + +/// Verifier Step 9: compute first part of batched polynomial +/// commitment [D]_1 Note: the reference implemention differs from the +/// paper -- it does not add the following term to D1, but to F1 (Step +/// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n +/// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n +/// [t_hi]_1) is added to F1 in Step 10 and the multiplication by +/// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in +/// Step 8. +/// +/// INPUT +/// \param[in] beta, gamma: permutation challenges -- hashes of +/// transcript (from step 4) +/// \param[in] alpha: quotinet challenge -- hash of transcript (from +/// step 4) +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] nu: opening challenge -- hash of transcript (denoted by +/// v in [GWC19]) (from step 4) +/// \param[in] u: multipoint evaluation challenge -- hash of +/// transcript (from step 4) +/// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial +/// L1 at x=zeta i.e. L1(zeta) (from step 6) +/// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q +/// evaluated at the secret input (from verifier +/// preprocessed input) +/// \param[in] S_polys_at_secret_g1: permutation polynomials S +/// evaluated at the secret input (from verifier +/// preprocessed input) +/// \param[in] proof: SNARK proof produced by the prover +/// \param[in] preprocessed_input: verifier preprocessed input +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] D1: first part of batched polynomial commitment [D]_1 +template +step_nine_out_t plonk_verifier::step_nine( + const step_four_out_t &step_four_out, + const step_six_out_t &step_six_out, + const plonk_proof &proof, + const verifier_preprocessed_input_t &preprocessed_input, + const srs &srs) +{ + libff::G1 D1; + + // D1 is computed in 3 parts + std::vector> D1_part(3); + + Field alpha_power2 = libff::power(step_four_out.alpha, libff::bigint<1>(2)); + + // compute D1_part[0]: + // (a_bar b_bar [q_M]_1 + a_bar [q_L]_1 + b_bar [q_R]_1 + c_bar [q_O]_1 + + // [q_C]_1) nu Note: the paper omits the final multiplication by nu + std::vector> curve_points{ + preprocessed_input.Q_polys_at_secret_g1[M], + preprocessed_input.Q_polys_at_secret_g1[L], + preprocessed_input.Q_polys_at_secret_g1[R], + preprocessed_input.Q_polys_at_secret_g1[O], + preprocessed_input.Q_polys_at_secret_g1[C]}; + std::vector> scalar_elements{proof.a_zeta * proof.b_zeta * + step_four_out.nu, + proof.a_zeta * step_four_out.nu, + proof.b_zeta * step_four_out.nu, + proof.c_zeta * step_four_out.nu, + step_four_out.nu}; + D1_part[0] = plonk_multi_exp_G1(curve_points, scalar_elements); + + // compute D1_part[1]: + // ((a_bar + beta zeta + gamma)(b_bar + beta k1 zeta + gamma)(c_bar + beta + // k2 zeta + gamma) alpha + L1(zeta) alpha^2 + u) [z]_1 + Field D1_part1_scalar = + (proof.a_zeta + (step_four_out.beta * step_four_out.zeta) + + step_four_out.gamma) * + (proof.b_zeta + (step_four_out.beta * srs.k1 * step_four_out.zeta) + + step_four_out.gamma) * + (proof.c_zeta + (step_four_out.beta * srs.k2 * step_four_out.zeta) + + step_four_out.gamma) * + step_four_out.alpha * step_four_out.nu + + step_six_out.L_0_zeta * alpha_power2 * step_four_out.nu + + step_four_out.u; + D1_part[1] = D1_part1_scalar * proof.z_poly_at_secret_g1; + + // compute D1_part[2]: + // (a_bar + beta s_sigma1_bar + gamma)(b_bar + beta s_sigma2_bar + + // gamma)alpha beta z_preprocessed_input.omega_roots_bar [s_sigma3]_1 + Field D1_part2_scalar = + ((proof.a_zeta + (step_four_out.beta * proof.S_0_zeta) + + step_four_out.gamma) * + (proof.b_zeta + (step_four_out.beta * proof.S_1_zeta) + + step_four_out.gamma) * + step_four_out.alpha * step_four_out.beta * proof.z_poly_xomega_zeta * + step_four_out.nu) * + Field(-1); + D1_part[2] = D1_part2_scalar * preprocessed_input.S_polys_at_secret_g1[2]; + + // Compute D1 = D1_part[0] + D1_part[1] + D1_part[2] + D1 = D1_part[0] + D1_part[1] + D1_part[2]; + + step_nine_out_t step_nine_out(std::move(D1)); + return step_nine_out; +} + +/// Verifier Step 10: compute full batched polynomial commitment [F]_1 +/// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + +/// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the +/// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is +/// addedto [D]_1 in the paper (see commenst to Steps 8,9) +/// +/// INPUT +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] nu: opening challenge -- hash of transcript (denoted by +/// v in [GWC19]) (from step 4) +/// \param[in] u: multipoint evaluation challenge -- hash of +/// transcript (from step 4) +/// \param[in] D1: first part of batched polynomial commitment [D]_1 +/// (from step 9) +/// \param[in] S_polys_at_secret_g1: permutation polynomials S +/// evaluated at the secret input (from verifier +/// preprocessed input) +/// \param[in] proof: SNARK proof produced by the prover +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] F1: full batched polynomial commitment [F]_1 +template +step_ten_out_t plonk_verifier::step_ten( + const step_four_out_t &step_four_out, + const step_nine_out_t &step_nine_out, + const plonk_proof &proof, + const verifier_preprocessed_input_t &preprocessed_input, + const srs &srs) +{ + libff::G1 F1; + Field zeta_power_n = + libff::power(step_four_out.zeta, libff::bigint<1>(srs.num_gates + 2)); + Field zeta_power_2n = libff::power( + step_four_out.zeta, libff::bigint<1>(2 * (srs.num_gates + 2))); + std::vector nu_power(7); + for (size_t i = 0; i < nu_power.size(); ++i) { + nu_power[i] = libff::power(step_four_out.nu, libff::bigint<1>(i)); + } + std::vector> curve_points{ + proof.t_poly_at_secret_g1[lo], // nu^0 + proof.t_poly_at_secret_g1[mid], // nu^0 + proof.t_poly_at_secret_g1[hi], // nu^0 + step_nine_out.D1, // nu^1 + proof.W_polys_blinded_at_secret_g1[a], // nu^2 + proof.W_polys_blinded_at_secret_g1[b], // nu^3 + proof.W_polys_blinded_at_secret_g1[c], // nu^4 + preprocessed_input.S_polys_at_secret_g1[0], // nu^5 + preprocessed_input.S_polys_at_secret_g1[1] // nu^6 + }; + std::vector> scalar_elements{ + Field(1), + zeta_power_n, // zeta^(n+2), + zeta_power_2n, // zeta^(2*(n+2)), + Field(1), + nu_power[2], // nu^2, + nu_power[3], // nu^3, + nu_power[4], // nu^4, + nu_power[5], // nu^5, + nu_power[6] // nu^6 + }; + F1 = plonk_multi_exp_G1(curve_points, scalar_elements); + step_ten_out_t step_ten_out(std::move(F1)); + return step_ten_out; +} + +/// Verifier Step 11: compute group-encoded batch evaluation [E]_1 +/// +/// INPUT +/// \param[in] nu: opening challenge -- hash of transcript (denoted by +/// v in [GWC19]) (from step 4) +/// \param[in] u: multipoint evaluation challenge -- hash of +/// transcript (from step 4) +/// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = +/// r(zeta) - r0, where r0 is a constant term (from step 8) +/// \param[in] proof: SNARK proof produced by the prover +/// +/// OUTPUT +/// \param[out] E1: group-encoded batch evaluation [E]_1 +template +step_eleven_out_t plonk_verifier::step_eleven( + const step_four_out_t &step_four_out, + const step_eight_out_t &step_eight_out, + const plonk_proof &proof) +{ + libff::G1 E1; + std::vector nu_power(7); + for (size_t i = 0; i < nu_power.size(); ++i) { + nu_power[i] = libff::power(step_four_out.nu, libff::bigint<1>(i)); + } + std::vector> curve_points{libff::G1::one()}; + std::vector> scalar_elements{ + step_eight_out.r_prime_zeta + nu_power[1] * proof.r_zeta + // v^1 + nu_power[2] * proof.a_zeta + // v^2 + nu_power[3] * proof.b_zeta + // v^3 + nu_power[4] * proof.c_zeta + // v^4 + nu_power[5] * proof.S_0_zeta + // v^5 + nu_power[6] * proof.S_1_zeta + // v^6 + step_four_out.u * proof.z_poly_xomega_zeta}; + + E1 = plonk_multi_exp_G1(curve_points, scalar_elements); + + step_eleven_out_t step_eleven_out(std::move(E1)); + return step_eleven_out; +} + +/// Verifier Step 12: batch validate all evaluations +/// +/// Checks the following equality +/// +/// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta +/// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 +/// - [F]_1 + [E]_1, [1]_2 ) = Field(1) +/// +/// Denoted as: +/// +/// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 +/// +/// INPUT +/// \param[in] zeta: evaluation challenge -- hash of transcript (from +/// step 4) +/// \param[in] u: multipoint evaluation challenge -- hash of +/// transcript (from step 4) +/// \param[in] F1: full batched polynomial commitment [F]_1 (from step +/// 10) +/// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) +/// \param[in] proof: SNARK proof produced by the prover +/// \param[in] srs: structured reference string +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// +/// OUTPUT +/// \param[out] boolean 1/0 = valid/invalid proof +template +bool plonk_verifier::step_twelve( + const step_four_out_t &step_four_out, + const step_ten_out_t &step_ten_out, + const step_eleven_out_t &step_eleven_out, + const plonk_proof &proof, + const srs &srs) +{ + std::vector> curve_points_lhs{proof.W_zeta_at_secret, + proof.W_zeta_omega_at_secret}; + std::vector> scalar_elements_lhs{Field(1), step_four_out.u}; + libff::G1 pairing_first_lhs = + plonk_multi_exp_G1(curve_points_lhs, scalar_elements_lhs); + libff::G2 pairing_second_lhs = srs.secret_powers_g2[1]; + + std::vector> curve_points_rhs{proof.W_zeta_at_secret, + proof.W_zeta_omega_at_secret, + step_ten_out.F1, + step_eleven_out.E1}; + std::vector> scalar_elements_rhs{ + // Warning! raise to the power of -1 to check e() * e()^-1 = 1 + Field(-1) * step_four_out.zeta, + Field(-1) * step_four_out.u * step_four_out.zeta * + srs.omega_roots[base][1], + Field(-1) * Field(1), + Field(-1) * Field(-1)}; + + libff::G1 pairing_first_rhs = + plonk_multi_exp_G1(curve_points_rhs, scalar_elements_rhs); + libff::G2 pairing_second_rhs = srs.secret_powers_g2[0]; + + // TODO: move to unit test for step_twelve +#ifdef DEBUG + // load test vectors for debug + plonk_example example; + printf("[%s:%d] pairing_first_lhs\n", __FILE__, __LINE__); + pairing_first_lhs.print(); + libff::G1 pairing_first_lhs_aff(pairing_first_lhs); + pairing_first_lhs_aff.to_affine_coordinates(); + assert(pairing_first_lhs_aff.X == example.pairing_first_lhs[0]); + assert(pairing_first_lhs_aff.Y == example.pairing_first_lhs[1]); + + printf("[%s:%d] pairing_first_rhs\n", __FILE__, __LINE__); + pairing_first_rhs.print(); + libff::G1 pairing_first_rhs_aff(pairing_first_rhs); + pairing_first_rhs_aff.to_affine_coordinates(); + assert(pairing_first_rhs_aff.X == example.pairing_first_rhs[0]); + assert(pairing_first_rhs_aff.Y == example.pairing_first_rhs[1]); +#endif // #ifdef DEBUG + + const libff::G1_precomp _A = ppT::precompute_G1(pairing_first_lhs); + const libff::G2_precomp _B = ppT::precompute_G2(pairing_second_lhs); + const libff::G1_precomp _C = ppT::precompute_G1(pairing_first_rhs); + const libff::G2_precomp _D = ppT::precompute_G2(pairing_second_rhs); + const libff::Fqk miller_result = + ppT::double_miller_loop(_A, _B, _C, _D); + const libff::GT result = ppT::final_exponentiation(miller_result); + bool b_accept = (result == libff::GT::one()); + return b_accept; +} + +/// \attention The first three steps (as given in [GWC19] -- see +/// below) MUST be executed by the caller: +/// +/// - Verifier Step 1: validate that elements belong to group G1 +/// - Verifier Step 2: validate that elements belong to scalar field +/// Fr +/// - Verifier Step 3: validate that the public input belongs to +/// scalar field Fr +/// . +/// Therefore verification starts from Step 4 of [GWC19] +/// +/// INPUT +/// \param[in] proof: SNARK proof produced by the prover +/// \param[in] srs: structured reference string containing also circuit-specific +/// information +/// +/// OUTPUT +/// \param[out] boolean 1/0 = valid/invalid proof +template +bool plonk_verifier::verify_proof( + const plonk_proof &proof, const srs &srs) +{ + // compute verifier preprocessed input + const verifier_preprocessed_input_t preprocessed_input = + plonk_verifier::preprocessed_input(srs); + + // TODO: move to unit test for verify_proof +#ifdef DEBUG + // load test vector values form example for debug + plonk_example example; + for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { + printf("srs.Q_polys_at_secret_G1[%d] \n", i); + preprocessed_input.Q_polys_at_secret_g1[i].print(); + libff::G1 Q_poly_at_secret_g1_i( + preprocessed_input.Q_polys_at_secret_g1[i]); + Q_poly_at_secret_g1_i.to_affine_coordinates(); + assert(Q_poly_at_secret_g1_i.X == example.Q_polys_at_secret_g1[i][0]); + assert(Q_poly_at_secret_g1_i.Y == example.Q_polys_at_secret_g1[i][1]); + } + for (int i = 0; i < (int)srs.S_polys.size(); ++i) { + printf("S_polys_at_secret_G1[%d] \n", i); + preprocessed_input.S_polys_at_secret_g1[i].print(); + libff::G1 S_poly_at_secret_g1_i( + preprocessed_input.S_polys_at_secret_g1[i]); + S_poly_at_secret_g1_i.to_affine_coordinates(); + assert(S_poly_at_secret_g1_i.X == example.S_polys_at_secret_g1[i][0]); + assert(S_poly_at_secret_g1_i.Y == example.S_polys_at_secret_g1[i][1]); + } +#endif // #ifdef DEBUG + + // Verifier Step 1: validate that elements belong to group G1 + // Verifier Step 2: validate that elements belong to scalar field Fr + // Verifier Step 3: validate that the public input belongs to scalar field + // Fr + // + // Executed by the caller + + // Verifier Step 4: compute challenges hashed transcript as in + // prover description, from the common inputs, public input, and + // elements of pi-SNARK (fixed to the test vectors for now) + const step_four_out_t step_four_out = this->step_four(); + + // Verifier Step 5: compute zero polynomial evaluation + const step_five_out_t step_five_out = + this->step_five(step_four_out, srs); + // TODO: uni test for step_five +#ifdef DEBUG + printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); + step_five_out.zh_zeta.print(); + assert(step_five_out.zh_zeta == example.zh_zeta); +#endif // #ifdef DEBUG + + // Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) + // Note: the paper counts the L-polynomials from 1; we count from 0 + const step_six_out_t step_six_out = this->step_six(step_four_out, srs); + // TODO: uni test for step_six +#ifdef DEBUG + printf("L_0_zeta "); + step_six_out.L_0_zeta.print(); + assert(step_six_out.L_0_zeta == example.L_0_zeta); +#endif // #ifdef DEBUG + + // Verifier Step 7: compute public input polynomial evaluation PI(zeta) + const step_seven_out_t step_seven_out = + this->step_seven(step_four_out, srs); + // TODO: uni test for step_seven +#ifdef DEBUG + printf("PI_zeta "); + step_seven_out.PI_zeta.print(); + assert(step_seven_out.PI_zeta == example.PI_zeta); +#endif // #ifdef DEBUG + + // Verifier Step 8: compute quotient polynomial evaluation + // r'(zeta) = r(zeta) - r0, where r0 is a constant term + const step_eight_out_t step_eight_out = this->step_eight( + step_four_out, step_five_out, step_six_out, step_seven_out, proof); + // TODO: uni test for step_eight +#ifdef DEBUG + assert(step_eight_out.r_prime_zeta == example.r_prime_zeta); +#endif // #ifdef DEBUG + + // Verifier Step 9: compute first part of batched polynomial + // commitment [D]_1 + step_nine_out_t step_nine_out = this->step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); + // TODO: uni test for step_nine +#ifdef DEBUG + step_nine_out.D1.print(); + libff::G1 D1_aff(step_nine_out.D1); + D1_aff.to_affine_coordinates(); + assert(D1_aff.X == example.D1[0]); + assert(D1_aff.Y == example.D1[1]); +#endif // #ifdef DEBUG + + // Verifier Step 10: compute full batched polynomial commitment + // [F]_1 + step_ten_out_t step_ten_out = this->step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); + // TODO: uni test for step_ten +#ifdef DEBUG + printf("[%s:%d] F1\n", __FILE__, __LINE__); + step_ten_out.F1.print(); + libff::G1 F1_aff(step_ten_out.F1); + F1_aff.to_affine_coordinates(); + assert(F1_aff.X == example.F1[0]); + assert(F1_aff.Y == example.F1[1]); +#endif // #ifdef DEBUG + + // Verifier Step 11: compute group-encoded batch evaluation [E]_1 + const step_eleven_out_t step_eleven_out = + this->step_eleven(step_four_out, step_eight_out, proof); + // TODO: uni test for step_eleven +#ifdef DEBUG + printf("[%s:%d] E1\n", __FILE__, __LINE__); + step_eleven_out.E1.print(); + libff::G1 E1_aff(step_eleven_out.E1); + E1_aff.to_affine_coordinates(); + assert(E1_aff.X == example.E1[0]); + assert(E1_aff.Y == example.E1[1]); +#endif // #ifdef DEBUG + + // Verifier Step 12: batch validate all evaluations (check + // pairing) + bool b_accept = this->step_twelve( + step_four_out, step_ten_out, step_eleven_out, proof, srs); + return b_accept; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ From 82ddddfa8d193d946797df9f7e5b04c03b356512 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:54:04 +0100 Subject: [PATCH 009/154] plonk: added tests and test vector values --- .../zk_proof_systems/plonk/tests/example.hpp | 266 +++++ .../zk_proof_systems/plonk/tests/example.tcc | 918 ++++++++++++++++++ .../plonk/tests/test_plonk.cpp | 261 +++++ 3 files changed, 1445 insertions(+) create mode 100644 libsnark/zk_proof_systems/plonk/tests/example.hpp create mode 100644 libsnark/zk_proof_systems/plonk/tests/example.tcc create mode 100644 libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp new file mode 100644 index 000000000..cd4b040f6 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -0,0 +1,266 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_HPP_ + +/// Test vectors for the implementation of the PlonK protocol \[GWC19] +/// (\see plonk.hpp) produced using the Python implementation of Plonk +/// available at [PlonkPy]. +/// +/// The test vector values trace the execution of the Plonk protocol for +/// the example ciruit P(x) = x**3 + x + 5 = 35 discussed in a blog post +/// by Vitalik Buterin [VB19]. +/// +/// References: +/// - \[PlonkPy] +/// Title: Implementation of the Plonk ZKSNARK proof system in +/// Python, accessed in May 2022 on GitHub +/// https://github.com/ETHorHIL/Plonk_Py +/// - \[VB19] +/// Title: "Understanding PLONK", Vitalik Buterin, personal blog +/// post from 22 Sep 2019, +/// https://vitalik.ca/general/2019/09/22/plonk.html + +namespace libsnark +{ + +/// Example Plonk circuit from [VB19]: +/// +/// P(x) = x**3 + x + 5 = 35 +/// +/// circuit has 6 gates + 2 dummy gates (to make power of 2 for the FFT) +/// +/// gates / constraints +/// +/// L R O +/// 1 mul x * x = v1 +/// 2 mul v1 * x = v2 +/// 3 add v2 + x = v3 +/// 4 con5 1 * 5 = 5 +/// 5 pin 1 * 35 = 35 +/// 6 add v3 + 5 = 35 +/// 7 dum / / / +/// 8 dum / / / +/// +/// wire polynomials +/// +/// w_L = [ x, v1, v2, 1, 1, v3, /, /] = [a1, a2, a3, a4, a5, a6, a7, a8] = +/// a w_R = [ x, x, x, 5, 35, 5, /, /] = [b1, b2, b3, b4, b5, b6, b7, b8] +/// = b w_O = [v1, v2, v3, 5, 35, 35, /, /] = [c1, c2, c3, c4, c5, c6, c7, +/// c8] = c +/// +/// wires = [a1, a2, a3, a4, a5, a6, a7, a8, b1, b2, b3, b4, b5, b6, b7, b8, c1, +/// c2, c3, c4, c5, c6, c7, c8] index = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, +/// 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] perm = [ 9, 17, 18, +/// 5, 4, 19, 7, 8, 10, 11, 1, 14, 21, 20, 15, 16, 2, 3, 6, 12, 22, 13, +/// 23, 24] +/// +/// witness +/// +/// x = 3 => v1 = 9, v2 = 27, v3 = 30 +/// +/// w_L = a = [ 3, 9, 27, 1, 1, 30, 0, 0] +/// w_R = b = [ 3, 3, 3, 5, 35, 5, 0, 0] +/// w_O = c = [ 9, 27, 30, 5, 35, 35, 0, 0] +/// +/// W = w_L + w_R + w_O +/// +/// encoding of plonk gates +/// +/// add = [1, 1,-1, 0, 0] +/// mul = [0, 0,-1, 1, 0] +/// con5 = [0, 1, 0, 0, 5] +/// pi = [0, 1, 0, 0, 0] +/// dum = [0, 0, 0, 0, 0] +/// +/// gates matrix +/// +/// (q_L * a) + (q_R * b) + (q_O * c) + (q_M * a * b) + (q_C) = 0 +/// +/// gates q_L q_R q_O q_M q_C +/// 1 mul x * x = v1 : [ 0, 0, -1, 1, 0] +/// 2 mul v1 * x = v2 : [ 0, 0, -1, 1, 0] +/// 3 add v2 + x = v3 : [ 1, 1, -1, 0, 0] +/// 4 con5 1 * 5 = 5 : [ 0, 1, 0, 0, -5] +/// 5 pin 1 * 35 = 35 : [ 0, 1, 0, 0, 0] +/// 6 add v2 + 5 = 35 : [ 1, 1, -1, 0, 0] +/// 7 dum / / / : [ 0, 0, 0, 0, 0] +/// 8 dum / / / : [ 0, 0, 0, 0, 0] +/// +/// q_L = [ 0, 0, 1, 0, 0, 1, 0, 0] +/// q_R = [ 0, 0, 1, 1, 1, 1, 0, 0] +/// q_O = [-1, -1, -1, 0, 0, 0, 0, 0] +/// q_M = [ 1, 1, 0, 0, 0, -1, 0, 0] +/// q_C = [ 0, 0, 0, -1, 0, 0, 0, 0] +template class plonk_example +{ +public: + using Field = libff::Fr; + using BaseField = libff::Fq; + template using polynomial = std::vector; + + /// Circuit data + + /// number of gates / constraints. we have 6 gates for the example + /// circuit + 2 dummy gates to make it a power of 2 (for the fft) + size_t num_gates; + + /// number of q-polynomials + size_t num_qpolys; + + /// hard-coded gates matrix for the example circuit P(x) = x**3 + + /// x + 5 = 3 Each column is a q-vector + std::vector> gates_matrix; + + /// Transposed gates matrix: each row is a q-vector WARN: rows 2 + /// q_O and 3 q_M are swapped ti match the Plonk_Py test vectors + /// implementation (reason unclear) + std::vector> gates_matrix_transpose; + + /// witness values + /// w_L = a = [ 3, 9, 27, 1, 1, 30, 0, 0] + /// w_R = b = [ 3, 3, 3, 5, 35, 5, 0, 0] + /// w_O = c = [ 9, 27, 30, 5, 35, 35, 0, 0] + /// W = w_L + w_R + w_O + std::vector witness; + + /// wire permutation (TODO: add function + /// plonk_compute_permutation()) + std::vector wire_permutation; + + /// public input (PI) + Field public_input; + /// index of the row of the PI in the non-transposed gates_matrix + size_t public_input_index; + + /// n-th root of unity omega in Fq (n=8 is the number of + /// constraints in the example). omega is a generator of the + /// multiplicative subgroup H. Example (2**32)-th primitive root + /// of unity in the base field Fq of bls12-381 i.e. such that + /// omega_base**(2**32) = 1. The bls12-381 prime q is such that + /// any power of 2 divides (q-1). In particular 2**32|(q-1) and so + /// the 2**32-th root of unity exists. + Field omega_base; + + /// Constants k1,k2 to generate domains on which to evaluate the + /// witness polynomials. k can be random, but we fix it for debug + /// to match against the test vector values + Field k1; + /// Similarly, k2 can be random, but we fix it to match the test + /// vectors + Field k2; + + /// H_gen contains the generators of H, k1 H and K2 H in one place + /// ie. omega, omega_k1 and omega_k2 + std::vector H_gen; + /// H_gen permuted according to the wire permutation + std::vector H_gen_permute; + /// random hidden element secret (toxic waste). we fix it to a + /// constant in order to match against the test vectors + Field secret; + /// powers of secret times G1: 1*G1, secret^1*G1, secret^2*G1, ... + std::vector> secret_powers_g1; + /// powers of secret times G2: 1*G2, secret^1*G2 + std::vector> secret_powers_g2; + /// blinding scalars b1, b2, ..., b9. random but fixed to match + /// the python test vectors + std::vector prover_blind_scalars; + /// Hashes of transcript (Fiat-Shamir heuristic) + Field beta; + Field gamma; + Field alpha; + Field zeta; + Field nu; /// v in the paper + Field u; + /// Prover Round 1 + std::vector> W_polys; + /// vanishing polynomial zh_poly(X) = x^n-1. vanishes on all n + /// roots of unity omega_roots + std::vector zh_poly; + /// Witness polynomials blinded by b constants a_poly = + /// blind_polys[0] * zh_poly + W_polys[0] + std::vector> W_polys_blinded; + /// blinded witness polynomials evaluate at secret input + std::vector> W_polys_blinded_at_secret_g1; + /// Prover Round 2 + /// accumulator polynomial + std::vector A_poly; + /// blinded accumulator poly z(x) + std::vector z_poly; + /// blinded accumulator poly z(x) evaluated at secret + std::vector z_poly_at_secret_g1; + /// Prover Round 3 + /// z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted by w + std::vector z_poly_xomega; + /// t_poly: the quotient polynomial t(x) (see Round 3, pp28 + /// [GWC19]) + std::vector> t_poly; + /// t_poly_long: t(x) divided in three parts t(x) = t_lo(x) + + /// t_mid(x) x^n + t_hi(x) x^{2n} + polynomial t_poly_long; + /// t_poly_at_secret_g1: t(x) evaluated at the secret input zeta + /// i.e. t(zeta) + std::vector> t_poly_at_secret_g1; + /// Prover Round 4 + Field a_zeta; + Field b_zeta; + Field c_zeta; + Field S_0_zeta; + Field S_1_zeta; + Field t_zeta; + Field z_poly_xomega_zeta; + /// Prover Round 5 + /// linearisation polynomial r(x) + polynomial r_poly; + /// linearisation polynomial evaluated at x=zeta ie. r(zeta) + Field r_zeta; + /// opening proof polynomial W_zeta(x) + polynomial W_zeta; + /// opening proof polynomial W_{zeta omega}(x) + polynomial W_zeta_omega; + /// commitment to opening proof polynomial W_zeta(x) at secert + /// input i.e. [W_zeta(secret)]_1 (represented as a point on the + /// curve as a pair of X,Y coordinates (values in the base field)) + std::vector W_zeta_at_secret; + /// commitment to opening proof polynomial W_{zeta omega}(x) at + /// secert input i.e. [W_{zeta omega}(secret)]_1 + std::vector W_zeta_omega_at_secret; + /// Verifier precomputation + std::vector> Q_polys_at_secret_g1; + std::vector> S_polys_at_secret_g1; + /// Verifier Step 5: vanishing polynomial evaluation at zeta + Field zh_zeta; + /// Verifier Step 6: compute Lagrange polynomial evaluation + /// L1(zeta) + Field L_0_zeta; + /// Verifier Step7: evaluate public input polynomial at zeta + Field PI_zeta; + /// Verifier Step 8: compute quotient polynomial evaluation + /// r'(zeta) = r(zeta) - r0, where r0 is a constant term + Field r_prime_zeta; + /// Verifier Step 9 + std::vector D1; + /// Verifier Step 10: compute full batched polynomial commitment + std::vector F1; + /// Verifier Step 11: compute group-encoded batch evaluation [E]_1 + std::vector E1; + /// Verifier Step 12: batch validate all evaluations via pairing + std::vector pairing_first_lhs; + std::vector pairing_first_rhs; + // std::vector pairing_second_lhs; + // std::vector pairing_second_rhs; + + plonk_example(); +}; + +} // namespace libsnark + +#include + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/example.tcc b/libsnark/zk_proof_systems/plonk/tests/example.tcc new file mode 100644 index 000000000..d6f9a9fe6 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/example.tcc @@ -0,0 +1,918 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ + +/// Instantiation of the test vector values from the Python implementation +/// of the Plonk protocol. \see example.hpp . + +namespace libsnark +{ + +template plonk_example::plonk_example() +{ + using Field = libff::Fr; + using BaseField = libff::Fq; + + // Circuit data + + // number of gates / constraints. we have 6 gates for the example + // circuit + 2 dummy gates to make it a power of 2 (for the fft) + this->num_gates = 8; + + // number of q-polynomials + this->num_qpolys = 5; + + // hard-coded gates matrix for the example circuit P(x) = x**3 + x + // + 5 = 3 Each column is a q-vector + this->gates_matrix = { + // q_L q_R q_M q_O q_C + {Field(0), Field(0), Field(1), -Field("1"), Field(0)}, // mul + {Field(0), Field(0), Field(1), -Field("1"), Field(0)}, // mul + {Field(1), Field(1), Field(0), -Field("1"), Field(0)}, // add + {Field(0), Field(1), Field(0), Field(0), -Field("5")}, // con5 + {Field(0), Field(1), Field(0), Field(0), Field(0)}, // PI + {Field(1), Field(1), Field(0), -Field("1"), Field(0)}, // add + {Field(0), Field(0), Field(0), Field(0), Field(0)}, // dummy + {Field(0), Field(0), Field(0), Field(0), Field(0)}, // dummy + }; + + this->gates_matrix_transpose = { + // mul mul add con5 PI add dum dum + {Field(0), + Field(0), + Field(1), + Field(0), + Field(0), + Field(1), + Field(0), + Field(0)}, // q_L + {Field(0), + Field(0), + Field(1), + Field(1), + Field(1), + Field(1), + Field(0), + Field(0)}, // q_R + {Field(1), + Field(1), + Field(0), + Field(0), + Field(0), + Field(0), + Field(0), + Field(0)}, // q_M + {-Field("1"), + -Field("1"), + -Field("1"), + Field(0), + Field(0), + -Field("1"), + Field(0), + Field(0)}, // q_O + {Field(0), + Field(0), + Field(0), + -Field("5"), + Field(0), + Field(0), + Field(0), + Field(0)}, // q_C + }; + + // witness values + // w_L = a = [ 3, 9, 27, 1, 1, 30, 0, 0] + // w_R = b = [ 3, 3, 3, 5, 35, 5, 0, 0] + // w_O = c = [ 9, 27, 30, 5, 35, 35, 0, 0] + // W = w_L + w_R + w_O + this->witness = { + 3, 9, 27, 1, 1, 30, 0, 0, // w_L + 3, 3, 3, 5, 35, 5, 0, 0, // w_R + 9, 27, 30, 5, 35, 35, 0, 0 // w_O + }; + + // wire permutation (TODO: add function plonk_compute_permutation()) + this->wire_permutation = {9, 17, 18, 5, 4, 19, 7, 8, 10, 11, 1, 14, + 21, 20, 15, 16, 2, 3, 6, 12, 22, 13, 23, 24}; + + // public input (PI) + this->public_input = Field(35); + + // index of the row of the PI in the non-transposed gates_matrix + this->public_input_index = 4; + + // n-th root of unity omega in Fq (n=8 is the number of constraints + // in the example). omega is a generator of the multiplicative + // subgroup H. Example (2**32)-th primitive root of unity in the + // base field Fq of bls12-381 i.e. such that omega_base**(2**32) = + // 1. The bls12-381 prime q is such that any power of 2 divides + // (q-1). In particular 2**32|(q-1) and so the 2**32-th root of + // unity exists. + this->omega_base = Field("2367469443165877065961295211566080294796737370150" + "6253797663184111817857449850"); + + // Constants k1,k2 to generate domains on which to evaluate the witness + // polynomials. k can be random, but we fix it for debug to match + // against the test vector values + this->k1 = Field("706987411474581393682955260879121390206111740035659671471" + "3673571023200548519"); + // Similarly, k2 can be random, but we fix it to match the test + // vectors + this->k2 = libff::power(k1, libff::bigint<1>(2)); + + // H_gen contains the generators of H, k1 H and K2 H in one place + // ie. omega, omega_k1 and omega_k2 + this->H_gen = { + Field("1"), + Field("2367469443165877065961295211566080294796737370150625379766318411" + "1817857449850"), + Field("3465144826073652318776269530687742778270252468765361963008"), + Field("8685283084174350996472453922654922162880456818468779543064782192" + "722679779374"), + Field("5243587517512619047944774050818596583769055250052763782260365869" + "9938581184512"), + Field("2876118074346741981983478839252516288972317879902138402494047458" + "8120723734663"), + Field("5243587517512619047598259568211231351891428296983989504433340623" + "1173219221505"), + Field("4375059209095183948297528658553104367481009568205885827953887650" + "7215901405139"), + Field("7069874114745813936829552608791213902061117400356596714713673571" + "023200548519"), + Field("6296993470737855411634321870255436387440388789676314980338138891" + "26570754409"), + Field("2134293230218433692027649469636827607837588105510789904753879922" + "6396168459088"), + Field("1267882965986156059121750719885063580789301664257248207931748295" + "050157094180"), + Field("4536600106038037654261818789939475193562943510017104110788998512" + "8915380635994"), + Field("5180617582805240493828430832116042219894651362156000632456984481" + "0812010430104"), + Field("3109294287294185355917124581181768975931467144541973877506485947" + "3542412725425"), + Field("5116799220914003442032598978830090225690125083627038961467191040" + "4888424090333"), + Field("1838592104783212022667877350171394113611392647210607993375145291" + "4767234401351"), + Field("3787649880178070211080878147767178500088988709179240616011656188" + "3724775274403"), + Field("2013895375313748245055634445236271583185979532535422332242782401" + "9686639989507"), + Field("2345700989319520162686183217527414661504655478998796606881532728" + "3610815221310"), + Field("3404995412729407025276896700647202470157662602842155788885220578" + "5171346783162"), + Field("1455937637334548836863895903051418083680066540873523166248709681" + "6213805910110"), + Field("3229692142198870802889139605582325000583075717517341450017583468" + "0251941195006"), + Field("2897886528193098885258590833291181922264399771053967175378833141" + "6327765963203")}; + + // H_gen permuted according to the wire permutation + this->H_gen_permute = { + Field("7069874114745813936829552608791213902061117400356596714713673571" + "023200548519"), + Field("1838592104783212022667877350171394113611392647210607993375145291" + "4767234401351"), + Field("3787649880178070211080878147767178500088988709179240616011656188" + "3724775274403"), + Field("5243587517512619047944774050818596583769055250052763782260365869" + "9938581184512"), + Field("8685283084174350996472453922654922162880456818468779543064782192" + "722679779374"), + Field("2013895375313748245055634445236271583185979532535422332242782401" + "9686639989507"), + Field("5243587517512619047598259568211231351891428296983989504433340623" + "1173219221505"), + Field("4375059209095183948297528658553104367481009568205885827953887650" + "7215901405139"), + Field("6296993470737855411634321870255436387440388789676314980338138891" + "26570754409"), + Field("2134293230218433692027649469636827607837588105510789904753879922" + "6396168459088"), + Field("1"), + Field("5180617582805240493828430832116042219894651362156000632456984481" + "0812010430104"), + Field("3404995412729407025276896700647202470157662602842155788885220578" + "5171346783162"), + Field("2345700989319520162686183217527414661504655478998796606881532728" + "3610815221310"), + Field("3109294287294185355917124581181768975931467144541973877506485947" + "3542412725425"), + Field("5116799220914003442032598978830090225690125083627038961467191040" + "4888424090333"), + Field("2367469443165877065961295211566080294796737370150625379766318411" + "1817857449850"), + Field("3465144826073652318776269530687742778270252468765361963008"), + Field("2876118074346741981983478839252516288972317879902138402494047458" + "8120723734663"), + Field("1267882965986156059121750719885063580789301664257248207931748295" + "050157094180"), + Field("1455937637334548836863895903051418083680066540873523166248709681" + "6213805910110"), + Field("4536600106038037654261818789939475193562943510017104110788998512" + "8915380635994"), + Field("3229692142198870802889139605582325000583075717517341450017583468" + "0251941195006"), + Field("2897886528193098885258590833291181922264399771053967175378833141" + "6327765963203")}; + + // random hidden element secret (toxic waste). we fix it to a + // constant in order to match against the test vectors + this->secret = Field("13778279493383315901513166932749987230291710199728570" + "152123261818328463629146"); + + this->secret_powers_g1 = { + {BaseField("36854167537133870167810883151830777579616207957825464098945" + "78378688607592378376318836054947676345821548104185464507"), + BaseField("13395065449444764730204713799419212215849338759383496204265" + "43736416511423956333506472724655353366534992391756441569")}, + {BaseField("20749965662226492945615097978198189221739861329213084113581" + "40896113079536003850694012630431408673580733705096617791"), + BaseField("20776169388666778595331629779008748452369857341460416596178" + "70201535410847474163664062006824876754586584291291275540")}, + {BaseField("29908066896405034961181068491184887680953048361228849374589" + "15361027713460409591689021671430152609090653721640806775"), + BaseField("15069105631190064801231642485088185662289730777561049481656" + "05526387811452704182227509354555265743592891256699177447")}, + {BaseField("11623994229753380094658096850046421770851169520142342404026" + "11534721365805950787073304245916047514747507357062412420"), + BaseField("32439913241842824306660774309390158013390581471164196275365" + "28847445203118923037149866561100103780253903700544760551")}, + {BaseField("66595550477645955422317691187591228045792600941665863117655" + "0711534449750755438228569302251439190379809780541605589"), + BaseField("15639754518865509584520548319903391700028182018162323764862" + "89252647203460244570019694049681767056597843416540080200")}, + {BaseField("13997155334738944346453484434520404070385952861192139915240" + "09101772100073848392561767527055222979107182734281429257"), + BaseField("24801967186118020827532424272070678408955817575006204546556" + "73428668098605801043836809939785138234969928618554184939")}, + {BaseField("72198996603356233208233142438023880002035034269949947481094" + "0866633976625729399263772964415588210693897376315032210"), + BaseField("23909713088018334455114179971652675642764792282949811409915" + "37842761274654400117722746265926005170825975983654738210")}, + {BaseField("24946452033393671727656887869287695560429335312866283157804" + "59840863253114375261836717471927002510598950105128289874"), + BaseField("22308947402682432087653424099864122493269262968494186222854" + "0161286780230155004903395236049749437555611923506858957")}, + {BaseField("13692091156184100189040529930284250299924138421820151450177" + "24608932835902017735132442291326610507957006806305596987"), + BaseField("16697997752614730182918384485633392374605603738670095512703" + "85685110329728891027501463328761827882531243313994834792")}, + {BaseField("32324617157201419767841199840089167892367982261722591009915" + "24828275951110441373038297570085682311463031127657083499"), + BaseField("21748585940969090447471146438241363898290310715892941128918" + "97914222472713836544371512541030476560224224399906695672")}, + {BaseField("32945190541547333935734520835897537392840680022512314688362" + "06591341493107913789146528048543749767535356614865447074"), + BaseField( + "10784239041438369956852608259577689512593965753533688873687516562" + "19548634950458729521798081562106307219496322329732")}}; + + // blinding scalars b1, b2, ..., b9. random but fixed to match + // the python test vectors + prover_blind_scalars = {Field("80633968928703880558063703697897048577551160" + "44327394765020751373651916505604"), + Field("68270264301200565976794531113706823063169483" + "63643792417785314991392447377909"), + Field("20903799562102387073359556962112335230020378" + "309596765284572286455779329747315"), + Field("27445824854335787523979734401573136947589999" + "159092723101543900479804718923773"), + Field("52164479755085410212907573804852358855974754" + "07449078898274648785082871817687"), + Field("48720156268681305476740160454555587712391923" + "971264646500554531948708930944069"), + Field("21318915166515188286980897071631919826831011" + "87444208330829153527689737950718"), + Field("47548532878000795436471885496554996210469829" + "388180983864669623532585348412472"), + Field("25345997198725001609008178533933158854206333" + "20379105447254598708515031311667")}; + + // Hashes of transcript (Fiat-Shamir heuristic) + this->beta = Field("3710899868510394644410941212967766116886736137326022751" + "891187938298987182388"); + this->gamma = Field("110379303840831945879077096653321168432672740458288022" + "49545114995763715746939"); + this->alpha = Field("379799789992747238930717819864848384921111623418803600" + "22719385400306128734648"); + this->zeta = Field("4327197228921839935583364394550235027071910395980312641" + "5018065799136107272465"); + this->nu = Field("275158598338697752421507265080923414294782807831923791651" + "55175653098691426347"); + this->u = Field("1781751143954696684632449211212056577828855388109883650570" + "6049265393896966778"); + + // Prover Round 1 + + // Witness polynomials + this->W_polys = {// W_polys[a] + { + Field("65544843968907738099309675635232457297113190625" + "65954727825457337492322648073"), // t^0 + + Field("32948500085781872641455643871559485192618005894" + "853042154825967834821350910602"), // t^1 + + Field("45881390778235416653057335020812871593791953167" + "194904897994502135810789212158"), // t^2 + + Field("21733506116237836259034000970136844665656294154" + "820722285692118576560701570202"), // t^3 + + Field("65544843968907738099309675635232457297113190625" + "65954727825457337492322648063"), // t^4 + + Field("45705312676907413054326239314722310412178003523" + "796150825755316050920327615864"), // t^5 + + Field("45881390778235416685976210868512568622166513708" + "728461291561900589081727860734"), // t^6 + + Field("44844314713252590040795968599532914049288014275" + "85360378933914937574782272359") // t^7 + }, + // W_polys[a] + { + Field("13108968793781547619861935127046491459422638125" + "131909455650914674984645296135"), // t^0 + + Field("26701543132601498945146394479737583456967318942" + "563611087328104827461434190940"), // t^1 + + Field("32772421984453869048355408507838609029015494238" + "821870097275942011674602504197"), // t^2 + + Field("13599340474087270913269318764079985464155297112" + "973389232502566508274445532606"), // t^3 + + Field("26217937587563095239723870254092982918845276250" + "263818911301829349969290592260"), // t^4 + + Field("25734332042524691531702487408893143141641031409" + "948219651572864520903125521309"), // t^5 + + Field("32772421984453869050954267127393848268097696386" + "837677180978631363248623976453"), // t^6 + + Field("38836534701038919568777280363661219612617457535" + "570055673803781543238157124155") // t^7 + }, + // W_polys[a] + { + Field("19663453190672321429792902690569737189133957187" + "697864183476372012476967944210"), // t^0 + + Field("20106536651950714560943936006683707043835113765" + "212154412313674714935702104191"), // t^1 + + Field("13108968793781547595172778241271718688141717718" + "981742160475365835031441309698"), // t^2 + + Field("18246392504049801299811961511777672791578098930" + "042302001761141999236289949018"), // t^3 + + Field("65544843968907738099309675635232457297113190625" + "65954727825457337492322648065"), // t^4 + + Field("61114009356123806527913480518568834841881410048" + "93593661961261119293373765499"), // t^5 + + Field("13108968793781547644551092012821264230703558531" + "282076750826463514937849282562"), // t^6 + + Field("79715450835132939659004949378677025180891988003" + "79587746567580866473215365792") // t^7 + }}; + // vanishing_poly + // 52435875175126190479447740508185965837690552500527637822603658699938581184512 + //+ 0 t^1 + 0 t^2 + 0 t^3 + 0 t^4 + 0 t^5 + 0 t^6 + 0 t^7 + 1 t^8 + this->zh_poly = { + Field("5243587517512619047944774050818596583769055250052763782260365869" + "9938581184512"), // t^0 + + Field("0"), // t^1 + + Field("0"), // t^2 + + Field("0"), // t^3 + + Field("0"), // t^4 + + Field("0"), // t^5 + + Field("0"), // t^6 + + Field("0"), // t^7 + + Field("1"), // t^8 + }; + // Witness polynomials blinded by b constants + // a_poly = blind_polys[0] * zh_poly + W_polys[0] + this->W_polys_blinded = { + // W_polys_blinded[a] + { + Field("521633331418969076916992549603385292610849231994498001326438" + "01046038456454677"), // t^0 + + Field("248851031929114845856492735017697803348628898505256473898052" + "16461169434404998"), // t^1 + + Field("458813907782354166530573350208128715937919531671949048979945" + "02135810789212158"), // t^2 + + Field("217335061162378362590340009701368446656562941548207222856921" + "18576560701570202"), // t^3 + + Field("655448439689077380993096756352324572971131906256595472782545" + "7337492322648063"), // t^4 + + Field("457053126769074130543262393147223104121780035237961508257553" + "16050920327615864"), // t^5 + + Field("458813907782354166859762108685125686221665137087284612915619" + "00589081727860734"), // t^6 + + Field("448443147132525900407959685995329140492880142758536037893391" + "4937574782272359"), // t^7 + + Field("682702643012005659767945311137068230631694836364379241778531" + "4991392447377909"), // t^8 + + Field("806339689287038805580637036978970485775511604432739476502075" + "1373651916505604") // t^9 + }, + // W_polys_blinded[b] + { + Field("380990191145719505753299412336593203495231914665668241767106" + "72895118507556875"), // t^0 + + Field("579774357049911187178683751762524822694694063296684580275581" + "8371682104443625"), // t^1 + + Field("327724219844538690483554085078386090290154942388218700972759" + "42011674602504197"), // t^2 + + Field("135993404740872709132693187640799854641552971129733892325025" + "66508274445532606"), // t^3 + + Field("262179375875630952397238702540929829188452762502638189113018" + "29349969290592260"), // t^4 + + Field("257343320425246915317024874088931431416410314099482196515728" + "64520903125521309"), // t^5 + + Field("327724219844538690509542671273938482680976963868376771809786" + "31363248623976453"), // t^6 + + Field("388365347010389195687772803636612196126174575355700556738037" + "81543238157124155"), // t^7 + + Field("274458248543357875239797344015731369475899991590927231015439" + "00479804718923773"), // t^8 + + Field("209037995621023870733595569621123352300203783095967652845722" + "86455779329747315") // t^9 + }, + // W_polys_blinded[c] + { + Field("233791720971172064325004827442001153144325857169608555055254" + "98763706618184654"), // t^0 + + Field("148900886764421735396531786261984711582376383577630755140390" + "25929852830286504"), // t^1 + + Field("131089687937815475951727782412717186881417177189817421604753" + "65835031441309698"), // t^2 + + Field("182463925040498012998119615117776727915780989300423020017611" + "41999236289949018"), // t^3 + + Field("655448439689077380993096756352324572971131906256595472782545" + "7337492322648065"), // t^4 + + Field("611140093561238065279134805185688348418814100489359366196126" + "1119293373765499"), // t^5 + + Field("131089687937815476445510920128212642307035585312820767508264" + "63514937849282562"), // t^6 + + Field("797154508351329396590049493786770251808919880037958774656758" + "0866473215365792"), // t^7 + + Field("487201562686813054767401604545555877123919239712646465005545" + "31948708930944069"), // t^8 + + Field("521644797550854102129075738048523588559747540744907889827464" + "8785082871817687") // t^9 + }}; + // blinded witness polynomials evaluate at secret input + this->W_polys_blinded_at_secret_g1 = { + // W_polys_blinded_at_secret_g1[a] (x,y) + {BaseField("14812287891036618330676930721693823329702411523226156376233" + "17748273515137146902630034361568804034167204753099284501"), + BaseField("17964750299387068157283823706566054419626655811998147128959" + "26933741011033298072747963710561309706677692173630366237")}, + // W_polys_blinded_at_secret_g1[b] (x,y) + {BaseField("29432220588068977731172413919004940878073922894991625118592" + "59126805842169805910975063699386916233854515174105508725"), + BaseField("14617147990844911049525808735959595358829529410173698594487" + "62515518178805418879678173039509762385815865920800988196")}, + // W_polys_blinded_at_secret_g1[c] (x,y) + {BaseField("14391627324702662166442733543984684422882998027578504520373" + "12698084674043069817398172864897193109985787550989102559"), + BaseField( + "29011633872445735455259638237873043070766218287795562103418244491" + "41545494290892417899030834624333222271719003612974")}}; + // Prover Round 2 + // accumulatro polynomial + this->A_poly = { + Field("2518625392737982296343610325189127807488571368919632517794638553" + "2342220728117"), // t^0 + + Field("3343004226366800205137468684843812026286862538920524966872869345" + "3463660552682"), // t^1 + + Field("1204771288456474927231408409787544475988184671052023508676578841" + "2377967852364"), // t^2 + + Field("1654220606090652573608134811761648464025584860436467340851483101" + "8718382023477"), // t^3 + + Field("2783712845267402774526728481246187236057799933701726441152811280" + "4611642359798"), // t^4 + + Field("3732208461409147234788564051800623612946480973700210337990448546" + "1155139003575"), // t^5 + + Field("6413652480339839192085204403325965541536359421783588217290146845" + "390811835496"), // t^6 + + Field("5096442001688032260934660998312846158129100711302111193973619127" + "1694500382544"), // t^7 + }; + // blinded accumulator poly z(x) + this->z_poly = { + Field("2265165420750732280253528539849796218946508036881721973069178682" + "3827189416450"), // t^0 + + Field("3831738456079339709435054186006908989008934850155190362666272862" + "0816893324723"), // t^1 + + Field("9915821367913230443615994390712252777198745523076026755936634884" + "688229901646"), // t^2 + + Field("1654220606090652573608134811761648464025584860436467340851483101" + "8718382023477"), // t^3 + + Field("2783712845267402774526728481246187236057799933701726441152811280" + "4611642359798"), // t^4 + + Field("3732208461409147234788564051800623612946480973700210337990448546" + "1155139003575"), // t^5 + + Field("6413652480339839192085204403325965541536359421783588217290146845" + "390811835496"), // t^6 + + Field("5096442001688032260934660998312846158129100711302111193973619127" + "1694500382544"), // t^7 + + Field("2534599719872500160900817853393315885420633320379105447254598708" + "515031311667"), // t^8 + + Field("4754853287800079543647188549655499621046982938818098386466962353" + "2585348412472"), // t^9 + + Field("2131891516651518828698089707163191982683101187444208330829153527" + "689737950718"), // t^10 + }; + // blinded accumulator poly z(x) evaluated at secret + this->z_poly_at_secret_g1 = { + BaseField("218229772328487280905090401999839431733408937653957673318017" + "4184484710730756128092226245721766481877396312865768304"), + BaseField("292507928406344683037670492963483727823750442012637110834805" + "8274997491709275417542814945756255382474849922144871524")}; + // Prover Round 3 + // t_poly_at_secret_g1: t(x) evaluated at the secret input zeta i.e. t(zeta) + this->t_poly_at_secret_g1 = { + // t_poly_at_secret_g1[0] (x,y) + {BaseField("36334753045440395809371680338918211810312700289483151569664" + "30357290637750912918602224358395819959043217498580613188"), + BaseField("14280901549512618100167591929669036233606392208611617045103" + "58440208878251190328471919089961503194904379492282570328")}, + // t_poly_at_secret_g1[1] (x,y) + {BaseField("76363409032225954376660766997910850260552039791217261961132" + "3329140740033948682915660599655604319492439350037062593"), + BaseField("28136783837059300064723980127085168126317661898643574293043" + "41222779755096333176883586053913173384834727806732577514")}, + // t_poly_at_secret_g1[2] (x,y) + {BaseField("11337733321199745710063881143204871341221284322923746136104" + "71191239740936855771046194807037399513728603857921779020"), + BaseField( + "23717433852493404330471742080754816727740110188452404228212413264" + "03735375534578397825283190840736410689009347296342")}}; + // z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted by w + this->z_poly_xomega = { + Field("2265165420750732280253528539849796218946508036881721973069178682" + "3827189416450"), // t^0 + + Field("3522707332061080835798112609163881083507261400618189899676704579" + "1350279877954"), // t^1 + + Field("3309030535278527195951493880213970747872492878590839259324563659" + "7703335115887"), // t^2 + + Field("4088099918379397647346118061563173960283766613891904952309372247" + "5099935064612"), // t^3 + + Field("2459874672245216273418045569572409347711255316351037341107554589" + "5326938824715"), // t^4 + + Field("3130512625781403637138050922833186963879103219436289731932477576" + "1009602152629"), // t^5 + + Field("5012222053129571007016945989949647333098134542190693273050557821" + "1550198923184"), // t^6 + + Field("3064349268741886919262515885662041664089860259376571962820647628" + "4834360312181"), // t^7 + + Field("2534599719872500160900817853393315885420633320379105447254598708" + "515031311667"), // t^8 + + Field("1419615120215068486878184007202189531439457176459524671730274215" + "4033633385750"), // t^9 + + Field("1019842429205845332898215495550756855277887015561016627161000987" + "5240306916807") // t^10 + }; + // t_poly: the quotient polynomial t(x) (see Round 3, pp28 [GWC19]), + this->t_poly_long = { + Field("1613850149506400547772007762591425736533070021337736890758518750" + "3110317398551"), // t^0 + + Field("3040368902288718889983204820945380652817775664997775098304580225" + "9681526185231"), // t^1 + + Field("1042102470564703322665398547899923945819513306900065157914357111" + "3800640238933"), // t^2 + + Field("1633462087831609539968808827529008330124698299502354144702821124" + "4300088022199"), // t^3 + + Field("3632784646360485930553771159655097618380845063905226267905837784" + "5835048276810"), // t^4 + + Field("3656196858094264844695875765748620979140837444590225078292098611" + "0855788988433"), // t^5 + + Field("4523255421893679400053241195748570388235240684403702464129656520" + "043856004349"), // t^6 + + Field("1002647493544172661013146016776665819687146794207805535060529180" + "6843077939272"), // t^7 + + Field("3548121107888953018916580962039584646709578854362089670366763654" + "2576580345734"), // t^8 + + Field("2297931724833055633330038364258628456490770251522597328783342991" + "5658557329963"), // t^9 + + Field("6252854478478019668247055899364396160278584256715602663448250419" + "916088342384"), // t^10 + + Field("2407613143858867391555076078532805439108651463880076324787621056" + "1552682158710"), // t^11 + + Field("3674667163620429559371781226732735616050875001211632077958321530" + "694677958113"), // t^12 + + Field("1942412489095028244973144301361474632107814650518722125151606411" + "7233674898523"), // t^13 + + Field("4005762677304860945679708501660985182956740054316240488989084561" + "2848784733039"), // t^14 + + Field("1931303367871217529389379259233466201562729351133418057091284445" + "3652385236582"), // t^15 + + Field("2221817730104195391229605776246015275856933020723204442957788785" + "1871298997907"), // t^16 + + Field("3588159848730797308072409316494361587812978320894884007923341012" + "0898701096353"), // t^17 + + Field("1310205747596608722863298127271181852811202233900209260215326001" + "1136972622921"), // t^18 + + Field("8560623145505212661032016828864500149385317605488145618652908867" + "288785811948"), // t^19 + + Field("4065894564211273790799140230700764854860230755995745210191240729" + "3426046132023"), // t^20 + + Field("5081908704900564950804424995622495124460340656509539811225297312" + "5211073271073"), // t^21 + + Field("4666457525759582528402241552791202565704683710647774067806134699" + "2623383015707"), // t^22 + + Field("4306907993838530907933054915935228091472808577800496469450130926" + "3755728838047"), // t^23 + + Field("4947724791243297456277917191608867362506589718656153051429472063" + "9066541459749"), // t^24 + + Field("2087040818294080218293142955185975472708718151197964942361522282" + "2038546839608"), // t^25 + + Field("1458546107620775338054728063563476188812102450800490940500969838" + "6466329925772"), // t^26 + + Field("7078989131341788220225651051808493470990658902234100299184940135" + "97364414823"), // t^27 + + Field("2984093618809324090683329124882124934996621572654997040583232120" + "5298097143557"), // t^28 + + Field("6188816264874193895800450614104712986342233687836446073160843161" + "893236587105") // t^29 + }; + // t_poly_long: t(x), divided in three parts t(x), = t_lo(x), + + // t_mid(x), x^n + t_hi(x), x^{2n} + this->t_poly = {// ft_lo + { + Field("161385014950640054777200776259142573653307002133" + "77368907585187503110317398551"), // t^0 + + Field("304036890228871888998320482094538065281777566499" + "77750983045802259681526185231"), // t^1 + + Field("104210247056470332266539854789992394581951330690" + "00651579143571113800640238933"), // t^2 + + Field("163346208783160953996880882752900833012469829950" + "23541447028211244300088022199"), // t^3 + + Field("363278464636048593055377115965509761838084506390" + "52262679058377845835048276810"), // t^4 + + Field("365619685809426484469587576574862097914083744459" + "02250782920986110855788988433"), // t^5 + + Field("452325542189367940005324119574857038823524068440" + "3702464129656520043856004349"), // t^6 + + Field("100264749354417266101314601677666581968714679420" + "78055350605291806843077939272"), // t^7 + + Field("354812110788895301891658096203958464670957885436" + "20896703667636542576580345734"), // t^8 + + Field("229793172483305563333003836425862845649077025152" + "25973287833429915658557329963") // t^9 + }, + // t_mid + { + Field("625285447847801966824705589936439616027858425671" + "5602663448250419916088342384"), // t^0 + + Field("240761314385886739155507607853280543910865146388" + "00763247876210561552682158710"), // t^1 + + Field("367466716362042955937178122673273561605087500121" + "1632077958321530694677958113"), // t^2 + + Field("194241248909502824497314430136147463210781465051" + "87221251516064117233674898523"), // t^3 + + Field("400576267730486094567970850166098518295674005431" + "62404889890845612848784733039"), // t^4 + + Field("193130336787121752938937925923346620156272935113" + "34180570912844453652385236582"), // t^5 + + Field("222181773010419539122960577624601527585693302072" + "32044429577887851871298997907"), // t^6 + + Field("358815984873079730807240931649436158781297832089" + "48840079233410120898701096353"), // t^7 + + Field("131020574759660872286329812727118185281120223390" + "02092602153260011136972622921"), // t^8 + + Field("856062314550521266103201682886450014938531760548" + "8145618652908867288785811948") // t^9 + }, + // t_hi + { + Field("406589456421127379079914023070076485486023075599" + "57452101912407293426046132023"), // t^0 + + Field("508190870490056495080442499562249512446034065650" + "95398112252973125211073271073"), // t^1 + + Field("466645752575958252840224155279120256570468371064" + "77740678061346992623383015707"), // t^2 + + Field("430690799383853090793305491593522809147280857780" + "04964694501309263755728838047"), // t^3 + + Field("494772479124329745627791719160886736250658971865" + "61530514294720639066541459749"), // t^4 + + Field("208704081829408021829314295518597547270871815119" + "79649423615222822038546839608"), // t^5 + + Field("145854610762077533805472806356347618881210245080" + "04909405009698386466329925772"), // t^6 + + Field("707898913134178822022565105180849347099065890223" + "410029918494013597364414823"), // t^7 + + Field("298409361880932409068332912488212493499662157265" + "49970405832321205298097143557"), // t^8 + + Field("618881626487419389580045061410471298634223368783" + "6446073160843161893236587105") // t^9 + }}; + // Prover Round 4 + this->a_zeta = Field("89018754633263103134565706528698737767467674290012895" + "06712732994487869455294"); + this->b_zeta = Field("17059370482702287697833061796226204248201565415155528" + "923232473993993212080397"); + this->c_zeta = Field("24097569659300085566963716541699131253974499863725226" + "36184003898699439708220"); + this->S_0_zeta = Field("461436261558032879183302794283908482860766454284773" + "53060129573054942492588828"); + this->S_1_zeta = Field("243927046358912523431432696335637683451450085201403" + "60299402842967762646340846"); + this->t_zeta = Field("17704211079697158667898451781925539666888780633357685" + "549668669638883218786797"); + this->z_poly_xomega_zeta = Field("28842520748921749858267479462666161290723" + "351257502457358354355079408206613634"); + // Prover Round 5 + // linearisation polynomial r(x) + this->r_poly = { + Field("2603512055252796692071737904087507556829684549510721336678959715" + "7169046865340"), // t^0 + + Field("3942753965961071766143624447190676478891460844964486462800593298" + "0154778950407"), // t^1 + + Field("1743566792151933472376808485105574264437105927288539768954931379" + "3693366950787"), // t^2 + + Field("4942865003799481471749027521378523306396518062429387236185665079" + "8295465747357"), // t^3 + + Field("4415918367620933880836129889969775566105477399880154139724106878" + "707122735424"), // t^4 + + Field("8948900433568314567249974508827746248263244175570022612023712197" + "372700744447"), // t^5 + + Field("2960702973715822632300470900105704342347090742964455410397076921" + "9991866925475"), // t^6 + + Field("4140950340042081861784876195481408717940244394208041020815793396" + "987141178934"), // t^7 + + Field("4030038061106409199760524044467210289705742219665913488385521773" + "2857702756316"), // t^8 + + Field("4793378445006658536717368078811814461230636700375498945907637919" + "9822825835746"), // t^9 + + Field("2288087964390040455243247170114287577194614314265017877490312785" + "1353091457234") // t^10 + }; + // linearisation polynomial evaluated at x=zeta ie. r(zeta) + this->r_zeta = Field("98401833553540757648601291397401878521368727319456218" + "53688663309524905254695"); + // opening proof polynomial W_zeta(x) + this->W_zeta = { + Field("2425208075861302430388734364060671625126106358899275231917791230" + "8896977829530"), // x^0 + + Field("1060760789872469863243912303046696427113635606636800367079996536" + "1976876241434"), // x^1 + + Field("4945570090835204155867856741605638033127077675733215306305597163" + "4526190286005"), // x^2 + + Field("3332027100358956385527160855090111765264327736597228066927830862" + "6702032462766"), // x^3 + + Field("1585236647926224968598276457268065881132907825354517423594189230" + "0400403939930"), // x^4 + + Field("2768243031239845689523160572736932993927651703690421976097490318" + "4897420916090"), // x^5 + + Field("3408971485363305489368119320301696605838015578921377320829539984" + "918748131464"), // x^6 + + Field("6170013496654113309991805083384693399451071882671661442964650981" + "706324964718"), // x^7 + + Field("4046651207853235565358275015621115513666336518059676997543319340" + "6332496460952"), // x^8 + + Field("2779755100662473972439074429356997821277920509470931427485728915" + "1379644029144") // x^9 + }; + // opening proof polynomial W_{zeta omega}(x) + this->W_zeta_omega = { + Field("4053156463693497745052164515731838082731509222453505556234840603" + "5588261107649"), // x^0 + + Field("4058277206829669744576668736724647055016570296582250369803518901" + "3689327598242"), // x^1 + + Field("3469229733620729618347120395255874659028106129936335068581145823" + "3238031608744"), // x^2 + + Field("3672976997032667925860661999685787149672966747083938789879739560" + "7660186144417"), // x^3 + + Field("3920037723815253535315325165819311372867884025491460418913281378" + "9688481911843"), // x^4 + + Field("3780677159511070124578530692688093256358861446957732007938945605" + "6927918503907"), // x^5 + + Field("3008905681484411520937149759836469023029665120031639147269349017" + "3328399559224"), // x^6 + + Field("5019223596666837703964065504139865465420595258667351312020460215" + "9086894893773"), // x^7 + + Field("5046455272607465584094271013540888943906468773469964673357231746" + "9624082573673"), // x^8 + + Field("2131891516651518828698089707163191982683101187444208330829153527" + "689737950718") // x^9 + }; + // commitment to opening proof polynomial W_zeta(x) at secert input + // i.e. [W_zeta(secret)]_1 (represented as a point on the curve as a + // pair of X,Y coordinates (values in the base field)) + this->W_zeta_at_secret = { + BaseField("870060484392950318936407436339281693869104302033433437217724" + "352106918879203859031480272360445121364037832041952039"), + BaseField("861299420568581680683022801956519699850698057581115592449001" + "068617883576936792838745784184017332399410405735556637")}; + // commitment to opening proof polynomial W_{zeta omega}(x) at + // secert input i.e. [W_{zeta omega}(secret)]_1 + this->W_zeta_omega_at_secret = { + BaseField("655495718420813899433022178744291341055707361726913326276228" + "363256669650441492160760400814686050651569669287015855"), + BaseField("229481443404822103284044189219285257403125043021601137826232" + "4574002174077316300644184560707652291246729455056384738")}; + // Verifier precomputation + this->Q_polys_at_secret_g1 = { + // Q_polys_at_secret_G1[0](x, y) + {BaseField("37872638117646271814730035813573941475040188186517949668804" + "5184488721729111812849671928978444183306485908524284480"), + BaseField("79183321462482392539235348002489945030682397254523366395010" + "2448253555712343824442312037763251986444707559468789167")}, + // Q_polys_at_secret_G1[1](x, y) + {BaseField("34631210648960787533875729378285482931236025064470116389646" + "95206791719047814189335281941216929475385990343236354767"), + BaseField("37560055274848745758731228857694331283955625702810481826014" + "69211783316382910994832150136370603197748628978251617855")}, + // Q_polys_at_secret_G1[2](x, y) + {BaseField("38929455936321242573458158228059689667920715759118216184118" + "50268364131846825179296155052328167376852966904585186447"), + BaseField("14387651874046990029377825249761966997493481734049336060559" + "94266712582628388073773207681042085983472030360245506053")}, + // Q_polys_at_secret_G1[3](x, y) + {BaseField("21395203688591242318834236925149705288598122582999309763678" + "81008205428239812556102432321082924215659317599549354780"), + BaseField("31608016701108926123111249555539915826675093054796279958192" + "54406979123526107121808691993608981196593224342875940517")}, + // Q_polys_at_secret_G1[4](x, y) + {BaseField("14947061974880505484736471897005901630187100836190498942013" + "40042906428954701970245565963571442231938653450961032544"), + BaseField( + "28246023002329815495890687586581650096148528539495759217955996750" + "03541734658829364117937951492488210759581945412529")}}; + this->S_polys_at_secret_g1 = { + // S_polys_at_secret_G1[0](x, y) + {BaseField("36368078628695840142519314182027223097391859322500348523037" + "5359988783103495068430872040401356145672343538149573956"), + BaseField("38086117155279067619957746135328045145411168060473709058159" + "23618967460517724494838454007652229237779324980791026678")}, + // S_polys_at_secret_G1[1](x, y) + {BaseField("22692902817920796240439217704871520306588775874145333548088" + "21851134353908789851247370093633774252241702882912887085"), + BaseField("12029919948961427716735907593948285124581150685050417216921" + "00348489247274098109255301291346677656642600399089495236")}, + // S_polys_at_secret_G1[2](x, y) + {BaseField("14092796445922828479110756772232507484316624225197532585861" + "36046888366320164223401617201095933133577003578716884726"), + BaseField( + "17392526753346659131838574196457588111148361438835640062331721065" + "01577251543276680000254892836167925142291524692240")}}; + // Verifier Step 5: vanishing polynomial evaluation at zeta + this->zh_zeta = Field("3231291541068425176363304614853753627837086743398580" + "603659947674812058489341"); + // Verifier Step 6: compute Lagrange polynomial evaluation L1(zeta) + this->L_0_zeta = Field("249023502880157597838915072978532235843469796520075" + "92864411578966192407598153"); + // Verifier Step 7: evaluate public input polynomial at zeta + this->PI_zeta = Field("5213191382864624158721462223282140052666923997678483" + "8364162926303506898992750"); + // Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = + // r(zeta) - r0, where r0 is a constant term + this->r_prime_zeta = Field("17704211079697158667898451781925539666888780633" + "357685549668669638883218786797"); + // Verifier Step 9 + this->D1 = { + // (x,y) + BaseField("295055128993514571465051427628530985500804633619823829912294" + "3701060700368614623093700969937886225712332445422779232"), + BaseField("177357457743368679564228713000738451950615223042556119935832" + "0811214796879879223471447420612658036440896892253660321")}; + // Verifier Step 10: compute full batched polynomial commitment + this->F1 = { + // (x,y) + BaseField("182674249211586861258228800954744156123303054902439656689558" + "7306861582709499257146203756040438377200227370973259986"), + BaseField("317469800320460430597039038149214739328961296782892898627772" + "0440012247826580102584515518061223894220403192017952478")}; + // Verifier Step 11: compute group-encoded batch evaluation [E]_1 + this->E1 = { + // (x,y) + BaseField("896211057343888615494168233046980277322670342780717794143414" + "541657336321268995118530971981505762603044924183423639"), + BaseField("243066919022843377501447737580021700365442316598462908640891" + "9423216148134888225770566675462506053600277852687652642")}; + // Verifier Step 12: batch validate all evaluations via pairing + this->pairing_first_lhs = { + // (x,y) + BaseField("259441502792996125537510028389383648449414919567783080548752" + "7382596454063206138678026974672787696177127251762793677"), + BaseField("235250982894607804932611639285546907420234209359655517101542" + "1209941442208769351281087086741535791209871063622971343")}; + this->pairing_first_rhs = { + // (x,y) +#if 0 // pairing check e() = e() + BaseField("2786086768974850272772873952573647917824800608941506526890251802946860616723974417792544909526285497672211326145554"), + BaseField("3322299130191197851913727020573383402853736418546119609247136782819928908204641650829975455690084120791575793280234") +#endif // #if 0 // pairing check e() = e() + // (x,y)^-1 +#if 1 // pairing check e() * e()^-1 = 1 + BaseField("278608676897485027277287395257364791782480060894150652689025" + "1802946860616723974417792544909526285497672211326145554"), + BaseField("680110425030469541504062805162520753703146401392888276084921" + "353304102742286196213612712173438931543246318479279553") +#endif // #if 1 // pairing check e() * e()^-1 = 1 + }; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp new file mode 100644 index 000000000..3293b0883 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -0,0 +1,261 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// Test program that exercises the Plonk protocol (first setup, then +/// prover, then verifier) on a synthetic R1CS instance. + +namespace libsnark +{ + +// Manipulate elements of a valid proof to assert that proof +// verification fails +// +// Plonk proof Pi is composed of the following elements: +// +// Pi ([a]_1, [b]_1, [c]_1, [z]_1, +// [t_lo]_1, [t_mi]_1, [t_hi]_1, +// \bar{a}, \bar{b}, \bar{c}, +// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, +// [W_zeta]_1, [W_{zeta omega_roots}]_1 +// r_zeta (*)) +template +void test_verify_invalid_proof( + const plonk_proof &valid_proof, const srs &srs) +{ + // initialize verifier + plonk_verifier verifier; + bool b_accept = true; + + // random element on the curve initialized to zero + libff::G1 G1_noise = libff::G1::zero(); + // random element in the scalar field initialized to zero + libff::Fr Fr_noise = libff::Fr::zero(); + // initialize the manipulated proof to the valid one + plonk_proof proof = valid_proof; + + // manipulate [a]_1, [b]_1, [c]_1 + for (size_t i = 0; i < valid_proof.W_polys_blinded_at_secret_g1.size(); + ++i) { + // re-initialize the manipulated proof + proof = valid_proof; + G1_noise = libff::G1::random_element(); + proof.W_polys_blinded_at_secret_g1[i] = + proof.W_polys_blinded_at_secret_g1[i] + G1_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + } + // manipulate [z]_1 + proof = valid_proof; + G1_noise = libff::G1::random_element(); + proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 + for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { + // re-initialize the manipulated proof + proof = valid_proof; + G1_noise = libff::G1::random_element(); + proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + } + // manipulate \bar{a} + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.a_zeta = proof.a_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate \bar{b} + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.b_zeta = proof.b_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate \bar{c} + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.c_zeta = proof.c_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate \bar{S_sigma1} + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.S_0_zeta = proof.S_0_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate \bar{S_sigma2} + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.S_1_zeta = proof.S_1_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate \bar{z_w} + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate [W_zeta]_1 + proof = valid_proof; + G1_noise = libff::G1::random_element(); + proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate [W_{zeta omega_roots}]_1 + proof = valid_proof; + G1_noise = libff::G1::random_element(); + proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); + // manipulate r_zeta + proof = valid_proof; + Fr_noise = libff::Fr::random_element(); + proof.r_zeta = proof.r_zeta + Fr_noise; + b_accept = verifier.verify_proof(proof, srs); + ASSERT_FALSE(b_accept); +} + +template void test_plonk() +{ +#ifndef DEBUG + printf("[%s:%d] WARNING! DEBUG info disabled.\n", __FILE__, __LINE__); + // assert(0); +#endif // #ifndef DEBUG + + // Execute all tests for the given curve. + ppT::init_public_params(); + + using Field = libff::Fr; + + // --- TEST VECTORS --- + // load test vector values from example circuit + plonk_example example; + + // --- SETUP --- + printf("[%s:%d] Setup...\n", __FILE__, __LINE__); + // random hidden element secret (toxic waste). we fix it to a + // constant in order to match against the test vectors + Field secret = example.secret; +#ifdef DEBUG + printf("[%s:%d] secret ", __FILE__, __LINE__); + secret.print(); +#endif // #ifdef DEBUG + + printf("[%s:%d] SRS...\n", __FILE__, __LINE__); + // --- USRS --- + // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, + // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 + usrs usrs = plonk_usrs_derive_from_secret(secret); + // --- circuit --- + circuit_t circuit = + plonk_curcuit_description_from_example(example); + // --- SRS --- + srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // sompare SRS against reference test values + for (int i = 0; i < (int)srs.num_gates + 3; ++i) { + printf("secret_power_G1[%2d] ", i); + srs.secret_powers_g1[i].print(); + // test from generator + libff::G1 srs_secret_powers_g1_i(srs.secret_powers_g1[i]); + srs_secret_powers_g1_i.to_affine_coordinates(); + ASSERT_EQ(srs_secret_powers_g1_i.X, example.secret_powers_g1[i][0]); + ASSERT_EQ(srs_secret_powers_g1_i.Y, example.secret_powers_g1[i][1]); + } + for (int i = 0; i < 2; ++i) { + printf("secret_power_G2[%2d] ", i); + srs.secret_powers_g2[i].print(); + } + + // --- PROVER --- + printf("[%s:%d] Prover...\n", __FILE__, __LINE__); + + // initialize prover + plonk_prover prover; + // compute proof + plonk_proof proof = prover.compute_proof(srs); + // compare proof against test vector values (debug) + ASSERT_EQ(proof.a_zeta, example.a_zeta); + ASSERT_EQ(proof.b_zeta, example.b_zeta); + ASSERT_EQ(proof.c_zeta, example.c_zeta); + ASSERT_EQ(proof.S_0_zeta, example.S_0_zeta); + ASSERT_EQ(proof.S_1_zeta, example.S_1_zeta); + ASSERT_EQ(proof.z_poly_xomega_zeta, example.z_poly_xomega_zeta); + ASSERT_EQ(proof.r_zeta, example.r_zeta); + for (int i = 0; i < (int)NUM_HGEN; ++i) { + printf("W_polys_at_secret_g1[%d]\n", i); + proof.W_polys_blinded_at_secret_g1[i].print(); + libff::G1 W_polys_blinded_at_secret_g1_i( + proof.W_polys_blinded_at_secret_g1[i]); + W_polys_blinded_at_secret_g1_i.to_affine_coordinates(); + ASSERT_EQ( + W_polys_blinded_at_secret_g1_i.X, + example.W_polys_blinded_at_secret_g1[i][0]); + ASSERT_EQ( + W_polys_blinded_at_secret_g1_i.Y, + example.W_polys_blinded_at_secret_g1[i][1]); + } + proof.z_poly_at_secret_g1.print(); + libff::G1 z_poly_at_secret_g1_aff(proof.z_poly_at_secret_g1); + z_poly_at_secret_g1_aff.to_affine_coordinates(); + ASSERT_EQ(z_poly_at_secret_g1_aff.X, example.z_poly_at_secret_g1[0]); + ASSERT_EQ(z_poly_at_secret_g1_aff.Y, example.z_poly_at_secret_g1[1]); + for (int i = 0; i < (int)NUM_HGEN; ++i) { + printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); + proof.t_poly_at_secret_g1[i].print(); + libff::G1 t_poly_at_secret_g1_i(proof.t_poly_at_secret_g1[i]); + t_poly_at_secret_g1_i.to_affine_coordinates(); + ASSERT_EQ(t_poly_at_secret_g1_i.X, example.t_poly_at_secret_g1[i][0]); + ASSERT_EQ(t_poly_at_secret_g1_i.Y, example.t_poly_at_secret_g1[i][1]); + } + proof.W_zeta_at_secret.print(); + libff::G1 W_zeta_at_secret_aff(proof.W_zeta_at_secret); + W_zeta_at_secret_aff.to_affine_coordinates(); + ASSERT_EQ(W_zeta_at_secret_aff.X, example.W_zeta_at_secret[0]); + ASSERT_EQ(W_zeta_at_secret_aff.Y, example.W_zeta_at_secret[1]); + proof.W_zeta_omega_at_secret.print(); + libff::G1 W_zeta_omega_at_secret_aff(proof.W_zeta_omega_at_secret); + W_zeta_omega_at_secret_aff.to_affine_coordinates(); + ASSERT_EQ(W_zeta_omega_at_secret_aff.X, example.W_zeta_omega_at_secret[0]); + ASSERT_EQ(W_zeta_omega_at_secret_aff.Y, example.W_zeta_omega_at_secret[1]); + + // --- VERIFIER --- + printf("[%s:%d] Verifier...\n", __FILE__, __LINE__); + // initialize verifier + plonk_verifier verifier; + // verify proof + bool b_valid_proof = verifier.verify_proof(proof, srs); + ASSERT_TRUE(b_valid_proof); + // assert that proof verification fails when the proof is + // manipulated. must be executed when DEBUG is not defined to + // disable certain assert-s that may fail before the verify + // invalid proof test +#ifndef DEBUG + test_verify_invalid_proof(proof, srs); +#endif // #ifndef DEBUG +#ifndef DEBUG + printf("[%s:%d] WARNING! DEBUG info was disabled.\n", __FILE__, __LINE__); +#endif // #ifndef DEBUG + printf("[%s:%d] Test OK\n", __FILE__, __LINE__); + // end +} + +TEST(TestPlonk, BLS12_381) { test_plonk(); } + +} // namespace libsnark From e9ebc1231fc3aa26caca8303d8254d5c46b96fb7 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 27 Jun 2022 11:54:04 +0100 Subject: [PATCH 010/154] plonk: added tests and test vector values; minor fixes to formatting using higher version clang-format-11 --- libsnark/zk_proof_systems/plonk/prover.tcc | 7 ++++--- libsnark/zk_proof_systems/plonk/srs.tcc | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 63c0317fb..a490e1ffa 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -184,9 +184,10 @@ round_two_out_t plonk_prover::round_two( // compute permutation polynomial // blinding polynomial: b8 + b7 X + b6 X^2 - std::vector z1_blind_poly{round_one_out.blind_scalars[8], - round_one_out.blind_scalars[7], - round_one_out.blind_scalars[6]}; + std::vector z1_blind_poly{ + round_one_out.blind_scalars[8], + round_one_out.blind_scalars[7], + round_one_out.blind_scalars[6]}; // multiply by the vanishing polynomial: z1 = z1 * this->zh_poly libfqfft::_polynomial_multiplication( z1_blind_poly, z1_blind_poly, round_zero_out.zh_poly); diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 42f26e15f..184a5d108 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -62,7 +62,8 @@ usrs plonk_usrs_derive_from_secret(const libff::Fr &secret) /// particular circuit i.e. /// /// usrs = -/// srs = (proving_key, verificataion_key) = derive(usrs, circuit_description) +/// srs = (proving_key, verificataion_key) = derive(usrs, +/// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit) From efd9f9bbb1275f29a44513a19db03ace5d570765 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 28 Jun 2022 14:47:32 +0100 Subject: [PATCH 011/154] plonk: fixed formatting with clang-format-11 --- libsnark/zk_proof_systems/plonk/verifier.tcc | 25 ++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index c382b8c72..5f8c014b2 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -302,12 +302,12 @@ step_nine_out_t plonk_verifier::step_nine( preprocessed_input.Q_polys_at_secret_g1[R], preprocessed_input.Q_polys_at_secret_g1[O], preprocessed_input.Q_polys_at_secret_g1[C]}; - std::vector> scalar_elements{proof.a_zeta * proof.b_zeta * - step_four_out.nu, - proof.a_zeta * step_four_out.nu, - proof.b_zeta * step_four_out.nu, - proof.c_zeta * step_four_out.nu, - step_four_out.nu}; + std::vector> scalar_elements{ + proof.a_zeta * proof.b_zeta * step_four_out.nu, + proof.a_zeta * step_four_out.nu, + proof.b_zeta * step_four_out.nu, + proof.c_zeta * step_four_out.nu, + step_four_out.nu}; D1_part[0] = plonk_multi_exp_G1(curve_points, scalar_elements); // compute D1_part[1]: @@ -488,17 +488,18 @@ bool plonk_verifier::step_twelve( const plonk_proof &proof, const srs &srs) { - std::vector> curve_points_lhs{proof.W_zeta_at_secret, - proof.W_zeta_omega_at_secret}; + std::vector> curve_points_lhs{ + proof.W_zeta_at_secret, proof.W_zeta_omega_at_secret}; std::vector> scalar_elements_lhs{Field(1), step_four_out.u}; libff::G1 pairing_first_lhs = plonk_multi_exp_G1(curve_points_lhs, scalar_elements_lhs); libff::G2 pairing_second_lhs = srs.secret_powers_g2[1]; - std::vector> curve_points_rhs{proof.W_zeta_at_secret, - proof.W_zeta_omega_at_secret, - step_ten_out.F1, - step_eleven_out.E1}; + std::vector> curve_points_rhs{ + proof.W_zeta_at_secret, + proof.W_zeta_omega_at_secret, + step_ten_out.F1, + step_eleven_out.E1}; std::vector> scalar_elements_rhs{ // Warning! raise to the power of -1 to check e() * e()^-1 = 1 Field(-1) * step_four_out.zeta, From bfe869cca17021cd7a1dcf12b9a2332dec65ad13 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 28 Jun 2022 14:52:35 +0100 Subject: [PATCH 012/154] plonk: added updated version of libff with support for curve bls12-381 --- depends/libff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libff b/depends/libff index 5f9a4bdd9..6dee67e4a 160000 --- a/depends/libff +++ b/depends/libff @@ -1 +1 @@ -Subproject commit 5f9a4bdd9bea61036b57cfe972354fc97c497457 +Subproject commit 6dee67e4aa3d75200670f2cec8585f37b693f7f2 From 20dadc051eda61a789221631e411af7b51ff1750 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 28 Jun 2022 15:02:43 +0100 Subject: [PATCH 013/154] plonk: replaced all DEBUG guards with DEBUG_PLONK to avoid redeclaration error --- libsnark/zk_proof_systems/plonk/circuit.tcc | 16 +++---- libsnark/zk_proof_systems/plonk/plonk.hpp | 4 +- libsnark/zk_proof_systems/plonk/prover.tcc | 48 +++++++++---------- .../plonk/tests/test_plonk.cpp | 25 +++++----- libsnark/zk_proof_systems/plonk/verifier.tcc | 36 +++++++------- 5 files changed, 66 insertions(+), 63 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 60531cdc1..00f5d9586 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -38,22 +38,22 @@ circuit_t plonk_curcuit_description_from_example( // match against the test vector values circuit.k1 = example.k1; circuit.k2 = example.k2; -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] k1 ", __FILE__, __LINE__); circuit.k1.print(); printf("[%s:%d] k2 ", __FILE__, __LINE__); circuit.k2.print(); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK circuit.num_gates = example.num_gates; // TODO: throw exception -#ifdef DEBUG +#ifdef DEBUG_PLONK // ensure that num_gates is not 0 assert(circuit.num_gates); // ensure num_gates is power of 2 bool b_is_power2 = ((circuit.num_gates & (circuit.num_gates - 1)) == 0); assert(b_is_power2); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK circuit.num_qpolys = example.num_qpolys; @@ -96,26 +96,26 @@ circuit_t plonk_curcuit_description_from_example( plonk_roots_of_unity_omega_to_subgroup_H( circuit.omega_roots, circuit.H_gen); // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] circuit.H_gen\n", __FILE__, __LINE__); print_vector(circuit.H_gen); for (int i = 0; i < (int)circuit.H_gen.size(); ++i) { assert(circuit.H_gen[i] == example.H_gen[i]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // permute circuit.H_gen according to the wire permutation circuit.H_gen_permute.resize(num_hgen * circuit.num_gates, Field(0)); plonk_permute_subgroup_H( circuit.H_gen, wire_permutation, circuit.H_gen_permute); // TODO: write unit test for plonk_permute_subgroup_H -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] circuit.H_gen_permute\n", __FILE__, __LINE__); print_vector(circuit.H_gen_permute); for (size_t i = 0; i < circuit.H_gen_permute.size(); ++i) { assert(circuit.H_gen_permute[i] == example.H_gen_permute[i]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index ee3ca38ad..3d310fb66 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -15,8 +15,8 @@ // enable debug checks. in particular enable comparisons to test // vector values. -#define DEBUG -//#undef DEBUG +#define DEBUG_PLONK +//#undef DEBUG_PLONK /// Declaration of common untility functions for ppzkSNARK proof /// system Plonk. The implementation instantiates the protocol of diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index a490e1ffa..1cb2a6115 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -102,13 +102,13 @@ round_one_out_t plonk_prover::round_one( } // TODO: move to unit test for // plonk_interpolate_polynomial_from_points -#ifdef DEBUG +#ifdef DEBUG_PLONK for (int i = 0; i < nwitness; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, i); print_vector(W_polys[i]); assert(W_polys[i] == example.W_polys[i]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // hard-coded values for the "random" blinding constants from // example circuit @@ -207,11 +207,11 @@ round_two_out_t plonk_prover::round_two( plonk_interpolate_polynomial_from_points(A_vector, A_poly); // TODO: move to unit test for // plonk_interpolate_polynomial_from_points -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] A_poly\n", __FILE__, __LINE__); print_vector(A_poly); assert(A_poly == example.A_poly); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // add blinding polynomial z_1 to the accumulator polynomial A_poly libfqfft::_polynomial_addition(z_poly, z1_blind_poly, A_poly); @@ -445,13 +445,13 @@ round_three_out_t plonk_prover::round_three( t_poly_long, remainder, t_poly_long, round_zero_out.zh_poly); // TODO: move to unit test for round_three() -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); print_vector(t_poly_long); assert(t_poly_long == example.t_poly_long); printf("[%s:%d] remainder\n", __FILE__, __LINE__); print_vector(remainder); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK assert(libfqfft::_is_zero(remainder)); // break this->t_poly_long into three parts: lo, mid, hi, each of degree @@ -468,13 +468,13 @@ round_three_out_t plonk_prover::round_three( t_poly[i] = tmp; } // TODO: move to unit test for round_three() -#ifdef DEBUG +#ifdef DEBUG_PLONK for (int i = 0; i < num_hgen; ++i) { printf("[%s:%d] t_poly[%d]\n", __FILE__, __LINE__, i); print_vector(t_poly[i]); assert(t_poly[i] == example.t_poly[i]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // evaluate each part of t_poly in the secret input t_poly_at_secret_g1.resize(num_hgen); for (int i = 0; i < num_hgen; ++i) { @@ -748,9 +748,9 @@ round_five_out_t plonk_prover::round_five( libfqfft::_polynomial_addition(r_poly, r_poly, r_part[3]); // TODO: move to unit test for compyting r_poly -#ifdef DEBUG +#ifdef DEBUG_PLONK assert(r_poly == example.r_poly); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Evaluate the r-polynomial at zeta. Note: in the reference // implementation, r_zeta is added to the pi-SNARK proof. In the @@ -761,9 +761,9 @@ round_five_out_t plonk_prover::round_five( r_poly.size(), r_poly, round_four_out.zeta); // TODO: move to unit test for compyting r_zeta -#ifdef DEBUG +#ifdef DEBUG_PLONK assert(r_zeta == example.r_zeta); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // W_zeta polynomial is of degree 6 in the random element nu and // hence has 7 terms @@ -916,10 +916,10 @@ round_five_out_t plonk_prover::round_five( assert(libfqfft::_is_zero(remainder)); // TODO: move to unit test for round_five -#ifdef DEBUG +#ifdef DEBUG_PLONK assert(W_zeta == example.W_zeta); assert(W_zeta_omega == example.W_zeta_omega); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Evaluate polynomials W_zeta and W_zeta_omega at the seceret // input @@ -999,7 +999,7 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) plonk_prover::round_one(round_zero_out, witness, srs); // Prover Round 1 output check against test vectors // TODO: move to unit test for round 1 -#ifdef DEBUG +#ifdef DEBUG_PLONK for (int i = 0; i < (int)NUM_HGEN; ++i) { printf("[%s:%d] W_polys_blinded[%d]\n", __FILE__, __LINE__, i); print_vector(round_one_out.W_polys_blinded[i]); @@ -1019,14 +1019,14 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) W_polys_blinded_at_secret_g1_i.Y == example.W_polys_blinded_at_secret_g1[i][1]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); round_two_out_t round_two_out = plonk_prover::round_two(round_zero_out, round_one_out, witness, srs); // Prover Round 2 output check against test vectors // TODO: move to unit test for round 2 -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] z_poly\n", __FILE__, __LINE__); print_vector(round_two_out.z_poly); assert(round_two_out.z_poly == example.z_poly); @@ -1037,14 +1037,14 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) z_poly_at_secret_g1_aff.to_affine_coordinates(); assert(z_poly_at_secret_g1_aff.X == example.z_poly_at_secret_g1[0]); assert(z_poly_at_secret_g1_aff.Y == example.z_poly_at_secret_g1[1]); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); round_three_out_t round_three_out = plonk_prover::round_three( round_zero_out, round_one_out, round_two_out, srs); // Prover Round 3 output check against test vectors // TODO: move to unit test for round 3 -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); for (int i = 0; i < (int)NUM_HGEN; ++i) { printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); @@ -1055,14 +1055,14 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) assert(t_poly_at_secret_g1_i.X == example.t_poly_at_secret_g1[i][0]); assert(t_poly_at_secret_g1_i.Y == example.t_poly_at_secret_g1[i][1]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); round_four_out_t round_four_out = plonk_prover::round_four(round_one_out, round_three_out, srs); // Prover Round 4 output check against test vectors // TODO: move to unit test for round 4 -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); printf("a_zeta "); round_four_out.a_zeta.print(); @@ -1085,7 +1085,7 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) printf("z_poly_xomega_zeta "); round_four_out.z_poly_xomega_zeta.print(); assert(round_four_out.z_poly_xomega_zeta == example.z_poly_xomega_zeta); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); round_five_out_t round_five_out = plonk_prover::round_five( @@ -1097,7 +1097,7 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) srs); // Prover Round 5 output check against test vectors // TODO: move to unit test for round 5 -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); printf("r_zeta "); round_five_out.r_zeta.print(); @@ -1115,7 +1115,7 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) W_zeta_omega_at_secret_aff.to_affine_coordinates(); assert(W_zeta_omega_at_secret_aff.X == example.W_zeta_omega_at_secret[0]); assert(W_zeta_omega_at_secret_aff.Y == example.W_zeta_omega_at_secret[1]); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // construct proof plonk_proof proof( diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 3293b0883..3fd1359d6 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -134,10 +134,10 @@ void test_verify_invalid_proof( template void test_plonk() { -#ifndef DEBUG - printf("[%s:%d] WARNING! DEBUG info disabled.\n", __FILE__, __LINE__); +#ifndef DEBUG_PLONK + printf("[%s:%d] WARNING! DEBUG_PLONK info disabled.\n", __FILE__, __LINE__); // assert(0); -#endif // #ifndef DEBUG +#endif // #ifndef DEBUG_PLONK // Execute all tests for the given curve. ppT::init_public_params(); @@ -153,10 +153,10 @@ template void test_plonk() // random hidden element secret (toxic waste). we fix it to a // constant in order to match against the test vectors Field secret = example.secret; -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] secret ", __FILE__, __LINE__); secret.print(); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK printf("[%s:%d] SRS...\n", __FILE__, __LINE__); // --- USRS --- @@ -243,15 +243,18 @@ template void test_plonk() bool b_valid_proof = verifier.verify_proof(proof, srs); ASSERT_TRUE(b_valid_proof); // assert that proof verification fails when the proof is - // manipulated. must be executed when DEBUG is not defined to + // manipulated. must be executed when DEBUG_PLONK is not defined to // disable certain assert-s that may fail before the verify // invalid proof test -#ifndef DEBUG +#ifndef DEBUG_PLONK test_verify_invalid_proof(proof, srs); -#endif // #ifndef DEBUG -#ifndef DEBUG - printf("[%s:%d] WARNING! DEBUG info was disabled.\n", __FILE__, __LINE__); -#endif // #ifndef DEBUG +#endif // #ifndef DEBUG_PLONK +#ifndef DEBUG_PLONK + printf( + "[%s:%d] WARNING! DEBUG_PLONK info was disabled.\n", + __FILE__, + __LINE__); +#endif // #ifndef DEBUG_PLONK printf("[%s:%d] Test OK\n", __FILE__, __LINE__); // end } diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 5f8c014b2..9ae1ccb32 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -513,7 +513,7 @@ bool plonk_verifier::step_twelve( libff::G2 pairing_second_rhs = srs.secret_powers_g2[0]; // TODO: move to unit test for step_twelve -#ifdef DEBUG +#ifdef DEBUG_PLONK // load test vectors for debug plonk_example example; printf("[%s:%d] pairing_first_lhs\n", __FILE__, __LINE__); @@ -529,7 +529,7 @@ bool plonk_verifier::step_twelve( pairing_first_rhs_aff.to_affine_coordinates(); assert(pairing_first_rhs_aff.X == example.pairing_first_rhs[0]); assert(pairing_first_rhs_aff.Y == example.pairing_first_rhs[1]); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK const libff::G1_precomp _A = ppT::precompute_G1(pairing_first_lhs); const libff::G2_precomp _B = ppT::precompute_G2(pairing_second_lhs); @@ -569,7 +569,7 @@ bool plonk_verifier::verify_proof( plonk_verifier::preprocessed_input(srs); // TODO: move to unit test for verify_proof -#ifdef DEBUG +#ifdef DEBUG_PLONK // load test vector values form example for debug plonk_example example; for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { @@ -590,7 +590,7 @@ bool plonk_verifier::verify_proof( assert(S_poly_at_secret_g1_i.X == example.S_polys_at_secret_g1[i][0]); assert(S_poly_at_secret_g1_i.Y == example.S_polys_at_secret_g1[i][1]); } -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 1: validate that elements belong to group G1 // Verifier Step 2: validate that elements belong to scalar field Fr @@ -608,80 +608,80 @@ bool plonk_verifier::verify_proof( const step_five_out_t step_five_out = this->step_five(step_four_out, srs); // TODO: uni test for step_five -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); step_five_out.zh_zeta.print(); assert(step_five_out.zh_zeta == example.zh_zeta); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) // Note: the paper counts the L-polynomials from 1; we count from 0 const step_six_out_t step_six_out = this->step_six(step_four_out, srs); // TODO: uni test for step_six -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("L_0_zeta "); step_six_out.L_0_zeta.print(); assert(step_six_out.L_0_zeta == example.L_0_zeta); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 7: compute public input polynomial evaluation PI(zeta) const step_seven_out_t step_seven_out = this->step_seven(step_four_out, srs); // TODO: uni test for step_seven -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("PI_zeta "); step_seven_out.PI_zeta.print(); assert(step_seven_out.PI_zeta == example.PI_zeta); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 8: compute quotient polynomial evaluation // r'(zeta) = r(zeta) - r0, where r0 is a constant term const step_eight_out_t step_eight_out = this->step_eight( step_four_out, step_five_out, step_six_out, step_seven_out, proof); // TODO: uni test for step_eight -#ifdef DEBUG +#ifdef DEBUG_PLONK assert(step_eight_out.r_prime_zeta == example.r_prime_zeta); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 9: compute first part of batched polynomial // commitment [D]_1 step_nine_out_t step_nine_out = this->step_nine( step_four_out, step_six_out, proof, preprocessed_input, srs); // TODO: uni test for step_nine -#ifdef DEBUG +#ifdef DEBUG_PLONK step_nine_out.D1.print(); libff::G1 D1_aff(step_nine_out.D1); D1_aff.to_affine_coordinates(); assert(D1_aff.X == example.D1[0]); assert(D1_aff.Y == example.D1[1]); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 10: compute full batched polynomial commitment // [F]_1 step_ten_out_t step_ten_out = this->step_ten( step_four_out, step_nine_out, proof, preprocessed_input, srs); // TODO: uni test for step_ten -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] F1\n", __FILE__, __LINE__); step_ten_out.F1.print(); libff::G1 F1_aff(step_ten_out.F1); F1_aff.to_affine_coordinates(); assert(F1_aff.X == example.F1[0]); assert(F1_aff.Y == example.F1[1]); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 11: compute group-encoded batch evaluation [E]_1 const step_eleven_out_t step_eleven_out = this->step_eleven(step_four_out, step_eight_out, proof); // TODO: uni test for step_eleven -#ifdef DEBUG +#ifdef DEBUG_PLONK printf("[%s:%d] E1\n", __FILE__, __LINE__); step_eleven_out.E1.print(); libff::G1 E1_aff(step_eleven_out.E1); E1_aff.to_affine_coordinates(); assert(E1_aff.X == example.E1[0]); assert(E1_aff.Y == example.E1[1]); -#endif // #ifdef DEBUG +#endif // #ifdef DEBUG_PLONK // Verifier Step 12: batch validate all evaluations (check // pairing) From 357dffca6c0367ed6e9aa33377fba212f974b313 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 28 Jun 2022 15:08:50 +0100 Subject: [PATCH 014/154] plonk: fixed unused variable compilation error --- libsnark/zk_proof_systems/plonk/circuit.tcc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 00f5d9586..b5692181f 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -51,8 +51,7 @@ circuit_t plonk_curcuit_description_from_example( // ensure that num_gates is not 0 assert(circuit.num_gates); // ensure num_gates is power of 2 - bool b_is_power2 = ((circuit.num_gates & (circuit.num_gates - 1)) == 0); - assert(b_is_power2); + assert((circuit.num_gates & (circuit.num_gates - 1)) == 0); #endif // #ifdef DEBUG_PLONK circuit.num_qpolys = example.num_qpolys; From 75e79f47f95fba1077b3d2b88f79512c9e3e8584 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 29 Jun 2022 13:54:02 +0100 Subject: [PATCH 015/154] plonk: removed unused Lagrange basis input parameter from function plonk_compute_public_input_polynomial and plonk_interpolate_over_lagrange_basis --- libsnark/zk_proof_systems/plonk/circuit.tcc | 5 ++--- libsnark/zk_proof_systems/plonk/plonk.hpp | 1 - libsnark/zk_proof_systems/plonk/plonk.tcc | 7 +------ 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index b5692181f..0bfd8eb00 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -69,8 +69,7 @@ circuit_t plonk_curcuit_description_from_example( // compute public input (PI) polynomial std::vector PI_points(circuit.num_gates, Field(0)); PI_points[PI_index] = Field(-PI_value); - plonk_compute_public_input_polynomial( - PI_points, circuit.L_basis, circuit.PI_poly); + plonk_compute_public_input_polynomial(PI_points, circuit.PI_poly); // compute the selector polynomials (q-polynomials) from the // transposed gates matrix over the Lagrange basis q_poly = \sum_i @@ -79,7 +78,7 @@ circuit_t plonk_curcuit_description_from_example( circuit.Q_polys.resize( circuit.num_qpolys, polynomial(circuit.num_gates)); plonk_compute_selector_polynomials( - gates_matrix_transpose, circuit.L_basis, circuit.Q_polys); + gates_matrix_transpose, circuit.Q_polys); // number of generators for H, Hk1, Hk2 int num_hgen = NUM_HGEN; diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index 3d310fb66..e58e5a19b 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -133,7 +133,6 @@ void plonk_interpolate_over_lagrange_basis( template void plonk_compute_selector_polynomials( const std::vector> &gates_matrix_transpose, - const std::vector> &L_basis, std::vector> &Q_polys); /// output: omega[0] are the n roots of unity, omega[1] are diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index 4d2a71ae8..633aeac95 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -160,12 +160,10 @@ void plonk_interpolate_over_lagrange_basis( template void plonk_compute_selector_polynomials( const std::vector> &gates_matrix_transpose, - const std::vector> &L_basis, std::vector> &Q_polys) { assert(gates_matrix_transpose.size() == Q_polys.size()); assert(gates_matrix_transpose[0].size() == Q_polys[0].size()); - assert(gates_matrix_transpose[0].size() == L_basis.size()); size_t num_qpolys = gates_matrix_transpose.size(); for (size_t i = 0; i < num_qpolys; ++i) { std::vector q_vec = gates_matrix_transpose[i]; @@ -175,11 +173,8 @@ void plonk_compute_selector_polynomials( template void plonk_compute_public_input_polynomial( - const std::vector &PI_points, - const std::vector> &L_basis, - polynomial &PI_poly) + const std::vector &PI_points, polynomial &PI_poly) { - assert(PI_points.size() == L_basis.size()); plonk_interpolate_polynomial_from_points(PI_points, PI_poly); }; From 056db0b9a16d8babef970527281f0373952ae5f1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 30 Jun 2022 14:28:32 +0100 Subject: [PATCH 016/154] plonk: changed include-s of local files to be added with "" rather than <> --- libsnark/zk_proof_systems/plonk/circuit.hpp | 2 +- libsnark/zk_proof_systems/plonk/plonk.hpp | 3 ++- libsnark/zk_proof_systems/plonk/prover.hpp | 2 +- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 7 ++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index 9fada7254..97d0e6741 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -9,7 +9,7 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ -#include +#include "libsnark/zk_proof_systems/plonk/plonk.hpp" /// Declaration of Common Preprocessed Input interfaces for ppzkSNARK /// proof system Plonk. diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index e58e5a19b..d157b4bb7 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -9,8 +9,9 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ +#include "libsnark/zk_proof_systems/plonk/tests/example.hpp" + #include -#include #include // enable debug checks. in particular enable comparisons to test diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index afedd3ee9..55c232016 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -9,7 +9,7 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_HPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_HPP_ -#include +#include "libsnark/zk_proof_systems/plonk/srs.hpp" /// Declaration of Prover interfaces for ppzkSNARK proof system Plonk.This /// includes: diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 3fd1359d6..dece35ba2 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -6,6 +6,10 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "libsnark/zk_proof_systems/plonk/circuit.hpp" +#include "libsnark/zk_proof_systems/plonk/prover.hpp" +#include "libsnark/zk_proof_systems/plonk/verifier.hpp" + #include #include #include @@ -14,9 +18,6 @@ #include #include #include -#include -#include -#include /// Test program that exercises the Plonk protocol (first setup, then /// prover, then verifier) on a synthetic R1CS instance. From 681429915ec9ecc753716785c06c8dc417fcb5d5 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 30 Jun 2022 14:48:32 +0100 Subject: [PATCH 017/154] plonk: moved libff and libfqfft include headers from test_plonk.cpp to example.hpp --- libsnark/zk_proof_systems/plonk/tests/example.hpp | 5 +++++ libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index cd4b040f6..39fb15be6 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -27,6 +27,11 @@ /// post from 22 Sep 2019, /// https://vitalik.ca/general/2019/09/22/plonk.html +#include +#include +#include +#include + namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index dece35ba2..9580871e6 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -14,10 +14,6 @@ #include #include #include -#include -#include -#include -#include /// Test program that exercises the Plonk protocol (first setup, then /// prover, then verifier) on a synthetic R1CS instance. From 43517b7ccb81b6c722684203a4f68414490284e1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 30 Jun 2022 14:56:21 +0100 Subject: [PATCH 018/154] plonk: removed local alias of polynomial and replaced with the global definition by including polynomial.hpp --- libsnark/zk_proof_systems/plonk/plonk.hpp | 2 -- libsnark/zk_proof_systems/plonk/tests/example.hpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index d157b4bb7..18e15c3db 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -44,8 +44,6 @@ enum Q_polys_id { L, R, M, O, C }; enum t_polys_id { lo, mid, hi }; enum omega_id { base, base_k1, base_k2 }; -template using polynomial = std::vector; - /***************************** Main algorithms *******************************/ /// print the elements of a vector diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 39fb15be6..fb652e580 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace libsnark { @@ -108,7 +109,6 @@ template class plonk_example public: using Field = libff::Fr; using BaseField = libff::Fq; - template using polynomial = std::vector; /// Circuit data From 514c3e6bbcb062245faf0a3d986e8313c6d2597c Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 12:12:33 +0100 Subject: [PATCH 019/154] plonk: removed the template parameter ppT from the plonk_example class as this class is specific to the BLS12_381 curve. Added an exception check for ppT == bls12_381_pp before each creation of a new plonk_example object. --- libsnark/zk_proof_systems/plonk/circuit.hpp | 2 +- libsnark/zk_proof_systems/plonk/circuit.tcc | 13 ++++- libsnark/zk_proof_systems/plonk/prover.tcc | 57 +++++++++++++++++-- .../zk_proof_systems/plonk/tests/example.hpp | 7 ++- .../zk_proof_systems/plonk/tests/example.tcc | 18 +++++- .../plonk/tests/test_plonk.cpp | 17 +++++- libsnark/zk_proof_systems/plonk/verifier.tcc | 33 ++++++++++- 7 files changed, 128 insertions(+), 19 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index 97d0e6741..d4c45ba23 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -59,7 +59,7 @@ template struct circuit_t { template circuit_t plonk_curcuit_description_from_example( - const plonk_example example); + const plonk_example example); } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 0bfd8eb00..ad289e8b9 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -18,10 +18,19 @@ namespace libsnark /// Compute or fill-in ciruit specific data from example. template circuit_t plonk_curcuit_description_from_example( - const plonk_example example) + const plonk_example example) { - using Field = libff::Fr; + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + using Field = libff::Fr; circuit_t circuit; // public input (PI) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 1cb2a6115..112812616 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -81,8 +81,17 @@ round_one_out_t plonk_prover::round_one( using Field = libff::Fr; int nwitness = 3; + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve. TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // initialize hard-coded values from example circuit - plonk_example example; + plonk_example example; // output from round 1 std::vector> blind_scalars; @@ -168,7 +177,7 @@ round_two_out_t plonk_prover::round_two( { using Field = libff::Fr; // initialize hard-coded values from example circuit - plonk_example example; + plonk_example example; // output from round 2 libff::Fr beta; @@ -259,8 +268,17 @@ round_three_out_t plonk_prover::round_three( using Field = libff::Fr; int num_hgen = NUM_HGEN; + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // initialize hard-coded values from example circuit - plonk_example example; + plonk_example example; // output from round 3 libff::Fr alpha; @@ -531,8 +549,17 @@ round_four_out_t plonk_prover::round_four( const srs &srs) { using Field = libff::Fr; + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // initialize hard-coded values from example circuit - plonk_example example; + plonk_example example; // output from round 4 libff::Fr zeta; @@ -637,8 +664,17 @@ round_five_out_t plonk_prover::round_five( using Field = libff::Fr; polynomial remainder; + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // initialize hard-coded values from example circuit - plonk_example example; + plonk_example example; // output from round 5 libff::Fr nu; @@ -985,8 +1021,17 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) { using Field = libff::Fr; + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // initialize hard-coded values from example circuit - plonk_example example; + plonk_example example; std::vector witness = example.witness; // Prover Round 0 (initialization) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index fb652e580..6d79fa554 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -104,11 +104,12 @@ namespace libsnark /// q_O = [-1, -1, -1, 0, 0, 0, 0, 0] /// q_M = [ 1, 1, 0, 0, 0, -1, 0, 0] /// q_C = [ 0, 0, 0, -1, 0, 0, 0, 0] -template class plonk_example +// template class plonk_example +class plonk_example { public: - using Field = libff::Fr; - using BaseField = libff::Fq; + using Field = libff::Fr; + using BaseField = libff::Fq; /// Circuit data diff --git a/libsnark/zk_proof_systems/plonk/tests/example.tcc b/libsnark/zk_proof_systems/plonk/tests/example.tcc index d6f9a9fe6..a9dee03d2 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.tcc +++ b/libsnark/zk_proof_systems/plonk/tests/example.tcc @@ -14,10 +14,22 @@ namespace libsnark { -template plonk_example::plonk_example() +// the example class is defined specifically for the BLS12-381 +// curve. This function checks that the template parameter ppT indeed +// corresponds to the bls12_381 curev i.e. is equal to +// libff::bls12_381_pp +template void plonk_exception_assert_curve_bls12_381() { - using Field = libff::Fr; - using BaseField = libff::Fq; + const bool b_bls12_381 = std::is_same::value; + if (!b_bls12_381) { + throw std::domain_error("Curve is not BLS12-381"); + } +} + +plonk_example::plonk_example() +{ + using Field = libff::Fr; + using BaseField = libff::Fq; // Circuit data diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 9580871e6..bdc8f9191 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -136,14 +136,29 @@ template void test_plonk() // assert(0); #endif // #ifndef DEBUG_PLONK + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + // Execute all tests for the given curve. ppT::init_public_params(); using Field = libff::Fr; // --- TEST VECTORS --- + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // load test vector values from example circuit - plonk_example example; + plonk_example example; // --- SETUP --- printf("[%s:%d] Setup...\n", __FILE__, __LINE__); diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 9ae1ccb32..160d155da 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -87,8 +87,17 @@ template void plonk_verifier::step_three(const srs &srs) /// transcript template step_four_out_t plonk_verifier::step_four() { + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // load challenges from example for debug - plonk_example example; + plonk_example example; // step 4 output libff::Fr beta; libff::Fr gamma; @@ -514,8 +523,17 @@ bool plonk_verifier::step_twelve( // TODO: move to unit test for step_twelve #ifdef DEBUG_PLONK + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // load test vectors for debug - plonk_example example; + plonk_example example; printf("[%s:%d] pairing_first_lhs\n", __FILE__, __LINE__); pairing_first_lhs.print(); libff::G1 pairing_first_lhs_aff(pairing_first_lhs); @@ -570,8 +588,17 @@ bool plonk_verifier::verify_proof( // TODO: move to unit test for verify_proof #ifdef DEBUG_PLONK + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // load test vector values form example for debug - plonk_example example; + plonk_example example; for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { printf("srs.Q_polys_at_secret_G1[%d] \n", i); preprocessed_input.Q_polys_at_secret_g1[i].print(); From 00bff4f7dc15e43ad6213b69b588de526ab1fee4 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 13:13:55 +0100 Subject: [PATCH 020/154] plonk: added missing #include to polynomial.hpp and included polynomial.hpp with "" rather than <> in plonk --- libsnark/common/data_structures/polynomial.hpp | 2 ++ libsnark/zk_proof_systems/plonk/tests/example.hpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libsnark/common/data_structures/polynomial.hpp b/libsnark/common/data_structures/polynomial.hpp index 2143b36b4..d1984fc87 100644 --- a/libsnark/common/data_structures/polynomial.hpp +++ b/libsnark/common/data_structures/polynomial.hpp @@ -9,6 +9,8 @@ #ifndef __LIBSNARK_COMMON_DATA_STRUCTURES_POLYNOMIAL_HPP__ #define __LIBSNARK_COMMON_DATA_STRUCTURES_POLYNOMIAL_HPP__ +#include + namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 6d79fa554..643c090a0 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -27,11 +27,12 @@ /// post from 22 Sep 2019, /// https://vitalik.ca/general/2019/09/22/plonk.html +#include "libsnark/common/data_structures/polynomial.hpp" + #include #include #include #include -#include namespace libsnark { From 350f500cb90589aff97a111df175349db78dd4e2 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 13:21:22 +0100 Subject: [PATCH 021/154] plonk: renamed NUM_HGEN to NUM_HSETS and fixed corresponding comment --- libsnark/zk_proof_systems/plonk/circuit.tcc | 2 +- libsnark/zk_proof_systems/plonk/plonk.hpp | 5 +++-- libsnark/zk_proof_systems/plonk/plonk.tcc | 10 +++++----- libsnark/zk_proof_systems/plonk/prover.tcc | 8 ++++---- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 4 ++-- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index ad289e8b9..9ca988620 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -90,7 +90,7 @@ circuit_t plonk_curcuit_description_from_example( gates_matrix_transpose, circuit.Q_polys); // number of generators for H, Hk1, Hk2 - int num_hgen = NUM_HGEN; + int num_hgen = NUM_HSETS; // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, // omega[2] are omega[0]*k2 // std::vector> omega; diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index 18e15c3db..3347d4a3b 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -33,8 +33,9 @@ /// maximum degree of the encoded monomials in the usrs const size_t MAX_DEGREE = 254; -/// number of generators for H, Hk1, Hk2 -const size_t NUM_HGEN = 3; +/// number of H-sets: H, Hk1 and Hk2, where H is a subgroup, while Hk1 +/// and Hk2 are cosets +const size_t NUM_HSETS = 3; namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index 633aeac95..695fd20bb 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -186,7 +186,7 @@ template void plonk_compute_roots_of_unity_omega( const FieldT k1, const FieldT k2, std::vector> &omega) { - assert(omega.size() == NUM_HGEN); + assert(omega.size() == NUM_HSETS); assert(omega[0].size() > 0); size_t num_gates = omega[0].size(); // Get the n-th root of unity omega in Fq (n=8 is the number of @@ -215,7 +215,7 @@ template void plonk_roots_of_unity_omega_to_subgroup_H( const std::vector> &omega, std::vector &H_gen) { - assert(omega.size() == NUM_HGEN); + assert(omega.size() == NUM_HSETS); assert(omega[0].size() > 0); std::copy(omega[base].begin(), omega[base].end(), back_inserter(H_gen)); std::copy( @@ -248,10 +248,10 @@ void plonk_compute_permutation_polynomials( const size_t num_gates, std::vector> &S_polys) { - assert(S_polys.size() == NUM_HGEN); + assert(S_polys.size() == NUM_HSETS); assert(S_polys[0].size() == num_gates); - assert(H_gen_permute.size() == (NUM_HGEN * num_gates)); - for (size_t i = 0; i < NUM_HGEN; ++i) { + assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + for (size_t i = 0; i < NUM_HSETS; ++i) { typename std::vector::const_iterator begin = H_gen_permute.begin() + (i * num_gates); typename std::vector::const_iterator end = diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 112812616..99e423fd8 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -266,7 +266,7 @@ round_three_out_t plonk_prover::round_three( const srs &srs) { using Field = libff::Fr; - int num_hgen = NUM_HGEN; + int num_hgen = NUM_HSETS; // the example class is defined specifically for the BLS12-381 // curve, so make sure we are using this curve TODO: remove when @@ -1045,13 +1045,13 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) // Prover Round 1 output check against test vectors // TODO: move to unit test for round 1 #ifdef DEBUG_PLONK - for (int i = 0; i < (int)NUM_HGEN; ++i) { + for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] W_polys_blinded[%d]\n", __FILE__, __LINE__, i); print_vector(round_one_out.W_polys_blinded[i]); assert(round_one_out.W_polys_blinded[i] == example.W_polys_blinded[i]); } printf("[%s:%d] Output from Round 1\n", __FILE__, __LINE__); - for (int i = 0; i < (int)NUM_HGEN; ++i) { + for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("W_polys_at_secret_g1[%d]\n", i); round_one_out.W_polys_blinded_at_secret_g1[i].print(); libff::G1 W_polys_blinded_at_secret_g1_i( @@ -1091,7 +1091,7 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) // TODO: move to unit test for round 3 #ifdef DEBUG_PLONK printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); - for (int i = 0; i < (int)NUM_HGEN; ++i) { + for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); round_three_out.t_poly_at_secret_g1[i].print(); libff::G1 t_poly_at_secret_g1_i( diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index bdc8f9191..ffc87f00e 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -210,7 +210,7 @@ template void test_plonk() ASSERT_EQ(proof.S_1_zeta, example.S_1_zeta); ASSERT_EQ(proof.z_poly_xomega_zeta, example.z_poly_xomega_zeta); ASSERT_EQ(proof.r_zeta, example.r_zeta); - for (int i = 0; i < (int)NUM_HGEN; ++i) { + for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("W_polys_at_secret_g1[%d]\n", i); proof.W_polys_blinded_at_secret_g1[i].print(); libff::G1 W_polys_blinded_at_secret_g1_i( @@ -228,7 +228,7 @@ template void test_plonk() z_poly_at_secret_g1_aff.to_affine_coordinates(); ASSERT_EQ(z_poly_at_secret_g1_aff.X, example.z_poly_at_secret_g1[0]); ASSERT_EQ(z_poly_at_secret_g1_aff.Y, example.z_poly_at_secret_g1[1]); - for (int i = 0; i < (int)NUM_HGEN; ++i) { + for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); proof.t_poly_at_secret_g1[i].print(); libff::G1 t_poly_at_secret_g1_i(proof.t_poly_at_secret_g1[i]); From 4bd62440be69e4e617a098912b11995d9dbda712 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 13:30:30 +0100 Subject: [PATCH 022/154] plonk: removed an extra copy of f_points in plonk_interpolate_polynomial_from_points for improved efficiency --- libsnark/zk_proof_systems/plonk/plonk.tcc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index 695fd20bb..cd300e6b2 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -86,9 +86,8 @@ void plonk_interpolate_polynomial_from_points( size_t npoints = f_points.size(); std::shared_ptr> domain = libfqfft::get_evaluation_domain(npoints); - polynomial u = f_points; - domain->iFFT(u); - f_poly = u; + f_poly = f_points; + domain->iFFT(f_poly); } /// Interpolate a polynomial from a set of points over Lagrange basis From f65b04876a9196e6ffe73cf27800c922f352f9d6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 13:44:36 +0100 Subject: [PATCH 023/154] plonk: added empty line between all class members for improved readability --- libsnark/zk_proof_systems/plonk/circuit.hpp | 10 +++++ libsnark/zk_proof_systems/plonk/prover.hpp | 38 +++++++++++++++++++ libsnark/zk_proof_systems/plonk/srs.hpp | 10 +++++ .../zk_proof_systems/plonk/tests/example.hpp | 38 +++++++++++++++++++ libsnark/zk_proof_systems/plonk/verifier.hpp | 12 ++++++ 5 files changed, 108 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index d4c45ba23..de29d0f29 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -30,28 +30,38 @@ namespace libsnark /// Plonk circuit-specific data template struct circuit_t { using Field = libff::Fr; + /// number of gates / constraints size_t num_gates; + /// number of selector polynomials (q-polynomials) (= 5 in the /// vanilla Plonk proposal [GWC19]) size_t num_qpolys; + /// Lagrange basis std::vector> L_basis; + /// Public input polynomial polynomial PI_poly; + /// Circuit selector polynomials (Q-polynomials) std::vector> Q_polys; + /// Permutation polynomials S_sigma_1, S_sigma_2, S_sigma_2 (see /// [GWC19], Sect. 8.1) std::vector> S_polys; + /// omega[0] are the n roots of unity, omega[1] are omega[0]*k1, /// omega[2] are omega[0]*k2 std::vector> omega_roots; + /// H_gen contains the generators of H, k1 H and k2 H in one place /// ie. omega, omega_k1 and omega_k2 std::vector H_gen; + /// H_gen permuted according to the wire permutation std::vector H_gen_permute; + /// constants for H, k1 H, k2 H libff::Fr k1; libff::Fr k2; diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 55c232016..75740d958 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -44,22 +44,29 @@ template class plonk_proof /// [a]_1, [b]_1, [c]_1 std::vector> W_polys_blinded_at_secret_g1; + /// [z]_1, libff::G1 z_poly_at_secret_g1; + /// [t_lo]_1, [t_mi]_1, [t_hi]_1 std::vector> t_poly_at_secret_g1; + /// \bar{a}, \bar{b}, \bar{c}, Field a_zeta; Field b_zeta; Field c_zeta; + /// \bar{S_sigma1}, \bar{S_sigma2}, Field S_0_zeta; Field S_1_zeta; + /// \bar{z_w} Field z_poly_xomega_zeta; + /// [W_zeta]_1, [W_{zeta omega_roots}]_1 libff::G1 W_zeta_at_secret; libff::G1 W_zeta_omega_at_secret; + /// r_zeta (*) Field r_zeta; @@ -94,12 +101,16 @@ template class plonk_proof /// Prover round 0 output template struct round_zero_out_t { + /// - zh_poly: vanishing polynomial Zh (from round 0) std::vector> zh_poly; + /// - null_poly: 0 polynomial (from round 0) polynomial> null_poly; + /// - neg_one_poly: -1 polynomial (from round 0) polynomial> neg_one_poly; + /// stuct constructor round_zero_out_t( const std::vector> &&zh_poly, @@ -112,18 +123,23 @@ template struct round_zero_out_t { /// Prover round 1 output template struct round_one_out_t { + /// - blind_scalars: blinding scalars b1, b2, ..., b9 (only /// b1-b6 used in round 1) std::vector> blind_scalars; + /// - W_polys: witness polynomials (Lagrange interpolation of the /// witness values) std::vector>> W_polys; + /// - W_polys_blinded: blinded witness polynomials std::vector>> W_polys_blinded; + /// - W_polys_blinded_at_secret_g1: the blinded witness polynomials /// evaluated at the secret input denoted [a]_1, [b]_1, [c]_1 in /// [GWC19] std::vector> W_polys_blinded_at_secret_g1; + /// stuct constructor round_one_out_t( const std::vector> &&blind_scalars, @@ -140,15 +156,20 @@ template struct round_one_out_t { /// Prover round 2 output template struct round_two_out_t { + /// - beta: permutation challenge -- hash of transcript libff::Fr beta; + /// - gamma: permutation challenge -- hash of transcript libff::Fr gamma; + /// - z_poly: blinded accumulator poly z(x) polynomial> z_poly; + /// - z_poly_at_secret_g1: blinded accumulator poly z(x) evaluated at /// secret libff::G1 z_poly_at_secret_g1; + /// stuct constructor round_two_out_t( libff::Fr &&beta, @@ -165,19 +186,25 @@ template struct round_two_out_t { /// Prover round 3 output template struct round_three_out_t { + /// - alpha: quotient challenge -- hash of transcript libff::Fr alpha; + /// - z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted by w std::vector> z_poly_xomega; + /// - t_poly: t(x) divided in three parts t(x) = t_lo(x) + t_mid(x) x^n /// + t_hi(x) x^{2n} std::vector>> t_poly; + /// - t_poly_long: the quotient polynomial t(x) (see Round 3, pp28 /// [GWC19]) polynomial> t_poly_long; + /// - t_poly_at_secret_g1: t(x) evaluated at the secret input zeta /// i.e. t(zeta) std::vector> t_poly_at_secret_g1; + /// stuct constructor round_three_out_t( libff::Fr &&alpha, @@ -196,22 +223,27 @@ template struct round_three_out_t { /// Prover round 4 output template struct round_four_out_t { + /// - zeta: evaluation challenge -- hash of transcript libff::Fr zeta; + /// - a_zeta, b_zeta, c_zeta: the blinded witness polynomials a(x), /// b(x), c(x) (denoted by W_polys_blinded[] output from Round 1) /// evaluated at x=zeta i.e. a(z), b(z), c(z) libff::Fr a_zeta; libff::Fr b_zeta; libff::Fr c_zeta; + /// - S_0_zeta, S_1_zeta: the permutation polynomials S_sigma_1(x), /// S_sigma_2(x) from the common preprocessed input (see [GWC19], /// Sect. 8.1) evaluated at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) libff::Fr S_0_zeta; libff::Fr S_1_zeta; + /// - z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) shifted by w /// (output from Round 3) evaluated at x=zeta i.e. z(zeta*w) libff::Fr z_poly_xomega_zeta; + /// - t_zeta: the quotient polynomial t(x) output from Round 3, see /// pp28 [GWC19]) evaluated at x=zeta i.e. t(z). IMPORTANT! the /// original Plonk proposal [GWC19] does not output this parameter @@ -243,20 +275,26 @@ template struct round_four_out_t { /// Prover round 5 output template struct round_five_out_t { + /// - nu: opening challenge -- hash of transcript (denoted by v in /// [GWC19]) libff::Fr nu; + /// - r_zeta: linearisation polynomial r(x) evaluated at x=zeta /// ie. r(zeta) libff::Fr r_zeta; + /// - W_zeta_at_secret: commitment to opening proof polynomial /// W_zeta(x) at secert input i.e. [W_zeta(secret)]_1 libff::G1 W_zeta_at_secret; + /// - W_zeta_omega_at_secret: commitment to opening proof polynomial /// W_{zeta omega}(x) at secert input i.e. [W_{zeta omega}(secret)]_1 libff::G1 W_zeta_omega_at_secret; + /// - u: multipoint evaluation challenge -- hash of transcript libff::Fr u; + /// struct constructor round_five_out_t( libff::Fr &&nu, diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index e86769491..2c585cafb 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -75,29 +75,39 @@ template class srs { public: using Field = libff::Fr; + /// number of gates in the analyzed circuit, denoted by "n" in /// [GWC19] size_t num_gates; + /// number of selector polynomials (q-polynomials) (= 5 in the /// vanilla Plonk proposal [GWC19]) size_t num_qpolys; + /// Lagrange basis std::vector> L_basis; + /// Public input polynomial polynomial PI_poly; + /// Circuit selector polynomials (Q-polynomials) std::vector> Q_polys; + /// Permutation polynomials S_sigma_1, S_sigma_2, S_sigma_2 (see /// [GWC19], Sect. 8.1) std::vector> S_polys; + /// omega[0] are the n roots of unity, omega[1] are omega[0]*k1, /// omega[2] are omega[0]*k2 std::vector> omega_roots; + /// H_gen contains the generators of H, k1 H and k2 H in one place /// ie. omega, omega_k1 and omega_k2 std::vector H_gen; + /// H_gen permuted according to the wire permutation std::vector H_gen_permute; + /// constants for H, k1 H, k2 H libff::Fr k1; libff::Fr k2; diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 643c090a0..83251fc99 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -143,6 +143,7 @@ class plonk_example /// public input (PI) Field public_input; + /// index of the row of the PI in the non-transposed gates_matrix size_t public_input_index; @@ -159,6 +160,7 @@ class plonk_example /// witness polynomials. k can be random, but we fix it for debug /// to match against the test vector values Field k1; + /// Similarly, k2 can be random, but we fix it to match the test /// vectors Field k2; @@ -166,18 +168,23 @@ class plonk_example /// H_gen contains the generators of H, k1 H and K2 H in one place /// ie. omega, omega_k1 and omega_k2 std::vector H_gen; + /// H_gen permuted according to the wire permutation std::vector H_gen_permute; + /// random hidden element secret (toxic waste). we fix it to a /// constant in order to match against the test vectors Field secret; /// powers of secret times G1: 1*G1, secret^1*G1, secret^2*G1, ... std::vector> secret_powers_g1; + /// powers of secret times G2: 1*G2, secret^1*G2 std::vector> secret_powers_g2; + /// blinding scalars b1, b2, ..., b9. random but fixed to match /// the python test vectors std::vector prover_blind_scalars; + /// Hashes of transcript (Fiat-Shamir heuristic) Field beta; Field gamma; @@ -185,36 +192,51 @@ class plonk_example Field zeta; Field nu; /// v in the paper Field u; + /// Prover Round 1 std::vector> W_polys; + /// vanishing polynomial zh_poly(X) = x^n-1. vanishes on all n /// roots of unity omega_roots std::vector zh_poly; + /// Witness polynomials blinded by b constants a_poly = /// blind_polys[0] * zh_poly + W_polys[0] std::vector> W_polys_blinded; + /// blinded witness polynomials evaluate at secret input std::vector> W_polys_blinded_at_secret_g1; + /// Prover Round 2 + /// accumulator polynomial std::vector A_poly; + /// blinded accumulator poly z(x) std::vector z_poly; + /// blinded accumulator poly z(x) evaluated at secret std::vector z_poly_at_secret_g1; + /// Prover Round 3 + /// z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted by w std::vector z_poly_xomega; + /// t_poly: the quotient polynomial t(x) (see Round 3, pp28 /// [GWC19]) std::vector> t_poly; + /// t_poly_long: t(x) divided in three parts t(x) = t_lo(x) + /// t_mid(x) x^n + t_hi(x) x^{2n} polynomial t_poly_long; + /// t_poly_at_secret_g1: t(x) evaluated at the secret input zeta /// i.e. t(zeta) std::vector> t_poly_at_secret_g1; + /// Prover Round 4 + Field a_zeta; Field b_zeta; Field c_zeta; @@ -222,41 +244,57 @@ class plonk_example Field S_1_zeta; Field t_zeta; Field z_poly_xomega_zeta; + /// Prover Round 5 + /// linearisation polynomial r(x) polynomial r_poly; + /// linearisation polynomial evaluated at x=zeta ie. r(zeta) Field r_zeta; + /// opening proof polynomial W_zeta(x) polynomial W_zeta; + /// opening proof polynomial W_{zeta omega}(x) polynomial W_zeta_omega; + /// commitment to opening proof polynomial W_zeta(x) at secert /// input i.e. [W_zeta(secret)]_1 (represented as a point on the /// curve as a pair of X,Y coordinates (values in the base field)) std::vector W_zeta_at_secret; + /// commitment to opening proof polynomial W_{zeta omega}(x) at /// secert input i.e. [W_{zeta omega}(secret)]_1 std::vector W_zeta_omega_at_secret; + /// Verifier precomputation std::vector> Q_polys_at_secret_g1; std::vector> S_polys_at_secret_g1; + /// Verifier Step 5: vanishing polynomial evaluation at zeta Field zh_zeta; + /// Verifier Step 6: compute Lagrange polynomial evaluation /// L1(zeta) Field L_0_zeta; + /// Verifier Step7: evaluate public input polynomial at zeta Field PI_zeta; + /// Verifier Step 8: compute quotient polynomial evaluation /// r'(zeta) = r(zeta) - r0, where r0 is a constant term Field r_prime_zeta; + /// Verifier Step 9 std::vector D1; + /// Verifier Step 10: compute full batched polynomial commitment std::vector F1; + /// Verifier Step 11: compute group-encoded batch evaluation [E]_1 std::vector E1; + /// Verifier Step 12: batch validate all evaluations via pairing std::vector pairing_first_lhs; std::vector pairing_first_rhs; diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 28033abf1..0e32cd27b 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -167,17 +167,20 @@ template class plonk_verifier /// \attention This validation MUST be done by the caller. Empty /// function here for consistency with the description in [GWC19] static void step_one(const plonk_proof &proof); + /// Verifier Step 2: validate that elements belong to scalar field Fr /// /// \attention This validation MUST be done by the caller. Empty /// function here for consistency with the description in [GWC19] static void step_two(const plonk_proof &proof); + /// Verifier Step 3: validate that the public input belongs to scalar /// field Fr /// /// \attention This validation MUST be done by the caller. Empty /// function here for consistency with the description in [GWC19] static void step_three(const srs &srs); + /// Verifier Step 4: compute challenges hashed transcript as in prover /// description, from the common inputs, public input, and elements of /// pi-SNARK. TODO: fixed to the test vectors for now @@ -192,6 +195,7 @@ template class plonk_verifier /// \param[out] u: multipoint evaluation challenge - hash of /// transcript static step_four_out_t step_four(); + /// Verifier Step 5: compute zero polynomial evaluation /// /// INPUT @@ -205,6 +209,7 @@ template class plonk_verifier /// x=zeta i.e. Zh(zeta) static step_five_out_t step_five( const step_four_out_t &step_four_out, const srs &srs); + /// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) /// Note: the paper counts the L-polynomials from 1; we count from 0 /// @@ -219,6 +224,7 @@ template class plonk_verifier /// L1 at x=zeta i.e. L1(zeta) static step_six_out_t step_six( const step_four_out_t &step_four_out, const srs &srs); + /// Verifier Step 7: compute public input polynomial evaluation /// PI(zeta) /// @@ -233,6 +239,7 @@ template class plonk_verifier /// x=zeta i.e. PI(zeta) static step_seven_out_t step_seven( const step_four_out_t &step_four_out, const srs &srs); + /// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = /// r(zeta) - r0, where r0 is a constant term \note follows the Python /// reference implementation, which slightly deviates from the paper @@ -266,6 +273,7 @@ template class plonk_verifier const step_six_out_t &step_six_out, const step_seven_out_t &step_seven_out, const plonk_proof &proof); + /// Verifier Step 9: compute first part of batched polynomial /// commitment [D]_1 Note: the reference implemention differs from the /// paper -- it does not add the following term to D1, but to F1 (Step @@ -307,6 +315,7 @@ template class plonk_verifier const plonk_proof &proof, const verifier_preprocessed_input_t &preprocessed_input, const srs &srs); + /// Verifier Step 10: compute full batched polynomial commitment [F]_1 /// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + /// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the @@ -337,6 +346,7 @@ template class plonk_verifier const plonk_proof &proof, const verifier_preprocessed_input_t &preprocessed_input, const srs &srs); + /// Verifier Step 11: compute group-encoded batch evaluation [E]_1 /// /// INPUT @@ -354,6 +364,7 @@ template class plonk_verifier const step_four_out_t &step_four_out, const step_eight_out_t &step_eight_out, const plonk_proof &proof); + /// Verifier Step 12: batch validate all evaluations /// /// Checks the following equality @@ -387,6 +398,7 @@ template class plonk_verifier const step_eleven_out_t &step_eleven_out, const plonk_proof &proof, const srs &srs); + /// \attention The first three steps (as given in [GWC19] -- see /// below) MUST be executed by the caller: /// From 9286c7dc86043687c8e6fadc41c1bd4cd323710a Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 14:22:10 +0100 Subject: [PATCH 024/154] plonk: moved function plonk_curcuit_description_from_example to test_plonk.cpp as it is dependent on the particular test values of the example we use for debug. --- libsnark/zk_proof_systems/plonk/circuit.hpp | 4 - libsnark/zk_proof_systems/plonk/circuit.tcc | 119 +---------------- libsnark/zk_proof_systems/plonk/srs.hpp | 2 + .../zk_proof_systems/plonk/tests/example.hpp | 1 + .../plonk/tests/test_plonk.cpp | 120 +++++++++++++++++- 5 files changed, 124 insertions(+), 122 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index de29d0f29..6535a84b4 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -67,10 +67,6 @@ template struct circuit_t { libff::Fr k2; }; -template -circuit_t plonk_curcuit_description_from_example( - const plonk_example example); - } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/circuit.tcc" diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 9ca988620..2fff3fe77 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -15,123 +15,8 @@ namespace libsnark { -/// Compute or fill-in ciruit specific data from example. -template -circuit_t plonk_curcuit_description_from_example( - const plonk_example example) -{ - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - - using Field = libff::Fr; - circuit_t circuit; - - // public input (PI) - Field PI_value = example.public_input; - // index of the row of the PI in the non-transposed gates_matrix - int PI_index = example.public_input_index; - // Transposed gates matrix: each row is a q-vector - std::vector> gates_matrix_transpose = - example.gates_matrix_transpose; - // wire permutation - std::vector wire_permutation = example.wire_permutation; - // Generate domains on which to evaluate the witness - // polynomials. k1,k2 can be random, but we fix them for debug to - // match against the test vector values - circuit.k1 = example.k1; - circuit.k2 = example.k2; -#ifdef DEBUG_PLONK - printf("[%s:%d] k1 ", __FILE__, __LINE__); - circuit.k1.print(); - printf("[%s:%d] k2 ", __FILE__, __LINE__); - circuit.k2.print(); -#endif // #ifdef DEBUG_PLONK - - circuit.num_gates = example.num_gates; - // TODO: throw exception -#ifdef DEBUG_PLONK - // ensure that num_gates is not 0 - assert(circuit.num_gates); - // ensure num_gates is power of 2 - assert((circuit.num_gates & (circuit.num_gates - 1)) == 0); -#endif // #ifdef DEBUG_PLONK - - circuit.num_qpolys = example.num_qpolys; - - // We represent the constraints q_L, q_R, q_O, q_M, q_C and the - // witness w_L, w_R, w_O as polynomials in the roots of unity - // e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 - // compute Lagrange basis - circuit.L_basis.resize( - circuit.num_gates, polynomial(circuit.num_gates)); - std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); - plonk_compute_lagrange_basis(circuit.num_gates, circuit.L_basis); - - // compute public input (PI) polynomial - std::vector PI_points(circuit.num_gates, Field(0)); - PI_points[PI_index] = Field(-PI_value); - plonk_compute_public_input_polynomial(PI_points, circuit.PI_poly); - - // compute the selector polynomials (q-polynomials) from the - // transposed gates matrix over the Lagrange basis q_poly = \sum_i - // q[i] * L[i] where q[i] is a coefficient (a scalar Field - // element) and L[i] is a polynomial with Field coefficients - circuit.Q_polys.resize( - circuit.num_qpolys, polynomial(circuit.num_gates)); - plonk_compute_selector_polynomials( - gates_matrix_transpose, circuit.Q_polys); - - // number of generators for H, Hk1, Hk2 - int num_hgen = NUM_HSETS; - // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, - // omega[2] are omega[0]*k2 - // std::vector> omega; - circuit.omega_roots.resize(num_hgen, std::vector(circuit.num_gates)); - plonk_compute_roots_of_unity_omega( - circuit.k1, circuit.k2, circuit.omega_roots); - // H_gen contains the generators of H, k1 H and k2 H in one place - // ie. circuit.omega_roots, circuit.omega_roots_k1 and - // circuit.omega_roots_k2 - plonk_roots_of_unity_omega_to_subgroup_H( - circuit.omega_roots, circuit.H_gen); - // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H -#ifdef DEBUG_PLONK - printf("[%s:%d] circuit.H_gen\n", __FILE__, __LINE__); - print_vector(circuit.H_gen); - for (int i = 0; i < (int)circuit.H_gen.size(); ++i) { - assert(circuit.H_gen[i] == example.H_gen[i]); - } -#endif // #ifdef DEBUG_PLONK - - // permute circuit.H_gen according to the wire permutation - circuit.H_gen_permute.resize(num_hgen * circuit.num_gates, Field(0)); - plonk_permute_subgroup_H( - circuit.H_gen, wire_permutation, circuit.H_gen_permute); - // TODO: write unit test for plonk_permute_subgroup_H -#ifdef DEBUG_PLONK - printf("[%s:%d] circuit.H_gen_permute\n", __FILE__, __LINE__); - print_vector(circuit.H_gen_permute); - for (size_t i = 0; i < circuit.H_gen_permute.size(); ++i) { - assert(circuit.H_gen_permute[i] == example.H_gen_permute[i]); - } -#endif // #ifdef DEBUG_PLONK - - // compute the permutation polynomials S_sigma_1, S_sigma_2, - // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) - circuit.S_polys.resize(num_hgen, polynomial(circuit.num_gates)); - plonk_compute_permutation_polynomials( - circuit.H_gen_permute, circuit.num_gates, circuit.S_polys); - - return circuit; -} +// TODO: add here function for describing the target circuit through +// the circuit_t structure } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 2c585cafb..028134094 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -26,6 +26,8 @@ /// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, /// Report 2019/953, 2019, +#include "libsnark/common/data_structures/polynomial.hpp" + namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 83251fc99..90a2114fc 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -28,6 +28,7 @@ /// https://vitalik.ca/general/2019/09/22/plonk.html #include "libsnark/common/data_structures/polynomial.hpp" +#include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include #include diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index ffc87f00e..166c3e0dd 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -129,6 +129,124 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } +/// Compute or fill-in ciruit specific data from example. +template +circuit_t plonk_circuit_description_from_example( + const plonk_example example) +{ + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + + using Field = libff::Fr; + circuit_t circuit; + + // public input (PI) + Field PI_value = example.public_input; + // index of the row of the PI in the non-transposed gates_matrix + int PI_index = example.public_input_index; + // Transposed gates matrix: each row is a q-vector + std::vector> gates_matrix_transpose = + example.gates_matrix_transpose; + // wire permutation + std::vector wire_permutation = example.wire_permutation; + // Generate domains on which to evaluate the witness + // polynomials. k1,k2 can be random, but we fix them for debug to + // match against the test vector values + circuit.k1 = example.k1; + circuit.k2 = example.k2; +#ifdef DEBUG_PLONK + printf("[%s:%d] k1 ", __FILE__, __LINE__); + circuit.k1.print(); + printf("[%s:%d] k2 ", __FILE__, __LINE__); + circuit.k2.print(); +#endif // #ifdef DEBUG_PLONK + + circuit.num_gates = example.num_gates; + // TODO: throw exception +#ifdef DEBUG_PLONK + // ensure that num_gates is not 0 + assert(circuit.num_gates); + // ensure num_gates is power of 2 + assert((circuit.num_gates & (circuit.num_gates - 1)) == 0); +#endif // #ifdef DEBUG_PLONK + + circuit.num_qpolys = example.num_qpolys; + + // We represent the constraints q_L, q_R, q_O, q_M, q_C and the + // witness w_L, w_R, w_O as polynomials in the roots of unity + // e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 + // compute Lagrange basis + circuit.L_basis.resize( + circuit.num_gates, polynomial(circuit.num_gates)); + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + plonk_compute_lagrange_basis(circuit.num_gates, circuit.L_basis); + + // compute public input (PI) polynomial + std::vector PI_points(circuit.num_gates, Field(0)); + PI_points[PI_index] = Field(-PI_value); + plonk_compute_public_input_polynomial(PI_points, circuit.PI_poly); + + // compute the selector polynomials (q-polynomials) from the + // transposed gates matrix over the Lagrange basis q_poly = \sum_i + // q[i] * L[i] where q[i] is a coefficient (a scalar Field + // element) and L[i] is a polynomial with Field coefficients + circuit.Q_polys.resize( + circuit.num_qpolys, polynomial(circuit.num_gates)); + plonk_compute_selector_polynomials( + gates_matrix_transpose, circuit.Q_polys); + + // number of generators for H, Hk1, Hk2 + int num_hgen = NUM_HSETS; + // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, + // omega[2] are omega[0]*k2 + // std::vector> omega; + circuit.omega_roots.resize(num_hgen, std::vector(circuit.num_gates)); + plonk_compute_roots_of_unity_omega( + circuit.k1, circuit.k2, circuit.omega_roots); + // H_gen contains the generators of H, k1 H and k2 H in one place + // ie. circuit.omega_roots, circuit.omega_roots_k1 and + // circuit.omega_roots_k2 + plonk_roots_of_unity_omega_to_subgroup_H( + circuit.omega_roots, circuit.H_gen); + // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H +#ifdef DEBUG_PLONK + printf("[%s:%d] circuit.H_gen\n", __FILE__, __LINE__); + print_vector(circuit.H_gen); + for (int i = 0; i < (int)circuit.H_gen.size(); ++i) { + assert(circuit.H_gen[i] == example.H_gen[i]); + } +#endif // #ifdef DEBUG_PLONK + + // permute circuit.H_gen according to the wire permutation + circuit.H_gen_permute.resize(num_hgen * circuit.num_gates, Field(0)); + plonk_permute_subgroup_H( + circuit.H_gen, wire_permutation, circuit.H_gen_permute); + // TODO: write unit test for plonk_permute_subgroup_H +#ifdef DEBUG_PLONK + printf("[%s:%d] circuit.H_gen_permute\n", __FILE__, __LINE__); + print_vector(circuit.H_gen_permute); + for (size_t i = 0; i < circuit.H_gen_permute.size(); ++i) { + assert(circuit.H_gen_permute[i] == example.H_gen_permute[i]); + } +#endif // #ifdef DEBUG_PLONK + + // compute the permutation polynomials S_sigma_1, S_sigma_2, + // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) + circuit.S_polys.resize(num_hgen, polynomial(circuit.num_gates)); + plonk_compute_permutation_polynomials( + circuit.H_gen_permute, circuit.num_gates, circuit.S_polys); + + return circuit; +} + template void test_plonk() { #ifndef DEBUG_PLONK @@ -177,7 +295,7 @@ template void test_plonk() usrs usrs = plonk_usrs_derive_from_secret(secret); // --- circuit --- circuit_t circuit = - plonk_curcuit_description_from_example(example); + plonk_circuit_description_from_example(example); // --- SRS --- srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // sompare SRS against reference test values From fcb19b2bce16d8c70a6a81bafe1700c8cb742870 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 1 Jul 2022 14:28:33 +0100 Subject: [PATCH 025/154] plonk: added the maximum degree of the monomials in the usrs to be an input parameter to function plonk_usrs_derive_from_secret that creates the usrs object --- libsnark/zk_proof_systems/plonk/srs.hpp | 3 ++- libsnark/zk_proof_systems/plonk/srs.tcc | 7 ++++--- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 028134094..3c8385801 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -68,7 +68,8 @@ template class usrs }; template -usrs plonk_usrs_derive_from_secret(const libff::Fr &secret); +usrs plonk_usrs_derive_from_secret( + const libff::Fr &secret, const size_t max_degree); /// Plain (i.e. non-universal srs). Contains secret encoded monomials /// with maximum degree equal to the number of gates of the analyzed diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 184a5d108..88cd1b2ac 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -21,7 +21,8 @@ namespace libsnark /// /// \note only for debug template -usrs plonk_usrs_derive_from_secret(const libff::Fr &secret) +usrs plonk_usrs_derive_from_secret( + const libff::Fr &secret, const size_t max_degree) { // compute powers of secret times G1: 1*G1, secret^1*G1, secret^2*G1, ... const libff::bigint::num_limbs> secret_bigint = @@ -33,10 +34,10 @@ usrs plonk_usrs_derive_from_secret(const libff::Fr &secret) libff::find_wnaf::num_limbs>(window_size, secret_bigint); std::vector> secret_powers_g1; - secret_powers_g1.reserve(MAX_DEGREE); + secret_powers_g1.reserve(max_degree); libff::G1 secret_i_g1 = libff::G1::one(); secret_powers_g1.push_back(secret_i_g1); - for (size_t i = 1; i < MAX_DEGREE; ++i) { + for (size_t i = 1; i < max_degree; ++i) { // secret^i * G1 secret_i_g1 = libff::fixed_window_wnaf_exp>( window_size, secret_i_g1, naf); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 166c3e0dd..39ca715c1 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -292,7 +292,7 @@ template void test_plonk() // --- USRS --- // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 - usrs usrs = plonk_usrs_derive_from_secret(secret); + usrs usrs = plonk_usrs_derive_from_secret(secret, MAX_DEGREE); // --- circuit --- circuit_t circuit = plonk_circuit_description_from_example(example); From f91823e87fb412ae7d78721505f7444782bd6e21 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 7 Jul 2022 11:58:20 +0100 Subject: [PATCH 026/154] plonk: removed macro MAX_DEGREE specifying the maximum monomial degree supported in the USRS. This maximum degree is now input as a parameter to plonk_usrs_derive_from_secret that creates the USRS. --- libsnark/zk_proof_systems/plonk/plonk.hpp | 3 --- libsnark/zk_proof_systems/plonk/srs.hpp | 5 ++--- libsnark/zk_proof_systems/plonk/srs.tcc | 1 - libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 4 +++- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index 3347d4a3b..7cda36759 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -30,9 +30,6 @@ /// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, /// Report 2019/953, 2019, -/// maximum degree of the encoded monomials in the usrs -const size_t MAX_DEGREE = 254; - /// number of H-sets: H, Hk1 and Hk2, where H is a subgroup, while Hk1 /// and Hk2 are cosets const size_t NUM_HSETS = 3; diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 3c8385801..d2191625f 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -45,9 +45,8 @@ namespace libsnark /// srs = (proving_key, verificataion_key) = derive(usrs, circuit_description) /// -/// Universal srs (usrs). Contains secret encoded monomials with -/// maximum degree MAX_DEGREE and is so independent of any particular -/// circuit. +/// Universal srs (usrs). Contains secret encoded monomials with some +/// maximum degree and is so independent of any particular circuit. template class usrs { public: diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 88cd1b2ac..eff1a67d4 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -69,7 +69,6 @@ template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit) { - assert(circuit.num_gates <= MAX_DEGREE); // secret^i * G1 std::vector> secret_powers_g1; secret_powers_g1.reserve(circuit.num_gates + 3); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 39ca715c1..b952c83c3 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -290,9 +290,11 @@ template void test_plonk() printf("[%s:%d] SRS...\n", __FILE__, __LINE__); // --- USRS --- + // maximum degree of the encoded monomials in the usrs + size_t max_degree = 254; // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 - usrs usrs = plonk_usrs_derive_from_secret(secret, MAX_DEGREE); + usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); // --- circuit --- circuit_t circuit = plonk_circuit_description_from_example(example); From b1792f8170fb2ef6b04d581b3fec866f6dd59041 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 7 Jul 2022 14:36:36 +0100 Subject: [PATCH 027/154] plonk: added constructor to structure circuit_t --- libsnark/zk_proof_systems/plonk/circuit.hpp | 27 ++++++ .../plonk/tests/test_plonk.cpp | 87 +++++++++++-------- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index 6535a84b4..f67cf17ef 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -65,6 +65,33 @@ template struct circuit_t { /// constants for H, k1 H, k2 H libff::Fr k1; libff::Fr k2; + + /// stuct constructor + circuit_t( + size_t num_gates, + size_t num_qpolys, + std::vector> &&L_basis, + polynomial &&PI_poly, + std::vector> &&Q_polys, + std::vector> &&S_polys, + std::vector> &&omega_roots, + std::vector &&H_gen, + std::vector &&H_gen_permute, + libff::Fr &&k1, + libff::Fr &&k2) + : num_gates(num_gates) + , num_qpolys(num_qpolys) + , L_basis(L_basis) + , PI_poly(PI_poly) + , Q_polys(Q_polys) + , S_polys(S_polys) + , omega_roots(omega_roots) + , H_gen(H_gen) + , H_gen_permute(H_gen_permute) + , k1(k1) + , k2(k2) + { + } }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index b952c83c3..a2c163dd6 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -145,7 +145,6 @@ circuit_t plonk_circuit_description_from_example( } using Field = libff::Fr; - circuit_t circuit; // public input (PI) Field PI_value = example.public_input; @@ -159,91 +158,103 @@ circuit_t plonk_circuit_description_from_example( // Generate domains on which to evaluate the witness // polynomials. k1,k2 can be random, but we fix them for debug to // match against the test vector values - circuit.k1 = example.k1; - circuit.k2 = example.k2; + libff::Fr k1 = example.k1; + libff::Fr k2 = example.k2; #ifdef DEBUG_PLONK printf("[%s:%d] k1 ", __FILE__, __LINE__); - circuit.k1.print(); + k1.print(); printf("[%s:%d] k2 ", __FILE__, __LINE__); - circuit.k2.print(); + k2.print(); #endif // #ifdef DEBUG_PLONK - circuit.num_gates = example.num_gates; + size_t num_gates = example.num_gates; // TODO: throw exception #ifdef DEBUG_PLONK // ensure that num_gates is not 0 - assert(circuit.num_gates); + assert(num_gates); // ensure num_gates is power of 2 - assert((circuit.num_gates & (circuit.num_gates - 1)) == 0); + assert((num_gates & (num_gates - 1)) == 0); #endif // #ifdef DEBUG_PLONK - circuit.num_qpolys = example.num_qpolys; + size_t num_qpolys = example.num_qpolys; // We represent the constraints q_L, q_R, q_O, q_M, q_C and the // witness w_L, w_R, w_O as polynomials in the roots of unity // e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 // compute Lagrange basis - circuit.L_basis.resize( - circuit.num_gates, polynomial(circuit.num_gates)); + std::vector> L_basis; + L_basis.resize(num_gates, polynomial(num_gates)); std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); - plonk_compute_lagrange_basis(circuit.num_gates, circuit.L_basis); + libfqfft::get_evaluation_domain(num_gates); + plonk_compute_lagrange_basis(num_gates, L_basis); // compute public input (PI) polynomial - std::vector PI_points(circuit.num_gates, Field(0)); + polynomial PI_poly; + std::vector PI_points(num_gates, Field(0)); PI_points[PI_index] = Field(-PI_value); - plonk_compute_public_input_polynomial(PI_points, circuit.PI_poly); + plonk_compute_public_input_polynomial(PI_points, PI_poly); // compute the selector polynomials (q-polynomials) from the // transposed gates matrix over the Lagrange basis q_poly = \sum_i // q[i] * L[i] where q[i] is a coefficient (a scalar Field // element) and L[i] is a polynomial with Field coefficients - circuit.Q_polys.resize( - circuit.num_qpolys, polynomial(circuit.num_gates)); - plonk_compute_selector_polynomials( - gates_matrix_transpose, circuit.Q_polys); + std::vector> Q_polys; + Q_polys.resize(num_qpolys, polynomial(num_gates)); + plonk_compute_selector_polynomials(gates_matrix_transpose, Q_polys); // number of generators for H, Hk1, Hk2 int num_hgen = NUM_HSETS; // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, // omega[2] are omega[0]*k2 - // std::vector> omega; - circuit.omega_roots.resize(num_hgen, std::vector(circuit.num_gates)); - plonk_compute_roots_of_unity_omega( - circuit.k1, circuit.k2, circuit.omega_roots); + std::vector> omega_roots; + omega_roots.resize(num_hgen, std::vector(num_gates)); + plonk_compute_roots_of_unity_omega(k1, k2, omega_roots); // H_gen contains the generators of H, k1 H and k2 H in one place // ie. circuit.omega_roots, circuit.omega_roots_k1 and // circuit.omega_roots_k2 - plonk_roots_of_unity_omega_to_subgroup_H( - circuit.omega_roots, circuit.H_gen); + std::vector H_gen; + plonk_roots_of_unity_omega_to_subgroup_H(omega_roots, H_gen); // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H #ifdef DEBUG_PLONK - printf("[%s:%d] circuit.H_gen\n", __FILE__, __LINE__); - print_vector(circuit.H_gen); - for (int i = 0; i < (int)circuit.H_gen.size(); ++i) { - assert(circuit.H_gen[i] == example.H_gen[i]); + printf("[%s:%d] H_gen\n", __FILE__, __LINE__); + print_vector(H_gen); + for (int i = 0; i < (int)H_gen.size(); ++i) { + assert(H_gen[i] == example.H_gen[i]); } #endif // #ifdef DEBUG_PLONK // permute circuit.H_gen according to the wire permutation - circuit.H_gen_permute.resize(num_hgen * circuit.num_gates, Field(0)); - plonk_permute_subgroup_H( - circuit.H_gen, wire_permutation, circuit.H_gen_permute); + std::vector H_gen_permute; + H_gen_permute.resize(num_hgen * num_gates, Field(0)); + plonk_permute_subgroup_H(H_gen, wire_permutation, H_gen_permute); // TODO: write unit test for plonk_permute_subgroup_H #ifdef DEBUG_PLONK - printf("[%s:%d] circuit.H_gen_permute\n", __FILE__, __LINE__); - print_vector(circuit.H_gen_permute); - for (size_t i = 0; i < circuit.H_gen_permute.size(); ++i) { - assert(circuit.H_gen_permute[i] == example.H_gen_permute[i]); + printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); + print_vector(H_gen_permute); + for (size_t i = 0; i < H_gen_permute.size(); ++i) { + assert(H_gen_permute[i] == example.H_gen_permute[i]); } #endif // #ifdef DEBUG_PLONK // compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) - circuit.S_polys.resize(num_hgen, polynomial(circuit.num_gates)); + std::vector> S_polys; + S_polys.resize(num_hgen, polynomial(num_gates)); plonk_compute_permutation_polynomials( - circuit.H_gen_permute, circuit.num_gates, circuit.S_polys); + H_gen_permute, num_gates, S_polys); + circuit_t circuit( + std::move(num_gates), + std::move(num_qpolys), + std::move(L_basis), + std::move(PI_poly), + std::move(Q_polys), + std::move(S_polys), + std::move(omega_roots), + std::move(H_gen), + std::move(H_gen_permute), + std::move(k1), + std::move(k2)); return circuit; } From 5aa5d204961b5720f62f1d306adeb5681eea7a01 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 7 Jul 2022 14:41:27 +0100 Subject: [PATCH 028/154] plonk: added clarification of the purpose of the circuit_t strcuture in the comment section of circuit.hpp --- libsnark/zk_proof_systems/plonk/circuit.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index f67cf17ef..eda0d63d7 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -11,8 +11,8 @@ #include "libsnark/zk_proof_systems/plonk/plonk.hpp" -/// Declaration of Common Preprocessed Input interfaces for ppzkSNARK -/// proof system Plonk. +/// Declaration of Common Preprocessed Input data structures for a +/// specific arithmetic circuit. /// /// This includes: /// - class for common preprocessed input From d333ca9e0b2b41f11d64ef1e6647e524a1e16114 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 7 Jul 2022 15:12:05 +0100 Subject: [PATCH 029/154] plonk: removed unused function check_field_element --- libsnark/zk_proof_systems/plonk/plonk.hpp | 3 --- libsnark/zk_proof_systems/plonk/plonk.tcc | 7 ------- 2 files changed, 10 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index 7cda36759..36f2cbbbc 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -228,9 +228,6 @@ void plonk_compute_accumulator( const std::vector &H_gen_permute, std::vector &A); -/// check that the input is an element of the field -template bool check_field_element(const FieldT x); - } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/plonk.tcc" diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index cd300e6b2..b98779dab 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -400,13 +400,6 @@ void plonk_compute_accumulator( } } -/// check that the input is an element of the field -template bool check_field_element(const FieldT x) -{ - bool b_valid = (typeid(x) == typeid(FieldT)); - return b_valid; -} - } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ From 7bf884330a454c811a215ad58c0aa06f6fb228a7 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 7 Jul 2022 17:22:24 +0100 Subject: [PATCH 030/154] plonk: improved efficiency in the computation of the roots of unity omega. namely, do not recompute the power from scratch each time, but iteratively multiply by omega_base at each iteration. --- libsnark/zk_proof_systems/plonk/plonk.tcc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index b98779dab..ca99a3ae5 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -196,13 +196,14 @@ void plonk_compute_roots_of_unity_omega( // power of 2 divides (q-1). In particular 2**32|(q-1) and so the // 2**32-th root of unity exists. FieldT omega_base = libff::get_root_of_unity(num_gates); + FieldT omega_i = 1; for (size_t i = 0; i < num_gates; ++i) { - FieldT omega_i = libff::power(omega_base, libff::bigint<1>(i)); omega[base][i] = omega_i; FieldT omega_k1_i = omega[base][i] * k1; FieldT omega_k2_i = omega[base][i] * k2; omega[base_k1][i] = omega_k1_i; omega[base_k2][i] = omega_k2_i; + omega_i *= omega_base; } } From 24ad6de3d2294af227980c20e9b89cac58db9b73 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 07:34:23 +0100 Subject: [PATCH 031/154] plonk: corrected description of function plonk_compute_roots_of_unity_omega in comments --- libsnark/zk_proof_systems/plonk/plonk.tcc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index ca99a3ae5..174c15368 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -177,10 +177,12 @@ void plonk_compute_public_input_polynomial( plonk_interpolate_polynomial_from_points(PI_points, PI_poly); }; -/// output: omega[0] are the n roots of unity, omega[1] are -/// omega[0]*k1, omega[2] are omega[0]*k2; k1 H is a coset of H with -/// generator omega_k1 distinct from H; k2 H is a coset of H with -/// generator omega_k2, distinct from H and k1 H +/// This function computes the sets H, k1H, k2H. H is a +/// multiplicative subgroup containing the n-th roots of unity in Fr, +/// where \omega is a primitive n-th root of unity and a generator of +/// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +/// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( const FieldT k1, const FieldT k2, std::vector> &omega) From 9d35d555fe85dcabdfa45a524d7c0cf6966d533c Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 08:01:26 +0100 Subject: [PATCH 032/154] plonk: added minor correction of "encrypted" to "encoded" in comments --- libsnark/zk_proof_systems/plonk/plonk.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index 174c15368..2ef851650 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -285,7 +285,7 @@ libff::G1 plonk_multi_exp_G1( return product; } -/// Evaluate a polynomial F at the encrypted secret input +/// Evaluate a polynomial F at the encoded secret input /// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i /// /// INPUT From 94f84944ec0e74a06921d5c8de2eeb87bd57c138 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 09:11:06 +0100 Subject: [PATCH 033/154] plonk: modified function plonk_compute_roots_of_unity_omega to allocate space for the 2d vector omega inside itself rather than by the caller. the motivation is to avoid errors from passing inputs with incorrect size. --- libsnark/zk_proof_systems/plonk/plonk.hpp | 15 ++++++++----- libsnark/zk_proof_systems/plonk/plonk.tcc | 22 +++++++++++++++---- .../plonk/tests/test_plonk.cpp | 5 +++-- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index 36f2cbbbc..1789890da 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -132,13 +132,18 @@ void plonk_compute_selector_polynomials( const std::vector> &gates_matrix_transpose, std::vector> &Q_polys); -/// output: omega[0] are the n roots of unity, omega[1] are -/// omega[0]*k1, omega[2] are omega[0]*k2; k1 H is a coset of H with -/// generator omega_k1 distinct from H; k2 H is a coset of H with -/// generator omega_k2, distinct from H and k1 H +/// This function computes the sets H, k1H, k2H. H is a +/// multiplicative subgroup containing the n-th roots of unity in Fr, +/// where \omega is a primitive n-th root of unity and a generator of +/// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +/// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( - const FieldT k1, const FieldT k2, std::vector> &omega); + const size_t num_gates, + const FieldT k1, + const FieldT k2, + std::vector> &omega); /// copy the roots of unity omega[base], omega[k1] and omega[k2] into /// a single vector H_gen representing the multiplicative subgroups diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index 2ef851650..038f661ba 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -185,11 +185,25 @@ void plonk_compute_public_input_polynomial( /// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( - const FieldT k1, const FieldT k2, std::vector> &omega) + const size_t num_gates, + const FieldT k1, + const FieldT k2, + std::vector> &omega) { - assert(omega.size() == NUM_HSETS); - assert(omega[0].size() > 0); - size_t num_gates = omega[0].size(); + // ensure that num_gates is not 0 and is power of 2 + // TODO: check also that it's less than 2^(ppT::s) + try { + bool b_nonzero = (num_gates > 0); + bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); + if (!(b_nonzero && b_is_power2)) { + throw std::invalid_argument("Curve is not BLS12-381"); + } + } catch (const std::invalid_argument &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + omega.resize(NUM_HSETS, std::vector(num_gates)); + // Get the n-th root of unity omega in Fq (n=8 is the number of // constraints in the example). omega is a generator of the // multiplicative subgroup H. Example (2**32)-th primitive root diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index a2c163dd6..0acf51989 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -204,16 +204,17 @@ circuit_t plonk_circuit_description_from_example( // number of generators for H, Hk1, Hk2 int num_hgen = NUM_HSETS; + // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, // omega[2] are omega[0]*k2 std::vector> omega_roots; - omega_roots.resize(num_hgen, std::vector(num_gates)); - plonk_compute_roots_of_unity_omega(k1, k2, omega_roots); + plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); // H_gen contains the generators of H, k1 H and k2 H in one place // ie. circuit.omega_roots, circuit.omega_roots_k1 and // circuit.omega_roots_k2 std::vector H_gen; plonk_roots_of_unity_omega_to_subgroup_H(omega_roots, H_gen); + // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H #ifdef DEBUG_PLONK printf("[%s:%d] H_gen\n", __FILE__, __LINE__); From 33a80c3b23b92848c42601984a59dba893abc4a5 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 09:28:52 +0100 Subject: [PATCH 034/154] plonk: replaced function plonk_roots_of_unity_omega_to_subgroup_H with plonk_multiplicative_subgroups_H_k1H_k2H. the latter recomputes the vector of omega roots in order to avoid passing it as an input parameter potentially with the wrong size (as was done in plonk_roots_of_unity_omega_to_subgroup_H) --- libsnark/zk_proof_systems/plonk/plonk.hpp | 19 +++++++--- libsnark/zk_proof_systems/plonk/plonk.tcc | 38 +++++++++++++++---- .../plonk/tests/test_plonk.cpp | 3 +- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/plonk.hpp index 1789890da..3bd4ebd5a 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/plonk.hpp @@ -145,13 +145,20 @@ void plonk_compute_roots_of_unity_omega( const FieldT k2, std::vector> &omega); -/// copy the roots of unity omega[base], omega[k1] and omega[k2] into -/// a single vector H_gen representing the multiplicative subgroups -/// H, k1 H and k2 H (see [GWC19] Sect. 8); \see -/// plonk_compute_roots_of_unity_omega +/// This function computes the sets H, k1H, k2H, where H is a +/// multiplicative subgroup containing the n-th roots of unity in Fr and +/// \omega is a primitive n-th root of unity and a generator of +/// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +/// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. +/// +/// \note uses plonk_compute_roots_of_unity_omega template -void plonk_roots_of_unity_omega_to_subgroup_H( - const std::vector> &omega, std::vector &H_gen); +void plonk_multiplicative_subgroups_H_k1H_k2H( + const size_t num_gates, + const FieldT k1, + const FieldT k2, + std::vector &H_gen); /// permute the multiplicative subgroup H according to the wire /// permutation: (see [GWC19] Sect. 8), \see diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index 038f661ba..f55ee7e04 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -223,16 +223,38 @@ void plonk_compute_roots_of_unity_omega( } } -/// copy the roots of unity omega[base], omega[k1] and omega[k2] into -/// a single vector H_gen representing the multiplicative subgroups -/// H, k1 H and k2 H (see [GWC19] Sect. 8); \see -/// plonk_compute_roots_of_unity_omega +/// This function computes the sets H, k1H, k2H, where H is a +/// multiplicative subgroup containing the n-th roots of unity in Fr and +/// \omega is a primitive n-th root of unity and a generator of +/// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +/// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. +/// +/// \note uses plonk_compute_roots_of_unity_omega template -void plonk_roots_of_unity_omega_to_subgroup_H( - const std::vector> &omega, std::vector &H_gen) +void plonk_multiplicative_subgroups_H_k1H_k2H( + const size_t num_gates, + const FieldT k1, + const FieldT k2, + std::vector &H_gen) { - assert(omega.size() == NUM_HSETS); - assert(omega[0].size() > 0); + // ensure that num_gates is not 0 and is power of 2 + try { + bool b_nonzero = (num_gates > 0); + bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); + if (!(b_nonzero && b_is_power2)) { + throw std::invalid_argument("Curve is not BLS12-381"); + } + } catch (const std::invalid_argument &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + + // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, + // omega[2] are omega[0]*k2 + std::vector> omega; + plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega); + std::copy(omega[base].begin(), omega[base].end(), back_inserter(H_gen)); std::copy( omega[base_k1].begin(), omega[base_k1].end(), back_inserter(H_gen)); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 0acf51989..033c5d7d5 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -209,11 +209,12 @@ circuit_t plonk_circuit_description_from_example( // omega[2] are omega[0]*k2 std::vector> omega_roots; plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); + // H_gen contains the generators of H, k1 H and k2 H in one place // ie. circuit.omega_roots, circuit.omega_roots_k1 and // circuit.omega_roots_k2 std::vector H_gen; - plonk_roots_of_unity_omega_to_subgroup_H(omega_roots, H_gen); + plonk_multiplicative_subgroups_H_k1H_k2H(num_gates, k1, k2, H_gen); // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H #ifdef DEBUG_PLONK From f1409f87d946553e192fddcb21c00588b2e8237c Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 09:42:25 +0100 Subject: [PATCH 035/154] plonk: fixed typo in comments --- libsnark/zk_proof_systems/plonk/plonk.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/plonk.tcc index f55ee7e04..a88cc9f0b 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/plonk.tcc @@ -417,7 +417,7 @@ FieldT plonk_compute_accumulator_factor( return res; } -// - A: accumulatro vector +// - A: accumulator vector template void plonk_compute_accumulator( const size_t n, // num_gates From e04ecdf29a7b2a0ced4148b3f60d4fb31073fc64 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 09:45:33 +0100 Subject: [PATCH 036/154] plonk: removed extra output specifed in the Doxygen comments to plonk_prover::round_zero --- libsnark/zk_proof_systems/plonk/prover.tcc | 1 - 1 file changed, 1 deletion(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 99e423fd8..26744cc7b 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -24,7 +24,6 @@ namespace libsnark /// circuit-specific information /// /// OUTPUT -/// \param[out] W_polys: Lagrange interpolation of the witness values /// \param[out] zh_poly: vanishing polynomial /// \param[out] null_poly: 0 polynomial /// \param[out] neg_one_poly: -1 polynomial From 8d5ed167400d68c5ff17485c2f1461c276184849 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 09:48:36 +0100 Subject: [PATCH 037/154] plonk: replaced type of constant parameter nwitness from int to const size_t --- libsnark/zk_proof_systems/plonk/prover.tcc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 26744cc7b..896777d90 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -78,7 +78,7 @@ round_one_out_t plonk_prover::round_one( const srs &srs) { using Field = libff::Fr; - int nwitness = 3; + const size_t nwitness = NUM_HSETS; // the example class is defined specifically for the BLS12-381 // curve, so make sure we are using this curve. TODO: remove when @@ -100,7 +100,7 @@ round_one_out_t plonk_prover::round_one( // compute witness polynomials via Lagrange interpolation W_polys.resize(nwitness, polynomial(srs.num_gates)); - for (int i = 0; i < nwitness; ++i) { + for (size_t i = 0; i < nwitness; ++i) { typename std::vector::const_iterator begin = witness.begin() + (i * srs.num_gates); typename std::vector::const_iterator end = @@ -111,8 +111,8 @@ round_one_out_t plonk_prover::round_one( // TODO: move to unit test for // plonk_interpolate_polynomial_from_points #ifdef DEBUG_PLONK - for (int i = 0; i < nwitness; ++i) { - printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, i); + for (size_t i = 0; i < nwitness; ++i) { + printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); print_vector(W_polys[i]); assert(W_polys[i] == example.W_polys[i]); } @@ -131,7 +131,7 @@ round_one_out_t plonk_prover::round_one( // compute blinded witness polynomials e.g. a_poly = // blind_polys[0] * zh_poly + W_polys[0] W_polys_blinded.resize(nwitness); - for (int i = 0; i < nwitness; ++i) { + for (size_t i = 0; i < nwitness; ++i) { libfqfft::_polynomial_multiplication( W_polys_blinded[i], blind_polys[i], round_zero_out.zh_poly); libfqfft::_polynomial_addition( From 341a12c436ff595b62178b7f01171c8afc13491b Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 13:08:58 +0100 Subject: [PATCH 038/154] plonk: created a separate struct to contain all hashes of the communication transcript produced by the prover. added it as input to prover::compute_proof. removed all variables (alpha, beta, gamma, zeta, nu, u) representing transcript hashes from the output structs of the prover. these are passed in by the caller, who computes them from the transcript. --- libsnark/zk_proof_systems/plonk/prover.hpp | 73 ++++----- libsnark/zk_proof_systems/plonk/prover.tcc | 147 +++++++++--------- libsnark/zk_proof_systems/plonk/srs.hpp | 31 ++++ .../plonk/tests/test_plonk.cpp | 10 +- 4 files changed, 136 insertions(+), 125 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 75740d958..15d79238c 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -157,12 +157,6 @@ template struct round_one_out_t { /// Prover round 2 output template struct round_two_out_t { - /// - beta: permutation challenge -- hash of transcript - libff::Fr beta; - - /// - gamma: permutation challenge -- hash of transcript - libff::Fr gamma; - /// - z_poly: blinded accumulator poly z(x) polynomial> z_poly; @@ -172,14 +166,9 @@ template struct round_two_out_t { /// stuct constructor round_two_out_t( - libff::Fr &&beta, - libff::Fr &&gamma, polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1) - : beta(beta) - , gamma(gamma) - , z_poly(z_poly) - , z_poly_at_secret_g1(z_poly_at_secret_g1) + : z_poly(z_poly), z_poly_at_secret_g1(z_poly_at_secret_g1) { } }; @@ -187,9 +176,6 @@ template struct round_two_out_t { /// Prover round 3 output template struct round_three_out_t { - /// - alpha: quotient challenge -- hash of transcript - libff::Fr alpha; - /// - z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted by w std::vector> z_poly_xomega; @@ -207,13 +193,11 @@ template struct round_three_out_t { /// stuct constructor round_three_out_t( - libff::Fr &&alpha, std::vector> &&z_poly_xomega, std::vector>> &&t_poly, polynomial> &&t_poly_long, std::vector> &&t_poly_at_secret_g1) - : alpha(alpha) - , z_poly_xomega(z_poly_xomega) + : z_poly_xomega(z_poly_xomega) , t_poly(t_poly) , t_poly_long(t_poly_long) , t_poly_at_secret_g1(t_poly_at_secret_g1) @@ -224,9 +208,6 @@ template struct round_three_out_t { /// Prover round 4 output template struct round_four_out_t { - /// - zeta: evaluation challenge -- hash of transcript - libff::Fr zeta; - /// - a_zeta, b_zeta, c_zeta: the blinded witness polynomials a(x), /// b(x), c(x) (denoted by W_polys_blinded[] output from Round 1) /// evaluated at x=zeta i.e. a(z), b(z), c(z) @@ -253,7 +234,6 @@ template struct round_four_out_t { libff::Fr t_zeta; /// stuct constructor round_four_out_t( - libff::Fr &&zeta, libff::Fr &&a_zeta, libff::Fr &&b_zeta, libff::Fr &&c_zeta, @@ -261,8 +241,7 @@ template struct round_four_out_t { libff::Fr &&S_1_zeta, libff::Fr &&z_poly_xomega_zeta, libff::Fr &&t_zeta) - : zeta(zeta) - , a_zeta(a_zeta) + : a_zeta(a_zeta) , b_zeta(b_zeta) , c_zeta(c_zeta) , S_0_zeta(S_0_zeta) @@ -276,10 +255,6 @@ template struct round_four_out_t { /// Prover round 5 output template struct round_five_out_t { - /// - nu: opening challenge -- hash of transcript (denoted by v in - /// [GWC19]) - libff::Fr nu; - /// - r_zeta: linearisation polynomial r(x) evaluated at x=zeta /// ie. r(zeta) libff::Fr r_zeta; @@ -292,21 +267,14 @@ template struct round_five_out_t { /// W_{zeta omega}(x) at secert input i.e. [W_{zeta omega}(secret)]_1 libff::G1 W_zeta_omega_at_secret; - /// - u: multipoint evaluation challenge -- hash of transcript - libff::Fr u; - /// struct constructor round_five_out_t( - libff::Fr &&nu, libff::Fr &&r_zeta, libff::G1 &&W_zeta_at_secret, - libff::G1 &&W_zeta_omega_at_secret, - libff::Fr &&u) - : nu(nu) - , r_zeta(r_zeta) + libff::G1 &&W_zeta_omega_at_secret) + : r_zeta(r_zeta) , W_zeta_at_secret(W_zeta_at_secret) , W_zeta_omega_at_secret(W_zeta_omega_at_secret) - , u(u) { } }; @@ -368,12 +336,12 @@ template class plonk_prover /// circuit-specific information /// /// OUTPUT - /// \param[out] beta, gamma: permutation challenges -- hashes of - /// transcript /// \param[out] z_poly: blinded accumulator poly z(x) /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret static round_two_out_t round_two( + const libff::Fr beta, + const libff::Fr gamma, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const std::vector> &witness, @@ -392,7 +360,6 @@ template class plonk_prover /// circuit-specific information /// /// OUTPUT - /// \param[out] alpha: quotinet challenge -- hash of transcript /// \param[out] t_poly_long: the quotient polynomial t(x) (see Round /// 3, pp28 [GWC19]) /// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + @@ -402,6 +369,9 @@ template class plonk_prover /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted /// by w static round_three_out_t round_three( + const libff::Fr alpha, + const libff::Fr beta, + const libff::Fr gamma, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -420,7 +390,6 @@ template class plonk_prover /// circuit-specific information /// /// OUTPUT - /// \param[out] zeta: evaluation challenge -- hash of transcript /// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness /// polynomials a(x), b(x), c(x) (denoted by /// W_polys_blinded[] output from Round 1) evaluated at @@ -440,6 +409,7 @@ template class plonk_prover /// same in order to match the test vectors. TODO can /// remove t_zeta in the future static round_four_out_t round_four( + const libff::Fr zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs); @@ -480,10 +450,6 @@ template class plonk_prover /// circuit-specific information /// /// OUTPUT - /// \param[out] nu: opening challenge -- hash of transcript (denoted - /// by v in [GWC19]) - /// \param[out] u: multipoint evaluation challenge -- hash of - /// transcript /// \param[out] r_zeta: linearisation polynomial r(x) evaluated at /// x=zeta ie. r(zeta) /// \param[out] W_zeta_at_secret: commitment to opening proof @@ -493,6 +459,11 @@ template class plonk_prover /// polynomial W_{zeta omega}(x) at secert input /// i.e. [W_{zeta omega}(secret)]_1 static round_five_out_t round_five( + const libff::Fr alpha, + const libff::Fr beta, + const libff::Fr gamma, + const libff::Fr zeta, + const libff::Fr nu, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -535,10 +506,20 @@ template class plonk_prover /// INPUT /// \param[in] srs: structured reference string containing also /// circuit-specific information + /// \param[in] transcript_hash: hashes of the communication transcript + /// after prover rounds 1,2,3,4,5. TODO: \attention + /// currently the structure is used as an input initialized + /// with hard-coded example values for debug purposes. In + /// the long run it should be modified to be used as an + /// output. More specifically, the hard-coded values should + /// be overwritten with the actual transcript hashes + /// produced after the respective rounds within \ref + /// compute_proof /// /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) - static plonk_proof compute_proof(const srs &srs); + static plonk_proof compute_proof( + const srs &srs, transcript_hash_t &transcript_hash); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 896777d90..2838fb0a8 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -162,13 +162,13 @@ round_one_out_t plonk_prover::round_one( /// circuit-specific information /// /// OUTPUT -/// \param[out] beta, gamma: permutation challenges -- hashes of -/// transcript /// \param[out] z_poly: blinded accumulator poly z(x) /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret template round_two_out_t plonk_prover::round_two( + const libff::Fr beta, + const libff::Fr gamma, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const std::vector> &witness, @@ -178,17 +178,9 @@ round_two_out_t plonk_prover::round_two( // initialize hard-coded values from example circuit plonk_example example; - // output from round 2 - libff::Fr beta; - libff::Fr gamma; polynomial> z_poly; libff::G1 z_poly_at_secret_g1; - // permutation challenges (hashes of transcript); fixed to test - // values - beta = example.beta; - gamma = example.gamma; - // compute permutation polynomial // blinding polynomial: b8 + b7 X + b6 X^2 @@ -227,10 +219,7 @@ round_two_out_t plonk_prover::round_two( plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, z_poly); round_two_out_t round_two_out( - std::move(beta), - std::move(gamma), - std::move(z_poly), - std::move(z_poly_at_secret_g1)); + std::move(z_poly), std::move(z_poly_at_secret_g1)); return round_two_out; } @@ -248,7 +237,6 @@ round_two_out_t plonk_prover::round_two( /// circuit-specific information /// /// OUTPUT -/// \param[out] alpha: quotinet challenge -- hash of transcript /// \param[out] t_poly_long: the quotient polynomial t(x) (see Round /// 3, pp28 [GWC19]) /// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + @@ -259,6 +247,9 @@ round_two_out_t plonk_prover::round_two( /// by w template round_three_out_t plonk_prover::round_three( + const libff::Fr alpha, + const libff::Fr beta, + const libff::Fr gamma, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -280,15 +271,11 @@ round_three_out_t plonk_prover::round_three( plonk_example example; // output from round 3 - libff::Fr alpha; std::vector> z_poly_xomega; std::vector>> t_poly; polynomial> t_poly_long; std::vector> t_poly_at_secret_g1; - // quotient challenge (hash of transcript); fixed to test value - alpha = example.alpha; - // Computing the polynomial z(x*w) i.e. z(x) shifted by w where // w=srs.omega_roots is the base root of unity and z is // z_poly. we do this by multiplying the coefficients of z by w @@ -341,12 +328,12 @@ round_three_out_t plonk_prover::round_three( // X*beta as polynomial in X std::vector> xbeta_poly{ - {Field(0), round_two_out.beta}, // X*beta - {Field(0), round_two_out.beta * srs.k1}, // X*beta*k1 - {Field(0), round_two_out.beta * srs.k2} // X*beta*k2 + {Field(0), beta}, // X*beta + {Field(0), beta * srs.k1}, // X*beta*k1 + {Field(0), beta * srs.k2} // X*beta*k2 }; // represent gamma as polynomial in X, needed for prover Round 3 - polynomial gamma_poly{round_two_out.gamma}; // gamma + polynomial gamma_poly{gamma}; // gamma // represent alpha as polynomial in X, needed for prover Round 3 polynomial alpha_poly{alpha}; // alpha @@ -386,7 +373,7 @@ round_three_out_t plonk_prover::round_three( // --- Computation of t_part[2] // represent beta as polynomial in X, needed for prover Round 3 - polynomial beta_poly{round_two_out.beta}; + polynomial beta_poly{beta}; // S*beta as polynomial // S_sigma1(x)*beta, S_sigma2(x)*beta, S_sigma3(x)*beta std::vector> sbeta_poly(num_hgen); @@ -500,7 +487,6 @@ round_three_out_t plonk_prover::round_three( } round_three_out_t round_three_out( - std::move(alpha), std::move(z_poly_xomega), std::move(t_poly), std::move(t_poly_long), @@ -522,7 +508,6 @@ round_three_out_t plonk_prover::round_three( /// circuit-specific information /// /// OUTPUT -/// \param[out] zeta: evaluation challenge -- hash of transcript /// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness /// polynomials a(x), b(x), c(x) (denoted by /// W_polys_blinded[] output from Round 1) evaluated at @@ -543,6 +528,7 @@ round_three_out_t plonk_prover::round_three( /// remove t_zeta in the future template round_four_out_t plonk_prover::round_four( + const libff::Fr zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs) @@ -561,7 +547,6 @@ round_four_out_t plonk_prover::round_four( plonk_example example; // output from round 4 - libff::Fr zeta; libff::Fr a_zeta; libff::Fr b_zeta; libff::Fr c_zeta; @@ -570,9 +555,6 @@ round_four_out_t plonk_prover::round_four( libff::Fr z_poly_xomega_zeta; libff::Fr t_zeta; - // evaluation challenge (hash of transcript); fixed to test value - zeta = example.zeta; - a_zeta = libfqfft::evaluate_polynomial( srs.num_gates + 2, round_one_out.W_polys_blinded[a], zeta); b_zeta = libfqfft::evaluate_polynomial( @@ -591,7 +573,6 @@ round_four_out_t plonk_prover::round_four( zeta); round_four_out_t round_four_out( - std::move(zeta), std::move(a_zeta), std::move(b_zeta), std::move(c_zeta), @@ -639,10 +620,6 @@ round_four_out_t plonk_prover::round_four( /// circuit-specific information /// /// OUTPUT -/// \param[out] nu: opening challenge -- hash of transcript (denoted -/// by v in [GWC19]) -/// \param[out] u: multipoint evaluation challenge -- hash of -/// transcript /// \param[out] r_zeta: linearisation polynomial r(x) evaluated at /// x=zeta ie. r(zeta) /// \param[out] W_zeta_at_secret: commitment to opening proof @@ -653,6 +630,11 @@ round_four_out_t plonk_prover::round_four( /// i.e. [W_{zeta omega}(secret)]_1 template round_five_out_t plonk_prover::round_five( + const libff::Fr alpha, + const libff::Fr beta, + const libff::Fr gamma, + const libff::Fr zeta, + const libff::Fr nu, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -676,15 +658,9 @@ round_five_out_t plonk_prover::round_five( plonk_example example; // output from round 5 - libff::Fr nu; libff::Fr r_zeta; libff::G1 W_zeta_at_secret; libff::G1 W_zeta_omega_at_secret; - libff::Fr u; - - // openinig challenge (hash of transcript); fixed to test value - // (note: denoted v in [GWZ19]) - nu = example.nu; // compute linerisation polynomial r in five parts std::vector> r_part(5); @@ -725,27 +701,18 @@ round_five_out_t plonk_prover::round_five( // --- Computation of r_part[1] polynomial r1_const_poly{ - (round_four_out.a_zeta + (round_two_out.beta * round_four_out.zeta) + - round_two_out.gamma) * - (round_four_out.b_zeta + - (round_two_out.beta * srs.k1 * round_four_out.zeta) + - round_two_out.gamma) * - (round_four_out.c_zeta + - (round_two_out.beta * srs.k2 * round_four_out.zeta) + - round_two_out.gamma) * - round_three_out.alpha}; + (round_four_out.a_zeta + (beta * zeta) + gamma) * + (round_four_out.b_zeta + (beta * srs.k1 * zeta) + gamma) * + (round_four_out.c_zeta + (beta * srs.k2 * zeta) + gamma) * alpha}; libfqfft::_polynomial_multiplication( r_part[1], r1_const_poly, round_two_out.z_poly); // --- Computation of r_part[2] polynomial r2_const_poly{ - (round_four_out.a_zeta + - (round_two_out.beta * round_four_out.S_0_zeta) + round_two_out.gamma) * - (round_four_out.b_zeta + - (round_two_out.beta * round_four_out.S_1_zeta) + round_two_out.gamma) * - (round_three_out.alpha * round_two_out.beta * - round_four_out.z_poly_xomega_zeta)}; + (round_four_out.a_zeta + (beta * round_four_out.S_0_zeta) + gamma) * + (round_four_out.b_zeta + (beta * round_four_out.S_1_zeta) + gamma) * + (alpha * beta * round_four_out.z_poly_xomega_zeta)}; libfqfft::_polynomial_multiplication( r_part[2], r2_const_poly, srs.S_polys[2]); // -r_part[2] @@ -756,9 +723,9 @@ round_five_out_t plonk_prover::round_five( // r3 = accumulator_poly_ext3 * eval_poly(L_1, [zeta])[0] * alpha ** 2 polynomial L_0_zeta_poly{libfqfft::evaluate_polynomial( - srs.L_basis[0].size(), srs.L_basis[0], round_four_out.zeta)}; + srs.L_basis[0].size(), srs.L_basis[0], zeta)}; polynomial alpha_power2_poly{ - libff::power(round_three_out.alpha, libff::bigint<1>(2))}; + libff::power(alpha, libff::bigint<1>(2))}; libfqfft::_polynomial_multiplication( r_part[3], round_two_out.z_poly, L_0_zeta_poly); libfqfft::_polynomial_multiplication( @@ -792,8 +759,7 @@ round_five_out_t plonk_prover::round_five( // paper this is omitted, which makes the proof shorter at the // epxense of a slightly heavier computation on the verifier's // side - r_zeta = libfqfft::evaluate_polynomial( - r_poly.size(), r_poly, round_four_out.zeta); + r_zeta = libfqfft::evaluate_polynomial(r_poly.size(), r_poly, zeta); // TODO: move to unit test for compyting r_zeta #ifdef DEBUG_PLONK @@ -811,13 +777,13 @@ round_five_out_t plonk_prover::round_five( // t_mid(x) * zeta^(n+2) polynomial t_mid_zeta_n; polynomial zeta_powern_poly{ - libff::power(round_four_out.zeta, libff::bigint<1>(srs.num_gates + 2))}; + libff::power(zeta, libff::bigint<1>(srs.num_gates + 2))}; libfqfft::_polynomial_multiplication( t_mid_zeta_n, round_three_out.t_poly[mid], zeta_powern_poly); // t_hi(x) * zeta^(2(n+1)) polynomial t_hi_zeta_2n; - polynomial zeta_power2n_poly{libff::power( - round_four_out.zeta, libff::bigint<1>(2 * (srs.num_gates + 2)))}; + polynomial zeta_power2n_poly{ + libff::power(zeta, libff::bigint<1>(2 * (srs.num_gates + 2)))}; libfqfft::_polynomial_multiplication( t_hi_zeta_2n, round_three_out.t_poly[hi], zeta_power2n_poly); // -t_zeta as constant term polynomial @@ -924,7 +890,7 @@ round_five_out_t plonk_prover::round_five( } // compute 1/(X-zeta) * W_zeta - polynomial x_sub_zeta_poly{-round_four_out.zeta, Field(1)}; + polynomial x_sub_zeta_poly{-zeta, Field(1)}; libfqfft::_polynomial_division(W_zeta, remainder, W_zeta, x_sub_zeta_poly); assert(libfqfft::_is_zero(remainder)); @@ -942,7 +908,7 @@ round_five_out_t plonk_prover::round_five( // -zeta*srs.omega_roots; srs.omega_roots[base][1] = // srs.omega_roots_base polynomial x_sub_zeta_omega_roots{ - -(round_four_out.zeta * srs.omega_roots[base][1]), Field(1)}; + -(zeta * srs.omega_roots[base][1]), Field(1)}; // z(X) - z(zeta*srs.omega_roots) / X - // (zeta*srs.omega_roots) @@ -963,16 +929,10 @@ round_five_out_t plonk_prover::round_five( W_zeta_omega_at_secret = plonk_evaluate_poly_at_secret_G1( srs.secret_powers_g1, W_zeta_omega); - // Hashes of transcript (Fiat-Shamir heuristic) -- fixed to match - // the test vectors - u = example.u; - round_five_out_t round_five_out( - std::move(nu), std::move(r_zeta), std::move(W_zeta_at_secret), - std::move(W_zeta_omega_at_secret), - std::move(u)); + std::move(W_zeta_omega_at_secret)); return round_five_out; } @@ -1012,11 +972,21 @@ round_five_out_t plonk_prover::round_five( /// INPUT /// \param[in] srs: structured reference string containing also /// circuit-specific information +/// \param[in] transcript_hash: hashes of the communication transcript +/// after prover rounds 1,2,3,4,5. TODO: \attention +/// currently the structure is used as an input initialized +/// with hard-coded example values for debug purposes. In +/// the long run it should be modified to be used as an +/// output. More specifically, the hard-coded values should +/// be overwritten with the actual transcript hashes +/// produced after the respective rounds within \ref +/// compute_proof /// /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) template -plonk_proof plonk_prover::compute_proof(const srs &srs) +plonk_proof plonk_prover::compute_proof( + const srs &srs, transcript_hash_t &transcript_hash) { using Field = libff::Fr; @@ -1066,8 +1036,11 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) #endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); - round_two_out_t round_two_out = - plonk_prover::round_two(round_zero_out, round_one_out, witness, srs); + // - beta, gamma: permutation challenges - hashes of transcript of round 1 + const libff::Fr beta = transcript_hash.beta; + const libff::Fr gamma = transcript_hash.gamma; + round_two_out_t round_two_out = plonk_prover::round_two( + beta, gamma, round_zero_out, round_one_out, witness, srs); // Prover Round 2 output check against test vectors // TODO: move to unit test for round 2 #ifdef DEBUG_PLONK @@ -1084,8 +1057,10 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) #endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); + // - alpha: quotient challenge - hash of transcript of rounds 1,2 + libff::Fr alpha = transcript_hash.alpha; round_three_out_t round_three_out = plonk_prover::round_three( - round_zero_out, round_one_out, round_two_out, srs); + alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); // Prover Round 3 output check against test vectors // TODO: move to unit test for round 3 #ifdef DEBUG_PLONK @@ -1102,8 +1077,10 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) #endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); + // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 + libff::Fr zeta = transcript_hash.zeta; round_four_out_t round_four_out = - plonk_prover::round_four(round_one_out, round_three_out, srs); + plonk_prover::round_four(zeta, round_one_out, round_three_out, srs); // Prover Round 4 output check against test vectors // TODO: move to unit test for round 4 #ifdef DEBUG_PLONK @@ -1132,7 +1109,15 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) #endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); + /// - nu: opening challenge -- hash of transcript (denoted by v in + /// [GWC19]) + libff::Fr nu = transcript_hash.nu; round_five_out_t round_five_out = plonk_prover::round_five( + alpha, + beta, + gamma, + zeta, + nu, round_zero_out, round_one_out, round_two_out, @@ -1161,6 +1146,14 @@ plonk_proof plonk_prover::compute_proof(const srs &srs) assert(W_zeta_omega_at_secret_aff.Y == example.W_zeta_omega_at_secret[1]); #endif // #ifdef DEBUG_PLONK + // TODO: activate this part when we implement actual hashing of + // communication transcripts +#if 0 + // u: multipoint evaluation challenge -- hash of transcript from + // rounds 1,2,3,4,5 + libff::Fr u = transcript_hash.u; +#endif + // construct proof plonk_proof proof( round_one_out.W_polys_blinded_at_secret_g1, diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index d2191625f..94a074a07 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -200,6 +200,37 @@ template class plonk_keypair plonk_keypair(plonk_keypair &&other) = default; }; +/// Hashes of transcript after prover rounds 1,2,3,4,5 +template struct transcript_hash_t { + + /// - beta: permutation challenge - hashes of transcript after round 1 + libff::Fr beta; + /// - gamma: permutation challenge - hashes of transcript after round 1 + libff::Fr gamma; + /// - alpha: quotient challenge - hash of transcript after rounds 1,2 + libff::Fr alpha; + /// - zeta: evaluation challenge - hash of transcriptafter rounds 1,2,3 + libff::Fr zeta; + /// - nu: opening challenge - hash of transcript after rounds 1,2,3,4 + /// (denoted by v in [GWC19]) + libff::Fr nu; + /// - u: multipoint evaluation challenge -- hash of transcript after rounds + /// 1,2,3,4,5 + libff::Fr u; + + /// stuct constructor + transcript_hash_t( + libff::Fr &beta, + libff::Fr &gamma, + libff::Fr &alpha, + libff::Fr &zeta, + libff::Fr &nu, + libff::Fr &u) + : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) + { + } +}; + } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/srs.tcc" diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 033c5d7d5..339b01e11 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -330,11 +330,17 @@ template void test_plonk() // --- PROVER --- printf("[%s:%d] Prover...\n", __FILE__, __LINE__); - + transcript_hash_t transcript_hash( + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u); // initialize prover plonk_prover prover; // compute proof - plonk_proof proof = prover.compute_proof(srs); + plonk_proof proof = prover.compute_proof(srs, transcript_hash); // compare proof against test vector values (debug) ASSERT_EQ(proof.a_zeta, example.a_zeta); ASSERT_EQ(proof.b_zeta, example.b_zeta); From 42a979cfeae0325ca586474960ad8ef68470a9bc Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 15:21:41 +0100 Subject: [PATCH 039/154] plonk: added the witness vlaues to be passed as an input to prover::compute_proof by the caller. previously the witness was hard-coded from the example class which is used only for debug. --- libsnark/zk_proof_systems/plonk/prover.hpp | 4 +++- libsnark/zk_proof_systems/plonk/prover.tcc | 9 +++++---- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 4 +++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 15d79238c..5a9b439a3 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -519,7 +519,9 @@ template class plonk_prover /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) static plonk_proof compute_proof( - const srs &srs, transcript_hash_t &transcript_hash); + const srs &srs, + const std::vector &witness, + transcript_hash_t &transcript_hash); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 2838fb0a8..c167ac0dd 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -972,6 +972,8 @@ round_five_out_t plonk_prover::round_five( /// INPUT /// \param[in] srs: structured reference string containing also /// circuit-specific information +/// \param[in] witness: all internal values and public input +/// corresponding to the given circuit /// \param[in] transcript_hash: hashes of the communication transcript /// after prover rounds 1,2,3,4,5. TODO: \attention /// currently the structure is used as an input initialized @@ -986,10 +988,10 @@ round_five_out_t plonk_prover::round_five( /// \param[out] proof: SNARK proof Pi (see above) template plonk_proof plonk_prover::compute_proof( - const srs &srs, transcript_hash_t &transcript_hash) + const srs &srs, + const std::vector &witness, + transcript_hash_t &transcript_hash) { - using Field = libff::Fr; - // the example class is defined specifically for the BLS12-381 // curve, so make sure we are using this curve TODO: remove when // the implementation is stable and tested @@ -1001,7 +1003,6 @@ plonk_proof plonk_prover::compute_proof( } // initialize hard-coded values from example circuit plonk_example example; - std::vector witness = example.witness; // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 339b01e11..054410f42 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -340,7 +340,9 @@ template void test_plonk() // initialize prover plonk_prover prover; // compute proof - plonk_proof proof = prover.compute_proof(srs, transcript_hash); + std::vector witness = example.witness; + plonk_proof proof = + prover.compute_proof(srs, witness, transcript_hash); // compare proof against test vector values (debug) ASSERT_EQ(proof.a_zeta, example.a_zeta); ASSERT_EQ(proof.b_zeta, example.b_zeta); From f71b60f0ddea254b875b00fc3d30e29985ba6ee9 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 8 Jul 2022 16:05:52 +0100 Subject: [PATCH 040/154] plonk: implemented unit tests for prover rounds 1,2,3,4,5. --- libsnark/zk_proof_systems/plonk/prover.hpp | 25 +- libsnark/zk_proof_systems/plonk/prover.tcc | 244 ++------------ .../plonk/tests/test_plonk.cpp | 315 +++++++++++++++++- 3 files changed, 353 insertions(+), 231 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 5a9b439a3..5c3d53708 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -124,10 +124,6 @@ template struct round_zero_out_t { /// Prover round 1 output template struct round_one_out_t { - /// - blind_scalars: blinding scalars b1, b2, ..., b9 (only - /// b1-b6 used in round 1) - std::vector> blind_scalars; - /// - W_polys: witness polynomials (Lagrange interpolation of the /// witness values) std::vector>> W_polys; @@ -142,12 +138,10 @@ template struct round_one_out_t { /// stuct constructor round_one_out_t( - const std::vector> &&blind_scalars, const std::vector>> &&W_polys, const std::vector>> &&W_polys_blinded, const std::vector> &&W_polys_blinded_at_secret_g1) - : blind_scalars(blind_scalars) - , W_polys(W_polys) + : W_polys(W_polys) , W_polys_blinded(W_polys_blinded) , W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) { @@ -307,13 +301,13 @@ template class plonk_prover /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) /// \param[in] null_poly: 0 polynomial (from round 0) /// \param[in] neg_one_poly: -1 polynomial (from round 0) + /// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only + /// b1-b6 used in round 1) /// \param[in] witness: witness values /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] blind_scalars: blinding scalars b1, b2, ..., b9 (only - /// b1-b6 used in round 1) /// \param[out] W_polys: witness polynomials (Lagrange interpolation /// of the witness values) /// \param[out] W_polys_blinded: blinded witness polynomials @@ -322,15 +316,16 @@ template class plonk_prover /// [a]_1, [b]_1, [c]_1 in [GWC19] static round_one_out_t round_one( const round_zero_out_t &round_zero_out, + const std::vector> blind_scalars, const std::vector> &witness, const srs &srs); /// Prover Round 2 /// /// INPUT - /// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only - /// b7,b8,b9 used in round 2) (from round 1) /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) + /// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only + /// b7,b8,b9 used in round 2) /// \param[in] witness: witness values /// \param[in] srs: structured reference string containing also /// circuit-specific information @@ -343,7 +338,7 @@ template class plonk_prover const libff::Fr beta, const libff::Fr gamma, const round_zero_out_t &round_zero_out, - const round_one_out_t &round_one_out, + const std::vector> blind_scalars, const std::vector> &witness, const srs &srs); @@ -506,6 +501,11 @@ template class plonk_prover /// INPUT /// \param[in] srs: structured reference string containing also /// circuit-specific information + /// \param[in] witness: all internal values and public input + /// corresponding to the given circuit + /// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 + /// used in prover rounds 1 and 2 (see Sect. 8.3, roumds + /// 1,2 [GWC19]) /// \param[in] transcript_hash: hashes of the communication transcript /// after prover rounds 1,2,3,4,5. TODO: \attention /// currently the structure is used as an input initialized @@ -521,6 +521,7 @@ template class plonk_prover static plonk_proof compute_proof( const srs &srs, const std::vector &witness, + const std::vector> blind_scalars, transcript_hash_t &transcript_hash); }; diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index c167ac0dd..5fe3522f3 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -58,13 +58,13 @@ round_zero_out_t plonk_prover::round_zero(const srs srs) /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) /// \param[in] null_poly: 0 polynomial (from round 0) /// \param[in] neg_one_poly: -1 polynomial (from round 0) +/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +/// b1-b6 used in round 1) /// \param[in] witness: witness values /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT -/// \param[out] blind_scalars: blinding scalars b1, b2, ..., b9 (only -/// b1-b6 used in round 1) /// \param[out] W_polys: witness polynomials (Lagrange interpolation /// of the witness values) /// \param[out] W_polys_blinded: blinded witness polynomials @@ -74,26 +74,14 @@ round_zero_out_t plonk_prover::round_zero(const srs srs) template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, + const std::vector> blind_scalars, const std::vector> &witness, const srs &srs) { using Field = libff::Fr; const size_t nwitness = NUM_HSETS; - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve. TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // initialize hard-coded values from example circuit - plonk_example example; - // output from round 1 - std::vector> blind_scalars; std::vector>> W_polys; std::vector>> W_polys_blinded; std::vector> W_polys_blinded_at_secret_g1; @@ -108,19 +96,7 @@ round_one_out_t plonk_prover::round_one( std::vector W_points(begin, end); plonk_interpolate_polynomial_from_points(W_points, W_polys[i]); } - // TODO: move to unit test for - // plonk_interpolate_polynomial_from_points -#ifdef DEBUG_PLONK - for (size_t i = 0; i < nwitness; ++i) { - printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); - print_vector(W_polys[i]); - assert(W_polys[i] == example.W_polys[i]); - } -#endif // #ifdef DEBUG_PLONK - // hard-coded values for the "random" blinding constants from - // example circuit - blind_scalars = example.prover_blind_scalars; // represent the blinding scalars b1, b2, ..., b9 as polynomials std::vector> blind_polys{ {blind_scalars[1], blind_scalars[0]}, // b1 + b0 X @@ -143,7 +119,6 @@ round_one_out_t plonk_prover::round_one( srs.secret_powers_g1, W_polys_blinded, W_polys_blinded_at_secret_g1); round_one_out_t round_one_out( - std::move(blind_scalars), std::move(W_polys), std::move(W_polys_blinded), std::move(W_polys_blinded_at_secret_g1)); @@ -154,9 +129,9 @@ round_one_out_t plonk_prover::round_one( /// Prover Round 2 /// /// INPUT -/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -/// b7,b8,b9 used in round 2) (from round 1) /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +/// b7,b8,b9 used in round 2) /// \param[in] witness: witness values /// \param[in] srs: structured reference string containing also /// circuit-specific information @@ -170,13 +145,11 @@ round_two_out_t plonk_prover::round_two( const libff::Fr beta, const libff::Fr gamma, const round_zero_out_t &round_zero_out, - const round_one_out_t &round_one_out, + const std::vector> blind_scalars, const std::vector> &witness, const srs &srs) { using Field = libff::Fr; - // initialize hard-coded values from example circuit - plonk_example example; polynomial> z_poly; libff::G1 z_poly_at_secret_g1; @@ -185,9 +158,7 @@ round_two_out_t plonk_prover::round_two( // blinding polynomial: b8 + b7 X + b6 X^2 std::vector z1_blind_poly{ - round_one_out.blind_scalars[8], - round_one_out.blind_scalars[7], - round_one_out.blind_scalars[6]}; + blind_scalars[8], blind_scalars[7], blind_scalars[6]}; // multiply by the vanishing polynomial: z1 = z1 * this->zh_poly libfqfft::_polynomial_multiplication( z1_blind_poly, z1_blind_poly, round_zero_out.zh_poly); @@ -205,13 +176,6 @@ round_two_out_t plonk_prover::round_two( polynomial A_poly(srs.num_gates); plonk_interpolate_polynomial_from_points(A_vector, A_poly); - // TODO: move to unit test for - // plonk_interpolate_polynomial_from_points -#ifdef DEBUG_PLONK - printf("[%s:%d] A_poly\n", __FILE__, __LINE__); - print_vector(A_poly); - assert(A_poly == example.A_poly); -#endif // #ifdef DEBUG_PLONK // add blinding polynomial z_1 to the accumulator polynomial A_poly libfqfft::_polynomial_addition(z_poly, z1_blind_poly, A_poly); @@ -258,18 +222,6 @@ round_three_out_t plonk_prover::round_three( using Field = libff::Fr; int num_hgen = NUM_HSETS; - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // initialize hard-coded values from example circuit - plonk_example example; - // output from round 3 std::vector> z_poly_xomega; std::vector>> t_poly; @@ -447,16 +399,15 @@ round_three_out_t plonk_prover::round_three( polynomial remainder; libfqfft::_polynomial_division( t_poly_long, remainder, t_poly_long, round_zero_out.zh_poly); - - // TODO: move to unit test for round_three() -#ifdef DEBUG_PLONK - printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); - print_vector(t_poly_long); - assert(t_poly_long == example.t_poly_long); - printf("[%s:%d] remainder\n", __FILE__, __LINE__); - print_vector(remainder); -#endif // #ifdef DEBUG_PLONK - assert(libfqfft::_is_zero(remainder)); + try { + bool b_zero_remainder = libfqfft::_is_zero(remainder); + if (!b_zero_remainder) { + throw std::logic_error("Non-zero remainder in polynomial division"); + } + } catch (const std::logic_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } // break this->t_poly_long into three parts: lo, mid, hi, each of degree // 7. note: (srs.num_gates+3) is the length of the CRS = @@ -471,14 +422,7 @@ round_three_out_t plonk_prover::round_three( std::vector tmp(begin, end); t_poly[i] = tmp; } - // TODO: move to unit test for round_three() -#ifdef DEBUG_PLONK - for (int i = 0; i < num_hgen; ++i) { - printf("[%s:%d] t_poly[%d]\n", __FILE__, __LINE__, i); - print_vector(t_poly[i]); - assert(t_poly[i] == example.t_poly[i]); - } -#endif // #ifdef DEBUG_PLONK + // evaluate each part of t_poly in the secret input t_poly_at_secret_g1.resize(num_hgen); for (int i = 0; i < num_hgen; ++i) { @@ -534,17 +478,6 @@ round_four_out_t plonk_prover::round_four( const srs &srs) { using Field = libff::Fr; - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // initialize hard-coded values from example circuit - plonk_example example; // output from round 4 libff::Fr a_zeta; @@ -645,18 +578,6 @@ round_five_out_t plonk_prover::round_five( using Field = libff::Fr; polynomial remainder; - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // initialize hard-coded values from example circuit - plonk_example example; - // output from round 5 libff::Fr r_zeta; libff::G1 W_zeta_at_secret; @@ -749,8 +670,8 @@ round_five_out_t plonk_prover::round_five( libfqfft::_polynomial_addition(r_poly, r_poly, r_part[2]); libfqfft::_polynomial_addition(r_poly, r_poly, r_part[3]); - // TODO: move to unit test for compyting r_poly -#ifdef DEBUG_PLONK + // TODO: make a separate unit test for r_poly +#if 0 assert(r_poly == example.r_poly); #endif // #ifdef DEBUG_PLONK @@ -761,11 +682,6 @@ round_five_out_t plonk_prover::round_five( // side r_zeta = libfqfft::evaluate_polynomial(r_poly.size(), r_poly, zeta); - // TODO: move to unit test for compyting r_zeta -#ifdef DEBUG_PLONK - assert(r_zeta == example.r_zeta); -#endif // #ifdef DEBUG_PLONK - // W_zeta polynomial is of degree 6 in the random element nu and // hence has 7 terms std::vector> W_zeta_part(7); @@ -916,8 +832,8 @@ round_five_out_t plonk_prover::round_five( W_zeta_omega, remainder, W_zeta_omega, x_sub_zeta_omega_roots); assert(libfqfft::_is_zero(remainder)); - // TODO: move to unit test for round_five -#ifdef DEBUG_PLONK + // TODO: make a separate unit test for W_zeta, W_zeta_omega +#if 0 assert(W_zeta == example.W_zeta); assert(W_zeta_omega == example.W_zeta_omega); #endif // #ifdef DEBUG_PLONK @@ -974,6 +890,9 @@ round_five_out_t plonk_prover::round_five( /// circuit-specific information /// \param[in] witness: all internal values and public input /// corresponding to the given circuit +/// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 +/// used in prover rounds 1 and 2 (see Sect. 8.3, roumds +/// 1,2 [GWC19]) /// \param[in] transcript_hash: hashes of the communication transcript /// after prover rounds 1,2,3,4,5. TODO: \attention /// currently the structure is used as an input initialized @@ -990,20 +909,9 @@ template plonk_proof plonk_prover::compute_proof( const srs &srs, const std::vector &witness, + const std::vector> blind_scalars, transcript_hash_t &transcript_hash) { - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // initialize hard-coded values from example circuit - plonk_example example; - // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); @@ -1011,103 +919,26 @@ plonk_proof plonk_prover::compute_proof( // Prover Round 1 printf("[%s:%d] Prover Round 1...\n", __FILE__, __LINE__); round_one_out_t round_one_out = - plonk_prover::round_one(round_zero_out, witness, srs); - // Prover Round 1 output check against test vectors - // TODO: move to unit test for round 1 -#ifdef DEBUG_PLONK - for (int i = 0; i < (int)NUM_HSETS; ++i) { - printf("[%s:%d] W_polys_blinded[%d]\n", __FILE__, __LINE__, i); - print_vector(round_one_out.W_polys_blinded[i]); - assert(round_one_out.W_polys_blinded[i] == example.W_polys_blinded[i]); - } - printf("[%s:%d] Output from Round 1\n", __FILE__, __LINE__); - for (int i = 0; i < (int)NUM_HSETS; ++i) { - printf("W_polys_at_secret_g1[%d]\n", i); - round_one_out.W_polys_blinded_at_secret_g1[i].print(); - libff::G1 W_polys_blinded_at_secret_g1_i( - round_one_out.W_polys_blinded_at_secret_g1[i]); - W_polys_blinded_at_secret_g1_i.to_affine_coordinates(); - assert( - W_polys_blinded_at_secret_g1_i.X == - example.W_polys_blinded_at_secret_g1[i][0]); - assert( - W_polys_blinded_at_secret_g1_i.Y == - example.W_polys_blinded_at_secret_g1[i][1]); - } -#endif // #ifdef DEBUG_PLONK + plonk_prover::round_one(round_zero_out, blind_scalars, witness, srs); printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); // - beta, gamma: permutation challenges - hashes of transcript of round 1 const libff::Fr beta = transcript_hash.beta; const libff::Fr gamma = transcript_hash.gamma; round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, round_one_out, witness, srs); - // Prover Round 2 output check against test vectors - // TODO: move to unit test for round 2 -#ifdef DEBUG_PLONK - printf("[%s:%d] z_poly\n", __FILE__, __LINE__); - print_vector(round_two_out.z_poly); - assert(round_two_out.z_poly == example.z_poly); - printf("[%s:%d] Output from Round 2\n", __FILE__, __LINE__); - printf("[%s:%d] z_poly_at_secret_g1\n", __FILE__, __LINE__); - round_two_out.z_poly_at_secret_g1.print(); - libff::G1 z_poly_at_secret_g1_aff(round_two_out.z_poly_at_secret_g1); - z_poly_at_secret_g1_aff.to_affine_coordinates(); - assert(z_poly_at_secret_g1_aff.X == example.z_poly_at_secret_g1[0]); - assert(z_poly_at_secret_g1_aff.Y == example.z_poly_at_secret_g1[1]); -#endif // #ifdef DEBUG_PLONK + beta, gamma, round_zero_out, blind_scalars, witness, srs); printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); // - alpha: quotient challenge - hash of transcript of rounds 1,2 libff::Fr alpha = transcript_hash.alpha; round_three_out_t round_three_out = plonk_prover::round_three( alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); - // Prover Round 3 output check against test vectors - // TODO: move to unit test for round 3 -#ifdef DEBUG_PLONK - printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); - for (int i = 0; i < (int)NUM_HSETS; ++i) { - printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); - round_three_out.t_poly_at_secret_g1[i].print(); - libff::G1 t_poly_at_secret_g1_i( - round_three_out.t_poly_at_secret_g1[i]); - t_poly_at_secret_g1_i.to_affine_coordinates(); - assert(t_poly_at_secret_g1_i.X == example.t_poly_at_secret_g1[i][0]); - assert(t_poly_at_secret_g1_i.Y == example.t_poly_at_secret_g1[i][1]); - } -#endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 libff::Fr zeta = transcript_hash.zeta; round_four_out_t round_four_out = plonk_prover::round_four(zeta, round_one_out, round_three_out, srs); - // Prover Round 4 output check against test vectors - // TODO: move to unit test for round 4 -#ifdef DEBUG_PLONK - printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); - printf("a_zeta "); - round_four_out.a_zeta.print(); - assert(round_four_out.a_zeta == example.a_zeta); - printf("b_zeta "); - round_four_out.b_zeta.print(); - assert(round_four_out.b_zeta == example.b_zeta); - printf("c_zeta "); - round_four_out.c_zeta.print(); - assert(round_four_out.c_zeta == example.c_zeta); - printf("S_0_zeta "); - round_four_out.S_0_zeta.print(); - assert(round_four_out.S_0_zeta == example.S_0_zeta); - printf("S_1_zeta "); - round_four_out.S_1_zeta.print(); - assert(round_four_out.S_1_zeta == example.S_1_zeta); - printf("t_zeta "); - round_four_out.t_zeta.print(); - assert(round_four_out.t_zeta == example.t_zeta); - printf("z_poly_xomega_zeta "); - round_four_out.z_poly_xomega_zeta.print(); - assert(round_four_out.z_poly_xomega_zeta == example.z_poly_xomega_zeta); -#endif // #ifdef DEBUG_PLONK printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); /// - nu: opening challenge -- hash of transcript (denoted by v in @@ -1125,27 +956,6 @@ plonk_proof plonk_prover::compute_proof( round_three_out, round_four_out, srs); - // Prover Round 5 output check against test vectors - // TODO: move to unit test for round 5 -#ifdef DEBUG_PLONK - printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); - printf("r_zeta "); - round_five_out.r_zeta.print(); - assert(round_five_out.r_zeta == example.r_zeta); - printf("[%s:%d] W_zeta_at_secret \n", __FILE__, __LINE__); - round_five_out.W_zeta_at_secret.print(); - libff::G1 W_zeta_at_secret_aff(round_five_out.W_zeta_at_secret); - W_zeta_at_secret_aff.to_affine_coordinates(); - assert(W_zeta_at_secret_aff.X == example.W_zeta_at_secret[0]); - assert(W_zeta_at_secret_aff.Y == example.W_zeta_at_secret[1]); - printf("[%s:%d] W_zeta_omega_at_secret \n", __FILE__, __LINE__); - round_five_out.W_zeta_omega_at_secret.print(); - libff::G1 W_zeta_omega_at_secret_aff( - round_five_out.W_zeta_omega_at_secret); - W_zeta_omega_at_secret_aff.to_affine_coordinates(); - assert(W_zeta_omega_at_secret_aff.X == example.W_zeta_omega_at_secret[0]); - assert(W_zeta_omega_at_secret_aff.Y == example.W_zeta_omega_at_secret[1]); -#endif // #ifdef DEBUG_PLONK // TODO: activate this part when we implement actual hashing of // communication transcripts diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 054410f42..3b0752691 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -260,6 +260,310 @@ circuit_t plonk_circuit_description_from_example( return circuit; } +template +void test_plonk_compute_accumulator( + const plonk_example &example, + const libff::Fr &beta, + const libff::Fr &gamma, + const std::vector> &witness, + const srs &srs) +{ + using Field = libff::Fr; + // A[0] = 1; ... A[i] = computed from (i-1) + std::vector A_vector(srs.num_gates, Field(0)); + plonk_compute_accumulator( + srs.num_gates, + beta, + gamma, + witness, + srs.H_gen, + srs.H_gen_permute, + A_vector); + polynomial A_poly(srs.num_gates); + plonk_interpolate_polynomial_from_points(A_vector, A_poly); + + // initialize hard-coded values from example circuit + printf("[%s:%d] A_poly\n", __FILE__, __LINE__); + print_vector(A_poly); + ASSERT_EQ(A_poly, example.A_poly); +} + +template +void test_plonk_prover_round_one( + const plonk_example &example, + const round_zero_out_t &round_zero_out, + const std::vector> &witness, + const srs &srs) +{ + std::vector> blind_scalars = example.prover_blind_scalars; + round_one_out_t round_one_out = plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs); + for (int i = 0; i < (int)NUM_HSETS; ++i) { + printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); + print_vector(round_one_out.W_polys[i]); + ASSERT_EQ(round_one_out.W_polys[i], example.W_polys[i]); + } + for (int i = 0; i < (int)NUM_HSETS; ++i) { + printf("[%s:%d] W_polys_blinded[%d]\n", __FILE__, __LINE__, i); + print_vector(round_one_out.W_polys_blinded[i]); + ASSERT_EQ(round_one_out.W_polys_blinded[i], example.W_polys_blinded[i]); + } + printf("[%s:%d] Output from Round 1\n", __FILE__, __LINE__); + for (int i = 0; i < (int)NUM_HSETS; ++i) { + printf("W_polys_at_secret_g1[%d]\n", i); + round_one_out.W_polys_blinded_at_secret_g1[i].print(); + libff::G1 W_polys_blinded_at_secret_g1_i( + round_one_out.W_polys_blinded_at_secret_g1[i]); + W_polys_blinded_at_secret_g1_i.to_affine_coordinates(); + ASSERT_EQ( + W_polys_blinded_at_secret_g1_i.X, + example.W_polys_blinded_at_secret_g1[i][0]); + ASSERT_EQ( + W_polys_blinded_at_secret_g1_i.Y, + example.W_polys_blinded_at_secret_g1[i][1]); + } +} + +template +void test_plonk_prover_round_two( + const plonk_example &example, + const libff::Fr &beta, + const libff::Fr &gamma, + const round_zero_out_t &round_zero_out, + const std::vector> &blind_scalars, + const std::vector> &witness, + const srs &srs) +{ + round_two_out_t round_two_out = plonk_prover::round_two( + beta, gamma, round_zero_out, blind_scalars, witness, srs); + printf("[%s:%d] z_poly\n", __FILE__, __LINE__); + print_vector(round_two_out.z_poly); + ASSERT_EQ(round_two_out.z_poly, example.z_poly); + printf("[%s:%d] Output from Round 2\n", __FILE__, __LINE__); + printf("[%s:%d] z_poly_at_secret_g1\n", __FILE__, __LINE__); + round_two_out.z_poly_at_secret_g1.print(); + libff::G1 z_poly_at_secret_g1_aff(round_two_out.z_poly_at_secret_g1); + z_poly_at_secret_g1_aff.to_affine_coordinates(); + ASSERT_EQ(z_poly_at_secret_g1_aff.X, example.z_poly_at_secret_g1[0]); + ASSERT_EQ(z_poly_at_secret_g1_aff.Y, example.z_poly_at_secret_g1[1]); +} + +template +void test_plonk_prover_round_three( + const plonk_example &example, + const libff::Fr &alpha, + const libff::Fr &beta, + const libff::Fr &gamma, + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const round_two_out_t &round_two_out, + const srs &srs) +{ + round_three_out_t round_three_out = plonk_prover::round_three( + alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); + printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); + print_vector(round_three_out.t_poly_long); + ASSERT_EQ(round_three_out.t_poly_long, example.t_poly_long); + for (int i = 0; i < (int)NUM_HSETS; ++i) { + printf("[%s:%d] t_poly[%d]\n", __FILE__, __LINE__, i); + print_vector(round_three_out.t_poly[i]); + ASSERT_EQ(round_three_out.t_poly[i], example.t_poly[i]); + } + for (int i = 0; i < (int)NUM_HSETS; ++i) { + printf("[%s:%d] t_poly_at_secret_g1[%d]\n", __FILE__, __LINE__, i); + round_three_out.t_poly_at_secret_g1[i].print(); + libff::G1 t_poly_at_secret_g1_i( + round_three_out.t_poly_at_secret_g1[i]); + t_poly_at_secret_g1_i.to_affine_coordinates(); + ASSERT_EQ(t_poly_at_secret_g1_i.X, example.t_poly_at_secret_g1[i][0]); + ASSERT_EQ(t_poly_at_secret_g1_i.Y, example.t_poly_at_secret_g1[i][1]); + } +} + +template +void test_plonk_prover_round_four( + const plonk_example &example, + const libff::Fr &zeta, + const round_one_out_t &round_one_out, + const round_three_out_t &round_three_out, + const srs &srs) +{ + round_four_out_t round_four_out = plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs); + // Prover Round 4 output check against test vectors + printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); + printf("a_zeta "); + round_four_out.a_zeta.print(); + ASSERT_EQ(round_four_out.a_zeta, example.a_zeta); + printf("b_zeta "); + round_four_out.b_zeta.print(); + ASSERT_EQ(round_four_out.b_zeta, example.b_zeta); + printf("c_zeta "); + round_four_out.c_zeta.print(); + ASSERT_EQ(round_four_out.c_zeta, example.c_zeta); + printf("S_0_zeta "); + round_four_out.S_0_zeta.print(); + ASSERT_EQ(round_four_out.S_0_zeta, example.S_0_zeta); + printf("S_1_zeta "); + round_four_out.S_1_zeta.print(); + ASSERT_EQ(round_four_out.S_1_zeta, example.S_1_zeta); + printf("t_zeta "); + round_four_out.t_zeta.print(); + ASSERT_EQ(round_four_out.t_zeta, example.t_zeta); + printf("z_poly_xomega_zeta "); + round_four_out.z_poly_xomega_zeta.print(); + ASSERT_EQ(round_four_out.z_poly_xomega_zeta, example.z_poly_xomega_zeta); +} + +template +void test_plonk_prover_round_five( + const plonk_example &example, + const libff::Fr &alpha, + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &zeta, + const libff::Fr &nu, + const round_zero_out_t &round_zero_out, + const round_one_out_t &round_one_out, + const round_two_out_t &round_two_out, + const round_three_out_t &round_three_out, + const round_four_out_t &round_four_out, + const srs &srs) +{ + round_five_out_t round_five_out = plonk_prover::round_five( + alpha, + beta, + gamma, + zeta, + nu, + round_zero_out, + round_one_out, + round_two_out, + round_three_out, + round_four_out, + srs); + + printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); + printf("r_zeta "); + round_five_out.r_zeta.print(); + ASSERT_EQ(round_five_out.r_zeta, example.r_zeta); + printf("[%s:%d] W_zeta_at_secret \n", __FILE__, __LINE__); + round_five_out.W_zeta_at_secret.print(); + libff::G1 W_zeta_at_secret_aff(round_five_out.W_zeta_at_secret); + W_zeta_at_secret_aff.to_affine_coordinates(); + ASSERT_EQ(W_zeta_at_secret_aff.X, example.W_zeta_at_secret[0]); + ASSERT_EQ(W_zeta_at_secret_aff.Y, example.W_zeta_at_secret[1]); + printf("[%s:%d] W_zeta_omega_at_secret \n", __FILE__, __LINE__); + round_five_out.W_zeta_omega_at_secret.print(); + libff::G1 W_zeta_omega_at_secret_aff( + round_five_out.W_zeta_omega_at_secret); + W_zeta_omega_at_secret_aff.to_affine_coordinates(); + ASSERT_EQ(W_zeta_omega_at_secret_aff.X, example.W_zeta_omega_at_secret[0]); + ASSERT_EQ(W_zeta_omega_at_secret_aff.Y, example.W_zeta_omega_at_secret[1]); +} + +template void test_plonk_prover_rounds() +{ + using Field = libff::Fr; + + // example test values are defined specifically for the BLS12-381 + // curve, so make sure we are using this curve + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + + ppT::init_public_params(); + + // load test vector values from example circuit + plonk_example example; + // random hidden element secret (toxic waste) + Field secret = example.secret; + // example witness + std::vector witness = example.witness; + // get hard-coded values for the transcipt hash + transcript_hash_t transcript_hash( + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u); + // hard-coded values for the "random" blinding constants from + // example circuit + std::vector> blind_scalars = example.prover_blind_scalars; + // prepare srs + size_t max_degree = 254; + usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); + circuit_t circuit = + plonk_circuit_description_from_example(example); + srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + + // Prover Round 0 (initialization) + round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); + + // Unit test Prover Round 1 + printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); + test_plonk_prover_round_one(example, round_zero_out, witness, srs); + + // Unit test Prover Round 2 + printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); + const libff::Fr beta = transcript_hash.beta; + const libff::Fr gamma = transcript_hash.gamma; + test_plonk_prover_round_two( + example, beta, gamma, round_zero_out, blind_scalars, witness, srs); + + // Unit test plonk_compute_accumulator + test_plonk_compute_accumulator(example, beta, gamma, witness, srs); + + // Unit test Prover Round 3 + printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); + round_one_out_t round_one_out = plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs); + round_two_out_t round_two_out = plonk_prover::round_two( + beta, gamma, round_zero_out, blind_scalars, witness, srs); + libff::Fr alpha = transcript_hash.alpha; + test_plonk_prover_round_three( + example, + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs); + + // Unit test Prover Round 4 + printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); + round_three_out_t round_three_out = plonk_prover::round_three( + alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + libff::Fr zeta = transcript_hash.zeta; + test_plonk_prover_round_four( + example, zeta, round_one_out, round_three_out, srs); + + // Unit test Prover Round 5 + printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); + round_four_out_t round_four_out = plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs); + libff::Fr nu = transcript_hash.nu; + test_plonk_prover_round_five( + example, + alpha, + beta, + gamma, + zeta, + nu, + round_zero_out, + round_one_out, + round_two_out, + round_three_out, + round_four_out, + srs); +} + template void test_plonk() { #ifndef DEBUG_PLONK @@ -341,8 +645,11 @@ template void test_plonk() plonk_prover prover; // compute proof std::vector witness = example.witness; + // hard-coded values for the "random" blinding constants from + // example circuit + std::vector> blind_scalars = example.prover_blind_scalars; plonk_proof proof = - prover.compute_proof(srs, witness, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, transcript_hash); // compare proof against test vector values (debug) ASSERT_EQ(proof.a_zeta, example.a_zeta); ASSERT_EQ(proof.b_zeta, example.b_zeta); @@ -412,6 +719,10 @@ template void test_plonk() // end } -TEST(TestPlonk, BLS12_381) { test_plonk(); } +TEST(TestPlonk, BLS12_381) +{ + test_plonk(); + test_plonk_prover_rounds(); +} } // namespace libsnark From a35d1cbabad3513f520eebac08be2ea392ecdebb Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 11 Jul 2022 08:48:51 +0100 Subject: [PATCH 041/154] plonk: broke down test_plonk into three separate unit tests: test_plonk_srs, test_plonk_prover, test_plonk_verifier --- .../plonk/tests/test_plonk.cpp | 160 ++++++++++++------ 1 file changed, 105 insertions(+), 55 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 3b0752691..75a6eca31 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -21,6 +21,8 @@ namespace libsnark { +#define PLONK_MAX_DEGREE 245 + // Manipulate elements of a valid proof to assert that proof // verification fails // @@ -484,6 +486,9 @@ template void test_plonk_prover_rounds() Field secret = example.secret; // example witness std::vector witness = example.witness; + // example circuit + circuit_t circuit = + plonk_circuit_description_from_example(example); // get hard-coded values for the transcipt hash transcript_hash_t transcript_hash( example.beta, @@ -495,11 +500,11 @@ template void test_plonk_prover_rounds() // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; + // maximum degree of the encoded monomials in the usrs + size_t max_degree = PLONK_MAX_DEGREE; + // prepare srs - size_t max_degree = 254; usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - circuit_t circuit = - plonk_circuit_description_from_example(example); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // Prover Round 0 (initialization) @@ -564,27 +569,11 @@ template void test_plonk_prover_rounds() srs); } -template void test_plonk() +template void test_plonk_srs() { -#ifndef DEBUG_PLONK - printf("[%s:%d] WARNING! DEBUG_PLONK info disabled.\n", __FILE__, __LINE__); - // assert(0); -#endif // #ifndef DEBUG_PLONK - - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - - // Execute all tests for the given curve. - ppT::init_public_params(); - using Field = libff::Fr; - // --- TEST VECTORS --- - // the example class is defined specifically for the BLS12-381 + // example test values are defined specifically for the BLS12-381 // curve, so make sure we are using this curve try { plonk_exception_assert_curve_bls12_381(); @@ -592,32 +581,26 @@ template void test_plonk() std::cout << "Error: " << e.what() << "\n"; exit(EXIT_FAILURE); } + ppT::init_public_params(); // load test vector values from example circuit plonk_example example; - - // --- SETUP --- - printf("[%s:%d] Setup...\n", __FILE__, __LINE__); - // random hidden element secret (toxic waste). we fix it to a - // constant in order to match against the test vectors + // random hidden element secret (toxic waste) Field secret = example.secret; -#ifdef DEBUG_PLONK - printf("[%s:%d] secret ", __FILE__, __LINE__); - secret.print(); -#endif // #ifdef DEBUG_PLONK + // example circuit + circuit_t circuit = + plonk_circuit_description_from_example(example); + // maximum degree of the encoded monomials in the usrs + size_t max_degree = PLONK_MAX_DEGREE; - printf("[%s:%d] SRS...\n", __FILE__, __LINE__); // --- USRS --- - // maximum degree of the encoded monomials in the usrs - size_t max_degree = 254; // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - // --- circuit --- - circuit_t circuit = - plonk_circuit_description_from_example(example); // --- SRS --- srs srs = plonk_srs_derive_from_usrs(usrs, circuit); - // sompare SRS against reference test values + // compare SRS against reference test values + printf("[%s:%d] secret ", __FILE__, __LINE__); + secret.print(); for (int i = 0; i < (int)srs.num_gates + 3; ++i) { printf("secret_power_G1[%2d] ", i); srs.secret_powers_g1[i].print(); @@ -631,9 +614,31 @@ template void test_plonk() printf("secret_power_G2[%2d] ", i); srs.secret_powers_g2[i].print(); } +} - // --- PROVER --- - printf("[%s:%d] Prover...\n", __FILE__, __LINE__); +template void test_plonk_prover() +{ + using Field = libff::Fr; + + // example test values are defined specifically for the BLS12-381 + // curve, so make sure we are using this curve + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + ppT::init_public_params(); + // load test vector values from example circuit + plonk_example example; + // random hidden element secret (toxic waste) + Field secret = example.secret; + // example witness + std::vector witness = example.witness; + // example circuit + circuit_t circuit = + plonk_circuit_description_from_example(example); + // get hard-coded values for the transcipt hash transcript_hash_t transcript_hash( example.beta, example.gamma, @@ -641,13 +646,19 @@ template void test_plonk() example.zeta, example.nu, example.u); - // initialize prover - plonk_prover prover; - // compute proof - std::vector witness = example.witness; // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; + // maximum degree of the encoded monomials in the usrs + size_t max_degree = PLONK_MAX_DEGREE; + + // prepare srs + usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); + srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + + // initialize prover + plonk_prover prover; + // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, transcript_hash); // compare proof against test vector values (debug) @@ -694,9 +705,54 @@ template void test_plonk() W_zeta_omega_at_secret_aff.to_affine_coordinates(); ASSERT_EQ(W_zeta_omega_at_secret_aff.X, example.W_zeta_omega_at_secret[0]); ASSERT_EQ(W_zeta_omega_at_secret_aff.Y, example.W_zeta_omega_at_secret[1]); +} + +template void test_plonk_verifier() +{ + using Field = libff::Fr; + + // example test values are defined specifically for the BLS12-381 + // curve, so make sure we are using this curve + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + ppT::init_public_params(); + // load test vector values from example circuit + plonk_example example; + // random hidden element secret (toxic waste) + Field secret = example.secret; + // example witness + std::vector witness = example.witness; + // example circuit + circuit_t circuit = + plonk_circuit_description_from_example(example); + // get hard-coded values for the transcipt hash + transcript_hash_t transcript_hash( + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u); + // hard-coded values for the "random" blinding constants from + // example circuit + std::vector> blind_scalars = example.prover_blind_scalars; + // maximum degree of the encoded monomials in the usrs + size_t max_degree = PLONK_MAX_DEGREE; + + // prepare srs + usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); + srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + + // initialize prover + plonk_prover prover; + // compute proof + plonk_proof proof = + prover.compute_proof(srs, witness, blind_scalars, transcript_hash); - // --- VERIFIER --- - printf("[%s:%d] Verifier...\n", __FILE__, __LINE__); // initialize verifier plonk_verifier verifier; // verify proof @@ -705,24 +761,18 @@ template void test_plonk() // assert that proof verification fails when the proof is // manipulated. must be executed when DEBUG_PLONK is not defined to // disable certain assert-s that may fail before the verify - // invalid proof test + // invalid proof test TODO: remove DEBUG guards #ifndef DEBUG_PLONK test_verify_invalid_proof(proof, srs); #endif // #ifndef DEBUG_PLONK -#ifndef DEBUG_PLONK - printf( - "[%s:%d] WARNING! DEBUG_PLONK info was disabled.\n", - __FILE__, - __LINE__); -#endif // #ifndef DEBUG_PLONK - printf("[%s:%d] Test OK\n", __FILE__, __LINE__); - // end } TEST(TestPlonk, BLS12_381) { - test_plonk(); + test_plonk_srs(); test_plonk_prover_rounds(); + test_plonk_prover(); + test_plonk_verifier(); } } // namespace libsnark From 7ff9c7feaba3eb83eca94c1291212129e076958d Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 11 Jul 2022 09:21:02 +0100 Subject: [PATCH 042/154] plonk: added the hashes of the communication transcript (challenges alpha, beta, gamma, etc.) as inputs to verifier verify_proof and step_four to be computed by the caller. previously it was hard-coded from the example test-vector values. the goal is to make the verifier implementation independent of the example test vector values. --- .../plonk/tests/test_plonk.cpp | 32 ++++++------ libsnark/zk_proof_systems/plonk/verifier.hpp | 25 +++++++-- libsnark/zk_proof_systems/plonk/verifier.tcc | 51 +++++++++++-------- 3 files changed, 67 insertions(+), 41 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 75a6eca31..f83d0341c 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -36,7 +36,9 @@ namespace libsnark // r_zeta (*)) template void test_verify_invalid_proof( - const plonk_proof &valid_proof, const srs &srs) + const plonk_proof &valid_proof, + const srs &srs, + transcript_hash_t &transcript_hash) { // initialize verifier plonk_verifier verifier; @@ -57,14 +59,14 @@ void test_verify_invalid_proof( G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = proof.W_polys_blinded_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); } // manipulate [z]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { @@ -72,62 +74,62 @@ void test_verify_invalid_proof( proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); } // manipulate \bar{a} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate \bar{b} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate \bar{c} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); // manipulate r_zeta proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs); + b_accept = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_FALSE(b_accept); } @@ -756,14 +758,14 @@ template void test_plonk_verifier() // initialize verifier plonk_verifier verifier; // verify proof - bool b_valid_proof = verifier.verify_proof(proof, srs); + bool b_valid_proof = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_TRUE(b_valid_proof); // assert that proof verification fails when the proof is // manipulated. must be executed when DEBUG_PLONK is not defined to // disable certain assert-s that may fail before the verify // invalid proof test TODO: remove DEBUG guards #ifndef DEBUG_PLONK - test_verify_invalid_proof(proof, srs); + test_verify_invalid_proof(proof, srs, transcript_hash); #endif // #ifndef DEBUG_PLONK } diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 0e32cd27b..565bd4207 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -185,6 +185,14 @@ template class plonk_verifier /// description, from the common inputs, public input, and elements of /// pi-SNARK. TODO: fixed to the test vectors for now /// + /// INPUT + /// \param[in] transcript_hash: hashes of the communication transcript + /// after prover rounds 1,2,3,4,5. TODO: \attention + /// currently the hashes are pre-computed by the caller and + /// passed as input for the purpouses of unit testing. In + /// the long run this input can be removed and the hashes + /// can be computed directly inside verifier::step_four() + /// /// OUTPUT /// \param[out] beta, gamma: permutation challenges - hashes of /// transcript @@ -194,7 +202,8 @@ template class plonk_verifier /// v in [GWC19]) /// \param[out] u: multipoint evaluation challenge - hash of /// transcript - static step_four_out_t step_four(); + static step_four_out_t step_four( + transcript_hash_t &transcript_hash); /// Verifier Step 5: compute zero polynomial evaluation /// @@ -412,12 +421,20 @@ template class plonk_verifier /// INPUT /// \param[in] proof: SNARK proof produced by the prover /// \param[in] srs: structured reference string containing also - /// circuit-specific - /// information + /// circuit-specific information + /// \param[in] transcript_hash: hashes of the communication transcript + /// after prover rounds 1,2,3,4,5. TODO: \attention + /// currently the hashes are pre-computed by the caller and + /// passed as input for the purpouses of unit testing. In + /// the long run this input can be removed and the hashes + /// can be computed directly inside verifier::step_four() /// /// OUTPUT /// \param[out] boolean 1/0 = valid/invalid proof - bool verify_proof(const plonk_proof &proof, const srs &srs); + bool verify_proof( + const plonk_proof &proof, + const srs &srs, + transcript_hash_t &transcript_hash); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 160d155da..dc5093225 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -76,6 +76,14 @@ template void plonk_verifier::step_three(const srs &srs) /// description, from the common inputs, public input, and elements of /// pi-SNARK. TODO: fixed to the test vectors for now /// +/// INPUT +/// \param[in] transcript_hash: hashes of the communication transcript +/// after prover rounds 1,2,3,4,5. TODO: \attention +/// currently the hashes are pre-computed by the caller and +/// passed as input for the purpouses of unit testing. In +/// the long run this input can be removed and the hashes +/// can be computed directly inside verifier::step_four() +/// /// OUTPUT /// \param[out] beta, gamma: permutation challenges - hashes of /// transcript @@ -85,19 +93,10 @@ template void plonk_verifier::step_three(const srs &srs) /// v in [GWC19]) /// \param[out] u: multipoint evaluation challenge - hash of /// transcript -template step_four_out_t plonk_verifier::step_four() +template +step_four_out_t plonk_verifier::step_four( + transcript_hash_t &transcript_hash) { - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // load challenges from example for debug - plonk_example example; // step 4 output libff::Fr beta; libff::Fr gamma; @@ -106,12 +105,12 @@ template step_four_out_t plonk_verifier::step_four() libff::Fr nu; libff::Fr u; - beta = example.beta; - gamma = example.gamma; - alpha = example.alpha; - zeta = example.zeta; - nu = example.nu; - u = example.u; + beta = transcript_hash.beta; + gamma = transcript_hash.gamma; + alpha = transcript_hash.alpha; + zeta = transcript_hash.zeta; + nu = transcript_hash.nu; + u = transcript_hash.u; step_four_out_t step_four_out( std::move(beta), @@ -573,14 +572,22 @@ bool plonk_verifier::step_twelve( /// /// INPUT /// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string containing also circuit-specific -/// information +/// \param[in] srs: structured reference string containing also +/// circuit-specific information +/// \param[in] transcript_hash: hashes of the communication transcript +/// after prover rounds 1,2,3,4,5. TODO: \attention +/// currently the hashes are pre-computed by the caller and +/// passed as input for the purpouses of unit testing. In +/// the long run this input can be removed and the hashes +/// can be computed directly inside verifier::step_four() /// /// OUTPUT /// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::verify_proof( - const plonk_proof &proof, const srs &srs) + const plonk_proof &proof, + const srs &srs, + transcript_hash_t &transcript_hash) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = @@ -629,7 +636,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 4: compute challenges hashed transcript as in // prover description, from the common inputs, public input, and // elements of pi-SNARK (fixed to the test vectors for now) - const step_four_out_t step_four_out = this->step_four(); + const step_four_out_t step_four_out = this->step_four(transcript_hash); // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = From 4f7f908c5f3e15168be66befe791a9981bb179dc Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 11 Jul 2022 12:31:56 +0100 Subject: [PATCH 043/154] plonk: implemented unit tests for verifier steps 1-12 --- .../plonk/tests/test_plonk.cpp | 333 +++++++++++++++++- libsnark/zk_proof_systems/plonk/verifier.tcc | 109 ------ 2 files changed, 324 insertions(+), 118 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index f83d0341c..d4733b693 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -172,13 +172,10 @@ circuit_t plonk_circuit_description_from_example( #endif // #ifdef DEBUG_PLONK size_t num_gates = example.num_gates; - // TODO: throw exception -#ifdef DEBUG_PLONK // ensure that num_gates is not 0 - assert(num_gates); + assert(num_gates > 0); // ensure num_gates is power of 2 assert((num_gates & (num_gates - 1)) == 0); -#endif // #ifdef DEBUG_PLONK size_t num_qpolys = example.num_qpolys; @@ -709,6 +706,327 @@ template void test_plonk_prover() ASSERT_EQ(W_zeta_omega_at_secret_aff.Y, example.W_zeta_omega_at_secret[1]); } +template +void test_plonk_verifier_preprocessed_input( + const plonk_example &example, const srs &srs) +{ + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + + // compute verifier preprocessed input + const verifier_preprocessed_input_t preprocessed_input = + plonk_verifier::preprocessed_input(srs); + + for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { + printf("srs.Q_polys_at_secret_G1[%d] \n", i); + preprocessed_input.Q_polys_at_secret_g1[i].print(); + libff::G1 Q_poly_at_secret_g1_i( + preprocessed_input.Q_polys_at_secret_g1[i]); + Q_poly_at_secret_g1_i.to_affine_coordinates(); + ASSERT_EQ(Q_poly_at_secret_g1_i.X, example.Q_polys_at_secret_g1[i][0]); + ASSERT_EQ(Q_poly_at_secret_g1_i.Y, example.Q_polys_at_secret_g1[i][1]); + } + for (int i = 0; i < (int)srs.S_polys.size(); ++i) { + printf("S_polys_at_secret_G1[%d] \n", i); + preprocessed_input.S_polys_at_secret_g1[i].print(); + libff::G1 S_poly_at_secret_g1_i( + preprocessed_input.S_polys_at_secret_g1[i]); + S_poly_at_secret_g1_i.to_affine_coordinates(); + ASSERT_EQ(S_poly_at_secret_g1_i.X, example.S_polys_at_secret_g1[i][0]); + ASSERT_EQ(S_poly_at_secret_g1_i.Y, example.S_polys_at_secret_g1[i][1]); + } +} + +template +void test_plonk_verifier_step_five( + const plonk_example &example, + const step_four_out_t &step_four_out, + const srs &srs) +{ + const step_five_out_t step_five_out = + plonk_verifier::step_five(step_four_out, srs); + printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); + step_five_out.zh_zeta.print(); + ASSERT_EQ(step_five_out.zh_zeta, example.zh_zeta); +} + +template +void test_plonk_verifier_step_six( + const plonk_example &example, + const step_four_out_t &step_four_out, + const srs &srs) +{ + const step_six_out_t step_six_out = + plonk_verifier::step_six(step_four_out, srs); + printf("L_0_zeta "); + step_six_out.L_0_zeta.print(); + ASSERT_EQ(step_six_out.L_0_zeta, example.L_0_zeta); +} + +template +void test_plonk_verifier_step_seven( + const plonk_example &example, + const step_four_out_t &step_four_out, + const srs &srs) +{ + const step_seven_out_t step_seven_out = + plonk_verifier::step_seven(step_four_out, srs); + printf("PI_zeta "); + step_seven_out.PI_zeta.print(); + ASSERT_EQ(step_seven_out.PI_zeta, example.PI_zeta); +} + +template +void test_plonk_verifier_step_eight( + const plonk_example &example, + const step_four_out_t &step_four_out, + const step_five_out_t &step_five_out, + const step_six_out_t &step_six_out, + const step_seven_out_t &step_seven_out, + const plonk_proof &proof) +{ + const step_eight_out_t step_eight_out = + plonk_verifier::step_eight( + step_four_out, step_five_out, step_six_out, step_seven_out, proof); + ASSERT_EQ(step_eight_out.r_prime_zeta, example.r_prime_zeta); +} + +template +void test_plonk_verifier_step_nine( + const plonk_example &example, + const step_four_out_t &step_four_out, + const step_six_out_t &step_six_out, + const plonk_proof &proof, + const verifier_preprocessed_input_t &preprocessed_input, + const srs &srs) +{ + step_nine_out_t step_nine_out = plonk_verifier::step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); + step_nine_out.D1.print(); + libff::G1 D1_aff(step_nine_out.D1); + D1_aff.to_affine_coordinates(); + ASSERT_EQ(D1_aff.X, example.D1[0]); + ASSERT_EQ(D1_aff.Y, example.D1[1]); +} + +template +void test_plonk_verifier_step_ten( + const plonk_example &example, + const step_four_out_t &step_four_out, + const step_nine_out_t &step_nine_out, + const plonk_proof &proof, + const verifier_preprocessed_input_t &preprocessed_input, + const srs &srs) +{ + step_ten_out_t step_ten_out = plonk_verifier::step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); + printf("[%s:%d] F1\n", __FILE__, __LINE__); + step_ten_out.F1.print(); + libff::G1 F1_aff(step_ten_out.F1); + F1_aff.to_affine_coordinates(); + ASSERT_EQ(F1_aff.X, example.F1[0]); + ASSERT_EQ(F1_aff.Y, example.F1[1]); +} + +template +void test_plonk_verifier_step_eleven( + const plonk_example &example, + const step_four_out_t &step_four_out, + const step_eight_out_t &step_eight_out, + const plonk_proof &proof) +{ + const step_eleven_out_t step_eleven_out = + plonk_verifier::step_eleven(step_four_out, step_eight_out, proof); + printf("[%s:%d] E1\n", __FILE__, __LINE__); + step_eleven_out.E1.print(); + libff::G1 E1_aff(step_eleven_out.E1); + E1_aff.to_affine_coordinates(); + ASSERT_EQ(E1_aff.X, example.E1[0]); + ASSERT_EQ(E1_aff.Y, example.E1[1]); +} + +// step 12 +template +void test_plonk_verifier_pairing( + const plonk_example &example, + const libff::Fr &zeta, // step 4 + const libff::Fr &u, // step 4 + const libff::G1 &F1, // step 10 + const libff::G1 &E1, // step 11 + const plonk_proof &proof, + const srs &srs) +{ + // the example class is defined specifically for the BLS12-381 + // curve, so make sure we are using this curve TODO: remove when + // the implementation is stable and tested + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + using Field = libff::Fr; + std::vector> curve_points_lhs{ + proof.W_zeta_at_secret, proof.W_zeta_omega_at_secret}; + std::vector> scalar_elements_lhs{Field(1), u}; + libff::G1 pairing_first_lhs = + plonk_multi_exp_G1(curve_points_lhs, scalar_elements_lhs); + libff::G2 pairing_second_lhs = srs.secret_powers_g2[1]; + std::vector> curve_points_rhs{ + proof.W_zeta_at_secret, proof.W_zeta_omega_at_secret, F1, E1}; + std::vector> scalar_elements_rhs{ + // Warning! raise to the power of -1 to check e() * e()^-1 = 1 + Field(-1) * zeta, + Field(-1) * u * zeta * srs.omega_roots[base][1], + Field(-1) * Field(1), + Field(-1) * Field(-1)}; + + libff::G1 pairing_first_rhs = + plonk_multi_exp_G1(curve_points_rhs, scalar_elements_rhs); + libff::G2 pairing_second_rhs = srs.secret_powers_g2[0]; + + const libff::G1_precomp _A = ppT::precompute_G1(pairing_first_lhs); + const libff::G2_precomp _B = ppT::precompute_G2(pairing_second_lhs); + const libff::G1_precomp _C = ppT::precompute_G1(pairing_first_rhs); + const libff::G2_precomp _D = ppT::precompute_G2(pairing_second_rhs); + const libff::Fqk miller_result = + ppT::double_miller_loop(_A, _B, _C, _D); + const libff::GT result = ppT::final_exponentiation(miller_result); + bool b_accept = (result == libff::GT::one()); + + printf("[%s:%d] pairing_first_lhs\n", __FILE__, __LINE__); + pairing_first_lhs.print(); + libff::G1 pairing_first_lhs_aff(pairing_first_lhs); + pairing_first_lhs_aff.to_affine_coordinates(); + ASSERT_EQ(pairing_first_lhs_aff.X, example.pairing_first_lhs[0]); + ASSERT_EQ(pairing_first_lhs_aff.Y, example.pairing_first_lhs[1]); + + printf("[%s:%d] pairing_first_rhs\n", __FILE__, __LINE__); + pairing_first_rhs.print(); + libff::G1 pairing_first_rhs_aff(pairing_first_rhs); + pairing_first_rhs_aff.to_affine_coordinates(); + ASSERT_EQ(pairing_first_rhs_aff.X, example.pairing_first_rhs[0]); + ASSERT_EQ(pairing_first_rhs_aff.Y, example.pairing_first_rhs[1]); + + ASSERT_TRUE(b_accept); +} + +template void test_plonk_verifier_steps() +{ + using Field = libff::Fr; + + // example test values are defined specifically for the BLS12-381 + // curve, so make sure we are using this curve + try { + plonk_exception_assert_curve_bls12_381(); + } catch (const std::domain_error &e) { + std::cout << "Error: " << e.what() << "\n"; + exit(EXIT_FAILURE); + } + ppT::init_public_params(); + // load test vector values from example circuit + plonk_example example; + // random hidden element secret (toxic waste) + Field secret = example.secret; + // example witness + std::vector witness = example.witness; + // example circuit + circuit_t circuit = + plonk_circuit_description_from_example(example); + // get hard-coded values for the transcipt hash + transcript_hash_t transcript_hash( + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u); + // hard-coded values for the "random" blinding constants from + // example circuit + std::vector> blind_scalars = example.prover_blind_scalars; + // maximum degree of the encoded monomials in the usrs + size_t max_degree = PLONK_MAX_DEGREE; + + // prepare srs + usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); + srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + + // initialize prover + plonk_prover prover; + // compute proof + plonk_proof proof = + prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + + // Unit test verifier preprocessed input + test_plonk_verifier_preprocessed_input(example, srs); + + // unit test verifier step 5 + const step_four_out_t step_four_out = + plonk_verifier::step_four(transcript_hash); + test_plonk_verifier_step_five(example, step_four_out, srs); + + // unit test verifier step 6 + test_plonk_verifier_step_six(example, step_four_out, srs); + + // unit test verifier step 7 + test_plonk_verifier_step_seven(example, step_four_out, srs); + + // unit test verifier step 8 + const step_five_out_t step_five_out = + plonk_verifier::step_five(step_four_out, srs); + const step_six_out_t step_six_out = + plonk_verifier::step_six(step_four_out, srs); + const step_seven_out_t step_seven_out = + plonk_verifier::step_seven(step_four_out, srs); + test_plonk_verifier_step_eight( + example, + step_four_out, + step_five_out, + step_six_out, + step_seven_out, + proof); + + // unit test verifier step 9 + const verifier_preprocessed_input_t preprocessed_input = + plonk_verifier::preprocessed_input(srs); + test_plonk_verifier_step_nine( + example, step_four_out, step_six_out, proof, preprocessed_input, srs); + + // unit test verifier step 10 + step_nine_out_t step_nine_out = plonk_verifier::step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); + test_plonk_verifier_step_ten( + example, step_four_out, step_nine_out, proof, preprocessed_input, srs); + + // unit test verifier step 11 + const step_eight_out_t step_eight_out = + plonk_verifier::step_eight( + step_four_out, step_five_out, step_six_out, step_seven_out, proof); + test_plonk_verifier_step_eleven( + example, step_four_out, step_eight_out, proof); + + // unit test verifier pairing (step 12) + step_ten_out_t step_ten_out = plonk_verifier::step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); + const step_eleven_out_t step_eleven_out = + plonk_verifier::step_eleven(step_four_out, step_eight_out, proof); + test_plonk_verifier_pairing( + example, + step_four_out.zeta, + step_four_out.u, + step_ten_out.F1, + step_eleven_out.E1, + proof, + srs); +} + template void test_plonk_verifier() { using Field = libff::Fr; @@ -761,12 +1079,8 @@ template void test_plonk_verifier() bool b_valid_proof = verifier.verify_proof(proof, srs, transcript_hash); ASSERT_TRUE(b_valid_proof); // assert that proof verification fails when the proof is - // manipulated. must be executed when DEBUG_PLONK is not defined to - // disable certain assert-s that may fail before the verify - // invalid proof test TODO: remove DEBUG guards -#ifndef DEBUG_PLONK + // manipulated test_verify_invalid_proof(proof, srs, transcript_hash); -#endif // #ifndef DEBUG_PLONK } TEST(TestPlonk, BLS12_381) @@ -774,6 +1088,7 @@ TEST(TestPlonk, BLS12_381) test_plonk_srs(); test_plonk_prover_rounds(); test_plonk_prover(); + test_plonk_verifier_steps(); test_plonk_verifier(); } diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index dc5093225..532e5485b 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -520,34 +520,6 @@ bool plonk_verifier::step_twelve( plonk_multi_exp_G1(curve_points_rhs, scalar_elements_rhs); libff::G2 pairing_second_rhs = srs.secret_powers_g2[0]; - // TODO: move to unit test for step_twelve -#ifdef DEBUG_PLONK - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // load test vectors for debug - plonk_example example; - printf("[%s:%d] pairing_first_lhs\n", __FILE__, __LINE__); - pairing_first_lhs.print(); - libff::G1 pairing_first_lhs_aff(pairing_first_lhs); - pairing_first_lhs_aff.to_affine_coordinates(); - assert(pairing_first_lhs_aff.X == example.pairing_first_lhs[0]); - assert(pairing_first_lhs_aff.Y == example.pairing_first_lhs[1]); - - printf("[%s:%d] pairing_first_rhs\n", __FILE__, __LINE__); - pairing_first_rhs.print(); - libff::G1 pairing_first_rhs_aff(pairing_first_rhs); - pairing_first_rhs_aff.to_affine_coordinates(); - assert(pairing_first_rhs_aff.X == example.pairing_first_rhs[0]); - assert(pairing_first_rhs_aff.Y == example.pairing_first_rhs[1]); -#endif // #ifdef DEBUG_PLONK - const libff::G1_precomp _A = ppT::precompute_G1(pairing_first_lhs); const libff::G2_precomp _B = ppT::precompute_G2(pairing_second_lhs); const libff::G1_precomp _C = ppT::precompute_G1(pairing_first_rhs); @@ -593,39 +565,6 @@ bool plonk_verifier::verify_proof( const verifier_preprocessed_input_t preprocessed_input = plonk_verifier::preprocessed_input(srs); - // TODO: move to unit test for verify_proof -#ifdef DEBUG_PLONK - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // load test vector values form example for debug - plonk_example example; - for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { - printf("srs.Q_polys_at_secret_G1[%d] \n", i); - preprocessed_input.Q_polys_at_secret_g1[i].print(); - libff::G1 Q_poly_at_secret_g1_i( - preprocessed_input.Q_polys_at_secret_g1[i]); - Q_poly_at_secret_g1_i.to_affine_coordinates(); - assert(Q_poly_at_secret_g1_i.X == example.Q_polys_at_secret_g1[i][0]); - assert(Q_poly_at_secret_g1_i.Y == example.Q_polys_at_secret_g1[i][1]); - } - for (int i = 0; i < (int)srs.S_polys.size(); ++i) { - printf("S_polys_at_secret_G1[%d] \n", i); - preprocessed_input.S_polys_at_secret_g1[i].print(); - libff::G1 S_poly_at_secret_g1_i( - preprocessed_input.S_polys_at_secret_g1[i]); - S_poly_at_secret_g1_i.to_affine_coordinates(); - assert(S_poly_at_secret_g1_i.X == example.S_polys_at_secret_g1[i][0]); - assert(S_poly_at_secret_g1_i.Y == example.S_polys_at_secret_g1[i][1]); - } -#endif // #ifdef DEBUG_PLONK - // Verifier Step 1: validate that elements belong to group G1 // Verifier Step 2: validate that elements belong to scalar field Fr // Verifier Step 3: validate that the public input belongs to scalar field @@ -641,81 +580,33 @@ bool plonk_verifier::verify_proof( // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = this->step_five(step_four_out, srs); - // TODO: uni test for step_five -#ifdef DEBUG_PLONK - printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); - step_five_out.zh_zeta.print(); - assert(step_five_out.zh_zeta == example.zh_zeta); -#endif // #ifdef DEBUG_PLONK // Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) // Note: the paper counts the L-polynomials from 1; we count from 0 const step_six_out_t step_six_out = this->step_six(step_four_out, srs); - // TODO: uni test for step_six -#ifdef DEBUG_PLONK - printf("L_0_zeta "); - step_six_out.L_0_zeta.print(); - assert(step_six_out.L_0_zeta == example.L_0_zeta); -#endif // #ifdef DEBUG_PLONK // Verifier Step 7: compute public input polynomial evaluation PI(zeta) const step_seven_out_t step_seven_out = this->step_seven(step_four_out, srs); - // TODO: uni test for step_seven -#ifdef DEBUG_PLONK - printf("PI_zeta "); - step_seven_out.PI_zeta.print(); - assert(step_seven_out.PI_zeta == example.PI_zeta); -#endif // #ifdef DEBUG_PLONK // Verifier Step 8: compute quotient polynomial evaluation // r'(zeta) = r(zeta) - r0, where r0 is a constant term const step_eight_out_t step_eight_out = this->step_eight( step_four_out, step_five_out, step_six_out, step_seven_out, proof); - // TODO: uni test for step_eight -#ifdef DEBUG_PLONK - assert(step_eight_out.r_prime_zeta == example.r_prime_zeta); -#endif // #ifdef DEBUG_PLONK // Verifier Step 9: compute first part of batched polynomial // commitment [D]_1 step_nine_out_t step_nine_out = this->step_nine( step_four_out, step_six_out, proof, preprocessed_input, srs); - // TODO: uni test for step_nine -#ifdef DEBUG_PLONK - step_nine_out.D1.print(); - libff::G1 D1_aff(step_nine_out.D1); - D1_aff.to_affine_coordinates(); - assert(D1_aff.X == example.D1[0]); - assert(D1_aff.Y == example.D1[1]); -#endif // #ifdef DEBUG_PLONK // Verifier Step 10: compute full batched polynomial commitment // [F]_1 step_ten_out_t step_ten_out = this->step_ten( step_four_out, step_nine_out, proof, preprocessed_input, srs); - // TODO: uni test for step_ten -#ifdef DEBUG_PLONK - printf("[%s:%d] F1\n", __FILE__, __LINE__); - step_ten_out.F1.print(); - libff::G1 F1_aff(step_ten_out.F1); - F1_aff.to_affine_coordinates(); - assert(F1_aff.X == example.F1[0]); - assert(F1_aff.Y == example.F1[1]); -#endif // #ifdef DEBUG_PLONK // Verifier Step 11: compute group-encoded batch evaluation [E]_1 const step_eleven_out_t step_eleven_out = this->step_eleven(step_four_out, step_eight_out, proof); - // TODO: uni test for step_eleven -#ifdef DEBUG_PLONK - printf("[%s:%d] E1\n", __FILE__, __LINE__); - step_eleven_out.E1.print(); - libff::G1 E1_aff(step_eleven_out.E1); - E1_aff.to_affine_coordinates(); - assert(E1_aff.X == example.E1[0]); - assert(E1_aff.Y == example.E1[1]); -#endif // #ifdef DEBUG_PLONK // Verifier Step 12: batch validate all evaluations (check // pairing) From 49d652d9f6b87d4721ed7ab47fb23fe9f6c3e1d2 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 09:30:55 +0100 Subject: [PATCH 044/154] plonk: moved all constructors from the *.hpp files to the corresponding *.tcc files --- libsnark/zk_proof_systems/plonk/circuit.hpp | 16 +-- libsnark/zk_proof_systems/plonk/circuit.tcc | 28 +++++ libsnark/zk_proof_systems/plonk/prover.hpp | 59 ++--------- libsnark/zk_proof_systems/plonk/prover.tcc | 106 +++++++++++++++++++ libsnark/zk_proof_systems/plonk/srs.hpp | 38 ++----- libsnark/zk_proof_systems/plonk/srs.tcc | 68 ++++++++++++ libsnark/zk_proof_systems/plonk/verifier.hpp | 26 ++--- libsnark/zk_proof_systems/plonk/verifier.tcc | 87 +++++++++++++-- 8 files changed, 308 insertions(+), 120 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index eda0d63d7..db493f688 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -66,7 +66,6 @@ template struct circuit_t { libff::Fr k1; libff::Fr k2; - /// stuct constructor circuit_t( size_t num_gates, size_t num_qpolys, @@ -78,20 +77,7 @@ template struct circuit_t { std::vector &&H_gen, std::vector &&H_gen_permute, libff::Fr &&k1, - libff::Fr &&k2) - : num_gates(num_gates) - , num_qpolys(num_qpolys) - , L_basis(L_basis) - , PI_poly(PI_poly) - , Q_polys(Q_polys) - , S_polys(S_polys) - , omega_roots(omega_roots) - , H_gen(H_gen) - , H_gen_permute(H_gen_permute) - , k1(k1) - , k2(k2) - { - } + libff::Fr &&k2); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 2fff3fe77..2b2b0685c 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -18,6 +18,34 @@ namespace libsnark // TODO: add here function for describing the target circuit through // the circuit_t structure +/// stuct constructor +template +circuit_t::circuit_t( + size_t num_gates, + size_t num_qpolys, + std::vector> &&L_basis, + polynomial &&PI_poly, + std::vector> &&Q_polys, + std::vector> &&S_polys, + std::vector> &&omega_roots, + std::vector &&H_gen, + std::vector &&H_gen_permute, + libff::Fr &&k1, + libff::Fr &&k2) + : num_gates(num_gates) + , num_qpolys(num_qpolys) + , L_basis(L_basis) + , PI_poly(PI_poly) + , Q_polys(Q_polys) + , S_polys(S_polys) + , omega_roots(omega_roots) + , H_gen(H_gen) + , H_gen_permute(H_gen_permute) + , k1(k1) + , k2(k2) +{ +} + } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 5c3d53708..10f73e86d 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -82,21 +82,7 @@ template class plonk_proof Field &z_poly_xomega_zeta, libff::G1 &W_zeta_at_secret, libff::G1 &W_zeta_omega_at_secret, - Field &r_zeta) - : W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) - , z_poly_at_secret_g1(z_poly_at_secret_g1) - , t_poly_at_secret_g1(t_poly_at_secret_g1) - , a_zeta(a_zeta) - , b_zeta(b_zeta) - , c_zeta(c_zeta) - , S_0_zeta(S_0_zeta) - , S_1_zeta(S_1_zeta) - , z_poly_xomega_zeta(z_poly_xomega_zeta) - , W_zeta_at_secret(W_zeta_at_secret) - , W_zeta_omega_at_secret(W_zeta_omega_at_secret) - , r_zeta(r_zeta) - { - } + Field &r_zeta); }; /// Prover round 0 output @@ -115,10 +101,7 @@ template struct round_zero_out_t { round_zero_out_t( const std::vector> &&zh_poly, const polynomial> &&null_poly, - const polynomial> &&neg_one_poly) - : zh_poly(zh_poly), null_poly(null_poly), neg_one_poly(neg_one_poly) - { - } + const polynomial> &&neg_one_poly); }; /// Prover round 1 output @@ -140,12 +123,7 @@ template struct round_one_out_t { round_one_out_t( const std::vector>> &&W_polys, const std::vector>> &&W_polys_blinded, - const std::vector> &&W_polys_blinded_at_secret_g1) - : W_polys(W_polys) - , W_polys_blinded(W_polys_blinded) - , W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) - { - } + const std::vector> &&W_polys_blinded_at_secret_g1); }; /// Prover round 2 output @@ -161,10 +139,7 @@ template struct round_two_out_t { /// stuct constructor round_two_out_t( polynomial> &&z_poly, - libff::G1 &&z_poly_at_secret_g1) - : z_poly(z_poly), z_poly_at_secret_g1(z_poly_at_secret_g1) - { - } + libff::G1 &&z_poly_at_secret_g1); }; /// Prover round 3 output @@ -190,13 +165,7 @@ template struct round_three_out_t { std::vector> &&z_poly_xomega, std::vector>> &&t_poly, polynomial> &&t_poly_long, - std::vector> &&t_poly_at_secret_g1) - : z_poly_xomega(z_poly_xomega) - , t_poly(t_poly) - , t_poly_long(t_poly_long) - , t_poly_at_secret_g1(t_poly_at_secret_g1) - { - } + std::vector> &&t_poly_at_secret_g1); }; /// Prover round 4 output @@ -234,16 +203,7 @@ template struct round_four_out_t { libff::Fr &&S_0_zeta, libff::Fr &&S_1_zeta, libff::Fr &&z_poly_xomega_zeta, - libff::Fr &&t_zeta) - : a_zeta(a_zeta) - , b_zeta(b_zeta) - , c_zeta(c_zeta) - , S_0_zeta(S_0_zeta) - , S_1_zeta(S_1_zeta) - , z_poly_xomega_zeta(z_poly_xomega_zeta) - , t_zeta(t_zeta) - { - } + libff::Fr &&t_zeta); }; /// Prover round 5 output @@ -265,12 +225,7 @@ template struct round_five_out_t { round_five_out_t( libff::Fr &&r_zeta, libff::G1 &&W_zeta_at_secret, - libff::G1 &&W_zeta_omega_at_secret) - : r_zeta(r_zeta) - , W_zeta_at_secret(W_zeta_at_secret) - , W_zeta_omega_at_secret(W_zeta_omega_at_secret) - { - } + libff::G1 &&W_zeta_omega_at_secret); }; /// Plonk prover. Computes object of class plonk_proof. diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 5fe3522f3..2ff2c5a11 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -15,6 +15,16 @@ namespace libsnark { +/// Prover round 0 output constructor +template +round_zero_out_t::round_zero_out_t( + const std::vector> &&zh_poly, + const polynomial> &&null_poly, + const polynomial> &&neg_one_poly) + : zh_poly(zh_poly), null_poly(null_poly), neg_one_poly(neg_one_poly) +{ +} + /// Prover Round 0 initialization /// /// Initialization @@ -52,6 +62,18 @@ round_zero_out_t plonk_prover::round_zero(const srs srs) return round_zero_out; } +/// Prover round 1 output constructor +template +round_one_out_t::round_one_out_t( + const std::vector>> &&W_polys, + const std::vector>> &&W_polys_blinded, + const std::vector> &&W_polys_blinded_at_secret_g1) + : W_polys(W_polys) + , W_polys_blinded(W_polys_blinded) + , W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) +{ +} + /// Prover Round 1 /// /// INPUT @@ -126,6 +148,14 @@ round_one_out_t plonk_prover::round_one( return round_one_out; } +/// Prover round 2 output +template +round_two_out_t::round_two_out_t( + polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1) + : z_poly(z_poly), z_poly_at_secret_g1(z_poly_at_secret_g1) +{ +} + /// Prover Round 2 /// /// INPUT @@ -188,6 +218,20 @@ round_two_out_t plonk_prover::round_two( return round_two_out; } +/// Prover round 3 output constructor +template +round_three_out_t::round_three_out_t( + std::vector> &&z_poly_xomega, + std::vector>> &&t_poly, + polynomial> &&t_poly_long, + std::vector> &&t_poly_at_secret_g1) + : z_poly_xomega(z_poly_xomega) + , t_poly(t_poly) + , t_poly_long(t_poly_long) + , t_poly_at_secret_g1(t_poly_at_secret_g1) +{ +} + /// Prover Round 3 /// /// INPUT @@ -439,6 +483,26 @@ round_three_out_t plonk_prover::round_three( return round_three_out; } +/// Prover round 4 output constructor +template +round_four_out_t::round_four_out_t( + libff::Fr &&a_zeta, + libff::Fr &&b_zeta, + libff::Fr &&c_zeta, + libff::Fr &&S_0_zeta, + libff::Fr &&S_1_zeta, + libff::Fr &&z_poly_xomega_zeta, + libff::Fr &&t_zeta) + : a_zeta(a_zeta) + , b_zeta(b_zeta) + , c_zeta(c_zeta) + , S_0_zeta(S_0_zeta) + , S_1_zeta(S_1_zeta) + , z_poly_xomega_zeta(z_poly_xomega_zeta) + , t_zeta(t_zeta) +{ +} + /// Prover Round 4 /// /// INPUT @@ -517,6 +581,18 @@ round_four_out_t plonk_prover::round_four( return round_four_out; } +/// Prover round 5 output constructor +template +round_five_out_t::round_five_out_t( + libff::Fr &&r_zeta, + libff::G1 &&W_zeta_at_secret, + libff::G1 &&W_zeta_omega_at_secret) + : r_zeta(r_zeta) + , W_zeta_at_secret(W_zeta_at_secret) + , W_zeta_omega_at_secret(W_zeta_omega_at_secret) +{ +} + /// Prover Round 5 /// /// INPUT @@ -853,6 +929,36 @@ round_five_out_t plonk_prover::round_five( return round_five_out; } +// class plonk_proof constructor +template +plonk_proof::plonk_proof( + std::vector> &W_polys_blinded_at_secret_g1, + libff::G1 &z_poly_at_secret_g1, + std::vector> &t_poly_at_secret_g1, + Field &a_zeta, + Field &b_zeta, + Field &c_zeta, + Field &S_0_zeta, + Field &S_1_zeta, + Field &z_poly_xomega_zeta, + libff::G1 &W_zeta_at_secret, + libff::G1 &W_zeta_omega_at_secret, + Field &r_zeta) + : W_polys_blinded_at_secret_g1(W_polys_blinded_at_secret_g1) + , z_poly_at_secret_g1(z_poly_at_secret_g1) + , t_poly_at_secret_g1(t_poly_at_secret_g1) + , a_zeta(a_zeta) + , b_zeta(b_zeta) + , c_zeta(c_zeta) + , S_0_zeta(S_0_zeta) + , S_1_zeta(S_1_zeta) + , z_poly_xomega_zeta(z_poly_xomega_zeta) + , W_zeta_at_secret(W_zeta_at_secret) + , W_zeta_omega_at_secret(W_zeta_omega_at_secret) + , r_zeta(r_zeta) +{ +} + /// Prover compute SNARK proof /// /// Pi ([a]_1, [b]_1, [c]_1, [z]_1, diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 94a074a07..0fcf67b0e 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -60,10 +60,7 @@ template class usrs usrs( std::vector> &&secret_powers_g1, - std::vector> &&secret_powers_g2) - : secret_powers_g1(secret_powers_g1), secret_powers_g2(secret_powers_g2) - { - } + std::vector> &&secret_powers_g2); }; template @@ -134,22 +131,7 @@ template class srs const libff::Fr &k1, const libff::Fr &k2, std::vector> &&secret_powers_g1, - std::vector> &&secret_powers_g2) - : num_gates(num_gates) - , num_qpolys(num_qpolys) - , L_basis(L_basis) - , PI_poly(PI_poly) - , Q_polys(Q_polys) - , S_polys(S_polys) - , omega_roots(omega_roots) - , H_gen(H_gen) - , H_gen_permute(H_gen_permute) - , k1(k1) - , k2(k2) - , secret_powers_g1(secret_powers_g1) - , secret_powers_g2(secret_powers_g2) - { - } + std::vector> &&secret_powers_g2); }; template @@ -178,8 +160,7 @@ template class plonk_verification_key std::vector> secret_powers_g2; plonk_verification_key(); - plonk_verification_key(std::vector> &&secret_powers_g2) - : secret_powers_g2(std::move(secret_powers_g2)){}; + plonk_verification_key(std::vector> &&secret_powers_g2); }; /// A key pair for Plonk, which consists of a proving key and a @@ -192,10 +173,8 @@ template class plonk_keypair plonk_keypair() = default; plonk_keypair(const plonk_keypair &other) = default; - plonk_keypair(plonk_proving_key &&pk, plonk_verification_key &&vk) - : pk(std::move(pk)), vk(std::move(vk)) - { - } + plonk_keypair( + plonk_proving_key &&pk, plonk_verification_key &&vk); plonk_keypair(plonk_keypair &&other) = default; }; @@ -218,17 +197,14 @@ template struct transcript_hash_t { /// 1,2,3,4,5 libff::Fr u; - /// stuct constructor + /// struct constructor transcript_hash_t( libff::Fr &beta, libff::Fr &gamma, libff::Fr &alpha, libff::Fr &zeta, libff::Fr &nu, - libff::Fr &u) - : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) - { - } + libff::Fr &u); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index eff1a67d4..0ecc24ed9 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -15,6 +15,74 @@ namespace libsnark { +// class usrs constructor +template +usrs::usrs( + std::vector> &&secret_powers_g1, + std::vector> &&secret_powers_g2) + : secret_powers_g1(secret_powers_g1), secret_powers_g2(secret_powers_g2) +{ +} + +// class srs constructor +template +srs::srs( + const size_t &num_gates, + const size_t &num_qpolys, + const std::vector> &L_basis, + const polynomial &PI_poly, + const std::vector> &Q_polys, + const std::vector> &S_polys, + const std::vector> &omega_roots, + const std::vector &H_gen, + const std::vector &H_gen_permute, + const libff::Fr &k1, + const libff::Fr &k2, + std::vector> &&secret_powers_g1, + std::vector> &&secret_powers_g2) + : num_gates(num_gates) + , num_qpolys(num_qpolys) + , L_basis(L_basis) + , PI_poly(PI_poly) + , Q_polys(Q_polys) + , S_polys(S_polys) + , omega_roots(omega_roots) + , H_gen(H_gen) + , H_gen_permute(H_gen_permute) + , k1(k1) + , k2(k2) + , secret_powers_g1(secret_powers_g1) + , secret_powers_g2(secret_powers_g2) +{ +} + +/// class plonk_verification_key +template +plonk_verification_key::plonk_verification_key( + std::vector> &&secret_powers_g2) + : secret_powers_g2(std::move(secret_powers_g2)){}; + +/// class plonk_keypair constructor +template +plonk_keypair::plonk_keypair( + plonk_proving_key &&pk, plonk_verification_key &&vk) + : pk(std::move(pk)), vk(std::move(vk)) +{ +} + +/// struct transcript_hash_t constructor +template +transcript_hash_t::transcript_hash_t( + libff::Fr &beta, + libff::Fr &gamma, + libff::Fr &alpha, + libff::Fr &zeta, + libff::Fr &nu, + libff::Fr &u) + : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) +{ +} + /// Compute a universal srs (usrs). It is composed *only* of encoded /// powers of the secret value in the group generator. Therefore a usrs /// is independent of any particular circuit. diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 565bd4207..246f69a8c 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -65,6 +65,11 @@ namespace libsnark template struct verifier_preprocessed_input_t { std::vector> Q_polys_at_secret_g1; std::vector> S_polys_at_secret_g1; + + /// struct constructor + verifier_preprocessed_input_t( + std::vector> &&Q_polys_at_secret_g1, + std::vector> &&S_polys_at_secret_g1); }; /// Verifier step 4 output @@ -81,17 +86,14 @@ template struct step_four_out_t { libff::Fr &&alpha, libff::Fr &&zeta, libff::Fr &&nu, - libff::Fr &&u) - : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) - { - } + libff::Fr &&u); }; /// Verifier step 5 output template struct step_five_out_t { /// evaluation of vanishing polynomial Zh at x=zeta i.e. Zh(zeta) libff::Fr zh_zeta; - step_five_out_t(libff::Fr &&zh_zeta) : zh_zeta(zh_zeta) {} + step_five_out_t(libff::Fr &&zh_zeta); }; /// Verifier step 6 output @@ -99,14 +101,14 @@ template struct step_six_out_t { /// Lagrange polynomial evaluation of polynomial L1 at x=zeta /// i.e. L1(zeta) libff::Fr L_0_zeta; - step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) {} + step_six_out_t(libff::Fr &&L_0_zeta); }; /// Verifier step 7 output template struct step_seven_out_t { /// Public input polynomial PI evaluated at x=zeta .e. PI(zeta) libff::Fr PI_zeta; - step_seven_out_t(libff::Fr &&PI_zeta) : PI_zeta(PI_zeta) {} + step_seven_out_t(libff::Fr &&PI_zeta); }; /// Verifier step 8 output @@ -114,16 +116,14 @@ template struct step_eight_out_t { /// compute quotient polynomial evaluation r'(zeta) = r(zeta) - r0, /// where r0 is a constant term Note: libff::Fr r_prime_zeta; - step_eight_out_t(libff::Fr &&r_prime_zeta) : r_prime_zeta(r_prime_zeta) - { - } + step_eight_out_t(libff::Fr &&r_prime_zeta); }; /// Verifier step 9 output template struct step_nine_out_t { /// first part of batched polynomial commitment [D]_1 libff::G1 D1; - step_nine_out_t(libff::G1 &&D1) : D1(D1) {} + step_nine_out_t(libff::G1 &&D1); }; /// Verifier step 10 output @@ -131,14 +131,14 @@ template struct step_ten_out_t { /// full batched polynomial commitment [F]_1 = [D]_1 + v [a]_1 + v^2 /// [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + v^5 [s_sigma_2]_1 libff::G1 F1; - step_ten_out_t(libff::G1 &&F1) : F1(F1) {} + step_ten_out_t(libff::G1 &&F1); }; /// Verifier step 11 output template struct step_eleven_out_t { /// group-encoded batch evaluation [E]_1 libff::G1 E1; - step_eleven_out_t(libff::G1 &&E1) : E1(E1) {} + step_eleven_out_t(libff::G1 &&E1); }; /// Plonk verifier. Verifies object of class plonk_proof. diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 532e5485b..5d5069cc5 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -15,6 +15,16 @@ namespace libsnark { +/// struct verifier_preprocessed_input_t constructor +template +verifier_preprocessed_input_t::verifier_preprocessed_input_t( + std::vector> &&Q_polys_at_secret_g1, + std::vector> &&S_polys_at_secret_g1) + : Q_polys_at_secret_g1(Q_polys_at_secret_g1) + , S_polys_at_secret_g1(S_polys_at_secret_g1) +{ +} + /// Verifier precomputation /// /// INPUT @@ -30,18 +40,18 @@ template verifier_preprocessed_input_t plonk_verifier::preprocessed_input( const srs &srs) { - verifier_preprocessed_input_t preprocessed_input; - preprocessed_input.Q_polys_at_secret_g1.resize(srs.Q_polys.size()); + std::vector> Q_polys_at_secret_g1; + Q_polys_at_secret_g1.resize(srs.Q_polys.size()); plonk_evaluate_polys_at_secret_G1( - srs.secret_powers_g1, - srs.Q_polys, - preprocessed_input.Q_polys_at_secret_g1); + srs.secret_powers_g1, srs.Q_polys, Q_polys_at_secret_g1); - preprocessed_input.S_polys_at_secret_g1.resize(srs.S_polys.size()); + std::vector> S_polys_at_secret_g1; + S_polys_at_secret_g1.resize(srs.S_polys.size()); plonk_evaluate_polys_at_secret_G1( - srs.secret_powers_g1, - srs.S_polys, - preprocessed_input.S_polys_at_secret_g1); + srs.secret_powers_g1, srs.S_polys, S_polys_at_secret_g1); + + verifier_preprocessed_input_t preprocessed_input( + std::move(Q_polys_at_secret_g1), std::move(S_polys_at_secret_g1)); return preprocessed_input; } @@ -72,6 +82,19 @@ template void plonk_verifier::step_three(const srs &srs) { } +/// struct step_four_out_t constructor +template +step_four_out_t::step_four_out_t( + libff::Fr &&beta, + libff::Fr &&gamma, + libff::Fr &&alpha, + libff::Fr &&zeta, + libff::Fr &&nu, + libff::Fr &&u) + : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) +{ +} + /// Verifier Step 4: compute challenges hashed transcript as in prover /// description, from the common inputs, public input, and elements of /// pi-SNARK. TODO: fixed to the test vectors for now @@ -123,6 +146,13 @@ step_four_out_t plonk_verifier::step_four( return step_four_out; } +/// struct step_five_out_t constructor +template +step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) + : zh_zeta(zh_zeta) +{ +} + /// Verifier Step 5: compute zero polynomial evaluation /// /// INPUT @@ -146,6 +176,13 @@ step_five_out_t plonk_verifier::step_five( return step_five_out; } +/// struct step_six_out_t constructor +template +step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) + : L_0_zeta(L_0_zeta) +{ +} + /// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) /// Note: the paper counts the L-polynomials from 1; we count from 0 /// @@ -169,6 +206,13 @@ step_six_out_t plonk_verifier::step_six( return step_six_out; } +/// struct step_seven_out_t constructor +template +step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) + : PI_zeta(PI_zeta) +{ +} + /// Verifier Step 7: compute public input polynomial evaluation /// PI(zeta) /// @@ -192,6 +236,13 @@ step_seven_out_t plonk_verifier::step_seven( return step_seven_out; } +/// struct step_eight_out_t constructor +template +step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) + : r_prime_zeta(r_prime_zeta) +{ +} + /// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = /// r(zeta) - r0, where r0 is a constant term \note follows the Python /// reference implementation, which slightly deviates from the paper @@ -251,6 +302,12 @@ step_eight_out_t plonk_verifier::step_eight( return step_eight_out; } +/// struct step_nine_out_t constructor +template +step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) +{ +} + /// Verifier Step 9: compute first part of batched polynomial /// commitment [D]_1 Note: the reference implemention differs from the /// paper -- it does not add the following term to D1, but to F1 (Step @@ -353,6 +410,12 @@ step_nine_out_t plonk_verifier::step_nine( return step_nine_out; } +/// struct step_ten_out_t constructor +template +step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) +{ +} + /// Verifier Step 10: compute full batched polynomial commitment [F]_1 /// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + /// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the @@ -421,6 +484,12 @@ step_ten_out_t plonk_verifier::step_ten( return step_ten_out; } +/// struct step_eleven_out_t constructor +template +step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) +{ +} + /// Verifier Step 11: compute group-encoded batch evaluation [E]_1 /// /// INPUT From 61ebc3c5762cfe845c99fe4704ee9b6ff810b8af Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 09:40:03 +0100 Subject: [PATCH 045/154] plonk: renamed plonk.* to utils.* to better reflect the content of these files which contain common internal utility functions --- libsnark/zk_proof_systems/plonk/circuit.hpp | 2 +- libsnark/zk_proof_systems/plonk/tests/example.hpp | 2 +- libsnark/zk_proof_systems/plonk/{plonk.hpp => utils.hpp} | 8 ++++---- libsnark/zk_proof_systems/plonk/{plonk.tcc => utils.tcc} | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) rename libsnark/zk_proof_systems/plonk/{plonk.hpp => utils.hpp} (97%) rename libsnark/zk_proof_systems/plonk/{plonk.tcc => utils.tcc} (98%) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index db493f688..4c8458bb7 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -9,7 +9,7 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ -#include "libsnark/zk_proof_systems/plonk/plonk.hpp" +#include "libsnark/zk_proof_systems/plonk/utils.hpp" /// Declaration of Common Preprocessed Input data structures for a /// specific arithmetic circuit. diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 90a2114fc..fbc443ebe 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -10,7 +10,7 @@ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_HPP_ /// Test vectors for the implementation of the PlonK protocol \[GWC19] -/// (\see plonk.hpp) produced using the Python implementation of Plonk +/// (\see utils.hpp) produced using the Python implementation of Plonk /// available at [PlonkPy]. /// /// The test vector values trace the execution of the Plonk protocol for diff --git a/libsnark/zk_proof_systems/plonk/plonk.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp similarity index 97% rename from libsnark/zk_proof_systems/plonk/plonk.hpp rename to libsnark/zk_proof_systems/plonk/utils.hpp index 3bd4ebd5a..6ff3f5586 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -6,8 +6,8 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ -#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ -#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_HPP_ #include "libsnark/zk_proof_systems/plonk/tests/example.hpp" @@ -242,6 +242,6 @@ void plonk_compute_accumulator( } // namespace libsnark -#include "libsnark/zk_proof_systems/plonk/plonk.tcc" +#include "libsnark/zk_proof_systems/plonk/utils.tcc" -#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_HPP_ +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/plonk.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc similarity index 98% rename from libsnark/zk_proof_systems/plonk/plonk.tcc rename to libsnark/zk_proof_systems/plonk/utils.tcc index a88cc9f0b..ce498ea33 100644 --- a/libsnark/zk_proof_systems/plonk/plonk.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -6,11 +6,11 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ -#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ -#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ /// Implementation of interfaces for a ppzkSNARK for Plonk. See -/// plonk.hpp . +/// utils.hpp . namespace libsnark { @@ -441,4 +441,4 @@ void plonk_compute_accumulator( } // namespace libsnark -#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PLONK_TCC_ +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ From a281e27eba94eba907dc88e59338eb4019911705 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 11:15:07 +0100 Subject: [PATCH 046/154] plonk: renamed plonk_multiplicative_subgroups_H_k1H_k2H to plonk_compute_cosets_H_k1H_k2H --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 2 +- libsnark/zk_proof_systems/plonk/utils.hpp | 2 +- libsnark/zk_proof_systems/plonk/utils.tcc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index d4733b693..18a6d640c 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -215,7 +215,7 @@ circuit_t plonk_circuit_description_from_example( // ie. circuit.omega_roots, circuit.omega_roots_k1 and // circuit.omega_roots_k2 std::vector H_gen; - plonk_multiplicative_subgroups_H_k1H_k2H(num_gates, k1, k2, H_gen); + plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_gen); // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H #ifdef DEBUG_PLONK diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 6ff3f5586..16a47077d 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -154,7 +154,7 @@ void plonk_compute_roots_of_unity_omega( /// /// \note uses plonk_compute_roots_of_unity_omega template -void plonk_multiplicative_subgroups_H_k1H_k2H( +void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, const FieldT k1, const FieldT k2, diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index ce498ea33..4b29b980b 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -232,7 +232,7 @@ void plonk_compute_roots_of_unity_omega( /// /// \note uses plonk_compute_roots_of_unity_omega template -void plonk_multiplicative_subgroups_H_k1H_k2H( +void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, const FieldT k1, const FieldT k2, From 51439d11dfae9bb8135be3ccf990ea7c7b3746d9 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 11:20:45 +0100 Subject: [PATCH 047/154] plonk: removed obsolete function plonk_interpolate_over_lagrange_basis --- libsnark/zk_proof_systems/plonk/utils.hpp | 31 ------------ libsnark/zk_proof_systems/plonk/utils.tcc | 61 ----------------------- 2 files changed, 92 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 16a47077d..bb2a45848 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -91,37 +91,6 @@ template void plonk_interpolate_polynomial_from_points( const std::vector &f_points, polynomial &f_poly); -/// Interpolate a polynomial from a set of points over Lagrange basis -/// -/// INPUT: -/// -/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), -/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], -/// ... which we want to interpolate as a polynomial -/// -/// \param[in] L[0..n-1][0..n-1]: Lagrange basis over the n roots of -/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, -/// a1, ..., a_{n-1}] is a vector representing the -/// coefficients of the i-th Lagrange polynomial L_i(x) = -/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 -/// and L_i(x\neq{omega_i)})=0 -/// -/// OUTPUT: -/// -/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., -/// a_{n-1}] of the polynomial f(x) interpolating the set -/// of points f_points over the Lagrange basis. For -/// example if f_poly[0..n-1] = [a0, a1, ..., a_{n-1}] -/// then this represents the polynomial f(x) = -/// \sum^{n-1}_{i=0} f_vec[i] * L[i] = -/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that -/// f(omega_i)=f_vec[i]. -template -void plonk_interpolate_over_lagrange_basis( - const std::vector &f_points, - const std::vector> &L, - polynomial &f_poly); - /// Compute the selector polynomials of the given circuit (also /// called here "q-polynomials"). See Sect. 8.1. The matrix /// gates_matrix_transpose has 5 rows, each corresponding to the diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 4b29b980b..25b1abc2f 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -90,67 +90,6 @@ void plonk_interpolate_polynomial_from_points( domain->iFFT(f_poly); } -/// Interpolate a polynomial from a set of points over Lagrange basis -/// -/// INPUT: -/// -/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), -/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], -/// ... which we want to interpolate as a polynomial -/// -/// \param[in] L[0..n-1][0..n-1]: Lagrange basis over the n roots of -/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, -/// a1, ..., a_{n-1}] is a vector representing the -/// coefficients of the i-th Lagrange polynomial L_i(x) = -/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 -/// and L_i(x\neq{omega_i)})=0 -/// -/// OUTPUT: -/// -/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., -/// a_{n-1}] of the polynomial f(x) interpolating the set -/// of points f_points over the Lagrange basis. For -/// example if f_poly[0..n-1] = [a0, a1, ..., a_{n-1}] -/// then this represents the polynomial f(x) = -/// \sum^{n-1}_{i=0} f_vec[i] * L[i] = -/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that -/// f(omega_i)=f_vec[i]. -template -void plonk_interpolate_over_lagrange_basis( - const std::vector &f_points, - const std::vector> &L, - polynomial &f_poly) -{ - assert(L.size() != 0); - assert(L.size() == L[0].size()); - assert(L.size() == f_points.size()); - - size_t num_gates = L.size(); - - // initialize f_poly - std::fill(f_poly.begin(), f_poly.end(), FieldT(0)); - - // the num_gates components of f_poly. each components is - // a polynomial that is the multiplication of the i-th element of - // f_points to the i-th polynomial in the lagrange basis L[i]: - // f_poly_component[i] = f_points[i] * L[i] - for (size_t i = 0; i < num_gates; ++i) { - polynomial f_poly_component_i; - // represent the scalar f_points[i] as an all-zero vector with - // only the first element set to f_points[i]. this is done in - // order to use libfqfft multiplication function as a function - // for multiply vector by scalar. - std::vector f_points_coeff_i(num_gates, FieldT(0)); - f_points_coeff_i[0] = f_points[i]; - // f_poly_component[i] = f_points[i] * L[i] - libfqfft::_polynomial_multiplication( - f_poly_component_i, f_points_coeff_i, L[i]); - // accumulate the i-th component to f_poly - libfqfft::_polynomial_addition( - f_poly, f_poly, f_poly_component_i); - } -} - /// Compute the selector polynomials of the given circuit (also /// called here "q-polynomials"). See Sect. 8.1. The matrix /// gates_matrix_transpose has 5 rows, each corresponding to the From 30b026a207a4544740510d95526b6774f6e86466 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 11:33:10 +0100 Subject: [PATCH 048/154] plonk: removed exit(EXIT_FAILURE) in several exception handles so that we don't exit the process upon error. --- libsnark/zk_proof_systems/plonk/prover.tcc | 1 - libsnark/zk_proof_systems/plonk/utils.tcc | 2 -- 2 files changed, 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 2ff2c5a11..f7d3924a0 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -450,7 +450,6 @@ round_three_out_t plonk_prover::round_three( } } catch (const std::logic_error &e) { std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); } // break this->t_poly_long into three parts: lo, mid, hi, each of degree diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 25b1abc2f..0bc8bac6b 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -139,7 +139,6 @@ void plonk_compute_roots_of_unity_omega( } } catch (const std::invalid_argument &e) { std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); } omega.resize(NUM_HSETS, std::vector(num_gates)); @@ -186,7 +185,6 @@ void plonk_compute_cosets_H_k1H_k2H( } } catch (const std::invalid_argument &e) { std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); } // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, From eefca7edd9bee3138bc3cac5c46dc21887de2d46 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 11:47:57 +0100 Subject: [PATCH 049/154] plonk: modified functions plonk_permute_subgroup_H and plonk_compute_permutation_polynomials not to rely on the caller for allocating the correct sizes of the return parameters. those are now allocated within the functions. --- .../plonk/tests/test_plonk.cpp | 14 ++++---------- libsnark/zk_proof_systems/plonk/utils.hpp | 10 ++++------ libsnark/zk_proof_systems/plonk/utils.tcc | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 18a6d640c..f5d4bcc4d 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -203,9 +203,6 @@ circuit_t plonk_circuit_description_from_example( Q_polys.resize(num_qpolys, polynomial(num_gates)); plonk_compute_selector_polynomials(gates_matrix_transpose, Q_polys); - // number of generators for H, Hk1, Hk2 - int num_hgen = NUM_HSETS; - // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, // omega[2] are omega[0]*k2 std::vector> omega_roots; @@ -227,9 +224,8 @@ circuit_t plonk_circuit_description_from_example( #endif // #ifdef DEBUG_PLONK // permute circuit.H_gen according to the wire permutation - std::vector H_gen_permute; - H_gen_permute.resize(num_hgen * num_gates, Field(0)); - plonk_permute_subgroup_H(H_gen, wire_permutation, H_gen_permute); + std::vector H_gen_permute = + plonk_permute_subgroup_H(H_gen, wire_permutation, num_gates); // TODO: write unit test for plonk_permute_subgroup_H #ifdef DEBUG_PLONK printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); @@ -241,10 +237,8 @@ circuit_t plonk_circuit_description_from_example( // compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) - std::vector> S_polys; - S_polys.resize(num_hgen, polynomial(num_gates)); - plonk_compute_permutation_polynomials( - H_gen_permute, num_gates, S_polys); + std::vector> S_polys = + plonk_compute_permutation_polynomials(H_gen_permute, num_gates); circuit_t circuit( std::move(num_gates), diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index bb2a45848..02464c51e 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -134,18 +134,16 @@ void plonk_compute_cosets_H_k1H_k2H( /// plonk_compute_roots_of_unity_omega, \see /// plonk_roots_of_unity_omega_to_subgroup_H template -void plonk_permute_subgroup_H( +std::vector plonk_permute_subgroup_H( const std::vector &H_gen, const std::vector &wire_permutation, - std::vector &H_gen_permute); + const size_t num_gates); /// compute the permutation polynomials S_sigma_1, S_sigma_2, /// S_sigma_2 (see [GWC19], Sect. 8.1) template -void plonk_compute_permutation_polynomials( - const std::vector &H_gen_permute, - const size_t num_gates, - std::vector> &S_polys); +std::vector> plonk_compute_permutation_polynomials( + const std::vector &H_gen_permute, const size_t num_gates); // A wrapper for multi_exp_method_BDLO12_signed() dot-product a // vector of group elements in G1 (curve points) with a vector of diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 0bc8bac6b..1112c713d 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -204,28 +204,29 @@ void plonk_compute_cosets_H_k1H_k2H( /// plonk_compute_roots_of_unity_omega, \see /// plonk_roots_of_unity_omega_to_subgroup_H template -void plonk_permute_subgroup_H( +std::vector plonk_permute_subgroup_H( const std::vector &H_gen, const std::vector &wire_permutation, - std::vector &H_gen_permute) + const size_t num_gates) { assert(H_gen.size() > 0); + std::vector H_gen_permute; + H_gen_permute.resize(NUM_HSETS * num_gates, FieldT(0)); for (size_t i = 0; i < H_gen.size(); ++i) { H_gen_permute[i] = H_gen[wire_permutation[i] - 1]; } + return H_gen_permute; } /// compute the permutation polynomials S_sigma_1, S_sigma_2, /// S_sigma_2 (see [GWC19], Sect. 8.1) template -void plonk_compute_permutation_polynomials( - const std::vector &H_gen_permute, - const size_t num_gates, - std::vector> &S_polys) +std::vector> plonk_compute_permutation_polynomials( + const std::vector &H_gen_permute, const size_t num_gates) { - assert(S_polys.size() == NUM_HSETS); - assert(S_polys[0].size() == num_gates); assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + std::vector> S_polys; + S_polys.resize(NUM_HSETS, polynomial(num_gates)); for (size_t i = 0; i < NUM_HSETS; ++i) { typename std::vector::const_iterator begin = H_gen_permute.begin() + (i * num_gates); @@ -234,6 +235,7 @@ void plonk_compute_permutation_polynomials( std::vector S_points(begin, end); plonk_interpolate_polynomial_from_points(S_points, S_polys[i]); } + return S_polys; } // A wrapper for multi_exp_method_BDLO12_signed() dot-product a From bd6084d971dd8aefe42bf4759fb72c790177ab58 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 12:03:22 +0100 Subject: [PATCH 050/154] plonk: renamed input parameter n of plonk_compute_permutation_polynomials and plonk_compute_accumulator to the more expressive num_gates --- libsnark/zk_proof_systems/plonk/utils.tcc | 45 ++++++++++++----------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 1112c713d..7b1de7872 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -320,7 +320,7 @@ void plonk_evaluate_polys_at_secret_G1( template FieldT plonk_compute_accumulator_factor( const size_t i, - const size_t n, // nconstraimts + const size_t num_gates, const FieldT beta, const FieldT gamma, const std::vector &witness, @@ -328,25 +328,26 @@ FieldT plonk_compute_accumulator_factor( const std::vector &H_gen_permute, const std::vector &A) { - assert(n); - assert((i >= 0) && (i < n)); - assert(witness.size() == (3 * n)); - assert(H_gen.size() == (3 * n)); - assert(H_gen_permute.size() == (3 * n)); - assert(A.size() == n); + assert(num_gates); + assert((i >= 0) && (i < num_gates)); + assert(witness.size() == (NUM_HSETS * num_gates)); + assert(H_gen.size() == (NUM_HSETS * num_gates)); + assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + assert(A.size() == num_gates); FieldT res = FieldT(1); if (i > 0) { FieldT nom_1 = witness[i - 1] + (beta * H_gen[i - 1]) + gamma; FieldT den_1 = witness[i - 1] + (beta * H_gen_permute[i - 1]) + gamma; - FieldT nom_2 = witness[n + i - 1] + (beta * H_gen[n + i - 1]) + gamma; - FieldT den_2 = - witness[n + i - 1] + (beta * H_gen_permute[n + i - 1]) + gamma; + FieldT nom_2 = witness[num_gates + i - 1] + + (beta * H_gen[num_gates + i - 1]) + gamma; + FieldT den_2 = witness[num_gates + i - 1] + + (beta * H_gen_permute[num_gates + i - 1]) + gamma; - FieldT nom_3 = - witness[2 * n + i - 1] + (beta * H_gen[2 * n + i - 1]) + gamma; - FieldT den_3 = witness[2 * n + i - 1] + - (beta * H_gen_permute[2 * n + i - 1]) + gamma; + FieldT nom_3 = witness[2 * num_gates + i - 1] + + (beta * H_gen[2 * num_gates + i - 1]) + gamma; + FieldT den_3 = witness[2 * num_gates + i - 1] + + (beta * H_gen_permute[2 * num_gates + i - 1]) + gamma; FieldT nom = nom_1 * nom_2 * nom_3; FieldT den = den_1 * den_2 * den_3; @@ -359,7 +360,7 @@ FieldT plonk_compute_accumulator_factor( // - A: accumulator vector template void plonk_compute_accumulator( - const size_t n, // num_gates + const size_t num_gates, const FieldT beta, const FieldT gamma, const std::vector &witness, @@ -367,14 +368,14 @@ void plonk_compute_accumulator( const std::vector &H_gen_permute, std::vector &A) { - assert(n); - assert(witness.size() == (3 * n)); - assert(H_gen.size() == (3 * n)); - assert(H_gen_permute.size() == (3 * n)); - assert(A.size() == n); - for (size_t i = 0; i < n; ++i) { + assert(num_gates); + assert(witness.size() == (NUM_HSETS * num_gates)); + assert(H_gen.size() == (NUM_HSETS * num_gates)); + assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + assert(A.size() == num_gates); + for (size_t i = 0; i < num_gates; ++i) { A[i] = plonk_compute_accumulator_factor( - i, n, beta, gamma, witness, H_gen, H_gen_permute, A); + i, num_gates, beta, gamma, witness, H_gen, H_gen_permute, A); } } From e5899200eaf6e43d60fa8ea839ce1e2dc4e20827 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 12:09:14 +0100 Subject: [PATCH 051/154] plonk: fixed typo in comments --- libsnark/zk_proof_systems/plonk/prover.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 10f73e86d..2480e9367 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -369,7 +369,7 @@ template class plonk_prover /// INPUT /// \param[in] beta, gamma: permutation challenges -- hashes of /// transcript (from round 2) - /// \param[in] alpha: quotinet challenge -- hash of transcript (from + /// \param[in] alpha: quotient challenge -- hash of transcript (from /// round 3) /// \param[in] zeta: evaluation challenge -- hash of transcript (from /// round 4) From 6b2d65dafe8116baeef5b52a21071f7eec81d0c6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 12:14:43 +0100 Subject: [PATCH 052/154] plonk: fixed multiple input parameters to prover functions to be passed by const reference in order to save an extra copy --- libsnark/zk_proof_systems/plonk/prover.hpp | 28 +++++++++++----------- libsnark/zk_proof_systems/plonk/prover.tcc | 28 +++++++++++----------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 2480e9367..7a43a2a9a 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -248,7 +248,7 @@ template class plonk_prover /// \param[out] zh_poly: vanishing polynomial /// \param[out] null_poly: 0 polynomial /// \param[out] neg_one_poly: -1 polynomial - static round_zero_out_t round_zero(const srs srs); + static round_zero_out_t round_zero(const srs &srs); /// Prover Round 1 /// @@ -271,7 +271,7 @@ template class plonk_prover /// [a]_1, [b]_1, [c]_1 in [GWC19] static round_one_out_t round_one( const round_zero_out_t &round_zero_out, - const std::vector> blind_scalars, + const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs); @@ -290,8 +290,8 @@ template class plonk_prover /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret static round_two_out_t round_two( - const libff::Fr beta, - const libff::Fr gamma, + const libff::Fr &beta, + const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, @@ -319,9 +319,9 @@ template class plonk_prover /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted /// by w static round_three_out_t round_three( - const libff::Fr alpha, - const libff::Fr beta, - const libff::Fr gamma, + const libff::Fr &alpha, + const libff::Fr &beta, + const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -359,7 +359,7 @@ template class plonk_prover /// same in order to match the test vectors. TODO can /// remove t_zeta in the future static round_four_out_t round_four( - const libff::Fr zeta, + const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs); @@ -409,11 +409,11 @@ template class plonk_prover /// polynomial W_{zeta omega}(x) at secert input /// i.e. [W_{zeta omega}(secret)]_1 static round_five_out_t round_five( - const libff::Fr alpha, - const libff::Fr beta, - const libff::Fr gamma, - const libff::Fr zeta, - const libff::Fr nu, + const libff::Fr &alpha, + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &zeta, + const libff::Fr &nu, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -476,7 +476,7 @@ template class plonk_prover static plonk_proof compute_proof( const srs &srs, const std::vector &witness, - const std::vector> blind_scalars, + const std::vector> &blind_scalars, transcript_hash_t &transcript_hash); }; diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index f7d3924a0..c73224acb 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -38,7 +38,7 @@ round_zero_out_t::round_zero_out_t( /// \param[out] null_poly: 0 polynomial /// \param[out] neg_one_poly: -1 polynomial template -round_zero_out_t plonk_prover::round_zero(const srs srs) +round_zero_out_t plonk_prover::round_zero(const srs &srs) { using Field = libff::Fr; @@ -96,7 +96,7 @@ round_one_out_t::round_one_out_t( template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, - const std::vector> blind_scalars, + const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs) { @@ -172,8 +172,8 @@ round_two_out_t::round_two_out_t( /// evaluated at secret template round_two_out_t plonk_prover::round_two( - const libff::Fr beta, - const libff::Fr gamma, + const libff::Fr &beta, + const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, @@ -255,9 +255,9 @@ round_three_out_t::round_three_out_t( /// by w template round_three_out_t plonk_prover::round_three( - const libff::Fr alpha, - const libff::Fr beta, - const libff::Fr gamma, + const libff::Fr &alpha, + const libff::Fr &beta, + const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -535,7 +535,7 @@ round_four_out_t::round_four_out_t( /// remove t_zeta in the future template round_four_out_t plonk_prover::round_four( - const libff::Fr zeta, + const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs) @@ -638,11 +638,11 @@ round_five_out_t::round_five_out_t( /// i.e. [W_{zeta omega}(secret)]_1 template round_five_out_t plonk_prover::round_five( - const libff::Fr alpha, - const libff::Fr beta, - const libff::Fr gamma, - const libff::Fr zeta, - const libff::Fr nu, + const libff::Fr &alpha, + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &zeta, + const libff::Fr &nu, const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -1014,7 +1014,7 @@ template plonk_proof plonk_prover::compute_proof( const srs &srs, const std::vector &witness, - const std::vector> blind_scalars, + const std::vector> &blind_scalars, transcript_hash_t &transcript_hash) { // Prover Round 0 (initialization) From 2d50edf4f6bc07706ed6d0d0afd3229038c1831a Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 12:32:19 +0100 Subject: [PATCH 053/154] plonk: corrected comment --- libsnark/zk_proof_systems/plonk/prover.tcc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index c73224acb..f52e7f748 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -452,9 +452,9 @@ round_three_out_t plonk_prover::round_three( std::cout << "Error: " << e.what() << "\n"; } - // break this->t_poly_long into three parts: lo, mid, hi, each of degree - // 7. note: (srs.num_gates+3) is the length of the CRS = - // (srs.num_gates+2) powers of G1 + 1 power of G2 + // break this->t_poly_long into three parts: lo, mid, hi, each of + // degree (num_gates-1). note: (srs.num_gates+3) is the length of + // the CRS = (srs.num_gates+2) powers of G1 + 1 power of G2 t_poly.resize(num_hgen); for (int i = 0; i < num_hgen; ++i) { typename std::vector::iterator begin = From a6dbb31b9cebd52362820265460e66dfaa1705d2 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 14:02:18 +0100 Subject: [PATCH 054/154] plonk: added missing reference to the reference Python implementation \[PlonkPy] in comments --- libsnark/zk_proof_systems/plonk/prover.tcc | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index f52e7f748..f6548f378 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -530,9 +530,9 @@ round_four_out_t::round_four_out_t( /// 3, see pp28 [GWC19]) evaluated at x=zeta /// i.e. t(z). IMPORTANT! the original Plonk proposal /// [GWC19] does not output this parameter t_zeta. The -/// Python reference implementation does, so we do the -/// same in order to match the test vectors. TODO can -/// remove t_zeta in the future +/// Python reference implementation \[PlonkPy] does, so we +/// do the same in order to match the test vectors. TODO +/// can remove t_zeta in the future template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, @@ -613,9 +613,9 @@ round_five_out_t::round_five_out_t( /// 3, see pp28 [GWC19]) evaluated at x=zeta /// i.e. t(z). IMPORTANT! the original Plonk proposal /// [GWC19] does not output this parameter t_zeta. The -/// Python reference implementation does, so we do the same -/// in order to match the test vectors. TODO can remove -/// t_zeta in the future (from round 4) +/// Python reference implementation \[PlonkPy] does, so we +/// do the same in order to match the test vectors. TODO +/// can remove t_zeta in the future (from round 4) /// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) /// shifted by w (output from Round 3) evaluated at x=zeta /// i.e. z(zeta*w) (from round 4) @@ -734,8 +734,8 @@ round_five_out_t plonk_prover::round_five( // // r(x) = r(x) - zh(zeta) (t_lo(x) + zeta^n t_mid(x) + zeta^2n t_hi(x)) // - // In the reference implementation, the missing term is added in - // the computation of the W_zeta(x) polynomial + // In the reference implementation \[PlonkPy], the missing term is + // added in the computation of the W_zeta(x) polynomial // // linearisation polynomial r(x) polynomial r_poly; @@ -967,15 +967,15 @@ plonk_proof::plonk_proof( /// [W_zeta]_1, [W_{zeta omega}]_1 /// r_zeta) /// -/// \note in the reference Python implementation, r_zeta (the -/// evaluation of the linearlization polynomial r(X) at zeta from +/// \note in the reference Python implementation \[PlonkPy], r_zeta +/// (the evaluation of the linearlization polynomial r(X) at zeta from /// Prover round 5) is added to the pi-SNARK proof. In the paper this /// is omitted, which seems to make the proof shorter by 1 element at /// the epxense of a slightly heavier computation on the verifier's -/// side. Here we follow the reference implementation to make sure we -/// match the test values. TODO: once all test vectors are verified, -/// we may remove r_zeta from the proof to be fully compliant with the -/// paper. +/// side. Here we follow the reference implementation \[PlonkPy] to +/// make sure we match the test values. TODO: once all test vectors +/// are verified, we may remove r_zeta from the proof to be fully +/// compliant with the paper. /// /// Mapping code-to-paper quantities /// From ec7c826584557f8f5630411805daad1298422e70 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 14:04:28 +0100 Subject: [PATCH 055/154] plonk: modified plonk_verifier::step_four() to directly pass the input parameter transcript_hash to the constructor instead of first copying and then moving. --- libsnark/zk_proof_systems/plonk/verifier.hpp | 2 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 28 +++++--------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 246f69a8c..e9f9f6631 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -203,7 +203,7 @@ template class plonk_verifier /// \param[out] u: multipoint evaluation challenge - hash of /// transcript static step_four_out_t step_four( - transcript_hash_t &transcript_hash); + const transcript_hash_t &transcript_hash); /// Verifier Step 5: compute zero polynomial evaluation /// diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 5d5069cc5..dbcd42796 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -118,30 +118,16 @@ step_four_out_t::step_four_out_t( /// transcript template step_four_out_t plonk_verifier::step_four( - transcript_hash_t &transcript_hash) + const transcript_hash_t &transcript_hash) { // step 4 output - libff::Fr beta; - libff::Fr gamma; - libff::Fr alpha; - libff::Fr zeta; - libff::Fr nu; - libff::Fr u; - - beta = transcript_hash.beta; - gamma = transcript_hash.gamma; - alpha = transcript_hash.alpha; - zeta = transcript_hash.zeta; - nu = transcript_hash.nu; - u = transcript_hash.u; - step_four_out_t step_four_out( - std::move(beta), - std::move(gamma), - std::move(alpha), - std::move(zeta), - std::move(nu), - std::move(u)); + Field(transcript_hash.beta), + Field(transcript_hash.gamma), + Field(transcript_hash.alpha), + Field(transcript_hash.zeta), + Field(transcript_hash.nu), + Field(transcript_hash.u)); return step_four_out; } From 533cc4956d4a10da3a576672b250f9bbbbe8eccd Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 13 Jul 2022 14:53:03 +0100 Subject: [PATCH 056/154] plonk: removed check that we are on the BLS12-381 in view of the fact that all example test vectors are defined on this curve. the check is not necessary since there will be an error at the compiler level if there is an attempt to compile the unit tests for a curve other than BLS12-381. --- .../plonk/tests/test_plonk.cpp | 88 ++++--------------- 1 file changed, 17 insertions(+), 71 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index f5d4bcc4d..e4330c478 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -134,20 +134,12 @@ void test_verify_invalid_proof( } /// Compute or fill-in ciruit specific data from example. +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template circuit_t plonk_circuit_description_from_example( const plonk_example example) { - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - using Field = libff::Fr; // public input (PI) @@ -458,19 +450,12 @@ void test_plonk_prover_round_five( ASSERT_EQ(W_zeta_omega_at_secret_aff.Y, example.W_zeta_omega_at_secret[1]); } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_prover_rounds() { using Field = libff::Fr; - // example test values are defined specifically for the BLS12-381 - // curve, so make sure we are using this curve - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - ppT::init_public_params(); // load test vector values from example circuit @@ -562,18 +547,12 @@ template void test_plonk_prover_rounds() srs); } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_srs() { using Field = libff::Fr; - // example test values are defined specifically for the BLS12-381 - // curve, so make sure we are using this curve - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } ppT::init_public_params(); // load test vector values from example circuit plonk_example example; @@ -609,18 +588,12 @@ template void test_plonk_srs() } } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_prover() { using Field = libff::Fr; - // example test values are defined specifically for the BLS12-381 - // curve, so make sure we are using this curve - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } ppT::init_public_params(); // load test vector values from example circuit plonk_example example; @@ -700,20 +673,12 @@ template void test_plonk_prover() ASSERT_EQ(W_zeta_omega_at_secret_aff.Y, example.W_zeta_omega_at_secret[1]); } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_verifier_preprocessed_input( const plonk_example &example, const srs &srs) { - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } - // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = plonk_verifier::preprocessed_input(srs); @@ -846,7 +811,9 @@ void test_plonk_verifier_step_eleven( ASSERT_EQ(E1_aff.Y, example.E1[1]); } -// step 12 +/// test verifier step 12 +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_verifier_pairing( const plonk_example &example, @@ -857,15 +824,6 @@ void test_plonk_verifier_pairing( const plonk_proof &proof, const srs &srs) { - // the example class is defined specifically for the BLS12-381 - // curve, so make sure we are using this curve TODO: remove when - // the implementation is stable and tested - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } using Field = libff::Fr; std::vector> curve_points_lhs{ proof.W_zeta_at_secret, proof.W_zeta_omega_at_secret}; @@ -912,18 +870,12 @@ void test_plonk_verifier_pairing( ASSERT_TRUE(b_accept); } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_verifier_steps() { using Field = libff::Fr; - // example test values are defined specifically for the BLS12-381 - // curve, so make sure we are using this curve - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } ppT::init_public_params(); // load test vector values from example circuit plonk_example example; @@ -1021,18 +973,12 @@ template void test_plonk_verifier_steps() srs); } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve template void test_plonk_verifier() { using Field = libff::Fr; - // example test values are defined specifically for the BLS12-381 - // curve, so make sure we are using this curve - try { - plonk_exception_assert_curve_bls12_381(); - } catch (const std::domain_error &e) { - std::cout << "Error: " << e.what() << "\n"; - exit(EXIT_FAILURE); - } ppT::init_public_params(); // load test vector values from example circuit plonk_example example; From a5de10c84f0662f6cfe4b73dbe9ff8a14e847124 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 20 Jul 2022 16:47:41 +0100 Subject: [PATCH 057/154] plonk: remove all all try-catch clauses and let the caller handle the thrown exceptions. addresses issue https://github.com/clearmatics/libsnark/issues/57 --- libsnark/zk_proof_systems/plonk/prover.tcc | 10 +++------ libsnark/zk_proof_systems/plonk/utils.tcc | 26 +++++++++------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index f6548f378..2b64baf62 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -443,13 +443,9 @@ round_three_out_t plonk_prover::round_three( polynomial remainder; libfqfft::_polynomial_division( t_poly_long, remainder, t_poly_long, round_zero_out.zh_poly); - try { - bool b_zero_remainder = libfqfft::_is_zero(remainder); - if (!b_zero_remainder) { - throw std::logic_error("Non-zero remainder in polynomial division"); - } - } catch (const std::logic_error &e) { - std::cout << "Error: " << e.what() << "\n"; + bool b_zero_remainder = libfqfft::_is_zero(remainder); + if (!b_zero_remainder) { + throw std::logic_error("Non-zero remainder in polynomial division"); } // break this->t_poly_long into three parts: lo, mid, hi, each of diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 7b1de7872..d57f4c910 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -131,14 +131,11 @@ void plonk_compute_roots_of_unity_omega( { // ensure that num_gates is not 0 and is power of 2 // TODO: check also that it's less than 2^(ppT::s) - try { - bool b_nonzero = (num_gates > 0); - bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); - if (!(b_nonzero && b_is_power2)) { - throw std::invalid_argument("Curve is not BLS12-381"); - } - } catch (const std::invalid_argument &e) { - std::cout << "Error: " << e.what() << "\n"; + bool b_nonzero = (num_gates > 0); + bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); + if (!(b_nonzero && b_is_power2)) { + throw std::invalid_argument( + "Number of gates not power of 2 or is zero."); } omega.resize(NUM_HSETS, std::vector(num_gates)); @@ -177,14 +174,11 @@ void plonk_compute_cosets_H_k1H_k2H( std::vector &H_gen) { // ensure that num_gates is not 0 and is power of 2 - try { - bool b_nonzero = (num_gates > 0); - bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); - if (!(b_nonzero && b_is_power2)) { - throw std::invalid_argument("Curve is not BLS12-381"); - } - } catch (const std::invalid_argument &e) { - std::cout << "Error: " << e.what() << "\n"; + bool b_nonzero = (num_gates > 0); + bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); + if (!(b_nonzero && b_is_power2)) { + throw std::invalid_argument( + "Number of gates not power of 2 or is zero."); } // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, From d20f7ca530c999977d1411d0efdce9e7103045d3 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 22 Jul 2022 15:02:39 +0100 Subject: [PATCH 058/154] plonk: fixed functions plonk_compute_accumulator and plonk_compute_selector_polynomials to allocate the size of their return values inside of the function i.e. not to rely on the caller to pass inputs with correct size. addressing issue https://github.com/clearmatics/libsnark/issues/58, bullet 7 --- libsnark/zk_proof_systems/plonk/prover.tcc | 11 ++------- .../plonk/tests/test_plonk.cpp | 17 ++++--------- libsnark/zk_proof_systems/plonk/utils.hpp | 13 +++++----- libsnark/zk_proof_systems/plonk/utils.tcc | 24 +++++++++++-------- 4 files changed, 27 insertions(+), 38 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 2b64baf62..de023d95d 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -194,15 +194,8 @@ round_two_out_t plonk_prover::round_two( z1_blind_poly, z1_blind_poly, round_zero_out.zh_poly); // A[0] = 1; ... A[i] = computed from (i-1) - std::vector A_vector(srs.num_gates, Field(0)); - plonk_compute_accumulator( - srs.num_gates, - beta, - gamma, - witness, - srs.H_gen, - srs.H_gen_permute, - A_vector); + std::vector A_vector = plonk_compute_accumulator( + srs.num_gates, beta, gamma, witness, srs.H_gen, srs.H_gen_permute); polynomial A_poly(srs.num_gates); plonk_interpolate_polynomial_from_points(A_vector, A_poly); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index e4330c478..193d8fcb7 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -191,9 +191,9 @@ circuit_t plonk_circuit_description_from_example( // transposed gates matrix over the Lagrange basis q_poly = \sum_i // q[i] * L[i] where q[i] is a coefficient (a scalar Field // element) and L[i] is a polynomial with Field coefficients - std::vector> Q_polys; - Q_polys.resize(num_qpolys, polynomial(num_gates)); - plonk_compute_selector_polynomials(gates_matrix_transpose, Q_polys); + std::vector> Q_polys = + plonk_compute_selector_polynomials( + num_gates, num_qpolys, gates_matrix_transpose); // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, // omega[2] are omega[0]*k2 @@ -257,15 +257,8 @@ void test_plonk_compute_accumulator( { using Field = libff::Fr; // A[0] = 1; ... A[i] = computed from (i-1) - std::vector A_vector(srs.num_gates, Field(0)); - plonk_compute_accumulator( - srs.num_gates, - beta, - gamma, - witness, - srs.H_gen, - srs.H_gen_permute, - A_vector); + std::vector A_vector = plonk_compute_accumulator( + srs.num_gates, beta, gamma, witness, srs.H_gen, srs.H_gen_permute); polynomial A_poly(srs.num_gates); plonk_interpolate_polynomial_from_points(A_vector, A_poly); diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 02464c51e..2d788e777 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -97,9 +97,9 @@ void plonk_interpolate_polynomial_from_points( /// values L, R, M, O and C for each gate; the number of columns is /// equal to the number of gates. L_basis is the Lagrange basis. template -void plonk_compute_selector_polynomials( - const std::vector> &gates_matrix_transpose, - std::vector> &Q_polys); +std::vector> plonk_compute_selector_polynomials( + const size_t &num_gates, + const std::vector> &gates_matrix_transpose); /// This function computes the sets H, k1H, k2H. H is a /// multiplicative subgroup containing the n-th roots of unity in Fr, @@ -198,14 +198,13 @@ FieldT plonk_compute_accumulator_factor( /// A: accumulatro vector template -void plonk_compute_accumulator( - const size_t n, // num_gates +std::vector plonk_compute_accumulator( + const size_t num_gates, const FieldT beta, const FieldT gamma, const std::vector &witness, const std::vector &H_gen, // H, Hk1, Hk2 - const std::vector &H_gen_permute, - std::vector &A); + const std::vector &H_gen_permute); } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index d57f4c910..e077ad98d 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -96,17 +96,21 @@ void plonk_interpolate_polynomial_from_points( /// values L, R, M, O and C for each gate; the number of columns is /// equal to the number of gates. L_basis is the Lagrange basis. template -void plonk_compute_selector_polynomials( - const std::vector> &gates_matrix_transpose, - std::vector> &Q_polys) +std::vector> plonk_compute_selector_polynomials( + const size_t &num_gates, + const size_t &num_qpolys, + const std::vector> &gates_matrix_transpose) { - assert(gates_matrix_transpose.size() == Q_polys.size()); - assert(gates_matrix_transpose[0].size() == Q_polys[0].size()); - size_t num_qpolys = gates_matrix_transpose.size(); + assert(gates_matrix_transpose.size() == num_qpolys); + assert(gates_matrix_transpose[0].size() == num_gates); + + std::vector> Q_polys; + Q_polys.resize(num_qpolys, polynomial(num_gates)); for (size_t i = 0; i < num_qpolys; ++i) { std::vector q_vec = gates_matrix_transpose[i]; plonk_interpolate_polynomial_from_points(q_vec, Q_polys[i]); } + return Q_polys; }; template @@ -353,24 +357,24 @@ FieldT plonk_compute_accumulator_factor( // - A: accumulator vector template -void plonk_compute_accumulator( +std::vector plonk_compute_accumulator( const size_t num_gates, const FieldT beta, const FieldT gamma, const std::vector &witness, const std::vector &H_gen, // H, Hk1, Hk2 - const std::vector &H_gen_permute, - std::vector &A) + const std::vector &H_gen_permute) { assert(num_gates); assert(witness.size() == (NUM_HSETS * num_gates)); assert(H_gen.size() == (NUM_HSETS * num_gates)); assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); - assert(A.size() == num_gates); + std::vector A(num_gates, FieldT(0)); for (size_t i = 0; i < num_gates; ++i) { A[i] = plonk_compute_accumulator_factor( i, num_gates, beta, gamma, witness, H_gen, H_gen_permute, A); } + return A; } } // namespace libsnark From dd322746d397855b6c98ec22c89d51bb44f21812 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 22 Jul 2022 13:08:45 +0100 Subject: [PATCH 059/154] plonk: removed storing the pre-computed Lagrange basis as part of the srs. instead compute it on-the-fly as we need it. addresses issue https://github.com/clearmatics/libsnark/issues/55 --- libsnark/zk_proof_systems/plonk/circuit.hpp | 4 ---- libsnark/zk_proof_systems/plonk/circuit.tcc | 2 -- libsnark/zk_proof_systems/plonk/prover.tcc | 10 ++++++++-- libsnark/zk_proof_systems/plonk/srs.hpp | 4 ---- libsnark/zk_proof_systems/plonk/srs.tcc | 3 --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 5 ----- libsnark/zk_proof_systems/plonk/utils.hpp | 6 +++--- libsnark/zk_proof_systems/plonk/utils.tcc | 10 +++++----- libsnark/zk_proof_systems/plonk/verifier.tcc | 4 +++- 9 files changed, 19 insertions(+), 29 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index 4c8458bb7..dd05fddd1 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -38,9 +38,6 @@ template struct circuit_t { /// vanilla Plonk proposal [GWC19]) size_t num_qpolys; - /// Lagrange basis - std::vector> L_basis; - /// Public input polynomial polynomial PI_poly; @@ -69,7 +66,6 @@ template struct circuit_t { circuit_t( size_t num_gates, size_t num_qpolys, - std::vector> &&L_basis, polynomial &&PI_poly, std::vector> &&Q_polys, std::vector> &&S_polys, diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 2b2b0685c..bae016eff 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -23,7 +23,6 @@ template circuit_t::circuit_t( size_t num_gates, size_t num_qpolys, - std::vector> &&L_basis, polynomial &&PI_poly, std::vector> &&Q_polys, std::vector> &&S_polys, @@ -34,7 +33,6 @@ circuit_t::circuit_t( libff::Fr &&k2) : num_gates(num_gates) , num_qpolys(num_qpolys) - , L_basis(L_basis) , PI_poly(PI_poly) , Q_polys(Q_polys) , S_polys(S_polys) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index de023d95d..beda2f197 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -410,13 +410,16 @@ round_three_out_t plonk_prover::round_three( // --- Computation of t_part[3] + std::vector> L_basis = + plonk_compute_lagrange_basis(srs.num_gates); + // z(x) - 1 polynomial z_neg_one; libfqfft::_polynomial_addition( z_neg_one, round_two_out.z_poly, neg_one_poly); // (z(x)-1) * L_1(x) libfqfft::_polynomial_multiplication( - t_part[3], z_neg_one, srs.L_basis[0]); + t_part[3], z_neg_one, L_basis[0]); // (z(x)-1) * L_1(x) * alpha libfqfft::_polynomial_multiplication( t_part[3], t_part[3], alpha_poly); @@ -706,9 +709,12 @@ round_five_out_t plonk_prover::round_five( // --- Computation of r_part[3] + std::vector> L_basis = + plonk_compute_lagrange_basis(srs.num_gates); + // r3 = accumulator_poly_ext3 * eval_poly(L_1, [zeta])[0] * alpha ** 2 polynomial L_0_zeta_poly{libfqfft::evaluate_polynomial( - srs.L_basis[0].size(), srs.L_basis[0], zeta)}; + L_basis[0].size(), L_basis[0], zeta)}; polynomial alpha_power2_poly{ libff::power(alpha, libff::bigint<1>(2))}; libfqfft::_polynomial_multiplication( diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 0fcf67b0e..529dd1670 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -83,9 +83,6 @@ template class srs /// vanilla Plonk proposal [GWC19]) size_t num_qpolys; - /// Lagrange basis - std::vector> L_basis; - /// Public input polynomial polynomial PI_poly; @@ -121,7 +118,6 @@ template class srs srs(const size_t &num_gates, const size_t &num_qpolys, - const std::vector> &L_basis, const polynomial &PI_poly, const std::vector> &Q_polys, const std::vector> &S_polys, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 0ecc24ed9..643753fce 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -29,7 +29,6 @@ template srs::srs( const size_t &num_gates, const size_t &num_qpolys, - const std::vector> &L_basis, const polynomial &PI_poly, const std::vector> &Q_polys, const std::vector> &S_polys, @@ -42,7 +41,6 @@ srs::srs( std::vector> &&secret_powers_g2) : num_gates(num_gates) , num_qpolys(num_qpolys) - , L_basis(L_basis) , PI_poly(PI_poly) , Q_polys(Q_polys) , S_polys(S_polys) @@ -153,7 +151,6 @@ srs plonk_srs_derive_from_usrs( srs srs( circuit.num_gates, circuit.num_qpolys, - circuit.L_basis, circuit.PI_poly, circuit.Q_polys, circuit.S_polys, diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 193d8fcb7..9c65d80ae 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -174,12 +174,8 @@ circuit_t plonk_circuit_description_from_example( // We represent the constraints q_L, q_R, q_O, q_M, q_C and the // witness w_L, w_R, w_O as polynomials in the roots of unity // e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 - // compute Lagrange basis - std::vector> L_basis; - L_basis.resize(num_gates, polynomial(num_gates)); std::shared_ptr> domain = libfqfft::get_evaluation_domain(num_gates); - plonk_compute_lagrange_basis(num_gates, L_basis); // compute public input (PI) polynomial polynomial PI_poly; @@ -235,7 +231,6 @@ circuit_t plonk_circuit_description_from_example( circuit_t circuit( std::move(num_gates), std::move(num_qpolys), - std::move(L_basis), std::move(PI_poly), std::move(Q_polys), std::move(S_polys), diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 2d788e777..6e09cbce0 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -63,10 +63,10 @@ template void print_vector(const std::vector &v); /// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 /// and L_i(x\neq{omega_i)})=0 /// -/// Note: uses libfqfft iFFT for the interpolation +/// \note uses libfqfft iFFT for the interpolation template -void plonk_compute_lagrange_basis( - const size_t npoints, std::vector> &L); +std::vector> plonk_compute_lagrange_basis( + const size_t &npoints); /// Interpolate a polynomial from a set of points through inverse FFT /// diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index e077ad98d..e8700c84f 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -42,12 +42,11 @@ template void print_vector(const std::vector &v) /// /// \note uses libfqfft iFFT for the interpolation template -void plonk_compute_lagrange_basis( - const size_t npoints, std::vector> &L) +std::vector> plonk_compute_lagrange_basis( + const size_t &npoints) { - assert(L.size() != 0); - assert(L.size() == L[0].size()); - assert(L.size() == npoints); + std::vector> L; + L.resize(npoints, polynomial(npoints)); std::shared_ptr> domain = libfqfft::get_evaluation_domain(npoints); @@ -58,6 +57,7 @@ void plonk_compute_lagrange_basis( domain->iFFT(u); L[i] = u; } + return L; } /// Interpolate a polynomial from a set of points through inverse FFT diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index dbcd42796..788284649 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -185,9 +185,11 @@ template step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) { + std::vector> L_basis = + plonk_compute_lagrange_basis(srs.num_gates); libff::Fr L_0_zeta; L_0_zeta = libfqfft::evaluate_polynomial( - srs.L_basis[0].size(), srs.L_basis[0], step_four_out.zeta); + L_basis[0].size(), L_basis[0], step_four_out.zeta); step_six_out_t step_six_out(std::move(L_0_zeta)); return step_six_out; } From 54a368ddb89c401809a53640878da37e8364b3c6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 25 Jul 2022 08:51:29 +0100 Subject: [PATCH 060/154] plonk: added the libfqfft domain parameter as part of the srs. correspondingly function plonk_compute_lagrange_basis was modified to accept domain as an input parameter (from the srs) thus removing the need to compute the domain inside its body. --- libsnark/zk_proof_systems/plonk/prover.tcc | 4 ++-- libsnark/zk_proof_systems/plonk/srs.hpp | 6 +++++- libsnark/zk_proof_systems/plonk/srs.tcc | 10 ++++++++-- libsnark/zk_proof_systems/plonk/utils.hpp | 5 ++++- libsnark/zk_proof_systems/plonk/utils.tcc | 8 ++++---- libsnark/zk_proof_systems/plonk/verifier.tcc | 2 +- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index beda2f197..515e3bdda 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -411,7 +411,7 @@ round_three_out_t plonk_prover::round_three( // --- Computation of t_part[3] std::vector> L_basis = - plonk_compute_lagrange_basis(srs.num_gates); + plonk_compute_lagrange_basis(srs.num_gates, srs.domain); // z(x) - 1 polynomial z_neg_one; @@ -710,7 +710,7 @@ round_five_out_t plonk_prover::round_five( // --- Computation of r_part[3] std::vector> L_basis = - plonk_compute_lagrange_basis(srs.num_gates); + plonk_compute_lagrange_basis(srs.num_gates, srs.domain); // r3 = accumulator_poly_ext3 * eval_poly(L_1, [zeta])[0] * alpha ** 2 polynomial L_0_zeta_poly{libfqfft::evaluate_polynomial( diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 529dd1670..8a5d57676 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -116,6 +116,9 @@ template class srs /// [\alpha]_2 std::vector> secret_powers_g2; + /// the libfqfft domain + std::shared_ptr> domain; + srs(const size_t &num_gates, const size_t &num_qpolys, const polynomial &PI_poly, @@ -127,7 +130,8 @@ template class srs const libff::Fr &k1, const libff::Fr &k2, std::vector> &&secret_powers_g1, - std::vector> &&secret_powers_g2); + std::vector> &&secret_powers_g2, + std::shared_ptr> domain); }; template diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 643753fce..5610b6436 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -38,7 +38,8 @@ srs::srs( const libff::Fr &k1, const libff::Fr &k2, std::vector> &&secret_powers_g1, - std::vector> &&secret_powers_g2) + std::vector> &&secret_powers_g2, + std::shared_ptr>> domain) : num_gates(num_gates) , num_qpolys(num_qpolys) , PI_poly(PI_poly) @@ -51,6 +52,7 @@ srs::srs( , k2(k2) , secret_powers_g1(secret_powers_g1) , secret_powers_g2(secret_powers_g2) + , domain(domain) { } @@ -148,6 +150,9 @@ srs plonk_srs_derive_from_usrs( secret_powers_g2.push_back(usrs.secret_powers_g2[i]); } + std::shared_ptr>> domain = + libfqfft::get_evaluation_domain>(circuit.num_gates); + srs srs( circuit.num_gates, circuit.num_qpolys, @@ -160,7 +165,8 @@ srs plonk_srs_derive_from_usrs( circuit.k1, circuit.k2, std::move(secret_powers_g1), - std::move(secret_powers_g2)); + std::move(secret_powers_g2), + domain); return srs; } diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 6e09cbce0..a8c677809 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -53,6 +53,8 @@ template void print_vector(const std::vector &v); /// INPUT: /// /// \param[in] npoints - number of points +/// \param[in] domain - libfqfft domain (\see +/// libfqfft::get_evaluation_domain) /// /// OUTPUT: /// @@ -66,7 +68,8 @@ template void print_vector(const std::vector &v); /// \note uses libfqfft iFFT for the interpolation template std::vector> plonk_compute_lagrange_basis( - const size_t &npoints); + const size_t &npoints, + std::shared_ptr> domain); /// Interpolate a polynomial from a set of points through inverse FFT /// diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index e8700c84f..2a38b26b5 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -30,6 +30,8 @@ template void print_vector(const std::vector &v) /// INPUT: /// /// \param[in] npoints - number of points +/// \param[in] domain - libfqfft domain (\see +/// libfqfft::get_evaluation_domain) /// /// OUTPUT: /// @@ -43,13 +45,11 @@ template void print_vector(const std::vector &v) /// \note uses libfqfft iFFT for the interpolation template std::vector> plonk_compute_lagrange_basis( - const size_t &npoints) + const size_t &npoints, + std::shared_ptr> domain) { std::vector> L; L.resize(npoints, polynomial(npoints)); - - std::shared_ptr> domain = - libfqfft::get_evaluation_domain(npoints); for (size_t i = 0; i < npoints; ++i) { polynomial u(npoints, FieldT(0)); u[i] = FieldT(1); diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 788284649..a3d6730c1 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -186,7 +186,7 @@ step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) { std::vector> L_basis = - plonk_compute_lagrange_basis(srs.num_gates); + plonk_compute_lagrange_basis(srs.num_gates, srs.domain); libff::Fr L_0_zeta; L_0_zeta = libfqfft::evaluate_polynomial( L_basis[0].size(), L_basis[0], step_four_out.zeta); From 50621cf6c880997ce688cb31a827ef99191e620f Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 11:34:34 +0100 Subject: [PATCH 061/154] plonk: added the 0-th Lagrange basis polynomial in the SRS instead of computing the full basis on demand (we only use the 0-th polynomial from the basis); addresses PR comment https://github.com/clearmatics/libsnark/pull/62#discussion_r933200581 . --- libsnark/zk_proof_systems/plonk/prover.tcc | 10 ++-------- libsnark/zk_proof_systems/plonk/srs.hpp | 4 ++++ libsnark/zk_proof_systems/plonk/srs.tcc | 10 ++++++++++ libsnark/zk_proof_systems/plonk/verifier.tcc | 7 ++----- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 515e3bdda..bd5a5d078 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -410,16 +410,13 @@ round_three_out_t plonk_prover::round_three( // --- Computation of t_part[3] - std::vector> L_basis = - plonk_compute_lagrange_basis(srs.num_gates, srs.domain); - // z(x) - 1 polynomial z_neg_one; libfqfft::_polynomial_addition( z_neg_one, round_two_out.z_poly, neg_one_poly); // (z(x)-1) * L_1(x) libfqfft::_polynomial_multiplication( - t_part[3], z_neg_one, L_basis[0]); + t_part[3], z_neg_one, srs.L_basis_zero); // (z(x)-1) * L_1(x) * alpha libfqfft::_polynomial_multiplication( t_part[3], t_part[3], alpha_poly); @@ -709,12 +706,9 @@ round_five_out_t plonk_prover::round_five( // --- Computation of r_part[3] - std::vector> L_basis = - plonk_compute_lagrange_basis(srs.num_gates, srs.domain); - // r3 = accumulator_poly_ext3 * eval_poly(L_1, [zeta])[0] * alpha ** 2 polynomial L_0_zeta_poly{libfqfft::evaluate_polynomial( - L_basis[0].size(), L_basis[0], zeta)}; + srs.L_basis_zero.size(), srs.L_basis_zero, zeta)}; polynomial alpha_power2_poly{ libff::power(alpha, libff::bigint<1>(2))}; libfqfft::_polynomial_multiplication( diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 8a5d57676..38bed687b 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -116,6 +116,9 @@ template class srs /// [\alpha]_2 std::vector> secret_powers_g2; + /// the 0-th polynomial of the Lagrange basis + polynomial L_basis_zero; + /// the libfqfft domain std::shared_ptr> domain; @@ -131,6 +134,7 @@ template class srs const libff::Fr &k2, std::vector> &&secret_powers_g1, std::vector> &&secret_powers_g2, + const polynomial &L_basis_zero, std::shared_ptr> domain); }; diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 5610b6436..7aa6637af 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -39,6 +39,7 @@ srs::srs( const libff::Fr &k2, std::vector> &&secret_powers_g1, std::vector> &&secret_powers_g2, + const polynomial &L_basis_zero, std::shared_ptr>> domain) : num_gates(num_gates) , num_qpolys(num_qpolys) @@ -52,6 +53,7 @@ srs::srs( , k2(k2) , secret_powers_g1(secret_powers_g1) , secret_powers_g2(secret_powers_g2) + , L_basis_zero(L_basis_zero) , domain(domain) { } @@ -153,6 +155,13 @@ srs plonk_srs_derive_from_usrs( std::shared_ptr>> domain = libfqfft::get_evaluation_domain>(circuit.num_gates); + // compute 0-th Lagrange basis vector via inverse FFT + // see \ref plonk_compute_lagrange_basis() + polynomial> u(circuit.num_gates, libff::Fr(0)); + u[0] = libff::Fr(1); + domain->iFFT(u); + polynomial> L_basis_zero = u; + srs srs( circuit.num_gates, circuit.num_qpolys, @@ -166,6 +175,7 @@ srs plonk_srs_derive_from_usrs( circuit.k2, std::move(secret_powers_g1), std::move(secret_powers_g2), + std::move(L_basis_zero), domain); return srs; diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index a3d6730c1..3768469e7 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -185,11 +185,8 @@ template step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) { - std::vector> L_basis = - plonk_compute_lagrange_basis(srs.num_gates, srs.domain); - libff::Fr L_0_zeta; - L_0_zeta = libfqfft::evaluate_polynomial( - L_basis[0].size(), L_basis[0], step_four_out.zeta); + libff::Fr L_0_zeta = libfqfft::evaluate_polynomial( + srs.L_basis_zero.size(), srs.L_basis_zero, step_four_out.zeta); step_six_out_t step_six_out(std::move(L_0_zeta)); return step_six_out; } From da267daea4217505dff58e65d18e488b82627f65 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 18 Aug 2022 08:37:26 +0100 Subject: [PATCH 062/154] plonk: removed unused function plonk_compute_lagrange_basis() --- libsnark/zk_proof_systems/plonk/srs.tcc | 1 - libsnark/zk_proof_systems/plonk/utils.hpp | 24 --------------- libsnark/zk_proof_systems/plonk/utils.tcc | 36 ----------------------- 3 files changed, 61 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 7aa6637af..ef4ee9c30 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -156,7 +156,6 @@ srs plonk_srs_derive_from_usrs( libfqfft::get_evaluation_domain>(circuit.num_gates); // compute 0-th Lagrange basis vector via inverse FFT - // see \ref plonk_compute_lagrange_basis() polynomial> u(circuit.num_gates, libff::Fr(0)); u[0] = libff::Fr(1); domain->iFFT(u); diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index a8c677809..9daba2ef4 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -47,30 +47,6 @@ enum omega_id { base, base_k1, base_k2 }; /// print the elements of a vector template void print_vector(const std::vector &v); -/// Compute the Lagrange basis polynomials for interpolating sets of -/// n points -/// -/// INPUT: -/// -/// \param[in] npoints - number of points -/// \param[in] domain - libfqfft domain (\see -/// libfqfft::get_evaluation_domain) -/// -/// OUTPUT: -/// -/// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of -/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, -/// a1, ..., a_{n-1}] is a vector representing the -/// coefficients of the i-th Lagrange polynomial L_i(x) = -/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 -/// and L_i(x\neq{omega_i)})=0 -/// -/// \note uses libfqfft iFFT for the interpolation -template -std::vector> plonk_compute_lagrange_basis( - const size_t &npoints, - std::shared_ptr> domain); - /// Interpolate a polynomial from a set of points through inverse FFT /// /// INPUT: diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 2a38b26b5..13482419a 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -24,42 +24,6 @@ template void print_vector(const std::vector &v) } } -/// Compute the Lagrange basis polynomials for interpolating sets of -/// n points -/// -/// INPUT: -/// -/// \param[in] npoints - number of points -/// \param[in] domain - libfqfft domain (\see -/// libfqfft::get_evaluation_domain) -/// -/// OUTPUT: -/// -/// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of -/// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, -/// a1, ..., a_{n-1}] is a vector representing the -/// coefficients of the i-th Lagrange polynomial L_i(x) = -/// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 -/// and L_i(x\neq{omega_i)})=0 -/// -/// \note uses libfqfft iFFT for the interpolation -template -std::vector> plonk_compute_lagrange_basis( - const size_t &npoints, - std::shared_ptr> domain) -{ - std::vector> L; - L.resize(npoints, polynomial(npoints)); - for (size_t i = 0; i < npoints; ++i) { - polynomial u(npoints, FieldT(0)); - u[i] = FieldT(1); - // compute i-th Lagrange basis vector via inverse FFT - domain->iFFT(u); - L[i] = u; - } - return L; -} - /// Interpolate a polynomial from a set of points through inverse FFT /// /// INPUT: From 031a30091c2bcbb7cbcdd2faa94eeaa64c0441d8 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 25 Jul 2022 15:08:47 +0100 Subject: [PATCH 063/154] plonk: updated depedent library libff to latest version --- depends/libff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libff b/depends/libff index 6dee67e4a..f9a588c05 160000 --- a/depends/libff +++ b/depends/libff @@ -1 +1 @@ -Subproject commit 6dee67e4aa3d75200670f2cec8585f37b693f7f2 +Subproject commit f9a588c05ff803adef5b94a677a6eb37d7ea94cc From 4fdd45e7f4ea323e6fdabaa56851d438e71f5f39 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 17:55:10 +0100 Subject: [PATCH 064/154] plonk: move print_vector function to libff (cf. Issue https://github.com/clearmatics/libsnark/issues/59 , PR https://github.com/clearmatics/libsnark/pull/64) --- depends/libff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libff b/depends/libff index f9a588c05..6dee67e4a 160000 --- a/depends/libff +++ b/depends/libff @@ -1 +1 @@ -Subproject commit f9a588c05ff803adef5b94a677a6eb37d7ea94cc +Subproject commit 6dee67e4aa3d75200670f2cec8585f37b693f7f2 From 9a52cf8a871e22e816c362dbbbe509e107dd9a67 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 18:39:05 +0100 Subject: [PATCH 065/154] plonk: updated libff from 6dee67e to f9a588c in order to include the newly added print_vector function (PR https://github.com/clearmatics/libsnark/pull/64) --- depends/libff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libff b/depends/libff index 6dee67e4a..f9a588c05 160000 --- a/depends/libff +++ b/depends/libff @@ -1 +1 @@ -Subproject commit 6dee67e4aa3d75200670f2cec8585f37b693f7f2 +Subproject commit f9a588c05ff803adef5b94a677a6eb37d7ea94cc From bc56a6368e507493ff26d728840e10d3df00559a Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 26 Aug 2022 14:56:20 +0100 Subject: [PATCH 066/154] plonk: prepended explicitly libff:: to every call to print_vector which is now part of libff. --- .../zk_proof_systems/plonk/tests/test_plonk.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 9c65d80ae..ea6297f68 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -205,7 +205,7 @@ circuit_t plonk_circuit_description_from_example( // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H #ifdef DEBUG_PLONK printf("[%s:%d] H_gen\n", __FILE__, __LINE__); - print_vector(H_gen); + libff::print_vector(H_gen); for (int i = 0; i < (int)H_gen.size(); ++i) { assert(H_gen[i] == example.H_gen[i]); } @@ -217,7 +217,7 @@ circuit_t plonk_circuit_description_from_example( // TODO: write unit test for plonk_permute_subgroup_H #ifdef DEBUG_PLONK printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); - print_vector(H_gen_permute); + libff::print_vector(H_gen_permute); for (size_t i = 0; i < H_gen_permute.size(); ++i) { assert(H_gen_permute[i] == example.H_gen_permute[i]); } @@ -259,7 +259,7 @@ void test_plonk_compute_accumulator( // initialize hard-coded values from example circuit printf("[%s:%d] A_poly\n", __FILE__, __LINE__); - print_vector(A_poly); + libff::print_vector(A_poly); ASSERT_EQ(A_poly, example.A_poly); } @@ -275,12 +275,12 @@ void test_plonk_prover_round_one( round_zero_out, blind_scalars, witness, srs); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); - print_vector(round_one_out.W_polys[i]); + libff::print_vector(round_one_out.W_polys[i]); ASSERT_EQ(round_one_out.W_polys[i], example.W_polys[i]); } for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] W_polys_blinded[%d]\n", __FILE__, __LINE__, i); - print_vector(round_one_out.W_polys_blinded[i]); + libff::print_vector(round_one_out.W_polys_blinded[i]); ASSERT_EQ(round_one_out.W_polys_blinded[i], example.W_polys_blinded[i]); } printf("[%s:%d] Output from Round 1\n", __FILE__, __LINE__); @@ -312,7 +312,7 @@ void test_plonk_prover_round_two( round_two_out_t round_two_out = plonk_prover::round_two( beta, gamma, round_zero_out, blind_scalars, witness, srs); printf("[%s:%d] z_poly\n", __FILE__, __LINE__); - print_vector(round_two_out.z_poly); + libff::print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); printf("[%s:%d] Output from Round 2\n", __FILE__, __LINE__); printf("[%s:%d] z_poly_at_secret_g1\n", __FILE__, __LINE__); @@ -338,11 +338,11 @@ void test_plonk_prover_round_three( alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); - print_vector(round_three_out.t_poly_long); + libff::print_vector(round_three_out.t_poly_long); ASSERT_EQ(round_three_out.t_poly_long, example.t_poly_long); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] t_poly[%d]\n", __FILE__, __LINE__, i); - print_vector(round_three_out.t_poly[i]); + libff::print_vector(round_three_out.t_poly[i]); ASSERT_EQ(round_three_out.t_poly[i], example.t_poly[i]); } for (int i = 0; i < (int)NUM_HSETS; ++i) { From 915015d23e917865aae7dac18948111e8d7c15d6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 21 Jul 2022 13:11:45 +0100 Subject: [PATCH 067/154] plonk: replaced structure transcript_hash_t with class transcript_hasher that makes a call to hash function. for the moment it directly returns the expected hash values for the purposes of testing. addresses issue https://github.com/clearmatics/libsnark/issues/56. --- libsnark/zk_proof_systems/plonk/prover.hpp | 13 +-- libsnark/zk_proof_systems/plonk/prover.tcc | 33 ++++--- libsnark/zk_proof_systems/plonk/srs.hpp | 42 ++++---- libsnark/zk_proof_systems/plonk/srs.tcc | 67 +++++++++++-- .../plonk/tests/test_plonk.cpp | 96 ++++++++----------- libsnark/zk_proof_systems/plonk/verifier.hpp | 33 +++---- libsnark/zk_proof_systems/plonk/verifier.tcc | 48 ++++------ 7 files changed, 165 insertions(+), 167 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 7a43a2a9a..d4a878e01 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -461,15 +461,8 @@ template class plonk_prover /// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 /// used in prover rounds 1 and 2 (see Sect. 8.3, roumds /// 1,2 [GWC19]) - /// \param[in] transcript_hash: hashes of the communication transcript - /// after prover rounds 1,2,3,4,5. TODO: \attention - /// currently the structure is used as an input initialized - /// with hard-coded example values for debug purposes. In - /// the long run it should be modified to be used as an - /// output. More specifically, the hard-coded values should - /// be overwritten with the actual transcript hashes - /// produced after the respective rounds within \ref - /// compute_proof + /// \param[in] transcript_hasher: hashes of the communication + /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) @@ -477,7 +470,7 @@ template class plonk_prover const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hash_t &transcript_hash); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index bd5a5d078..1f572ed79 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -987,15 +987,8 @@ plonk_proof::plonk_proof( /// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 /// used in prover rounds 1 and 2 (see Sect. 8.3, roumds /// 1,2 [GWC19]) -/// \param[in] transcript_hash: hashes of the communication transcript -/// after prover rounds 1,2,3,4,5. TODO: \attention -/// currently the structure is used as an input initialized -/// with hard-coded example values for debug purposes. In -/// the long run it should be modified to be used as an -/// output. More specifically, the hard-coded values should -/// be overwritten with the actual transcript hashes -/// produced after the respective rounds within \ref -/// compute_proof +/// \param[in] transcript_hasher: hashes of the communication +/// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] proof: SNARK proof Pi (see above) @@ -1004,7 +997,7 @@ plonk_proof plonk_prover::compute_proof( const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); @@ -1017,27 +1010,28 @@ plonk_proof plonk_prover::compute_proof( printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); // - beta, gamma: permutation challenges - hashes of transcript of round 1 - const libff::Fr beta = transcript_hash.beta; - const libff::Fr gamma = transcript_hash.gamma; + const libff::Fr beta = hasher.get_hash(); + const libff::Fr gamma = hasher.get_hash(); + round_two_out_t round_two_out = plonk_prover::round_two( beta, gamma, round_zero_out, blind_scalars, witness, srs); printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); // - alpha: quotient challenge - hash of transcript of rounds 1,2 - libff::Fr alpha = transcript_hash.alpha; + const libff::Fr alpha = hasher.get_hash(); round_three_out_t round_three_out = plonk_prover::round_three( alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 - libff::Fr zeta = transcript_hash.zeta; + const libff::Fr zeta = hasher.get_hash(); round_four_out_t round_four_out = plonk_prover::round_four(zeta, round_one_out, round_three_out, srs); printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); /// - nu: opening challenge -- hash of transcript (denoted by v in /// [GWC19]) - libff::Fr nu = transcript_hash.nu; + const libff::Fr nu = hasher.get_hash(); round_five_out_t round_five_out = plonk_prover::round_five( alpha, beta, @@ -1053,10 +1047,15 @@ plonk_proof plonk_prover::compute_proof( // TODO: activate this part when we implement actual hashing of // communication transcripts -#if 0 +#if 0 // u: multipoint evaluation challenge -- hash of transcript from // rounds 1,2,3,4,5 - libff::Fr u = transcript_hash.u; + const libff::Fr u = hasher.get_hash(); +#else + // do the hash anyway in order to keep the correct count of the + // hasher istep member (which resets to 0 only after the last hash + // is performed which is hash of u) + hasher.get_hash(); #endif // construct proof diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 38bed687b..db208d28e 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -183,32 +183,22 @@ template class plonk_keypair plonk_keypair(plonk_keypair &&other) = default; }; -/// Hashes of transcript after prover rounds 1,2,3,4,5 -template struct transcript_hash_t { - - /// - beta: permutation challenge - hashes of transcript after round 1 - libff::Fr beta; - /// - gamma: permutation challenge - hashes of transcript after round 1 - libff::Fr gamma; - /// - alpha: quotient challenge - hash of transcript after rounds 1,2 - libff::Fr alpha; - /// - zeta: evaluation challenge - hash of transcriptafter rounds 1,2,3 - libff::Fr zeta; - /// - nu: opening challenge - hash of transcript after rounds 1,2,3,4 - /// (denoted by v in [GWC19]) - libff::Fr nu; - /// - u: multipoint evaluation challenge -- hash of transcript after rounds - /// 1,2,3,4,5 - libff::Fr u; - - /// struct constructor - transcript_hash_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u); +/// transcript hasher interface +template class transcript_hasher +{ +private: + // the current step of the hasher + size_t istep; + +public: + void add_element(const libff::Fr &element); + void add_element(const libff::G1 &element); + void add_element(const libff::G2 &element); + + libff::Fr get_hash(); + + // constructor + transcript_hasher(size_t &istep); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index ef4ee9c30..2c552d9ed 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -72,19 +72,68 @@ plonk_keypair::plonk_keypair( { } -/// struct transcript_hash_t constructor +/// transcript_hasher constructor template -transcript_hash_t::transcript_hash_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u) - : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) +transcript_hasher::transcript_hasher(size_t &istep) : istep(istep) { } +/// dummy implementation of get_hash that directly returns the +/// expected hard-coded hashes for the purposes of unit testing TODO +/// to be replaced by a call to a proper hash function e.g. SHA2, +/// BLAKE, etc. +template libff::Fr transcript_hasher::get_hash() +{ + assert((this->istep >= 0) && (this->istep <= 5)); + using Field = libff::Fr; + + Field beta = Field("3710899868510394644410941212967766116886736137326022751" + "891187938298987182388"); + Field gamma = Field("110379303840831945879077096653321168432672740458288022" + "49545114995763715746939"); + Field alpha = Field("379799789992747238930717819864848384921111623418803600" + "22719385400306128734648"); + Field zeta = Field("4327197228921839935583364394550235027071910395980312641" + "5018065799136107272465"); + Field nu = Field("275158598338697752421507265080923414294782807831923791651" + "55175653098691426347"); + Field u = Field("1781751143954696684632449211212056577828855388109883650570" + "6049265393896966778"); + if (this->istep == 0) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return beta; + } + if (this->istep == 1) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return gamma; + } + if (this->istep == 2) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return alpha; + } + if (this->istep == 3) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return zeta; + } + if (this->istep == 4) { + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep++; + return nu; + } + if (this->istep == 5) { + // reset step to 0 + printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); + this->istep = 0; + return u; + } + // error + return 0; +} + /// Compute a universal srs (usrs). It is composed *only* of encoded /// powers of the secret value in the group generator. Therefore a usrs /// is independent of any particular circuit. diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index ea6297f68..acfcae5f7 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -38,7 +38,7 @@ template void test_verify_invalid_proof( const plonk_proof &valid_proof, const srs &srs, - transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { // initialize verifier plonk_verifier verifier; @@ -59,14 +59,14 @@ void test_verify_invalid_proof( G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = proof.W_polys_blinded_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); } // manipulate [z]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { @@ -74,62 +74,62 @@ void test_verify_invalid_proof( proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); } // manipulate \bar{a} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{b} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{c} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate r_zeta proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, transcript_hash); + b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); } @@ -455,14 +455,6 @@ template void test_plonk_prover_rounds() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -473,6 +465,10 @@ template void test_plonk_prover_rounds() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // Prover Round 0 (initialization) round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); @@ -482,8 +478,8 @@ template void test_plonk_prover_rounds() // Unit test Prover Round 2 printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); - const libff::Fr beta = transcript_hash.beta; - const libff::Fr gamma = transcript_hash.gamma; + const libff::Fr beta = hasher.get_hash(); + const libff::Fr gamma = hasher.get_hash(); test_plonk_prover_round_two( example, beta, gamma, round_zero_out, blind_scalars, witness, srs); @@ -496,7 +492,7 @@ template void test_plonk_prover_rounds() round_zero_out, blind_scalars, witness, srs); round_two_out_t round_two_out = plonk_prover::round_two( beta, gamma, round_zero_out, blind_scalars, witness, srs); - libff::Fr alpha = transcript_hash.alpha; + const libff::Fr alpha = hasher.get_hash(); test_plonk_prover_round_three( example, alpha, @@ -511,7 +507,7 @@ template void test_plonk_prover_rounds() printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); round_three_out_t round_three_out = plonk_prover::round_three( alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); - libff::Fr zeta = transcript_hash.zeta; + const libff::Fr zeta = hasher.get_hash(); test_plonk_prover_round_four( example, zeta, round_one_out, round_three_out, srs); @@ -519,7 +515,7 @@ template void test_plonk_prover_rounds() printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); round_four_out_t round_four_out = plonk_prover::round_four( zeta, round_one_out, round_three_out, srs); - libff::Fr nu = transcript_hash.nu; + const libff::Fr nu = hasher.get_hash(); test_plonk_prover_round_five( example, alpha, @@ -592,14 +588,6 @@ template void test_plonk_prover() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -610,11 +598,15 @@ template void test_plonk_prover() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // initialize prover plonk_prover prover; // compute proof plonk_proof proof = - prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, hasher); // compare proof against test vector values (debug) ASSERT_EQ(proof.a_zeta, example.a_zeta); ASSERT_EQ(proof.b_zeta, example.b_zeta); @@ -874,14 +866,6 @@ template void test_plonk_verifier_steps() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -892,18 +876,22 @@ template void test_plonk_verifier_steps() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // initialize prover plonk_prover prover; // compute proof plonk_proof proof = - prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, hasher); // Unit test verifier preprocessed input test_plonk_verifier_preprocessed_input(example, srs); // unit test verifier step 5 const step_four_out_t step_four_out = - plonk_verifier::step_four(transcript_hash); + plonk_verifier::step_four(hasher); test_plonk_verifier_step_five(example, step_four_out, srs); // unit test verifier step 6 @@ -977,14 +965,6 @@ template void test_plonk_verifier() // example circuit circuit_t circuit = plonk_circuit_description_from_example(example); - // get hard-coded values for the transcipt hash - transcript_hash_t transcript_hash( - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -995,20 +975,24 @@ template void test_plonk_verifier() usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + // initialize hasher + size_t istep = 0; + transcript_hasher hasher(istep); + // initialize prover plonk_prover prover; // compute proof plonk_proof proof = - prover.compute_proof(srs, witness, blind_scalars, transcript_hash); + prover.compute_proof(srs, witness, blind_scalars, hasher); // initialize verifier plonk_verifier verifier; // verify proof - bool b_valid_proof = verifier.verify_proof(proof, srs, transcript_hash); + bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); ASSERT_TRUE(b_valid_proof); // assert that proof verification fails when the proof is // manipulated - test_verify_invalid_proof(proof, srs, transcript_hash); + test_verify_invalid_proof(proof, srs, hasher); } TEST(TestPlonk, BLS12_381) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index e9f9f6631..81bdd4841 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -81,12 +81,12 @@ template struct step_four_out_t { libff::Fr nu; libff::Fr u; step_four_out_t( - libff::Fr &&beta, - libff::Fr &&gamma, - libff::Fr &&alpha, - libff::Fr &&zeta, - libff::Fr &&nu, - libff::Fr &&u); + libff::Fr &beta, + libff::Fr &gamma, + libff::Fr &alpha, + libff::Fr &zeta, + libff::Fr &nu, + libff::Fr &u); }; /// Verifier step 5 output @@ -186,12 +186,8 @@ template class plonk_verifier /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT - /// \param[in] transcript_hash: hashes of the communication transcript - /// after prover rounds 1,2,3,4,5. TODO: \attention - /// currently the hashes are pre-computed by the caller and - /// passed as input for the purpouses of unit testing. In - /// the long run this input can be removed and the hashes - /// can be computed directly inside verifier::step_four() + /// \param[in] transcript_hasher: hashes of the communication + /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] beta, gamma: permutation challenges - hashes of @@ -202,8 +198,7 @@ template class plonk_verifier /// v in [GWC19]) /// \param[out] u: multipoint evaluation challenge - hash of /// transcript - static step_four_out_t step_four( - const transcript_hash_t &transcript_hash); + static step_four_out_t step_four(transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// @@ -422,19 +417,15 @@ template class plonk_verifier /// \param[in] proof: SNARK proof produced by the prover /// \param[in] srs: structured reference string containing also /// circuit-specific information - /// \param[in] transcript_hash: hashes of the communication transcript - /// after prover rounds 1,2,3,4,5. TODO: \attention - /// currently the hashes are pre-computed by the caller and - /// passed as input for the purpouses of unit testing. In - /// the long run this input can be removed and the hashes - /// can be computed directly inside verifier::step_four() + /// \param[in] transcript_hasher: hashes of the communication + /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] boolean 1/0 = valid/invalid proof bool verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hash_t &transcript_hash); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 3768469e7..dbf4ff2c5 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -85,12 +85,12 @@ template void plonk_verifier::step_three(const srs &srs) /// struct step_four_out_t constructor template step_four_out_t::step_four_out_t( - libff::Fr &&beta, - libff::Fr &&gamma, - libff::Fr &&alpha, - libff::Fr &&zeta, - libff::Fr &&nu, - libff::Fr &&u) + libff::Fr &beta, + libff::Fr &gamma, + libff::Fr &alpha, + libff::Fr &zeta, + libff::Fr &nu, + libff::Fr &u) : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) { } @@ -100,12 +100,8 @@ step_four_out_t::step_four_out_t( /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT -/// \param[in] transcript_hash: hashes of the communication transcript -/// after prover rounds 1,2,3,4,5. TODO: \attention -/// currently the hashes are pre-computed by the caller and -/// passed as input for the purpouses of unit testing. In -/// the long run this input can be removed and the hashes -/// can be computed directly inside verifier::step_four() +/// \param[in] transcript_hasher: hashes of the communication +/// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] beta, gamma: permutation challenges - hashes of @@ -118,16 +114,16 @@ step_four_out_t::step_four_out_t( /// transcript template step_four_out_t plonk_verifier::step_four( - const transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { + libff::Fr beta = hasher.get_hash(); + libff::Fr gamma = hasher.get_hash(); + libff::Fr alpha = hasher.get_hash(); + libff::Fr zeta = hasher.get_hash(); + libff::Fr nu = hasher.get_hash(); + libff::Fr u = hasher.get_hash(); // step 4 output - step_four_out_t step_four_out( - Field(transcript_hash.beta), - Field(transcript_hash.gamma), - Field(transcript_hash.alpha), - Field(transcript_hash.zeta), - Field(transcript_hash.nu), - Field(transcript_hash.u)); + step_four_out_t step_four_out(beta, gamma, alpha, zeta, nu, u); return step_four_out; } @@ -600,12 +596,8 @@ bool plonk_verifier::step_twelve( /// \param[in] proof: SNARK proof produced by the prover /// \param[in] srs: structured reference string containing also /// circuit-specific information -/// \param[in] transcript_hash: hashes of the communication transcript -/// after prover rounds 1,2,3,4,5. TODO: \attention -/// currently the hashes are pre-computed by the caller and -/// passed as input for the purpouses of unit testing. In -/// the long run this input can be removed and the hashes -/// can be computed directly inside verifier::step_four() +/// \param[in] transcript_hasher: hashes of the communication +/// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT /// \param[out] boolean 1/0 = valid/invalid proof @@ -613,7 +605,7 @@ template bool plonk_verifier::verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hash_t &transcript_hash) + transcript_hasher &hasher) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = @@ -629,7 +621,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 4: compute challenges hashed transcript as in // prover description, from the common inputs, public input, and // elements of pi-SNARK (fixed to the test vectors for now) - const step_four_out_t step_four_out = this->step_four(transcript_hash); + const step_four_out_t step_four_out = this->step_four(hasher); // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = From 4c666775ecf8f94b788dc754b5628359f1da1986 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 16 Aug 2022 15:22:37 +0100 Subject: [PATCH 068/154] plonk: implementation of transcript hasher, addressing issue #56 and PR #61. --- libsnark/zk_proof_systems/plonk/prover.hpp | 30 +++- libsnark/zk_proof_systems/plonk/prover.tcc | 85 ++++++++-- libsnark/zk_proof_systems/plonk/srs.hpp | 78 ++++++++- libsnark/zk_proof_systems/plonk/srs.tcc | 157 +++++++++++++++--- .../plonk/tests/test_plonk.cpp | 150 +++++++++++++---- libsnark/zk_proof_systems/plonk/verifier.hpp | 4 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 43 ++++- 7 files changed, 468 insertions(+), 79 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index d4a878e01..f92a59bd1 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -269,11 +269,15 @@ template class plonk_prover /// \param[out] W_polys_blinded_at_secret_g1: the blinded witness /// polynomials evaluated at the secret input denoted /// [a]_1, [b]_1, [c]_1 in [GWC19] + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_one_out_t round_one( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 2 /// @@ -289,13 +293,17 @@ template class plonk_prover /// \param[out] z_poly: blinded accumulator poly z(x) /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_two_out_t round_two( const libff::Fr &beta, const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 3 /// @@ -318,6 +326,9 @@ template class plonk_prover /// input zeta i.e. t(zeta) /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted /// by w + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_three_out_t round_three( const libff::Fr &alpha, const libff::Fr &beta, @@ -325,7 +336,8 @@ template class plonk_prover const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 4 /// @@ -358,11 +370,15 @@ template class plonk_prover /// Python reference implementation does, so we do the /// same in order to match the test vectors. TODO can /// remove t_zeta in the future + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_four_out_t round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover Round 5 /// @@ -408,6 +424,9 @@ template class plonk_prover /// \param[out] W_zeta_omega_at_secret: commitment to opening proof /// polynomial W_{zeta omega}(x) at secert input /// i.e. [W_{zeta omega}(secret)]_1 + /// \param[out] transcript_hasher: accumulates the communication + /// transcript into a buffer to be hashed after prover + /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). static round_five_out_t round_five( const libff::Fr &alpha, const libff::Fr &beta, @@ -419,7 +438,8 @@ template class plonk_prover const round_two_out_t &round_two_out, const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, - const srs &srs); + const srs &srs, + transcript_hasher &hasher); /// Prover compute SNARK proof /// diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 1f572ed79..a9c3640e6 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -93,12 +93,16 @@ round_one_out_t::round_one_out_t( /// \param[out] W_polys_blinded_at_secret_g1: the blinded witness /// polynomials evaluated at the secret input denoted /// [a]_1, [b]_1, [c]_1 in [GWC19] +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; const size_t nwitness = NUM_HSETS; @@ -140,6 +144,11 @@ round_one_out_t plonk_prover::round_one( plonk_evaluate_polys_at_secret_G1( srs.secret_powers_g1, W_polys_blinded, W_polys_blinded_at_secret_g1); + // add outputs from Round 1 to the hash buffer + hasher.add_element(W_polys_blinded_at_secret_g1[a]); + hasher.add_element(W_polys_blinded_at_secret_g1[b]); + hasher.add_element(W_polys_blinded_at_secret_g1[c]); + round_one_out_t round_one_out( std::move(W_polys), std::move(W_polys_blinded), @@ -170,6 +179,9 @@ round_two_out_t::round_two_out_t( /// \param[out] z_poly: blinded accumulator poly z(x) /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) /// evaluated at secret +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_two_out_t plonk_prover::round_two( const libff::Fr &beta, @@ -177,7 +189,8 @@ round_two_out_t plonk_prover::round_two( const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; @@ -205,6 +218,9 @@ round_two_out_t plonk_prover::round_two( z_poly_at_secret_g1 = plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, z_poly); + // add outputs from Round 2 to the hash buffer + hasher.add_element(z_poly_at_secret_g1); + round_two_out_t round_two_out( std::move(z_poly), std::move(z_poly_at_secret_g1)); @@ -246,6 +262,9 @@ round_three_out_t::round_three_out_t( /// input zeta i.e. t(zeta) /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted /// by w +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, @@ -254,7 +273,8 @@ round_three_out_t plonk_prover::round_three( const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; int num_hgen = NUM_HSETS; @@ -462,6 +482,11 @@ round_three_out_t plonk_prover::round_three( srs.secret_powers_g1, t_poly[i]); } + // add outputs from Round 3 to the hash buffer + hasher.add_element(t_poly_at_secret_g1[lo]); + hasher.add_element(t_poly_at_secret_g1[mid]); + hasher.add_element(t_poly_at_secret_g1[hi]); + round_three_out_t round_three_out( std::move(z_poly_xomega), std::move(t_poly), @@ -522,12 +547,16 @@ round_four_out_t::round_four_out_t( /// Python reference implementation \[PlonkPy] does, so we /// do the same in order to match the test vectors. TODO /// can remove t_zeta in the future +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; @@ -557,6 +586,14 @@ round_four_out_t plonk_prover::round_four( round_three_out.z_poly_xomega, zeta); + // add outputs from Round 4 to the hash buffer + hasher.add_element(a_zeta); + hasher.add_element(b_zeta); + hasher.add_element(c_zeta); + hasher.add_element(S_0_zeta); + hasher.add_element(S_1_zeta); + hasher.add_element(z_poly_xomega_zeta); + round_four_out_t round_four_out( std::move(a_zeta), std::move(b_zeta), @@ -625,6 +662,9 @@ round_five_out_t::round_five_out_t( /// \param[out] W_zeta_omega_at_secret: commitment to opening proof /// polynomial W_{zeta omega}(x) at secert input /// i.e. [W_{zeta omega}(secret)]_1 +/// \param[out] transcript_hasher: accumulates the communication +/// transcript into a buffer to be hashed after prover +/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, @@ -637,7 +677,8 @@ round_five_out_t plonk_prover::round_five( const round_two_out_t &round_two_out, const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { using Field = libff::Fr; polynomial remainder; @@ -909,6 +950,11 @@ round_five_out_t plonk_prover::round_five( W_zeta_omega_at_secret = plonk_evaluate_poly_at_secret_G1( srs.secret_powers_g1, W_zeta_omega); + // add outputs from Round 5 to the hash buffer + hasher.add_element(r_zeta); + hasher.add_element(W_zeta_at_secret); + hasher.add_element(W_zeta_omega_at_secret); + round_five_out_t round_five_out( std::move(r_zeta), std::move(W_zeta_at_secret), @@ -1005,28 +1051,40 @@ plonk_proof plonk_prover::compute_proof( // Prover Round 1 printf("[%s:%d] Prover Round 1...\n", __FILE__, __LINE__); - round_one_out_t round_one_out = - plonk_prover::round_one(round_zero_out, blind_scalars, witness, srs); + round_one_out_t round_one_out = plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); - // - beta, gamma: permutation challenges - hashes of transcript of round 1 + // - beta: permutation challenges - hashes of transcript of round + // 1 (\attention the original protocl appends a 0, while we don't + // append anyhting to avoid making a copy of the buffer) const libff::Fr beta = hasher.get_hash(); + // - gamma: permutation challenges - hashes of transcript of round + // 1 with 1 appended + hasher.add_element(libff::Fr::one()); const libff::Fr gamma = hasher.get_hash(); round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs); + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); // - alpha: quotient challenge - hash of transcript of rounds 1,2 const libff::Fr alpha = hasher.get_hash(); round_three_out_t round_three_out = plonk_prover::round_three( - alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 const libff::Fr zeta = hasher.get_hash(); - round_four_out_t round_four_out = - plonk_prover::round_four(zeta, round_one_out, round_three_out, srs); + round_four_out_t round_four_out = plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs, hasher); printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); /// - nu: opening challenge -- hash of transcript (denoted by v in @@ -1043,7 +1101,8 @@ plonk_proof plonk_prover::compute_proof( round_two_out, round_three_out, round_four_out, - srs); + srs, + hasher); // TODO: activate this part when we implement actual hashing of // communication transcripts diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index db208d28e..e58199855 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -184,21 +184,93 @@ template class plonk_keypair }; /// transcript hasher interface +/// +/// the hasher works in the Prover as follows: +/// +/// round 1 +/// +/// add_element(buffer, a_eval_exp) +/// add_element(buffer, b_eval_exp) +/// add_element(buffer, c_eval_exp) +/// // buffer = first_output +/// +/// round 2 +/// +/// beta = hash(str(buffer) + "0") +/// gamma = hash(str(buffer) + "1") +/// +/// acc_eval = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs()) +/// +/// add_element(buffer, acc_eval) +/// // buffer = first_output + second_output +/// +/// round 3 +/// +/// alpha = hash(str(buffer)) +/// +/// add_element(buffer, t_lo_eval_exp) +/// add_element(buffer, t_mid_eval_exp) +/// add_element(buffer, t_hi_eval_exp) +/// // buffer = first_output + second_output + third_output +/// +/// round 4 +/// +/// zeta = hash(str(buffer)) +/// +/// add_element(buffer, a_zeta) +/// add_element(buffer, b_zeta) +/// add_element(buffer, c_zeta) +/// add_element(buffer, S_0_zeta) +/// add_element(buffer, S_1_zeta) +/// add_element(buffer, accumulator_shift_zeta) +/// add_element(buffer, t_zeta) +/// add_element(buffer, r_zeta) +/// // buffer = first_output + second_output + third_output + fourth_output +/// +/// round 5 +/// +/// nu = hash(str(buffer)) +/// +/// W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs()) +/// W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, +/// W_zeta_omega.to_coeffs()) +/// +/// add_element(buffer, W_zeta_eval_exp) +/// add_element(buffer, W_zeta_omega_eval_exp) +/// +/// // buffer = first_output + second_output + third_output + fourth_output +/// + fifth_output +/// +/// u = hash(str(buffer)) +/// template class transcript_hasher { private: - // the current step of the hasher - size_t istep; + // buffer accumulating data to be hashed + std::vector buffer; public: void add_element(const libff::Fr &element); void add_element(const libff::G1 &element); void add_element(const libff::G2 &element); + // TODO: use next declaration to implement an actual hash function + // e.g. BLAKE (from Aztec barretenberg implementation): + // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 + // + // std::array + // Blake2sHasher::hash(std::vector const& buffer) + libff::Fr get_hash(); + // clear the buffer (for now only for testing) + void buffer_clear(); + + // get buffer size + size_t buffer_size(); + // constructor - transcript_hasher(size_t &istep); + transcript_hasher(std::vector &buffer); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 2c552d9ed..299adce8c 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -74,19 +74,99 @@ plonk_keypair::plonk_keypair( /// transcript_hasher constructor template -transcript_hasher::transcript_hasher(size_t &istep) : istep(istep) +transcript_hasher::transcript_hasher(std::vector &buffer) + : buffer(std::move(buffer)) { } +/// clear the buffer (for now only for testing) +template void transcript_hasher::buffer_clear() +{ + this->buffer.clear(); +} + +/// get buffer size +template size_t transcript_hasher::buffer_size() +{ + return this->buffer.size(); +} + +/// add an Fr element to the transcript buffer for hashing +template +void transcript_hasher::add_element(const libff::Fr &element) +{ + // convert the Fr element into a string + std::string str; + { + std::ostringstream ss; + libff::field_write( + element, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +/// add the coordinates of a G1 curve point to the transcript buffer for hashing +template +void transcript_hasher::add_element(const libff::G1 &element) +{ + libff::G1 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +/// add the coordinates of a G2 curve point to the transcript buffer for hashing +template +void transcript_hasher::add_element(const libff::G2 &element) +{ + libff::G2 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + /// dummy implementation of get_hash that directly returns the /// expected hard-coded hashes for the purposes of unit testing TODO /// to be replaced by a call to a proper hash function e.g. SHA2, /// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { - assert((this->istep >= 0) && (this->istep <= 5)); using Field = libff::Fr; + size_t buffer_len = this->buffer.size(); + // DEBUG + printf("[%s:%d] len %7d\n", __FILE__, __LINE__, (int)buffer_len); + + // vector of valid lengths (\attention specific to BLS12-381) + std::vector length{288, 320, 416, 704, 896, 1120}; + Field beta = Field("3710899868510394644410941212967766116886736137326022751" "891187938298987182388"); Field gamma = Field("110379303840831945879077096653321168432672740458288022" @@ -99,38 +179,73 @@ template libff::Fr transcript_hasher::get_hash() "55175653098691426347"); Field u = Field("1781751143954696684632449211212056577828855388109883650570" "6049265393896966778"); - if (this->istep == 0) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // beta + if (buffer_len == length[0]) { + printf( + "[%s:%d] buffer_len %d: beta\n", + __FILE__, + __LINE__, + (int)buffer_len); return beta; } - if (this->istep == 1) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // gamma + if (buffer_len == length[1]) { + printf( + "[%s:%d] buffer_len %d: gamma\n", + __FILE__, + __LINE__, + (int)buffer_len); return gamma; } - if (this->istep == 2) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // alpha + if (buffer_len == length[2]) { + printf( + "[%s:%d] buffer_len %d: alpha\n", + __FILE__, + __LINE__, + (int)buffer_len); return alpha; } - if (this->istep == 3) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // zeta + if (buffer_len == length[3]) { + printf( + "[%s:%d] buffer_len %d: zeta\n", + __FILE__, + __LINE__, + (int)buffer_len); return zeta; } - if (this->istep == 4) { - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep++; + // nu + if (buffer_len == length[4]) { + printf( + "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); return nu; } - if (this->istep == 5) { + // u + if (buffer_len == length[5]) { // reset step to 0 - printf("[%s:%d] istep %d\n", __FILE__, __LINE__, (int)istep); - this->istep = 0; + printf( + "[%s:%d] buffer_len %d: u + clear()\n", + __FILE__, + __LINE__, + (int)buffer_len); + this->buffer.clear(); return u; } - // error + bool b_valid_length = + ((buffer_len == length[0]) || (buffer_len == length[1]) || + (buffer_len == length[2]) || (buffer_len == length[3]) || + (buffer_len == length[4]) || (buffer_len == length[5])); + try { + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); + } + } catch (const std::logic_error &e) { + std::cout << "Error: " << e.what() << "\n"; + } + assert(b_valid_length); + // If we are here, then the hasher buffer has invalid length so return error return 0; } diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index acfcae5f7..68e13ee87 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -268,11 +268,12 @@ void test_plonk_prover_round_one( const plonk_example &example, const round_zero_out_t &round_zero_out, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { std::vector> blind_scalars = example.prover_blind_scalars; round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs); + round_zero_out, blind_scalars, witness, srs, hasher); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); libff::print_vector(round_one_out.W_polys[i]); @@ -307,10 +308,11 @@ void test_plonk_prover_round_two( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs); + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] z_poly\n", __FILE__, __LINE__); libff::print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); @@ -332,10 +334,18 @@ void test_plonk_prover_round_three( const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_three_out_t round_three_out = plonk_prover::round_three( - alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); libff::print_vector(round_three_out.t_poly_long); @@ -362,10 +372,11 @@ void test_plonk_prover_round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs); + zeta, round_one_out, round_three_out, srs, hasher); // Prover Round 4 output check against test vectors printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); printf("a_zeta "); @@ -404,7 +415,8 @@ void test_plonk_prover_round_five( const round_two_out_t &round_two_out, const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, - const srs &srs) + const srs &srs, + transcript_hasher &hasher) { round_five_out_t round_five_out = plonk_prover::round_five( alpha, @@ -417,7 +429,8 @@ void test_plonk_prover_round_five( round_two_out, round_three_out, round_four_out, - srs); + srs, + hasher); printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); printf("r_zeta "); @@ -466,32 +479,59 @@ template void test_plonk_prover_rounds() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // Prover Round 0 (initialization) round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); - // Unit test Prover Round 1 + // --- Unit test Prover Round 1 --- + // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); - test_plonk_prover_round_one(example, round_zero_out, witness, srs); + test_plonk_prover_round_one( + example, round_zero_out, witness, srs, hasher); - // Unit test Prover Round 2 + // --- Unit test Prover Round 2 --- + // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); + round_one_out_t round_one_out = plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); const libff::Fr beta = hasher.get_hash(); + hasher.add_element(libff::Fr::one()); const libff::Fr gamma = hasher.get_hash(); test_plonk_prover_round_two( - example, beta, gamma, round_zero_out, blind_scalars, witness, srs); + example, + beta, + gamma, + round_zero_out, + blind_scalars, + witness, + srs, + hasher); // Unit test plonk_compute_accumulator test_plonk_compute_accumulator(example, beta, gamma, witness, srs); - // Unit test Prover Round 3 + // --- Unit test Prover Round 3 --- + // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); - round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs); round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs); + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); + hasher.add_element(libff::Fr::one()); + // add outputs from Round 2 to the hash buffer + hasher.add_element(round_two_out.z_poly_at_secret_g1); const libff::Fr alpha = hasher.get_hash(); test_plonk_prover_round_three( example, @@ -501,20 +541,61 @@ template void test_plonk_prover_rounds() round_zero_out, round_one_out, round_two_out, - srs); + srs, + hasher); - // Unit test Prover Round 4 + // --- Unit test Prover Round 4 --- printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); round_three_out_t round_three_out = plonk_prover::round_three( - alpha, beta, gamma, round_zero_out, round_one_out, round_two_out, srs); + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); + hasher.add_element(libff::Fr::one()); + // add outputs from Round 2 to the hash buffer + hasher.add_element(round_two_out.z_poly_at_secret_g1); + // add outputs from Round 3 to the hash buffer + hasher.add_element(round_three_out.t_poly_at_secret_g1[lo]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); const libff::Fr zeta = hasher.get_hash(); test_plonk_prover_round_four( - example, zeta, round_one_out, round_three_out, srs); + example, zeta, round_one_out, round_three_out, srs, hasher); - // Unit test Prover Round 5 + // --- Unit test Prover Round 5 --- printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs); + zeta, round_one_out, round_three_out, srs, hasher); + // clear hash buffer + hasher.buffer_clear(); + // add outputs from Round 1 to the hash buffer + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); + hasher.add_element(libff::Fr::one()); + // add outputs from Round 2 to the hash buffer + hasher.add_element(round_two_out.z_poly_at_secret_g1); + // add outputs from Round 3 to the hash buffer + hasher.add_element(round_three_out.t_poly_at_secret_g1[lo]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); + hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); + // add outputs from Round 4 to the hash buffer + hasher.add_element(round_four_out.a_zeta); + hasher.add_element(round_four_out.b_zeta); + hasher.add_element(round_four_out.c_zeta); + hasher.add_element(round_four_out.S_0_zeta); + hasher.add_element(round_four_out.S_1_zeta); + hasher.add_element(round_four_out.z_poly_xomega_zeta); const libff::Fr nu = hasher.get_hash(); test_plonk_prover_round_five( example, @@ -528,7 +609,8 @@ template void test_plonk_prover_rounds() round_two_out, round_three_out, round_four_out, - srs); + srs, + hasher); } /// \attention the example class is defined specifically for the BLS12-381 @@ -599,8 +681,8 @@ template void test_plonk_prover() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // initialize prover plonk_prover prover; @@ -877,8 +959,8 @@ template void test_plonk_verifier_steps() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // initialize prover plonk_prover prover; @@ -891,7 +973,7 @@ template void test_plonk_verifier_steps() // unit test verifier step 5 const step_four_out_t step_four_out = - plonk_verifier::step_four(hasher); + plonk_verifier::step_four(proof, hasher); test_plonk_verifier_step_five(example, step_four_out, srs); // unit test verifier step 6 @@ -976,8 +1058,8 @@ template void test_plonk_verifier() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - size_t istep = 0; - transcript_hasher hasher(istep); + std::vector buffer; + transcript_hasher hasher(buffer); // initialize prover plonk_prover prover; diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 81bdd4841..ea26340ea 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -186,6 +186,7 @@ template class plonk_verifier /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT + /// \param[in] proof: SNARK proof produced by the prover /// \param[in] transcript_hasher: hashes of the communication /// transcript after prover rounds 1,2,3,4,5. /// @@ -198,7 +199,8 @@ template class plonk_verifier /// v in [GWC19]) /// \param[out] u: multipoint evaluation challenge - hash of /// transcript - static step_four_out_t step_four(transcript_hasher &hasher); + static step_four_out_t step_four( + const plonk_proof &proof, transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index dbf4ff2c5..5380fe5b3 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -100,6 +100,7 @@ step_four_out_t::step_four_out_t( /// pi-SNARK. TODO: fixed to the test vectors for now /// /// INPUT +/// \param[in] proof: SNARK proof produced by the prover /// \param[in] transcript_hasher: hashes of the communication /// transcript after prover rounds 1,2,3,4,5. /// @@ -114,14 +115,52 @@ step_four_out_t::step_four_out_t( /// transcript template step_four_out_t plonk_verifier::step_four( - transcript_hasher &hasher) + const plonk_proof &proof, transcript_hasher &hasher) { + // add outputs from Round 1 to the hash buffer + hasher.add_element(proof.W_polys_blinded_at_secret_g1[a]); + hasher.add_element(proof.W_polys_blinded_at_secret_g1[b]); + hasher.add_element(proof.W_polys_blinded_at_secret_g1[c]); + // - beta: permutation challenge - hashes of transcript of round + // 1 (\attention the original protocl appends a 0, while we don't + // append anyhting to avoid making a copy of the buffer) libff::Fr beta = hasher.get_hash(); + // - gamma: permutation challenge - hashes of transcript of round + // 1 with 1 appended + hasher.add_element(libff::Fr::one()); libff::Fr gamma = hasher.get_hash(); + + // add outputs from Round 2 to the hash buffer + hasher.add_element(proof.z_poly_at_secret_g1); + // - alpha: quotient challenge - hash of transcript of rounds 1,2 libff::Fr alpha = hasher.get_hash(); + + // add outputs from Round 3 to the hash buffer + hasher.add_element(proof.t_poly_at_secret_g1[lo]); + hasher.add_element(proof.t_poly_at_secret_g1[mid]); + hasher.add_element(proof.t_poly_at_secret_g1[hi]); + // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 libff::Fr zeta = hasher.get_hash(); + + // add outputs from Round 4 to the hash buffer + hasher.add_element(proof.a_zeta); + hasher.add_element(proof.b_zeta); + hasher.add_element(proof.c_zeta); + hasher.add_element(proof.S_0_zeta); + hasher.add_element(proof.S_1_zeta); + hasher.add_element(proof.z_poly_xomega_zeta); + // - nu: opening challenge -- hash of transcript (denoted by v in + // [GWC19]) libff::Fr nu = hasher.get_hash(); + + // add outputs from Round 5 to the hash buffer + hasher.add_element(proof.r_zeta); + hasher.add_element(proof.W_zeta_at_secret); + hasher.add_element(proof.W_zeta_omega_at_secret); + // u: multipoint evaluation challenge -- hash of transcript from + // rounds 1,2,3,4,5 libff::Fr u = hasher.get_hash(); + // step 4 output step_four_out_t step_four_out(beta, gamma, alpha, zeta, nu, u); @@ -621,7 +660,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 4: compute challenges hashed transcript as in // prover description, from the common inputs, public input, and // elements of pi-SNARK (fixed to the test vectors for now) - const step_four_out_t step_four_out = this->step_four(hasher); + const step_four_out_t step_four_out = this->step_four(proof, hasher); // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = From 73ff0383b21ff4bf79939a8c15e16ce4753a27c0 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 10:29:07 +0100 Subject: [PATCH 069/154] plonk: moved the initialisation of the array of expected hash values to the transcript hasher constructor (cf. https://github.com/clearmatics/libsnark/pull/61#discussion_r935463921); added exception handling in case the buffer length is invalid (cf. https://github.com/clearmatics/libsnark/pull/61#discussion_r935473057) --- libsnark/zk_proof_systems/plonk/srs.hpp | 3 + libsnark/zk_proof_systems/plonk/srs.tcc | 90 +++++++++++-------- .../plonk/tests/test_plonk.cpp | 1 - 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index e58199855..2acb93c4c 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -248,6 +248,9 @@ template class transcript_hasher private: // buffer accumulating data to be hashed std::vector buffer; + // array containing the hash values of the communication transcript + // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u + std::array, 6> hash_values; public: void add_element(const libff::Fr &element); diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 299adce8c..e6fbcbd86 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -77,6 +77,25 @@ template transcript_hasher::transcript_hasher(std::vector &buffer) : buffer(std::move(buffer)) { + // test array containing the expected hash values of the communication + // transcript i.e. the communication challenges (in this order): beta, + // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 + this->hash_values = { + libff::Fr("3710899868510394644410941212967766116886736137326022751" + "891187938298987182388"), // beta + libff::Fr("110379303840831945879077096653321168432672740458288022" + "49545114995763715746939"), // gamma + libff::Fr("379799789992747238930717819864848384921111623418803600" + "22719385400306128734648"), // alpha + libff::Fr("4327197228921839935583364394550235027071910395980312641" + "5018065799136107272465"), // zeta + libff::Fr( + "275158598338697752421507265080923414294782807831923791651" + "55175653098691426347"), // nu + libff::Fr( + "1781751143954696684632449211212056577828855388109883650570" + "6049265393896966778"), // u + }; } /// clear the buffer (for now only for testing) @@ -158,27 +177,37 @@ void transcript_hasher::add_element(const libff::G2 &element) /// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { - using Field = libff::Fr; - size_t buffer_len = this->buffer.size(); // DEBUG printf("[%s:%d] len %7d\n", __FILE__, __LINE__, (int)buffer_len); // vector of valid lengths (\attention specific to BLS12-381) - std::vector length{288, 320, 416, 704, 896, 1120}; - - Field beta = Field("3710899868510394644410941212967766116886736137326022751" - "891187938298987182388"); - Field gamma = Field("110379303840831945879077096653321168432672740458288022" - "49545114995763715746939"); - Field alpha = Field("379799789992747238930717819864848384921111623418803600" - "22719385400306128734648"); - Field zeta = Field("4327197228921839935583364394550235027071910395980312641" - "5018065799136107272465"); - Field nu = Field("275158598338697752421507265080923414294782807831923791651" - "55175653098691426347"); - Field u = Field("1781751143954696684632449211212056577828855388109883650570" - "6049265393896966778"); + const std::vector length{288, 320, 416, 704, 896, 1120}; + + // If we are here, then the hasher buffer has invalid length so throw an + // exception + bool b_valid_length = + ((buffer_len == length[0]) || (buffer_len == length[1]) || + (buffer_len == length[2]) || (buffer_len == length[3]) || + (buffer_len == length[4]) || (buffer_len == length[5])); + try { + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); + } + } catch (const std::logic_error &e) { + std::cout << "Error: " << e.what() << "\n"; + } + if (!b_valid_length) { + printf( + "[%s:%d] Error: invalid length of transcript hasher buffer\n", + __FILE__, + __LINE__); + } + assert(b_valid_length); + + libff::Fr challenge = 0; + // beta if (buffer_len == length[0]) { printf( @@ -186,7 +215,7 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return beta; + challenge = this->hash_values[0]; // beta } // gamma if (buffer_len == length[1]) { @@ -195,7 +224,7 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return gamma; + challenge = this->hash_values[1]; // gamma } // alpha if (buffer_len == length[2]) { @@ -204,7 +233,7 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return alpha; + challenge = this->hash_values[2]; // alpha } // zeta if (buffer_len == length[3]) { @@ -213,13 +242,13 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - return zeta; + challenge = this->hash_values[3]; // zeta } // nu if (buffer_len == length[4]) { printf( "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); - return nu; + challenge = this->hash_values[4]; // nu } // u if (buffer_len == length[5]) { @@ -230,23 +259,10 @@ template libff::Fr transcript_hasher::get_hash() __LINE__, (int)buffer_len); this->buffer.clear(); - return u; + challenge = this->hash_values[5]; // u } - bool b_valid_length = - ((buffer_len == length[0]) || (buffer_len == length[1]) || - (buffer_len == length[2]) || (buffer_len == length[3]) || - (buffer_len == length[4]) || (buffer_len == length[5])); - try { - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - } catch (const std::logic_error &e) { - std::cout << "Error: " << e.what() << "\n"; - } - assert(b_valid_length); - // If we are here, then the hasher buffer has invalid length so return error - return 0; + + return challenge; } /// Compute a universal srs (usrs). It is composed *only* of encoded diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 68e13ee87..e6329831c 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -20,7 +20,6 @@ namespace libsnark { - #define PLONK_MAX_DEGREE 245 // Manipulate elements of a valid proof to assert that proof From 8d6494d19c0bb397103907bfa230a746b3270ee4 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 17 Aug 2022 20:07:52 +0100 Subject: [PATCH 070/154] plonk: removed catching the invalid size exception within the get_hash function. the caller must handle it. --- libsnark/zk_proof_systems/plonk/srs.tcc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index e6fbcbd86..ff3ba75f5 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -190,13 +190,9 @@ template libff::Fr transcript_hasher::get_hash() ((buffer_len == length[0]) || (buffer_len == length[1]) || (buffer_len == length[2]) || (buffer_len == length[3]) || (buffer_len == length[4]) || (buffer_len == length[5])); - try { - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - } catch (const std::logic_error &e) { - std::cout << "Error: " << e.what() << "\n"; + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); } if (!b_valid_length) { printf( From 24f3ae7b415815d8ceb0f4a6169646d4196898e0 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 18 Aug 2022 09:44:34 +0100 Subject: [PATCH 071/154] plonk: removed computation of the challenge u at the end of the prover process since u is not used by the prover anyway. removed the automatic clearing of the hasher buffer inside get_hash. the caller is now responsible to clear the buffer when reusing the same hasher object. see also PR comment https://github.com/clearmatics/libsnark/pull/61#discussion_r948822968 . --- libsnark/zk_proof_systems/plonk/prover.tcc | 13 --------- libsnark/zk_proof_systems/plonk/srs.tcc | 1 - .../plonk/tests/test_plonk.cpp | 28 ++++++++++++++++++- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index a9c3640e6..4b1596113 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -1104,19 +1104,6 @@ plonk_proof plonk_prover::compute_proof( srs, hasher); - // TODO: activate this part when we implement actual hashing of - // communication transcripts -#if 0 - // u: multipoint evaluation challenge -- hash of transcript from - // rounds 1,2,3,4,5 - const libff::Fr u = hasher.get_hash(); -#else - // do the hash anyway in order to keep the correct count of the - // hasher istep member (which resets to 0 only after the last hash - // is performed which is hash of u) - hasher.get_hash(); -#endif - // construct proof plonk_proof proof( round_one_out.W_polys_blinded_at_secret_g1, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index ff3ba75f5..415f364a8 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -254,7 +254,6 @@ template libff::Fr transcript_hasher::get_hash() __FILE__, __LINE__, (int)buffer_len); - this->buffer.clear(); challenge = this->hash_values[5]; // u } diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index e6329831c..18cb18d36 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -54,6 +54,7 @@ void test_verify_invalid_proof( for (size_t i = 0; i < valid_proof.W_polys_blinded_at_secret_g1.size(); ++i) { // re-initialize the manipulated proof + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = @@ -62,6 +63,7 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } // manipulate [z]_1 + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; @@ -70,6 +72,7 @@ void test_verify_invalid_proof( // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { // re-initialize the manipulated proof + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; @@ -77,54 +80,63 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } // manipulate \bar{a} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{b} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{c} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 + hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; b_accept = verifier.verify_proof(proof, srs, hasher); ASSERT_FALSE(b_accept); // manipulate r_zeta + hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; @@ -967,12 +979,18 @@ template void test_plonk_verifier_steps() plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); + // clear the hasher buffer in order to re-use the same transcript_hasher + // object for the verifier + hasher.buffer_clear(); + // Unit test verifier preprocessed input test_plonk_verifier_preprocessed_input(example, srs); - // unit test verifier step 5 + // compute step 4 const step_four_out_t step_four_out = plonk_verifier::step_four(proof, hasher); + + // unit test verifier step 5 test_plonk_verifier_step_five(example, step_four_out, srs); // unit test verifier step 6 @@ -1066,11 +1084,19 @@ template void test_plonk_verifier() plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); + // clear the hasher buffer in order to re-use the same transcript_hasher + // object for the verifier + hasher.buffer_clear(); + // initialize verifier plonk_verifier verifier; // verify proof bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); ASSERT_TRUE(b_valid_proof); + + // clear the hasher buffer in order to re-use the same transcript_hasher + // object + hasher.buffer_clear(); // assert that proof verification fails when the proof is // manipulated test_verify_invalid_proof(proof, srs, hasher); From c66787d19c6718f02a52a0f6a927b82f87dd4077 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 18 Aug 2022 10:01:50 +0100 Subject: [PATCH 072/154] plonk: use std::count to check if the hasher buffer is of valid length instead of explicitly checking all valid lengths. --- libsnark/zk_proof_systems/plonk/srs.tcc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 415f364a8..2648a9a40 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -187,9 +187,7 @@ template libff::Fr transcript_hasher::get_hash() // If we are here, then the hasher buffer has invalid length so throw an // exception bool b_valid_length = - ((buffer_len == length[0]) || (buffer_len == length[1]) || - (buffer_len == length[2]) || (buffer_len == length[3]) || - (buffer_len == length[4]) || (buffer_len == length[5])); + (0 != std::count(length.begin(), length.end(), buffer_len)); if (!b_valid_length) { throw std::logic_error( "Error: invalid length of transcript hasher buffer"); From 8e3ac3b92a1ebfd1c309eefeb24e5ed3633b58f3 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 19 Aug 2022 11:41:54 +0100 Subject: [PATCH 073/154] plonk: removed doc comments /// from cpp and tcc files. left only in headers. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r949757635 --- libsnark/zk_proof_systems/plonk/circuit.tcc | 6 +- libsnark/zk_proof_systems/plonk/prover.tcc | 422 ++++++++-------- libsnark/zk_proof_systems/plonk/srs.tcc | 52 +- .../zk_proof_systems/plonk/tests/example.tcc | 4 +- libsnark/zk_proof_systems/plonk/utils.tcc | 172 ++++--- libsnark/zk_proof_systems/plonk/verifier.tcc | 468 +++++++++--------- 6 files changed, 580 insertions(+), 544 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index bae016eff..06a14e3fb 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -9,8 +9,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ -/// Implementation of Common Preprocessed Input interfaces for a -/// ppzkSNARK for Plonk. See circuit.hpp . +// Implementation of Common Preprocessed Input interfaces for a +// ppzkSNARK for Plonk. See circuit.hpp . namespace libsnark { @@ -18,7 +18,7 @@ namespace libsnark // TODO: add here function for describing the target circuit through // the circuit_t structure -/// stuct constructor +// stuct constructor template circuit_t::circuit_t( size_t num_gates, diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 4b1596113..5d79429e3 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -9,13 +9,13 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_PROVER_TCC_ -/// Implementation of Prover interfaces for a ppzkSNARK for Plonk. See -/// prover.hpp . +// Implementation of Prover interfaces for a ppzkSNARK for Plonk. See +// prover.hpp . namespace libsnark { -/// Prover round 0 output constructor +// Prover round 0 output constructor template round_zero_out_t::round_zero_out_t( const std::vector> &&zh_poly, @@ -25,18 +25,18 @@ round_zero_out_t::round_zero_out_t( { } -/// Prover Round 0 initialization -/// -/// Initialization -/// -/// INPUT -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] zh_poly: vanishing polynomial -/// \param[out] null_poly: 0 polynomial -/// \param[out] neg_one_poly: -1 polynomial +// Prover Round 0 initialization +// +// Initialization +// +// INPUT +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] zh_poly: vanishing polynomial +// \param[out] null_poly: 0 polynomial +// \param[out] neg_one_poly: -1 polynomial template round_zero_out_t plonk_prover::round_zero(const srs &srs) { @@ -62,7 +62,7 @@ round_zero_out_t plonk_prover::round_zero(const srs &srs) return round_zero_out; } -/// Prover round 1 output constructor +// Prover round 1 output constructor template round_one_out_t::round_one_out_t( const std::vector>> &&W_polys, @@ -74,28 +74,28 @@ round_one_out_t::round_one_out_t( { } -/// Prover Round 1 -/// -/// INPUT -/// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -/// \param[in] null_poly: 0 polynomial (from round 0) -/// \param[in] neg_one_poly: -1 polynomial (from round 0) -/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -/// b1-b6 used in round 1) -/// \param[in] witness: witness values -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] W_polys: witness polynomials (Lagrange interpolation -/// of the witness values) -/// \param[out] W_polys_blinded: blinded witness polynomials -/// \param[out] W_polys_blinded_at_secret_g1: the blinded witness -/// polynomials evaluated at the secret input denoted -/// [a]_1, [b]_1, [c]_1 in [GWC19] -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 1 +// +// INPUT +// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +// \param[in] null_poly: 0 polynomial (from round 0) +// \param[in] neg_one_poly: -1 polynomial (from round 0) +// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +// b1-b6 used in round 1) +// \param[in] witness: witness values +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] W_polys: witness polynomials (Lagrange interpolation +// of the witness values) +// \param[out] W_polys_blinded: blinded witness polynomials +// \param[out] W_polys_blinded_at_secret_g1: the blinded witness +// polynomials evaluated at the secret input denoted +// [a]_1, [b]_1, [c]_1 in [GWC19] +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, @@ -157,7 +157,7 @@ round_one_out_t plonk_prover::round_one( return round_one_out; } -/// Prover round 2 output +// Prover round 2 output template round_two_out_t::round_two_out_t( polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1) @@ -165,23 +165,23 @@ round_two_out_t::round_two_out_t( { } -/// Prover Round 2 -/// -/// INPUT -/// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -/// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -/// b7,b8,b9 used in round 2) -/// \param[in] witness: witness values -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] z_poly: blinded accumulator poly z(x) -/// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) -/// evaluated at secret -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 2 +// +// INPUT +// \param[in] zh_poly: vanishing polynomial Zh (from round 0) +// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only +// b7,b8,b9 used in round 2) +// \param[in] witness: witness values +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] z_poly: blinded accumulator poly z(x) +// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) +// evaluated at secret +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_two_out_t plonk_prover::round_two( const libff::Fr &beta, @@ -227,7 +227,7 @@ round_two_out_t plonk_prover::round_two( return round_two_out; } -/// Prover round 3 output constructor +// Prover round 3 output constructor template round_three_out_t::round_three_out_t( std::vector> &&z_poly_xomega, @@ -241,30 +241,30 @@ round_three_out_t::round_three_out_t( { } -/// Prover Round 3 -/// -/// INPUT -/// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) -/// \param[in] W_polys_blinded: blinded witness polynomials (from -/// Round 1) -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from round 2) -/// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] t_poly_long: the quotient polynomial t(x) (see Round -/// 3, pp28 [GWC19]) -/// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -/// t_mid(x) x^n + t_hi(x) x^{2n} -/// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret -/// input zeta i.e. t(zeta) -/// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -/// by w -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 3 +// +// INPUT +// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) +// \param[in] W_polys_blinded: blinded witness polynomials (from +// Round 1) +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from round 2) +// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] t_poly_long: the quotient polynomial t(x) (see Round +// 3, pp28 [GWC19]) +// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + +// t_mid(x) x^n + t_hi(x) x^{2n} +// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret +// input zeta i.e. t(zeta) +// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted +// by w +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, @@ -496,7 +496,7 @@ round_three_out_t plonk_prover::round_three( return round_three_out; } -/// Prover round 4 output constructor +// Prover round 4 output constructor template round_four_out_t::round_four_out_t( libff::Fr &&a_zeta, @@ -516,40 +516,40 @@ round_four_out_t::round_four_out_t( { } -/// Prover Round 4 -/// -/// INPUT -/// \param[in] W_polys_blinded: blinded witness polynomials (from -/// Round 1) -/// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -/// by w (from Round 3) -/// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, -/// pp28 [GWC19]) (from Round 3) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness -/// polynomials a(x), b(x), c(x) (denoted by -/// W_polys_blinded[] output from Round 1) evaluated at -/// x=zeta i.e. a(z), b(z), c(z) -/// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials -/// S_sigma_1(x), S_sigma_2(x) from the common -/// preprocessed input (see [GWC19], Sect. 8.1) evaluated -/// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) -/// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -/// shifted by w (output from Round 3) evaluated at x=zeta -/// i.e. z(zeta*w) -/// \param[out] t_zeta: the quotient polynomial t(x) output from Round -/// 3, see pp28 [GWC19]) evaluated at x=zeta -/// i.e. t(z). IMPORTANT! the original Plonk proposal -/// [GWC19] does not output this parameter t_zeta. The -/// Python reference implementation \[PlonkPy] does, so we -/// do the same in order to match the test vectors. TODO -/// can remove t_zeta in the future -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 4 +// +// INPUT +// \param[in] W_polys_blinded: blinded witness polynomials (from +// Round 1) +// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted +// by w (from Round 3) +// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, +// pp28 [GWC19]) (from Round 3) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness +// polynomials a(x), b(x), c(x) (denoted by +// W_polys_blinded[] output from Round 1) evaluated at +// x=zeta i.e. a(z), b(z), c(z) +// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials +// S_sigma_1(x), S_sigma_2(x) from the common +// preprocessed input (see [GWC19], Sect. 8.1) evaluated +// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) +// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) +// shifted by w (output from Round 3) evaluated at x=zeta +// i.e. z(zeta*w) +// \param[out] t_zeta: the quotient polynomial t(x) output from Round +// 3, see pp28 [GWC19]) evaluated at x=zeta +// i.e. t(z). IMPORTANT! the original Plonk proposal +// [GWC19] does not output this parameter t_zeta. The +// Python reference implementation \[PlonkPy] does, so we +// do the same in order to match the test vectors. TODO +// can remove t_zeta in the future +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, @@ -606,7 +606,7 @@ round_four_out_t plonk_prover::round_four( return round_four_out; } -/// Prover round 5 output constructor +// Prover round 5 output constructor template round_five_out_t::round_five_out_t( libff::Fr &&r_zeta, @@ -618,53 +618,53 @@ round_five_out_t::round_five_out_t( { } -/// Prover Round 5 -/// -/// INPUT -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from round 2) -/// \param[in] alpha: quotinet challenge -- hash of transcript (from -/// round 3) -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// round 4) -/// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials -/// a(x), b(x), c(x) (denoted by W_polys_blinded[] output -/// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) -/// (from round 4) -/// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials -/// S_sigma_1(x), S_sigma_2(x) from the common preprocessed -/// input (see [GWC19], Sect. 8.1) evaluated at x=zeta -/// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) -/// \param[in] t_zeta: the quotient polynomial t(x) output from Round -/// 3, see pp28 [GWC19]) evaluated at x=zeta -/// i.e. t(z). IMPORTANT! the original Plonk proposal -/// [GWC19] does not output this parameter t_zeta. The -/// Python reference implementation \[PlonkPy] does, so we -/// do the same in order to match the test vectors. TODO -/// can remove t_zeta in the future (from round 4) -/// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -/// shifted by w (output from Round 3) evaluated at x=zeta -/// i.e. z(zeta*w) (from round 4) -/// \param[in] W_polys_blinded: blinded witness polynomials (from -/// round 1) -/// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -/// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) -/// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] r_zeta: linearisation polynomial r(x) evaluated at -/// x=zeta ie. r(zeta) -/// \param[out] W_zeta_at_secret: commitment to opening proof -/// polynomial W_zeta(x) at secert input -/// i.e. [W_zeta(secret)]_1 -/// \param[out] W_zeta_omega_at_secret: commitment to opening proof -/// polynomial W_{zeta omega}(x) at secert input -/// i.e. [W_{zeta omega}(secret)]_1 -/// \param[out] transcript_hasher: accumulates the communication -/// transcript into a buffer to be hashed after prover -/// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). +// Prover Round 5 +// +// INPUT +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from round 2) +// \param[in] alpha: quotinet challenge -- hash of transcript (from +// round 3) +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// round 4) +// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials +// a(x), b(x), c(x) (denoted by W_polys_blinded[] output +// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) +// (from round 4) +// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials +// S_sigma_1(x), S_sigma_2(x) from the common preprocessed +// input (see [GWC19], Sect. 8.1) evaluated at x=zeta +// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) +// \param[in] t_zeta: the quotient polynomial t(x) output from Round +// 3, see pp28 [GWC19]) evaluated at x=zeta +// i.e. t(z). IMPORTANT! the original Plonk proposal +// [GWC19] does not output this parameter t_zeta. The +// Python reference implementation \[PlonkPy] does, so we +// do the same in order to match the test vectors. TODO +// can remove t_zeta in the future (from round 4) +// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) +// shifted by w (output from Round 3) evaluated at x=zeta +// i.e. z(zeta*w) (from round 4) +// \param[in] W_polys_blinded: blinded witness polynomials (from +// round 1) +// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + +// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) +// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] r_zeta: linearisation polynomial r(x) evaluated at +// x=zeta ie. r(zeta) +// \param[out] W_zeta_at_secret: commitment to opening proof +// polynomial W_zeta(x) at secert input +// i.e. [W_zeta(secret)]_1 +// \param[out] W_zeta_omega_at_secret: commitment to opening proof +// polynomial W_{zeta omega}(x) at secert input +// i.e. [W_{zeta omega}(secret)]_1 +// \param[out] transcript_hasher: accumulates the communication +// transcript into a buffer to be hashed after prover +// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, @@ -993,51 +993,51 @@ plonk_proof::plonk_proof( { } -/// Prover compute SNARK proof -/// -/// Pi ([a]_1, [b]_1, [c]_1, [z]_1, -/// [t_lo]_1, [t_mi]_1, [t_hi]_1, -/// \bar{a}, \bar{b}, \bar{c}, -/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, -/// [W_zeta]_1, [W_{zeta omega}]_1 -/// r_zeta) -/// -/// \note in the reference Python implementation \[PlonkPy], r_zeta -/// (the evaluation of the linearlization polynomial r(X) at zeta from -/// Prover round 5) is added to the pi-SNARK proof. In the paper this -/// is omitted, which seems to make the proof shorter by 1 element at -/// the epxense of a slightly heavier computation on the verifier's -/// side. Here we follow the reference implementation \[PlonkPy] to -/// make sure we match the test values. TODO: once all test vectors -/// are verified, we may remove r_zeta from the proof to be fully -/// compliant with the paper. -/// -/// Mapping code-to-paper quantities -/// -/// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 -/// (from Round 1) -/// \param z_poly_at_secret_g1: [z]_1 (from Round 2) -/// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, -/// [t_hi]_1 (from Round 3) -/// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, -/// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, -/// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) -/// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, -/// [W_{zeta omega}]_1 (from Round 5) -/// -/// INPUT -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// \param[in] witness: all internal values and public input -/// corresponding to the given circuit -/// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 -/// used in prover rounds 1 and 2 (see Sect. 8.3, roumds -/// 1,2 [GWC19]) -/// \param[in] transcript_hasher: hashes of the communication -/// transcript after prover rounds 1,2,3,4,5. -/// -/// OUTPUT -/// \param[out] proof: SNARK proof Pi (see above) +// Prover compute SNARK proof +// +// Pi ([a]_1, [b]_1, [c]_1, [z]_1, +// [t_lo]_1, [t_mi]_1, [t_hi]_1, +// \bar{a}, \bar{b}, \bar{c}, +// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, +// [W_zeta]_1, [W_{zeta omega}]_1 +// r_zeta) +// +// \note in the reference Python implementation \[PlonkPy], r_zeta +// (the evaluation of the linearlization polynomial r(X) at zeta from +// Prover round 5) is added to the pi-SNARK proof. In the paper this +// is omitted, which seems to make the proof shorter by 1 element at +// the epxense of a slightly heavier computation on the verifier's +// side. Here we follow the reference implementation \[PlonkPy] to +// make sure we match the test values. TODO: once all test vectors +// are verified, we may remove r_zeta from the proof to be fully +// compliant with the paper. +// +// Mapping code-to-paper quantities +// +// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 +// (from Round 1) +// \param z_poly_at_secret_g1: [z]_1 (from Round 2) +// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, +// [t_hi]_1 (from Round 3) +// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, +// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, +// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) +// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, +// [W_{zeta omega}]_1 (from Round 5) +// +// INPUT +// \param[in] srs: structured reference string containing also +// circuit-specific information +// \param[in] witness: all internal values and public input +// corresponding to the given circuit +// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 +// used in prover rounds 1 and 2 (see Sect. 8.3, roumds +// 1,2 [GWC19]) +// \param[in] transcript_hasher: hashes of the communication +// transcript after prover rounds 1,2,3,4,5. +// +// OUTPUT +// \param[out] proof: SNARK proof Pi (see above) template plonk_proof plonk_prover::compute_proof( const srs &srs, @@ -1087,8 +1087,8 @@ plonk_proof plonk_prover::compute_proof( zeta, round_one_out, round_three_out, srs, hasher); printf("[%s:%d] Prover Round 5...\n", __FILE__, __LINE__); - /// - nu: opening challenge -- hash of transcript (denoted by v in - /// [GWC19]) + // - nu: opening challenge -- hash of transcript (denoted by v in + // [GWC19]) const libff::Fr nu = hasher.get_hash(); round_five_out_t round_five_out = plonk_prover::round_five( alpha, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 2648a9a40..d52488575 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -9,8 +9,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ -/// Implementation of SRS interfaces for a ppzkSNARK for Plonk. See -/// srs.hpp . +// Implementation of SRS interfaces for a ppzkSNARK for Plonk. See +// srs.hpp . namespace libsnark { @@ -58,13 +58,13 @@ srs::srs( { } -/// class plonk_verification_key +// class plonk_verification_key template plonk_verification_key::plonk_verification_key( std::vector> &&secret_powers_g2) : secret_powers_g2(std::move(secret_powers_g2)){}; -/// class plonk_keypair constructor +// class plonk_keypair constructor template plonk_keypair::plonk_keypair( plonk_proving_key &&pk, plonk_verification_key &&vk) @@ -72,7 +72,7 @@ plonk_keypair::plonk_keypair( { } -/// transcript_hasher constructor +// transcript_hasher constructor template transcript_hasher::transcript_hasher(std::vector &buffer) : buffer(std::move(buffer)) @@ -98,19 +98,19 @@ transcript_hasher::transcript_hasher(std::vector &buffer) }; } -/// clear the buffer (for now only for testing) +// clear the buffer (for now only for testing) template void transcript_hasher::buffer_clear() { this->buffer.clear(); } -/// get buffer size +// get buffer size template size_t transcript_hasher::buffer_size() { return this->buffer.size(); } -/// add an Fr element to the transcript buffer for hashing +// add an Fr element to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::Fr &element) { @@ -127,7 +127,7 @@ void transcript_hasher::add_element(const libff::Fr &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -/// add the coordinates of a G1 curve point to the transcript buffer for hashing +// add the coordinates of a G1 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G1 &element) { @@ -149,7 +149,7 @@ void transcript_hasher::add_element(const libff::G1 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -/// add the coordinates of a G2 curve point to the transcript buffer for hashing +// add the coordinates of a G2 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G2 &element) { @@ -171,10 +171,10 @@ void transcript_hasher::add_element(const libff::G2 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -/// dummy implementation of get_hash that directly returns the -/// expected hard-coded hashes for the purposes of unit testing TODO -/// to be replaced by a call to a proper hash function e.g. SHA2, -/// BLAKE, etc. +// dummy implementation of get_hash that directly returns the +// expected hard-coded hashes for the purposes of unit testing TODO +// to be replaced by a call to a proper hash function e.g. SHA2, +// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { size_t buffer_len = this->buffer.size(); @@ -258,11 +258,11 @@ template libff::Fr transcript_hasher::get_hash() return challenge; } -/// Compute a universal srs (usrs). It is composed *only* of encoded -/// powers of the secret value in the group generator. Therefore a usrs -/// is independent of any particular circuit. -/// -/// \note only for debug +// Compute a universal srs (usrs). It is composed *only* of encoded +// powers of the secret value in the group generator. Therefore a usrs +// is independent of any particular circuit. +// +// \note only for debug template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) @@ -301,13 +301,13 @@ usrs plonk_usrs_derive_from_secret( return usrs(std::move(secret_powers_g1), std::move(secret_powers_g2)); } -/// Derive the (plain) SRS from the circuit description and the -/// USRS. The (plain) SRS is a specialization of the USRS for one -/// particular circuit i.e. -/// -/// usrs = -/// srs = (proving_key, verificataion_key) = derive(usrs, -/// circuit_description) +// Derive the (plain) SRS from the circuit description and the +// USRS. The (plain) SRS is a specialization of the USRS for one +// particular circuit i.e. +// +// usrs = +// srs = (proving_key, verificataion_key) = derive(usrs, +// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.tcc b/libsnark/zk_proof_systems/plonk/tests/example.tcc index a9dee03d2..2b90b121a 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.tcc +++ b/libsnark/zk_proof_systems/plonk/tests/example.tcc @@ -8,8 +8,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_TCC_ -/// Instantiation of the test vector values from the Python implementation -/// of the Plonk protocol. \see example.hpp . +// Instantiation of the test vector values from the Python implementation +// of the Plonk protocol. \see example.hpp . namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 13482419a..2cb62ae60 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -9,13 +9,13 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ -/// Implementation of interfaces for a ppzkSNARK for Plonk. See -/// utils.hpp . +// Implementation of interfaces for a ppzkSNARK for Plonk. See +// utils.hpp . namespace libsnark { -/// print the elements of a vector +// print the elements of a vector template void print_vector(const std::vector &v) { for (size_t i = 0; i < v.size(); ++i) { @@ -24,25 +24,61 @@ template void print_vector(const std::vector &v) } } -/// Interpolate a polynomial from a set of points through inverse FFT -/// -/// INPUT: -/// -/// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), -/// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], -/// ... which we want to interpolate as a polynomial -/// -/// OUTPUT: -/// -/// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] -/// of the polynomial f(x) interpolating the set of points -/// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., -/// a_{n-1}] then this represents the polynomial f(x) = -/// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that -/// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} -/// are the n roots of unity. -/// -/// \note uses libfqfft iFFT for the interpolation +// Compute the Lagrange basis polynomials for interpolating sets of +// n points +// +// INPUT: +// +// \param[in] npoints - number of points +// +// OUTPUT: +// +// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of +// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, +// a1, ..., a_{n-1}] is a vector representing the +// coefficients of the i-th Lagrange polynomial L_i(x) = +// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 +// and L_i(x\neq{omega_i)})=0 +// +// \note uses libfqfft iFFT for the interpolation +template +void plonk_compute_lagrange_basis( + const size_t npoints, std::vector> &L) +{ + assert(L.size() != 0); + assert(L.size() == L[0].size()); + assert(L.size() == npoints); + + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(npoints); + for (size_t i = 0; i < npoints; ++i) { + polynomial u(npoints, FieldT(0)); + u[i] = FieldT(1); + // compute i-th Lagrange basis vector via inverse FFT + domain->iFFT(u); + L[i] = u; + } +} + +// Interpolate a polynomial from a set of points through inverse FFT +// +// INPUT: +// +// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), +// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], +// ... which we want to interpolate as a polynomial +// +// OUTPUT: +// +// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] +// of the polynomial f(x) interpolating the set of points +// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., +// a_{n-1}] then this represents the polynomial f(x) = +// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that +// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} +// are the n roots of unity. +// +// \note uses libfqfft iFFT for the interpolation template void plonk_interpolate_polynomial_from_points( const std::vector &f_points, polynomial &f_poly) @@ -54,11 +90,11 @@ void plonk_interpolate_polynomial_from_points( domain->iFFT(f_poly); } -/// Compute the selector polynomials of the given circuit (also -/// called here "q-polynomials"). See Sect. 8.1. The matrix -/// gates_matrix_transpose has 5 rows, each corresponding to the -/// values L, R, M, O and C for each gate; the number of columns is -/// equal to the number of gates. L_basis is the Lagrange basis. +// Compute the selector polynomials of the given circuit (also +// called here "q-polynomials"). See Sect. 8.1. The matrix +// gates_matrix_transpose has 5 rows, each corresponding to the +// values L, R, M, O and C for each gate; the number of columns is +// equal to the number of gates. L_basis is the Lagrange basis. template std::vector> plonk_compute_selector_polynomials( const size_t &num_gates, @@ -84,12 +120,12 @@ void plonk_compute_public_input_polynomial( plonk_interpolate_polynomial_from_points(PI_points, PI_poly); }; -/// This function computes the sets H, k1H, k2H. H is a -/// multiplicative subgroup containing the n-th roots of unity in Fr, -/// where \omega is a primitive n-th root of unity and a generator of -/// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -/// consist of 3n distinct elements. \see [GWC19] pp26 (top). +// This function computes the sets H, k1H, k2H. H is a +// multiplicative subgroup containing the n-th roots of unity in Fr, +// where \omega is a primitive n-th root of unity and a generator of +// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( const size_t num_gates, @@ -126,14 +162,14 @@ void plonk_compute_roots_of_unity_omega( } } -/// This function computes the sets H, k1H, k2H, where H is a -/// multiplicative subgroup containing the n-th roots of unity in Fr and -/// \omega is a primitive n-th root of unity and a generator of -/// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -/// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -/// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. -/// -/// \note uses plonk_compute_roots_of_unity_omega +// This function computes the sets H, k1H, k2H, where H is a +// multiplicative subgroup containing the n-th roots of unity in Fr and +// \omega is a primitive n-th root of unity and a generator of +// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen +// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus +// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. +// +// \note uses plonk_compute_roots_of_unity_omega template void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, @@ -161,10 +197,10 @@ void plonk_compute_cosets_H_k1H_k2H( omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_gen)); } -/// permute the multiplicative subgroup H according to the wire -/// permutation: (see [GWC19] Sect. 8), \see -/// plonk_compute_roots_of_unity_omega, \see -/// plonk_roots_of_unity_omega_to_subgroup_H +// permute the multiplicative subgroup H according to the wire +// permutation: (see [GWC19] Sect. 8), \see +// plonk_compute_roots_of_unity_omega, \see +// plonk_roots_of_unity_omega_to_subgroup_H template std::vector plonk_permute_subgroup_H( const std::vector &H_gen, @@ -180,8 +216,8 @@ std::vector plonk_permute_subgroup_H( return H_gen_permute; } -/// compute the permutation polynomials S_sigma_1, S_sigma_2, -/// S_sigma_2 (see [GWC19], Sect. 8.1) +// compute the permutation polynomials S_sigma_1, S_sigma_2, +// S_sigma_2 (see [GWC19], Sect. 8.1) template std::vector> plonk_compute_permutation_polynomials( const std::vector &H_gen_permute, const size_t num_gates) @@ -222,21 +258,21 @@ libff::G1 plonk_multi_exp_G1( return product; } -/// Evaluate a polynomial F at the encoded secret input -/// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i -/// -/// INPUT -/// -/// \param[in] secret_powers_g1: \secret^i*G1: -/// 0\le{i} libff::G1 plonk_evaluate_poly_at_secret_G1( const std::vector> &secret_powers_g1, @@ -257,8 +293,8 @@ libff::G1 plonk_evaluate_poly_at_secret_G1( return f_poly_at_secret_g1; } -/// Evaluate a list of polynomials in the encrypted secret input: see -/// plonk_evaluate_poly_at_secret_G1 +// Evaluate a list of polynomials in the encrypted secret input: see +// plonk_evaluate_poly_at_secret_G1 template void plonk_evaluate_polys_at_secret_G1( const std::vector> &secret_powers_g1, @@ -275,10 +311,10 @@ void plonk_evaluate_polys_at_secret_G1( } } -/// Compute the factors in the product of the permutation polynomial -/// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], -/// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], -/// H_gen_permute[i-1]m etc. +// Compute the factors in the product of the permutation polynomial +// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], +// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], +// H_gen_permute[i-1]m etc. template FieldT plonk_compute_accumulator_factor( const size_t i, diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 5380fe5b3..c7cf4f650 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -9,13 +9,13 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_VERIFIER_TCC_ -/// Implementation of Verifier interfaces for a ppzkSNARK for Plonk. See -/// verifier.hpp . +// Implementation of Verifier interfaces for a ppzkSNARK for Plonk. See +// verifier.hpp . namespace libsnark { -/// struct verifier_preprocessed_input_t constructor +// struct verifier_preprocessed_input_t constructor template verifier_preprocessed_input_t::verifier_preprocessed_input_t( std::vector> &&Q_polys_at_secret_g1, @@ -25,17 +25,17 @@ verifier_preprocessed_input_t::verifier_preprocessed_input_t( { } -/// Verifier precomputation -/// -/// INPUT -/// \param[in] srs: structured reference string -/// -/// OUTPUT -/// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated -/// at -/// the secret input -/// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the -/// secret input +// Verifier precomputation +// +// INPUT +// \param[in] srs: structured reference string +// +// OUTPUT +// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated +// at +// the secret input +// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the +// secret input template verifier_preprocessed_input_t plonk_verifier::preprocessed_input( const srs &srs) @@ -55,34 +55,34 @@ verifier_preprocessed_input_t plonk_verifier::preprocessed_input( return preprocessed_input; } -/// Verifier Step 1: validate that elements belong to group G1 -/// -/// \attention This validation MUST be done by the caller. Empty -/// function here for consistency with the description in [GWC19] +// Verifier Step 1: validate that elements belong to group G1 +// +// \attention This validation MUST be done by the caller. Empty +// function here for consistency with the description in [GWC19] template void plonk_verifier::step_one(const plonk_proof &proof) { } -/// Verifier Step 2: validate that elements belong to scalar field Fr -/// -/// \attention This validation MUST be done by the caller. Empty -/// function here for consistency with the description in [GWC19] +// Verifier Step 2: validate that elements belong to scalar field Fr +// +// \attention This validation MUST be done by the caller. Empty +// function here for consistency with the description in [GWC19] template void plonk_verifier::step_two(const plonk_proof &proof) { } -/// Verifier Step 3: validate that the public input belongs to scalar -/// field Fr -/// -/// \attention This validation MUST be done by the caller. Empty -/// function here for consistency with the description in [GWC19] +// Verifier Step 3: validate that the public input belongs to scalar +// field Fr +// +// \attention This validation MUST be done by the caller. Empty +// function here for consistency with the description in [GWC19] template void plonk_verifier::step_three(const srs &srs) { } -/// struct step_four_out_t constructor +// struct step_four_out_t constructor template step_four_out_t::step_four_out_t( libff::Fr &beta, @@ -95,24 +95,24 @@ step_four_out_t::step_four_out_t( { } -/// Verifier Step 4: compute challenges hashed transcript as in prover -/// description, from the common inputs, public input, and elements of -/// pi-SNARK. TODO: fixed to the test vectors for now -/// -/// INPUT -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] transcript_hasher: hashes of the communication -/// transcript after prover rounds 1,2,3,4,5. -/// -/// OUTPUT -/// \param[out] beta, gamma: permutation challenges - hashes of -/// transcript -/// \param[out] alpha: quotinet challenge - hash of transcript -/// \param[out] zeta: evaluation challenge - hash of transcript -/// \param[out] nu: opening challenge - hash of transcript (denoted by -/// v in [GWC19]) -/// \param[out] u: multipoint evaluation challenge - hash of -/// transcript +// Verifier Step 4: compute challenges hashed transcript as in prover +// description, from the common inputs, public input, and elements of +// pi-SNARK. TODO: fixed to the test vectors for now +// +// INPUT +// \param[in] proof: SNARK proof produced by the prover +// \param[in] transcript_hasher: hashes of the communication +// transcript after prover rounds 1,2,3,4,5. +// +// OUTPUT +// \param[out] beta, gamma: permutation challenges - hashes of +// transcript +// \param[out] alpha: quotinet challenge - hash of transcript +// \param[out] zeta: evaluation challenge - hash of transcript +// \param[out] nu: opening challenge - hash of transcript (denoted by +// v in [GWC19]) +// \param[out] u: multipoint evaluation challenge - hash of +// transcript template step_four_out_t plonk_verifier::step_four( const plonk_proof &proof, transcript_hasher &hasher) @@ -167,24 +167,24 @@ step_four_out_t plonk_verifier::step_four( return step_four_out; } -/// struct step_five_out_t constructor +// struct step_five_out_t constructor template step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) : zh_zeta(zh_zeta) { } -/// Verifier Step 5: compute zero polynomial evaluation -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at -/// x=zeta i.e. Zh(zeta) +// Verifier Step 5: compute zero polynomial evaluation +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at +// x=zeta i.e. Zh(zeta) template step_five_out_t plonk_verifier::step_five( const step_four_out_t &step_four_out, const srs &srs) @@ -197,25 +197,25 @@ step_five_out_t plonk_verifier::step_five( return step_five_out; } -/// struct step_six_out_t constructor +// struct step_six_out_t constructor template step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) { } -/// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) -/// Note: the paper counts the L-polynomials from 1; we count from 0 -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial -/// L1 at x=zeta i.e. L1(zeta) +// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) +// Note: the paper counts the L-polynomials from 1; we count from 0 +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial +// L1 at x=zeta i.e. L1(zeta) template step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) @@ -226,25 +226,25 @@ step_six_out_t plonk_verifier::step_six( return step_six_out; } -/// struct step_seven_out_t constructor +// struct step_seven_out_t constructor template step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) : PI_zeta(PI_zeta) { } -/// Verifier Step 7: compute public input polynomial evaluation -/// PI(zeta) -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] PI_zeta: public input polynomial PI evaluated at -/// x=zeta i.e. PI(zeta) +// Verifier Step 7: compute public input polynomial evaluation +// PI(zeta) +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] PI_zeta: public input polynomial PI evaluated at +// x=zeta i.e. PI(zeta) template step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) @@ -256,40 +256,40 @@ step_seven_out_t plonk_verifier::step_seven( return step_seven_out; } -/// struct step_eight_out_t constructor +// struct step_eight_out_t constructor template step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) : r_prime_zeta(r_prime_zeta) { } -/// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = -/// r(zeta) - r0, where r0 is a constant term \note follows the Python -/// reference implementation, which slightly deviates from the paper -/// due to the presence of the r_zeta term in the proof (not present -/// in the paper). In particular, the reference code computes and -/// uses r'(zeta) in step 8, while the paper uses r0. In addition, the -/// reference code divides r'(zeta) by the vanishing polynomial at -/// zeta zh_zeta, while the paper does not do that (see also Step 9). -/// -/// INPUT -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from step 4) -/// \param[in] alpha: quotinet challenge -- hash of transcript (from -/// step 4) -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at -/// x=zeta i.e. Zh(zeta) (from step 5) -/// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -/// L1 at x=zeta i.e. L1(zeta) (from step 6) -/// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta -/// i.e. PI(zeta) (from step 7) -/// \param[in] proof: SNARK proof produced by the prover -/// -/// OUTPUT -/// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) -/// = r(zeta) - r0, where r0 is a constant term +// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = +// r(zeta) - r0, where r0 is a constant term \note follows the Python +// reference implementation, which slightly deviates from the paper +// due to the presence of the r_zeta term in the proof (not present +// in the paper). In particular, the reference code computes and +// uses r'(zeta) in step 8, while the paper uses r0. In addition, the +// reference code divides r'(zeta) by the vanishing polynomial at +// zeta zh_zeta, while the paper does not do that (see also Step 9). +// +// INPUT +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from step 4) +// \param[in] alpha: quotinet challenge -- hash of transcript (from +// step 4) +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at +// x=zeta i.e. Zh(zeta) (from step 5) +// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial +// L1 at x=zeta i.e. L1(zeta) (from step 6) +// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta +// i.e. PI(zeta) (from step 7) +// \param[in] proof: SNARK proof produced by the prover +// +// OUTPUT +// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) +// = r(zeta) - r0, where r0 is a constant term template step_eight_out_t plonk_verifier::step_eight( const step_four_out_t &step_four_out, @@ -322,47 +322,47 @@ step_eight_out_t plonk_verifier::step_eight( return step_eight_out; } -/// struct step_nine_out_t constructor +// struct step_nine_out_t constructor template step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) { } -/// Verifier Step 9: compute first part of batched polynomial -/// commitment [D]_1 Note: the reference implemention differs from the -/// paper -- it does not add the following term to D1, but to F1 (Step -/// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -/// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -/// [t_hi]_1) is added to F1 in Step 10 and the multiplication by -/// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in -/// Step 8. -/// -/// INPUT -/// \param[in] beta, gamma: permutation challenges -- hashes of -/// transcript (from step 4) -/// \param[in] alpha: quotinet challenge -- hash of transcript (from -/// step 4) -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] nu: opening challenge -- hash of transcript (denoted by -/// v in [GWC19]) (from step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -/// L1 at x=zeta i.e. L1(zeta) (from step 6) -/// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q -/// evaluated at the secret input (from verifier -/// preprocessed input) -/// \param[in] S_polys_at_secret_g1: permutation polynomials S -/// evaluated at the secret input (from verifier -/// preprocessed input) -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] preprocessed_input: verifier preprocessed input -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] D1: first part of batched polynomial commitment [D]_1 +// Verifier Step 9: compute first part of batched polynomial +// commitment [D]_1 Note: the reference implemention differs from the +// paper -- it does not add the following term to D1, but to F1 (Step +// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n +// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n +// [t_hi]_1) is added to F1 in Step 10 and the multiplication by +// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in +// Step 8. +// +// INPUT +// \param[in] beta, gamma: permutation challenges -- hashes of +// transcript (from step 4) +// \param[in] alpha: quotinet challenge -- hash of transcript (from +// step 4) +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] nu: opening challenge -- hash of transcript (denoted by +// v in [GWC19]) (from step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial +// L1 at x=zeta i.e. L1(zeta) (from step 6) +// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q +// evaluated at the secret input (from verifier +// preprocessed input) +// \param[in] S_polys_at_secret_g1: permutation polynomials S +// evaluated at the secret input (from verifier +// preprocessed input) +// \param[in] proof: SNARK proof produced by the prover +// \param[in] preprocessed_input: verifier preprocessed input +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] D1: first part of batched polynomial commitment [D]_1 template step_nine_out_t plonk_verifier::step_nine( const step_four_out_t &step_four_out, @@ -430,36 +430,36 @@ step_nine_out_t plonk_verifier::step_nine( return step_nine_out; } -/// struct step_ten_out_t constructor +// struct step_ten_out_t constructor template step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) { } -/// Verifier Step 10: compute full batched polynomial commitment [F]_1 -/// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + -/// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the -/// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is -/// addedto [D]_1 in the paper (see commenst to Steps 8,9) -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] nu: opening challenge -- hash of transcript (denoted by -/// v in [GWC19]) (from step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] D1: first part of batched polynomial commitment [D]_1 -/// (from step 9) -/// \param[in] S_polys_at_secret_g1: permutation polynomials S -/// evaluated at the secret input (from verifier -/// preprocessed input) -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] F1: full batched polynomial commitment [F]_1 +// Verifier Step 10: compute full batched polynomial commitment [F]_1 +// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + +// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the +// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is +// addedto [D]_1 in the paper (see commenst to Steps 8,9) +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] nu: opening challenge -- hash of transcript (denoted by +// v in [GWC19]) (from step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] D1: first part of batched polynomial commitment [D]_1 +// (from step 9) +// \param[in] S_polys_at_secret_g1: permutation polynomials S +// evaluated at the secret input (from verifier +// preprocessed input) +// \param[in] proof: SNARK proof produced by the prover +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] F1: full batched polynomial commitment [F]_1 template step_ten_out_t plonk_verifier::step_ten( const step_four_out_t &step_four_out, @@ -504,25 +504,25 @@ step_ten_out_t plonk_verifier::step_ten( return step_ten_out; } -/// struct step_eleven_out_t constructor +// struct step_eleven_out_t constructor template step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) { } -/// Verifier Step 11: compute group-encoded batch evaluation [E]_1 -/// -/// INPUT -/// \param[in] nu: opening challenge -- hash of transcript (denoted by -/// v in [GWC19]) (from step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = -/// r(zeta) - r0, where r0 is a constant term (from step 8) -/// \param[in] proof: SNARK proof produced by the prover -/// -/// OUTPUT -/// \param[out] E1: group-encoded batch evaluation [E]_1 +// Verifier Step 11: compute group-encoded batch evaluation [E]_1 +// +// INPUT +// \param[in] nu: opening challenge -- hash of transcript (denoted by +// v in [GWC19]) (from step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = +// r(zeta) - r0, where r0 is a constant term (from step 8) +// \param[in] proof: SNARK proof produced by the prover +// +// OUTPUT +// \param[out] E1: group-encoded batch evaluation [E]_1 template step_eleven_out_t plonk_verifier::step_eleven( const step_four_out_t &step_four_out, @@ -550,33 +550,33 @@ step_eleven_out_t plonk_verifier::step_eleven( return step_eleven_out; } -/// Verifier Step 12: batch validate all evaluations -/// -/// Checks the following equality -/// -/// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta -/// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 -/// - [F]_1 + [E]_1, [1]_2 ) = Field(1) -/// -/// Denoted as: -/// -/// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 -/// -/// INPUT -/// \param[in] zeta: evaluation challenge -- hash of transcript (from -/// step 4) -/// \param[in] u: multipoint evaluation challenge -- hash of -/// transcript (from step 4) -/// \param[in] F1: full batched polynomial commitment [F]_1 (from step -/// 10) -/// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// -/// OUTPUT -/// \param[out] boolean 1/0 = valid/invalid proof +// Verifier Step 12: batch validate all evaluations +// +// Checks the following equality +// +// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta +// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 +// - [F]_1 + [E]_1, [1]_2 ) = Field(1) +// +// Denoted as: +// +// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 +// +// INPUT +// \param[in] zeta: evaluation challenge -- hash of transcript (from +// step 4) +// \param[in] u: multipoint evaluation challenge -- hash of +// transcript (from step 4) +// \param[in] F1: full batched polynomial commitment [F]_1 (from step +// 10) +// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) +// \param[in] proof: SNARK proof produced by the prover +// \param[in] srs: structured reference string +// \param[in] srs: structured reference string containing also +// circuit-specific information +// +// OUTPUT +// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::step_twelve( const step_four_out_t &step_four_out, @@ -620,26 +620,26 @@ bool plonk_verifier::step_twelve( return b_accept; } -/// \attention The first three steps (as given in [GWC19] -- see -/// below) MUST be executed by the caller: -/// -/// - Verifier Step 1: validate that elements belong to group G1 -/// - Verifier Step 2: validate that elements belong to scalar field -/// Fr -/// - Verifier Step 3: validate that the public input belongs to -/// scalar field Fr -/// . -/// Therefore verification starts from Step 4 of [GWC19] -/// -/// INPUT -/// \param[in] proof: SNARK proof produced by the prover -/// \param[in] srs: structured reference string containing also -/// circuit-specific information -/// \param[in] transcript_hasher: hashes of the communication -/// transcript after prover rounds 1,2,3,4,5. -/// -/// OUTPUT -/// \param[out] boolean 1/0 = valid/invalid proof +// \attention The first three steps (as given in [GWC19] -- see +// below) MUST be executed by the caller: +// +// - Verifier Step 1: validate that elements belong to group G1 +// - Verifier Step 2: validate that elements belong to scalar field +// Fr +// - Verifier Step 3: validate that the public input belongs to +// scalar field Fr +// . +// Therefore verification starts from Step 4 of [GWC19] +// +// INPUT +// \param[in] proof: SNARK proof produced by the prover +// \param[in] srs: structured reference string containing also +// circuit-specific information +// \param[in] transcript_hasher: hashes of the communication +// transcript after prover rounds 1,2,3,4,5. +// +// OUTPUT +// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::verify_proof( const plonk_proof &proof, From afdd4dfe4c17788309955a39df0edd0d3047f814 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 19 Aug 2022 11:54:23 +0100 Subject: [PATCH 074/154] plonk: moved constructor of transcipt_hasher class as first method in the class. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r949761293 --- libsnark/zk_proof_systems/plonk/srs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 2acb93c4c..2d28c6fe5 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -253,6 +253,9 @@ template class transcript_hasher std::array, 6> hash_values; public: + // constructor + transcript_hasher(std::vector &buffer); + void add_element(const libff::Fr &element); void add_element(const libff::G1 &element); void add_element(const libff::G2 &element); @@ -271,9 +274,6 @@ template class transcript_hasher // get buffer size size_t buffer_size(); - - // constructor - transcript_hasher(std::vector &buffer); }; } // namespace libsnark From c6396cf09908f537f3d0bd62777a393e588d80b1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 26 Aug 2022 11:42:23 +0100 Subject: [PATCH 075/154] plonk: added back the computation of the multipoint challenge u in the last round of the prover. we need to compute u even though we are not using it in the prover in order to make sure that the prover and verifier make exactly the same number of calls to transcript_hasher.get_hash(). addresses PR #61 comment https://github.com/clearmatics/libsnark/pull/61#discussion_r952276778 --- libsnark/zk_proof_systems/plonk/prover.tcc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 5d79429e3..5fd95ff21 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -1104,6 +1104,16 @@ plonk_proof plonk_prover::compute_proof( srs, hasher); + // u: multipoint evaluation challenge -- hash of transcript from + // rounds 1,2,3,4,5 + const libff::Fr u = hasher.get_hash(); + // get_hash may update the internal state of the + // transcript_hasher, depending on the implementation, therefore + // the prover and verifier must make exactly the same calls to + // both add_element and get_hash. that's why here we are computing + // u even if we are not using it. + libff::UNUSED(u); + // construct proof plonk_proof proof( round_one_out.W_polys_blinded_at_secret_g1, From d001bd33d809812b6af23753f48b8dc45af84320 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 26 Aug 2022 12:51:59 +0100 Subject: [PATCH 076/154] plonk: in transcript_hasher removed the private buffer variable as an input parameter to the constructor. only the object has access to the buffer now. addresses PR #61 comment https://github.com/clearmatics/libsnark/pull/61#issuecomment-1223692351 --- libsnark/zk_proof_systems/plonk/srs.hpp | 2 +- libsnark/zk_proof_systems/plonk/srs.tcc | 6 +++--- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 12 ++++-------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 2d28c6fe5..d87646a77 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -254,7 +254,7 @@ template class transcript_hasher public: // constructor - transcript_hasher(std::vector &buffer); + transcript_hasher(); void add_element(const libff::Fr &element); void add_element(const libff::G1 &element); diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index d52488575..5f5d33945 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -73,10 +73,10 @@ plonk_keypair::plonk_keypair( } // transcript_hasher constructor -template -transcript_hasher::transcript_hasher(std::vector &buffer) - : buffer(std::move(buffer)) +template transcript_hasher::transcript_hasher() { + // initialize to empty vector + this->buffer.clear(); // test array containing the expected hash values of the communication // transcript i.e. the communication challenges (in this order): beta, // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 18cb18d36..2c82339dd 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -490,8 +490,7 @@ template void test_plonk_prover_rounds() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // Prover Round 0 (initialization) round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); @@ -692,8 +691,7 @@ template void test_plonk_prover() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // initialize prover plonk_prover prover; @@ -970,8 +968,7 @@ template void test_plonk_verifier_steps() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // initialize prover plonk_prover prover; @@ -1075,8 +1072,7 @@ template void test_plonk_verifier() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - std::vector buffer; - transcript_hasher hasher(buffer); + transcript_hasher hasher; // initialize prover plonk_prover prover; From a1f1806ba187008d5f5204e8dabfa5d40f630dc8 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 5 Sep 2022 14:08:04 +0100 Subject: [PATCH 077/154] plonk: moved function signature comments from .tcc to .hpp files only; removed redundant comments indicating class constructors' other minor comments formatting --- libsnark/zk_proof_systems/plonk/circuit.tcc | 1 - libsnark/zk_proof_systems/plonk/prover.hpp | 7 +- libsnark/zk_proof_systems/plonk/prover.tcc | 208 ----------------- libsnark/zk_proof_systems/plonk/srs.hpp | 22 +- libsnark/zk_proof_systems/plonk/srs.tcc | 26 --- libsnark/zk_proof_systems/plonk/utils.tcc | 87 ------- libsnark/zk_proof_systems/plonk/verifier.hpp | 1 - libsnark/zk_proof_systems/plonk/verifier.tcc | 232 ------------------- 8 files changed, 22 insertions(+), 562 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 06a14e3fb..721b70fa8 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -18,7 +18,6 @@ namespace libsnark // TODO: add here function for describing the target circuit through // the circuit_t structure -// stuct constructor template circuit_t::circuit_t( size_t num_gates, diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index f92a59bd1..aaf1f6661 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -97,7 +97,6 @@ template struct round_zero_out_t { /// - neg_one_poly: -1 polynomial (from round 0) polynomial> neg_one_poly; - /// stuct constructor round_zero_out_t( const std::vector> &&zh_poly, const polynomial> &&null_poly, @@ -119,7 +118,6 @@ template struct round_one_out_t { /// [GWC19] std::vector> W_polys_blinded_at_secret_g1; - /// stuct constructor round_one_out_t( const std::vector>> &&W_polys, const std::vector>> &&W_polys_blinded, @@ -136,7 +134,6 @@ template struct round_two_out_t { /// secret libff::G1 z_poly_at_secret_g1; - /// stuct constructor round_two_out_t( polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1); @@ -160,7 +157,6 @@ template struct round_three_out_t { /// i.e. t(zeta) std::vector> t_poly_at_secret_g1; - /// stuct constructor round_three_out_t( std::vector> &&z_poly_xomega, std::vector>> &&t_poly, @@ -195,7 +191,7 @@ template struct round_four_out_t { /// same in order to match the test vectors. TODO can remove t_zeta /// in the future libff::Fr t_zeta; - /// stuct constructor + round_four_out_t( libff::Fr &&a_zeta, libff::Fr &&b_zeta, @@ -221,7 +217,6 @@ template struct round_five_out_t { /// W_{zeta omega}(x) at secert input i.e. [W_{zeta omega}(secret)]_1 libff::G1 W_zeta_omega_at_secret; - /// struct constructor round_five_out_t( libff::Fr &&r_zeta, libff::G1 &&W_zeta_at_secret, diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 5fd95ff21..02d3ed102 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// Prover round 0 output constructor template round_zero_out_t::round_zero_out_t( const std::vector> &&zh_poly, @@ -25,18 +24,6 @@ round_zero_out_t::round_zero_out_t( { } -// Prover Round 0 initialization -// -// Initialization -// -// INPUT -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] zh_poly: vanishing polynomial -// \param[out] null_poly: 0 polynomial -// \param[out] neg_one_poly: -1 polynomial template round_zero_out_t plonk_prover::round_zero(const srs &srs) { @@ -62,7 +49,6 @@ round_zero_out_t plonk_prover::round_zero(const srs &srs) return round_zero_out; } -// Prover round 1 output constructor template round_one_out_t::round_one_out_t( const std::vector>> &&W_polys, @@ -74,28 +60,6 @@ round_one_out_t::round_one_out_t( { } -// Prover Round 1 -// -// INPUT -// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -// \param[in] null_poly: 0 polynomial (from round 0) -// \param[in] neg_one_poly: -1 polynomial (from round 0) -// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -// b1-b6 used in round 1) -// \param[in] witness: witness values -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] W_polys: witness polynomials (Lagrange interpolation -// of the witness values) -// \param[out] W_polys_blinded: blinded witness polynomials -// \param[out] W_polys_blinded_at_secret_g1: the blinded witness -// polynomials evaluated at the secret input denoted -// [a]_1, [b]_1, [c]_1 in [GWC19] -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, @@ -157,7 +121,6 @@ round_one_out_t plonk_prover::round_one( return round_one_out; } -// Prover round 2 output template round_two_out_t::round_two_out_t( polynomial> &&z_poly, libff::G1 &&z_poly_at_secret_g1) @@ -165,23 +128,6 @@ round_two_out_t::round_two_out_t( { } -// Prover Round 2 -// -// INPUT -// \param[in] zh_poly: vanishing polynomial Zh (from round 0) -// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only -// b7,b8,b9 used in round 2) -// \param[in] witness: witness values -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] z_poly: blinded accumulator poly z(x) -// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) -// evaluated at secret -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_two_out_t plonk_prover::round_two( const libff::Fr &beta, @@ -227,7 +173,6 @@ round_two_out_t plonk_prover::round_two( return round_two_out; } -// Prover round 3 output constructor template round_three_out_t::round_three_out_t( std::vector> &&z_poly_xomega, @@ -241,30 +186,6 @@ round_three_out_t::round_three_out_t( { } -// Prover Round 3 -// -// INPUT -// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) -// \param[in] W_polys_blinded: blinded witness polynomials (from -// Round 1) -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from round 2) -// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] t_poly_long: the quotient polynomial t(x) (see Round -// 3, pp28 [GWC19]) -// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -// t_mid(x) x^n + t_hi(x) x^{2n} -// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret -// input zeta i.e. t(zeta) -// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -// by w -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, @@ -496,7 +417,6 @@ round_three_out_t plonk_prover::round_three( return round_three_out; } -// Prover round 4 output constructor template round_four_out_t::round_four_out_t( libff::Fr &&a_zeta, @@ -516,40 +436,6 @@ round_four_out_t::round_four_out_t( { } -// Prover Round 4 -// -// INPUT -// \param[in] W_polys_blinded: blinded witness polynomials (from -// Round 1) -// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted -// by w (from Round 3) -// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, -// pp28 [GWC19]) (from Round 3) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness -// polynomials a(x), b(x), c(x) (denoted by -// W_polys_blinded[] output from Round 1) evaluated at -// x=zeta i.e. a(z), b(z), c(z) -// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials -// S_sigma_1(x), S_sigma_2(x) from the common -// preprocessed input (see [GWC19], Sect. 8.1) evaluated -// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) -// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -// shifted by w (output from Round 3) evaluated at x=zeta -// i.e. z(zeta*w) -// \param[out] t_zeta: the quotient polynomial t(x) output from Round -// 3, see pp28 [GWC19]) evaluated at x=zeta -// i.e. t(z). IMPORTANT! the original Plonk proposal -// [GWC19] does not output this parameter t_zeta. The -// Python reference implementation \[PlonkPy] does, so we -// do the same in order to match the test vectors. TODO -// can remove t_zeta in the future -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, @@ -606,7 +492,6 @@ round_four_out_t plonk_prover::round_four( return round_four_out; } -// Prover round 5 output constructor template round_five_out_t::round_five_out_t( libff::Fr &&r_zeta, @@ -618,53 +503,6 @@ round_five_out_t::round_five_out_t( { } -// Prover Round 5 -// -// INPUT -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from round 2) -// \param[in] alpha: quotinet challenge -- hash of transcript (from -// round 3) -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// round 4) -// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials -// a(x), b(x), c(x) (denoted by W_polys_blinded[] output -// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) -// (from round 4) -// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials -// S_sigma_1(x), S_sigma_2(x) from the common preprocessed -// input (see [GWC19], Sect. 8.1) evaluated at x=zeta -// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) -// \param[in] t_zeta: the quotient polynomial t(x) output from Round -// 3, see pp28 [GWC19]) evaluated at x=zeta -// i.e. t(z). IMPORTANT! the original Plonk proposal -// [GWC19] does not output this parameter t_zeta. The -// Python reference implementation \[PlonkPy] does, so we -// do the same in order to match the test vectors. TODO -// can remove t_zeta in the future (from round 4) -// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) -// shifted by w (output from Round 3) evaluated at x=zeta -// i.e. z(zeta*w) (from round 4) -// \param[in] W_polys_blinded: blinded witness polynomials (from -// round 1) -// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + -// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) -// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] r_zeta: linearisation polynomial r(x) evaluated at -// x=zeta ie. r(zeta) -// \param[out] W_zeta_at_secret: commitment to opening proof -// polynomial W_zeta(x) at secert input -// i.e. [W_zeta(secret)]_1 -// \param[out] W_zeta_omega_at_secret: commitment to opening proof -// polynomial W_{zeta omega}(x) at secert input -// i.e. [W_{zeta omega}(secret)]_1 -// \param[out] transcript_hasher: accumulates the communication -// transcript into a buffer to be hashed after prover -// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). template round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, @@ -963,7 +801,6 @@ round_five_out_t plonk_prover::round_five( return round_five_out; } -// class plonk_proof constructor template plonk_proof::plonk_proof( std::vector> &W_polys_blinded_at_secret_g1, @@ -993,51 +830,6 @@ plonk_proof::plonk_proof( { } -// Prover compute SNARK proof -// -// Pi ([a]_1, [b]_1, [c]_1, [z]_1, -// [t_lo]_1, [t_mi]_1, [t_hi]_1, -// \bar{a}, \bar{b}, \bar{c}, -// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, -// [W_zeta]_1, [W_{zeta omega}]_1 -// r_zeta) -// -// \note in the reference Python implementation \[PlonkPy], r_zeta -// (the evaluation of the linearlization polynomial r(X) at zeta from -// Prover round 5) is added to the pi-SNARK proof. In the paper this -// is omitted, which seems to make the proof shorter by 1 element at -// the epxense of a slightly heavier computation on the verifier's -// side. Here we follow the reference implementation \[PlonkPy] to -// make sure we match the test values. TODO: once all test vectors -// are verified, we may remove r_zeta from the proof to be fully -// compliant with the paper. -// -// Mapping code-to-paper quantities -// -// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 -// (from Round 1) -// \param z_poly_at_secret_g1: [z]_1 (from Round 2) -// \param t_poly_at_secret_g1[lo, mi, hi]: [t_lo]_1, [t_mi]_1, -// [t_hi]_1 (from Round 3) -// \param a_zeta, b_zeta, c_zeta, S_0_zeta, S_1_zeta, -// z_poly_xomega_zeta: \bar{a}, \bar{b}, \bar{c}, -// \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w} (from Round 4) -// \param W_zeta_at_secret, W_zeta_omega_at_secret: [W_zeta]_1, -// [W_{zeta omega}]_1 (from Round 5) -// -// INPUT -// \param[in] srs: structured reference string containing also -// circuit-specific information -// \param[in] witness: all internal values and public input -// corresponding to the given circuit -// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 -// used in prover rounds 1 and 2 (see Sect. 8.3, roumds -// 1,2 [GWC19]) -// \param[in] transcript_hasher: hashes of the communication -// transcript after prover rounds 1,2,3,4,5. -// -// OUTPUT -// \param[out] proof: SNARK proof Pi (see above) template plonk_proof plonk_prover::compute_proof( const srs &srs, diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index d87646a77..5a8786d9a 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -63,6 +63,11 @@ template class usrs std::vector> &&secret_powers_g2); }; +/// Compute a universal srs (usrs). It is composed *only* of encoded +/// powers of the secret value in the group generator. Therefore a usrs +/// is independent of any particular circuit. +/// +/// \note only for debug template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree); @@ -138,6 +143,13 @@ template class srs std::shared_ptr> domain); }; +/// Derive the (plain) SRS from the circuit description and the +/// USRS. The (plain) SRS is a specialization of the USRS for one +/// particular circuit i.e. +/// +/// usrs = +/// srs = (proving_key, verificataion_key) = derive(usrs, +/// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit); @@ -253,11 +265,15 @@ template class transcript_hasher std::array, 6> hash_values; public: - // constructor transcript_hasher(); + // add an Fr element to the transcript buffer for hashing void add_element(const libff::Fr &element); + // add the coordinates of a G1 curve point to the transcript buffer for + // hashing void add_element(const libff::G1 &element); + // add the coordinates of a G2 curve point to the transcript buffer for + // hashing void add_element(const libff::G2 &element); // TODO: use next declaration to implement an actual hash function @@ -267,6 +283,10 @@ template class transcript_hasher // std::array // Blake2sHasher::hash(std::vector const& buffer) + // dummy implementation of get_hash that directly returns the + // expected hard-coded hashes for the purposes of unit testing TODO + // to be replaced by a call to a proper hash function e.g. SHA2, + // BLAKE, etc. libff::Fr get_hash(); // clear the buffer (for now only for testing) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 5f5d33945..4b2bb870c 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// class usrs constructor template usrs::usrs( std::vector> &&secret_powers_g1, @@ -24,7 +23,6 @@ usrs::usrs( { } -// class srs constructor template srs::srs( const size_t &num_gates, @@ -58,13 +56,11 @@ srs::srs( { } -// class plonk_verification_key template plonk_verification_key::plonk_verification_key( std::vector> &&secret_powers_g2) : secret_powers_g2(std::move(secret_powers_g2)){}; -// class plonk_keypair constructor template plonk_keypair::plonk_keypair( plonk_proving_key &&pk, plonk_verification_key &&vk) @@ -72,7 +68,6 @@ plonk_keypair::plonk_keypair( { } -// transcript_hasher constructor template transcript_hasher::transcript_hasher() { // initialize to empty vector @@ -98,19 +93,16 @@ template transcript_hasher::transcript_hasher() }; } -// clear the buffer (for now only for testing) template void transcript_hasher::buffer_clear() { this->buffer.clear(); } -// get buffer size template size_t transcript_hasher::buffer_size() { return this->buffer.size(); } -// add an Fr element to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::Fr &element) { @@ -127,7 +119,6 @@ void transcript_hasher::add_element(const libff::Fr &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -// add the coordinates of a G1 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G1 &element) { @@ -149,7 +140,6 @@ void transcript_hasher::add_element(const libff::G1 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -// add the coordinates of a G2 curve point to the transcript buffer for hashing template void transcript_hasher::add_element(const libff::G2 &element) { @@ -171,10 +161,6 @@ void transcript_hasher::add_element(const libff::G2 &element) std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); } -// dummy implementation of get_hash that directly returns the -// expected hard-coded hashes for the purposes of unit testing TODO -// to be replaced by a call to a proper hash function e.g. SHA2, -// BLAKE, etc. template libff::Fr transcript_hasher::get_hash() { size_t buffer_len = this->buffer.size(); @@ -258,11 +244,6 @@ template libff::Fr transcript_hasher::get_hash() return challenge; } -// Compute a universal srs (usrs). It is composed *only* of encoded -// powers of the secret value in the group generator. Therefore a usrs -// is independent of any particular circuit. -// -// \note only for debug template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) @@ -301,13 +282,6 @@ usrs plonk_usrs_derive_from_secret( return usrs(std::move(secret_powers_g1), std::move(secret_powers_g2)); } -// Derive the (plain) SRS from the circuit description and the -// USRS. The (plain) SRS is a specialization of the USRS for one -// particular circuit i.e. -// -// usrs = -// srs = (proving_key, verificataion_key) = derive(usrs, -// circuit_description) template srs plonk_srs_derive_from_usrs( const usrs &usrs, const circuit_t &circuit) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 2cb62ae60..aecdbe972 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// print the elements of a vector template void print_vector(const std::vector &v) { for (size_t i = 0; i < v.size(); ++i) { @@ -24,23 +23,6 @@ template void print_vector(const std::vector &v) } } -// Compute the Lagrange basis polynomials for interpolating sets of -// n points -// -// INPUT: -// -// \param[in] npoints - number of points -// -// OUTPUT: -// -// \param[out] L[0..n-1][0..n-1]: Lagrange basis over the n roots of -// unity omega_0, ..., omega_{n-1} i.e. L[omega_i] = [a0, -// a1, ..., a_{n-1}] is a vector representing the -// coefficients of the i-th Lagrange polynomial L_i(x) = -// a0+a1x+a2x^2+..+a_{n-1}x^{n-1} s.t. L_i(x=omega_i)=1 -// and L_i(x\neq{omega_i)})=0 -// -// \note uses libfqfft iFFT for the interpolation template void plonk_compute_lagrange_basis( const size_t npoints, std::vector> &L) @@ -60,25 +42,6 @@ void plonk_compute_lagrange_basis( } } -// Interpolate a polynomial from a set of points through inverse FFT -// -// INPUT: -// -// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), -// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], -// ... which we want to interpolate as a polynomial -// -// OUTPUT: -// -// \param[out] f_poly[0..n-1]: the coefficients [a0, a1, ..., a_{n-1}] -// of the polynomial f(x) interpolating the set of points -// f_points. For example if f_poly[0..n-1] = [a0, a1, ..., -// a_{n-1}] then this represents the polynomial f(x) = -// a0+a1x+a1x^2+...+a_{n-1}x^{n-1} such that -// f(omega_i)=f_points[i], where omega_0, ..., omega_{n-1} -// are the n roots of unity. -// -// \note uses libfqfft iFFT for the interpolation template void plonk_interpolate_polynomial_from_points( const std::vector &f_points, polynomial &f_poly) @@ -90,11 +53,6 @@ void plonk_interpolate_polynomial_from_points( domain->iFFT(f_poly); } -// Compute the selector polynomials of the given circuit (also -// called here "q-polynomials"). See Sect. 8.1. The matrix -// gates_matrix_transpose has 5 rows, each corresponding to the -// values L, R, M, O and C for each gate; the number of columns is -// equal to the number of gates. L_basis is the Lagrange basis. template std::vector> plonk_compute_selector_polynomials( const size_t &num_gates, @@ -120,12 +78,6 @@ void plonk_compute_public_input_polynomial( plonk_interpolate_polynomial_from_points(PI_points, PI_poly); }; -// This function computes the sets H, k1H, k2H. H is a -// multiplicative subgroup containing the n-th roots of unity in Fr, -// where \omega is a primitive n-th root of unity and a generator of -// H i.e H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -// consist of 3n distinct elements. \see [GWC19] pp26 (top). template void plonk_compute_roots_of_unity_omega( const size_t num_gates, @@ -162,14 +114,6 @@ void plonk_compute_roots_of_unity_omega( } } -// This function computes the sets H, k1H, k2H, where H is a -// multiplicative subgroup containing the n-th roots of unity in Fr and -// \omega is a primitive n-th root of unity and a generator of -// H ie. H = {1, \omega, ..., \omega^{n-1}}. k1, k2 \in Fr are chosen -// such that H, H k1, H k2 are distinct cosets of H in Fr, and thus -// consist of 3n distinct elements. \see [GWC19] pp26 (top) and Sect. 8. -// -// \note uses plonk_compute_roots_of_unity_omega template void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, @@ -197,10 +141,6 @@ void plonk_compute_cosets_H_k1H_k2H( omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_gen)); } -// permute the multiplicative subgroup H according to the wire -// permutation: (see [GWC19] Sect. 8), \see -// plonk_compute_roots_of_unity_omega, \see -// plonk_roots_of_unity_omega_to_subgroup_H template std::vector plonk_permute_subgroup_H( const std::vector &H_gen, @@ -216,8 +156,6 @@ std::vector plonk_permute_subgroup_H( return H_gen_permute; } -// compute the permutation polynomials S_sigma_1, S_sigma_2, -// S_sigma_2 (see [GWC19], Sect. 8.1) template std::vector> plonk_compute_permutation_polynomials( const std::vector &H_gen_permute, const size_t num_gates) @@ -236,9 +174,6 @@ std::vector> plonk_compute_permutation_polynomials( return S_polys; } -// A wrapper for multi_exp_method_BDLO12_signed() dot-product a -// vector of group elements in G1 (curve points) with a vector of -// scalar elements in Fr template libff::G1 plonk_multi_exp_G1( const std::vector> &curve_points, @@ -258,21 +193,6 @@ libff::G1 plonk_multi_exp_G1( return product; } -// Evaluate a polynomial F at the encoded secret input -// \secret^i*G_1 ie. compute f(\secret)*G1 = [f(\secret)]_i -// -// INPUT -// -// \param[in] secret_powers_g1: \secret^i*G1: -// 0\le{i} libff::G1 plonk_evaluate_poly_at_secret_G1( const std::vector> &secret_powers_g1, @@ -293,8 +213,6 @@ libff::G1 plonk_evaluate_poly_at_secret_G1( return f_poly_at_secret_g1; } -// Evaluate a list of polynomials in the encrypted secret input: see -// plonk_evaluate_poly_at_secret_G1 template void plonk_evaluate_polys_at_secret_G1( const std::vector> &secret_powers_g1, @@ -311,10 +229,6 @@ void plonk_evaluate_polys_at_secret_G1( } } -// Compute the factors in the product of the permutation polynomial -// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], -// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], -// H_gen_permute[i-1]m etc. template FieldT plonk_compute_accumulator_factor( const size_t i, @@ -355,7 +269,6 @@ FieldT plonk_compute_accumulator_factor( return res; } -// - A: accumulator vector template std::vector plonk_compute_accumulator( const size_t num_gates, diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index ea26340ea..cae73f192 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -66,7 +66,6 @@ template struct verifier_preprocessed_input_t { std::vector> Q_polys_at_secret_g1; std::vector> S_polys_at_secret_g1; - /// struct constructor verifier_preprocessed_input_t( std::vector> &&Q_polys_at_secret_g1, std::vector> &&S_polys_at_secret_g1); diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index c7cf4f650..1b23eeca2 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -15,7 +15,6 @@ namespace libsnark { -// struct verifier_preprocessed_input_t constructor template verifier_preprocessed_input_t::verifier_preprocessed_input_t( std::vector> &&Q_polys_at_secret_g1, @@ -25,17 +24,6 @@ verifier_preprocessed_input_t::verifier_preprocessed_input_t( { } -// Verifier precomputation -// -// INPUT -// \param[in] srs: structured reference string -// -// OUTPUT -// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q evaluated -// at -// the secret input -// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at the -// secret input template verifier_preprocessed_input_t plonk_verifier::preprocessed_input( const srs &srs) @@ -55,34 +43,20 @@ verifier_preprocessed_input_t plonk_verifier::preprocessed_input( return preprocessed_input; } -// Verifier Step 1: validate that elements belong to group G1 -// -// \attention This validation MUST be done by the caller. Empty -// function here for consistency with the description in [GWC19] template void plonk_verifier::step_one(const plonk_proof &proof) { } -// Verifier Step 2: validate that elements belong to scalar field Fr -// -// \attention This validation MUST be done by the caller. Empty -// function here for consistency with the description in [GWC19] template void plonk_verifier::step_two(const plonk_proof &proof) { } -// Verifier Step 3: validate that the public input belongs to scalar -// field Fr -// -// \attention This validation MUST be done by the caller. Empty -// function here for consistency with the description in [GWC19] template void plonk_verifier::step_three(const srs &srs) { } -// struct step_four_out_t constructor template step_four_out_t::step_four_out_t( libff::Fr &beta, @@ -95,24 +69,6 @@ step_four_out_t::step_four_out_t( { } -// Verifier Step 4: compute challenges hashed transcript as in prover -// description, from the common inputs, public input, and elements of -// pi-SNARK. TODO: fixed to the test vectors for now -// -// INPUT -// \param[in] proof: SNARK proof produced by the prover -// \param[in] transcript_hasher: hashes of the communication -// transcript after prover rounds 1,2,3,4,5. -// -// OUTPUT -// \param[out] beta, gamma: permutation challenges - hashes of -// transcript -// \param[out] alpha: quotinet challenge - hash of transcript -// \param[out] zeta: evaluation challenge - hash of transcript -// \param[out] nu: opening challenge - hash of transcript (denoted by -// v in [GWC19]) -// \param[out] u: multipoint evaluation challenge - hash of -// transcript template step_four_out_t plonk_verifier::step_four( const plonk_proof &proof, transcript_hasher &hasher) @@ -167,24 +123,12 @@ step_four_out_t plonk_verifier::step_four( return step_four_out; } -// struct step_five_out_t constructor template step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) : zh_zeta(zh_zeta) { } -// Verifier Step 5: compute zero polynomial evaluation -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at -// x=zeta i.e. Zh(zeta) template step_five_out_t plonk_verifier::step_five( const step_four_out_t &step_four_out, const srs &srs) @@ -197,25 +141,12 @@ step_five_out_t plonk_verifier::step_five( return step_five_out; } -// struct step_six_out_t constructor template step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) { } -// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) -// Note: the paper counts the L-polynomials from 1; we count from 0 -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial -// L1 at x=zeta i.e. L1(zeta) template step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) @@ -226,25 +157,12 @@ step_six_out_t plonk_verifier::step_six( return step_six_out; } -// struct step_seven_out_t constructor template step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) : PI_zeta(PI_zeta) { } -// Verifier Step 7: compute public input polynomial evaluation -// PI(zeta) -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] PI_zeta: public input polynomial PI evaluated at -// x=zeta i.e. PI(zeta) template step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) @@ -256,40 +174,12 @@ step_seven_out_t plonk_verifier::step_seven( return step_seven_out; } -// struct step_eight_out_t constructor template step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) : r_prime_zeta(r_prime_zeta) { } -// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = -// r(zeta) - r0, where r0 is a constant term \note follows the Python -// reference implementation, which slightly deviates from the paper -// due to the presence of the r_zeta term in the proof (not present -// in the paper). In particular, the reference code computes and -// uses r'(zeta) in step 8, while the paper uses r0. In addition, the -// reference code divides r'(zeta) by the vanishing polynomial at -// zeta zh_zeta, while the paper does not do that (see also Step 9). -// -// INPUT -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from step 4) -// \param[in] alpha: quotinet challenge -- hash of transcript (from -// step 4) -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at -// x=zeta i.e. Zh(zeta) (from step 5) -// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -// L1 at x=zeta i.e. L1(zeta) (from step 6) -// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta -// i.e. PI(zeta) (from step 7) -// \param[in] proof: SNARK proof produced by the prover -// -// OUTPUT -// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) -// = r(zeta) - r0, where r0 is a constant term template step_eight_out_t plonk_verifier::step_eight( const step_four_out_t &step_four_out, @@ -322,47 +212,11 @@ step_eight_out_t plonk_verifier::step_eight( return step_eight_out; } -// struct step_nine_out_t constructor template step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) { } -// Verifier Step 9: compute first part of batched polynomial -// commitment [D]_1 Note: the reference implemention differs from the -// paper -- it does not add the following term to D1, but to F1 (Step -// 10): -Zh(zeta)([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -// [t_hi]_1). Instead ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n -// [t_hi]_1) is added to F1 in Step 10 and the multiplication by -// Zh(zeta) is accounted for by dividing by Zh(zeta) of r'(zeta) in -// Step 8. -// -// INPUT -// \param[in] beta, gamma: permutation challenges -- hashes of -// transcript (from step 4) -// \param[in] alpha: quotinet challenge -- hash of transcript (from -// step 4) -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] nu: opening challenge -- hash of transcript (denoted by -// v in [GWC19]) (from step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial -// L1 at x=zeta i.e. L1(zeta) (from step 6) -// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q -// evaluated at the secret input (from verifier -// preprocessed input) -// \param[in] S_polys_at_secret_g1: permutation polynomials S -// evaluated at the secret input (from verifier -// preprocessed input) -// \param[in] proof: SNARK proof produced by the prover -// \param[in] preprocessed_input: verifier preprocessed input -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] D1: first part of batched polynomial commitment [D]_1 template step_nine_out_t plonk_verifier::step_nine( const step_four_out_t &step_four_out, @@ -430,36 +284,11 @@ step_nine_out_t plonk_verifier::step_nine( return step_nine_out; } -// struct step_ten_out_t constructor template step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) { } -// Verifier Step 10: compute full batched polynomial commitment [F]_1 -// = [D]_1 + v [a]_1 + v^2 [b]_1 + v^3 [c]_1 + v^4 [s_sigma_1]_1 + -// v^5 [s_sigma_2]_1 Note: to [F]_1 the erefernce code also adds the -// term ([t_lo]_1 + zeta^n [t_mid]_1 + zeta^2n [t_hi]_1) which is -// addedto [D]_1 in the paper (see commenst to Steps 8,9) -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] nu: opening challenge -- hash of transcript (denoted by -// v in [GWC19]) (from step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] D1: first part of batched polynomial commitment [D]_1 -// (from step 9) -// \param[in] S_polys_at_secret_g1: permutation polynomials S -// evaluated at the secret input (from verifier -// preprocessed input) -// \param[in] proof: SNARK proof produced by the prover -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] F1: full batched polynomial commitment [F]_1 template step_ten_out_t plonk_verifier::step_ten( const step_four_out_t &step_four_out, @@ -504,25 +333,11 @@ step_ten_out_t plonk_verifier::step_ten( return step_ten_out; } -// struct step_eleven_out_t constructor template step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) { } -// Verifier Step 11: compute group-encoded batch evaluation [E]_1 -// -// INPUT -// \param[in] nu: opening challenge -- hash of transcript (denoted by -// v in [GWC19]) (from step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = -// r(zeta) - r0, where r0 is a constant term (from step 8) -// \param[in] proof: SNARK proof produced by the prover -// -// OUTPUT -// \param[out] E1: group-encoded batch evaluation [E]_1 template step_eleven_out_t plonk_verifier::step_eleven( const step_four_out_t &step_four_out, @@ -550,33 +365,6 @@ step_eleven_out_t plonk_verifier::step_eleven( return step_eleven_out; } -// Verifier Step 12: batch validate all evaluations -// -// Checks the following equality -// -// e( [W_zeta]_1 + u [W_{zeta srs.omega_roots}]_1, [x]_2 ) * e( -zeta -// [W_zeta ]_1 - u zeta srs.omega_roots [W_{zeta srs.omega_roots}]_1 -// - [F]_1 + [E]_1, [1]_2 ) = Field(1) -// -// Denoted as: -// -// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 -// -// INPUT -// \param[in] zeta: evaluation challenge -- hash of transcript (from -// step 4) -// \param[in] u: multipoint evaluation challenge -- hash of -// transcript (from step 4) -// \param[in] F1: full batched polynomial commitment [F]_1 (from step -// 10) -// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) -// \param[in] proof: SNARK proof produced by the prover -// \param[in] srs: structured reference string -// \param[in] srs: structured reference string containing also -// circuit-specific information -// -// OUTPUT -// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::step_twelve( const step_four_out_t &step_four_out, @@ -620,26 +408,6 @@ bool plonk_verifier::step_twelve( return b_accept; } -// \attention The first three steps (as given in [GWC19] -- see -// below) MUST be executed by the caller: -// -// - Verifier Step 1: validate that elements belong to group G1 -// - Verifier Step 2: validate that elements belong to scalar field -// Fr -// - Verifier Step 3: validate that the public input belongs to -// scalar field Fr -// . -// Therefore verification starts from Step 4 of [GWC19] -// -// INPUT -// \param[in] proof: SNARK proof produced by the prover -// \param[in] srs: structured reference string containing also -// circuit-specific information -// \param[in] transcript_hasher: hashes of the communication -// transcript after prover rounds 1,2,3,4,5. -// -// OUTPUT -// \param[out] boolean 1/0 = valid/invalid proof template bool plonk_verifier::verify_proof( const plonk_proof &proof, From a9d084deffed7daa3afe459b4c3c2d062e509bfb Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 8 Sep 2022 14:32:47 +0100 Subject: [PATCH 078/154] plonk: replaced test values in transcript_hasher with values from the plonk_example class; addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r964175573 . --- libsnark/zk_proof_systems/plonk/srs.tcc | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 4b2bb870c..c2878d679 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -70,26 +70,20 @@ plonk_keypair::plonk_keypair( template transcript_hasher::transcript_hasher() { + plonk_example example; + // initialize to empty vector this->buffer.clear(); // test array containing the expected hash values of the communication // transcript i.e. the communication challenges (in this order): beta, // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 this->hash_values = { - libff::Fr("3710899868510394644410941212967766116886736137326022751" - "891187938298987182388"), // beta - libff::Fr("110379303840831945879077096653321168432672740458288022" - "49545114995763715746939"), // gamma - libff::Fr("379799789992747238930717819864848384921111623418803600" - "22719385400306128734648"), // alpha - libff::Fr("4327197228921839935583364394550235027071910395980312641" - "5018065799136107272465"), // zeta - libff::Fr( - "275158598338697752421507265080923414294782807831923791651" - "55175653098691426347"), // nu - libff::Fr( - "1781751143954696684632449211212056577828855388109883650570" - "6049265393896966778"), // u + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u, }; } From 1b6bb12c030b102ce97eec6a77ae72207ca79d3d Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 8 Sep 2022 14:42:36 +0100 Subject: [PATCH 079/154] plonk: removed redundant debug info and unreachable debug checks. addresses PR# 61. --- libsnark/zk_proof_systems/plonk/srs.tcc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index c2878d679..1ef98c32b 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -158,8 +158,6 @@ void transcript_hasher::add_element(const libff::G2 &element) template libff::Fr transcript_hasher::get_hash() { size_t buffer_len = this->buffer.size(); - // DEBUG - printf("[%s:%d] len %7d\n", __FILE__, __LINE__, (int)buffer_len); // vector of valid lengths (\attention specific to BLS12-381) const std::vector length{288, 320, 416, 704, 896, 1120}; @@ -172,13 +170,6 @@ template libff::Fr transcript_hasher::get_hash() throw std::logic_error( "Error: invalid length of transcript hasher buffer"); } - if (!b_valid_length) { - printf( - "[%s:%d] Error: invalid length of transcript hasher buffer\n", - __FILE__, - __LINE__); - } - assert(b_valid_length); libff::Fr challenge = 0; From 0d85885e5611921c4ef9e87b0ebfef41fe0f972b Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 8 Sep 2022 14:45:00 +0100 Subject: [PATCH 080/154] plonk: set transcript hasher constants alpha, beta, ... to type const. see PR #61 --- libsnark/zk_proof_systems/plonk/verifier.hpp | 24 ++++++++++---------- libsnark/zk_proof_systems/plonk/verifier.tcc | 12 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index cae73f192..c1645627b 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -73,19 +73,19 @@ template struct verifier_preprocessed_input_t { /// Verifier step 4 output template struct step_four_out_t { - libff::Fr beta; - libff::Fr gamma; - libff::Fr alpha; - libff::Fr zeta; - libff::Fr nu; - libff::Fr u; + const libff::Fr beta; + const libff::Fr gamma; + const libff::Fr alpha; + const libff::Fr zeta; + const libff::Fr nu; + const libff::Fr u; step_four_out_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u); + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &alpha, + const libff::Fr &zeta, + const libff::Fr &nu, + const libff::Fr &u); }; /// Verifier step 5 output diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 1b23eeca2..134311749 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -59,12 +59,12 @@ template void plonk_verifier::step_three(const srs &srs) template step_four_out_t::step_four_out_t( - libff::Fr &beta, - libff::Fr &gamma, - libff::Fr &alpha, - libff::Fr &zeta, - libff::Fr &nu, - libff::Fr &u) + const libff::Fr &beta, + const libff::Fr &gamma, + const libff::Fr &alpha, + const libff::Fr &zeta, + const libff::Fr &nu, + const libff::Fr &u) : beta(beta), gamma(gamma), alpha(alpha), zeta(zeta), nu(nu), u(u) { } From c281281a2b726f4a624bd1ea41d5a72a1eabc939 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Sep 2022 12:56:26 +0100 Subject: [PATCH 081/154] plonk: added the transcript_hasher class as an additional specialization parameter to the prover and verifier classes. moved the current transcript_hasher class from files srs.* to its own files under tests, the reason being that its implementation is specific to the bls12-381 curve. set the prover and verifier to be instantiated with this bls12-381-specific implementation of transcript_hasher. this commit addresses steps 2. and 4. from comment https://github.com/clearmatics/libsnark/pull/61#discussion_r966911185 of PR#61. --- libsnark/zk_proof_systems/plonk/prover.hpp | 15 +- libsnark/zk_proof_systems/plonk/prover.tcc | 41 +-- libsnark/zk_proof_systems/plonk/srs.hpp | 101 ------- libsnark/zk_proof_systems/plonk/srs.tcc | 161 ----------- ...ls12_381_test_vector_transcript_hasher.cpp | 182 ++++++++++++ ...ls12_381_test_vector_transcript_hasher.hpp | 120 ++++++++ .../plonk/tests/test_plonk.cpp | 271 ++++++++++-------- libsnark/zk_proof_systems/plonk/verifier.hpp | 6 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 63 ++-- 9 files changed, 517 insertions(+), 443 deletions(-) create mode 100644 libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp create mode 100644 libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index aaf1f6661..ebf15c626 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -224,7 +224,8 @@ template struct round_five_out_t { }; /// Plonk prover. Computes object of class plonk_proof. -template class plonk_prover +template class plonk_prover +// template class plonk_prover { using Field = libff::Fr; @@ -272,7 +273,7 @@ template class plonk_prover const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 2 /// @@ -298,7 +299,7 @@ template class plonk_prover const std::vector> blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 3 /// @@ -332,7 +333,7 @@ template class plonk_prover const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 4 /// @@ -373,7 +374,7 @@ template class plonk_prover const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover Round 5 /// @@ -434,7 +435,7 @@ template class plonk_prover const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); /// Prover compute SNARK proof /// @@ -485,7 +486,7 @@ template class plonk_prover const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hasher &hasher); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 02d3ed102..2c3a17861 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -24,8 +24,9 @@ round_zero_out_t::round_zero_out_t( { } -template -round_zero_out_t plonk_prover::round_zero(const srs &srs) +template +round_zero_out_t plonk_prover::round_zero( + const srs &srs) { using Field = libff::Fr; @@ -60,13 +61,13 @@ round_one_out_t::round_one_out_t( { } -template -round_one_out_t plonk_prover::round_one( +template +round_one_out_t plonk_prover::round_one( const round_zero_out_t &round_zero_out, const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; const size_t nwitness = NUM_HSETS; @@ -128,15 +129,15 @@ round_two_out_t::round_two_out_t( { } -template -round_two_out_t plonk_prover::round_two( +template +round_two_out_t plonk_prover::round_two( const libff::Fr &beta, const libff::Fr &gamma, const round_zero_out_t &round_zero_out, const std::vector> blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; @@ -186,8 +187,8 @@ round_three_out_t::round_three_out_t( { } -template -round_three_out_t plonk_prover::round_three( +template +round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, const libff::Fr &beta, const libff::Fr &gamma, @@ -195,7 +196,7 @@ round_three_out_t plonk_prover::round_three( const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; int num_hgen = NUM_HSETS; @@ -436,13 +437,13 @@ round_four_out_t::round_four_out_t( { } -template -round_four_out_t plonk_prover::round_four( +template +round_four_out_t plonk_prover::round_four( const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; @@ -503,8 +504,8 @@ round_five_out_t::round_five_out_t( { } -template -round_five_out_t plonk_prover::round_five( +template +round_five_out_t plonk_prover::round_five( const libff::Fr &alpha, const libff::Fr &beta, const libff::Fr &gamma, @@ -516,7 +517,7 @@ round_five_out_t plonk_prover::round_five( const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { using Field = libff::Fr; polynomial remainder; @@ -830,12 +831,12 @@ plonk_proof::plonk_proof( { } -template -plonk_proof plonk_prover::compute_proof( +template +plonk_proof plonk_prover::compute_proof( const srs &srs, const std::vector &witness, const std::vector> &blind_scalars, - transcript_hasher &hasher) + transcript_hasher &hasher) { // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 5a8786d9a..7fecac31b 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -195,107 +195,6 @@ template class plonk_keypair plonk_keypair(plonk_keypair &&other) = default; }; -/// transcript hasher interface -/// -/// the hasher works in the Prover as follows: -/// -/// round 1 -/// -/// add_element(buffer, a_eval_exp) -/// add_element(buffer, b_eval_exp) -/// add_element(buffer, c_eval_exp) -/// // buffer = first_output -/// -/// round 2 -/// -/// beta = hash(str(buffer) + "0") -/// gamma = hash(str(buffer) + "1") -/// -/// acc_eval = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs()) -/// -/// add_element(buffer, acc_eval) -/// // buffer = first_output + second_output -/// -/// round 3 -/// -/// alpha = hash(str(buffer)) -/// -/// add_element(buffer, t_lo_eval_exp) -/// add_element(buffer, t_mid_eval_exp) -/// add_element(buffer, t_hi_eval_exp) -/// // buffer = first_output + second_output + third_output -/// -/// round 4 -/// -/// zeta = hash(str(buffer)) -/// -/// add_element(buffer, a_zeta) -/// add_element(buffer, b_zeta) -/// add_element(buffer, c_zeta) -/// add_element(buffer, S_0_zeta) -/// add_element(buffer, S_1_zeta) -/// add_element(buffer, accumulator_shift_zeta) -/// add_element(buffer, t_zeta) -/// add_element(buffer, r_zeta) -/// // buffer = first_output + second_output + third_output + fourth_output -/// -/// round 5 -/// -/// nu = hash(str(buffer)) -/// -/// W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs()) -/// W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, -/// W_zeta_omega.to_coeffs()) -/// -/// add_element(buffer, W_zeta_eval_exp) -/// add_element(buffer, W_zeta_omega_eval_exp) -/// -/// // buffer = first_output + second_output + third_output + fourth_output -/// + fifth_output -/// -/// u = hash(str(buffer)) -/// -template class transcript_hasher -{ -private: - // buffer accumulating data to be hashed - std::vector buffer; - // array containing the hash values of the communication transcript - // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u - std::array, 6> hash_values; - -public: - transcript_hasher(); - - // add an Fr element to the transcript buffer for hashing - void add_element(const libff::Fr &element); - // add the coordinates of a G1 curve point to the transcript buffer for - // hashing - void add_element(const libff::G1 &element); - // add the coordinates of a G2 curve point to the transcript buffer for - // hashing - void add_element(const libff::G2 &element); - - // TODO: use next declaration to implement an actual hash function - // e.g. BLAKE (from Aztec barretenberg implementation): - // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 - // - // std::array - // Blake2sHasher::hash(std::vector const& buffer) - - // dummy implementation of get_hash that directly returns the - // expected hard-coded hashes for the purposes of unit testing TODO - // to be replaced by a call to a proper hash function e.g. SHA2, - // BLAKE, etc. - libff::Fr get_hash(); - - // clear the buffer (for now only for testing) - void buffer_clear(); - - // get buffer size - size_t buffer_size(); -}; - } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/srs.tcc" diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 1ef98c32b..c837e6326 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -68,167 +68,6 @@ plonk_keypair::plonk_keypair( { } -template transcript_hasher::transcript_hasher() -{ - plonk_example example; - - // initialize to empty vector - this->buffer.clear(); - // test array containing the expected hash values of the communication - // transcript i.e. the communication challenges (in this order): beta, - // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 - this->hash_values = { - example.beta, - example.gamma, - example.alpha, - example.zeta, - example.nu, - example.u, - }; -} - -template void transcript_hasher::buffer_clear() -{ - this->buffer.clear(); -} - -template size_t transcript_hasher::buffer_size() -{ - return this->buffer.size(); -} - -template -void transcript_hasher::add_element(const libff::Fr &element) -{ - // convert the Fr element into a string - std::string str; - { - std::ostringstream ss; - libff::field_write( - element, ss); - str = ss.str(); - } - // copy the string as a sequence of uint8_t elements at the end of - // the buffer - std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); -} - -template -void transcript_hasher::add_element(const libff::G1 &element) -{ - libff::G1 element_aff(element); - element_aff.to_affine_coordinates(); - - // convert the affine coordinates of the curve point into a string - std::string str; - { - std::ostringstream ss; - libff::group_write< - libff::encoding_binary, - libff::form_plain, - libff::compression_off>(element_aff, ss); - str = ss.str(); - } - // copy the string as a sequence of uint8_t elements at the end of - // the buffer - std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); -} - -template -void transcript_hasher::add_element(const libff::G2 &element) -{ - libff::G2 element_aff(element); - element_aff.to_affine_coordinates(); - - // convert the affine coordinates of the curve point into a string - std::string str; - { - std::ostringstream ss; - libff::group_write< - libff::encoding_binary, - libff::form_plain, - libff::compression_off>(element_aff, ss); - str = ss.str(); - } - // copy the string as a sequence of uint8_t elements at the end of - // the buffer - std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); -} - -template libff::Fr transcript_hasher::get_hash() -{ - size_t buffer_len = this->buffer.size(); - - // vector of valid lengths (\attention specific to BLS12-381) - const std::vector length{288, 320, 416, 704, 896, 1120}; - - // If we are here, then the hasher buffer has invalid length so throw an - // exception - bool b_valid_length = - (0 != std::count(length.begin(), length.end(), buffer_len)); - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - - libff::Fr challenge = 0; - - // beta - if (buffer_len == length[0]) { - printf( - "[%s:%d] buffer_len %d: beta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[0]; // beta - } - // gamma - if (buffer_len == length[1]) { - printf( - "[%s:%d] buffer_len %d: gamma\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[1]; // gamma - } - // alpha - if (buffer_len == length[2]) { - printf( - "[%s:%d] buffer_len %d: alpha\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[2]; // alpha - } - // zeta - if (buffer_len == length[3]) { - printf( - "[%s:%d] buffer_len %d: zeta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[3]; // zeta - } - // nu - if (buffer_len == length[4]) { - printf( - "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); - challenge = this->hash_values[4]; // nu - } - // u - if (buffer_len == length[5]) { - // reset step to 0 - printf( - "[%s:%d] buffer_len %d: u + clear()\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[5]; // u - } - - return challenge; -} - template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp new file mode 100644 index 000000000..a8836e640 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -0,0 +1,182 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ + +// Implementation of the transcript hasher interface specific to the BLS12-381 +// curve. See bls12_381_test_vector_transcript_hasher.hpp +namespace libsnark +{ + +bls12_381_test_vector_transcript_hasher:: + bls12_381_test_vector_transcript_hasher() +{ + plonk_example example; + + // initialize to empty vector + this->buffer.clear(); + // test array containing the expected hash values of the communication + // transcript i.e. the communication challenges (in this order): beta, + // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 + this->hash_values = { + example.beta, + example.gamma, + example.alpha, + example.zeta, + example.nu, + example.u, + }; +} + +void bls12_381_test_vector_transcript_hasher::buffer_clear() +{ + this->buffer.clear(); +} + +size_t bls12_381_test_vector_transcript_hasher::buffer_size() +{ + return this->buffer.size(); +} + +void bls12_381_test_vector_transcript_hasher::add_element( + const libff::Fr &element) +{ + // convert the Fr element into a string + std::string str; + { + std::ostringstream ss; + libff::field_write( + element, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +void bls12_381_test_vector_transcript_hasher::add_element( + const libff::G1 &element) +{ + libff::G1 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +void bls12_381_test_vector_transcript_hasher::add_element( + const libff::G2 &element) +{ + libff::G2 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +libff::Fr bls12_381_test_vector_transcript_hasher:: + get_hash() +{ + size_t buffer_len = this->buffer.size(); + + // vector of valid lengths (\attention specific to BLS12-381) + const std::vector length{288, 320, 416, 704, 896, 1120}; + + // If we are here, then the hasher buffer has invalid length so throw an + // exception + bool b_valid_length = + (0 != std::count(length.begin(), length.end(), buffer_len)); + if (!b_valid_length) { + throw std::logic_error( + "Error: invalid length of transcript hasher buffer"); + } + + libff::Fr challenge = 0; + + // beta + if (buffer_len == length[0]) { + printf( + "[%s:%d] buffer_len %d: beta\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[0]; // beta + } + // gamma + if (buffer_len == length[1]) { + printf( + "[%s:%d] buffer_len %d: gamma\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[1]; // gamma + } + // alpha + if (buffer_len == length[2]) { + printf( + "[%s:%d] buffer_len %d: alpha\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[2]; // alpha + } + // zeta + if (buffer_len == length[3]) { + printf( + "[%s:%d] buffer_len %d: zeta\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[3]; // zeta + } + // nu + if (buffer_len == length[4]) { + printf( + "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); + challenge = this->hash_values[4]; // nu + } + // u + if (buffer_len == length[5]) { + // reset step to 0 + printf( + "[%s:%d] buffer_len %d: u + clear()\n", + __FILE__, + __LINE__, + (int)buffer_len); + challenge = this->hash_values[5]; // u + } + + return challenge; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp new file mode 100644 index 000000000..fd9be7093 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -0,0 +1,120 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ + +namespace libsnark +{ + +/// transcript hasher interface specific to the BLS12-381 curve +/// +/// the hasher works in the Prover as follows: +/// +/// round 1 +/// +/// add_element(buffer, a_eval_exp) +/// add_element(buffer, b_eval_exp) +/// add_element(buffer, c_eval_exp) +/// // buffer = first_output +/// +/// round 2 +/// +/// beta = hash(str(buffer) + "0") +/// gamma = hash(str(buffer) + "1") +/// +/// acc_eval = evaluate_in_exponent(CRS, accumulator_poly.to_coeffs()) +/// +/// add_element(buffer, acc_eval) +/// // buffer = first_output + second_output +/// +/// round 3 +/// +/// alpha = hash(str(buffer)) +/// +/// add_element(buffer, t_lo_eval_exp) +/// add_element(buffer, t_mid_eval_exp) +/// add_element(buffer, t_hi_eval_exp) +/// // buffer = first_output + second_output + third_output +/// +/// round 4 +/// +/// zeta = hash(str(buffer)) +/// +/// add_element(buffer, a_zeta) +/// add_element(buffer, b_zeta) +/// add_element(buffer, c_zeta) +/// add_element(buffer, S_0_zeta) +/// add_element(buffer, S_1_zeta) +/// add_element(buffer, accumulator_shift_zeta) +/// add_element(buffer, t_zeta) +/// add_element(buffer, r_zeta) +/// // buffer = first_output + second_output + third_output + fourth_output +/// +/// round 5 +/// +/// nu = hash(str(buffer)) +/// +/// W_zeta_eval_exp = evaluate_in_exponent(CRS, W_zeta.to_coeffs()) +/// W_zeta_omega_eval_exp = evaluate_in_exponent(CRS, +/// W_zeta_omega.to_coeffs()) +/// +/// add_element(buffer, W_zeta_eval_exp) +/// add_element(buffer, W_zeta_omega_eval_exp) +/// +/// // buffer = first_output + second_output + third_output + fourth_output +/// + fifth_output +/// +/// u = hash(str(buffer)) +/// +class bls12_381_test_vector_transcript_hasher +{ +private: + // buffer accumulating data to be hashed + std::vector buffer; + // array containing the hash values of the communication transcript + // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u + std::array, 6> hash_values; + +public: + bls12_381_test_vector_transcript_hasher(); + + // add an Fr element to the transcript buffer for hashing + void add_element(const libff::Fr &element); + // add the coordinates of a G1 curve point to the transcript buffer for + // hashing + void add_element(const libff::G1 &element); + // add the coordinates of a G2 curve point to the transcript buffer for + // hashing + void add_element(const libff::G2 &element); + + // TODO: use next declaration to implement an actual hash function + // e.g. BLAKE (from Aztec barretenberg implementation): + // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 + // + // std::array + // Blake2sHasher::hash(std::vector const& buffer) + + // dummy implementation of get_hash that directly returns the + // expected hard-coded hashes for the purposes of unit testing TODO + // to be replaced by a call to a proper hash function e.g. SHA2, + // BLAKE, etc. + libff::Fr get_hash(); + + // clear the buffer (for now only for testing) + void buffer_clear(); + + // get buffer size + size_t buffer_size(); +}; + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 2c82339dd..55960b4e3 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -8,6 +8,7 @@ #include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include "libsnark/zk_proof_systems/plonk/prover.hpp" +#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp" #include "libsnark/zk_proof_systems/plonk/verifier.hpp" #include @@ -33,14 +34,14 @@ namespace libsnark // \bar{S_sigma1}, \bar{S_sigma2}, \bar{z_w}, // [W_zeta]_1, [W_{zeta omega_roots}]_1 // r_zeta (*)) -template +template void test_verify_invalid_proof( const plonk_proof &valid_proof, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { // initialize verifier - plonk_verifier verifier; + plonk_verifier verifier; bool b_accept = true; // random element on the curve initialized to zero @@ -274,17 +275,18 @@ void test_plonk_compute_accumulator( ASSERT_EQ(A_poly, example.A_poly); } -template +template void test_plonk_prover_round_one( const plonk_example &example, const round_zero_out_t &round_zero_out, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { std::vector> blind_scalars = example.prover_blind_scalars; - round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_one_out_t round_one_out = + plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); libff::print_vector(round_one_out.W_polys[i]); @@ -311,7 +313,7 @@ void test_plonk_prover_round_one( } } -template +template void test_plonk_prover_round_two( const plonk_example &example, const libff::Fr &beta, @@ -320,10 +322,11 @@ void test_plonk_prover_round_two( const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + round_two_out_t round_two_out = + plonk_prover::round_two( + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); printf("[%s:%d] z_poly\n", __FILE__, __LINE__); libff::print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); @@ -336,7 +339,7 @@ void test_plonk_prover_round_two( ASSERT_EQ(z_poly_at_secret_g1_aff.Y, example.z_poly_at_secret_g1[1]); } -template +template void test_plonk_prover_round_three( const plonk_example &example, const libff::Fr &alpha, @@ -346,17 +349,18 @@ void test_plonk_prover_round_three( const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_three_out_t round_three_out = plonk_prover::round_three( - alpha, - beta, - gamma, - round_zero_out, - round_one_out, - round_two_out, - srs, - hasher); + round_three_out_t round_three_out = + plonk_prover::round_three( + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); printf("[%s:%d] t_poly_long\n", __FILE__, __LINE__); libff::print_vector(round_three_out.t_poly_long); @@ -377,17 +381,18 @@ void test_plonk_prover_round_three( } } -template +template void test_plonk_prover_round_four( const plonk_example &example, const libff::Fr &zeta, const round_one_out_t &round_one_out, const round_three_out_t &round_three_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs, hasher); + round_four_out_t round_four_out = + plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs, hasher); // Prover Round 4 output check against test vectors printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); printf("a_zeta "); @@ -413,7 +418,7 @@ void test_plonk_prover_round_four( ASSERT_EQ(round_four_out.z_poly_xomega_zeta, example.z_poly_xomega_zeta); } -template +template void test_plonk_prover_round_five( const plonk_example &example, const libff::Fr &alpha, @@ -427,21 +432,22 @@ void test_plonk_prover_round_five( const round_three_out_t &round_three_out, const round_four_out_t &round_four_out, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { - round_five_out_t round_five_out = plonk_prover::round_five( - alpha, - beta, - gamma, - zeta, - nu, - round_zero_out, - round_one_out, - round_two_out, - round_three_out, - round_four_out, - srs, - hasher); + round_five_out_t round_five_out = + plonk_prover::round_five( + alpha, + beta, + gamma, + zeta, + nu, + round_zero_out, + round_one_out, + round_two_out, + round_three_out, + round_four_out, + srs, + hasher); printf("[%s:%d] Outputs from Prover round 5\n", __FILE__, __LINE__); printf("r_zeta "); @@ -464,7 +470,7 @@ void test_plonk_prover_round_five( /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_prover_rounds() +template void test_plonk_prover_rounds() { using Field = libff::Fr; @@ -490,22 +496,24 @@ template void test_plonk_prover_rounds() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // Prover Round 0 (initialization) - round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); + round_zero_out_t round_zero_out = + plonk_prover::round_zero(srs); // --- Unit test Prover Round 1 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); - test_plonk_prover_round_one( + test_plonk_prover_round_one( example, round_zero_out, witness, srs, hasher); // --- Unit test Prover Round 2 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); - round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_one_out_t round_one_out = + plonk_prover::round_one( + round_zero_out, blind_scalars, witness, srs, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -515,7 +523,7 @@ template void test_plonk_prover_rounds() const libff::Fr beta = hasher.get_hash(); hasher.add_element(libff::Fr::one()); const libff::Fr gamma = hasher.get_hash(); - test_plonk_prover_round_two( + test_plonk_prover_round_two( example, beta, gamma, @@ -531,8 +539,9 @@ template void test_plonk_prover_rounds() // --- Unit test Prover Round 3 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); - round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + round_two_out_t round_two_out = + plonk_prover::round_two( + beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -543,7 +552,7 @@ template void test_plonk_prover_rounds() // add outputs from Round 2 to the hash buffer hasher.add_element(round_two_out.z_poly_at_secret_g1); const libff::Fr alpha = hasher.get_hash(); - test_plonk_prover_round_three( + test_plonk_prover_round_three( example, alpha, beta, @@ -556,15 +565,16 @@ template void test_plonk_prover_rounds() // --- Unit test Prover Round 4 --- printf("[%s:%d] Prover Round 4...\n", __FILE__, __LINE__); - round_three_out_t round_three_out = plonk_prover::round_three( - alpha, - beta, - gamma, - round_zero_out, - round_one_out, - round_two_out, - srs, - hasher); + round_three_out_t round_three_out = + plonk_prover::round_three( + alpha, + beta, + gamma, + round_zero_out, + round_one_out, + round_two_out, + srs, + hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -579,13 +589,14 @@ template void test_plonk_prover_rounds() hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); const libff::Fr zeta = hasher.get_hash(); - test_plonk_prover_round_four( + test_plonk_prover_round_four( example, zeta, round_one_out, round_three_out, srs, hasher); // --- Unit test Prover Round 5 --- printf("[%s:%d] Unit test Prover Round 5...\n", __FILE__, __LINE__); - round_four_out_t round_four_out = plonk_prover::round_four( - zeta, round_one_out, round_three_out, srs, hasher); + round_four_out_t round_four_out = + plonk_prover::round_four( + zeta, round_one_out, round_three_out, srs, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -607,7 +618,7 @@ template void test_plonk_prover_rounds() hasher.add_element(round_four_out.S_1_zeta); hasher.add_element(round_four_out.z_poly_xomega_zeta); const libff::Fr nu = hasher.get_hash(); - test_plonk_prover_round_five( + test_plonk_prover_round_five( example, alpha, beta, @@ -666,7 +677,7 @@ template void test_plonk_srs() /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_prover() +template void test_plonk_prover() { using Field = libff::Fr; @@ -691,10 +702,10 @@ template void test_plonk_prover() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // initialize prover - plonk_prover prover; + plonk_prover prover; // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); @@ -746,13 +757,13 @@ template void test_plonk_prover() /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template +template void test_plonk_verifier_preprocessed_input( const plonk_example &example, const srs &srs) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = - plonk_verifier::preprocessed_input(srs); + plonk_verifier::preprocessed_input(srs); for (int i = 0; i < (int)srs.Q_polys.size(); ++i) { printf("srs.Q_polys_at_secret_G1[%d] \n", i); @@ -774,46 +785,46 @@ void test_plonk_verifier_preprocessed_input( } } -template +template void test_plonk_verifier_step_five( const plonk_example &example, const step_four_out_t &step_four_out, const srs &srs) { const step_five_out_t step_five_out = - plonk_verifier::step_five(step_four_out, srs); + plonk_verifier::step_five(step_four_out, srs); printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); step_five_out.zh_zeta.print(); ASSERT_EQ(step_five_out.zh_zeta, example.zh_zeta); } -template +template void test_plonk_verifier_step_six( const plonk_example &example, const step_four_out_t &step_four_out, const srs &srs) { const step_six_out_t step_six_out = - plonk_verifier::step_six(step_four_out, srs); + plonk_verifier::step_six(step_four_out, srs); printf("L_0_zeta "); step_six_out.L_0_zeta.print(); ASSERT_EQ(step_six_out.L_0_zeta, example.L_0_zeta); } -template +template void test_plonk_verifier_step_seven( const plonk_example &example, const step_four_out_t &step_four_out, const srs &srs) { const step_seven_out_t step_seven_out = - plonk_verifier::step_seven(step_four_out, srs); + plonk_verifier::step_seven(step_four_out, srs); printf("PI_zeta "); step_seven_out.PI_zeta.print(); ASSERT_EQ(step_seven_out.PI_zeta, example.PI_zeta); } -template +template void test_plonk_verifier_step_eight( const plonk_example &example, const step_four_out_t &step_four_out, @@ -823,12 +834,12 @@ void test_plonk_verifier_step_eight( const plonk_proof &proof) { const step_eight_out_t step_eight_out = - plonk_verifier::step_eight( + plonk_verifier::step_eight( step_four_out, step_five_out, step_six_out, step_seven_out, proof); ASSERT_EQ(step_eight_out.r_prime_zeta, example.r_prime_zeta); } -template +template void test_plonk_verifier_step_nine( const plonk_example &example, const step_four_out_t &step_four_out, @@ -837,8 +848,9 @@ void test_plonk_verifier_step_nine( const verifier_preprocessed_input_t &preprocessed_input, const srs &srs) { - step_nine_out_t step_nine_out = plonk_verifier::step_nine( - step_four_out, step_six_out, proof, preprocessed_input, srs); + step_nine_out_t step_nine_out = + plonk_verifier::step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); step_nine_out.D1.print(); libff::G1 D1_aff(step_nine_out.D1); D1_aff.to_affine_coordinates(); @@ -846,7 +858,7 @@ void test_plonk_verifier_step_nine( ASSERT_EQ(D1_aff.Y, example.D1[1]); } -template +template void test_plonk_verifier_step_ten( const plonk_example &example, const step_four_out_t &step_four_out, @@ -855,8 +867,9 @@ void test_plonk_verifier_step_ten( const verifier_preprocessed_input_t &preprocessed_input, const srs &srs) { - step_ten_out_t step_ten_out = plonk_verifier::step_ten( - step_four_out, step_nine_out, proof, preprocessed_input, srs); + step_ten_out_t step_ten_out = + plonk_verifier::step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); printf("[%s:%d] F1\n", __FILE__, __LINE__); step_ten_out.F1.print(); libff::G1 F1_aff(step_ten_out.F1); @@ -865,7 +878,7 @@ void test_plonk_verifier_step_ten( ASSERT_EQ(F1_aff.Y, example.F1[1]); } -template +template void test_plonk_verifier_step_eleven( const plonk_example &example, const step_four_out_t &step_four_out, @@ -873,7 +886,8 @@ void test_plonk_verifier_step_eleven( const plonk_proof &proof) { const step_eleven_out_t step_eleven_out = - plonk_verifier::step_eleven(step_four_out, step_eight_out, proof); + plonk_verifier::step_eleven( + step_four_out, step_eight_out, proof); printf("[%s:%d] E1\n", __FILE__, __LINE__); step_eleven_out.E1.print(); libff::G1 E1_aff(step_eleven_out.E1); @@ -943,7 +957,7 @@ void test_plonk_verifier_pairing( /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_verifier_steps() +template void test_plonk_verifier_steps() { using Field = libff::Fr; @@ -968,42 +982,46 @@ template void test_plonk_verifier_steps() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // initialize prover - plonk_prover prover; + plonk_prover prover; // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // clear the hasher buffer in order to re-use the same transcript_hasher - // object for the verifier + // clear the hasher buffer in order to re-use the same + // transcript_hasher object for the verifier hasher.buffer_clear(); // Unit test verifier preprocessed input - test_plonk_verifier_preprocessed_input(example, srs); + test_plonk_verifier_preprocessed_input( + example, srs); // compute step 4 const step_four_out_t step_four_out = - plonk_verifier::step_four(proof, hasher); + plonk_verifier::step_four(proof, hasher); // unit test verifier step 5 - test_plonk_verifier_step_five(example, step_four_out, srs); + test_plonk_verifier_step_five( + example, step_four_out, srs); // unit test verifier step 6 - test_plonk_verifier_step_six(example, step_four_out, srs); + test_plonk_verifier_step_six( + example, step_four_out, srs); // unit test verifier step 7 - test_plonk_verifier_step_seven(example, step_four_out, srs); + test_plonk_verifier_step_seven( + example, step_four_out, srs); // unit test verifier step 8 const step_five_out_t step_five_out = - plonk_verifier::step_five(step_four_out, srs); + plonk_verifier::step_five(step_four_out, srs); const step_six_out_t step_six_out = - plonk_verifier::step_six(step_four_out, srs); + plonk_verifier::step_six(step_four_out, srs); const step_seven_out_t step_seven_out = - plonk_verifier::step_seven(step_four_out, srs); - test_plonk_verifier_step_eight( + plonk_verifier::step_seven(step_four_out, srs); + test_plonk_verifier_step_eight( example, step_four_out, step_five_out, @@ -1013,28 +1031,31 @@ template void test_plonk_verifier_steps() // unit test verifier step 9 const verifier_preprocessed_input_t preprocessed_input = - plonk_verifier::preprocessed_input(srs); - test_plonk_verifier_step_nine( + plonk_verifier::preprocessed_input(srs); + test_plonk_verifier_step_nine( example, step_four_out, step_six_out, proof, preprocessed_input, srs); // unit test verifier step 10 - step_nine_out_t step_nine_out = plonk_verifier::step_nine( - step_four_out, step_six_out, proof, preprocessed_input, srs); - test_plonk_verifier_step_ten( + step_nine_out_t step_nine_out = + plonk_verifier::step_nine( + step_four_out, step_six_out, proof, preprocessed_input, srs); + test_plonk_verifier_step_ten( example, step_four_out, step_nine_out, proof, preprocessed_input, srs); // unit test verifier step 11 const step_eight_out_t step_eight_out = - plonk_verifier::step_eight( + plonk_verifier::step_eight( step_four_out, step_five_out, step_six_out, step_seven_out, proof); - test_plonk_verifier_step_eleven( + test_plonk_verifier_step_eleven( example, step_four_out, step_eight_out, proof); // unit test verifier pairing (step 12) - step_ten_out_t step_ten_out = plonk_verifier::step_ten( - step_four_out, step_nine_out, proof, preprocessed_input, srs); + step_ten_out_t step_ten_out = + plonk_verifier::step_ten( + step_four_out, step_nine_out, proof, preprocessed_input, srs); const step_eleven_out_t step_eleven_out = - plonk_verifier::step_eleven(step_four_out, step_eight_out, proof); + plonk_verifier::step_eleven( + step_four_out, step_eight_out, proof); test_plonk_verifier_pairing( example, step_four_out.zeta, @@ -1047,7 +1068,7 @@ template void test_plonk_verifier_steps() /// \attention the example class is defined specifically for the BLS12-381 /// curve, so make sure we are using this curve -template void test_plonk_verifier() +template void test_plonk_verifier() { using Field = libff::Fr; @@ -1072,26 +1093,26 @@ template void test_plonk_verifier() srs srs = plonk_srs_derive_from_usrs(usrs, circuit); // initialize hasher - transcript_hasher hasher; + transcript_hasher hasher; // initialize prover - plonk_prover prover; + plonk_prover prover; // compute proof plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // clear the hasher buffer in order to re-use the same transcript_hasher - // object for the verifier + // clear the hasher buffer in order to re-use the same + // transcript_hasher object for the verifier hasher.buffer_clear(); // initialize verifier - plonk_verifier verifier; + plonk_verifier verifier; // verify proof bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); ASSERT_TRUE(b_valid_proof); - // clear the hasher buffer in order to re-use the same transcript_hasher - // object + // clear the hasher buffer in order to re-use the same + // transcript_hasher object hasher.buffer_clear(); // assert that proof verification fails when the proof is // manipulated @@ -1101,10 +1122,18 @@ template void test_plonk_verifier() TEST(TestPlonk, BLS12_381) { test_plonk_srs(); - test_plonk_prover_rounds(); - test_plonk_prover(); - test_plonk_verifier_steps(); - test_plonk_verifier(); + test_plonk_prover_rounds< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); + test_plonk_prover< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); + test_plonk_verifier_steps< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); + test_plonk_verifier< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index c1645627b..bb02b9218 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -141,7 +141,7 @@ template struct step_eleven_out_t { }; /// Plonk verifier. Verifies object of class plonk_proof. -template class plonk_verifier +template class plonk_verifier { using Field = libff::Fr; @@ -199,7 +199,7 @@ template class plonk_verifier /// \param[out] u: multipoint evaluation challenge - hash of /// transcript static step_four_out_t step_four( - const plonk_proof &proof, transcript_hasher &hasher); + const plonk_proof &proof, transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// @@ -426,7 +426,7 @@ template class plonk_verifier bool verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hasher &hasher); + transcript_hasher &hasher); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 134311749..dea93dca2 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -24,9 +24,9 @@ verifier_preprocessed_input_t::verifier_preprocessed_input_t( { } -template -verifier_preprocessed_input_t plonk_verifier::preprocessed_input( - const srs &srs) +template +verifier_preprocessed_input_t plonk_verifier:: + preprocessed_input(const srs &srs) { std::vector> Q_polys_at_secret_g1; Q_polys_at_secret_g1.resize(srs.Q_polys.size()); @@ -43,17 +43,20 @@ verifier_preprocessed_input_t plonk_verifier::preprocessed_input( return preprocessed_input; } -template -void plonk_verifier::step_one(const plonk_proof &proof) +template +void plonk_verifier::step_one( + const plonk_proof &proof) { } -template -void plonk_verifier::step_two(const plonk_proof &proof) +template +void plonk_verifier::step_two( + const plonk_proof &proof) { } -template void plonk_verifier::step_three(const srs &srs) +template +void plonk_verifier::step_three(const srs &srs) { } @@ -69,9 +72,9 @@ step_four_out_t::step_four_out_t( { } -template -step_four_out_t plonk_verifier::step_four( - const plonk_proof &proof, transcript_hasher &hasher) +template +step_four_out_t plonk_verifier::step_four( + const plonk_proof &proof, transcript_hasher &hasher) { // add outputs from Round 1 to the hash buffer hasher.add_element(proof.W_polys_blinded_at_secret_g1[a]); @@ -129,8 +132,8 @@ step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) { } -template -step_five_out_t plonk_verifier::step_five( +template +step_five_out_t plonk_verifier::step_five( const step_four_out_t &step_four_out, const srs &srs) { libff::Fr zh_zeta; @@ -147,8 +150,8 @@ step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) { } -template -step_six_out_t plonk_verifier::step_six( +template +step_six_out_t plonk_verifier::step_six( const step_four_out_t &step_four_out, const srs &srs) { libff::Fr L_0_zeta = libfqfft::evaluate_polynomial( @@ -163,8 +166,8 @@ step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) { } -template -step_seven_out_t plonk_verifier::step_seven( +template +step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) { libff::Fr PI_zeta; @@ -180,8 +183,8 @@ step_eight_out_t::step_eight_out_t(libff::Fr &&r_prime_zeta) { } -template -step_eight_out_t plonk_verifier::step_eight( +template +step_eight_out_t plonk_verifier::step_eight( const step_four_out_t &step_four_out, const step_five_out_t &step_five_out, const step_six_out_t &step_six_out, @@ -217,8 +220,8 @@ step_nine_out_t::step_nine_out_t(libff::G1 &&D1) : D1(D1) { } -template -step_nine_out_t plonk_verifier::step_nine( +template +step_nine_out_t plonk_verifier::step_nine( const step_four_out_t &step_four_out, const step_six_out_t &step_six_out, const plonk_proof &proof, @@ -289,8 +292,8 @@ step_ten_out_t::step_ten_out_t(libff::G1 &&F1) : F1(F1) { } -template -step_ten_out_t plonk_verifier::step_ten( +template +step_ten_out_t plonk_verifier::step_ten( const step_four_out_t &step_four_out, const step_nine_out_t &step_nine_out, const plonk_proof &proof, @@ -338,8 +341,8 @@ step_eleven_out_t::step_eleven_out_t(libff::G1 &&E1) : E1(E1) { } -template -step_eleven_out_t plonk_verifier::step_eleven( +template +step_eleven_out_t plonk_verifier::step_eleven( const step_four_out_t &step_four_out, const step_eight_out_t &step_eight_out, const plonk_proof &proof) @@ -365,8 +368,8 @@ step_eleven_out_t plonk_verifier::step_eleven( return step_eleven_out; } -template -bool plonk_verifier::step_twelve( +template +bool plonk_verifier::step_twelve( const step_four_out_t &step_four_out, const step_ten_out_t &step_ten_out, const step_eleven_out_t &step_eleven_out, @@ -408,11 +411,11 @@ bool plonk_verifier::step_twelve( return b_accept; } -template -bool plonk_verifier::verify_proof( +template +bool plonk_verifier::verify_proof( const plonk_proof &proof, const srs &srs, - transcript_hasher &hasher) + transcript_hasher &hasher) { // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = From f92f12d845fcaa5eeca6cc902c64de133849a7c3 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Sep 2022 13:02:32 +0100 Subject: [PATCH 082/154] plonk: created a new transcript_hasher.hpp file with just a comment that describes the interface of a common transcript hasher. addresses step 1. from comment https://github.com/clearmatics/libsnark/pull/61#discussion_r966911185 of PR#61. --- .../transcript_hasher/transcript_hasher.hpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 libsnark/transcript_hasher/transcript_hasher.hpp diff --git a/libsnark/transcript_hasher/transcript_hasher.hpp b/libsnark/transcript_hasher/transcript_hasher.hpp new file mode 100644 index 000000000..1409c73cf --- /dev/null +++ b/libsnark/transcript_hasher/transcript_hasher.hpp @@ -0,0 +1,32 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_TRANSCRIPT_HASHER_TRANSCRIPT_HASHER_HPP_ +#define LIBSNARK_TRANSCRIPT_HASHER_TRANSCRIPT_HASHER_HPP_ + +// // interface for a common transcript_hasher class used to implement +// // functionality for hashing the communication transcript in ZK proof +// // systems under ./zk_proof_systems +// template class transcript_hasher +// { +// public: +// transcript_hasher(); +// +// // add an Fr element to the transcript buffer for hashing +// void add_element(const libff::Fr &element); +// // add the coordinates of a G1 curve point to the transcript buffer for +// // hashing +// void add_element(const libff::G1 &element); +// // add the coordinates of a G2 curve point to the transcript buffer for +// // hashing +// void add_element(const libff::G2 &element); +// // return the hash value of the communication transcript +// libff::Fr get_hash(); +// }; + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_HPP_ From 825d65c29e414135eb5c494b3c19bf45c34b598c Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Sep 2022 14:30:03 +0100 Subject: [PATCH 083/154] plonk: replaced the checks over all valid buffer lengths in the transcript hasher with a while loop directly finding the correct length; addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r964183723 . --- ...ls12_381_test_vector_transcript_hasher.cpp | 77 +++++++------------ 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index a8836e640..043d1bd05 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -121,59 +121,34 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: libff::Fr challenge = 0; - // beta - if (buffer_len == length[0]) { - printf( - "[%s:%d] buffer_len %d: beta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[0]; // beta - } - // gamma - if (buffer_len == length[1]) { - printf( - "[%s:%d] buffer_len %d: gamma\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[1]; // gamma - } - // alpha - if (buffer_len == length[2]) { - printf( - "[%s:%d] buffer_len %d: alpha\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[2]; // alpha - } - // zeta - if (buffer_len == length[3]) { - printf( - "[%s:%d] buffer_len %d: zeta\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[3]; // zeta - } - // nu - if (buffer_len == length[4]) { - printf( - "[%s:%d] buffer_len %d: nu\n", __FILE__, __LINE__, (int)buffer_len); - challenge = this->hash_values[4]; // nu - } - // u - if (buffer_len == length[5]) { - // reset step to 0 - printf( - "[%s:%d] buffer_len %d: u + clear()\n", - __FILE__, - __LINE__, - (int)buffer_len); - challenge = this->hash_values[5]; // u + // map the index length=0,1...5 to the challenge string=beta, + // gamma, ...; used to print explicitly the challenge string for debug + std::map challenge_str; + challenge_str[0] = "beta"; + challenge_str[1] = "gamma"; + challenge_str[2] = "alpha"; + challenge_str[3] = "zeta"; + challenge_str[4] = "nu"; + challenge_str[5] = "u"; + + // find the mathcing index + size_t i = 0; + while (buffer_len != length[i]) { + ++i; + if (i >= length.size()) { + throw std::logic_error( + "Error: invalid index of transcript hasher buffer"); + } } + printf( + "[%s:%d] buffer_len %d: %s\n", + __FILE__, + __LINE__, + (int)buffer_len, + challenge_str[i].c_str()); + challenge = this->hash_values[i]; // beta + return challenge; } From 23a6bb0c7ad36e0bc31d64da9d328007b5490049 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 08:49:02 +0100 Subject: [PATCH 084/154] plonk: replaced challenge_str map with a vector. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968600750 . --- .../tests/bls12_381_test_vector_transcript_hasher.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 043d1bd05..8e3deae8b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -123,13 +123,8 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: // map the index length=0,1...5 to the challenge string=beta, // gamma, ...; used to print explicitly the challenge string for debug - std::map challenge_str; - challenge_str[0] = "beta"; - challenge_str[1] = "gamma"; - challenge_str[2] = "alpha"; - challenge_str[3] = "zeta"; - challenge_str[4] = "nu"; - challenge_str[5] = "u"; + std::vector challenge_str = { + "beta", "gamma", "alpha", "zeta", "nu", "u"}; // find the mathcing index size_t i = 0; From f43ec832aa6441fb516e264b1c2e81f2ae34810f Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 08:51:32 +0100 Subject: [PATCH 085/154] plonk: combine two error checks that are functionally the same into one. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968604416 . --- .../bls12_381_test_vector_transcript_hasher.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 8e3deae8b..2e50d35e6 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -110,15 +110,6 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: // vector of valid lengths (\attention specific to BLS12-381) const std::vector length{288, 320, 416, 704, 896, 1120}; - // If we are here, then the hasher buffer has invalid length so throw an - // exception - bool b_valid_length = - (0 != std::count(length.begin(), length.end(), buffer_len)); - if (!b_valid_length) { - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); - } - libff::Fr challenge = 0; // map the index length=0,1...5 to the challenge string=beta, @@ -126,13 +117,15 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: std::vector challenge_str = { "beta", "gamma", "alpha", "zeta", "nu", "u"}; - // find the mathcing index + // find the matching index size_t i = 0; while (buffer_len != length[i]) { ++i; if (i >= length.size()) { + // If we are here, then the hasher buffer has invalid length so + // throw an exception throw std::logic_error( - "Error: invalid index of transcript hasher buffer"); + "Error: invalid length of transcript hasher buffer"); } } From 29ca79d924c2811317bbaf9f3527af8889174ab1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 11:13:25 +0100 Subject: [PATCH 086/154] plonk: declared const challenge upon assignment in bls12_381_test_vector_transcript_hasher::get_hash(). addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968605915 . --- .../plonk/tests/bls12_381_test_vector_transcript_hasher.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 2e50d35e6..689935637 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -110,8 +110,6 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: // vector of valid lengths (\attention specific to BLS12-381) const std::vector length{288, 320, 416, 704, 896, 1120}; - libff::Fr challenge = 0; - // map the index length=0,1...5 to the challenge string=beta, // gamma, ...; used to print explicitly the challenge string for debug std::vector challenge_str = { @@ -135,7 +133,9 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: __LINE__, (int)buffer_len, challenge_str[i].c_str()); - challenge = this->hash_values[i]; // beta + + const libff::Fr challenge = + this->hash_values[i]; // beta return challenge; } From f314a57751073a1c96dd2b07e090a28bc6753a57 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 11:15:40 +0100 Subject: [PATCH 087/154] plonk: removed redundant this-> in get_hash. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968607769 . --- .../plonk/tests/bls12_381_test_vector_transcript_hasher.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 689935637..453e42be0 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -134,8 +134,7 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: (int)buffer_len, challenge_str[i].c_str()); - const libff::Fr challenge = - this->hash_values[i]; // beta + const libff::Fr challenge = hash_values[i]; // beta return challenge; } From b8d85a2654df9e695657300ee5da806ed25a446d Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 13 Sep 2022 12:13:50 +0100 Subject: [PATCH 088/154] plonk: created length and challenge arrays as const members of class bls12_381_test_vector_transcript_hasher initialized in the constructor. addresses https://github.com/clearmatics/libsnark/pull/61#discussion_r968607447 . --- .../bls12_381_test_vector_transcript_hasher.cpp | 16 +++++----------- .../bls12_381_test_vector_transcript_hasher.hpp | 7 ++++++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 453e42be0..aed065d54 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -16,6 +16,8 @@ namespace libsnark bls12_381_test_vector_transcript_hasher:: bls12_381_test_vector_transcript_hasher() + : length_array({288, 320, 416, 704, 896, 1120}) + , challenge_array({"beta", "gamma", "alpha", "zeta", "nu", "u"}) { plonk_example example; @@ -107,19 +109,11 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: { size_t buffer_len = this->buffer.size(); - // vector of valid lengths (\attention specific to BLS12-381) - const std::vector length{288, 320, 416, 704, 896, 1120}; - - // map the index length=0,1...5 to the challenge string=beta, - // gamma, ...; used to print explicitly the challenge string for debug - std::vector challenge_str = { - "beta", "gamma", "alpha", "zeta", "nu", "u"}; - // find the matching index size_t i = 0; - while (buffer_len != length[i]) { + while (buffer_len != length_array[i]) { ++i; - if (i >= length.size()) { + if (i >= length_array.size()) { // If we are here, then the hasher buffer has invalid length so // throw an exception throw std::logic_error( @@ -132,7 +126,7 @@ libff::Fr bls12_381_test_vector_transcript_hasher:: __FILE__, __LINE__, (int)buffer_len, - challenge_str[i].c_str()); + challenge_array[i].c_str()); const libff::Fr challenge = hash_values[i]; // beta diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index fd9be7093..749bd7a49 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -80,6 +80,11 @@ class bls12_381_test_vector_transcript_hasher // array containing the hash values of the communication transcript // i.e. the six challenges (in this order): beta, gamma, alpha, zeta, nu, u std::array, 6> hash_values; + // vector of valid lengths (\attention specific to BLS12-381) + const std::array length_array; + // map the index length=0,1...5 to the challenge string=beta, + // gamma, ...; used to print explicitly the challenge string for debug + const std::array challenge_array; public: bls12_381_test_vector_transcript_hasher(); @@ -93,7 +98,7 @@ class bls12_381_test_vector_transcript_hasher // hashing void add_element(const libff::G2 &element); - // TODO: use next declaration to implement an actual hash function + // TODO: use following declaration to implement an actual hash function // e.g. BLAKE (from Aztec barretenberg implementation): // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 // From af0d012b0d276e5dc254d89a3d48c723e78cb719 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 14 Sep 2022 14:00:54 +0100 Subject: [PATCH 089/154] plonk: amended comments to transcript hasher code according to suggestions in https://github.com/clearmatics/libsnark/pull/61#discussion_r970529544 . --- .../bls12_381_test_vector_transcript_hasher.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index 749bd7a49..a992abff9 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -12,7 +12,12 @@ namespace libsnark { -/// transcript hasher interface specific to the BLS12-381 curve +/// Implementation of the transcript hasher interface (see +/// transcript_hasher.hpp), returning hard-coded test vector values +/// for the plonk proof system on a specific circuit, using the +/// BLS12-381 curve. Also performs a simple check on the transcript to +/// be hashed to verify correct operation of the plonk prover and +/// verifier. /// /// the hasher works in the Prover as follows: /// @@ -68,7 +73,7 @@ namespace libsnark /// add_element(buffer, W_zeta_omega_eval_exp) /// /// // buffer = first_output + second_output + third_output + fourth_output -/// + fifth_output +/// // + fifth_output /// /// u = hash(str(buffer)) /// @@ -98,13 +103,6 @@ class bls12_381_test_vector_transcript_hasher // hashing void add_element(const libff::G2 &element); - // TODO: use following declaration to implement an actual hash function - // e.g. BLAKE (from Aztec barretenberg implementation): - // https://github.com/AztecProtocol/barretenberg/blob/master/barretenberg/src/aztec/plonk/transcript/transcript.cpp#L33 - // - // std::array - // Blake2sHasher::hash(std::vector const& buffer) - // dummy implementation of get_hash that directly returns the // expected hard-coded hashes for the purposes of unit testing TODO // to be replaced by a call to a proper hash function e.g. SHA2, From 89c91f6b8ebc28943875ff6c3f1772db584cda9f Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Sep 2022 17:12:14 +0100 Subject: [PATCH 090/154] plonk: replaced while loop in get_hash with for loop; assert-ed that length and challenge arrays are of same length in transcript hasher constructor; minor edits. addresses lates comments in PR #61 . --- ...ls12_381_test_vector_transcript_hasher.cpp | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index aed065d54..6cbc0cb1b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -19,14 +19,16 @@ bls12_381_test_vector_transcript_hasher:: : length_array({288, 320, 416, 704, 896, 1120}) , challenge_array({"beta", "gamma", "alpha", "zeta", "nu", "u"}) { + assert(length_array.size() == challenge_array.size()); + plonk_example example; // initialize to empty vector - this->buffer.clear(); + buffer.clear(); // test array containing the expected hash values of the communication // transcript i.e. the communication challenges (in this order): beta, // gamma, alpha, zeta, nu, u WARNING! specific to curve BLS12-381 - this->hash_values = { + hash_values = { example.beta, example.gamma, example.alpha, @@ -107,30 +109,25 @@ void bls12_381_test_vector_transcript_hasher::add_element( libff::Fr bls12_381_test_vector_transcript_hasher:: get_hash() { - size_t buffer_len = this->buffer.size(); - - // find the matching index - size_t i = 0; - while (buffer_len != length_array[i]) { - ++i; - if (i >= length_array.size()) { - // If we are here, then the hasher buffer has invalid length so - // throw an exception - throw std::logic_error( - "Error: invalid length of transcript hasher buffer"); + const size_t buffer_len = this->buffer.size(); + + // find the matching index and return the corresponding challenge. + for (size_t i = 0; i < length_array.size(); ++i) { + if (buffer_len == length_array[i]) { + printf( + "[%s:%d] buffer_len %d: %s\n", + __FILE__, + __LINE__, + (int)buffer_len, + challenge_array[i].c_str()); + + return hash_values[i]; } } - printf( - "[%s:%d] buffer_len %d: %s\n", - __FILE__, - __LINE__, - (int)buffer_len, - challenge_array[i].c_str()); - - const libff::Fr challenge = hash_values[i]; // beta - - return challenge; + // If we are here, then the hasher buffer has invalid length so + // throw an exception + throw std::logic_error("Error: invalid length of transcript hasher buffer"); } } // namespace libsnark From 75176fe3881436eb5312d9e74a56e56673522677 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 16 Sep 2022 08:04:02 +0100 Subject: [PATCH 091/154] plonk: renamed example.tcc to example.cpp. added example.cpp and bls12_381_test_vector_transcript_hasher.cpp to CMakeLists.txt. added several headers to fix compilation errors. --- libsnark/CMakeLists.txt | 2 +- libsnark/zk_proof_systems/plonk/circuit.hpp | 2 ++ .../plonk/tests/bls12_381_test_vector_transcript_hasher.cpp | 2 ++ .../plonk/tests/bls12_381_test_vector_transcript_hasher.hpp | 6 ++++-- .../plonk/tests/{example.tcc => example.cpp} | 1 + libsnark/zk_proof_systems/plonk/tests/example.hpp | 4 ---- libsnark/zk_proof_systems/plonk/utils.hpp | 2 ++ 7 files changed, 12 insertions(+), 7 deletions(-) rename libsnark/zk_proof_systems/plonk/tests/{example.tcc => example.cpp} (99%) diff --git a/libsnark/CMakeLists.txt b/libsnark/CMakeLists.txt index 8b554fff8..8b9742400 100644 --- a/libsnark/CMakeLists.txt +++ b/libsnark/CMakeLists.txt @@ -205,7 +205,7 @@ if ("${IS_LIBSNARK_PARENT}") libsnark_test(test_r1cs_ppzksnark_verifier_gadget gadgetlib1/tests/test_r1cs_ppzksnark_verifier_gadget.cpp) libsnark_test(test_r1cs_gg_ppzksnark_verifier_gadget gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp) libsnark_test(test_kzg10_verifier_gadget gadgetlib1/tests/test_kzg10_verifier_gadget.cpp) - libsnark_test(test_plonk zk_proof_systems/plonk/tests/test_plonk.cpp) + libsnark_test(test_plonk zk_proof_systems/plonk/tests/example.cpp zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp zk_proof_systems/plonk/tests/test_plonk.cpp) # TODO (howardwu): Resolve runtime on targets: # libsnark_test(zk_proof_systems_uscs_ppzksnark_test zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark.cpp) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index dd05fddd1..bbffccb65 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -11,6 +11,8 @@ #include "libsnark/zk_proof_systems/plonk/utils.hpp" +#include + /// Declaration of Common Preprocessed Input data structures for a /// specific arithmetic circuit. /// diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index 6cbc0cb1b..fb9094bad 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -9,6 +9,8 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_CPP_ +#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp" + // Implementation of the transcript hasher interface specific to the BLS12-381 // curve. See bls12_381_test_vector_transcript_hasher.hpp namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index a992abff9..027afff2b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -9,6 +9,10 @@ #ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ #define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ +#include "libsnark/zk_proof_systems/plonk/utils.hpp" + +#include + namespace libsnark { @@ -118,6 +122,4 @@ class bls12_381_test_vector_transcript_hasher } // namespace libsnark -#include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp" - #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_BLS12_381_TEST_VECTOR_TRANSCRIPT_HASHER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/example.tcc b/libsnark/zk_proof_systems/plonk/tests/example.cpp similarity index 99% rename from libsnark/zk_proof_systems/plonk/tests/example.tcc rename to libsnark/zk_proof_systems/plonk/tests/example.cpp index 2b90b121a..977293d76 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.tcc +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -10,6 +10,7 @@ // Instantiation of the test vector values from the Python implementation // of the Plonk protocol. \see example.hpp . +#include "libsnark/zk_proof_systems/plonk/tests/example.hpp" namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index fbc443ebe..de2431609 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -31,8 +31,6 @@ #include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include -#include -#include #include namespace libsnark @@ -307,6 +305,4 @@ class plonk_example } // namespace libsnark -#include - #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_EXAMPLE_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 9daba2ef4..ad9386dfb 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -12,6 +12,8 @@ #include "libsnark/zk_proof_systems/plonk/tests/example.hpp" #include +#include +#include #include // enable debug checks. in particular enable comparisons to test From b3a2ffff867cd1457033328e11982e1eafcd4090 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 13 Oct 2022 11:53:22 +0100 Subject: [PATCH 092/154] plonk: formatted example.cpp with latest version of clang-format-11 --- .../zk_proof_systems/plonk/tests/example.cpp | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.cpp b/libsnark/zk_proof_systems/plonk/tests/example.cpp index 977293d76..9ab2bfcf9 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -292,24 +292,25 @@ plonk_example::plonk_example() // blinding scalars b1, b2, ..., b9. random but fixed to match // the python test vectors - prover_blind_scalars = {Field("80633968928703880558063703697897048577551160" - "44327394765020751373651916505604"), - Field("68270264301200565976794531113706823063169483" - "63643792417785314991392447377909"), - Field("20903799562102387073359556962112335230020378" - "309596765284572286455779329747315"), - Field("27445824854335787523979734401573136947589999" - "159092723101543900479804718923773"), - Field("52164479755085410212907573804852358855974754" - "07449078898274648785082871817687"), - Field("48720156268681305476740160454555587712391923" - "971264646500554531948708930944069"), - Field("21318915166515188286980897071631919826831011" - "87444208330829153527689737950718"), - Field("47548532878000795436471885496554996210469829" - "388180983864669623532585348412472"), - Field("25345997198725001609008178533933158854206333" - "20379105447254598708515031311667")}; + prover_blind_scalars = { + Field("80633968928703880558063703697897048577551160" + "44327394765020751373651916505604"), + Field("68270264301200565976794531113706823063169483" + "63643792417785314991392447377909"), + Field("20903799562102387073359556962112335230020378" + "309596765284572286455779329747315"), + Field("27445824854335787523979734401573136947589999" + "159092723101543900479804718923773"), + Field("52164479755085410212907573804852358855974754" + "07449078898274648785082871817687"), + Field("48720156268681305476740160454555587712391923" + "971264646500554531948708930944069"), + Field("21318915166515188286980897071631919826831011" + "87444208330829153527689737950718"), + Field("47548532878000795436471885496554996210469829" + "388180983864669623532585348412472"), + Field("25345997198725001609008178533933158854206333" + "20379105447254598708515031311667")}; // Hashes of transcript (Fiat-Shamir heuristic) this->beta = Field("3710899868510394644410941212967766116886736137326022751" From 00729f5eb4008b8ab9175c15831118f2e026a7e6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 13 Oct 2022 12:35:38 +0100 Subject: [PATCH 093/154] plonk: removed dummy functions for verifier steps 1,2,3 --- libsnark/zk_proof_systems/plonk/verifier.tcc | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index dea93dca2..f66d0b3bd 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -43,23 +43,6 @@ verifier_preprocessed_input_t plonk_verifier:: return preprocessed_input; } -template -void plonk_verifier::step_one( - const plonk_proof &proof) -{ -} - -template -void plonk_verifier::step_two( - const plonk_proof &proof) -{ -} - -template -void plonk_verifier::step_three(const srs &srs) -{ -} - template step_four_out_t::step_four_out_t( const libff::Fr &beta, From f51b9eb064fd8c3fd3893a9bec3f553110e3c7dd Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 25 Oct 2022 14:28:41 +0100 Subject: [PATCH 094/154] plonk: added support for BW6_761, BLS12_377 in CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e20f9dcc..a7cf356e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ set( "BN128" CACHE STRING - "Default curve: one of ALT_BN128, BN128, EDWARDS, MNT4, MNT6, BLS12_381" + "Default curve: one of ALT_BN128, BN128, EDWARDS, MNT4, MNT6, BW6_761, BLS12_377, BLS12_381" ) option( From 5426fac14f88cded41d49180e2eb7f1ffffd5c40 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 25 Oct 2022 14:39:35 +0100 Subject: [PATCH 095/154] plonk: updated depends/libff to latest revision --- depends/libff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libff b/depends/libff index f9a588c05..9f01c327c 160000 --- a/depends/libff +++ b/depends/libff @@ -1 +1 @@ -Subproject commit f9a588c05ff803adef5b94a677a6eb37d7ea94cc +Subproject commit 9f01c327cf928d9bb25d2586d7b4b8bc9726bc4c From b5278a6b12291a354a7740d3ea80785b546a7d24 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 25 Oct 2022 14:56:28 +0100 Subject: [PATCH 096/154] plonk: added domain parameter as input to several functions in prover to avoid recomputing it --- libsnark/zk_proof_systems/plonk/prover.hpp | 2 ++ libsnark/zk_proof_systems/plonk/prover.tcc | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index ebf15c626..ce1e434f7 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -273,6 +273,7 @@ template class plonk_prover const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, + std::shared_ptr>> domain, transcript_hasher &hasher); /// Prover Round 2 @@ -299,6 +300,7 @@ template class plonk_prover const std::vector> blind_scalars, const std::vector> &witness, const srs &srs, + std::shared_ptr>> domain, transcript_hasher &hasher); /// Prover Round 3 diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 2c3a17861..98a929340 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -67,6 +67,7 @@ round_one_out_t plonk_prover::round_one( const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, + std::shared_ptr>> domain, transcript_hasher &hasher) { using Field = libff::Fr; @@ -85,7 +86,8 @@ round_one_out_t plonk_prover::round_one( typename std::vector::const_iterator end = witness.begin() + (i * srs.num_gates) + (srs.num_gates); std::vector W_points(begin, end); - plonk_interpolate_polynomial_from_points(W_points, W_polys[i]); + plonk_interpolate_polynomial_from_points( + W_points, W_polys[i], domain); } // represent the blinding scalars b1, b2, ..., b9 as polynomials @@ -137,6 +139,7 @@ round_two_out_t plonk_prover::round_two( const std::vector> blind_scalars, const std::vector> &witness, const srs &srs, + std::shared_ptr>> domain, transcript_hasher &hasher) { using Field = libff::Fr; @@ -158,7 +161,7 @@ round_two_out_t plonk_prover::round_two( srs.num_gates, beta, gamma, witness, srs.H_gen, srs.H_gen_permute); polynomial A_poly(srs.num_gates); - plonk_interpolate_polynomial_from_points(A_vector, A_poly); + plonk_interpolate_polynomial_from_points(A_vector, A_poly, domain); // add blinding polynomial z_1 to the accumulator polynomial A_poly libfqfft::_polynomial_addition(z_poly, z1_blind_poly, A_poly); @@ -838,6 +841,9 @@ plonk_proof plonk_prover::compute_proof( const std::vector> &blind_scalars, transcript_hasher &hasher) { + std::shared_ptr>> domain = + libfqfft::get_evaluation_domain>(srs.num_gates); + // Prover Round 0 (initialization) printf("[%s:%d] Prover Round 0...\n", __FILE__, __LINE__); round_zero_out_t round_zero_out = plonk_prover::round_zero(srs); @@ -845,7 +851,7 @@ plonk_proof plonk_prover::compute_proof( // Prover Round 1 printf("[%s:%d] Prover Round 1...\n", __FILE__, __LINE__); round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_zero_out, blind_scalars, witness, srs, domain, hasher); printf("[%s:%d] Prover Round 2...\n", __FILE__, __LINE__); // - beta: permutation challenges - hashes of transcript of round @@ -858,7 +864,14 @@ plonk_proof plonk_prover::compute_proof( const libff::Fr gamma = hasher.get_hash(); round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + beta, + gamma, + round_zero_out, + blind_scalars, + witness, + srs, + domain, + hasher); printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); // - alpha: quotient challenge - hash of transcript of rounds 1,2 From 32d9b5717281f2055cdb31f3f493b2063a532f90 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 26 Oct 2022 09:13:39 +0100 Subject: [PATCH 097/154] plonk: removed domain parameter from the srs class --- libsnark/zk_proof_systems/plonk/srs.hpp | 6 +----- libsnark/zk_proof_systems/plonk/srs.tcc | 7 ++----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 7fecac31b..c7a2a413a 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -124,9 +124,6 @@ template class srs /// the 0-th polynomial of the Lagrange basis polynomial L_basis_zero; - /// the libfqfft domain - std::shared_ptr> domain; - srs(const size_t &num_gates, const size_t &num_qpolys, const polynomial &PI_poly, @@ -139,8 +136,7 @@ template class srs const libff::Fr &k2, std::vector> &&secret_powers_g1, std::vector> &&secret_powers_g2, - const polynomial &L_basis_zero, - std::shared_ptr> domain); + const polynomial &L_basis_zero); }; /// Derive the (plain) SRS from the circuit description and the diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index c837e6326..8c8fb25f6 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -37,8 +37,7 @@ srs::srs( const libff::Fr &k2, std::vector> &&secret_powers_g1, std::vector> &&secret_powers_g2, - const polynomial &L_basis_zero, - std::shared_ptr>> domain) + const polynomial &L_basis_zero) : num_gates(num_gates) , num_qpolys(num_qpolys) , PI_poly(PI_poly) @@ -52,7 +51,6 @@ srs::srs( , secret_powers_g1(secret_powers_g1) , secret_powers_g2(secret_powers_g2) , L_basis_zero(L_basis_zero) - , domain(domain) { } @@ -145,8 +143,7 @@ srs plonk_srs_derive_from_usrs( circuit.k2, std::move(secret_powers_g1), std::move(secret_powers_g2), - std::move(L_basis_zero), - domain); + std::move(L_basis_zero)); return srs; } From aee3a95e2bac11818ea3bf975aac9441c1e217e9 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 26 Oct 2022 09:17:58 +0100 Subject: [PATCH 098/154] plonk: added domain parameter as a new input to multiple functions as a result of changes to several function declarations in prover, verifier and srs --- .../plonk/tests/test_plonk.cpp | 67 ++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 55960b4e3..61cb4ab88 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -193,7 +193,7 @@ circuit_t plonk_circuit_description_from_example( polynomial PI_poly; std::vector PI_points(num_gates, Field(0)); PI_points[PI_index] = Field(-PI_value); - plonk_compute_public_input_polynomial(PI_points, PI_poly); + plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); // compute the selector polynomials (q-polynomials) from the // transposed gates matrix over the Lagrange basis q_poly = \sum_i @@ -201,7 +201,7 @@ circuit_t plonk_circuit_description_from_example( // element) and L[i] is a polynomial with Field coefficients std::vector> Q_polys = plonk_compute_selector_polynomials( - num_gates, num_qpolys, gates_matrix_transpose); + num_gates, num_qpolys, gates_matrix_transpose, domain); // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, // omega[2] are omega[0]*k2 @@ -238,7 +238,8 @@ circuit_t plonk_circuit_description_from_example( // compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) std::vector> S_polys = - plonk_compute_permutation_polynomials(H_gen_permute, num_gates); + plonk_compute_permutation_polynomials( + H_gen_permute, num_gates, domain); circuit_t circuit( std::move(num_gates), @@ -260,14 +261,15 @@ void test_plonk_compute_accumulator( const libff::Fr &beta, const libff::Fr &gamma, const std::vector> &witness, - const srs &srs) + const srs &srs, + std::shared_ptr>> domain) { using Field = libff::Fr; // A[0] = 1; ... A[i] = computed from (i-1) std::vector A_vector = plonk_compute_accumulator( srs.num_gates, beta, gamma, witness, srs.H_gen, srs.H_gen_permute); polynomial A_poly(srs.num_gates); - plonk_interpolate_polynomial_from_points(A_vector, A_poly); + plonk_interpolate_polynomial_from_points(A_vector, A_poly, domain); // initialize hard-coded values from example circuit printf("[%s:%d] A_poly\n", __FILE__, __LINE__); @@ -281,12 +283,13 @@ void test_plonk_prover_round_one( const round_zero_out_t &round_zero_out, const std::vector> &witness, const srs &srs, + std::shared_ptr>> domain, transcript_hasher &hasher) { std::vector> blind_scalars = example.prover_blind_scalars; round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_zero_out, blind_scalars, witness, srs, domain, hasher); for (int i = 0; i < (int)NUM_HSETS; ++i) { printf("[%s:%d] this->W_polys[%d]\n", __FILE__, __LINE__, (int)i); libff::print_vector(round_one_out.W_polys[i]); @@ -322,11 +325,19 @@ void test_plonk_prover_round_two( const std::vector> &blind_scalars, const std::vector> &witness, const srs &srs, + std::shared_ptr>> domain, transcript_hasher &hasher) { round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + beta, + gamma, + round_zero_out, + blind_scalars, + witness, + srs, + domain, + hasher); printf("[%s:%d] z_poly\n", __FILE__, __LINE__); libff::print_vector(round_two_out.z_poly); ASSERT_EQ(round_two_out.z_poly, example.z_poly); @@ -491,6 +502,9 @@ template void test_plonk_prover_rounds() // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); @@ -506,14 +520,14 @@ template void test_plonk_prover_rounds() // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); test_plonk_prover_round_one( - example, round_zero_out, witness, srs, hasher); + example, round_zero_out, witness, srs, domain, hasher); // --- Unit test Prover Round 2 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); round_one_out_t round_one_out = plonk_prover::round_one( - round_zero_out, blind_scalars, witness, srs, hasher); + round_zero_out, blind_scalars, witness, srs, domain, hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -531,17 +545,26 @@ template void test_plonk_prover_rounds() blind_scalars, witness, srs, + domain, hasher); // Unit test plonk_compute_accumulator - test_plonk_compute_accumulator(example, beta, gamma, witness, srs); + test_plonk_compute_accumulator( + example, beta, gamma, witness, srs, domain); // --- Unit test Prover Round 3 --- // reset buffer at the start of the round (needed for testing only) printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); round_two_out_t round_two_out = plonk_prover::round_two( - beta, gamma, round_zero_out, blind_scalars, witness, srs, hasher); + beta, + gamma, + round_zero_out, + blind_scalars, + witness, + srs, + domain, + hasher); // clear hash buffer hasher.buffer_clear(); // add outputs from Round 1 to the hash buffer @@ -651,6 +674,9 @@ template void test_plonk_srs() // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + // --- USRS --- // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 @@ -697,6 +723,9 @@ template void test_plonk_prover() // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); @@ -789,10 +818,11 @@ template void test_plonk_verifier_step_five( const plonk_example &example, const step_four_out_t &step_four_out, - const srs &srs) + std::shared_ptr>> domain) { const step_five_out_t step_five_out = - plonk_verifier::step_five(step_four_out, srs); + plonk_verifier::step_five( + step_four_out, domain); printf("[%s:%d] zh_zeta ", __FILE__, __LINE__); step_five_out.zh_zeta.print(); ASSERT_EQ(step_five_out.zh_zeta, example.zh_zeta); @@ -977,6 +1007,9 @@ template void test_plonk_verifier_steps() // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); @@ -1004,7 +1037,7 @@ template void test_plonk_verifier_steps() // unit test verifier step 5 test_plonk_verifier_step_five( - example, step_four_out, srs); + example, step_four_out, domain); // unit test verifier step 6 test_plonk_verifier_step_six( @@ -1016,7 +1049,8 @@ template void test_plonk_verifier_steps() // unit test verifier step 8 const step_five_out_t step_five_out = - plonk_verifier::step_five(step_four_out, srs); + plonk_verifier::step_five( + step_four_out, domain); const step_six_out_t step_six_out = plonk_verifier::step_six(step_four_out, srs); const step_seven_out_t step_seven_out = @@ -1088,6 +1122,9 @@ template void test_plonk_verifier() // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(circuit.num_gates); + // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs(usrs, circuit); From de332a8949e9a40fcf7f803586b92efa186b111b Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 26 Oct 2022 09:30:25 +0100 Subject: [PATCH 099/154] plonk: added domain parameter as a new input to multiple functions in utils.* --- libsnark/zk_proof_systems/plonk/utils.hpp | 11 ++++++--- libsnark/zk_proof_systems/plonk/utils.tcc | 27 ++++++++++++++--------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index ad9386dfb..2b1efce21 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -70,7 +70,9 @@ template void print_vector(const std::vector &v); /// \note uses libfqfft iFFT for the interpolation template void plonk_interpolate_polynomial_from_points( - const std::vector &f_points, polynomial &f_poly); + const std::vector &f_points, + polynomial &f_poly, + std::shared_ptr> domain); /// Compute the selector polynomials of the given circuit (also /// called here "q-polynomials"). See Sect. 8.1. The matrix @@ -80,7 +82,8 @@ void plonk_interpolate_polynomial_from_points( template std::vector> plonk_compute_selector_polynomials( const size_t &num_gates, - const std::vector> &gates_matrix_transpose); + const std::vector> &gates_matrix_transpose, + std::shared_ptr> domain); /// This function computes the sets H, k1H, k2H. H is a /// multiplicative subgroup containing the n-th roots of unity in Fr, @@ -124,7 +127,9 @@ std::vector plonk_permute_subgroup_H( /// S_sigma_2 (see [GWC19], Sect. 8.1) template std::vector> plonk_compute_permutation_polynomials( - const std::vector &H_gen_permute, const size_t num_gates); + const std::vector &H_gen_permute, + const size_t num_gates, + std::shared_ptr> domain); // A wrapper for multi_exp_method_BDLO12_signed() dot-product a // vector of group elements in G1 (curve points) with a vector of diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index aecdbe972..80a0dbe20 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -44,11 +44,10 @@ void plonk_compute_lagrange_basis( template void plonk_interpolate_polynomial_from_points( - const std::vector &f_points, polynomial &f_poly) + const std::vector &f_points, + polynomial &f_poly, + std::shared_ptr> domain) { - size_t npoints = f_points.size(); - std::shared_ptr> domain = - libfqfft::get_evaluation_domain(npoints); f_poly = f_points; domain->iFFT(f_poly); } @@ -57,7 +56,8 @@ template std::vector> plonk_compute_selector_polynomials( const size_t &num_gates, const size_t &num_qpolys, - const std::vector> &gates_matrix_transpose) + const std::vector> &gates_matrix_transpose, + std::shared_ptr> domain) { assert(gates_matrix_transpose.size() == num_qpolys); assert(gates_matrix_transpose[0].size() == num_gates); @@ -66,16 +66,20 @@ std::vector> plonk_compute_selector_polynomials( Q_polys.resize(num_qpolys, polynomial(num_gates)); for (size_t i = 0; i < num_qpolys; ++i) { std::vector q_vec = gates_matrix_transpose[i]; - plonk_interpolate_polynomial_from_points(q_vec, Q_polys[i]); + plonk_interpolate_polynomial_from_points( + q_vec, Q_polys[i], domain); } return Q_polys; }; template void plonk_compute_public_input_polynomial( - const std::vector &PI_points, polynomial &PI_poly) + const std::vector &PI_points, + polynomial &PI_poly, + std::shared_ptr> domain) { - plonk_interpolate_polynomial_from_points(PI_points, PI_poly); + plonk_interpolate_polynomial_from_points( + PI_points, PI_poly, domain); }; template @@ -158,7 +162,9 @@ std::vector plonk_permute_subgroup_H( template std::vector> plonk_compute_permutation_polynomials( - const std::vector &H_gen_permute, const size_t num_gates) + const std::vector &H_gen_permute, + const size_t num_gates, + std::shared_ptr> domain) { assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); std::vector> S_polys; @@ -169,7 +175,8 @@ std::vector> plonk_compute_permutation_polynomials( typename std::vector::const_iterator end = H_gen_permute.begin() + (i * num_gates) + (num_gates); std::vector S_points(begin, end); - plonk_interpolate_polynomial_from_points(S_points, S_polys[i]); + plonk_interpolate_polynomial_from_points( + S_points, S_polys[i], domain); } return S_polys; } From e5e3ddb0f310f9738e7a1a9c3692b31a8a535d78 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 26 Oct 2022 09:32:41 +0100 Subject: [PATCH 100/154] plonk: added domain parameter as an additional input parameter to several functions in verifier --- libsnark/zk_proof_systems/plonk/verifier.hpp | 3 ++- libsnark/zk_proof_systems/plonk/verifier.tcc | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index bb02b9218..ea18b0caf 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -213,7 +213,8 @@ template class plonk_verifier /// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at /// x=zeta i.e. Zh(zeta) static step_five_out_t step_five( - const step_four_out_t &step_four_out, const srs &srs); + const step_four_out_t &step_four_out, + std::shared_ptr>> domain); /// Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) /// Note: the paper counts the L-polynomials from 1; we count from 0 diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index f66d0b3bd..2f1b423be 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -117,16 +117,16 @@ step_five_out_t::step_five_out_t(libff::Fr &&zh_zeta) template step_five_out_t plonk_verifier::step_five( - const step_four_out_t &step_four_out, const srs &srs) + const step_four_out_t &step_four_out, + std::shared_ptr>> domain) { - libff::Fr zh_zeta; - std::shared_ptr> domain = - libfqfft::get_evaluation_domain(srs.num_gates); - zh_zeta = domain->compute_vanishing_polynomial(step_four_out.zeta); + libff::Fr zh_zeta = + domain->compute_vanishing_polynomial(step_four_out.zeta); step_five_out_t step_five_out(std::move(zh_zeta)); return step_five_out; } +/// struct step_six_out_t constructor template step_six_out_t::step_six_out_t(libff::Fr &&L_0_zeta) : L_0_zeta(L_0_zeta) @@ -400,6 +400,9 @@ bool plonk_verifier::verify_proof( const srs &srs, transcript_hasher &hasher) { + std::shared_ptr>> domain = + libfqfft::get_evaluation_domain>(srs.num_gates); + // compute verifier preprocessed input const verifier_preprocessed_input_t preprocessed_input = plonk_verifier::preprocessed_input(srs); @@ -418,7 +421,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 5: compute zero polynomial evaluation const step_five_out_t step_five_out = - this->step_five(step_four_out, srs); + this->step_five(step_four_out, domain); // Verifier Step 6: Compute Lagrange polynomial evaluation L1(zeta) // Note: the paper counts the L-polynomials from 1; we count from 0 From a0ea6eb466b44430bf4c26bcc99e14b11f7e4a80 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 4 Nov 2022 11:33:32 +0000 Subject: [PATCH 101/154] plonk: edited input and output parameters in all headers to correspond to the actual input/output variables (https://github.com/clearmatics/libsnark/pull/70#discussion_r1010223909) --- libsnark/zk_proof_systems/plonk/prover.hpp | 131 ++++++------------- libsnark/zk_proof_systems/plonk/utils.hpp | 2 + libsnark/zk_proof_systems/plonk/verifier.hpp | 128 ++++++------------ 3 files changed, 79 insertions(+), 182 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index ce1e434f7..5ed1bd6ee 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -236,35 +236,26 @@ template class plonk_prover /// /// INPUT /// \param[in] srs: structured reference string containing also - /// circuit-specific - /// information + /// circuit-specific information /// /// OUTPUT - /// \param[out] W_polys: Lagrange interpolation of the witness values - /// \param[out] zh_poly: vanishing polynomial - /// \param[out] null_poly: 0 polynomial - /// \param[out] neg_one_poly: -1 polynomial + /// \param[out] round_zero_out_t static round_zero_out_t round_zero(const srs &srs); /// Prover Round 1 /// /// INPUT - /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) - /// \param[in] null_poly: 0 polynomial (from round 0) - /// \param[in] neg_one_poly: -1 polynomial (from round 0) + /// \param[in] round_zero_out: see round_zero_out_t /// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only - /// b1-b6 used in round 1) + /// b1-b6 used in round 1) (see Sect. 8.1, Round 1 in [GWC19]) /// \param[in] witness: witness values /// \param[in] srs: structured reference string containing also /// circuit-specific information + /// \param[in] domain: libfqfft evaluation domain (see + /// libfqfft/evaluation_domain/evaluation_domain.hpp) /// /// OUTPUT - /// \param[out] W_polys: witness polynomials (Lagrange interpolation - /// of the witness values) - /// \param[out] W_polys_blinded: blinded witness polynomials - /// \param[out] W_polys_blinded_at_secret_g1: the blinded witness - /// polynomials evaluated at the secret input denoted - /// [a]_1, [b]_1, [c]_1 in [GWC19] + /// \param[out] round_one_out: see round_one_out_t /// \param[out] transcript_hasher: accumulates the communication /// transcript into a buffer to be hashed after prover /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). @@ -279,17 +270,19 @@ template class plonk_prover /// Prover Round 2 /// /// INPUT - /// \param[in] zh_poly: vanishing polynomial Zh (from round 0) + /// \param[in] beta, gamma: permutation challenges -- hashes of + /// transcript (from round 2) + /// \param[in] round_zero_out: see round_zero_out_t /// \param[in] blind_scalars: blinding scalars b1, b2, ..., b9 (only - /// b7,b8,b9 used in round 2) + /// b1-b6 used in round 1) (see Sect. 8.1, Round 1 in [GWC19]) /// \param[in] witness: witness values /// \param[in] srs: structured reference string containing also /// circuit-specific information + /// \param[in] domain: libfqfft evaluation domain (see + /// libfqfft/evaluation_domain/evaluation_domain.hpp) /// /// OUTPUT - /// \param[out] z_poly: blinded accumulator poly z(x) - /// \param[out] z_poly_at_secret_g1: blinded accumulator poly z(x) - /// evaluated at secret + /// \param[out] round_two_out: see round_two_out_t /// \param[out] transcript_hasher: accumulates the communication /// transcript into a buffer to be hashed after prover /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). @@ -306,24 +299,18 @@ template class plonk_prover /// Prover Round 3 /// /// INPUT - /// \param[in] zh_poly: vanishing polynomial Zh (from Round 0) - /// \param[in] W_polys_blinded: blinded witness polynomials (from - /// Round 1) + /// \param[in] alpha: quotient challenge -- hash of transcript (from + /// round 3) /// \param[in] beta, gamma: permutation challenges -- hashes of /// transcript (from round 2) - /// \param[in] z_poly: blinded accumulator poly z(x) (from Round 2) + /// \param[in] round_zero_out: see round_zero_out_t + /// \param[in] round_one_out: see round_one_out_t + /// \param[in] round_two_out: see round_two_out_t /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] t_poly_long: the quotient polynomial t(x) (see Round - /// 3, pp28 [GWC19]) - /// \param[out] t_poly: t(x) divided in three parts t(x) = t_lo(x) + - /// t_mid(x) x^n + t_hi(x) x^{2n} - /// \param[out] t_poly_at_secret_g1: t(x) evaluated at the secret - /// input zeta i.e. t(zeta) - /// \param[out] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted - /// by w + /// \param[out] round_three_out: see round_three_out_t /// \param[out] transcript_hasher: accumulates the communication /// transcript into a buffer to be hashed after prover /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). @@ -340,34 +327,15 @@ template class plonk_prover /// Prover Round 4 /// /// INPUT - /// \param[in] W_polys_blinded: blinded witness polynomials (from - /// Round 1) - /// \param[in] z_poly_xomega: the polynomial z(x*w) i.e. z(x) shifted - /// by w (from Round 3) - /// \param[in] t_poly_long: the quotient polynomial t(x) (see Round 3, - /// pp28 [GWC19]) (from Round 3) + /// \param[in] zeta: evaluation challenge -- hash of transcript (from + /// round 4) + /// \param[in] round_one_out: see round_one_out_t + /// \param[in] round_three_out: see round_three_out_t /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] a_zeta, b_zeta, c_zeta: the blinded witness - /// polynomials a(x), b(x), c(x) (denoted by - /// W_polys_blinded[] output from Round 1) evaluated at - /// x=zeta i.e. a(z), b(z), c(z) - /// \param[out] S_0_zeta, S_1_zeta: the permutation polynomials - /// S_sigma_1(x), S_sigma_2(x) from the common - /// preprocessed input (see [GWC19], Sect. 8.1) evaluated - /// at x=zeta i.e. S_sigma_1(z), S_sigma_2(z) - /// \param[out] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) - /// shifted by w (output from Round 3) evaluated at x=zeta - /// i.e. z(zeta*w) - /// \param[out] t_zeta: the quotient polynomial t(x) output from Round - /// 3, see pp28 [GWC19]) evaluated at x=zeta - /// i.e. t(z). IMPORTANT! the original Plonk proposal - /// [GWC19] does not output this parameter t_zeta. The - /// Python reference implementation does, so we do the - /// same in order to match the test vectors. TODO can - /// remove t_zeta in the future + /// \param[out] round_four_out: see round_four_out_t /// \param[out] transcript_hasher: accumulates the communication /// transcript into a buffer to be hashed after prover /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). @@ -381,47 +349,24 @@ template class plonk_prover /// Prover Round 5 /// /// INPUT - /// \param[in] beta, gamma: permutation challenges -- hashes of - /// transcript (from round 2) /// \param[in] alpha: quotient challenge -- hash of transcript (from /// round 3) + /// \param[in] beta, gamma: permutation challenges -- hashes of + /// transcript (from round 2) /// \param[in] zeta: evaluation challenge -- hash of transcript (from /// round 4) - /// \param[in] a_zeta, b_zeta, c_zeta: the blinded witness polynomials - /// a(x), b(x), c(x) (denoted by W_polys_blinded[] output - /// from Round 1) evaluated at x=zeta i.e. a(z), b(z), c(z) - /// (from round 4) - /// \param[in] S_0_zeta, S_1_zeta: the permutation polynomials - /// S_sigma_1(x), S_sigma_2(x) from the common preprocessed - /// input (see [GWC19], Sect. 8.1) evaluated at x=zeta - /// i.e. S_sigma_1(z), S_sigma_2(z) (from round 4) - /// \param[in] t_zeta: the quotient polynomial t(x) output from Round - /// 3, see pp28 [GWC19]) evaluated at x=zeta - /// i.e. t(z). IMPORTANT! the original Plonk proposal - /// [GWC19] does not output this parameter t_zeta. The - /// Python reference implementation does, so we do the same - /// in order to match the test vectors. TODO can remove - /// t_zeta in the future (from round 4) - /// \param[in] z_poly_xomega_zeta: the polynomial z(x*w) i.e. z(x) - /// shifted by w (output from Round 3) evaluated at x=zeta - /// i.e. z(zeta*w) (from round 4) - /// \param[in] W_polys_blinded: blinded witness polynomials (from - /// round 1) - /// \param[in] t_poly: t(x) divided in three parts t(x) = t_lo(x) + - /// t_mid(x) x^n + t_hi(x) x^{2n} (from round 3) - /// \param[in] z_poly: blinded accumulator poly z(x) (from round 2) + /// \param[in] nu: opening challenge -- hash of transcript (from round 5) + /// (denoted by v in [GWC19]) + /// \param[in] round_zero_out: see round_zero_out_t + /// \param[in] round_one_out: see round_one_out_t + /// \param[in] round_two_out: see round_two_out_t + /// \param[in] round_three_out: see round_three_out_t + /// \param[in] round_four_out: see round_four_out_t /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] r_zeta: linearisation polynomial r(x) evaluated at - /// x=zeta ie. r(zeta) - /// \param[out] W_zeta_at_secret: commitment to opening proof - /// polynomial W_zeta(x) at secert input - /// i.e. [W_zeta(secret)]_1 - /// \param[out] W_zeta_omega_at_secret: commitment to opening proof - /// polynomial W_{zeta omega}(x) at secert input - /// i.e. [W_{zeta omega}(secret)]_1 + /// \param[out] round_five_out: see round_five_out_t /// \param[out] transcript_hasher: accumulates the communication /// transcript into a buffer to be hashed after prover /// rounds 1,2,3,4,5 (cf. fiat-shamir heuristic). @@ -452,13 +397,13 @@ template class plonk_prover /// evaluation of the linearlization polynomial r(X) at zeta from /// Prover round 5) is added to the pi-SNARK proof. In the paper this /// is omitted, which seems to make the proof shorter by 1 element at - /// the epxense of a slightly heavier computation on the verifier's + /// the expense of a slightly heavier computation on the verifier's /// side. Here we follow the reference implementation to make sure we /// match the test values. TODO: once all test vectors are verified, /// we may remove r_zeta from the proof to be fully compliant with the /// paper. /// - /// Mapping code-to-paper quantities + /// Mapping code-to-paper quantities (format is 'code var : paper var') /// /// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 /// (from Round 1) @@ -477,7 +422,7 @@ template class plonk_prover /// \param[in] witness: all internal values and public input /// corresponding to the given circuit /// \param[in] blind_scalars: random blinding scalars b1, b2, ..., b9 - /// used in prover rounds 1 and 2 (see Sect. 8.3, roumds + /// used in prover rounds 1 and 2 (see Sect. 8.3, rounds /// 1,2 [GWC19]) /// \param[in] transcript_hasher: hashes of the communication /// transcript after prover rounds 1,2,3,4,5. diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 2b1efce21..b423db8c5 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -56,6 +56,8 @@ template void print_vector(const std::vector &v); /// \param[in] f_points[0..n-1]: a set of points (0,y0), (1,y1), /// ... (n-1,y_{n-1}) s.t. y0=f_points[0], y1=f_points[1], /// ... which we want to interpolate as a polynomial +/// \param[in] domain: libfqfft evaluation domain (see +/// libfqfft/evaluation_domain/evaluation_domain.hpp) /// /// OUTPUT: /// diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index ea18b0caf..b4ce4f322 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -36,7 +36,7 @@ namespace libsnark /// [W_zeta]_1, [W_{zeta omega}]_1 /// r_zeta (*)) /// -/// Mapping code-to-paper quantities (code: paper) +/// Mapping code-to-paper quantities (format code : paper) /// /// \param W_polys_blinded_at_secret_g1[a, b, c]: [a]_1, [b]_1, [c]_1 /// (from Round 1) @@ -63,7 +63,9 @@ namespace libsnark /// Verifier preprocessed input template struct verifier_preprocessed_input_t { + /// circuit selector polynomials Q evaluated at the secret input std::vector> Q_polys_at_secret_g1; + /// permutation polynomials S evaluated at the secret input std::vector> S_polys_at_secret_g1; verifier_preprocessed_input_t( @@ -73,11 +75,18 @@ template struct verifier_preprocessed_input_t { /// Verifier step 4 output template struct step_four_out_t { + /// permutation challenge - hashes of transcript (round 1) const libff::Fr beta; + /// permutation challenge - hashes of transcript (round 1) const libff::Fr gamma; + /// quotinet challenge - hash of transcript (round 2) const libff::Fr alpha; + /// evaluation challenge - hash of transcript (round 3) const libff::Fr zeta; + /// opening challenge - hash of transcript (round 4) (denoted by v in + /// [GWC19]) const libff::Fr nu; + /// multipoint evaluation challenge - hash of transcript (round 5) const libff::Fr u; step_four_out_t( const libff::Fr &beta, @@ -152,12 +161,8 @@ template class plonk_verifier /// \param[in] srs: structured reference string /// /// OUTPUT - /// \param[out] Q_polys_at_secret_g1: circuit selector polynomials Q - /// evaluated at - /// the secret input - /// \param[out] S_polys_at_secret_g1: permutation polynomials S evaluated at - /// the - /// secret input + /// \param[out] verifier_preprocessed_input: see + /// verifier_preprocessed_input_t static verifier_preprocessed_input_t preprocessed_input( const srs &srs); @@ -190,28 +195,19 @@ template class plonk_verifier /// transcript after prover rounds 1,2,3,4,5. /// /// OUTPUT - /// \param[out] beta, gamma: permutation challenges - hashes of - /// transcript - /// \param[out] alpha: quotinet challenge - hash of transcript - /// \param[out] zeta: evaluation challenge - hash of transcript - /// \param[out] nu: opening challenge - hash of transcript (denoted by - /// v in [GWC19]) - /// \param[out] u: multipoint evaluation challenge - hash of - /// transcript + /// \param[out] step_four_out: see step_four_out static step_four_out_t step_four( const plonk_proof &proof, transcript_hasher &hasher); /// Verifier Step 5: compute zero polynomial evaluation /// /// INPUT - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) - /// \param[in] srs: structured reference string containing also - /// circuit-specific information + /// \param[in] step_four_out: see step_four_out_t + /// \param[in] domain: libfqfft evaluation domain (see + /// libfqfft/evaluation_domain/evaluation_domain.hpp) /// /// OUTPUT - /// \param[out] zh_zeta: evaluation of vanishing polynomial Zh at - /// x=zeta i.e. Zh(zeta) + /// \param[out] step_five_out: see step_five_out_t static step_five_out_t step_five( const step_four_out_t &step_four_out, std::shared_ptr>> domain); @@ -220,14 +216,12 @@ template class plonk_verifier /// Note: the paper counts the L-polynomials from 1; we count from 0 /// /// INPUT - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) + /// \param[in] step_four_out: see step_four_out_t /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] L_0_zeta: Lagrange polynomial evaluation of polynomial - /// L1 at x=zeta i.e. L1(zeta) + /// \param[out] step_six_out: see step_six_out_t static step_six_out_t step_six( const step_four_out_t &step_four_out, const srs &srs); @@ -235,14 +229,12 @@ template class plonk_verifier /// PI(zeta) /// /// INPUT - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) + /// \param[in] step_four_out: see step_four_out_t /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] PI_zeta: public input polynomial PI evaluated at - /// x=zeta i.e. PI(zeta) + /// \param[out] step_seven_out: see step_seven_out_t static step_seven_out_t step_seven( const step_four_out_t &step_four_out, const srs &srs); @@ -256,23 +248,14 @@ template class plonk_verifier /// zeta zh_zeta, while the paper does not do that (see also Step 9). /// /// INPUT - /// \param[in] beta, gamma: permutation challenges -- hashes of - /// transcript (from step 4) - /// \param[in] alpha: quotinet challenge -- hash of transcript (from - /// step 4) - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) - /// \param[in] zh_zeta: evaluation of vanishing polynomial Zh at - /// x=zeta i.e. Zh(zeta) (from step 5) - /// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial - /// L1 at x=zeta i.e. L1(zeta) (from step 6) - /// \param[in] PI_zeta: public input polynomial PI evaluated at x=zeta - /// i.e. PI(zeta) (from step 7) + /// \param[in] step_four_out: see step_four_out_t + /// \param[in] step_five_out: see step_five_out_t + /// \param[in] step_six_out: see step_six_out_t + /// \param[in] step_seven_out: see step_seven_out_t /// \param[in] proof: SNARK proof produced by the prover /// /// OUTPUT - /// \param[out] r_prime_zeta: quotient polynomial evaluation r'(zeta) - /// = r(zeta) - r0, where r0 is a constant term + /// \param[out] step_eight_out: see step_eight_out_t static step_eight_out_t step_eight( const step_four_out_t &step_four_out, const step_five_out_t &step_five_out, @@ -290,31 +273,15 @@ template class plonk_verifier /// Step 8. /// /// INPUT - /// \param[in] beta, gamma: permutation challenges -- hashes of - /// transcript (from step 4) - /// \param[in] alpha: quotinet challenge -- hash of transcript (from - /// step 4) - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) - /// \param[in] nu: opening challenge -- hash of transcript (denoted by - /// v in [GWC19]) (from step 4) - /// \param[in] u: multipoint evaluation challenge -- hash of - /// transcript (from step 4) - /// \param[in] L_0_zeta: Lagrange polynomial evaluation of polynomial - /// L1 at x=zeta i.e. L1(zeta) (from step 6) - /// \param[in] Q_polys_at_secret_g1: circuit selector polynomials Q - /// evaluated at the secret input (from verifier - /// preprocessed input) - /// \param[in] S_polys_at_secret_g1: permutation polynomials S - /// evaluated at the secret input (from verifier - /// preprocessed input) + /// \param[in] step_four_out: see step_four_out_t + /// \param[in] step_six_out: see step_six_out_t /// \param[in] proof: SNARK proof produced by the prover /// \param[in] preprocessed_input: verifier preprocessed input /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] D1: first part of batched polynomial commitment [D]_1 + /// \param[out] step_nine_out: see step_nine_out_t static step_nine_out_t step_nine( const step_four_out_t &step_four_out, const step_six_out_t &step_six_out, @@ -329,23 +296,15 @@ template class plonk_verifier /// addedto [D]_1 in the paper (see commenst to Steps 8,9) /// /// INPUT - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) - /// \param[in] nu: opening challenge -- hash of transcript (denoted by - /// v in [GWC19]) (from step 4) - /// \param[in] u: multipoint evaluation challenge -- hash of - /// transcript (from step 4) - /// \param[in] D1: first part of batched polynomial commitment [D]_1 - /// (from step 9) - /// \param[in] S_polys_at_secret_g1: permutation polynomials S - /// evaluated at the secret input (from verifier - /// preprocessed input) + /// \param[in] step_four_out: see step_four_out_t + /// \param[in] step_nine_out: see step_nine_out_t /// \param[in] proof: SNARK proof produced by the prover + /// \param[in] preprocessed_input: verifier preprocessed input /// \param[in] srs: structured reference string containing also /// circuit-specific information /// /// OUTPUT - /// \param[out] F1: full batched polynomial commitment [F]_1 + /// \param[out] step_ten_out: see step_ten_out_t static step_ten_out_t step_ten( const step_four_out_t &step_four_out, const step_nine_out_t &step_nine_out, @@ -356,16 +315,12 @@ template class plonk_verifier /// Verifier Step 11: compute group-encoded batch evaluation [E]_1 /// /// INPUT - /// \param[in] nu: opening challenge -- hash of transcript (denoted by - /// v in [GWC19]) (from step 4) - /// \param[in] u: multipoint evaluation challenge -- hash of - /// transcript (from step 4) - /// \param[in] r_prime_zeta: quotient polynomial evaluation r'(zeta) = - /// r(zeta) - r0, where r0 is a constant term (from step 8) + /// \param[in] step_four_out: see step_four_out_t + /// \param[in] step_eight_out: see step_eight_out_t /// \param[in] proof: SNARK proof produced by the prover /// /// OUTPUT - /// \param[out] E1: group-encoded batch evaluation [E]_1 + /// \param[out] step_eleven_out: see step_eleven_out_t static step_eleven_out_t step_eleven( const step_four_out_t &step_four_out, const step_eight_out_t &step_eight_out, @@ -384,15 +339,10 @@ template class plonk_verifier /// e(first_lhs, second_lhs) * e(first_rhs, second_rhs) = 1 /// /// INPUT - /// \param[in] zeta: evaluation challenge -- hash of transcript (from - /// step 4) - /// \param[in] u: multipoint evaluation challenge -- hash of - /// transcript (from step 4) - /// \param[in] F1: full batched polynomial commitment [F]_1 (from step - /// 10) - /// \param[in] E1: group-encoded batch evaluation [E]_1 (from step 11) + /// \param[in] step_four_out: see step_four_out_t + /// \param[in] step_ten_out: see step_ten_out_t + /// \param[in] step_eleven_out: see step_eleven_out_t /// \param[in] proof: SNARK proof produced by the prover - /// \param[in] srs: structured reference string /// \param[in] srs: structured reference string containing also /// circuit-specific information /// From 19b52c340244c50b64ac5f5838734f18aefaad1a Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 9 Nov 2022 13:38:25 +0000 Subject: [PATCH 102/154] plonk: updated plonk_circuit_description_from_example to accept only gates matrix, wire premutation and public input as inputs (https://github.com/clearmatics/libsnark/issues/83) --- .../plonk/tests/test_plonk.cpp | 144 +++++++++++++----- 1 file changed, 102 insertions(+), 42 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 61cb4ab88..2c1849ee5 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -145,51 +145,50 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } -/// Compute or fill-in ciruit specific data from example. -/// \attention the example class is defined specifically for the BLS12-381 -/// curve, so make sure we are using this curve +// Derive circuit description in terms of polynomials from the (transposed) +// gates matrix and the wire permutation of the circuit. +// +// In addition, we also pass two more inputs: the value of the public +// input and the index of the row in which it is located in the non-transposed +// gates matrix. See "Enforcing public inputs:", Sect. 6, p.23 [GWC19]. +// +// TODO: change type of public_input and public_input_index to vector in order +// to handle the general case of multiple PIs template circuit_t plonk_circuit_description_from_example( - const plonk_example example) + const std::vector>> gates_matrix_transpose, + const std::vector wire_permutation, + const libff::Fr public_input, + const size_t public_input_index) { using Field = libff::Fr; - // public input (PI) - Field PI_value = example.public_input; - // index of the row of the PI in the non-transposed gates_matrix - int PI_index = example.public_input_index; - // Transposed gates matrix: each row is a q-vector - std::vector> gates_matrix_transpose = - example.gates_matrix_transpose; - // wire permutation - std::vector wire_permutation = example.wire_permutation; - // Generate domains on which to evaluate the witness - // polynomials. k1,k2 can be random, but we fix them for debug to - // match against the test vector values - libff::Fr k1 = example.k1; - libff::Fr k2 = example.k2; -#ifdef DEBUG_PLONK - printf("[%s:%d] k1 ", __FILE__, __LINE__); - k1.print(); - printf("[%s:%d] k2 ", __FILE__, __LINE__); - k2.print(); -#endif // #ifdef DEBUG_PLONK - - size_t num_gates = example.num_gates; + // the number of gates is equal to the number of columns in the transposed + // gates matrix + size_t num_gates = gates_matrix_transpose[0].size(); // ensure that num_gates is not 0 assert(num_gates > 0); // ensure num_gates is power of 2 assert((num_gates & (num_gates - 1)) == 0); - size_t num_qpolys = example.num_qpolys; + // the number of Q-polynomials (aka selector polynomials) is equal to the + // number of rows in the transposed gates matrix + size_t num_qpolys = gates_matrix_transpose.size(); - // We represent the constraints q_L, q_R, q_O, q_M, q_C and the - // witness w_L, w_R, w_O as polynomials in the roots of unity - // e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 + // the constraints q_L, q_R, q_O, q_M, q_C and the + // witness w_L, w_R, w_O are represented as polynomials in the roots of + // unity e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 std::shared_ptr> domain = libfqfft::get_evaluation_domain(num_gates); - // compute public input (PI) polynomial + // public_input (PI): e.g. PI is 35 for the example circuit P(x) = x**3 + x + // + 5 = 35 + Field PI_value = public_input; + // public_input_index: index of the row of the PI in the non-transposed + // (!) gates_matrix e.g. PI index is 4 in the example circuit (see + // example.hpp) + int PI_index = public_input_index; + // compute the PI polynomial polynomial PI_poly; std::vector PI_points(num_gates, Field(0)); PI_points[PI_index] = Field(-PI_value); @@ -203,7 +202,52 @@ circuit_t plonk_circuit_description_from_example( plonk_compute_selector_polynomials( num_gates, num_qpolys, gates_matrix_transpose, domain); - // omega[0] are the n roots of unity, omega[1] are omega[0]*k1, + // we need an example object here in order to copy the values for + // the constants k1,k2 (see more below). the latter are generated randomly, + // but we copy the hard-coded values here in order to match the test + // vectors. + plonk_example example; + // An explanation of the constants k1,k2 from [GWC19], Section 8, page 26 : + // + // "We explicitly define the multiplicative subgroup H as containing the + // n-th roots of unity in F_p , where w (omega) is a primitive n-th root of + // unity and a generator of H i.e: H = {1, w, ... , w^{n-1}}. We assume + // that the number of gates in a circuit is no more than n. We also include + // an optimisation suggested by Vitalik Buterin, to define the identity per- + // mutations through degree-1 polynomials. The identity permutations must + // map each wire value to a unique element \in F. This can be done by + // defining S_ID1(X) = X, S_ID2 (X) = k1 X, S_ID3(X) = k2 X [see below for + // more on S_ID1, S_ID2, S_ID3], where k1 , k2 are quadratic non-residues + // \in F. This effectively maps each wire value to a root of unity in H, + // with right and output wires having an additional multiplicative factor of + // k1, k2 applied respectively. By representing the identity permutation via + // degree-1 polynomials, their evaluations can be directly computed by the + // verifier. This reduces the size of the proof by 1 F element, as well as + // reducing the number of Fast-Fourier-Transforms required by the prover." + // + // Further in Sect. 8.1 [GWC19]: + // + // "S_ID1(X) = X, S_ID2(X) = k 1 X, S ID3 (X) = k 2 X: the identity + // permutation applied to a, b, c [the wire polynomials, see Round 1, p.27 + // [GWC19]]. k1, k2 \in F are chosen such that H, k1 H, k2 H are distinct + // cosets of H in F*, and thus consist of 3n distinct elements. (For + // example, when w (omega) is a quadratic residue in F, take k1 to be any + // quadratic non-residue, and k2 to be a quadratic non-residue not + // contained in k1 H.)" + + // Generate domains on which to evaluate the witness polynomials. k1,k2 can + // be random, but we fix them for debug to match against the test vector + // values. + libff::Fr k1 = example.k1; + libff::Fr k2 = example.k2; +#ifdef DEBUG_PLONK + printf("[%s:%d] k1 ", __FILE__, __LINE__); + k1.print(); + printf("[%s:%d] k2 ", __FILE__, __LINE__); + k2.print(); +#endif // #ifdef DEBUG_PLONK + + // omega[0] are the n roots of unity; omega[1] are omega[0]*k1; // omega[2] are omega[0]*k2 std::vector> omega_roots; plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); @@ -226,6 +270,7 @@ circuit_t plonk_circuit_description_from_example( // permute circuit.H_gen according to the wire permutation std::vector H_gen_permute = plonk_permute_subgroup_H(H_gen, wire_permutation, num_gates); + // TODO: write unit test for plonk_permute_subgroup_H #ifdef DEBUG_PLONK printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); @@ -494,8 +539,11 @@ template void test_plonk_prover_rounds() // example witness std::vector witness = example.witness; // example circuit - circuit_t circuit = - plonk_circuit_description_from_example(example); + circuit_t circuit = plonk_circuit_description_from_example( + example.gates_matrix_transpose, + example.wire_permutation, + example.public_input, + example.public_input_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -669,8 +717,11 @@ template void test_plonk_srs() // random hidden element secret (toxic waste) Field secret = example.secret; // example circuit - circuit_t circuit = - plonk_circuit_description_from_example(example); + circuit_t circuit = plonk_circuit_description_from_example( + example.gates_matrix_transpose, + example.wire_permutation, + example.public_input, + example.public_input_index); // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; @@ -715,8 +766,11 @@ template void test_plonk_prover() // example witness std::vector witness = example.witness; // example circuit - circuit_t circuit = - plonk_circuit_description_from_example(example); + circuit_t circuit = plonk_circuit_description_from_example( + example.gates_matrix_transpose, + example.wire_permutation, + example.public_input, + example.public_input_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -999,8 +1053,11 @@ template void test_plonk_verifier_steps() // example witness std::vector witness = example.witness; // example circuit - circuit_t circuit = - plonk_circuit_description_from_example(example); + circuit_t circuit = plonk_circuit_description_from_example( + example.gates_matrix_transpose, + example.wire_permutation, + example.public_input, + example.public_input_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1114,8 +1171,11 @@ template void test_plonk_verifier() // example witness std::vector witness = example.witness; // example circuit - circuit_t circuit = - plonk_circuit_description_from_example(example); + circuit_t circuit = plonk_circuit_description_from_example( + example.gates_matrix_transpose, + example.wire_permutation, + example.public_input, + example.public_input_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; From dc914ac67fc787f6b0cf046568b61d2777fe87a7 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 11 Nov 2022 08:33:52 +0000 Subject: [PATCH 103/154] plonk: updated example circuit description in comments in example.hpp --- .../zk_proof_systems/plonk/tests/example.hpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index de2431609..044e67b40 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -56,16 +56,18 @@ namespace libsnark /// /// wire polynomials /// -/// w_L = [ x, v1, v2, 1, 1, v3, /, /] = [a1, a2, a3, a4, a5, a6, a7, a8] = -/// a w_R = [ x, x, x, 5, 35, 5, /, /] = [b1, b2, b3, b4, b5, b6, b7, b8] -/// = b w_O = [v1, v2, v3, 5, 35, 35, /, /] = [c1, c2, c3, c4, c5, c6, c7, -/// c8] = c +/// w_L = [ x, v1, v2, 1, 1, v3, /, /] = [a1, a2, a3, a4, a5, a6, a7, a8] = a +/// w_R = [ x, x, x, 5, 35, 5, /, /] = [b1, b2, b3, b4, b5, b6, b7, b8] = b +/// w_O = [v1, v2, v3, 5, 35, 35, /, /] = [c1, c2, c3, c4, c5, c6, c7, c8] = c /// /// wires = [a1, a2, a3, a4, a5, a6, a7, a8, b1, b2, b3, b4, b5, b6, b7, b8, c1, -/// c2, c3, c4, c5, c6, c7, c8] index = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -/// 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] perm = [ 9, 17, 18, -/// 5, 4, 19, 7, 8, 10, 11, 1, 14, 21, 20, 15, 16, 2, 3, 6, 12, 22, 13, -/// 23, 24] +/// c2, c3, c4, c5, c6, c7, c8] +/// +/// index = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, +/// 18, 19, 20, 21, 22, 23, 24] +/// +/// perm = [ 9, 17, 18, 5, 4, 19, 7, 8, 10, 11, 1, 14, 21, 20, 15, 16, 2, +/// 3, 6, 12, 22, 13, 23, 24] /// /// witness /// From 5fae4244901629891edb20010e3c4cc99e47ad42 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 14 Nov 2022 13:30:40 +0000 Subject: [PATCH 104/154] plonk: renamed public_input and public_input_index respectively to PI_value and PI_gates_matrix_irow to better reflect the meaning of the two variables; edited comments. --- .../zk_proof_systems/plonk/tests/example.cpp | 4 +- .../zk_proof_systems/plonk/tests/example.hpp | 9 ++-- .../plonk/tests/test_plonk.cpp | 43 ++++++++++--------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.cpp b/libsnark/zk_proof_systems/plonk/tests/example.cpp index 9ab2bfcf9..4f4557e0d 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -115,10 +115,10 @@ plonk_example::plonk_example() 21, 20, 15, 16, 2, 3, 6, 12, 22, 13, 23, 24}; // public input (PI) - this->public_input = Field(35); + this->PI_value = Field(35); // index of the row of the PI in the non-transposed gates_matrix - this->public_input_index = 4; + this->PI_gates_matrix_irow = 4; // n-th root of unity omega in Fq (n=8 is the number of constraints // in the example). omega is a generator of the multiplicative diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 044e67b40..a38c01bd5 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -63,7 +63,7 @@ namespace libsnark /// wires = [a1, a2, a3, a4, a5, a6, a7, a8, b1, b2, b3, b4, b5, b6, b7, b8, c1, /// c2, c3, c4, c5, c6, c7, c8] /// -/// index = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, +/// index = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, /// 18, 19, 20, 21, 22, 23, 24] /// /// perm = [ 9, 17, 18, 5, 4, 19, 7, 8, 10, 11, 1, 14, 21, 20, 15, 16, 2, @@ -106,7 +106,6 @@ namespace libsnark /// q_O = [-1, -1, -1, 0, 0, 0, 0, 0] /// q_M = [ 1, 1, 0, 0, 0, -1, 0, 0] /// q_C = [ 0, 0, 0, -1, 0, 0, 0, 0] -// template class plonk_example class plonk_example { public: @@ -127,7 +126,7 @@ class plonk_example std::vector> gates_matrix; /// Transposed gates matrix: each row is a q-vector WARN: rows 2 - /// q_O and 3 q_M are swapped ti match the Plonk_Py test vectors + /// q_O and 3 q_M are swapped to match the Plonk_Py test vectors /// implementation (reason unclear) std::vector> gates_matrix_transpose; @@ -143,10 +142,10 @@ class plonk_example std::vector wire_permutation; /// public input (PI) - Field public_input; + Field PI_value; /// index of the row of the PI in the non-transposed gates_matrix - size_t public_input_index; + size_t PI_gates_matrix_irow; /// n-th root of unity omega in Fq (n=8 is the number of /// constraints in the example). omega is a generator of the diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 2c1849ee5..6e808d833 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -152,14 +152,22 @@ void test_verify_invalid_proof( // input and the index of the row in which it is located in the non-transposed // gates matrix. See "Enforcing public inputs:", Sect. 6, p.23 [GWC19]. // -// TODO: change type of public_input and public_input_index to vector in order +// PI_value (PI): e.g. PI is 35 for the example circuit P(x) = x**3 + x +// + 5 = 35 +// PI_gates_matrix_irow: index of the row of the PI in the non-transposed +// (!) gates_matrix e.g. PI index is 4 in the example circuit (see +// example.hpp). The row index is equal to the degree of x at the non-zero +// coefficient in the PI polynomial. So the PI polynomial in the example will be +// 35 x^4 . +// +// TODO: change type of PI_value and PI_gates_matrix_irow to vector in order // to handle the general case of multiple PIs template circuit_t plonk_circuit_description_from_example( const std::vector>> gates_matrix_transpose, const std::vector wire_permutation, - const libff::Fr public_input, - const size_t public_input_index) + const libff::Fr PI_value, + const size_t PI_gates_matrix_irow) { using Field = libff::Fr; @@ -181,17 +189,10 @@ circuit_t plonk_circuit_description_from_example( std::shared_ptr> domain = libfqfft::get_evaluation_domain(num_gates); - // public_input (PI): e.g. PI is 35 for the example circuit P(x) = x**3 + x - // + 5 = 35 - Field PI_value = public_input; - // public_input_index: index of the row of the PI in the non-transposed - // (!) gates_matrix e.g. PI index is 4 in the example circuit (see - // example.hpp) - int PI_index = public_input_index; // compute the PI polynomial polynomial PI_poly; std::vector PI_points(num_gates, Field(0)); - PI_points[PI_index] = Field(-PI_value); + PI_points[PI_gates_matrix_irow] = Field(-PI_value); plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); // compute the selector polynomials (q-polynomials) from the @@ -542,8 +543,8 @@ template void test_plonk_prover_rounds() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.public_input, - example.public_input_index); + example.PI_value, + example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -720,8 +721,8 @@ template void test_plonk_srs() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.public_input, - example.public_input_index); + example.PI_value, + example.PI_gates_matrix_irow); // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; @@ -769,8 +770,8 @@ template void test_plonk_prover() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.public_input, - example.public_input_index); + example.PI_value, + example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1056,8 +1057,8 @@ template void test_plonk_verifier_steps() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.public_input, - example.public_input_index); + example.PI_value, + example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1174,8 +1175,8 @@ template void test_plonk_verifier() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.public_input, - example.public_input_index); + example.PI_value, + example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; From 932d2a2622e0b20047ff44468882fb4ebf3ea645 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 14 Nov 2022 16:55:04 +0000 Subject: [PATCH 105/154] plonk: added wire indices of the public inputs to the srs. made corresponding changes to circuit and example classes and relevant function signatures. --- libsnark/zk_proof_systems/plonk/circuit.hpp | 4 ++++ libsnark/zk_proof_systems/plonk/circuit.tcc | 2 ++ libsnark/zk_proof_systems/plonk/srs.hpp | 4 ++++ libsnark/zk_proof_systems/plonk/srs.tcc | 3 +++ libsnark/zk_proof_systems/plonk/tests/example.cpp | 9 +++++++++ libsnark/zk_proof_systems/plonk/tests/example.hpp | 3 +++ libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 7 +++++++ 7 files changed, 32 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index bbffccb65..c1ae504c9 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -43,6 +43,9 @@ template struct circuit_t { /// Public input polynomial polynomial PI_poly; + /// Vector of indices of wires corresponding to public inputs (PI) + std::vector PI_wire_index; + /// Circuit selector polynomials (Q-polynomials) std::vector> Q_polys; @@ -69,6 +72,7 @@ template struct circuit_t { size_t num_gates, size_t num_qpolys, polynomial &&PI_poly, + std::vector &&PI_wire_index, std::vector> &&Q_polys, std::vector> &&S_polys, std::vector> &&omega_roots, diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 721b70fa8..151073a2c 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -23,6 +23,7 @@ circuit_t::circuit_t( size_t num_gates, size_t num_qpolys, polynomial &&PI_poly, + std::vector &&PI_wire_index, std::vector> &&Q_polys, std::vector> &&S_polys, std::vector> &&omega_roots, @@ -33,6 +34,7 @@ circuit_t::circuit_t( : num_gates(num_gates) , num_qpolys(num_qpolys) , PI_poly(PI_poly) + , PI_wire_index(PI_wire_index) , Q_polys(Q_polys) , S_polys(S_polys) , omega_roots(omega_roots) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index c7a2a413a..dbaf23a14 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -91,6 +91,9 @@ template class srs /// Public input polynomial polynomial PI_poly; + /// Vector of indices of wires corresponding to public inputs (PI) + std::vector PI_wire_index; + /// Circuit selector polynomials (Q-polynomials) std::vector> Q_polys; @@ -127,6 +130,7 @@ template class srs srs(const size_t &num_gates, const size_t &num_qpolys, const polynomial &PI_poly, + const std::vector &PI_wire_index, const std::vector> &Q_polys, const std::vector> &S_polys, const std::vector> &omega_roots, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 8c8fb25f6..97ea12d67 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -28,6 +28,7 @@ srs::srs( const size_t &num_gates, const size_t &num_qpolys, const polynomial &PI_poly, + const std::vector &PI_wire_index, const std::vector> &Q_polys, const std::vector> &S_polys, const std::vector> &omega_roots, @@ -41,6 +42,7 @@ srs::srs( : num_gates(num_gates) , num_qpolys(num_qpolys) , PI_poly(PI_poly) + , PI_wire_index(PI_wire_index) , Q_polys(Q_polys) , S_polys(S_polys) , omega_roots(omega_roots) @@ -134,6 +136,7 @@ srs plonk_srs_derive_from_usrs( circuit.num_gates, circuit.num_qpolys, circuit.PI_poly, + circuit.PI_wire_index, circuit.Q_polys, circuit.S_polys, circuit.omega_roots, diff --git a/libsnark/zk_proof_systems/plonk/tests/example.cpp b/libsnark/zk_proof_systems/plonk/tests/example.cpp index 4f4557e0d..b4eeedb5a 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -120,6 +120,15 @@ plonk_example::plonk_example() // index of the row of the PI in the non-transposed gates_matrix this->PI_gates_matrix_irow = 4; + // the example has 1 public input with wire index 12 (counting from 0) and + // value 35. it corresponds to the 4-th componnet of the w_R witness vector + // (counting from 0). in other words w_R[4]=35. recall that the full witness + // is = w_L + w_R + w_O (where '+' denotes concatentation). w_L has 8 + // components (since we have 8 gates == 6 "real" + 2 dummy) and the 4-th + // component of w_R is the PI (counting from 0), so it has wire index 8+4=12 + // (counting from 0). + this->PI_wire_index.push_back(12); + // n-th root of unity omega in Fq (n=8 is the number of constraints // in the example). omega is a generator of the multiplicative // subgroup H. Example (2**32)-th primitive root of unity in the diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index a38c01bd5..4450847f4 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -147,6 +147,9 @@ class plonk_example /// index of the row of the PI in the non-transposed gates_matrix size_t PI_gates_matrix_irow; + /// Vector of indices of wires corresponding to public inputs (PI) + std::vector PI_wire_index; + /// n-th root of unity omega in Fq (n=8 is the number of /// constraints in the example). omega is a generator of the /// multiplicative subgroup H. Example (2**32)-th primitive root diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 6e808d833..bb50dd334 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -166,6 +166,7 @@ template circuit_t plonk_circuit_description_from_example( const std::vector>> gates_matrix_transpose, const std::vector wire_permutation, + std::vector PI_wire_index, // TODO: make const const libff::Fr PI_value, const size_t PI_gates_matrix_irow) { @@ -291,6 +292,7 @@ circuit_t plonk_circuit_description_from_example( std::move(num_gates), std::move(num_qpolys), std::move(PI_poly), + std::move(PI_wire_index), std::move(Q_polys), std::move(S_polys), std::move(omega_roots), @@ -543,6 +545,7 @@ template void test_plonk_prover_rounds() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, + example.PI_wire_index, example.PI_value, example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from @@ -721,6 +724,7 @@ template void test_plonk_srs() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, + example.PI_wire_index, example.PI_value, example.PI_gates_matrix_irow); // maximum degree of the encoded monomials in the usrs @@ -770,6 +774,7 @@ template void test_plonk_prover() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, + example.PI_wire_index, example.PI_value, example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from @@ -1057,6 +1062,7 @@ template void test_plonk_verifier_steps() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, + example.PI_wire_index, example.PI_value, example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from @@ -1175,6 +1181,7 @@ template void test_plonk_verifier() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, + example.PI_wire_index, example.PI_value, example.PI_gates_matrix_irow); // hard-coded values for the "random" blinding constants from From 562229ccda6082104781cf552883075cc2b6e93f Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 15 Nov 2022 16:05:38 +0000 Subject: [PATCH 106/154] plonk: removed PI polynomial from srs, circuit and example. it is now computed in the prover and verifier from the PI wire indices, which are part of the srs. --- libsnark/zk_proof_systems/plonk/circuit.hpp | 4 --- libsnark/zk_proof_systems/plonk/circuit.tcc | 2 -- libsnark/zk_proof_systems/plonk/prover.tcc | 33 ++++++++++++++++++- libsnark/zk_proof_systems/plonk/srs.hpp | 4 --- libsnark/zk_proof_systems/plonk/srs.tcc | 3 -- .../plonk/tests/test_plonk.cpp | 31 ++++------------- libsnark/zk_proof_systems/plonk/verifier.tcc | 20 ++++++++++- 7 files changed, 57 insertions(+), 40 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp index c1ae504c9..7bd42da7d 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ b/libsnark/zk_proof_systems/plonk/circuit.hpp @@ -40,9 +40,6 @@ template struct circuit_t { /// vanilla Plonk proposal [GWC19]) size_t num_qpolys; - /// Public input polynomial - polynomial PI_poly; - /// Vector of indices of wires corresponding to public inputs (PI) std::vector PI_wire_index; @@ -71,7 +68,6 @@ template struct circuit_t { circuit_t( size_t num_gates, size_t num_qpolys, - polynomial &&PI_poly, std::vector &&PI_wire_index, std::vector> &&Q_polys, std::vector> &&S_polys, diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc index 151073a2c..4b1cb2712 100644 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ b/libsnark/zk_proof_systems/plonk/circuit.tcc @@ -22,7 +22,6 @@ template circuit_t::circuit_t( size_t num_gates, size_t num_qpolys, - polynomial &&PI_poly, std::vector &&PI_wire_index, std::vector> &&Q_polys, std::vector> &&S_polys, @@ -33,7 +32,6 @@ circuit_t::circuit_t( libff::Fr &&k2) : num_gates(num_gates) , num_qpolys(num_qpolys) - , PI_poly(PI_poly) , PI_wire_index(PI_wire_index) , Q_polys(Q_polys) , S_polys(S_polys) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 98a929340..6f2d533a5 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -195,6 +195,7 @@ round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, const libff::Fr &beta, const libff::Fr &gamma, + // const std::vector> &witness, // TODO const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, @@ -248,6 +249,36 @@ round_three_out_t plonk_prover::round_three( polynomial cqO; libfqfft::_polynomial_multiplication( cqO, round_one_out.W_polys_blinded[c], srs.Q_polys[O]); + + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(srs.num_gates); + + // compute PI polynomial from the PI_wire_index (stored in the srs) and + // the PI_value (stored in the witness) + // TODO: get from witness[srs.PI_wire_index] + std::vector PI_values = {Field(35)}; + + // by convention of this implementation the PI values are stored in the + // right input wire w_R (and not in the left input wire w_L as in [GWC19]). + // recall that the witness w is composed of left input w_L, right input w_R + // and output wires w_O (in this order) and so is the concatenation of w_L + // || w_R || w_O = w. each vector w_L, w_R and w_O of wire values is of + // length srs.num_gates and so in order to get the value of the PI[i] + // located at PI_wire_index[i] of w we need to do a modulo srs.num_gates + // operation (to skip the first srs.num_gates values stored in w_L). this is + // the reason for the following modulo srs.num_gates operation. + // TODO make example + std::vector PI_points(srs.num_gates, Field(0)); + for (size_t i = 0; i < PI_values.size(); i++) { + size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; + PI_points[PI_polynomial_power_of_x] = Field(-PI_values[i]); + } + assert(PI_points[4] == Field(-35)); + + // compute PI polynomial + polynomial PI_poly; + plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); + // t_part[0](x) = a(x)b(x)q_M(x) + a(x)q_L(x) + b(x)q_R(x) + c(x)q_O(x) + // PI(x) + q_C(x) polynomial poly_null{Field(0)}; @@ -255,7 +286,7 @@ round_three_out_t plonk_prover::round_three( libfqfft::_polynomial_addition(t_part[0], t_part[0], aqL); libfqfft::_polynomial_addition(t_part[0], t_part[0], bqR); libfqfft::_polynomial_addition(t_part[0], t_part[0], cqO); - libfqfft::_polynomial_addition(t_part[0], t_part[0], srs.PI_poly); + libfqfft::_polynomial_addition(t_part[0], t_part[0], PI_poly); libfqfft::_polynomial_addition(t_part[0], t_part[0], srs.Q_polys[C]); // --- Computation of t_part[1] diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index dbaf23a14..acc8b97d9 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -88,9 +88,6 @@ template class srs /// vanilla Plonk proposal [GWC19]) size_t num_qpolys; - /// Public input polynomial - polynomial PI_poly; - /// Vector of indices of wires corresponding to public inputs (PI) std::vector PI_wire_index; @@ -129,7 +126,6 @@ template class srs srs(const size_t &num_gates, const size_t &num_qpolys, - const polynomial &PI_poly, const std::vector &PI_wire_index, const std::vector> &Q_polys, const std::vector> &S_polys, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 97ea12d67..321a236ef 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -27,7 +27,6 @@ template srs::srs( const size_t &num_gates, const size_t &num_qpolys, - const polynomial &PI_poly, const std::vector &PI_wire_index, const std::vector> &Q_polys, const std::vector> &S_polys, @@ -41,7 +40,6 @@ srs::srs( const polynomial &L_basis_zero) : num_gates(num_gates) , num_qpolys(num_qpolys) - , PI_poly(PI_poly) , PI_wire_index(PI_wire_index) , Q_polys(Q_polys) , S_polys(S_polys) @@ -135,7 +133,6 @@ srs plonk_srs_derive_from_usrs( srs srs( circuit.num_gates, circuit.num_qpolys, - circuit.PI_poly, circuit.PI_wire_index, circuit.Q_polys, circuit.S_polys, diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index bb50dd334..7df2b0f53 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -166,9 +166,7 @@ template circuit_t plonk_circuit_description_from_example( const std::vector>> gates_matrix_transpose, const std::vector wire_permutation, - std::vector PI_wire_index, // TODO: make const - const libff::Fr PI_value, - const size_t PI_gates_matrix_irow) + std::vector PI_wire_index) // TODO: make const { using Field = libff::Fr; @@ -190,12 +188,6 @@ circuit_t plonk_circuit_description_from_example( std::shared_ptr> domain = libfqfft::get_evaluation_domain(num_gates); - // compute the PI polynomial - polynomial PI_poly; - std::vector PI_points(num_gates, Field(0)); - PI_points[PI_gates_matrix_irow] = Field(-PI_value); - plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); - // compute the selector polynomials (q-polynomials) from the // transposed gates matrix over the Lagrange basis q_poly = \sum_i // q[i] * L[i] where q[i] is a coefficient (a scalar Field @@ -291,7 +283,6 @@ circuit_t plonk_circuit_description_from_example( circuit_t circuit( std::move(num_gates), std::move(num_qpolys), - std::move(PI_poly), std::move(PI_wire_index), std::move(Q_polys), std::move(S_polys), @@ -545,9 +536,7 @@ template void test_plonk_prover_rounds() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.PI_wire_index, - example.PI_value, - example.PI_gates_matrix_irow); + example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -724,9 +713,7 @@ template void test_plonk_srs() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.PI_wire_index, - example.PI_value, - example.PI_gates_matrix_irow); + example.PI_wire_index); // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; @@ -774,9 +761,7 @@ template void test_plonk_prover() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.PI_wire_index, - example.PI_value, - example.PI_gates_matrix_irow); + example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1062,9 +1047,7 @@ template void test_plonk_verifier_steps() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.PI_wire_index, - example.PI_value, - example.PI_gates_matrix_irow); + example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1181,9 +1164,7 @@ template void test_plonk_verifier() circuit_t circuit = plonk_circuit_description_from_example( example.gates_matrix_transpose, example.wire_permutation, - example.PI_wire_index, - example.PI_value, - example.PI_gates_matrix_irow); + example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 2f1b423be..299b42473 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -153,9 +153,27 @@ template step_seven_out_t plonk_verifier::step_seven( const step_four_out_t &step_four_out, const srs &srs) { + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(srs.num_gates); + // construct the PI polynomial from the vector of PI values (received as + // input to the verifier) and the PI wire indices (stored in the srs) + // TODO: get from additional PI input + std::vector PI_values = {Field(35)}; + + std::vector PI_points(srs.num_gates, Field(0)); + for (size_t i = 0; i < PI_values.size(); i++) { + size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; + PI_points[PI_polynomial_power_of_x] = Field(-PI_values[i]); + } + assert(PI_points[4] == Field(-35)); + + // compute PI polynomial + polynomial PI_poly; + plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); + libff::Fr PI_zeta; PI_zeta = libfqfft::evaluate_polynomial( - srs.PI_poly.size(), srs.PI_poly, step_four_out.zeta); + PI_poly.size(), PI_poly, step_four_out.zeta); step_seven_out_t step_seven_out(std::move(PI_zeta)); return step_seven_out; } From 0069e9cd1c1be0bca12371c7ee726a8df1f0eba1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 16 Nov 2022 08:49:03 +0000 Subject: [PATCH 107/154] plonk: added the witness as an additional input to prover round_three. needed to access the wire indices of the public inputs in order to compute the public input polynomial. --- libsnark/zk_proof_systems/plonk/prover.hpp | 1 + libsnark/zk_proof_systems/plonk/prover.tcc | 69 +++++++++++++------ .../plonk/tests/test_plonk.cpp | 4 ++ 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.hpp b/libsnark/zk_proof_systems/plonk/prover.hpp index 5ed1bd6ee..0db33c1e4 100644 --- a/libsnark/zk_proof_systems/plonk/prover.hpp +++ b/libsnark/zk_proof_systems/plonk/prover.hpp @@ -321,6 +321,7 @@ template class plonk_prover const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, + const std::vector> &witness, const srs &srs, transcript_hasher &hasher); diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 6f2d533a5..74a99a212 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -195,10 +195,10 @@ round_three_out_t plonk_prover::round_three( const libff::Fr &alpha, const libff::Fr &beta, const libff::Fr &gamma, - // const std::vector> &witness, // TODO const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, + const std::vector> &witness, const srs &srs, transcript_hasher &hasher) { @@ -253,29 +253,57 @@ round_three_out_t plonk_prover::round_three( std::shared_ptr> domain = libfqfft::get_evaluation_domain(srs.num_gates); - // compute PI polynomial from the PI_wire_index (stored in the srs) and - // the PI_value (stored in the witness) - // TODO: get from witness[srs.PI_wire_index] - std::vector PI_values = {Field(35)}; - - // by convention of this implementation the PI values are stored in the - // right input wire w_R (and not in the left input wire w_L as in [GWC19]). - // recall that the witness w is composed of left input w_L, right input w_R - // and output wires w_O (in this order) and so is the concatenation of w_L - // || w_R || w_O = w. each vector w_L, w_R and w_O of wire values is of - // length srs.num_gates and so in order to get the value of the PI[i] - // located at PI_wire_index[i] of w we need to do a modulo srs.num_gates - // operation (to skip the first srs.num_gates values stored in w_L). this is - // the reason for the following modulo srs.num_gates operation. - // TODO make example + // Compute PI polynomial from the PI_wire_index (stored in the srs) and + // the PI_value (stored in the witness). By convention of this + // implementation the PI values are stored in the right input wire w_R (and + // not in the left input wire w_L as in [GWC19]). Recall that the witness w + // is composed of left input w_L, right input w_R and output wires w_O (in + // this order) and so is the concatenation of w_L || w_R || w_O = w. Each + // vector w_L, w_R and w_O of wire values is of length srs.num_gates and so + // in order to get the value of the i-th PI[i] located at PI_wire_index[i] + // of w we need to do a modulo srs.num_gates operation (to skip the first + // srs.num_gates values corresponding to w_L). This is the reason for the + // following modulo srs.num_gates operation. + // + // EXAMPLE + // + // Suppose that we have a circuit of 8 gates and the witness is w = w_L || + // w_R || w_O where (leftmost position corresponds to index 0): + // + // w_L = [ 3, 9,27, 1, 1,30, 0, 0] + // w_R = [ 3, 3, 3, 5,35, 5, 0, 0] + // w_O = [ 9,27,30, 5,35,35, 0, 0] + // + // so (leftmost position corresponds to index 0): + // + // w = [ 3,9,27,1,1,30,0,0,3,3,3,5,35,5,0,0,9,27,30,5,35,35,0,0] + // + // In this example circuit we have a single public input (PI) 35 first + // appearing at position 12 in w (counting from 0). In this case the vector + // srs.PI_wire_index will contain a single element srs.PI_wire_index[0] + // = 12. + // + // The value of the PI is extracted from the witness as PI_value = + // w[srs.PI_wire_index[0]] = w[12] = 35 + // + // To obtain the index of the PI in w_R we do a modulo num_gates (= 8) + // operation to skip the w_L vector (first 8 entries in w). Note that this + // index also corresponds to the power of x in the PI polynomial: + // + // power_of_x = srs.PI_wire_index[0] % num_gates = 12 % 8 = 4 + // + // Finally the PI polynomial is computed as + // + // PI_poly(x) = PI_value x^power_of_x = 35 x^4 std::vector PI_points(srs.num_gates, Field(0)); - for (size_t i = 0; i < PI_values.size(); i++) { + // loop over all wire indices that correspond to PIs + for (size_t i = 0; i < srs.PI_wire_index.size(); i++) { + Field PI_value = witness[srs.PI_wire_index[i]]; size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; - PI_points[PI_polynomial_power_of_x] = Field(-PI_values[i]); + PI_points[PI_polynomial_power_of_x] = Field(-PI_value); } assert(PI_points[4] == Field(-35)); - - // compute PI polynomial + // compute the PI polynomial polynomial PI_poly; plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); @@ -914,6 +942,7 @@ plonk_proof plonk_prover::compute_proof( round_zero_out, round_one_out, round_two_out, + witness, srs, hasher); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 7df2b0f53..9932844f3 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -398,6 +398,7 @@ void test_plonk_prover_round_three( const round_zero_out_t &round_zero_out, const round_one_out_t &round_one_out, const round_two_out_t &round_two_out, + const std::vector> &witness, const srs &srs, transcript_hasher &hasher) { @@ -409,6 +410,7 @@ void test_plonk_prover_round_three( round_zero_out, round_one_out, round_two_out, + witness, srs, hasher); printf("[%s:%d] Output from Round 3\n", __FILE__, __LINE__); @@ -624,6 +626,7 @@ template void test_plonk_prover_rounds() round_zero_out, round_one_out, round_two_out, + witness, srs, hasher); @@ -637,6 +640,7 @@ template void test_plonk_prover_rounds() round_zero_out, round_one_out, round_two_out, + witness, srs, hasher); // clear hash buffer From 65f377f9a740ac5ac2780933fc1b77c0c38428d8 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 16 Nov 2022 09:48:47 +0000 Subject: [PATCH 108/154] plonk: added the list of public input values as an additional input to the verifier --- libsnark/zk_proof_systems/plonk/prover.tcc | 1 - .../plonk/tests/test_plonk.cpp | 52 +++++++++++++------ libsnark/zk_proof_systems/plonk/verifier.hpp | 5 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 15 +++--- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 74a99a212..f15a164b8 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -302,7 +302,6 @@ round_three_out_t plonk_prover::round_three( size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; PI_points[PI_polynomial_power_of_x] = Field(-PI_value); } - assert(PI_points[4] == Field(-35)); // compute the PI polynomial polynomial PI_poly; plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 9932844f3..25455c717 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -38,6 +38,7 @@ template void test_verify_invalid_proof( const plonk_proof &valid_proof, const srs &srs, + const std::vector> &PI_value_list, transcript_hasher &hasher) { // initialize verifier @@ -60,7 +61,7 @@ void test_verify_invalid_proof( G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = proof.W_polys_blinded_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); } // manipulate [z]_1 @@ -68,7 +69,7 @@ void test_verify_invalid_proof( proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { @@ -77,7 +78,7 @@ void test_verify_invalid_proof( proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); } // manipulate \bar{a} @@ -85,63 +86,63 @@ void test_verify_invalid_proof( proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{b} hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{c} hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 hasher.buffer_clear(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate r_zeta hasher.buffer_clear(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; - b_accept = verifier.verify_proof(proof, srs, hasher); + b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); } @@ -894,10 +895,12 @@ template void test_plonk_verifier_step_seven( const plonk_example &example, const step_four_out_t &step_four_out, + const std::vector> &PI_value_list, const srs &srs) { const step_seven_out_t step_seven_out = - plonk_verifier::step_seven(step_four_out, srs); + plonk_verifier::step_seven( + step_four_out, PI_value_list, srs); printf("PI_zeta "); step_seven_out.PI_zeta.print(); ASSERT_EQ(step_seven_out.PI_zeta, example.PI_zeta); @@ -1082,6 +1085,13 @@ template void test_plonk_verifier_steps() test_plonk_verifier_preprocessed_input( example, srs); + // prepare the list of PI values for the example circuit + std::vector PI_value_list; + for (size_t i = 0; i < example.PI_wire_index.size(); i++) { + Field PI_value = example.witness[example.PI_wire_index[i]]; + PI_value_list.push_back(PI_value); + } + // compute step 4 const step_four_out_t step_four_out = plonk_verifier::step_four(proof, hasher); @@ -1096,7 +1106,7 @@ template void test_plonk_verifier_steps() // unit test verifier step 7 test_plonk_verifier_step_seven( - example, step_four_out, srs); + example, step_four_out, PI_value_list, srs); // unit test verifier step 8 const step_five_out_t step_five_out = @@ -1105,7 +1115,8 @@ template void test_plonk_verifier_steps() const step_six_out_t step_six_out = plonk_verifier::step_six(step_four_out, srs); const step_seven_out_t step_seven_out = - plonk_verifier::step_seven(step_four_out, srs); + plonk_verifier::step_seven( + step_four_out, PI_value_list, srs); test_plonk_verifier_step_eight( example, step_four_out, @@ -1197,8 +1208,15 @@ template void test_plonk_verifier() // initialize verifier plonk_verifier verifier; + // prepare the list of PI values for the example circuit + std::vector PI_value_list; + for (size_t i = 0; i < example.PI_wire_index.size(); i++) { + Field PI_value = example.witness[example.PI_wire_index[i]]; + PI_value_list.push_back(PI_value); + } // verify proof - bool b_valid_proof = verifier.verify_proof(proof, srs, hasher); + bool b_valid_proof = + verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_TRUE(b_valid_proof); // clear the hasher buffer in order to re-use the same @@ -1206,7 +1224,7 @@ template void test_plonk_verifier() hasher.buffer_clear(); // assert that proof verification fails when the proof is // manipulated - test_verify_invalid_proof(proof, srs, hasher); + test_verify_invalid_proof(proof, srs, PI_value_list, hasher); } TEST(TestPlonk, BLS12_381) diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index b4ce4f322..391917ed6 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -236,7 +236,9 @@ template class plonk_verifier /// OUTPUT /// \param[out] step_seven_out: see step_seven_out_t static step_seven_out_t step_seven( - const step_four_out_t &step_four_out, const srs &srs); + const step_four_out_t &step_four_out, + const std::vector &PI_value_list, + const srs &srs); /// Verifier Step 8: compute quotient polynomial evaluation r'(zeta) = /// r(zeta) - r0, where r0 is a constant term \note follows the Python @@ -377,6 +379,7 @@ template class plonk_verifier bool verify_proof( const plonk_proof &proof, const srs &srs, + const std::vector &PI_value_list, transcript_hasher &hasher); }; diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 299b42473..5224797c0 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -151,21 +151,19 @@ step_seven_out_t::step_seven_out_t(libff::Fr &&PI_zeta) template step_seven_out_t plonk_verifier::step_seven( - const step_four_out_t &step_four_out, const srs &srs) + const step_four_out_t &step_four_out, + const std::vector &PI_value_list, + const srs &srs) { std::shared_ptr> domain = libfqfft::get_evaluation_domain(srs.num_gates); // construct the PI polynomial from the vector of PI values (received as // input to the verifier) and the PI wire indices (stored in the srs) - // TODO: get from additional PI input - std::vector PI_values = {Field(35)}; - std::vector PI_points(srs.num_gates, Field(0)); - for (size_t i = 0; i < PI_values.size(); i++) { + for (size_t i = 0; i < PI_value_list.size(); i++) { size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; - PI_points[PI_polynomial_power_of_x] = Field(-PI_values[i]); + PI_points[PI_polynomial_power_of_x] = Field(-PI_value_list[i]); } - assert(PI_points[4] == Field(-35)); // compute PI polynomial polynomial PI_poly; @@ -416,6 +414,7 @@ template bool plonk_verifier::verify_proof( const plonk_proof &proof, const srs &srs, + const std::vector &PI_value_list, transcript_hasher &hasher) { std::shared_ptr>> domain = @@ -447,7 +446,7 @@ bool plonk_verifier::verify_proof( // Verifier Step 7: compute public input polynomial evaluation PI(zeta) const step_seven_out_t step_seven_out = - this->step_seven(step_four_out, srs); + this->step_seven(step_four_out, PI_value_list, srs); // Verifier Step 8: compute quotient polynomial evaluation // r'(zeta) = r(zeta) - r0, where r0 is a constant term From 36fb156ffee427e926c7444f4accaa8f6b8baa98 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 16 Nov 2022 11:14:44 +0000 Subject: [PATCH 109/154] plonk: added the gates matrix as input to the circuit description instead of its transpose. added function for transposing a matrix. --- .../plonk/tests/test_plonk.cpp | 45 +++++++++++-------- libsnark/zk_proof_systems/plonk/utils.hpp | 7 +++ libsnark/zk_proof_systems/plonk/utils.tcc | 18 ++++++++ 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 25455c717..f807c14d3 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -160,17 +160,19 @@ void test_verify_invalid_proof( // example.hpp). The row index is equal to the degree of x at the non-zero // coefficient in the PI polynomial. So the PI polynomial in the example will be // 35 x^4 . -// -// TODO: change type of PI_value and PI_gates_matrix_irow to vector in order -// to handle the general case of multiple PIs template circuit_t plonk_circuit_description_from_example( - const std::vector>> gates_matrix_transpose, + const std::vector>> gates_matrix, const std::vector wire_permutation, std::vector PI_wire_index) // TODO: make const { using Field = libff::Fr; + const size_t nrows = gates_matrix.size(); + const size_t ncols = gates_matrix[0].size(); + const std::vector> gates_matrix_transpose = + plonk_gates_matrix_transpose(gates_matrix, nrows, ncols); + // the number of gates is equal to the number of columns in the transposed // gates matrix size_t num_gates = gates_matrix_transpose[0].size(); @@ -537,9 +539,7 @@ template void test_plonk_prover_rounds() std::vector witness = example.witness; // example circuit circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix_transpose, - example.wire_permutation, - example.PI_wire_index); + example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -716,9 +716,7 @@ template void test_plonk_srs() Field secret = example.secret; // example circuit circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix_transpose, - example.wire_permutation, - example.PI_wire_index); + example.gates_matrix, example.wire_permutation, example.PI_wire_index); // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; @@ -764,9 +762,7 @@ template void test_plonk_prover() std::vector witness = example.witness; // example circuit circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix_transpose, - example.wire_permutation, - example.PI_wire_index); + example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1052,9 +1048,7 @@ template void test_plonk_verifier_steps() std::vector witness = example.witness; // example circuit circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix_transpose, - example.wire_permutation, - example.PI_wire_index); + example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1177,9 +1171,7 @@ template void test_plonk_verifier() std::vector witness = example.witness; // example circuit circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix_transpose, - example.wire_permutation, - example.PI_wire_index); + example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1227,6 +1219,20 @@ template void test_plonk_verifier() test_verify_invalid_proof(proof, srs, PI_value_list, hasher); } +/// \attention the example class is defined specifically for the BLS12-381 +/// curve, so make sure we are using this curve +template void test_plonk_gates_matrix_transpose() +{ + using Field = libff::Fr; + // load gates matrix from example circuit + plonk_example example; + size_t nrows = example.gates_matrix.size(); + size_t ncols = example.gates_matrix[0].size(); + std::vector> gates_matrix_transpose = + plonk_gates_matrix_transpose(example.gates_matrix, nrows, ncols); + ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); +} + TEST(TestPlonk, BLS12_381) { test_plonk_srs(); @@ -1242,6 +1248,7 @@ TEST(TestPlonk, BLS12_381) test_plonk_verifier< libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); + test_plonk_gates_matrix_transpose(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index b423db8c5..955c353a1 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -194,6 +194,13 @@ std::vector plonk_compute_accumulator( const std::vector &H_gen, // H, Hk1, Hk2 const std::vector &H_gen_permute); +/// transpose the gates matrix +template +std::vector> plonk_gates_matrix_transpose( + const std::vector> &gates_matrix, + const size_t &nrows, + const size_t &ncols); + } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/utils.tcc" diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 80a0dbe20..f464de9c3 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -297,6 +297,24 @@ std::vector plonk_compute_accumulator( return A; } +template +std::vector> plonk_gates_matrix_transpose( + const std::vector> &gates_matrix, + const size_t &nrows, + const size_t &ncols) +{ + size_t nrows_transpose = ncols; + size_t ncols_transpose = nrows; + std::vector> gates_matrix_transpose( + nrows_transpose, std::vector(ncols_transpose)); + for (size_t irow = 0; irow < nrows; ++irow) { + for (size_t icol = 0; icol < ncols; ++icol) { + gates_matrix_transpose[icol][irow] = gates_matrix[irow][icol]; + } + } + return gates_matrix_transpose; +} + } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ From 5a674e3f7d0746319a2e8e21df1a43739e97ac02 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 16 Nov 2022 11:46:13 +0000 Subject: [PATCH 110/154] plonk: modified plonk_srs_derive_from_usrs to accept usrs, gates matrix, wire permutation and a list of public input indices as input instead of a circuit_t structure --- libsnark/zk_proof_systems/plonk/srs.hpp | 15 +- libsnark/zk_proof_systems/plonk/srs.tcc | 151 ++++++++++++++++-- .../plonk/tests/test_plonk.cpp | 57 ++++--- 3 files changed, 173 insertions(+), 50 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index acc8b97d9..b28503d06 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -139,16 +139,15 @@ template class srs const polynomial &L_basis_zero); }; -/// Derive the (plain) SRS from the circuit description and the -/// USRS. The (plain) SRS is a specialization of the USRS for one -/// particular circuit i.e. -/// -/// usrs = -/// srs = (proving_key, verificataion_key) = derive(usrs, -/// circuit_description) +/// Derive the (plain) SRS from the USRS, the gates matrix, the wire permutation +/// and the list of public input (PI) indices. The (plain) SRS is a +/// specialization of the USRS for one particular circuit template srs plonk_srs_derive_from_usrs( - const usrs &usrs, const circuit_t &circuit); + const usrs &usrs, + const std::vector>> gates_matrix, + const std::vector wire_permutation, + const std::vector PI_wire_index); /// A proving key for Plonk template class plonk_proving_key diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 321a236ef..25afaeb79 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -106,12 +106,132 @@ usrs plonk_usrs_derive_from_secret( template srs plonk_srs_derive_from_usrs( - const usrs &usrs, const circuit_t &circuit) + const usrs &usrs, + const std::vector>> gates_matrix, + const std::vector wire_permutation, + const std::vector PI_wire_index) { + using Field = libff::Fr; + + const size_t nrows = gates_matrix.size(); + const size_t ncols = gates_matrix[0].size(); + const std::vector> gates_matrix_transpose = + plonk_gates_matrix_transpose(gates_matrix, nrows, ncols); + + // the number of gates is equal to the number of columns in the transposed + // gates matrix + size_t num_gates = gates_matrix_transpose[0].size(); + // ensure that num_gates is not 0 + assert(num_gates > 0); + // ensure num_gates is power of 2 + assert((num_gates & (num_gates - 1)) == 0); + + // the number of Q-polynomials (aka selector polynomials) is equal to the + // number of rows in the transposed gates matrix + size_t num_qpolys = gates_matrix_transpose.size(); + + // the constraints q_L, q_R, q_O, q_M, q_C and the + // witness w_L, w_R, w_O are represented as polynomials in the roots of + // unity e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(num_gates); + + // compute the selector polynomials (q-polynomials) from the + // transposed gates matrix over the Lagrange basis q_poly = \sum_i + // q[i] * L[i] where q[i] is a coefficient (a scalar Field + // element) and L[i] is a polynomial with Field coefficients + std::vector> Q_polys = + plonk_compute_selector_polynomials( + num_gates, num_qpolys, gates_matrix_transpose, domain); + + // we need an example object here in order to copy the values for + // the constants k1,k2 (see more below). the latter are generated randomly, + // but we copy the hard-coded values here in order to match the test + // vectors. + plonk_example example; + // An explanation of the constants k1,k2 from [GWC19], Section 8, page 26 : + // + // "We explicitly define the multiplicative subgroup H as containing the + // n-th roots of unity in F_p , where w (omega) is a primitive n-th root of + // unity and a generator of H i.e: H = {1, w, ... , w^{n-1}}. We assume + // that the number of gates in a circuit is no more than n. We also include + // an optimisation suggested by Vitalik Buterin, to define the identity per- + // mutations through degree-1 polynomials. The identity permutations must + // map each wire value to a unique element \in F. This can be done by + // defining S_ID1(X) = X, S_ID2 (X) = k1 X, S_ID3(X) = k2 X [see below for + // more on S_ID1, S_ID2, S_ID3], where k1 , k2 are quadratic non-residues + // \in F. This effectively maps each wire value to a root of unity in H, + // with right and output wires having an additional multiplicative factor of + // k1, k2 applied respectively. By representing the identity permutation via + // degree-1 polynomials, their evaluations can be directly computed by the + // verifier. This reduces the size of the proof by 1 F element, as well as + // reducing the number of Fast-Fourier-Transforms required by the prover." + // + // Further in Sect. 8.1 [GWC19]: + // + // "S_ID1(X) = X, S_ID2(X) = k 1 X, S ID3 (X) = k 2 X: the identity + // permutation applied to a, b, c [the wire polynomials, see Round 1, p.27 + // [GWC19]]. k1, k2 \in F are chosen such that H, k1 H, k2 H are distinct + // cosets of H in F*, and thus consist of 3n distinct elements. (For + // example, when w (omega) is a quadratic residue in F, take k1 to be any + // quadratic non-residue, and k2 to be a quadratic non-residue not + // contained in k1 H.)" + + // Generate domains on which to evaluate the witness polynomials. k1,k2 can + // be random, but we fix them for debug to match against the test vector + // values. + libff::Fr k1 = example.k1; + libff::Fr k2 = example.k2; +#ifdef DEBUG_PLONK + printf("[%s:%d] k1 ", __FILE__, __LINE__); + k1.print(); + printf("[%s:%d] k2 ", __FILE__, __LINE__); + k2.print(); +#endif // #ifdef DEBUG_PLONK + + // omega[0] are the n roots of unity; omega[1] are omega[0]*k1; + // omega[2] are omega[0]*k2 + std::vector> omega_roots; + plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); + + // H_gen contains the generators of H, k1 H and k2 H in one place + // ie. circuit.omega_roots, circuit.omega_roots_k1 and + // circuit.omega_roots_k2 + std::vector H_gen; + plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_gen); + + // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H +#ifdef DEBUG_PLONK + printf("[%s:%d] H_gen\n", __FILE__, __LINE__); + libff::print_vector(H_gen); + for (int i = 0; i < (int)H_gen.size(); ++i) { + assert(H_gen[i] == example.H_gen[i]); + } +#endif // #ifdef DEBUG_PLONK + + // permute circuit.H_gen according to the wire permutation + std::vector H_gen_permute = + plonk_permute_subgroup_H(H_gen, wire_permutation, num_gates); + + // TODO: write unit test for plonk_permute_subgroup_H +#ifdef DEBUG_PLONK + printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); + libff::print_vector(H_gen_permute); + for (size_t i = 0; i < H_gen_permute.size(); ++i) { + assert(H_gen_permute[i] == example.H_gen_permute[i]); + } +#endif // #ifdef DEBUG_PLONK + + // compute the permutation polynomials S_sigma_1, S_sigma_2, + // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) + std::vector> S_polys = + plonk_compute_permutation_polynomials( + H_gen_permute, num_gates, domain); + // secret^i * G1 std::vector> secret_powers_g1; - secret_powers_g1.reserve(circuit.num_gates + 3); - for (size_t i = 0; i < (circuit.num_gates + 3); ++i) { + secret_powers_g1.reserve(num_gates + 3); + for (size_t i = 0; i < (num_gates + 3); ++i) { secret_powers_g1.push_back(usrs.secret_powers_g1[i]); } // secret^i * G2 @@ -121,26 +241,23 @@ srs plonk_srs_derive_from_usrs( secret_powers_g2.push_back(usrs.secret_powers_g2[i]); } - std::shared_ptr>> domain = - libfqfft::get_evaluation_domain>(circuit.num_gates); - // compute 0-th Lagrange basis vector via inverse FFT - polynomial> u(circuit.num_gates, libff::Fr(0)); + polynomial> u(num_gates, libff::Fr(0)); u[0] = libff::Fr(1); domain->iFFT(u); polynomial> L_basis_zero = u; srs srs( - circuit.num_gates, - circuit.num_qpolys, - circuit.PI_wire_index, - circuit.Q_polys, - circuit.S_polys, - circuit.omega_roots, - circuit.H_gen, - circuit.H_gen_permute, - circuit.k1, - circuit.k2, + std::move(num_gates), + std::move(num_qpolys), + std::move(PI_wire_index), + std::move(Q_polys), + std::move(S_polys), + std::move(omega_roots), + std::move(H_gen), + std::move(H_gen_permute), + std::move(k1), + std::move(k2), std::move(secret_powers_g1), std::move(secret_powers_g2), std::move(L_basis_zero)); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index f807c14d3..8f2c681f9 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -537,9 +537,7 @@ template void test_plonk_prover_rounds() Field secret = example.secret; // example witness std::vector witness = example.witness; - // example circuit - circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix, example.wire_permutation, example.PI_wire_index); + // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -547,11 +545,15 @@ template void test_plonk_prover_rounds() size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); + libfqfft::get_evaluation_domain(example.num_gates); // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + srs srs = plonk_srs_derive_from_usrs( + usrs, + example.gates_matrix, + example.wire_permutation, + example.PI_wire_index); // initialize hasher transcript_hasher hasher; @@ -710,25 +712,27 @@ template void test_plonk_srs() using Field = libff::Fr; ppT::init_public_params(); + // load test vector values from example circuit plonk_example example; // random hidden element secret (toxic waste) Field secret = example.secret; - // example circuit - circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix, example.wire_permutation, example.PI_wire_index); // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); + libfqfft::get_evaluation_domain(example.num_gates); // --- USRS --- // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); // --- SRS --- - srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + srs srs = plonk_srs_derive_from_usrs( + usrs, + example.gates_matrix, + example.wire_permutation, + example.PI_wire_index); // compare SRS against reference test values printf("[%s:%d] secret ", __FILE__, __LINE__); secret.print(); @@ -760,9 +764,6 @@ template void test_plonk_prover() Field secret = example.secret; // example witness std::vector witness = example.witness; - // example circuit - circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -770,11 +771,15 @@ template void test_plonk_prover() size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); + libfqfft::get_evaluation_domain(example.num_gates); // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + srs srs = plonk_srs_derive_from_usrs( + usrs, + example.gates_matrix, + example.wire_permutation, + example.PI_wire_index); // initialize hasher transcript_hasher hasher; @@ -1046,9 +1051,6 @@ template void test_plonk_verifier_steps() Field secret = example.secret; // example witness std::vector witness = example.witness; - // example circuit - circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1056,11 +1058,15 @@ template void test_plonk_verifier_steps() size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); + libfqfft::get_evaluation_domain(example.num_gates); // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + srs srs = plonk_srs_derive_from_usrs( + usrs, + example.gates_matrix, + example.wire_permutation, + example.PI_wire_index); // initialize hasher transcript_hasher hasher; @@ -1169,9 +1175,6 @@ template void test_plonk_verifier() Field secret = example.secret; // example witness std::vector witness = example.witness; - // example circuit - circuit_t circuit = plonk_circuit_description_from_example( - example.gates_matrix, example.wire_permutation, example.PI_wire_index); // hard-coded values for the "random" blinding constants from // example circuit std::vector> blind_scalars = example.prover_blind_scalars; @@ -1179,11 +1182,15 @@ template void test_plonk_verifier() size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = - libfqfft::get_evaluation_domain(circuit.num_gates); + libfqfft::get_evaluation_domain(example.num_gates); // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs(usrs, circuit); + srs srs = plonk_srs_derive_from_usrs( + usrs, + example.gates_matrix, + example.wire_permutation, + example.PI_wire_index); // initialize hasher transcript_hasher hasher; From f77c8572a196a093a221fd461d59076ba40d0ff6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 16 Nov 2022 11:56:04 +0000 Subject: [PATCH 111/154] plonk: removed redundant circuit_t structure together with all related files and functions (circuit.hpp, circuit.cpp, plonk_circuit_description_from_example()) --- libsnark/zk_proof_systems/plonk/circuit.hpp | 85 ---------- libsnark/zk_proof_systems/plonk/circuit.tcc | 48 ------ libsnark/zk_proof_systems/plonk/srs.hpp | 1 + .../zk_proof_systems/plonk/tests/example.hpp | 1 - .../plonk/tests/test_plonk.cpp | 153 +----------------- 5 files changed, 2 insertions(+), 286 deletions(-) delete mode 100644 libsnark/zk_proof_systems/plonk/circuit.hpp delete mode 100644 libsnark/zk_proof_systems/plonk/circuit.tcc diff --git a/libsnark/zk_proof_systems/plonk/circuit.hpp b/libsnark/zk_proof_systems/plonk/circuit.hpp deleted file mode 100644 index 7bd42da7d..000000000 --- a/libsnark/zk_proof_systems/plonk/circuit.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libff, developed by Clearmatics Ltd - * (originally developed by SCIPR Lab) and contributors - * (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ -#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ - -#include "libsnark/zk_proof_systems/plonk/utils.hpp" - -#include - -/// Declaration of Common Preprocessed Input data structures for a -/// specific arithmetic circuit. -/// -/// This includes: -/// - class for common preprocessed input -/// -/// Reference: -/// - \[GWC19]: -/// Title: "Plonk: Permutations over lagrange-bases for oecumenical -/// noninteractive arguments of knowledge", Ariel Gabizon, Zachary -/// J. Williamson, and Oana Ciobotaru, Cryptology ePrint Archive, -/// Report 2019/953, 2019, - -namespace libsnark -{ - -/// Plonk circuit-specific data -template struct circuit_t { - using Field = libff::Fr; - - /// number of gates / constraints - size_t num_gates; - - /// number of selector polynomials (q-polynomials) (= 5 in the - /// vanilla Plonk proposal [GWC19]) - size_t num_qpolys; - - /// Vector of indices of wires corresponding to public inputs (PI) - std::vector PI_wire_index; - - /// Circuit selector polynomials (Q-polynomials) - std::vector> Q_polys; - - /// Permutation polynomials S_sigma_1, S_sigma_2, S_sigma_2 (see - /// [GWC19], Sect. 8.1) - std::vector> S_polys; - - /// omega[0] are the n roots of unity, omega[1] are omega[0]*k1, - /// omega[2] are omega[0]*k2 - std::vector> omega_roots; - - /// H_gen contains the generators of H, k1 H and k2 H in one place - /// ie. omega, omega_k1 and omega_k2 - std::vector H_gen; - - /// H_gen permuted according to the wire permutation - std::vector H_gen_permute; - - /// constants for H, k1 H, k2 H - libff::Fr k1; - libff::Fr k2; - - circuit_t( - size_t num_gates, - size_t num_qpolys, - std::vector &&PI_wire_index, - std::vector> &&Q_polys, - std::vector> &&S_polys, - std::vector> &&omega_roots, - std::vector &&H_gen, - std::vector &&H_gen_permute, - libff::Fr &&k1, - libff::Fr &&k2); -}; - -} // namespace libsnark - -#include "libsnark/zk_proof_systems/plonk/circuit.tcc" - -#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/circuit.tcc b/libsnark/zk_proof_systems/plonk/circuit.tcc deleted file mode 100644 index 4b1cb2712..000000000 --- a/libsnark/zk_proof_systems/plonk/circuit.tcc +++ /dev/null @@ -1,48 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libff, developed by Clearmatics Ltd - * (originally developed by SCIPR Lab) and contributors - * (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ -#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ - -// Implementation of Common Preprocessed Input interfaces for a -// ppzkSNARK for Plonk. See circuit.hpp . - -namespace libsnark -{ - -// TODO: add here function for describing the target circuit through -// the circuit_t structure - -template -circuit_t::circuit_t( - size_t num_gates, - size_t num_qpolys, - std::vector &&PI_wire_index, - std::vector> &&Q_polys, - std::vector> &&S_polys, - std::vector> &&omega_roots, - std::vector &&H_gen, - std::vector &&H_gen_permute, - libff::Fr &&k1, - libff::Fr &&k2) - : num_gates(num_gates) - , num_qpolys(num_qpolys) - , PI_wire_index(PI_wire_index) - , Q_polys(Q_polys) - , S_polys(S_polys) - , omega_roots(omega_roots) - , H_gen(H_gen) - , H_gen_permute(H_gen_permute) - , k1(k1) - , k2(k2) -{ -} - -} // namespace libsnark - -#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_CIRCUIT_TCC_ diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index b28503d06..0cf4ca8b5 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -27,6 +27,7 @@ /// Report 2019/953, 2019, #include "libsnark/common/data_structures/polynomial.hpp" +#include "libsnark/zk_proof_systems/plonk/utils.hpp" namespace libsnark { diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 4450847f4..954dbfc60 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -28,7 +28,6 @@ /// https://vitalik.ca/general/2019/09/22/plonk.html #include "libsnark/common/data_structures/polynomial.hpp" -#include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include #include diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 8f2c681f9..72378f12a 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -6,7 +6,6 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ -#include "libsnark/zk_proof_systems/plonk/circuit.hpp" #include "libsnark/zk_proof_systems/plonk/prover.hpp" #include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp" #include "libsnark/zk_proof_systems/plonk/verifier.hpp" @@ -15,6 +14,7 @@ #include #include #include +#include /// Test program that exercises the Plonk protocol (first setup, then /// prover, then verifier) on a synthetic R1CS instance. @@ -146,157 +146,6 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } -// Derive circuit description in terms of polynomials from the (transposed) -// gates matrix and the wire permutation of the circuit. -// -// In addition, we also pass two more inputs: the value of the public -// input and the index of the row in which it is located in the non-transposed -// gates matrix. See "Enforcing public inputs:", Sect. 6, p.23 [GWC19]. -// -// PI_value (PI): e.g. PI is 35 for the example circuit P(x) = x**3 + x -// + 5 = 35 -// PI_gates_matrix_irow: index of the row of the PI in the non-transposed -// (!) gates_matrix e.g. PI index is 4 in the example circuit (see -// example.hpp). The row index is equal to the degree of x at the non-zero -// coefficient in the PI polynomial. So the PI polynomial in the example will be -// 35 x^4 . -template -circuit_t plonk_circuit_description_from_example( - const std::vector>> gates_matrix, - const std::vector wire_permutation, - std::vector PI_wire_index) // TODO: make const -{ - using Field = libff::Fr; - - const size_t nrows = gates_matrix.size(); - const size_t ncols = gates_matrix[0].size(); - const std::vector> gates_matrix_transpose = - plonk_gates_matrix_transpose(gates_matrix, nrows, ncols); - - // the number of gates is equal to the number of columns in the transposed - // gates matrix - size_t num_gates = gates_matrix_transpose[0].size(); - // ensure that num_gates is not 0 - assert(num_gates > 0); - // ensure num_gates is power of 2 - assert((num_gates & (num_gates - 1)) == 0); - - // the number of Q-polynomials (aka selector polynomials) is equal to the - // number of rows in the transposed gates matrix - size_t num_qpolys = gates_matrix_transpose.size(); - - // the constraints q_L, q_R, q_O, q_M, q_C and the - // witness w_L, w_R, w_O are represented as polynomials in the roots of - // unity e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 - std::shared_ptr> domain = - libfqfft::get_evaluation_domain(num_gates); - - // compute the selector polynomials (q-polynomials) from the - // transposed gates matrix over the Lagrange basis q_poly = \sum_i - // q[i] * L[i] where q[i] is a coefficient (a scalar Field - // element) and L[i] is a polynomial with Field coefficients - std::vector> Q_polys = - plonk_compute_selector_polynomials( - num_gates, num_qpolys, gates_matrix_transpose, domain); - - // we need an example object here in order to copy the values for - // the constants k1,k2 (see more below). the latter are generated randomly, - // but we copy the hard-coded values here in order to match the test - // vectors. - plonk_example example; - // An explanation of the constants k1,k2 from [GWC19], Section 8, page 26 : - // - // "We explicitly define the multiplicative subgroup H as containing the - // n-th roots of unity in F_p , where w (omega) is a primitive n-th root of - // unity and a generator of H i.e: H = {1, w, ... , w^{n-1}}. We assume - // that the number of gates in a circuit is no more than n. We also include - // an optimisation suggested by Vitalik Buterin, to define the identity per- - // mutations through degree-1 polynomials. The identity permutations must - // map each wire value to a unique element \in F. This can be done by - // defining S_ID1(X) = X, S_ID2 (X) = k1 X, S_ID3(X) = k2 X [see below for - // more on S_ID1, S_ID2, S_ID3], where k1 , k2 are quadratic non-residues - // \in F. This effectively maps each wire value to a root of unity in H, - // with right and output wires having an additional multiplicative factor of - // k1, k2 applied respectively. By representing the identity permutation via - // degree-1 polynomials, their evaluations can be directly computed by the - // verifier. This reduces the size of the proof by 1 F element, as well as - // reducing the number of Fast-Fourier-Transforms required by the prover." - // - // Further in Sect. 8.1 [GWC19]: - // - // "S_ID1(X) = X, S_ID2(X) = k 1 X, S ID3 (X) = k 2 X: the identity - // permutation applied to a, b, c [the wire polynomials, see Round 1, p.27 - // [GWC19]]. k1, k2 \in F are chosen such that H, k1 H, k2 H are distinct - // cosets of H in F*, and thus consist of 3n distinct elements. (For - // example, when w (omega) is a quadratic residue in F, take k1 to be any - // quadratic non-residue, and k2 to be a quadratic non-residue not - // contained in k1 H.)" - - // Generate domains on which to evaluate the witness polynomials. k1,k2 can - // be random, but we fix them for debug to match against the test vector - // values. - libff::Fr k1 = example.k1; - libff::Fr k2 = example.k2; -#ifdef DEBUG_PLONK - printf("[%s:%d] k1 ", __FILE__, __LINE__); - k1.print(); - printf("[%s:%d] k2 ", __FILE__, __LINE__); - k2.print(); -#endif // #ifdef DEBUG_PLONK - - // omega[0] are the n roots of unity; omega[1] are omega[0]*k1; - // omega[2] are omega[0]*k2 - std::vector> omega_roots; - plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); - - // H_gen contains the generators of H, k1 H and k2 H in one place - // ie. circuit.omega_roots, circuit.omega_roots_k1 and - // circuit.omega_roots_k2 - std::vector H_gen; - plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_gen); - - // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H -#ifdef DEBUG_PLONK - printf("[%s:%d] H_gen\n", __FILE__, __LINE__); - libff::print_vector(H_gen); - for (int i = 0; i < (int)H_gen.size(); ++i) { - assert(H_gen[i] == example.H_gen[i]); - } -#endif // #ifdef DEBUG_PLONK - - // permute circuit.H_gen according to the wire permutation - std::vector H_gen_permute = - plonk_permute_subgroup_H(H_gen, wire_permutation, num_gates); - - // TODO: write unit test for plonk_permute_subgroup_H -#ifdef DEBUG_PLONK - printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); - libff::print_vector(H_gen_permute); - for (size_t i = 0; i < H_gen_permute.size(); ++i) { - assert(H_gen_permute[i] == example.H_gen_permute[i]); - } -#endif // #ifdef DEBUG_PLONK - - // compute the permutation polynomials S_sigma_1, S_sigma_2, - // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) - std::vector> S_polys = - plonk_compute_permutation_polynomials( - H_gen_permute, num_gates, domain); - - circuit_t circuit( - std::move(num_gates), - std::move(num_qpolys), - std::move(PI_wire_index), - std::move(Q_polys), - std::move(S_polys), - std::move(omega_roots), - std::move(H_gen), - std::move(H_gen_permute), - std::move(k1), - std::move(k2)); - return circuit; -} - template void test_plonk_compute_accumulator( const plonk_example &example, From c038bd35785c76f27b65fbcbdeaecb88c5d83c04 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 16 Nov 2022 13:53:20 +0000 Subject: [PATCH 112/154] plonk: hard-coded the values for k1 and k2 instead of loading them from the example class (Issue https://github.com/clearmatics/libsnark/issues/87) --- libsnark/zk_proof_systems/plonk/srs.tcc | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 25afaeb79..c61c8f298 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -144,11 +144,6 @@ srs plonk_srs_derive_from_usrs( plonk_compute_selector_polynomials( num_gates, num_qpolys, gates_matrix_transpose, domain); - // we need an example object here in order to copy the values for - // the constants k1,k2 (see more below). the latter are generated randomly, - // but we copy the hard-coded values here in order to match the test - // vectors. - plonk_example example; // An explanation of the constants k1,k2 from [GWC19], Section 8, page 26 : // // "We explicitly define the multiplicative subgroup H as containing the @@ -176,12 +171,13 @@ srs plonk_srs_derive_from_usrs( // example, when w (omega) is a quadratic residue in F, take k1 to be any // quadratic non-residue, and k2 to be a quadratic non-residue not // contained in k1 H.)" - - // Generate domains on which to evaluate the witness polynomials. k1,k2 can - // be random, but we fix them for debug to match against the test vector - // values. - libff::Fr k1 = example.k1; - libff::Fr k2 = example.k2; + // + // For the moment k1,k2 are fixed to the test vector values for debug + // purpouses. TODO choose k1,k2 according to the requirements in [GWC19] + libff::Fr k1 = + Field("706987411474581393682955260879121390206111740035659671471" + "3673571023200548519"); + libff::Fr k2 = libff::power(k1, libff::bigint<1>(2)); #ifdef DEBUG_PLONK printf("[%s:%d] k1 ", __FILE__, __LINE__); k1.print(); From c94ce10867db67e5d242b74f840b1af79c4231ce Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 10:25:38 +0000 Subject: [PATCH 113/154] plonk: removed debug checks using the exampe class which is out of scope; fixed unsigned assert compilation error. --- libsnark/zk_proof_systems/plonk/srs.tcc | 16 ++-------------- libsnark/zk_proof_systems/plonk/utils.tcc | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index c61c8f298..b2b8acbc5 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -197,26 +197,14 @@ srs plonk_srs_derive_from_usrs( plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_gen); // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H -#ifdef DEBUG_PLONK - printf("[%s:%d] H_gen\n", __FILE__, __LINE__); - libff::print_vector(H_gen); - for (int i = 0; i < (int)H_gen.size(); ++i) { - assert(H_gen[i] == example.H_gen[i]); - } -#endif // #ifdef DEBUG_PLONK + // assert(H_gen[i] == example.H_gen[i]); // permute circuit.H_gen according to the wire permutation std::vector H_gen_permute = plonk_permute_subgroup_H(H_gen, wire_permutation, num_gates); // TODO: write unit test for plonk_permute_subgroup_H -#ifdef DEBUG_PLONK - printf("[%s:%d] H_gen_permute\n", __FILE__, __LINE__); - libff::print_vector(H_gen_permute); - for (size_t i = 0; i < H_gen_permute.size(); ++i) { - assert(H_gen_permute[i] == example.H_gen_permute[i]); - } -#endif // #ifdef DEBUG_PLONK + // assert(H_gen_permute[i] == example.H_gen_permute[i]); // compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index f464de9c3..2bbaede9b 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -248,7 +248,7 @@ FieldT plonk_compute_accumulator_factor( const std::vector &A) { assert(num_gates); - assert((i >= 0) && (i < num_gates)); + assert(i < num_gates); assert(witness.size() == (NUM_HSETS * num_gates)); assert(H_gen.size() == (NUM_HSETS * num_gates)); assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); From b887d218442c834901ab00905f2e6f4da1f96547 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 11:10:49 +0000 Subject: [PATCH 114/154] plonk: changed variable name *_power_of_x to *_coordinate_x in PI polynomial computation to reflect correctly the logic of the code; edited related comments (https://github.com/clearmatics/libsnark/pull/91#discussion_r1024984706) --- libsnark/zk_proof_systems/plonk/prover.tcc | 19 ++++++------------- libsnark/zk_proof_systems/plonk/verifier.tcc | 4 ++-- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index f15a164b8..b1a99dcb7 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -258,12 +258,12 @@ round_three_out_t plonk_prover::round_three( // implementation the PI values are stored in the right input wire w_R (and // not in the left input wire w_L as in [GWC19]). Recall that the witness w // is composed of left input w_L, right input w_R and output wires w_O (in - // this order) and so is the concatenation of w_L || w_R || w_O = w. Each + // this order) and so w is the concatenation of w_L || w_R || w_O = w. Each // vector w_L, w_R and w_O of wire values is of length srs.num_gates and so // in order to get the value of the i-th PI[i] located at PI_wire_index[i] // of w we need to do a modulo srs.num_gates operation (to skip the first // srs.num_gates values corresponding to w_L). This is the reason for the - // following modulo srs.num_gates operation. + // modulo srs.num_gates operation in the code below. // // EXAMPLE // @@ -287,22 +287,15 @@ round_three_out_t plonk_prover::round_three( // w[srs.PI_wire_index[0]] = w[12] = 35 // // To obtain the index of the PI in w_R we do a modulo num_gates (= 8) - // operation to skip the w_L vector (first 8 entries in w). Note that this - // index also corresponds to the power of x in the PI polynomial: - // - // power_of_x = srs.PI_wire_index[0] % num_gates = 12 % 8 = 4 - // - // Finally the PI polynomial is computed as - // - // PI_poly(x) = PI_value x^power_of_x = 35 x^4 + // operation to skip the w_L vector (first 8 entries in w). std::vector PI_points(srs.num_gates, Field(0)); // loop over all wire indices that correspond to PIs for (size_t i = 0; i < srs.PI_wire_index.size(); i++) { Field PI_value = witness[srs.PI_wire_index[i]]; - size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; - PI_points[PI_polynomial_power_of_x] = Field(-PI_value); + size_t PI_coordinate_x = srs.PI_wire_index[i] % srs.num_gates; + PI_points[PI_coordinate_x] = Field(-PI_value); } - // compute the PI polynomial + // compute the PI polynomial from the list of points using iFFT polynomial PI_poly; plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 5224797c0..8204e4113 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -161,8 +161,8 @@ step_seven_out_t plonk_verifier::step_seven( // input to the verifier) and the PI wire indices (stored in the srs) std::vector PI_points(srs.num_gates, Field(0)); for (size_t i = 0; i < PI_value_list.size(); i++) { - size_t PI_polynomial_power_of_x = srs.PI_wire_index[i] % srs.num_gates; - PI_points[PI_polynomial_power_of_x] = Field(-PI_value_list[i]); + size_t PI_coordinate_x = srs.PI_wire_index[i] % srs.num_gates; + PI_points[PI_coordinate_x] = Field(-PI_value_list[i]); } // compute PI polynomial From e5f1ca74963ab84f9660adbdb40b2c9dfdd7e1cd Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 11:20:31 +0000 Subject: [PATCH 115/154] plonk: changed variable name PI_wire_index to PI_wire_indices (https://github.com/clearmatics/libsnark/pull/91#discussion_r1024994778) --- libsnark/zk_proof_systems/plonk/prover.tcc | 14 +++++++------- libsnark/zk_proof_systems/plonk/srs.hpp | 6 +++--- libsnark/zk_proof_systems/plonk/srs.tcc | 8 ++++---- .../zk_proof_systems/plonk/tests/example.cpp | 2 +- .../zk_proof_systems/plonk/tests/example.hpp | 2 +- .../plonk/tests/test_plonk.cpp | 18 +++++++++--------- libsnark/zk_proof_systems/plonk/verifier.tcc | 2 +- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index b1a99dcb7..3ed641e83 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -253,14 +253,14 @@ round_three_out_t plonk_prover::round_three( std::shared_ptr> domain = libfqfft::get_evaluation_domain(srs.num_gates); - // Compute PI polynomial from the PI_wire_index (stored in the srs) and + // Compute PI polynomial from the PI_wire_indices (stored in the srs) and // the PI_value (stored in the witness). By convention of this // implementation the PI values are stored in the right input wire w_R (and // not in the left input wire w_L as in [GWC19]). Recall that the witness w // is composed of left input w_L, right input w_R and output wires w_O (in // this order) and so w is the concatenation of w_L || w_R || w_O = w. Each // vector w_L, w_R and w_O of wire values is of length srs.num_gates and so - // in order to get the value of the i-th PI[i] located at PI_wire_index[i] + // in order to get the value of the i-th PI[i] located at PI_wire_indices[i] // of w we need to do a modulo srs.num_gates operation (to skip the first // srs.num_gates values corresponding to w_L). This is the reason for the // modulo srs.num_gates operation in the code below. @@ -280,19 +280,19 @@ round_three_out_t plonk_prover::round_three( // // In this example circuit we have a single public input (PI) 35 first // appearing at position 12 in w (counting from 0). In this case the vector - // srs.PI_wire_index will contain a single element srs.PI_wire_index[0] + // srs.PI_wire_indices will contain a single element srs.PI_wire_indices[0] // = 12. // // The value of the PI is extracted from the witness as PI_value = - // w[srs.PI_wire_index[0]] = w[12] = 35 + // w[srs.PI_wire_indices[0]] = w[12] = 35 // // To obtain the index of the PI in w_R we do a modulo num_gates (= 8) // operation to skip the w_L vector (first 8 entries in w). std::vector PI_points(srs.num_gates, Field(0)); // loop over all wire indices that correspond to PIs - for (size_t i = 0; i < srs.PI_wire_index.size(); i++) { - Field PI_value = witness[srs.PI_wire_index[i]]; - size_t PI_coordinate_x = srs.PI_wire_index[i] % srs.num_gates; + for (size_t i = 0; i < srs.PI_wire_indices.size(); i++) { + Field PI_value = witness[srs.PI_wire_indices[i]]; + size_t PI_coordinate_x = srs.PI_wire_indices[i] % srs.num_gates; PI_points[PI_coordinate_x] = Field(-PI_value); } // compute the PI polynomial from the list of points using iFFT diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 0cf4ca8b5..bd50c4e87 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -90,7 +90,7 @@ template class srs size_t num_qpolys; /// Vector of indices of wires corresponding to public inputs (PI) - std::vector PI_wire_index; + std::vector PI_wire_indices; /// Circuit selector polynomials (Q-polynomials) std::vector> Q_polys; @@ -127,7 +127,7 @@ template class srs srs(const size_t &num_gates, const size_t &num_qpolys, - const std::vector &PI_wire_index, + const std::vector &PI_wire_indices, const std::vector> &Q_polys, const std::vector> &S_polys, const std::vector> &omega_roots, @@ -148,7 +148,7 @@ srs plonk_srs_derive_from_usrs( const usrs &usrs, const std::vector>> gates_matrix, const std::vector wire_permutation, - const std::vector PI_wire_index); + const std::vector PI_wire_indices); /// A proving key for Plonk template class plonk_proving_key diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index b2b8acbc5..039efe6d0 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -27,7 +27,7 @@ template srs::srs( const size_t &num_gates, const size_t &num_qpolys, - const std::vector &PI_wire_index, + const std::vector &PI_wire_indices, const std::vector> &Q_polys, const std::vector> &S_polys, const std::vector> &omega_roots, @@ -40,7 +40,7 @@ srs::srs( const polynomial &L_basis_zero) : num_gates(num_gates) , num_qpolys(num_qpolys) - , PI_wire_index(PI_wire_index) + , PI_wire_indices(PI_wire_indices) , Q_polys(Q_polys) , S_polys(S_polys) , omega_roots(omega_roots) @@ -109,7 +109,7 @@ srs plonk_srs_derive_from_usrs( const usrs &usrs, const std::vector>> gates_matrix, const std::vector wire_permutation, - const std::vector PI_wire_index) + const std::vector PI_wire_indices) { using Field = libff::Fr; @@ -234,7 +234,7 @@ srs plonk_srs_derive_from_usrs( srs srs( std::move(num_gates), std::move(num_qpolys), - std::move(PI_wire_index), + std::move(PI_wire_indices), std::move(Q_polys), std::move(S_polys), std::move(omega_roots), diff --git a/libsnark/zk_proof_systems/plonk/tests/example.cpp b/libsnark/zk_proof_systems/plonk/tests/example.cpp index b4eeedb5a..89c8fc8bb 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -127,7 +127,7 @@ plonk_example::plonk_example() // components (since we have 8 gates == 6 "real" + 2 dummy) and the 4-th // component of w_R is the PI (counting from 0), so it has wire index 8+4=12 // (counting from 0). - this->PI_wire_index.push_back(12); + this->PI_wire_indices.push_back(12); // n-th root of unity omega in Fq (n=8 is the number of constraints // in the example). omega is a generator of the multiplicative diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 954dbfc60..70addc2fa 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -147,7 +147,7 @@ class plonk_example size_t PI_gates_matrix_irow; /// Vector of indices of wires corresponding to public inputs (PI) - std::vector PI_wire_index; + std::vector PI_wire_indices; /// n-th root of unity omega in Fq (n=8 is the number of /// constraints in the example). omega is a generator of the diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 72378f12a..f69130679 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -402,7 +402,7 @@ template void test_plonk_prover_rounds() usrs, example.gates_matrix, example.wire_permutation, - example.PI_wire_index); + example.PI_wire_indices); // initialize hasher transcript_hasher hasher; @@ -581,7 +581,7 @@ template void test_plonk_srs() usrs, example.gates_matrix, example.wire_permutation, - example.PI_wire_index); + example.PI_wire_indices); // compare SRS against reference test values printf("[%s:%d] secret ", __FILE__, __LINE__); secret.print(); @@ -628,7 +628,7 @@ template void test_plonk_prover() usrs, example.gates_matrix, example.wire_permutation, - example.PI_wire_index); + example.PI_wire_indices); // initialize hasher transcript_hasher hasher; @@ -915,7 +915,7 @@ template void test_plonk_verifier_steps() usrs, example.gates_matrix, example.wire_permutation, - example.PI_wire_index); + example.PI_wire_indices); // initialize hasher transcript_hasher hasher; @@ -936,8 +936,8 @@ template void test_plonk_verifier_steps() // prepare the list of PI values for the example circuit std::vector PI_value_list; - for (size_t i = 0; i < example.PI_wire_index.size(); i++) { - Field PI_value = example.witness[example.PI_wire_index[i]]; + for (size_t i = 0; i < example.PI_wire_indices.size(); i++) { + Field PI_value = example.witness[example.PI_wire_indices[i]]; PI_value_list.push_back(PI_value); } @@ -1039,7 +1039,7 @@ template void test_plonk_verifier() usrs, example.gates_matrix, example.wire_permutation, - example.PI_wire_index); + example.PI_wire_indices); // initialize hasher transcript_hasher hasher; @@ -1058,8 +1058,8 @@ template void test_plonk_verifier() plonk_verifier verifier; // prepare the list of PI values for the example circuit std::vector PI_value_list; - for (size_t i = 0; i < example.PI_wire_index.size(); i++) { - Field PI_value = example.witness[example.PI_wire_index[i]]; + for (size_t i = 0; i < example.PI_wire_indices.size(); i++) { + Field PI_value = example.witness[example.PI_wire_indices[i]]; PI_value_list.push_back(PI_value); } // verify proof diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 8204e4113..8cda463b2 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -161,7 +161,7 @@ step_seven_out_t plonk_verifier::step_seven( // input to the verifier) and the PI wire indices (stored in the srs) std::vector PI_points(srs.num_gates, Field(0)); for (size_t i = 0; i < PI_value_list.size(); i++) { - size_t PI_coordinate_x = srs.PI_wire_index[i] % srs.num_gates; + size_t PI_coordinate_x = srs.PI_wire_indices[i] % srs.num_gates; PI_points[PI_coordinate_x] = Field(-PI_value_list[i]); } From 1e685091fae1bb705d5f089d68bd608c2043b984 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 11:24:23 +0000 Subject: [PATCH 116/154] plonk: removed redundant debug info (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025008153) --- libsnark/zk_proof_systems/plonk/srs.tcc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 039efe6d0..04d1e1aea 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -178,12 +178,6 @@ srs plonk_srs_derive_from_usrs( Field("706987411474581393682955260879121390206111740035659671471" "3673571023200548519"); libff::Fr k2 = libff::power(k1, libff::bigint<1>(2)); -#ifdef DEBUG_PLONK - printf("[%s:%d] k1 ", __FILE__, __LINE__); - k1.print(); - printf("[%s:%d] k2 ", __FILE__, __LINE__); - k2.print(); -#endif // #ifdef DEBUG_PLONK // omega[0] are the n roots of unity; omega[1] are omega[0]*k1; // omega[2] are omega[0]*k2 From bec34ee6adfe21b46b5e554e1b460bb2ff09b775 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 11:26:51 +0000 Subject: [PATCH 117/154] plonk: fixed comment to refer to the correct function name (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025009791) --- libsnark/zk_proof_systems/plonk/srs.tcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 04d1e1aea..4cb8e6857 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -190,7 +190,7 @@ srs plonk_srs_derive_from_usrs( std::vector H_gen; plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_gen); - // TODO: write unit test for plonk_roots_of_unity_omega_to_subgroup_H + // TODO: write unit test for plonk_compute_cosets_H_k1H_k2H // assert(H_gen[i] == example.H_gen[i]); // permute circuit.H_gen according to the wire permutation From ae7eadc586a4ebf59b6b9f42383f4277f56e30e0 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 11:34:19 +0000 Subject: [PATCH 118/154] plonk: removed obsolete macro DEBUG_PLONK (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025070404) --- libsnark/zk_proof_systems/plonk/prover.tcc | 10 +++------- libsnark/zk_proof_systems/plonk/utils.hpp | 5 ----- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 3ed641e83..961fa340c 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -669,9 +669,7 @@ round_five_out_t plonk_prover::round_five( libfqfft::_polynomial_addition(r_poly, r_poly, r_part[3]); // TODO: make a separate unit test for r_poly -#if 0 - assert(r_poly == example.r_poly); -#endif // #ifdef DEBUG_PLONK + // assert(r_poly == example.r_poly); // Evaluate the r-polynomial at zeta. Note: in the reference // implementation, r_zeta is added to the pi-SNARK proof. In the @@ -831,10 +829,8 @@ round_five_out_t plonk_prover::round_five( assert(libfqfft::_is_zero(remainder)); // TODO: make a separate unit test for W_zeta, W_zeta_omega -#if 0 - assert(W_zeta == example.W_zeta); - assert(W_zeta_omega == example.W_zeta_omega); -#endif // #ifdef DEBUG_PLONK + // assert(W_zeta == example.W_zeta); + // assert(W_zeta_omega == example.W_zeta_omega); // Evaluate polynomials W_zeta and W_zeta_omega at the seceret // input diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 955c353a1..6b6915a6c 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -16,11 +16,6 @@ #include #include -// enable debug checks. in particular enable comparisons to test -// vector values. -#define DEBUG_PLONK -//#undef DEBUG_PLONK - /// Declaration of common untility functions for ppzkSNARK proof /// system Plonk. The implementation instantiates the protocol of /// PlonK \[GWC19], From e37f52f3b1b0cce8333ba79ba295f1bba562c7bb Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 11:51:06 +0000 Subject: [PATCH 119/154] plonk: renamed variable H_gen to H_prime to be consistent with the paper [GWC19] (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025104257) --- libsnark/zk_proof_systems/plonk/prover.tcc | 2 +- libsnark/zk_proof_systems/plonk/srs.hpp | 12 ++-- libsnark/zk_proof_systems/plonk/srs.tcc | 30 +++++----- .../zk_proof_systems/plonk/tests/example.cpp | 8 +-- .../zk_proof_systems/plonk/tests/example.hpp | 11 ++-- .../plonk/tests/test_plonk.cpp | 2 +- libsnark/zk_proof_systems/plonk/utils.hpp | 18 +++--- libsnark/zk_proof_systems/plonk/utils.tcc | 60 +++++++++---------- 8 files changed, 72 insertions(+), 71 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 961fa340c..06b256ebf 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -158,7 +158,7 @@ round_two_out_t plonk_prover::round_two( // A[0] = 1; ... A[i] = computed from (i-1) std::vector A_vector = plonk_compute_accumulator( - srs.num_gates, beta, gamma, witness, srs.H_gen, srs.H_gen_permute); + srs.num_gates, beta, gamma, witness, srs.H_prime, srs.H_prime_permute); polynomial A_poly(srs.num_gates); plonk_interpolate_polynomial_from_points(A_vector, A_poly, domain); diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index bd50c4e87..07c804849 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -103,12 +103,12 @@ template class srs /// omega[2] are omega[0]*k2 std::vector> omega_roots; - /// H_gen contains the generators of H, k1 H and k2 H in one place + /// H_prime contains the generators of H, k1 H and k2 H in one place /// ie. omega, omega_k1 and omega_k2 - std::vector H_gen; + std::vector H_prime; - /// H_gen permuted according to the wire permutation - std::vector H_gen_permute; + /// H_prime permuted according to the wire permutation + std::vector H_prime_permute; /// constants for H, k1 H, k2 H libff::Fr k1; @@ -131,8 +131,8 @@ template class srs const std::vector> &Q_polys, const std::vector> &S_polys, const std::vector> &omega_roots, - const std::vector &H_gen, - const std::vector &H_gen_permute, + const std::vector &H_prime, + const std::vector &H_prime_permute, const libff::Fr &k1, const libff::Fr &k2, std::vector> &&secret_powers_g1, diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 4cb8e6857..39bca92f1 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -31,8 +31,8 @@ srs::srs( const std::vector> &Q_polys, const std::vector> &S_polys, const std::vector> &omega_roots, - const std::vector &H_gen, - const std::vector &H_gen_permute, + const std::vector &H_prime, + const std::vector &H_prime_permute, const libff::Fr &k1, const libff::Fr &k2, std::vector> &&secret_powers_g1, @@ -44,8 +44,8 @@ srs::srs( , Q_polys(Q_polys) , S_polys(S_polys) , omega_roots(omega_roots) - , H_gen(H_gen) - , H_gen_permute(H_gen_permute) + , H_prime(H_prime) + , H_prime_permute(H_prime_permute) , k1(k1) , k2(k2) , secret_powers_g1(secret_powers_g1) @@ -184,27 +184,27 @@ srs plonk_srs_derive_from_usrs( std::vector> omega_roots; plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); - // H_gen contains the generators of H, k1 H and k2 H in one place + // H_prime contains the generators of H, k1 H and k2 H in one place // ie. circuit.omega_roots, circuit.omega_roots_k1 and // circuit.omega_roots_k2 - std::vector H_gen; - plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_gen); + std::vector H_prime; + plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_prime); // TODO: write unit test for plonk_compute_cosets_H_k1H_k2H - // assert(H_gen[i] == example.H_gen[i]); + // assert(H_prime[i] == example.H_prime[i]); - // permute circuit.H_gen according to the wire permutation - std::vector H_gen_permute = - plonk_permute_subgroup_H(H_gen, wire_permutation, num_gates); + // permute circuit.H_prime according to the wire permutation + std::vector H_prime_permute = + plonk_permute_subgroup_H(H_prime, wire_permutation, num_gates); // TODO: write unit test for plonk_permute_subgroup_H - // assert(H_gen_permute[i] == example.H_gen_permute[i]); + // assert(H_prime_permute[i] == example.H_prime_permute[i]); // compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) std::vector> S_polys = plonk_compute_permutation_polynomials( - H_gen_permute, num_gates, domain); + H_prime_permute, num_gates, domain); // secret^i * G1 std::vector> secret_powers_g1; @@ -232,8 +232,8 @@ srs plonk_srs_derive_from_usrs( std::move(Q_polys), std::move(S_polys), std::move(omega_roots), - std::move(H_gen), - std::move(H_gen_permute), + std::move(H_prime), + std::move(H_prime_permute), std::move(k1), std::move(k2), std::move(secret_powers_g1), diff --git a/libsnark/zk_proof_systems/plonk/tests/example.cpp b/libsnark/zk_proof_systems/plonk/tests/example.cpp index 89c8fc8bb..2677ee524 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.cpp @@ -148,9 +148,9 @@ plonk_example::plonk_example() // vectors this->k2 = libff::power(k1, libff::bigint<1>(2)); - // H_gen contains the generators of H, k1 H and K2 H in one place + // H_prime contains the generators of H, k1 H and K2 H in one place // ie. omega, omega_k1 and omega_k2 - this->H_gen = { + this->H_prime = { Field("1"), Field("2367469443165877065961295211566080294796737370150625379766318411" "1817857449850"), @@ -198,8 +198,8 @@ plonk_example::plonk_example() Field("2897886528193098885258590833291181922264399771053967175378833141" "6327765963203")}; - // H_gen permuted according to the wire permutation - this->H_gen_permute = { + // H_prime permuted according to the wire permutation + this->H_prime_permute = { Field("7069874114745813936829552608791213902061117400356596714713673571" "023200548519"), Field("1838592104783212022667877350171394113611392647210607993375145291" diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 70addc2fa..6d22456f0 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -167,12 +167,13 @@ class plonk_example /// vectors Field k2; - /// H_gen contains the generators of H, k1 H and K2 H in one place - /// ie. omega, omega_k1 and omega_k2 - std::vector H_gen; + /// H_prime (i.e. H' in [GWC19], e.g. see Sect. 8) contains the + /// generators of H, k1 H and K2 H in one place ie. omega, + /// omega_k1 and omega_k2 + std::vector H_prime; - /// H_gen permuted according to the wire permutation - std::vector H_gen_permute; + /// H_prime permuted according to the wire permutation + std::vector H_prime_permute; /// random hidden element secret (toxic waste). we fix it to a /// constant in order to match against the test vectors diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index f69130679..0321282d3 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -158,7 +158,7 @@ void test_plonk_compute_accumulator( using Field = libff::Fr; // A[0] = 1; ... A[i] = computed from (i-1) std::vector A_vector = plonk_compute_accumulator( - srs.num_gates, beta, gamma, witness, srs.H_gen, srs.H_gen_permute); + srs.num_gates, beta, gamma, witness, srs.H_prime, srs.H_prime_permute); polynomial A_poly(srs.num_gates); plonk_interpolate_polynomial_from_points(A_vector, A_poly, domain); diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 6b6915a6c..4673427c7 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -108,7 +108,7 @@ void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, const FieldT k1, const FieldT k2, - std::vector &H_gen); + std::vector &H_prime); /// permute the multiplicative subgroup H according to the wire /// permutation: (see [GWC19] Sect. 8), \see @@ -116,7 +116,7 @@ void plonk_compute_cosets_H_k1H_k2H( /// plonk_roots_of_unity_omega_to_subgroup_H template std::vector plonk_permute_subgroup_H( - const std::vector &H_gen, + const std::vector &H_prime, const std::vector &wire_permutation, const size_t num_gates); @@ -124,7 +124,7 @@ std::vector plonk_permute_subgroup_H( /// S_sigma_2 (see [GWC19], Sect. 8.1) template std::vector> plonk_compute_permutation_polynomials( - const std::vector &H_gen_permute, + const std::vector &H_prime_permute, const size_t num_gates, std::shared_ptr> domain); @@ -166,8 +166,8 @@ void plonk_evaluate_polys_at_secret_G1( /// Compute the factors in the product of the permutation polynomial /// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], -/// i>0 is computed from values at i-1 for witness[i-1], H_gen[i-1], -/// H_gen_permute[i-1]m etc. +/// i>0 is computed from values at i-1 for witness[i-1], H_prime[i-1], +/// H_prime_permute[i-1]m etc. template FieldT plonk_compute_accumulator_factor( const size_t i, @@ -175,8 +175,8 @@ FieldT plonk_compute_accumulator_factor( const FieldT beta, const FieldT gamma, const std::vector &witness, - const std::vector &H_gen, // H, Hk1, Hk2 - const std::vector &H_gen_permute, + const std::vector &H_prime, // H, Hk1, Hk2 + const std::vector &H_prime_permute, const std::vector &A); /// A: accumulatro vector @@ -186,8 +186,8 @@ std::vector plonk_compute_accumulator( const FieldT beta, const FieldT gamma, const std::vector &witness, - const std::vector &H_gen, // H, Hk1, Hk2 - const std::vector &H_gen_permute); + const std::vector &H_prime, // H, Hk1, Hk2 + const std::vector &H_prime_permute); /// transpose the gates matrix template diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 2bbaede9b..cbfad009c 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -123,7 +123,7 @@ void plonk_compute_cosets_H_k1H_k2H( const size_t num_gates, const FieldT k1, const FieldT k2, - std::vector &H_gen) + std::vector &H_prime) { // ensure that num_gates is not 0 and is power of 2 bool b_nonzero = (num_gates > 0); @@ -138,42 +138,42 @@ void plonk_compute_cosets_H_k1H_k2H( std::vector> omega; plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega); - std::copy(omega[base].begin(), omega[base].end(), back_inserter(H_gen)); + std::copy(omega[base].begin(), omega[base].end(), back_inserter(H_prime)); std::copy( - omega[base_k1].begin(), omega[base_k1].end(), back_inserter(H_gen)); + omega[base_k1].begin(), omega[base_k1].end(), back_inserter(H_prime)); std::copy( - omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_gen)); + omega[base_k2].begin(), omega[base_k2].end(), back_inserter(H_prime)); } template std::vector plonk_permute_subgroup_H( - const std::vector &H_gen, + const std::vector &H_prime, const std::vector &wire_permutation, const size_t num_gates) { - assert(H_gen.size() > 0); - std::vector H_gen_permute; - H_gen_permute.resize(NUM_HSETS * num_gates, FieldT(0)); - for (size_t i = 0; i < H_gen.size(); ++i) { - H_gen_permute[i] = H_gen[wire_permutation[i] - 1]; + assert(H_prime.size() > 0); + std::vector H_prime_permute; + H_prime_permute.resize(NUM_HSETS * num_gates, FieldT(0)); + for (size_t i = 0; i < H_prime.size(); ++i) { + H_prime_permute[i] = H_prime[wire_permutation[i] - 1]; } - return H_gen_permute; + return H_prime_permute; } template std::vector> plonk_compute_permutation_polynomials( - const std::vector &H_gen_permute, + const std::vector &H_prime_permute, const size_t num_gates, std::shared_ptr> domain) { - assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + assert(H_prime_permute.size() == (NUM_HSETS * num_gates)); std::vector> S_polys; S_polys.resize(NUM_HSETS, polynomial(num_gates)); for (size_t i = 0; i < NUM_HSETS; ++i) { typename std::vector::const_iterator begin = - H_gen_permute.begin() + (i * num_gates); + H_prime_permute.begin() + (i * num_gates); typename std::vector::const_iterator end = - H_gen_permute.begin() + (i * num_gates) + (num_gates); + H_prime_permute.begin() + (i * num_gates) + (num_gates); std::vector S_points(begin, end); plonk_interpolate_polynomial_from_points( S_points, S_polys[i], domain); @@ -243,30 +243,30 @@ FieldT plonk_compute_accumulator_factor( const FieldT beta, const FieldT gamma, const std::vector &witness, - const std::vector &H_gen, // H, Hk1, Hk2 - const std::vector &H_gen_permute, + const std::vector &H_prime, // H, Hk1, Hk2 + const std::vector &H_prime_permute, const std::vector &A) { assert(num_gates); assert(i < num_gates); assert(witness.size() == (NUM_HSETS * num_gates)); - assert(H_gen.size() == (NUM_HSETS * num_gates)); - assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + assert(H_prime.size() == (NUM_HSETS * num_gates)); + assert(H_prime_permute.size() == (NUM_HSETS * num_gates)); assert(A.size() == num_gates); FieldT res = FieldT(1); if (i > 0) { - FieldT nom_1 = witness[i - 1] + (beta * H_gen[i - 1]) + gamma; - FieldT den_1 = witness[i - 1] + (beta * H_gen_permute[i - 1]) + gamma; + FieldT nom_1 = witness[i - 1] + (beta * H_prime[i - 1]) + gamma; + FieldT den_1 = witness[i - 1] + (beta * H_prime_permute[i - 1]) + gamma; FieldT nom_2 = witness[num_gates + i - 1] + - (beta * H_gen[num_gates + i - 1]) + gamma; + (beta * H_prime[num_gates + i - 1]) + gamma; FieldT den_2 = witness[num_gates + i - 1] + - (beta * H_gen_permute[num_gates + i - 1]) + gamma; + (beta * H_prime_permute[num_gates + i - 1]) + gamma; FieldT nom_3 = witness[2 * num_gates + i - 1] + - (beta * H_gen[2 * num_gates + i - 1]) + gamma; + (beta * H_prime[2 * num_gates + i - 1]) + gamma; FieldT den_3 = witness[2 * num_gates + i - 1] + - (beta * H_gen_permute[2 * num_gates + i - 1]) + gamma; + (beta * H_prime_permute[2 * num_gates + i - 1]) + gamma; FieldT nom = nom_1 * nom_2 * nom_3; FieldT den = den_1 * den_2 * den_3; @@ -282,17 +282,17 @@ std::vector plonk_compute_accumulator( const FieldT beta, const FieldT gamma, const std::vector &witness, - const std::vector &H_gen, // H, Hk1, Hk2 - const std::vector &H_gen_permute) + const std::vector &H_prime, // H, Hk1, Hk2 + const std::vector &H_prime_permute) { assert(num_gates); assert(witness.size() == (NUM_HSETS * num_gates)); - assert(H_gen.size() == (NUM_HSETS * num_gates)); - assert(H_gen_permute.size() == (NUM_HSETS * num_gates)); + assert(H_prime.size() == (NUM_HSETS * num_gates)); + assert(H_prime_permute.size() == (NUM_HSETS * num_gates)); std::vector A(num_gates, FieldT(0)); for (size_t i = 0; i < num_gates; ++i) { A[i] = plonk_compute_accumulator_factor( - i, num_gates, beta, gamma, witness, H_gen, H_gen_permute, A); + i, num_gates, beta, gamma, witness, H_prime, H_prime_permute, A); } return A; } From 95c39a9589b77868b4951245f0d391bdbaae2f96 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 12:03:32 +0000 Subject: [PATCH 120/154] plonk: removed obsolete reference to circuit struct in comments --- libsnark/zk_proof_systems/plonk/srs.tcc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 39bca92f1..b05df0ed8 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -184,16 +184,15 @@ srs plonk_srs_derive_from_usrs( std::vector> omega_roots; plonk_compute_roots_of_unity_omega(num_gates, k1, k2, omega_roots); - // H_prime contains the generators of H, k1 H and k2 H in one place - // ie. circuit.omega_roots, circuit.omega_roots_k1 and - // circuit.omega_roots_k2 + // H_prime contains the generators of H, k1 H and k2 H in one + // place ie. omega_roots, omega_roots_k1 and omega_roots_k2 std::vector H_prime; plonk_compute_cosets_H_k1H_k2H(num_gates, k1, k2, H_prime); // TODO: write unit test for plonk_compute_cosets_H_k1H_k2H // assert(H_prime[i] == example.H_prime[i]); - // permute circuit.H_prime according to the wire permutation + // permute H_prime according to the wire permutation std::vector H_prime_permute = plonk_permute_subgroup_H(H_prime, wire_permutation, num_gates); From 98be246a710732691e43513bdd28af455df6104c Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 12:17:02 +0000 Subject: [PATCH 121/154] plonk: added more efficient allocation of vector secret_powers_g1 (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025107221) --- libsnark/zk_proof_systems/plonk/srs.tcc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index b05df0ed8..ce53c762d 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -206,8 +206,10 @@ srs plonk_srs_derive_from_usrs( H_prime_permute, num_gates, domain); // secret^i * G1 - std::vector> secret_powers_g1; - secret_powers_g1.reserve(num_gates + 3); + std::vector> secret_powers_g1( + usrs.secret_powers_g1.begin(), + usrs.secret_powers_g1.begin() + num_gates + 3); + for (size_t i = 0; i < (num_gates + 3); ++i) { secret_powers_g1.push_back(usrs.secret_powers_g1[i]); } From 5a453cf9ad4bd9fc8182ff9edc261f15ce8d65ee Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 12:53:37 +0000 Subject: [PATCH 122/154] plonk: removed unnecessary intermediate variable in the computation of the zero-th Lagrange basis polynomial (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025111406) --- libsnark/zk_proof_systems/plonk/srs.tcc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index ce53c762d..8e3ac8298 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -221,10 +221,9 @@ srs plonk_srs_derive_from_usrs( } // compute 0-th Lagrange basis vector via inverse FFT - polynomial> u(num_gates, libff::Fr(0)); - u[0] = libff::Fr(1); - domain->iFFT(u); - polynomial> L_basis_zero = u; + polynomial> L_basis_zero(num_gates, libff::Fr(0)); + L_basis_zero[0] = libff::Fr(1); + domain->iFFT(L_basis_zero); srs srs( std::move(num_gates), From 023d789ee502c9b7958825cb76b50b100cf20fce Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 13:25:28 +0000 Subject: [PATCH 123/154] plonk: changed signature of function plonk_gates_matrix_transpose to extract the dimensions directly from the gates_matrix (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025150304) --- libsnark/zk_proof_systems/plonk/srs.tcc | 5 +---- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 4 +--- libsnark/zk_proof_systems/plonk/utils.tcc | 11 ++++++----- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 8e3ac8298..ca036cd3a 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -112,11 +112,8 @@ srs plonk_srs_derive_from_usrs( const std::vector PI_wire_indices) { using Field = libff::Fr; - - const size_t nrows = gates_matrix.size(); - const size_t ncols = gates_matrix[0].size(); const std::vector> gates_matrix_transpose = - plonk_gates_matrix_transpose(gates_matrix, nrows, ncols); + plonk_gates_matrix_transpose(gates_matrix); // the number of gates is equal to the number of columns in the transposed // gates matrix diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 0321282d3..7e5f85d96 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1082,10 +1082,8 @@ template void test_plonk_gates_matrix_transpose() using Field = libff::Fr; // load gates matrix from example circuit plonk_example example; - size_t nrows = example.gates_matrix.size(); - size_t ncols = example.gates_matrix[0].size(); std::vector> gates_matrix_transpose = - plonk_gates_matrix_transpose(example.gates_matrix, nrows, ncols); + plonk_gates_matrix_transpose(example.gates_matrix); ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); } diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index cbfad009c..73eeda9d3 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -299,16 +299,17 @@ std::vector plonk_compute_accumulator( template std::vector> plonk_gates_matrix_transpose( - const std::vector> &gates_matrix, - const size_t &nrows, - const size_t &ncols) + const std::vector> &gates_matrix) { - size_t nrows_transpose = ncols; - size_t ncols_transpose = nrows; + const size_t nrows = gates_matrix.size(); + const size_t ncols = gates_matrix[0].size(); + const size_t nrows_transpose = ncols; + const size_t ncols_transpose = nrows; std::vector> gates_matrix_transpose( nrows_transpose, std::vector(ncols_transpose)); for (size_t irow = 0; irow < nrows; ++irow) { for (size_t icol = 0; icol < ncols; ++icol) { + assert(gates_matrix[icol].size() == ncols); gates_matrix_transpose[icol][irow] = gates_matrix[irow][icol]; } } From fe272b26026001f726d42fe036e850e1049f43c2 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 23 Nov 2022 14:07:20 +0000 Subject: [PATCH 124/154] plonk: moved comment regarding optimisation in representing the identity permutation to its proper place, i.e. after k1,k2 are defined (https://github.com/clearmatics/libsnark/pull/91#discussion_r1025074526) --- libsnark/zk_proof_systems/plonk/srs.tcc | 69 ++++++++++++++----------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index ca036cd3a..39c0a43a3 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -141,41 +141,52 @@ srs plonk_srs_derive_from_usrs( plonk_compute_selector_polynomials( num_gates, num_qpolys, gates_matrix_transpose, domain); - // An explanation of the constants k1,k2 from [GWC19], Section 8, page 26 : + // An explanation of the constants k1,k2 from [GWC19], Section 8, + // page 26 : // - // "We explicitly define the multiplicative subgroup H as containing the - // n-th roots of unity in F_p , where w (omega) is a primitive n-th root of - // unity and a generator of H i.e: H = {1, w, ... , w^{n-1}}. We assume - // that the number of gates in a circuit is no more than n. We also include - // an optimisation suggested by Vitalik Buterin, to define the identity per- - // mutations through degree-1 polynomials. The identity permutations must - // map each wire value to a unique element \in F. This can be done by - // defining S_ID1(X) = X, S_ID2 (X) = k1 X, S_ID3(X) = k2 X [see below for - // more on S_ID1, S_ID2, S_ID3], where k1 , k2 are quadratic non-residues - // \in F. This effectively maps each wire value to a root of unity in H, - // with right and output wires having an additional multiplicative factor of - // k1, k2 applied respectively. By representing the identity permutation via - // degree-1 polynomials, their evaluations can be directly computed by the - // verifier. This reduces the size of the proof by 1 F element, as well as - // reducing the number of Fast-Fourier-Transforms required by the prover." - // - // Further in Sect. 8.1 [GWC19]: - // - // "S_ID1(X) = X, S_ID2(X) = k 1 X, S ID3 (X) = k 2 X: the identity - // permutation applied to a, b, c [the wire polynomials, see Round 1, p.27 - // [GWC19]]. k1, k2 \in F are chosen such that H, k1 H, k2 H are distinct - // cosets of H in F*, and thus consist of 3n distinct elements. (For - // example, when w (omega) is a quadratic residue in F, take k1 to be any - // quadratic non-residue, and k2 to be a quadratic non-residue not - // contained in k1 H.)" + // "We explicitly define the multiplicative subgroup H as + // containing the n-th roots of unity in F_p , where w (omega) is + // a primitive n-th root of unity and a generator of H i.e: H = + // {1, w, ... , w^{n-1}}. We assume that the number of gates in a + // circuit is no more than n. + // - // For the moment k1,k2 are fixed to the test vector values for debug - // purpouses. TODO choose k1,k2 according to the requirements in [GWC19] + // For the moment k1,k2 are fixed to the test vector values for + // debug purpouses. TODO choose k1,k2 according to the + // requirements in [GWC19] libff::Fr k1 = Field("706987411474581393682955260879121390206111740035659671471" "3673571023200548519"); libff::Fr k2 = libff::power(k1, libff::bigint<1>(2)); + // From [GWC19], Section 8, page 26: + // + // "We also include an optimisation suggested by Vitalik Buterin, + // to define the identity permutations through degree-1 + // polynomials. The identity permutations must map each wire value + // to a unique element \in F. This can be done by defining + // S_ID1(X) = X, S_ID2 (X) = k1 X, S_ID3(X) = k2 X [see below for + // more on S_ID1, S_ID2, S_ID3], where k1, k2 are quadratic + // non-residues \in F. This effectively maps each wire value to a + // root of unity in H, with right and output wires having an + // additional multiplicative factor of k1, k2 applied + // respectively. By representing the identity permutation via + // degree-1 polynomials, their evaluations can be directly + // computed by the verifier. This reduces the size of the proof by + // 1 F element, as well as reducing the number of + // Fast-Fourier-Transforms required by the prover." + // + // Further in Sect. 8.1 [GWC19]: + // + // "S_ID1(X) = X, S_ID2(X) = k 1 X, S ID3 (X) = k 2 X: the + // identity permutation applied to a, b, c [the wire polynomials, + // see Round 1, p.27 [GWC19]]. k1, k2 \in F are chosen such that + // H, k1 H, k2 H are distinct cosets of H in F*, and thus consist + // of 3n distinct elements. (For example, when w (omega) is a + // quadratic residue in F, take k1 to be any quadratic + // non-residue, and k2 to be a quadratic non-residue not contained + // in k1 H.)" + // omega[0] are the n roots of unity; omega[1] are omega[0]*k1; // omega[2] are omega[0]*k2 std::vector> omega_roots; @@ -196,7 +207,7 @@ srs plonk_srs_derive_from_usrs( // TODO: write unit test for plonk_permute_subgroup_H // assert(H_prime_permute[i] == example.H_prime_permute[i]); - // compute the permutation polynomials S_sigma_1, S_sigma_2, + // Compute the permutation polynomials S_sigma_1, S_sigma_2, // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) std::vector> S_polys = plonk_compute_permutation_polynomials( From 7da9f612daff058613524d30191a921ece18a4dc Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 25 Nov 2022 14:08:36 +0000 Subject: [PATCH 125/154] plonk: clarified the origin of the constants k1,k2 in comments (https://github.com/clearmatics/libsnark/pull/91#discussion_r1031568957) --- libsnark/zk_proof_systems/plonk/srs.tcc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 39c0a43a3..533d1b43d 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -149,11 +149,12 @@ srs plonk_srs_derive_from_usrs( // a primitive n-th root of unity and a generator of H i.e: H = // {1, w, ... , w^{n-1}}. We assume that the number of gates in a // circuit is no more than n. - // - // For the moment k1,k2 are fixed to the test vector values for - // debug purpouses. TODO choose k1,k2 according to the - // requirements in [GWC19] + // For the moment k1,k2 are fixed (see below) to the test vector + // values from the plonk_example class for debug purpouses. Note + // that these test values are specific to the BLS12-381 curve and + // hence they satisfy the requirements for BLS12-381. TODO: choose + // k1,k2 according to the requirements in [GWC19] libff::Fr k1 = Field("706987411474581393682955260879121390206111740035659671471" "3673571023200548519"); From 65ee1389debf6ba3b77004e59f7e81c2f01acbcb Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 25 Nov 2022 14:11:23 +0000 Subject: [PATCH 126/154] plonk: changed variables to const (https://github.com/clearmatics/libsnark/pull/91#discussion_r1031580862) --- libsnark/zk_proof_systems/plonk/prover.tcc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index 06b256ebf..eb490b652 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -291,8 +291,8 @@ round_three_out_t plonk_prover::round_three( std::vector PI_points(srs.num_gates, Field(0)); // loop over all wire indices that correspond to PIs for (size_t i = 0; i < srs.PI_wire_indices.size(); i++) { - Field PI_value = witness[srs.PI_wire_indices[i]]; - size_t PI_coordinate_x = srs.PI_wire_indices[i] % srs.num_gates; + const Field PI_value = witness[srs.PI_wire_indices[i]]; + const size_t PI_coordinate_x = srs.PI_wire_indices[i] % srs.num_gates; PI_points[PI_coordinate_x] = Field(-PI_value); } // compute the PI polynomial from the list of points using iFFT From f689497cc0a9a9c6f41f6c7401a273831033f6d6 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 25 Nov 2022 14:51:55 +0000 Subject: [PATCH 127/154] plonk: added minor edits to comments --- libsnark/zk_proof_systems/plonk/srs.tcc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index 533d1b43d..fe8335644 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -151,10 +151,11 @@ srs plonk_srs_derive_from_usrs( // circuit is no more than n. // // For the moment k1,k2 are fixed (see below) to the test vector - // values from the plonk_example class for debug purpouses. Note + // values from the plonk_example class for debug purposes. Note // that these test values are specific to the BLS12-381 curve and - // hence they satisfy the requirements for BLS12-381. TODO: choose - // k1,k2 according to the requirements in [GWC19] + // hence they may ONLY satisfy the requirements for + // BLS12-381. TODO: choose k1,k2 according to the requirements in + // [GWC19] libff::Fr k1 = Field("706987411474581393682955260879121390206111740035659671471" "3673571023200548519"); From 0d3a5d4ad1b5c8902fec0dcdb62c198da0a25594 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 29 Nov 2022 15:08:03 +0000 Subject: [PATCH 128/154] plonk: added functions to generate constants k1,k2 (section 8.1 [GWC19]) and check their validity (addresses issue https://github.com/clearmatics/libsnark/issues/90) --- .../plonk/tests/test_plonk.cpp | 51 +++++++++++++++++++ libsnark/zk_proof_systems/plonk/utils.hpp | 41 +++++++++++++++ libsnark/zk_proof_systems/plonk/utils.tcc | 30 +++++++++++ 3 files changed, 122 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 7e5f85d96..69c448498 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1087,6 +1087,56 @@ template void test_plonk_gates_matrix_transpose() ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); } +template void test_plonk_constants_k1_k2() +{ + using Field = libff::Fr; + Field k1, k2; + // n = 2^s + const size_t n = std::pow(2, k1.s); + bool b_valid = false; + // load k1,k2 from example circuit + plonk_example example; + k1 = example.k1; + k2 = example.k2; + b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + ASSERT_TRUE(b_valid); + // check invalid k1,k2 + for (size_t i = 1; i <= example.num_gates; ++i) { + size_t ipower = i; + // invalid k2=k1*(omega^i) + k1 = example.k1; + k2 = k1 * (example.omega_base ^ ipower); + b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + ASSERT_FALSE(b_valid); + // invalid k1=k2*(omega^i) + k2 = example.k2; + k1 = k2 * (example.omega_base ^ ipower); + b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + ASSERT_FALSE(b_valid); + // invalid k1=omega^i + k1 = (example.omega_base ^ ipower); + k2 = example.k2; + b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + ASSERT_FALSE(b_valid); + // invalid k2=omega^i + k1 = example.k1; + k2 = (example.omega_base ^ ipower); + b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + ASSERT_FALSE(b_valid); + } + // generate new k1,k2 and assert they are valid for a random + // number of tests + size_t ntests = 1UL << 10; + for (size_t i = 0; i < ntests; ++i) { + k1 = 0; + k2 = 0; + plonk_generate_constants_k1_k2(n, k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + // printf("k1 "); k1.print(); printf("k2 "); k2.print(); + ASSERT_TRUE(b_valid); + } +} + TEST(TestPlonk, BLS12_381) { test_plonk_srs(); @@ -1103,6 +1153,7 @@ TEST(TestPlonk, BLS12_381) libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); test_plonk_gates_matrix_transpose(); + test_plonk_constants_k1_k2(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 4673427c7..e02f8be18 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -196,6 +196,47 @@ std::vector> plonk_gates_matrix_transpose( const size_t &nrows, const size_t &ncols); +/// generate constants k1,k2 \in Fr such that the sets H, k1H, k2H are +/// non-overlapping, where H = {w, w^1, w^2, ..., 2^n} is a +/// multiplicative subgroup of Fr of order n with generator w (denoted +/// as \omega in [GWC19]). w is a primitive n-th root of unity in Fr +/// and n is of the form 2^s where s is the largest power of 2 such +/// that 2^s < p and 2^{s+1} > p, where p is the prime modulus of +/// Fr. see also Section 8.1 in [GWC19]. note that p = 2^s * t + 1 so +/// that p-1 = 2^s t is the order of the multiplicative group Fr^* of +/// the scalar field Fr and s and t are members of the class Fp_model +/// defined in libff/libff/algebra/fields/fp.hpp . +/// +/// the algorithm generates random values for k1,k2 until the following +/// three conditions are simultaneously satisfied: +/// +/// 1) k1^n != 1 ensuring that k1 \notin H +/// 2) k2^n != 1 ensuring that k2 \notin H +/// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) +/// +/// to clarify 3), note that if (k1 k2^-1)^n == 1 then \exists i: 1 <= +/// i <= n: k1 = k2 w^i and so k1 \in k2H. this is because k1 = k2 w^i +/// is equivalent to k1 k2^-1 = w^i, equivalent to (k1 k2^-1)^n = +/// (w^i)^n = 1. the latter follows from the fact that w^i is an n-th +/// root of unity in Fr (for any i: 1<=i<=n). +/// +/// conditions 1) and 2) are special cases of 3) for which resp. k1=1, k2=k1 and +/// k1=1, k2=k2 +template +void plonk_generate_constants_k1_k2( + const size_t &n, FieldT &k1_result, FieldT &k2_result); + +/// check that the constants k1,k2 satisfy the following conditions: +/// +/// 1) k1 != 1 ensuring that k1 \notin H +/// 2) k2 != 1 ensuring that k2 \notin H +/// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) +/// +/// see Section 8.1 [GWC19] and plonk_generate_constants_k1_k2 +template +bool plonk_are_valid_constants_k1_k2( + const size_t &n, const FieldT &k1, const FieldT &k2); + } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/utils.tcc" diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 73eeda9d3..d2d637ebe 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -316,6 +316,36 @@ std::vector> plonk_gates_matrix_transpose( return gates_matrix_transpose; } +template +void plonk_generate_constants_k1_k2( + const size_t &n, FieldT &k1_result, FieldT &k2_result) +{ + FieldT k1, k2; + // choose k1 + do { + k1 = FieldT::random_element(); + } while ((k1 ^ n) == FieldT::one()); + // choose k2 + FieldT k1_over_k2; + do { + k2 = FieldT::random_element(); + k1_over_k2 = k1 * k2.inverse(); + } while (((k2 ^ n) == FieldT::one()) || + (((k1_over_k2) ^ n) == FieldT::one())); + k1_result = k1; + k2_result = k2; +} + +template +bool plonk_are_valid_constants_k1_k2( + const size_t &n, const FieldT &k1, const FieldT &k2) +{ + bool b_k1 = ((k1 ^ n) != FieldT::one()); + bool b_k2 = ((k2 ^ n) != FieldT::one()); + bool b_k1_k2 = (((k1 * k2.inverse()) ^ n) != FieldT::one()); + return (b_k1 && b_k2 && b_k1_k2); +} + } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ From 56c73c487d5e60442ac431849b897de0a52b35ca Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 30 Nov 2022 13:55:38 +0000 Subject: [PATCH 129/154] plonk: removed size n of the subrgroup H as input to the k1,k2 functions (https://github.com/clearmatics/libsnark/pull/94#discussion_r1035072768) --- .../zk_proof_systems/plonk/tests/test_plonk.cpp | 16 ++++++++-------- libsnark/zk_proof_systems/plonk/utils.hpp | 10 ++++------ libsnark/zk_proof_systems/plonk/utils.tcc | 10 ++++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 69c448498..927766324 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1092,13 +1092,13 @@ template void test_plonk_constants_k1_k2() using Field = libff::Fr; Field k1, k2; // n = 2^s - const size_t n = std::pow(2, k1.s); + // const size_t n = std::pow(2, Field::s); bool b_valid = false; // load k1,k2 from example circuit plonk_example example; k1 = example.k1; k2 = example.k2; - b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(k1, k2); ASSERT_TRUE(b_valid); // check invalid k1,k2 for (size_t i = 1; i <= example.num_gates; ++i) { @@ -1106,22 +1106,22 @@ template void test_plonk_constants_k1_k2() // invalid k2=k1*(omega^i) k1 = example.k1; k2 = k1 * (example.omega_base ^ ipower); - b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(k1, k2); ASSERT_FALSE(b_valid); // invalid k1=k2*(omega^i) k2 = example.k2; k1 = k2 * (example.omega_base ^ ipower); - b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(k1, k2); ASSERT_FALSE(b_valid); // invalid k1=omega^i k1 = (example.omega_base ^ ipower); k2 = example.k2; - b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(k1, k2); ASSERT_FALSE(b_valid); // invalid k2=omega^i k1 = example.k1; k2 = (example.omega_base ^ ipower); - b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(k1, k2); ASSERT_FALSE(b_valid); } // generate new k1,k2 and assert they are valid for a random @@ -1130,8 +1130,8 @@ template void test_plonk_constants_k1_k2() for (size_t i = 0; i < ntests; ++i) { k1 = 0; k2 = 0; - plonk_generate_constants_k1_k2(n, k1, k2); - b_valid = plonk_are_valid_constants_k1_k2(n, k1, k2); + plonk_generate_constants_k1_k2(k1, k2); + b_valid = plonk_are_valid_constants_k1_k2(k1, k2); // printf("k1 "); k1.print(); printf("k2 "); k2.print(); ASSERT_TRUE(b_valid); } diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index e02f8be18..a0402eda9 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -223,19 +223,17 @@ std::vector> plonk_gates_matrix_transpose( /// conditions 1) and 2) are special cases of 3) for which resp. k1=1, k2=k1 and /// k1=1, k2=k2 template -void plonk_generate_constants_k1_k2( - const size_t &n, FieldT &k1_result, FieldT &k2_result); +void plonk_generate_constants_k1_k2(FieldT &k1_result, FieldT &k2_result); /// check that the constants k1,k2 satisfy the following conditions: /// -/// 1) k1 != 1 ensuring that k1 \notin H -/// 2) k2 != 1 ensuring that k2 \notin H +/// 1) k1^n != 1 ensuring that k1 \notin H +/// 2) k2^n != 1 ensuring that k2 \notin H /// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) /// /// see Section 8.1 [GWC19] and plonk_generate_constants_k1_k2 template -bool plonk_are_valid_constants_k1_k2( - const size_t &n, const FieldT &k1, const FieldT &k2); +bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2); } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index d2d637ebe..847cd4a0a 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -317,9 +317,10 @@ std::vector> plonk_gates_matrix_transpose( } template -void plonk_generate_constants_k1_k2( - const size_t &n, FieldT &k1_result, FieldT &k2_result) +void plonk_generate_constants_k1_k2(FieldT &k1_result, FieldT &k2_result) { + // n = 2^s: maximum order of the H subgroup that is power of 2 + const size_t n = std::pow(2, FieldT::s); FieldT k1, k2; // choose k1 do { @@ -337,9 +338,10 @@ void plonk_generate_constants_k1_k2( } template -bool plonk_are_valid_constants_k1_k2( - const size_t &n, const FieldT &k1, const FieldT &k2) +bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) { + // n = 2^s: maximum order of the H subgroup that is power of 2 + const size_t n = std::pow(2, FieldT::s); bool b_k1 = ((k1 ^ n) != FieldT::one()); bool b_k2 = ((k2 ^ n) != FieldT::one()); bool b_k1_k2 = (((k1 * k2.inverse()) ^ n) != FieldT::one()); From 97f14649ff04931a64328356abdffac79b5af302 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 30 Nov 2022 13:58:53 +0000 Subject: [PATCH 130/154] plonk: changed variable names in k1,k2 functions to more meaningful names (https://github.com/clearmatics/libsnark/pull/94#discussion_r1035076523) --- libsnark/zk_proof_systems/plonk/utils.tcc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 847cd4a0a..66abcc25d 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -342,10 +342,12 @@ bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) { // n = 2^s: maximum order of the H subgroup that is power of 2 const size_t n = std::pow(2, FieldT::s); - bool b_k1 = ((k1 ^ n) != FieldT::one()); - bool b_k2 = ((k2 ^ n) != FieldT::one()); - bool b_k1_k2 = (((k1 * k2.inverse()) ^ n) != FieldT::one()); - return (b_k1 && b_k2 && b_k1_k2); + const bool k1_outside_H = ((k1 ^ n) != FieldT::one()); + const bool k2_outside_H = ((k2 ^ n) != FieldT::one()); + const bool k1_over_k2_outside_H = + (((k1 * k2.inverse()) ^ n) != FieldT::one()); + + return (k1_outside_H && k2_outside_H && k1_over_k2_outside_H); } } // namespace libsnark From b9748bc8f36ea3c159a4da202ddb1b311b2825d5 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 30 Nov 2022 14:05:19 +0000 Subject: [PATCH 131/154] plonk: removed redundant variable b_valid (https://github.com/clearmatics/libsnark/pull/94#discussion_r1035095882) --- .../plonk/tests/test_plonk.cpp | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 927766324..d52570c77 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1091,38 +1091,30 @@ template void test_plonk_constants_k1_k2() { using Field = libff::Fr; Field k1, k2; - // n = 2^s - // const size_t n = std::pow(2, Field::s); - bool b_valid = false; // load k1,k2 from example circuit plonk_example example; k1 = example.k1; k2 = example.k2; - b_valid = plonk_are_valid_constants_k1_k2(k1, k2); - ASSERT_TRUE(b_valid); + ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); // check invalid k1,k2 for (size_t i = 1; i <= example.num_gates; ++i) { size_t ipower = i; // invalid k2=k1*(omega^i) k1 = example.k1; k2 = k1 * (example.omega_base ^ ipower); - b_valid = plonk_are_valid_constants_k1_k2(k1, k2); - ASSERT_FALSE(b_valid); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); // invalid k1=k2*(omega^i) k2 = example.k2; k1 = k2 * (example.omega_base ^ ipower); - b_valid = plonk_are_valid_constants_k1_k2(k1, k2); - ASSERT_FALSE(b_valid); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); // invalid k1=omega^i k1 = (example.omega_base ^ ipower); k2 = example.k2; - b_valid = plonk_are_valid_constants_k1_k2(k1, k2); - ASSERT_FALSE(b_valid); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); // invalid k2=omega^i k1 = example.k1; k2 = (example.omega_base ^ ipower); - b_valid = plonk_are_valid_constants_k1_k2(k1, k2); - ASSERT_FALSE(b_valid); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); } // generate new k1,k2 and assert they are valid for a random // number of tests @@ -1131,9 +1123,8 @@ template void test_plonk_constants_k1_k2() k1 = 0; k2 = 0; plonk_generate_constants_k1_k2(k1, k2); - b_valid = plonk_are_valid_constants_k1_k2(k1, k2); // printf("k1 "); k1.print(); printf("k2 "); k2.print(); - ASSERT_TRUE(b_valid); + ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); } } From c0b31b9488128b732a43fe14bd4329272e18f376 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 30 Nov 2022 14:09:45 +0000 Subject: [PATCH 132/154] plonk: clarified parts of the test code for the k1,k2 constants in comments (https://github.com/clearmatics/libsnark/pull/94#discussion_r1035095072) --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index d52570c77..2c426a2e0 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1096,22 +1096,23 @@ template void test_plonk_constants_k1_k2() k1 = example.k1; k2 = example.k2; ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); - // check invalid k1,k2 + // check invalid values for k1,k2 by setting one of them to be + // equal to an element of H, k1H or k2H for (size_t i = 1; i <= example.num_gates; ++i) { size_t ipower = i; - // invalid k2=k1*(omega^i) + // set k2 to an element of k1H: k2=k1*(omega^i) k1 = example.k1; k2 = k1 * (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // invalid k1=k2*(omega^i) + // set k1 to an element of k2H: k1=k2*(omega^i) k2 = example.k2; k1 = k2 * (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // invalid k1=omega^i + // set k1 to an element of H: k1=omega^i k1 = (example.omega_base ^ ipower); k2 = example.k2; ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // invalid k2=omega^i + // set k2 to an element of H: k2=omega^i k1 = example.k1; k2 = (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); From e7c72c1d6240c4abc51ae848e5e559f4acbf5197 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 30 Nov 2022 14:35:38 +0000 Subject: [PATCH 133/154] plonk: added function to deterministically generate values for the constants k1,k2 (https://github.com/clearmatics/libsnark/pull/94#discussion_r1035084501) --- libsnark/zk_proof_systems/plonk/utils.hpp | 37 +++++++++++++++-------- libsnark/zk_proof_systems/plonk/utils.tcc | 15 ++++++++- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index a0402eda9..ff4817d8d 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -196,7 +196,28 @@ std::vector> plonk_gates_matrix_transpose( const size_t &nrows, const size_t &ncols); -/// generate constants k1,k2 \in Fr such that the sets H, k1H, k2H are +/// deterministically compute values for the constants k1,k2 \in Fr +/// (section 8.1 [GWC19]) as k1=g^{2s}, k2=nqr, where s is the largest +/// power of 2 such that 2^s < p and 2^{s+1} > p, p is the prime +/// modulus of Fr and nqr is a quadratic nonresidue in Fr^*. both s +/// and nqr are members of the class Fp_model defined in +/// libff/libff/algebra/fields/fp.hpp . +template +void plonk_generate_constants_k1_k2(FieldT &k1_result, FieldT &k2_result); + +/// generate values for the constants k1,k2 \in Fr (section 8.1 +/// [GWC19]) by trying random values until the following three +/// conditions are simultaneously satisfied: +/// +/// 1) k1^n != 1 ensuring that k1 \notin H +/// 2) k2^n != 1 ensuring that k2 \notin H +/// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) +template +void plonk_generate_random_constants_k1_k2( + FieldT &k1_result, FieldT &k2_result); + +/// check that the constants k1,k2 \in Fr (section 8.1 [GWC19]) are +/// valid. this is the case if the sets H, k1H, k2H are /// non-overlapping, where H = {w, w^1, w^2, ..., 2^n} is a /// multiplicative subgroup of Fr of order n with generator w (denoted /// as \omega in [GWC19]). w is a primitive n-th root of unity in Fr @@ -207,8 +228,8 @@ std::vector> plonk_gates_matrix_transpose( /// the scalar field Fr and s and t are members of the class Fp_model /// defined in libff/libff/algebra/fields/fp.hpp . /// -/// the algorithm generates random values for k1,k2 until the following -/// three conditions are simultaneously satisfied: +/// the function checks if the following three conditions are +/// simultaneously satisfied: /// /// 1) k1^n != 1 ensuring that k1 \notin H /// 2) k2^n != 1 ensuring that k2 \notin H @@ -223,16 +244,6 @@ std::vector> plonk_gates_matrix_transpose( /// conditions 1) and 2) are special cases of 3) for which resp. k1=1, k2=k1 and /// k1=1, k2=k2 template -void plonk_generate_constants_k1_k2(FieldT &k1_result, FieldT &k2_result); - -/// check that the constants k1,k2 satisfy the following conditions: -/// -/// 1) k1^n != 1 ensuring that k1 \notin H -/// 2) k2^n != 1 ensuring that k2 \notin H -/// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) -/// -/// see Section 8.1 [GWC19] and plonk_generate_constants_k1_k2 -template bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2); } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 66abcc25d..a43a31561 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -317,7 +317,20 @@ std::vector> plonk_gates_matrix_transpose( } template -void plonk_generate_constants_k1_k2(FieldT &k1_result, FieldT &k2_result) +void plonk_generate_constants_k1_k2(FieldT &k1, FieldT &k2) +{ + // n = 2^s: maximum order of the H subgroup that is power of 2 + const size_t n = std::pow(2, FieldT::s); + // generator of Fr^* + const FieldT g = FieldT::multiplicative_generator; + // set k1 = g^{2s} \notin H + k1 = g ^ n; + // set k2 to a quadratic nonresidue of Fr^* + k2 = FieldT::nqr; +} + +template +void plonk_generate_random_constants_k1_k2(FieldT &k1_result, FieldT &k2_result) { // n = 2^s: maximum order of the H subgroup that is power of 2 const size_t n = std::pow(2, FieldT::s); From 5b157e5dd7e4388d2cd3b29b4db1e41abc401756 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 1 Dec 2022 12:09:37 +0000 Subject: [PATCH 134/154] plonk: added unit tests for all curves for the function choosing the k1,k2 constants for plonk --- .../plonk/tests/test_plonk.cpp | 79 ++++++++++++++++--- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 2c426a2e0..e27414bd8 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -14,6 +14,14 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include /// Test program that exercises the Plonk protocol (first setup, then @@ -1087,8 +1095,24 @@ template void test_plonk_gates_matrix_transpose() ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); } +// generic test for all curves template void test_plonk_constants_k1_k2() { + ppT::init_public_params(); + + using Field = libff::Fr; + Field k1, k2; + plonk_generate_constants_k1_k2(k1, k2); + // printf("k1 "); k1.print(); printf("k2 "); k2.print(); + ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); +} + +// test specific to BLS12-381 (uses class example specific to +// BLS12-381) +template void test_plonk_constants_k1_k2_bls12_381() +{ + ppT::init_public_params(); + using Field = libff::Fr; Field k1, k2; // load k1,k2 from example circuit @@ -1119,14 +1143,52 @@ template void test_plonk_constants_k1_k2() } // generate new k1,k2 and assert they are valid for a random // number of tests - size_t ntests = 1UL << 10; - for (size_t i = 0; i < ntests; ++i) { - k1 = 0; - k2 = 0; - plonk_generate_constants_k1_k2(k1, k2); - // printf("k1 "); k1.print(); printf("k2 "); k2.print(); - ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); - } + k1 = 0; + k2 = 0; + plonk_generate_constants_k1_k2(k1, k2); + // printf("k1 "); k1.print(); printf("k2 "); k2.print(); + ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); +} + +TEST(TestPlonkConstantsK1K2, Edwards) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, Mnt4) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, Mnt6) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, BW6_761) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, BN128) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, ALT_BN128) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, BLS12_377) +{ + test_plonk_constants_k1_k2(); +} + +TEST(TestPlonkConstantsK1K2, BLS12_381) +{ + test_plonk_constants_k1_k2(); + test_plonk_constants_k1_k2_bls12_381(); } TEST(TestPlonk, BLS12_381) @@ -1145,7 +1207,6 @@ TEST(TestPlonk, BLS12_381) libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); test_plonk_gates_matrix_transpose(); - test_plonk_constants_k1_k2(); } } // namespace libsnark From 6d3fc29434e194019294c034e7b0453cf71fe1bd Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 6 Dec 2022 08:38:30 +0000 Subject: [PATCH 135/154] plonk: edited comments to valid k1,k2 tests (https://github.com/clearmatics/libsnark/pull/94#discussion_r1039410368) --- .../zk_proof_systems/plonk/tests/test_plonk.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index e27414bd8..f46a846a2 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1115,13 +1115,16 @@ template void test_plonk_constants_k1_k2_bls12_381() using Field = libff::Fr; Field k1, k2; - // load k1,k2 from example circuit + + // check that the example k1 and k2 are valid (according to + // plonk_are_valid_constants_k1_k2)" plonk_example example; k1 = example.k1; k2 = example.k2; ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); - // check invalid values for k1,k2 by setting one of them to be - // equal to an element of H, k1H or k2H + + // check that plonk_are_valid_constants_k1_k2 correctly detects + // invalid combinations of k1 and k2 for (size_t i = 1; i <= example.num_gates; ++i) { size_t ipower = i; // set k2 to an element of k1H: k2=k1*(omega^i) @@ -1141,8 +1144,9 @@ template void test_plonk_constants_k1_k2_bls12_381() k2 = (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); } - // generate new k1,k2 and assert they are valid for a random - // number of tests + + // check that plonk_generate_constants_k1_k2 generates valid k1 + // and k2 k1 = 0; k2 = 0; plonk_generate_constants_k1_k2(k1, k2); From 82e39f94109e3dc55b23f2bf6f9d28d2349d9d41 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 6 Dec 2022 09:26:50 +0000 Subject: [PATCH 136/154] plonk: added unit test for the randomized generation of constants k1,k2 (https://github.com/clearmatics/libsnark/pull/94#discussion_r1039418225) + removed some redundant comments --- .../plonk/tests/test_plonk.cpp | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index f46a846a2..bbefde6f2 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1103,7 +1103,18 @@ template void test_plonk_constants_k1_k2() using Field = libff::Fr; Field k1, k2; plonk_generate_constants_k1_k2(k1, k2); - // printf("k1 "); k1.print(); printf("k2 "); k2.print(); + ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); +} + +// generic test for all curves for an alternative method to generate +// constants k1,k2 using randomization +template void test_plonk_random_constants_k1_k2() +{ + ppT::init_public_params(); + + using Field = libff::Fr; + Field k1, k2; + plonk_generate_random_constants_k1_k2(k1, k2); ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); } @@ -1150,48 +1161,55 @@ template void test_plonk_constants_k1_k2_bls12_381() k1 = 0; k2 = 0; plonk_generate_constants_k1_k2(k1, k2); - // printf("k1 "); k1.print(); printf("k2 "); k2.print(); ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); } TEST(TestPlonkConstantsK1K2, Edwards) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, Mnt4) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, Mnt6) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, BW6_761) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, BN128) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, ALT_BN128) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, BLS12_377) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); } TEST(TestPlonkConstantsK1K2, BLS12_381) { test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); test_plonk_constants_k1_k2_bls12_381(); } From f8a0eaa89a7bbb16a2c35d2f9bc710cab74b17aa Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 6 Dec 2022 09:37:04 +0000 Subject: [PATCH 137/154] plonk: added validity assertion check in functions generating constants k1,k2 (https://github.com/clearmatics/libsnark/pull/94#discussion_r1039419943) --- libsnark/zk_proof_systems/plonk/utils.tcc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index a43a31561..229ca8ca6 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -327,6 +327,8 @@ void plonk_generate_constants_k1_k2(FieldT &k1, FieldT &k2) k1 = g ^ n; // set k2 to a quadratic nonresidue of Fr^* k2 = FieldT::nqr; + // assert k1,k2 are valid + assert(plonk_are_valid_constants_k1_k2(k1, k2)); } template @@ -348,6 +350,8 @@ void plonk_generate_random_constants_k1_k2(FieldT &k1_result, FieldT &k2_result) (((k1_over_k2) ^ n) == FieldT::one())); k1_result = k1; k2_result = k2; + // assert k1,k2 are valid + assert(plonk_are_valid_constants_k1_k2(k1, k2)); } template From aed4aca46e97fa34c03621a7afecea05e5944045 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 6 Dec 2022 13:42:47 +0000 Subject: [PATCH 138/154] plonk: fixed several comments -- grammar + moving part of comments to tcc file (https://github.com/clearmatics/libsnark/pull/94#discussion_r1039430204) --- .../plonk/tests/test_plonk.cpp | 6 ++-- libsnark/zk_proof_systems/plonk/utils.hpp | 31 ++++--------------- libsnark/zk_proof_systems/plonk/utils.tcc | 15 +++++++++ 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index bbefde6f2..dce28e70a 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1127,14 +1127,14 @@ template void test_plonk_constants_k1_k2_bls12_381() using Field = libff::Fr; Field k1, k2; - // check that the example k1 and k2 are valid (according to + // Check that the example k1 and k2 are valid (according to // plonk_are_valid_constants_k1_k2)" plonk_example example; k1 = example.k1; k2 = example.k2; ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); - // check that plonk_are_valid_constants_k1_k2 correctly detects + // Check that plonk_are_valid_constants_k1_k2 correctly detects // invalid combinations of k1 and k2 for (size_t i = 1; i <= example.num_gates; ++i) { size_t ipower = i; @@ -1156,7 +1156,7 @@ template void test_plonk_constants_k1_k2_bls12_381() ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); } - // check that plonk_generate_constants_k1_k2 generates valid k1 + // Check that plonk_generate_constants_k1_k2 generates valid k1 // and k2 k1 = 0; k2 = 0; diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index ff4817d8d..e8125806d 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -199,7 +199,7 @@ std::vector> plonk_gates_matrix_transpose( /// deterministically compute values for the constants k1,k2 \in Fr /// (section 8.1 [GWC19]) as k1=g^{2s}, k2=nqr, where s is the largest /// power of 2 such that 2^s < p and 2^{s+1} > p, p is the prime -/// modulus of Fr and nqr is a quadratic nonresidue in Fr^*. both s +/// modulus of Fr and nqr is a quadratic nonresidue in Fr^*. Both s /// and nqr are members of the class Fp_model defined in /// libff/libff/algebra/fields/fp.hpp . template @@ -216,33 +216,14 @@ template void plonk_generate_random_constants_k1_k2( FieldT &k1_result, FieldT &k2_result); -/// check that the constants k1,k2 \in Fr (section 8.1 [GWC19]) are -/// valid. this is the case if the sets H, k1H, k2H are -/// non-overlapping, where H = {w, w^1, w^2, ..., 2^n} is a +/// Check that the constants k1,k2 \in Fr (section 8.1 [GWC19]) are +/// valid. This is the case if the sets H, k1H, k2H are +/// non-overlapping, where H = {w, w^1, w^2, ..., w^n} is a /// multiplicative subgroup of Fr of order n with generator w (denoted /// as \omega in [GWC19]). w is a primitive n-th root of unity in Fr /// and n is of the form 2^s where s is the largest power of 2 such -/// that 2^s < p and 2^{s+1} > p, where p is the prime modulus of -/// Fr. see also Section 8.1 in [GWC19]. note that p = 2^s * t + 1 so -/// that p-1 = 2^s t is the order of the multiplicative group Fr^* of -/// the scalar field Fr and s and t are members of the class Fp_model -/// defined in libff/libff/algebra/fields/fp.hpp . -/// -/// the function checks if the following three conditions are -/// simultaneously satisfied: -/// -/// 1) k1^n != 1 ensuring that k1 \notin H -/// 2) k2^n != 1 ensuring that k2 \notin H -/// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) -/// -/// to clarify 3), note that if (k1 k2^-1)^n == 1 then \exists i: 1 <= -/// i <= n: k1 = k2 w^i and so k1 \in k2H. this is because k1 = k2 w^i -/// is equivalent to k1 k2^-1 = w^i, equivalent to (k1 k2^-1)^n = -/// (w^i)^n = 1. the latter follows from the fact that w^i is an n-th -/// root of unity in Fr (for any i: 1<=i<=n). -/// -/// conditions 1) and 2) are special cases of 3) for which resp. k1=1, k2=k1 and -/// k1=1, k2=k2 +/// that 2^s | (r-1), where r is the prime modulus of Fr. See also +/// Section 8.1 in [GWC19]. template bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2); diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 229ca8ca6..f297081ee 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -354,6 +354,21 @@ void plonk_generate_random_constants_k1_k2(FieldT &k1_result, FieldT &k2_result) assert(plonk_are_valid_constants_k1_k2(k1, k2)); } +// The function checks if the following three conditions are +// simultaneously satisfied: +// +// 1) k1^n != 1 ensuring that k1 \notin H +// 2) k2^n != 1 ensuring that k2 \notin H +// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) +// +// To clarify 3), note that if (k1 k2^-1)^n == 1 then \exists i: 1 <= +// i <= n: k1 = k2 w^i and so k1 \in k2H. This is because k1 = k2 w^i +// is equivalent to k1 k2^-1 = w^i, equivalent to (k1 k2^-1)^n = +// (w^i)^n = 1. The latter follows from the fact that w^i is an n-th +// root of unity in Fr (for any i: 1<=i<=n). +// +// conditions 1) and 2) are special cases of 3) for which resp. k1=1, +// k2=k1 and k1=1, k2=k2 template bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) { From a8d0771cd4b18b59742c6c1ab539136a011af149 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 11:52:20 +0000 Subject: [PATCH 139/154] plonk: added validity check 2 for constants k1,k2 to the generic unit test function and removed redundant check 3 from the bls12-381-specific unit test (https://github.com/clearmatics/libsnark/pull/94#discussion_r1046255658) --- .../plonk/tests/test_plonk.cpp | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index dce28e70a..055c37488 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1101,9 +1101,43 @@ template void test_plonk_constants_k1_k2() ppT::init_public_params(); using Field = libff::Fr; + + // Check that plonk_generate_constants_k1_k2 generates valid k1 + // and k2 Field k1, k2; plonk_generate_constants_k1_k2(k1, k2); ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); + + // store the valid choices for k1,k2 + Field k1_valid = k1; + Field k2_valid = k2; + // example value for the number of gates (must be power of 2) + size_t num_gates = 8; + // generate the n-th root of unity used as a generator of the + // multiplicative group H of size num_gates + Field omega_base = libff::get_root_of_unity(num_gates); + + // Check that plonk_are_valid_constants_k1_k2 correctly detects + // invalid combinations of k1 and k2 + for (size_t i = 1; i <= num_gates; ++i) { + size_t ipower = i; + // set k2 to an element of k1H: k2=k1*(omega^i) + k1 = k1_valid; + k2 = k1 * (omega_base ^ ipower); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); + // set k1 to an element of k2H: k1=k2*(omega^i) + k2 = k2_valid; + k1 = k2 * (omega_base ^ ipower); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); + // set k1 to an element of H: k1=omega^i + k1 = (omega_base ^ ipower); + k2 = k2_valid; + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); + // set k2 to an element of H: k2=omega^i + k1 = k1_valid; + k2 = (omega_base ^ ipower); + ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); + } } // generic test for all curves for an alternative method to generate @@ -1155,13 +1189,6 @@ template void test_plonk_constants_k1_k2_bls12_381() k2 = (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); } - - // Check that plonk_generate_constants_k1_k2 generates valid k1 - // and k2 - k1 = 0; - k2 = 0; - plonk_generate_constants_k1_k2(k1, k2); - ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); } TEST(TestPlonkConstantsK1K2, Edwards) From e292c7d0b97d9842e273b741e5ac61cb58b47745 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 12:06:30 +0000 Subject: [PATCH 140/154] plonk: moved comment inside function plus other minor edits (https://github.com/clearmatics/libsnark/pull/94#discussion_r1046267951) --- .../plonk/tests/test_plonk.cpp | 4 +-- libsnark/zk_proof_systems/plonk/utils.tcc | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 055c37488..372aa1edd 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1162,14 +1162,14 @@ template void test_plonk_constants_k1_k2_bls12_381() Field k1, k2; // Check that the example k1 and k2 are valid (according to - // plonk_are_valid_constants_k1_k2)" + // plonk_are_valid_constants_k1_k2. plonk_example example; k1 = example.k1; k2 = example.k2; ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); // Check that plonk_are_valid_constants_k1_k2 correctly detects - // invalid combinations of k1 and k2 + // invalid combinations of k1 and k2. for (size_t i = 1; i <= example.num_gates; ++i) { size_t ipower = i; // set k2 to an element of k1H: k2=k1*(omega^i) diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index f297081ee..52b0ee31c 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -354,24 +354,25 @@ void plonk_generate_random_constants_k1_k2(FieldT &k1_result, FieldT &k2_result) assert(plonk_are_valid_constants_k1_k2(k1, k2)); } -// The function checks if the following three conditions are -// simultaneously satisfied: -// -// 1) k1^n != 1 ensuring that k1 \notin H -// 2) k2^n != 1 ensuring that k2 \notin H -// 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) -// -// To clarify 3), note that if (k1 k2^-1)^n == 1 then \exists i: 1 <= -// i <= n: k1 = k2 w^i and so k1 \in k2H. This is because k1 = k2 w^i -// is equivalent to k1 k2^-1 = w^i, equivalent to (k1 k2^-1)^n = -// (w^i)^n = 1. The latter follows from the fact that w^i is an n-th -// root of unity in Fr (for any i: 1<=i<=n). -// -// conditions 1) and 2) are special cases of 3) for which resp. k1=1, -// k2=k1 and k1=1, k2=k2 template bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) { + // The function checks if the following three conditions are + // simultaneously satisfied: + // + // 1) k1^n != 1 ensuring that k1 \notin H + // 2) k2^n != 1 ensuring that k2 \notin H + // 3) (k1 k2^-1)^n != 1 ensuring that k2H \notin k1H (and vice-versa) + // + // To clarify 3), note that if (k1 k2^-1)^n == 1 then \exists i: 1 <= + // i <= n: k1 = k2 w^i and so k1 \in k2H. This is because k1 = k2 w^i + // is equivalent to k1 k2^-1 = w^i, equivalent to (k1 k2^-1)^n = + // (w^i)^n = 1. The latter follows from the fact that w^i is an n-th + // root of unity in Fr (for any i: 1<=i<=n). + // + // conditions 1) and 2) are special cases of 3) for which resp. k1=1, + // k2=k1 and k1=1, k2=k2 + // n = 2^s: maximum order of the H subgroup that is power of 2 const size_t n = std::pow(2, FieldT::s); const bool k1_outside_H = ((k1 ^ n) != FieldT::one()); From 2aa6416bbbdca8dcfc2955e180f2be3f78bf0bd7 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 12:13:46 +0000 Subject: [PATCH 141/154] plonk: removed ppT template parameter from bls12-381-specific test function. --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 372aa1edd..e60bf394d 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1154,10 +1154,9 @@ template void test_plonk_random_constants_k1_k2() // test specific to BLS12-381 (uses class example specific to // BLS12-381) -template void test_plonk_constants_k1_k2_bls12_381() +void test_plonk_constants_k1_k2_bls12_381() { - ppT::init_public_params(); - + using ppT = libff::bls12_381_pp; using Field = libff::Fr; Field k1, k2; @@ -1237,7 +1236,7 @@ TEST(TestPlonkConstantsK1K2, BLS12_381) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); - test_plonk_constants_k1_k2_bls12_381(); + test_plonk_constants_k1_k2_bls12_381(); } TEST(TestPlonk, BLS12_381) From eeecd714d76a1a5be464a4f9f32b23b2859ba0a8 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 16:42:28 +0000 Subject: [PATCH 142/154] plonk: edited sentences in comments to start with capital letter and end with full-stop at the end (https://github.com/clearmatics/libsnark/pull/94#discussion_r1046256563) --- libsnark/zk_proof_systems/plonk/prover.tcc | 62 +++---- libsnark/zk_proof_systems/plonk/srs.tcc | 30 ++-- .../plonk/tests/test_plonk.cpp | 160 +++++++++--------- libsnark/zk_proof_systems/plonk/utils.hpp | 16 +- libsnark/zk_proof_systems/plonk/utils.tcc | 8 +- libsnark/zk_proof_systems/plonk/verifier.tcc | 32 ++-- 6 files changed, 155 insertions(+), 153 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/prover.tcc b/libsnark/zk_proof_systems/plonk/prover.tcc index eb490b652..a59577985 100644 --- a/libsnark/zk_proof_systems/plonk/prover.tcc +++ b/libsnark/zk_proof_systems/plonk/prover.tcc @@ -78,7 +78,7 @@ round_one_out_t plonk_prover::round_one( std::vector>> W_polys_blinded; std::vector> W_polys_blinded_at_secret_g1; - // compute witness polynomials via Lagrange interpolation + // Compute witness polynomials via Lagrange interpolation. W_polys.resize(nwitness, polynomial(srs.num_gates)); for (size_t i = 0; i < nwitness; ++i) { typename std::vector::const_iterator begin = @@ -90,15 +90,15 @@ round_one_out_t plonk_prover::round_one( W_points, W_polys[i], domain); } - // represent the blinding scalars b1, b2, ..., b9 as polynomials + // Represent the blinding scalars b1, b2, ..., b9 as polynomials. std::vector> blind_polys{ {blind_scalars[1], blind_scalars[0]}, // b1 + b0 X {blind_scalars[3], blind_scalars[2]}, // b3 + b2 X {blind_scalars[5], blind_scalars[4]} // b5 + b4 X }; - // compute blinded witness polynomials e.g. a_poly = - // blind_polys[0] * zh_poly + W_polys[0] + // Compute blinded witness polynomials e.g. a_poly = + // blind_polys[0] * zh_poly + W_polys[0]. W_polys_blinded.resize(nwitness); for (size_t i = 0; i < nwitness; ++i) { libfqfft::_polynomial_multiplication( @@ -106,12 +106,12 @@ round_one_out_t plonk_prover::round_one( libfqfft::_polynomial_addition( W_polys_blinded[i], W_polys_blinded[i], W_polys[i]); } - // evaluate blinded witness polynomials at the secret input + // Evaluate blinded witness polynomials at the secret input. W_polys_blinded_at_secret_g1.resize(W_polys_blinded.size()); plonk_evaluate_polys_at_secret_G1( srs.secret_powers_g1, W_polys_blinded, W_polys_blinded_at_secret_g1); - // add outputs from Round 1 to the hash buffer + // Add outputs from Round 1 to the hash buffer. hasher.add_element(W_polys_blinded_at_secret_g1[a]); hasher.add_element(W_polys_blinded_at_secret_g1[b]); hasher.add_element(W_polys_blinded_at_secret_g1[c]); @@ -147,12 +147,12 @@ round_two_out_t plonk_prover::round_two( polynomial> z_poly; libff::G1 z_poly_at_secret_g1; - // compute permutation polynomial + // Compute permutation polynomial. // blinding polynomial: b8 + b7 X + b6 X^2 std::vector z1_blind_poly{ blind_scalars[8], blind_scalars[7], blind_scalars[6]}; - // multiply by the vanishing polynomial: z1 = z1 * this->zh_poly + // Multiply by the vanishing polynomial: z1 = z1 * this->zh_poly. libfqfft::_polynomial_multiplication( z1_blind_poly, z1_blind_poly, round_zero_out.zh_poly); @@ -163,12 +163,12 @@ round_two_out_t plonk_prover::round_two( polynomial A_poly(srs.num_gates); plonk_interpolate_polynomial_from_points(A_vector, A_poly, domain); - // add blinding polynomial z_1 to the accumulator polynomial A_poly + // Add blinding polynomial z_1 to the accumulator polynomial A_poly. libfqfft::_polynomial_addition(z_poly, z1_blind_poly, A_poly); z_poly_at_secret_g1 = plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, z_poly); - // add outputs from Round 2 to the hash buffer + // Add outputs from Round 2 to the hash buffer. hasher.add_element(z_poly_at_secret_g1); round_two_out_t round_two_out( @@ -213,7 +213,7 @@ round_three_out_t plonk_prover::round_three( // Computing the polynomial z(x*w) i.e. z(x) shifted by w where // w=srs.omega_roots is the base root of unity and z is - // z_poly. we do this by multiplying the coefficients of z by w + // z_poly. we do this by multiplying the coefficients of z by w. z_poly_xomega.resize(round_two_out.z_poly.size()); std::fill(z_poly_xomega.begin(), z_poly_xomega.end(), Field(0)); for (size_t i = 0; i < round_two_out.z_poly.size(); ++i) { @@ -223,9 +223,9 @@ round_three_out_t plonk_prover::round_three( z_poly_xomega[i] = round_two_out.z_poly[i] * omega_roots_i; } - // start computation of polynomial t(X) in round 3. we break t + // Start computation of polynomial t(X) in round 3. we break t // into 4 parts which we compute separately. each of the 4 parts - // is multiplied by 1/zh_poly in the paper + // is multiplied by 1/zh_poly in the paper. std::vector> t_part(4); // --- Computation of t_part[0] @@ -289,13 +289,13 @@ round_three_out_t plonk_prover::round_three( // To obtain the index of the PI in w_R we do a modulo num_gates (= 8) // operation to skip the w_L vector (first 8 entries in w). std::vector PI_points(srs.num_gates, Field(0)); - // loop over all wire indices that correspond to PIs + // Loop over all wire indices that correspond to PIs. for (size_t i = 0; i < srs.PI_wire_indices.size(); i++) { const Field PI_value = witness[srs.PI_wire_indices[i]]; const size_t PI_coordinate_x = srs.PI_wire_indices[i] % srs.num_gates; PI_points[PI_coordinate_x] = Field(-PI_value); } - // compute the PI polynomial from the list of points using iFFT + // Compute the PI polynomial from the list of points using iFFT. polynomial PI_poly; plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); @@ -317,9 +317,9 @@ round_three_out_t plonk_prover::round_three( {Field(0), beta * srs.k1}, // X*beta*k1 {Field(0), beta * srs.k2} // X*beta*k2 }; - // represent gamma as polynomial in X, needed for prover Round 3 + // Represent gamma as polynomial in X, needed for prover Round 3. polynomial gamma_poly{gamma}; // gamma - // represent alpha as polynomial in X, needed for prover Round 3 + // Represent alpha as polynomial in X, needed for prover Round 3. polynomial alpha_poly{alpha}; // alpha // a(x) + beta*x + gamma @@ -357,7 +357,7 @@ round_three_out_t plonk_prover::round_three( // --- Computation of t_part[2] - // represent beta as polynomial in X, needed for prover Round 3 + // Represent beta as polynomial in X, needed for prover Round 3. polynomial beta_poly{beta}; // S*beta as polynomial // S_sigma1(x)*beta, S_sigma2(x)*beta, S_sigma3(x)*beta @@ -437,9 +437,9 @@ round_three_out_t plonk_prover::round_three( throw std::logic_error("Non-zero remainder in polynomial division"); } - // break this->t_poly_long into three parts: lo, mid, hi, each of + // Break this->t_poly_long into three parts: lo, mid, hi, each of // degree (num_gates-1). note: (srs.num_gates+3) is the length of - // the CRS = (srs.num_gates+2) powers of G1 + 1 power of G2 + // the CRS = (srs.num_gates+2) powers of G1 + 1 power of G2. t_poly.resize(num_hgen); for (int i = 0; i < num_hgen; ++i) { typename std::vector::iterator begin = @@ -451,14 +451,14 @@ round_three_out_t plonk_prover::round_three( t_poly[i] = tmp; } - // evaluate each part of t_poly in the secret input + // Evaluate each part of t_poly in the secret input. t_poly_at_secret_g1.resize(num_hgen); for (int i = 0; i < num_hgen; ++i) { t_poly_at_secret_g1[i] = plonk_evaluate_poly_at_secret_G1( srs.secret_powers_g1, t_poly[i]); } - // add outputs from Round 3 to the hash buffer + // Add outputs from Round 3 to the hash buffer. hasher.add_element(t_poly_at_secret_g1[lo]); hasher.add_element(t_poly_at_secret_g1[mid]); hasher.add_element(t_poly_at_secret_g1[hi]); @@ -527,7 +527,7 @@ round_four_out_t plonk_prover::round_four( round_three_out.z_poly_xomega, zeta); - // add outputs from Round 4 to the hash buffer + // Add outputs from Round 4 to the hash buffer. hasher.add_element(a_zeta); hasher.add_element(b_zeta); hasher.add_element(c_zeta); @@ -581,13 +581,13 @@ round_five_out_t plonk_prover::round_five( libff::G1 W_zeta_at_secret; libff::G1 W_zeta_omega_at_secret; - // compute linerisation polynomial r in five parts + // Compute linerisation polynomial r in five parts. std::vector> r_part(5); // --- Computation of r_part[0] - // represent values as constant term polynomials in orderto use - // the functions in the libfqfft library on polynomials + // Represent values as constant term polynomials in orderto use + // the functions in the libfqfft library on polynomials. polynomial a_zeta_poly{round_four_out.a_zeta}; polynomial b_zeta_poly{round_four_out.b_zeta}; polynomial c_zeta_poly{round_four_out.c_zeta}; @@ -658,7 +658,7 @@ round_five_out_t plonk_prover::round_five( // r(x) = r(x) - zh(zeta) (t_lo(x) + zeta^n t_mid(x) + zeta^2n t_hi(x)) // // In the reference implementation \[PlonkPy], the missing term is - // added in the computation of the W_zeta(x) polynomial + // added in the computation of the W_zeta(x) polynomial. // // linearisation polynomial r(x) polynomial r_poly; @@ -675,11 +675,11 @@ round_five_out_t plonk_prover::round_five( // implementation, r_zeta is added to the pi-SNARK proof. In the // paper this is omitted, which makes the proof shorter at the // epxense of a slightly heavier computation on the verifier's - // side + // side. r_zeta = libfqfft::evaluate_polynomial(r_poly.size(), r_poly, zeta); // W_zeta polynomial is of degree 6 in the random element nu and - // hence has 7 terms + // hence has 7 terms. std::vector> W_zeta_part(7); // --- compute W_zeta_part[0] @@ -833,13 +833,13 @@ round_five_out_t plonk_prover::round_five( // assert(W_zeta_omega == example.W_zeta_omega); // Evaluate polynomials W_zeta and W_zeta_omega at the seceret - // input + // input. W_zeta_at_secret = plonk_evaluate_poly_at_secret_G1(srs.secret_powers_g1, W_zeta); W_zeta_omega_at_secret = plonk_evaluate_poly_at_secret_G1( srs.secret_powers_g1, W_zeta_omega); - // add outputs from Round 5 to the hash buffer + // Add outputs from Round 5 to the hash buffer. hasher.add_element(r_zeta); hasher.add_element(W_zeta_at_secret); hasher.add_element(W_zeta_omega_at_secret); diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index fe8335644..fb9c1e584 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -70,7 +70,7 @@ template usrs plonk_usrs_derive_from_secret( const libff::Fr &secret, const size_t max_degree) { - // compute powers of secret times G1: 1*G1, secret^1*G1, secret^2*G1, ... + // Compute powers of secret times G1: 1*G1, secret^1*G1, secret^2*G1, ... const libff::bigint::num_limbs> secret_bigint = secret.as_bigint(); const size_t window_size = std::max( @@ -90,7 +90,7 @@ usrs plonk_usrs_derive_from_secret( secret_powers_g1.push_back(secret_i_g1); } - // compute powers of secret times G2: 1*G2, secret^1*G2 + // Compute powers of secret times G2: 1*G2, secret^1*G2. // Note: in Plonk we *always* have 2 encoded elemnts in G2 std::vector> secret_powers_g2; secret_powers_g2.reserve(2); @@ -115,28 +115,28 @@ srs plonk_srs_derive_from_usrs( const std::vector> gates_matrix_transpose = plonk_gates_matrix_transpose(gates_matrix); - // the number of gates is equal to the number of columns in the transposed - // gates matrix + // The number of gates is equal to the number of columns in the + // transposed gates matrix. size_t num_gates = gates_matrix_transpose[0].size(); - // ensure that num_gates is not 0 + // Ensure that num_gates is not 0. assert(num_gates > 0); - // ensure num_gates is power of 2 + // Ensure num_gates is power of 2. assert((num_gates & (num_gates - 1)) == 0); - // the number of Q-polynomials (aka selector polynomials) is equal to the - // number of rows in the transposed gates matrix + // The number of Q-polynomials (aka selector polynomials) is equal + // to the number of rows in the transposed gates matrix. size_t num_qpolys = gates_matrix_transpose.size(); - // the constraints q_L, q_R, q_O, q_M, q_C and the + // The constraints q_L, q_R, q_O, q_M, q_C and the // witness w_L, w_R, w_O are represented as polynomials in the roots of - // unity e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8 + // unity e.g. f_{q_L}(omega_i) = q_L[i], 0\le{i}<8. std::shared_ptr> domain = libfqfft::get_evaluation_domain(num_gates); - // compute the selector polynomials (q-polynomials) from the + // Compute the selector polynomials (q-polynomials) from the // transposed gates matrix over the Lagrange basis q_poly = \sum_i // q[i] * L[i] where q[i] is a coefficient (a scalar Field - // element) and L[i] is a polynomial with Field coefficients + // element) and L[i] is a polynomial with Field coefficients. std::vector> Q_polys = plonk_compute_selector_polynomials( num_gates, num_qpolys, gates_matrix_transpose, domain); @@ -202,7 +202,7 @@ srs plonk_srs_derive_from_usrs( // TODO: write unit test for plonk_compute_cosets_H_k1H_k2H // assert(H_prime[i] == example.H_prime[i]); - // permute H_prime according to the wire permutation + // Permute H_prime according to the wire permutation. std::vector H_prime_permute = plonk_permute_subgroup_H(H_prime, wire_permutation, num_gates); @@ -210,7 +210,7 @@ srs plonk_srs_derive_from_usrs( // assert(H_prime_permute[i] == example.H_prime_permute[i]); // Compute the permutation polynomials S_sigma_1, S_sigma_2, - // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0) + // S_sigma_3 (see [GWC19], Sect. 8.1) (our indexing starts from 0). std::vector> S_polys = plonk_compute_permutation_polynomials( H_prime_permute, num_gates, domain); @@ -230,7 +230,7 @@ srs plonk_srs_derive_from_usrs( secret_powers_g2.push_back(usrs.secret_powers_g2[i]); } - // compute 0-th Lagrange basis vector via inverse FFT + // Compute 0-th Lagrange basis vector via inverse FFT. polynomial> L_basis_zero(num_gates, libff::Fr(0)); L_basis_zero[0] = libff::Fr(1); domain->iFFT(L_basis_zero); diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index e60bf394d..d33bec489 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -32,7 +32,7 @@ namespace libsnark #define PLONK_MAX_DEGREE 245 // Manipulate elements of a valid proof to assert that proof -// verification fails +// verification fails. // // Plonk proof Pi is composed of the following elements: // @@ -305,7 +305,7 @@ void test_plonk_prover_round_four( round_four_out_t round_four_out = plonk_prover::round_four( zeta, round_one_out, round_three_out, srs, hasher); - // Prover Round 4 output check against test vectors + // Prover Round 4 output check against test vectors. printf("[%s:%d] Output from Round 4\n", __FILE__, __LINE__); printf("a_zeta "); round_four_out.a_zeta.print(); @@ -381,14 +381,14 @@ void test_plonk_prover_round_five( } /// \attention the example class is defined specifically for the BLS12-381 -/// curve, so make sure we are using this curve +/// curve, so make sure we are using this curve. template void test_plonk_prover_rounds() { using Field = libff::Fr; ppT::init_public_params(); - // load test vector values from example circuit + // Load test vector values from example circuit. plonk_example example; // random hidden element secret (toxic waste) Field secret = example.secret; @@ -420,20 +420,20 @@ template void test_plonk_prover_rounds() plonk_prover::round_zero(srs); // --- Unit test Prover Round 1 --- - // reset buffer at the start of the round (needed for testing only) + // Reset buffer at the start of the round (needed for testing only). printf("[%s:%d] Unit test Prover Round 1...\n", __FILE__, __LINE__); test_plonk_prover_round_one( example, round_zero_out, witness, srs, domain, hasher); // --- Unit test Prover Round 2 --- - // reset buffer at the start of the round (needed for testing only) + // Reset buffer at the start of the round (needed for testing only). printf("[%s:%d] Unit test Prover Round 2...\n", __FILE__, __LINE__); round_one_out_t round_one_out = plonk_prover::round_one( round_zero_out, blind_scalars, witness, srs, domain, hasher); // clear hash buffer hasher.buffer_clear(); - // add outputs from Round 1 to the hash buffer + // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); @@ -456,7 +456,7 @@ template void test_plonk_prover_rounds() example, beta, gamma, witness, srs, domain); // --- Unit test Prover Round 3 --- - // reset buffer at the start of the round (needed for testing only) + // Reset buffer at the start of the round (needed for testing only). printf("[%s:%d] Prover Round 3...\n", __FILE__, __LINE__); round_two_out_t round_two_out = plonk_prover::round_two( @@ -468,14 +468,14 @@ template void test_plonk_prover_rounds() srs, domain, hasher); - // clear hash buffer + // Clear hash buffer. hasher.buffer_clear(); - // add outputs from Round 1 to the hash buffer + // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); hasher.add_element(libff::Fr::one()); - // add outputs from Round 2 to the hash buffer + // Add outputs from Round 2 to the hash buffer. hasher.add_element(round_two_out.z_poly_at_secret_g1); const libff::Fr alpha = hasher.get_hash(); test_plonk_prover_round_three( @@ -503,16 +503,16 @@ template void test_plonk_prover_rounds() witness, srs, hasher); - // clear hash buffer + // Clear hash buffer. hasher.buffer_clear(); - // add outputs from Round 1 to the hash buffer + // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); hasher.add_element(libff::Fr::one()); - // add outputs from Round 2 to the hash buffer + // Add outputs from Round 2 to the hash buffer. hasher.add_element(round_two_out.z_poly_at_secret_g1); - // add outputs from Round 3 to the hash buffer + // Add outputs from Round 3 to the hash buffer. hasher.add_element(round_three_out.t_poly_at_secret_g1[lo]); hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); @@ -525,20 +525,20 @@ template void test_plonk_prover_rounds() round_four_out_t round_four_out = plonk_prover::round_four( zeta, round_one_out, round_three_out, srs, hasher); - // clear hash buffer + // Clear hash buffer. hasher.buffer_clear(); - // add outputs from Round 1 to the hash buffer + // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[c]); hasher.add_element(libff::Fr::one()); - // add outputs from Round 2 to the hash buffer + // Add outputs from Round 2 to the hash buffer. hasher.add_element(round_two_out.z_poly_at_secret_g1); - // add outputs from Round 3 to the hash buffer + // Add outputs from Round 3 to the hash buffer. hasher.add_element(round_three_out.t_poly_at_secret_g1[lo]); hasher.add_element(round_three_out.t_poly_at_secret_g1[mid]); hasher.add_element(round_three_out.t_poly_at_secret_g1[hi]); - // add outputs from Round 4 to the hash buffer + // Add outputs from Round 4 to the hash buffer. hasher.add_element(round_four_out.a_zeta); hasher.add_element(round_four_out.b_zeta); hasher.add_element(round_four_out.c_zeta); @@ -570,7 +570,7 @@ template void test_plonk_srs() ppT::init_public_params(); - // load test vector values from example circuit + // Load test vector values from example circuit. plonk_example example; // random hidden element secret (toxic waste) Field secret = example.secret; @@ -581,8 +581,8 @@ template void test_plonk_srs() libfqfft::get_evaluation_domain(example.num_gates); // --- USRS --- - // compute SRS = powers of secret times G1: 1*G1, secret^1*G1, - // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2 + // Compute SRS = powers of secret times G1: 1*G1, secret^1*G1, + // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); // --- SRS --- srs srs = plonk_srs_derive_from_usrs( @@ -590,7 +590,7 @@ template void test_plonk_srs() example.gates_matrix, example.wire_permutation, example.PI_wire_indices); - // compare SRS against reference test values + // Compare SRS against reference test values. printf("[%s:%d] secret ", __FILE__, __LINE__); secret.print(); for (int i = 0; i < (int)srs.num_gates + 3; ++i) { @@ -615,9 +615,9 @@ template void test_plonk_prover() using Field = libff::Fr; ppT::init_public_params(); - // load test vector values from example circuit + // Load test vector values from example circuit. plonk_example example; - // random hidden element secret (toxic waste) + // Random hidden element secret (toxic waste). Field secret = example.secret; // example witness std::vector witness = example.witness; @@ -630,7 +630,7 @@ template void test_plonk_prover() std::shared_ptr> domain = libfqfft::get_evaluation_domain(example.num_gates); - // prepare srs + // Perepare srs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs( usrs, @@ -638,15 +638,15 @@ template void test_plonk_prover() example.wire_permutation, example.PI_wire_indices); - // initialize hasher + // Initialize hasher. transcript_hasher hasher; - // initialize prover + // Initialize prover. plonk_prover prover; - // compute proof + // Compute proof. plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // compare proof against test vector values (debug) + // Compare proof against test vector values (debug). ASSERT_EQ(proof.a_zeta, example.a_zeta); ASSERT_EQ(proof.b_zeta, example.b_zeta); ASSERT_EQ(proof.c_zeta, example.c_zeta); @@ -698,7 +698,7 @@ template void test_plonk_verifier_preprocessed_input( const plonk_example &example, const srs &srs) { - // compute verifier preprocessed input + // Compute verifier preprocessed input. const verifier_preprocessed_input_t preprocessed_input = plonk_verifier::preprocessed_input(srs); @@ -902,22 +902,22 @@ template void test_plonk_verifier_steps() using Field = libff::Fr; ppT::init_public_params(); - // load test vector values from example circuit + // Load test vector values from example circuit. plonk_example example; - // random hidden element secret (toxic waste) + // Random hidden element secret (toxic waste). Field secret = example.secret; - // example witness + // Example witness std::vector witness = example.witness; - // hard-coded values for the "random" blinding constants from + // Hard-coded values for the "random" blinding constants from. // example circuit std::vector> blind_scalars = example.prover_blind_scalars; - // maximum degree of the encoded monomials in the usrs + // Maximum degree of the encoded monomials in the usrs. size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = libfqfft::get_evaluation_domain(example.num_gates); - // prepare srs + // Prepare srs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs( usrs, @@ -925,31 +925,31 @@ template void test_plonk_verifier_steps() example.wire_permutation, example.PI_wire_indices); - // initialize hasher + // Initialize hasher. transcript_hasher hasher; - // initialize prover + // Initialize prover. plonk_prover prover; - // compute proof + // Compute proof. plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // clear the hasher buffer in order to re-use the same - // transcript_hasher object for the verifier + // Clear the hasher buffer in order to re-use the same + // transcript_hasher object for the verifier. hasher.buffer_clear(); - // Unit test verifier preprocessed input + // Unit test verifier preprocessed input. test_plonk_verifier_preprocessed_input( example, srs); - // prepare the list of PI values for the example circuit + // Prepare the list of PI values for the example circuit. std::vector PI_value_list; for (size_t i = 0; i < example.PI_wire_indices.size(); i++) { Field PI_value = example.witness[example.PI_wire_indices[i]]; PI_value_list.push_back(PI_value); } - // compute step 4 + // Compute step 4 const step_four_out_t step_four_out = plonk_verifier::step_four(proof, hasher); @@ -1026,22 +1026,22 @@ template void test_plonk_verifier() using Field = libff::Fr; ppT::init_public_params(); - // load test vector values from example circuit + // Load test vector values from example circuit. plonk_example example; - // random hidden element secret (toxic waste) + // Random hidden element secret (toxic waste). Field secret = example.secret; - // example witness + // Example witness. std::vector witness = example.witness; - // hard-coded values for the "random" blinding constants from - // example circuit + // Hard-coded values for the "random" blinding constants from + // example circuit. std::vector> blind_scalars = example.prover_blind_scalars; - // maximum degree of the encoded monomials in the usrs + // Maximum degree of the encoded monomials in the usrs. size_t max_degree = PLONK_MAX_DEGREE; std::shared_ptr> domain = libfqfft::get_evaluation_domain(example.num_gates); - // prepare srs + // Prepare srs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); srs srs = plonk_srs_derive_from_usrs( usrs, @@ -1049,37 +1049,37 @@ template void test_plonk_verifier() example.wire_permutation, example.PI_wire_indices); - // initialize hasher + // Initialize hasher. transcript_hasher hasher; - // initialize prover + // Initialize prover. plonk_prover prover; - // compute proof + // Compute proof. plonk_proof proof = prover.compute_proof(srs, witness, blind_scalars, hasher); - // clear the hasher buffer in order to re-use the same - // transcript_hasher object for the verifier + // Clear the hasher buffer in order to re-use the same + // transcript_hasher object for the verifier. hasher.buffer_clear(); - // initialize verifier + // Initialize verifier. plonk_verifier verifier; - // prepare the list of PI values for the example circuit + // Prepare the list of PI values for the example circuit. std::vector PI_value_list; for (size_t i = 0; i < example.PI_wire_indices.size(); i++) { Field PI_value = example.witness[example.PI_wire_indices[i]]; PI_value_list.push_back(PI_value); } - // verify proof + // Verify proof. bool b_valid_proof = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_TRUE(b_valid_proof); - // clear the hasher buffer in order to re-use the same - // transcript_hasher object + // Clear the hasher buffer in order to re-use the same + // transcript_hasher object. hasher.buffer_clear(); - // assert that proof verification fails when the proof is - // manipulated + // Assert that proof verification fails when the proof is + // manipulated. test_verify_invalid_proof(proof, srs, PI_value_list, hasher); } @@ -1088,7 +1088,7 @@ template void test_plonk_verifier() template void test_plonk_gates_matrix_transpose() { using Field = libff::Fr; - // load gates matrix from example circuit + // Load gates matrix from example circuit. plonk_example example; std::vector> gates_matrix_transpose = plonk_gates_matrix_transpose(example.gates_matrix); @@ -1103,37 +1103,37 @@ template void test_plonk_constants_k1_k2() using Field = libff::Fr; // Check that plonk_generate_constants_k1_k2 generates valid k1 - // and k2 + // and k2. Field k1, k2; plonk_generate_constants_k1_k2(k1, k2); ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); - // store the valid choices for k1,k2 + // Store the valid choices for k1,k2. Field k1_valid = k1; Field k2_valid = k2; - // example value for the number of gates (must be power of 2) + // Example value for the number of gates (must be power of 2). size_t num_gates = 8; - // generate the n-th root of unity used as a generator of the - // multiplicative group H of size num_gates + // Generate the n-th root of unity used as a generator of the + // multiplicative group H of size num_gates. Field omega_base = libff::get_root_of_unity(num_gates); // Check that plonk_are_valid_constants_k1_k2 correctly detects - // invalid combinations of k1 and k2 + // invalid combinations of k1 and k2. for (size_t i = 1; i <= num_gates; ++i) { size_t ipower = i; - // set k2 to an element of k1H: k2=k1*(omega^i) + // Set k2 to an element of k1H: k2=k1*(omega^i). k1 = k1_valid; k2 = k1 * (omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // set k1 to an element of k2H: k1=k2*(omega^i) + // Set k1 to an element of k2H: k1=k2*(omega^i). k2 = k2_valid; k1 = k2 * (omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // set k1 to an element of H: k1=omega^i + // Set k1 to an element of H: k1=omega^i. k1 = (omega_base ^ ipower); k2 = k2_valid; ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // set k2 to an element of H: k2=omega^i + // Set k2 to an element of H: k2=omega^i. k1 = k1_valid; k2 = (omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); @@ -1171,19 +1171,19 @@ void test_plonk_constants_k1_k2_bls12_381() // invalid combinations of k1 and k2. for (size_t i = 1; i <= example.num_gates; ++i) { size_t ipower = i; - // set k2 to an element of k1H: k2=k1*(omega^i) + // Set k2 to an element of k1H: k2=k1*(omega^i). k1 = example.k1; k2 = k1 * (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // set k1 to an element of k2H: k1=k2*(omega^i) + // Set k1 to an element of k2H: k1=k2*(omega^i). k2 = example.k2; k1 = k2 * (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // set k1 to an element of H: k1=omega^i + // Set k1 to an element of H: k1=omega^i. k1 = (example.omega_base ^ ipower); k2 = example.k2; ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); - // set k2 to an element of H: k2=omega^i + // Set k2 to an element of H: k2=omega^i. k1 = example.k1; k2 = (example.omega_base ^ ipower); ASSERT_FALSE(plonk_are_valid_constants_k1_k2(k1, k2)); diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index e8125806d..a93787365 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -110,7 +110,7 @@ void plonk_compute_cosets_H_k1H_k2H( const FieldT k2, std::vector &H_prime); -/// permute the multiplicative subgroup H according to the wire +/// Permute the multiplicative subgroup H according to the wire /// permutation: (see [GWC19] Sect. 8), \see /// plonk_compute_roots_of_unity_omega, \see /// plonk_roots_of_unity_omega_to_subgroup_H @@ -120,8 +120,8 @@ std::vector plonk_permute_subgroup_H( const std::vector &wire_permutation, const size_t num_gates); -/// compute the permutation polynomials S_sigma_1, S_sigma_2, -/// S_sigma_2 (see [GWC19], Sect. 8.1) +/// Compute the permutation polynomials S_sigma_1, S_sigma_2, +/// S_sigma_2 (see [GWC19], Sect. 8.1). template std::vector> plonk_compute_permutation_polynomials( const std::vector &H_prime_permute, @@ -157,7 +157,7 @@ libff::G1 plonk_evaluate_poly_at_secret_G1( const polynomial> &f_poly); /// Evaluate a list of polynomials in the encrypted secret input: see -/// plonk_evaluate_poly_at_secret_G1 +/// plonk_evaluate_poly_at_secret_G1. template void plonk_evaluate_polys_at_secret_G1( const std::vector> &secret_powers_g1, @@ -165,8 +165,8 @@ void plonk_evaluate_polys_at_secret_G1( std::vector> &Q_polys_at_secret_g1); /// Compute the factors in the product of the permutation polynomial -/// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], -/// i>0 is computed from values at i-1 for witness[i-1], H_prime[i-1], +/// z(X) in Prover Round 2. Note that accumulator A[0]=1 and A[i], i>0 +/// is computed from values at i-1 for witness[i-1], H_prime[i-1], /// H_prime_permute[i-1]m etc. template FieldT plonk_compute_accumulator_factor( @@ -196,7 +196,7 @@ std::vector> plonk_gates_matrix_transpose( const size_t &nrows, const size_t &ncols); -/// deterministically compute values for the constants k1,k2 \in Fr +/// Deterministically compute values for the constants k1,k2 \in Fr /// (section 8.1 [GWC19]) as k1=g^{2s}, k2=nqr, where s is the largest /// power of 2 such that 2^s < p and 2^{s+1} > p, p is the prime /// modulus of Fr and nqr is a quadratic nonresidue in Fr^*. Both s @@ -205,7 +205,7 @@ std::vector> plonk_gates_matrix_transpose( template void plonk_generate_constants_k1_k2(FieldT &k1_result, FieldT &k2_result); -/// generate values for the constants k1,k2 \in Fr (section 8.1 +/// Generate values for the constants k1,k2 \in Fr (section 8.1 /// [GWC19]) by trying random values until the following three /// conditions are simultaneously satisfied: /// diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 52b0ee31c..cc85aabe7 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -89,7 +89,7 @@ void plonk_compute_roots_of_unity_omega( const FieldT k2, std::vector> &omega) { - // ensure that num_gates is not 0 and is power of 2 + // Ensure that num_gates is not 0 and is power of 2. // TODO: check also that it's less than 2^(ppT::s) bool b_nonzero = (num_gates > 0); bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); @@ -125,7 +125,7 @@ void plonk_compute_cosets_H_k1H_k2H( const FieldT k2, std::vector &H_prime) { - // ensure that num_gates is not 0 and is power of 2 + // Ensure that num_gates is not 0 and is power of 2. bool b_nonzero = (num_gates > 0); bool b_is_power2 = ((num_gates & (num_gates - 1)) == 0); if (!(b_nonzero && b_is_power2)) { @@ -323,9 +323,9 @@ void plonk_generate_constants_k1_k2(FieldT &k1, FieldT &k2) const size_t n = std::pow(2, FieldT::s); // generator of Fr^* const FieldT g = FieldT::multiplicative_generator; - // set k1 = g^{2s} \notin H + // Set k1 = g^{2s} \notin H. k1 = g ^ n; - // set k2 to a quadratic nonresidue of Fr^* + // Set k2 to a quadratic nonresidue of Fr^* . k2 = FieldT::nqr; // assert k1,k2 are valid assert(plonk_are_valid_constants_k1_k2(k1, k2)); diff --git a/libsnark/zk_proof_systems/plonk/verifier.tcc b/libsnark/zk_proof_systems/plonk/verifier.tcc index 8cda463b2..bc320e7b0 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.tcc +++ b/libsnark/zk_proof_systems/plonk/verifier.tcc @@ -59,7 +59,7 @@ template step_four_out_t plonk_verifier::step_four( const plonk_proof &proof, transcript_hasher &hasher) { - // add outputs from Round 1 to the hash buffer + // Add outputs from Round 1 to the hash buffer. hasher.add_element(proof.W_polys_blinded_at_secret_g1[a]); hasher.add_element(proof.W_polys_blinded_at_secret_g1[b]); hasher.add_element(proof.W_polys_blinded_at_secret_g1[c]); @@ -72,19 +72,20 @@ step_four_out_t plonk_verifier::step_four( hasher.add_element(libff::Fr::one()); libff::Fr gamma = hasher.get_hash(); - // add outputs from Round 2 to the hash buffer + // Add outputs from Round 2 to the hash buffer. hasher.add_element(proof.z_poly_at_secret_g1); // - alpha: quotient challenge - hash of transcript of rounds 1,2 libff::Fr alpha = hasher.get_hash(); - // add outputs from Round 3 to the hash buffer + // Add outputs from Round 3 to the hash buffer. hasher.add_element(proof.t_poly_at_secret_g1[lo]); hasher.add_element(proof.t_poly_at_secret_g1[mid]); hasher.add_element(proof.t_poly_at_secret_g1[hi]); - // - zeta: evaluation challenge - hash of transcriptof rounds 1,2,3 + // - zeta: evaluation challenge - hash of transcriptof rounds + // - 1,2,3 libff::Fr zeta = hasher.get_hash(); - // add outputs from Round 4 to the hash buffer + // Add outputs from Round 4 to the hash buffer. hasher.add_element(proof.a_zeta); hasher.add_element(proof.b_zeta); hasher.add_element(proof.c_zeta); @@ -95,7 +96,7 @@ step_four_out_t plonk_verifier::step_four( // [GWC19]) libff::Fr nu = hasher.get_hash(); - // add outputs from Round 5 to the hash buffer + // Add outputs from Round 5 to the hash buffer. hasher.add_element(proof.r_zeta); hasher.add_element(proof.W_zeta_at_secret); hasher.add_element(proof.W_zeta_omega_at_secret); @@ -157,15 +158,16 @@ step_seven_out_t plonk_verifier::step_seven( { std::shared_ptr> domain = libfqfft::get_evaluation_domain(srs.num_gates); - // construct the PI polynomial from the vector of PI values (received as - // input to the verifier) and the PI wire indices (stored in the srs) + // Construct the PI polynomial from the vector of PI values + // (received as input to the verifier) and the PI wire indices + // (stored in the srs). std::vector PI_points(srs.num_gates, Field(0)); for (size_t i = 0; i < PI_value_list.size(); i++) { size_t PI_coordinate_x = srs.PI_wire_indices[i] % srs.num_gates; PI_points[PI_coordinate_x] = Field(-PI_value_list[i]); } - // compute PI polynomial + // Compute PI polynomial. polynomial PI_poly; plonk_compute_public_input_polynomial(PI_points, PI_poly, domain); @@ -193,7 +195,7 @@ step_eight_out_t plonk_verifier::step_eight( libff::Fr r_prime_zeta; Field alpha_power2 = libff::power(step_four_out.alpha, libff::bigint<1>(2)); - // compute polynomial r'(zeta) = r(zeta) - r_0 + // Compute polynomial r'(zeta) = r(zeta) - r_0 . std::vector r_prime_parts(5); r_prime_parts[0] = proof.r_zeta + step_seven_out.PI_zeta; r_prime_parts[1] = @@ -234,7 +236,7 @@ step_nine_out_t plonk_verifier::step_nine( Field alpha_power2 = libff::power(step_four_out.alpha, libff::bigint<1>(2)); - // compute D1_part[0]: + // Compute D1_part[0]: // (a_bar b_bar [q_M]_1 + a_bar [q_L]_1 + b_bar [q_R]_1 + c_bar [q_O]_1 + // [q_C]_1) nu Note: the paper omits the final multiplication by nu std::vector> curve_points{ @@ -251,7 +253,7 @@ step_nine_out_t plonk_verifier::step_nine( step_four_out.nu}; D1_part[0] = plonk_multi_exp_G1(curve_points, scalar_elements); - // compute D1_part[1]: + // Compute D1_part[1]: // ((a_bar + beta zeta + gamma)(b_bar + beta k1 zeta + gamma)(c_bar + beta // k2 zeta + gamma) alpha + L1(zeta) alpha^2 + u) [z]_1 Field D1_part1_scalar = @@ -266,7 +268,7 @@ step_nine_out_t plonk_verifier::step_nine( step_four_out.u; D1_part[1] = D1_part1_scalar * proof.z_poly_at_secret_g1; - // compute D1_part[2]: + // Compute D1_part[2]: // (a_bar + beta s_sigma1_bar + gamma)(b_bar + beta s_sigma2_bar + // gamma)alpha beta z_preprocessed_input.omega_roots_bar [s_sigma3]_1 Field D1_part2_scalar = @@ -279,7 +281,7 @@ step_nine_out_t plonk_verifier::step_nine( Field(-1); D1_part[2] = D1_part2_scalar * preprocessed_input.S_polys_at_secret_g1[2]; - // Compute D1 = D1_part[0] + D1_part[1] + D1_part[2] + // Compute D1 = D1_part[0] + D1_part[1] + D1_part[2] . D1 = D1_part[0] + D1_part[1] + D1_part[2]; step_nine_out_t step_nine_out(std::move(D1)); @@ -420,7 +422,7 @@ bool plonk_verifier::verify_proof( std::shared_ptr>> domain = libfqfft::get_evaluation_domain>(srs.num_gates); - // compute verifier preprocessed input + // Compute verifier preprocessed input. const verifier_preprocessed_input_t preprocessed_input = plonk_verifier::preprocessed_input(srs); From faf06424337e47fce06fca9af62ddd0c75182009 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 18:46:05 +0000 Subject: [PATCH 143/154] plonk: changed several variables to const type and removed an extra variable (https://github.com/clearmatics/libsnark/pull/94#discussion_r1049947746) --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index d33bec489..416de03ff 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1109,18 +1109,17 @@ template void test_plonk_constants_k1_k2() ASSERT_TRUE(plonk_are_valid_constants_k1_k2(k1, k2)); // Store the valid choices for k1,k2. - Field k1_valid = k1; - Field k2_valid = k2; + const Field k1_valid = k1; + const Field k2_valid = k2; // Example value for the number of gates (must be power of 2). - size_t num_gates = 8; + const size_t num_gates = 8; // Generate the n-th root of unity used as a generator of the // multiplicative group H of size num_gates. - Field omega_base = libff::get_root_of_unity(num_gates); + const Field omega_base = libff::get_root_of_unity(num_gates); // Check that plonk_are_valid_constants_k1_k2 correctly detects // invalid combinations of k1 and k2. - for (size_t i = 1; i <= num_gates; ++i) { - size_t ipower = i; + for (size_t ipower = 1; ipower <= num_gates; ++ipower) { // Set k2 to an element of k1H: k2=k1*(omega^i). k1 = k1_valid; k2 = k1 * (omega_base ^ ipower); From 4ba7fde2f64bf93c07e223d3e89b9f1b2f347bd1 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Wed, 7 Dec 2022 11:29:49 +0000 Subject: [PATCH 144/154] plonk: added helper function for preparing the gates matrix (Issue https://github.com/clearmatics/libsnark/issues/89) --- .../plonk/tests/test_plonk.cpp | 13 ++++++++ libsnark/zk_proof_systems/plonk/utils.hpp | 7 ++++ libsnark/zk_proof_systems/plonk/utils.tcc | 33 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 416de03ff..9751a5cf5 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1095,6 +1095,18 @@ template void test_plonk_gates_matrix_transpose() ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); } +template void test_plonk_prepare_gates_matrix() +{ + using Field = libff::Fr; + const size_t num_public_inputs = 8; + const std::vector> gates_matrix_init = + plonk_prepare_gates_matrix(num_public_inputs); + const std::vector PI_selector_vector{1, 0, 0, 0, 0}; + for (size_t i = 0; i < num_public_inputs; ++i) { + ASSERT_EQ(gates_matrix_init[i], PI_selector_vector); + } +} + // generic test for all curves template void test_plonk_constants_k1_k2() { @@ -1254,6 +1266,7 @@ TEST(TestPlonk, BLS12_381) libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); test_plonk_gates_matrix_transpose(); + test_plonk_prepare_gates_matrix(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index a93787365..a9035a5d7 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -227,6 +227,13 @@ void plonk_generate_random_constants_k1_k2( template bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2); +/// Return a matrix with top N rows filled in with the public inputs +/// selector vectors where N = num_public_inputs is the number of +/// public inputs passed as an input parameter by the caller. +template +std::vector>> plonk_prepare_gates_matrix( + const size_t &num_public_inputs); + } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/utils.tcc" diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index cc85aabe7..0eb268a1f 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -383,6 +383,39 @@ bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) return (k1_outside_H && k2_outside_H && k1_over_k2_outside_H); } +// In general, the i-th row of the gates matrix contains the i-th +// component of the selector vectors q_L, q_M, q_R, q_O, q_C (see +// Section 6 [GWC19]). The i-th compoment of each selector vector is +// determined by the i-th gate of the arithmetic circuit, which can be +// one of the following: addition, multiplication, multiplication by +// constant, public input. In particular, when the i-th gate is a +// public input, the i-th components of the selector vectors are: +// +// (q_L[i], q_M[i], q_R[i], q_O[i], q_C[i]) = (1, 0, 0, 0, 0) +// +// Therefore the top N rows of the initialized gates matrix will have +// the above form. See also Section 6 [GWC19]. +// +// \attention The convention for selector vector values corresponding +// to public inputs (PI) used in this function follows [GWC19] (as +// shown above) and is different from the one used in the example +// circuit for BLS12-381 (class example) where q_R[i]=1 rather than +// q_L[i]=1 i.e. +// +// (q_L[i], q_M[i], q_R[i], q_O[i], q_C[i]) = (0, 1, 0, 0, 0) +template +std::vector>> plonk_prepare_gates_matrix( + const size_t &num_public_inputs) +{ + using FieldT = libff::Fr; + std::vector> gates_matrix_init; + const std::vector PI_selector_vector{1, 0, 0, 0, 0}; + for (size_t i = 0; i < num_public_inputs; ++i) { + gates_matrix_init.push_back(PI_selector_vector); + } + return gates_matrix_init; +} + } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ From b5c3d864a860dd5b9b09e79e7cc108216c28875a Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 9 Dec 2022 12:32:11 +0000 Subject: [PATCH 145/154] plonk: added assert for the size of the returned gates matrix (https://github.com/clearmatics/libsnark/pull/97#discussion_r1042471794) --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 9751a5cf5..ebc5ac59b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1101,6 +1101,7 @@ template void test_plonk_prepare_gates_matrix() const size_t num_public_inputs = 8; const std::vector> gates_matrix_init = plonk_prepare_gates_matrix(num_public_inputs); + ASSERT_EQ(gates_matrix_init.size(), num_public_inputs); const std::vector PI_selector_vector{1, 0, 0, 0, 0}; for (size_t i = 0; i < num_public_inputs; ++i) { ASSERT_EQ(gates_matrix_init[i], PI_selector_vector); From 1c231c953eb30fd2cce79ec5a5ee47475c571601 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 12 Dec 2022 13:05:47 +0000 Subject: [PATCH 146/154] plonk: added proof and verfication for a simple circuit to test the convenience of the gates helper function (https://github.com/clearmatics/libsnark/pull/97#pullrequestreview-1208811967) --- .../plonk/tests/test_plonk.cpp | 139 +++++++++++++++++- libsnark/zk_proof_systems/plonk/utils.hpp | 13 ++ libsnark/zk_proof_systems/plonk/utils.tcc | 27 +++- 3 files changed, 168 insertions(+), 11 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index ebc5ac59b..3034c4940 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1095,17 +1095,140 @@ template void test_plonk_gates_matrix_transpose() ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); } -template void test_plonk_prepare_gates_matrix() +// We test the example circuit y^2 = x mod r where x=49 is a public +// input and y is the witness. We prove that we know y=7 such that y +// is the quadratic residue of x modulo the modulus r of the scalar +// field Fr of the given elliptic curve. The circuit is represented by +// one public input (PI) and one multiplication gate. According to the +// Plonk arithmetization rules, each gate (including the PI) is +// represented as: +// +// qL a + qR b + qO c + qM ab + qC = 0 +// +// where qL,qR,qO,qM,qC are the selector polynomials and +// a,b,c are respectively the vectors of left inputs, right inputs +// and outputs to the gates. +// +// Using the above representation, the PI and the multiplication +// gates are given resp. as +// +// PI: 1 a1 + 0 b1 + 0 c1 + 0 a1 b1 + 0 = 49 +// MUL: 0 a1 + 0 b1 + (-1) c1 + 1 a1 b1 + 0 = 0 +// +// where +// +// a = (a1, a2) = (x, y) +// b = (b1, b2) = (1, y) +// c = (c1, c2) = (x, x) +// qL = (1, 0) +// qR = (0, 0) +// qO = (0, -1) +// qM = (0, 1) +// qC = (0, 0) +// +// The selector polynomials as given above define the following gates +// matrix: +// +// qL qR qO qM qC +// 1 0 0 0 0 +// 0 0 -1 1 0 +// +// and the permutation expressing the copy-constraints is (second +// line below): +// +// (a1 a2 b1 b2 c1 c2) +// (c1 b2 b1 a2 c2 a1) +// +// reflecting the fact that a1=c1=c2=x and a2=b2=y +template +void test_plonk_prepare_gates_matrix() { using Field = libff::Fr; - const size_t num_public_inputs = 8; - const std::vector> gates_matrix_init = + + // 0 Arithmetization of test circuit y^2 = x mod r + + // The number of gates is 2: one public input (PI) gate and one + // multiplication gate. Tis nummer is also conveniently a power of + // 2 (needed for the FFT/iFFT) + const size_t num_gates = 2; + // The tested circuit has 1 public input + const size_t num_public_inputs = 1; + std::vector> gates_matrix = plonk_prepare_gates_matrix(num_public_inputs); - ASSERT_EQ(gates_matrix_init.size(), num_public_inputs); - const std::vector PI_selector_vector{1, 0, 0, 0, 0}; + ASSERT_EQ(gates_matrix.size(), num_public_inputs); + // Add the PI gate/s + const std::vector PI_gate{1, 0, 0, 0, 0}; for (size_t i = 0; i < num_public_inputs; ++i) { - ASSERT_EQ(gates_matrix_init[i], PI_selector_vector); + ASSERT_EQ(gates_matrix[i], PI_gate); + } + // Add the multiplication gate + const std::vector MUL_gate{0, 0, -1, 1, 0}; + gates_matrix.push_back(MUL_gate); + ASSERT_EQ(gates_matrix.size(), 2); + ASSERT_EQ(gates_matrix[0].size(), 5); + // Extract the PI indices from the gates matrix + std::vector PI_wire_indices = + plonk_public_input_indices_from_gates_matrix(gates_matrix); + ASSERT_EQ(PI_wire_indices.size(), 1); + ASSERT_EQ(PI_wire_indices[0], 0); + // Hard-code the wire permutation for the tested circuit. Note + // that counting of indices starts from 1. TODO: implement a + // general function to compute the wire permutation for any + // circuit + std::vector wire_permutation{5, 4, 3, 2, 6, 1}; + // maximum degree of the encoded monomials in the usrs + size_t max_degree = PLONK_MAX_DEGREE; + // Random hidden element kept secret (toxic waste) + Field secret = Field::random_element(); + + std::shared_ptr> domain = + libfqfft::get_evaluation_domain(num_gates); + + // 1 Generate SRS + + // compute usrs + usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); + // compute srs + srs srs = plonk_srs_derive_from_usrs( + usrs, gates_matrix, wire_permutation, PI_wire_indices); + + // 2 Compute proof + + // initialize prover hasher + transcript_hasher prover_hasher; + // prepare witness vector w = a+b+c + std::vector witness{49, 7, 1, 7, 49, 49}; + // nine random blinding constants for the prover polynomials + std::vector> blind_scalars; + const size_t nscalars = 9; + for (size_t i = 0; i < nscalars; ++i) { + Field r = Field::random_element(); + blind_scalars.push_back(r); + } + // initialize prover + plonk_prover prover; + // compute proof + plonk_proof proof = + prover.compute_proof(srs, witness, blind_scalars, prover_hasher); + + // 3 Verify proof + + // initialize verifier hasher + transcript_hasher verifier_hasher; + // Prepare the list of PI values. for the example circuit + std::vector PI_value_list; + for (size_t i = 0; i < PI_wire_indices.size(); i++) { + Field PI_value = witness[PI_wire_indices[i]]; + PI_value_list.push_back(PI_value); } + ASSERT_EQ(PI_value_list.size(), 1); + ASSERT_EQ(PI_value_list[0], Field(49)); + // initialize verifier + plonk_verifier verifier; + // verify proof + bool b_valid_proof = + verifier.verify_proof(proof, srs, PI_value_list, verifier_hasher); + ASSERT_TRUE(b_valid_proof); } // generic test for all curves @@ -1267,7 +1390,9 @@ TEST(TestPlonk, BLS12_381) libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); test_plonk_gates_matrix_transpose(); - test_plonk_prepare_gates_matrix(); + test_plonk_prepare_gates_matrix< + libff::bls12_381_pp, + bls12_381_test_vector_transcript_hasher>(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index a9035a5d7..6a10159aa 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -234,6 +234,19 @@ template std::vector>> plonk_prepare_gates_matrix( const size_t &num_public_inputs); +/// The function extracts the indices of the public inputs (PI) from the input +/// gates matrix under the convention that the i-th components of the selector +/// vectors q_L, q_R, q_O, q_M, q_C corresponding to the i-th selector vector +/// have the form +/// +/// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (1, 0, 0, 0, 0) +/// +/// The vector of PI indices is equal to the vector of indices of all rows in +/// the gates matrix that are equal to (1, 0, 0, 0, 0) +template +std::vector plonk_public_input_indices_from_gates_matrix( + const std::vector>> &gates_matrix); + } // namespace libsnark #include "libsnark/zk_proof_systems/plonk/utils.tcc" diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 0eb268a1f..38c26f8cc 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -308,8 +308,8 @@ std::vector> plonk_gates_matrix_transpose( std::vector> gates_matrix_transpose( nrows_transpose, std::vector(ncols_transpose)); for (size_t irow = 0; irow < nrows; ++irow) { + assert(gates_matrix[irow].size() == ncols); for (size_t icol = 0; icol < ncols; ++icol) { - assert(gates_matrix[icol].size() == ncols); gates_matrix_transpose[icol][irow] = gates_matrix[irow][icol]; } } @@ -384,14 +384,14 @@ bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) } // In general, the i-th row of the gates matrix contains the i-th -// component of the selector vectors q_L, q_M, q_R, q_O, q_C (see +// component of the selector vectors q_L, q_R, q_O, q_M, q_C (see // Section 6 [GWC19]). The i-th compoment of each selector vector is // determined by the i-th gate of the arithmetic circuit, which can be // one of the following: addition, multiplication, multiplication by // constant, public input. In particular, when the i-th gate is a // public input, the i-th components of the selector vectors are: // -// (q_L[i], q_M[i], q_R[i], q_O[i], q_C[i]) = (1, 0, 0, 0, 0) +// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (1, 0, 0, 0, 0) // // Therefore the top N rows of the initialized gates matrix will have // the above form. See also Section 6 [GWC19]. @@ -402,7 +402,7 @@ bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) // circuit for BLS12-381 (class example) where q_R[i]=1 rather than // q_L[i]=1 i.e. // -// (q_L[i], q_M[i], q_R[i], q_O[i], q_C[i]) = (0, 1, 0, 0, 0) +// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (0, 1, 0, 0, 0) template std::vector>> plonk_prepare_gates_matrix( const size_t &num_public_inputs) @@ -416,6 +416,25 @@ std::vector>> plonk_prepare_gates_matrix( return gates_matrix_init; } +// Examine the gates matrix row by row and store the indices of those rows that +// are equal to (1, 0, 0, 0, 0). These are the rows corresponding to public +// inputs. +template +std::vector plonk_public_input_indices_from_gates_matrix( + const std::vector>> &gates_matrix) +{ + using FieldT = libff::Fr; + // Vector of indices of wires corresponding to public inputs (PI) + std::vector PI_wire_indices; + const std::vector PI_selector_vector{1, 0, 0, 0, 0}; + for (size_t i = 0; i < gates_matrix.size(); ++i) { + // store the index of the gates matrix row encoding a PI + if (gates_matrix[i] == PI_selector_vector) { + PI_wire_indices.push_back(i); + } + } + return PI_wire_indices; +} } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ From a8df063d70cc50308bdc76a9359999a985899bff Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 11:04:32 +0000 Subject: [PATCH 147/154] plonk: added edits and clarifications in comments regarding preparation of gates matrix code --- .../plonk/tests/test_plonk.cpp | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 3034c4940..57c40d30d 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1095,13 +1095,14 @@ template void test_plonk_gates_matrix_transpose() ASSERT_EQ(gates_matrix_transpose, example.gates_matrix_transpose); } -// We test the example circuit y^2 = x mod r where x=49 is a public -// input and y is the witness. We prove that we know y=7 such that y -// is the quadratic residue of x modulo the modulus r of the scalar -// field Fr of the given elliptic curve. The circuit is represented by -// one public input (PI) and one multiplication gate. According to the -// Plonk arithmetization rules, each gate (including the PI) is -// represented as: +// We test the example circuit y^2 = x mod r where x is a public input +// and y is the witness. We prove that we know y such that x is the +// quadratic residue of y modulo the modulus r of the scalar field Fr +// of the given elliptic curve. For example x=49, y=7. +// +// The circuit is represented by one public input (PI) and one +// multiplication gate. According to the Plonk arithmetization rules, +// each gate (including the PI) is represented as: // // qL a + qR b + qO c + qM ab + qC = 0 // @@ -1113,7 +1114,7 @@ template void test_plonk_gates_matrix_transpose() // gates are given resp. as // // PI: 1 a1 + 0 b1 + 0 c1 + 0 a1 b1 + 0 = 49 -// MUL: 0 a1 + 0 b1 + (-1) c1 + 1 a1 b1 + 0 = 0 +// MUL: 0 a2 + 0 b2 + (-1) c2 + 1 a2 b2 + 0 = 0 // // where // @@ -1148,7 +1149,7 @@ void test_plonk_prepare_gates_matrix() // 0 Arithmetization of test circuit y^2 = x mod r // The number of gates is 2: one public input (PI) gate and one - // multiplication gate. Tis nummer is also conveniently a power of + // multiplication gate. Tis number is also conveniently a power of // 2 (needed for the FFT/iFFT) const size_t num_gates = 2; // The tested circuit has 1 public input @@ -1156,7 +1157,8 @@ void test_plonk_prepare_gates_matrix() std::vector> gates_matrix = plonk_prepare_gates_matrix(num_public_inputs); ASSERT_EQ(gates_matrix.size(), num_public_inputs); - // Add the PI gate/s + // Assert that the PI gates are located at the top N rows of the gates + // matrix const std::vector PI_gate{1, 0, 0, 0, 0}; for (size_t i = 0; i < num_public_inputs; ++i) { ASSERT_EQ(gates_matrix[i], PI_gate); From 712e50dc6c77aa70df74cf14efcef455e6bad303 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 15 Dec 2022 11:13:21 +0000 Subject: [PATCH 148/154] plonk: moved the gates matrix check into a separate unit test (https://github.com/clearmatics/libsnark/pull/97#discussion_r1048696516) --- .../plonk/tests/test_plonk.cpp | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 57c40d30d..fb2e19f53 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1157,12 +1157,6 @@ void test_plonk_prepare_gates_matrix() std::vector> gates_matrix = plonk_prepare_gates_matrix(num_public_inputs); ASSERT_EQ(gates_matrix.size(), num_public_inputs); - // Assert that the PI gates are located at the top N rows of the gates - // matrix - const std::vector PI_gate{1, 0, 0, 0, 0}; - for (size_t i = 0; i < num_public_inputs; ++i) { - ASSERT_EQ(gates_matrix[i], PI_gate); - } // Add the multiplication gate const std::vector MUL_gate{0, 0, -1, 1, 0}; gates_matrix.push_back(MUL_gate); @@ -1233,6 +1227,25 @@ void test_plonk_prepare_gates_matrix() ASSERT_TRUE(b_valid_proof); } +template void test_plonk_gates_matrix() +{ + using Field = libff::Fr; + // Test for 10 random values of num_public_inputs + const size_t ntests = 10; + for (size_t i = 0; i < ntests; ++i) { + const size_t num_public_inputs = random() % 100; + std::vector> gates_matrix = + plonk_prepare_gates_matrix(num_public_inputs); + ASSERT_EQ(gates_matrix.size(), num_public_inputs); + // Assert that the PI gates are located at the top N rows of the gates + // matrix + const std::vector PI_gate{1, 0, 0, 0, 0}; + for (size_t i = 0; i < num_public_inputs; ++i) { + ASSERT_EQ(gates_matrix[i], PI_gate); + } + } +} + // generic test for all curves template void test_plonk_constants_k1_k2() { @@ -1395,6 +1408,7 @@ TEST(TestPlonk, BLS12_381) test_plonk_prepare_gates_matrix< libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); + test_plonk_gates_matrix(); } } // namespace libsnark From 38d9067a559e7037e4a554231ea0d3bbda343ee3 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 9 Jan 2023 08:58:29 +0000 Subject: [PATCH 149/154] plonk: added correction in the copy-constraints permutation, according to comments in https://github.com/clearmatics/libsnark/pull/97#discussion_r1055570124 --- .../plonk/tests/test_plonk.cpp | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index fb2e19f53..27c462cb8 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1134,13 +1134,21 @@ template void test_plonk_gates_matrix_transpose() // 1 0 0 0 0 // 0 0 -1 1 0 // -// and the permutation expressing the copy-constraints is (second -// line below): +// To compute the permutation of inputs and outputs that would reflect +// the copy-constraints, note the following. Of all the elements of +// the input/output vector V = (a1, a2, b1, b2, c1, c2), the circuit +// uses a1=x, a2=y, b2=a2=y and c2=a1=x, while b1 and c1 are not used +// (see the variables with non-zero coefficients in the PI and MUL +// equations above). If we number the elements of V from 1 to 6, the +// permutation reflecting the copy constraints should be (6, 4, 3, 2, +// 5, 1) i.e. 6 and 1 are permuted to reflect c2=a1; 4 and 2 are +// permuted to reflect b2=a2 and 3 and 5 remain in place to reflect +// that b1 and c1 are not used. Equivalently, the permutation is ("/" +// means "unused"): // -// (a1 a2 b1 b2 c1 c2) -// (c1 b2 b1 a2 c2 a1) -// -// reflecting the fact that a1=c1=c2=x and a2=b2=y +// ( x y / y / x) +// (a1 a2 b1 b2 c1 c2) -> (1 2 3 4 5 6) +// (c2 b2 b1 a2 c1 a1) -> (6 4 3 2 5 1) template void test_plonk_prepare_gates_matrix() { @@ -1171,7 +1179,7 @@ void test_plonk_prepare_gates_matrix() // that counting of indices starts from 1. TODO: implement a // general function to compute the wire permutation for any // circuit - std::vector wire_permutation{5, 4, 3, 2, 6, 1}; + std::vector wire_permutation{6, 4, 3, 2, 5, 1}; // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; // Random hidden element kept secret (toxic waste) From 960506bbc6eb04babb6a251a19bcc17fd24dc11e Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 9 Jan 2023 11:19:08 +0000 Subject: [PATCH 150/154] plonk: added edits in comments --- libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 27c462cb8..ac42d7942 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1096,9 +1096,8 @@ template void test_plonk_gates_matrix_transpose() } // We test the example circuit y^2 = x mod r where x is a public input -// and y is the witness. We prove that we know y such that x is the -// quadratic residue of y modulo the modulus r of the scalar field Fr -// of the given elliptic curve. For example x=49, y=7. +// and y is the witness. Thus the circuit shows that x is a quadratic +// residue in the field Fr. For example x=49, y=7. // // The circuit is represented by one public input (PI) and one // multiplication gate. According to the Plonk arithmetization rules, @@ -1157,8 +1156,8 @@ void test_plonk_prepare_gates_matrix() // 0 Arithmetization of test circuit y^2 = x mod r // The number of gates is 2: one public input (PI) gate and one - // multiplication gate. Tis number is also conveniently a power of - // 2 (needed for the FFT/iFFT) + // multiplication gate. This number is also conveniently a power of + // 2 (needed for the FFT/iFFT). const size_t num_gates = 2; // The tested circuit has 1 public input const size_t num_public_inputs = 1; @@ -1178,7 +1177,7 @@ void test_plonk_prepare_gates_matrix() // Hard-code the wire permutation for the tested circuit. Note // that counting of indices starts from 1. TODO: implement a // general function to compute the wire permutation for any - // circuit + // circuit. std::vector wire_permutation{6, 4, 3, 2, 5, 1}; // maximum degree of the encoded monomials in the usrs size_t max_degree = PLONK_MAX_DEGREE; From 7fb0106bb67656705b3452ad10e756fbafdf3068 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 10 Jan 2023 19:00:02 +0000 Subject: [PATCH 151/154] plonk: added a wrapper for plonk_srs_derive_from_usrs_custom_PI_indices taking only the number of PIs as opposed to a vector of their indices (https://github.com/clearmatics/libsnark/pull/97#discussion_r1061359709); added utility function to compute teh values of the PIs from the witness to be passed to the verifier. --- libsnark/zk_proof_systems/plonk/srs.hpp | 13 ++++- libsnark/zk_proof_systems/plonk/srs.tcc | 19 ++++++- .../plonk/tests/test_plonk.cpp | 46 +++++++---------- libsnark/zk_proof_systems/plonk/utils.hpp | 27 +++++----- libsnark/zk_proof_systems/plonk/utils.tcc | 49 ++++++++++++++----- libsnark/zk_proof_systems/plonk/verifier.hpp | 2 + 6 files changed, 102 insertions(+), 54 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/srs.hpp b/libsnark/zk_proof_systems/plonk/srs.hpp index 07c804849..1bfdbfe54 100644 --- a/libsnark/zk_proof_systems/plonk/srs.hpp +++ b/libsnark/zk_proof_systems/plonk/srs.hpp @@ -144,12 +144,23 @@ template class srs /// and the list of public input (PI) indices. The (plain) SRS is a /// specialization of the USRS for one particular circuit template -srs plonk_srs_derive_from_usrs( +srs plonk_srs_derive_from_usrs_custom_PI_indices( const usrs &usrs, const std::vector>> gates_matrix, const std::vector wire_permutation, const std::vector PI_wire_indices); +/// A wrapper for plonk_srs_derive_from_usrs_custom_PI_indices that +/// assumes that the PI indices are located in the top +/// num_public_inputs rows of the gates matrix. num_public_inputs is +/// the number of public inputs. +template +srs plonk_srs_derive_from_usrs( + const usrs &usrs, + const std::vector>> gates_matrix, + const std::vector wire_permutation, + const size_t num_public_inputs); + /// A proving key for Plonk template class plonk_proving_key { diff --git a/libsnark/zk_proof_systems/plonk/srs.tcc b/libsnark/zk_proof_systems/plonk/srs.tcc index fb9c1e584..e20df5d74 100644 --- a/libsnark/zk_proof_systems/plonk/srs.tcc +++ b/libsnark/zk_proof_systems/plonk/srs.tcc @@ -105,7 +105,7 @@ usrs plonk_usrs_derive_from_secret( } template -srs plonk_srs_derive_from_usrs( +srs plonk_srs_derive_from_usrs_custom_PI_indices( const usrs &usrs, const std::vector>> gates_matrix, const std::vector wire_permutation, @@ -253,6 +253,23 @@ srs plonk_srs_derive_from_usrs( return srs; } +template +srs plonk_srs_derive_from_usrs( + const usrs &usrs, + const std::vector>> gates_matrix, + const std::vector wire_permutation, + const size_t num_public_inputs) +{ + std::vector PI_wire_indices; + // store the indices of the PIs + for (size_t i = 0; i < num_public_inputs; ++i) { + PI_wire_indices.push_back(i); + } + srs srs = plonk_srs_derive_from_usrs_custom_PI_indices( + usrs, gates_matrix, wire_permutation, PI_wire_indices); + return srs; +} + } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_SRS_TCC_ diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index ac42d7942..da4034cf5 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -406,7 +406,7 @@ template void test_plonk_prover_rounds() // prepare srs usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs( + srs srs = plonk_srs_derive_from_usrs_custom_PI_indices( usrs, example.gates_matrix, example.wire_permutation, @@ -585,7 +585,7 @@ template void test_plonk_srs() // secret^2*G1, ... and secret times G2: 1*G2, secret^1*G2. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); // --- SRS --- - srs srs = plonk_srs_derive_from_usrs( + srs srs = plonk_srs_derive_from_usrs_custom_PI_indices( usrs, example.gates_matrix, example.wire_permutation, @@ -632,7 +632,7 @@ template void test_plonk_prover() // Perepare srs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs( + srs srs = plonk_srs_derive_from_usrs_custom_PI_indices( usrs, example.gates_matrix, example.wire_permutation, @@ -919,7 +919,7 @@ template void test_plonk_verifier_steps() // Prepare srs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs( + srs srs = plonk_srs_derive_from_usrs_custom_PI_indices( usrs, example.gates_matrix, example.wire_permutation, @@ -1043,7 +1043,7 @@ template void test_plonk_verifier() // Prepare srs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - srs srs = plonk_srs_derive_from_usrs( + srs srs = plonk_srs_derive_from_usrs_custom_PI_indices( usrs, example.gates_matrix, example.wire_permutation, @@ -1159,7 +1159,7 @@ void test_plonk_prepare_gates_matrix() // multiplication gate. This number is also conveniently a power of // 2 (needed for the FFT/iFFT). const size_t num_gates = 2; - // The tested circuit has 1 public input + // The example circuit has 1 public input const size_t num_public_inputs = 1; std::vector> gates_matrix = plonk_prepare_gates_matrix(num_public_inputs); @@ -1169,11 +1169,6 @@ void test_plonk_prepare_gates_matrix() gates_matrix.push_back(MUL_gate); ASSERT_EQ(gates_matrix.size(), 2); ASSERT_EQ(gates_matrix[0].size(), 5); - // Extract the PI indices from the gates matrix - std::vector PI_wire_indices = - plonk_public_input_indices_from_gates_matrix(gates_matrix); - ASSERT_EQ(PI_wire_indices.size(), 1); - ASSERT_EQ(PI_wire_indices[0], 0); // Hard-code the wire permutation for the tested circuit. Note // that counting of indices starts from 1. TODO: implement a // general function to compute the wire permutation for any @@ -1189,19 +1184,19 @@ void test_plonk_prepare_gates_matrix() // 1 Generate SRS - // compute usrs + // Compute usrs. usrs usrs = plonk_usrs_derive_from_secret(secret, max_degree); - // compute srs + // Compute srs. srs srs = plonk_srs_derive_from_usrs( - usrs, gates_matrix, wire_permutation, PI_wire_indices); + usrs, gates_matrix, wire_permutation, num_public_inputs); // 2 Compute proof - // initialize prover hasher + // Initialize prover hasher. transcript_hasher prover_hasher; - // prepare witness vector w = a+b+c + // Prepare witness vector w = a+b+c. std::vector witness{49, 7, 1, 7, 49, 49}; - // nine random blinding constants for the prover polynomials + // Nine random blinding constants for the prover polynomials. std::vector> blind_scalars; const size_t nscalars = 9; for (size_t i = 0; i < nscalars; ++i) { @@ -1216,19 +1211,14 @@ void test_plonk_prepare_gates_matrix() // 3 Verify proof - // initialize verifier hasher + // Initialize verifier hasher. transcript_hasher verifier_hasher; - // Prepare the list of PI values. for the example circuit - std::vector PI_value_list; - for (size_t i = 0; i < PI_wire_indices.size(); i++) { - Field PI_value = witness[PI_wire_indices[i]]; - PI_value_list.push_back(PI_value); - } - ASSERT_EQ(PI_value_list.size(), 1); - ASSERT_EQ(PI_value_list[0], Field(49)); - // initialize verifier + // Prepare the list of PI values for the example circuit. + std::vector PI_value_list = + plonk_public_input_values_from_length(witness, num_public_inputs); + // Initialize verifier. plonk_verifier verifier; - // verify proof + // Verify proof. bool b_valid_proof = verifier.verify_proof(proof, srs, PI_value_list, verifier_hasher); ASSERT_TRUE(b_valid_proof); diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 6a10159aa..615026046 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -234,18 +234,23 @@ template std::vector>> plonk_prepare_gates_matrix( const size_t &num_public_inputs); -/// The function extracts the indices of the public inputs (PI) from the input -/// gates matrix under the convention that the i-th components of the selector -/// vectors q_L, q_R, q_O, q_M, q_C corresponding to the i-th selector vector -/// have the form -/// -/// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (1, 0, 0, 0, 0) -/// -/// The vector of PI indices is equal to the vector of indices of all rows in -/// the gates matrix that are equal to (1, 0, 0, 0, 0) +/// Extract the values corresponing to the public inputs from the +/// witness using the respective wire indices passed as input. Those +/// values are passed on to the verifier together with the proof. template -std::vector plonk_public_input_indices_from_gates_matrix( - const std::vector>> &gates_matrix); +std::vector> plonk_public_input_values_from_indices( + const std::vector> &witness, + const std::vector &PI_wire_indices); + +/// A wrapper for plonk_public_input_values_from_indices. Extracts the +/// values corresponing to the public inputs from the witness, assuming +/// that they are in the first num_public_inputs positions. In other +/// words extracts the values of the public inputs from the *length* of +/// the public input vector. +template +std::vector> plonk_public_input_values_from_length( + const std::vector> &witness, + const size_t &num_public_inputs); } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index 38c26f8cc..ccda500ee 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -416,25 +416,48 @@ std::vector>> plonk_prepare_gates_matrix( return gates_matrix_init; } -// Examine the gates matrix row by row and store the indices of those rows that -// are equal to (1, 0, 0, 0, 0). These are the rows corresponding to public -// inputs. +// Extract the values corresponing to the public inputs from the +// witness using the respective wire indices passed as input. Those +// values are passed on to the verifier together with the proof. template -std::vector plonk_public_input_indices_from_gates_matrix( - const std::vector>> &gates_matrix) +std::vector> plonk_public_input_values_from_indices( + const std::vector> &witness, + const std::vector &PI_wire_indices) { + assert(PI_wire_indices.size() <= witness.size()); + + using FieldT = libff::Fr; + std::vector PI_value_list; + for (size_t i = 0; i < PI_wire_indices.size(); i++) { + assert(PI_wire_indices[i] < witness.size()); + FieldT PI_value = witness[PI_wire_indices[i]]; + PI_value_list.push_back(PI_value); + } + return PI_value_list; +} + +// A wrapper for plonk_public_input_values_from_indices. Extracts the +// values corresponing to the public inputs from the witness, assuming +// that they are in the first num_public_inputs positions. In other +// words extracts the values of the public inputs from the *length* of +// the public input vector. +template +std::vector> plonk_public_input_values_from_length( + const std::vector> &witness, const size_t &num_public_inputs) +{ + assert(num_public_inputs <= witness.size()); + using FieldT = libff::Fr; - // Vector of indices of wires corresponding to public inputs (PI) std::vector PI_wire_indices; - const std::vector PI_selector_vector{1, 0, 0, 0, 0}; - for (size_t i = 0; i < gates_matrix.size(); ++i) { - // store the index of the gates matrix row encoding a PI - if (gates_matrix[i] == PI_selector_vector) { - PI_wire_indices.push_back(i); - } + // store the indices of the PIs + for (size_t i = 0; i < num_public_inputs; ++i) { + PI_wire_indices.push_back(i); } - return PI_wire_indices; + std::vector PI_value_list = + plonk_public_input_values_from_indices(witness, PI_wire_indices); + return PI_value_list; } + } // namespace libsnark #endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_UTILS_TCC_ diff --git a/libsnark/zk_proof_systems/plonk/verifier.hpp b/libsnark/zk_proof_systems/plonk/verifier.hpp index 391917ed6..6cf1babaa 100644 --- a/libsnark/zk_proof_systems/plonk/verifier.hpp +++ b/libsnark/zk_proof_systems/plonk/verifier.hpp @@ -371,6 +371,8 @@ template class plonk_verifier /// \param[in] proof: SNARK proof produced by the prover /// \param[in] srs: structured reference string containing also /// circuit-specific information + /// \param[in] PI_value_list: list of values corresponding to + /// public inputs /// \param[in] transcript_hasher: hashes of the communication /// transcript after prover rounds 1,2,3,4,5. /// From f748170462c946718c68e50b4c966930eff8b1af Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 13 Jan 2023 09:14:38 +0000 Subject: [PATCH 152/154] plonk: addressed latest PR #97 comments: function renaming, comments edits, minor code optimisations --- .../zk_proof_systems/plonk/tests/example.hpp | 10 +++++++ .../plonk/tests/test_plonk.cpp | 16 +++++------ libsnark/zk_proof_systems/plonk/utils.hpp | 4 +-- libsnark/zk_proof_systems/plonk/utils.tcc | 27 +++---------------- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/example.hpp b/libsnark/zk_proof_systems/plonk/tests/example.hpp index 6d22456f0..4ee3e5966 100644 --- a/libsnark/zk_proof_systems/plonk/tests/example.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/example.hpp @@ -105,6 +105,16 @@ namespace libsnark /// q_O = [-1, -1, -1, 0, 0, 0, 0, 0] /// q_M = [ 1, 1, 0, 0, 0, -1, 0, 0] /// q_C = [ 0, 0, 0, -1, 0, 0, 0, 0] +/// +/// \attention The convention for selector vector values corresponding +/// to public inputs (PI) used here is different from the one used in +/// plonk_prepare_gates_matrix which is consistent with [GWC19], namely: +/// +/// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (1, 0, 0, 0, 0) +/// +/// For comparsion, here (i.e. in the example class) q_R[i]=1 and so +/// +/// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (0, 1, 0, 0, 0) class plonk_example { public: diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index da4034cf5..ad19495ca 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -1112,14 +1112,14 @@ template void test_plonk_gates_matrix_transpose() // Using the above representation, the PI and the multiplication // gates are given resp. as // -// PI: 1 a1 + 0 b1 + 0 c1 + 0 a1 b1 + 0 = 49 +// PI: 1 a1 + 0 b1 + 0 c1 + 0 a1 b1 + 0 ( + PI) = 0 // MUL: 0 a2 + 0 b2 + (-1) c2 + 1 a2 b2 + 0 = 0 // -// where +// where ("/" means "unused"): // // a = (a1, a2) = (x, y) -// b = (b1, b2) = (1, y) -// c = (c1, c2) = (x, x) +// b = (b1, b2) = (/, y) +// c = (c1, c2) = (/, x) // qL = (1, 0) // qR = (0, 0) // qO = (0, -1) @@ -1175,7 +1175,7 @@ void test_plonk_prepare_gates_matrix() // circuit. std::vector wire_permutation{6, 4, 3, 2, 5, 1}; // maximum degree of the encoded monomials in the usrs - size_t max_degree = PLONK_MAX_DEGREE; + const size_t max_degree = PLONK_MAX_DEGREE; // Random hidden element kept secret (toxic waste) Field secret = Field::random_element(); @@ -1215,7 +1215,7 @@ void test_plonk_prepare_gates_matrix() transcript_hasher verifier_hasher; // Prepare the list of PI values for the example circuit. std::vector PI_value_list = - plonk_public_input_values_from_length(witness, num_public_inputs); + plonk_public_input_values(witness, num_public_inputs); // Initialize verifier. plonk_verifier verifier; // Verify proof. @@ -1224,7 +1224,7 @@ void test_plonk_prepare_gates_matrix() ASSERT_TRUE(b_valid_proof); } -template void test_plonk_gates_matrix() +template void test_plonk_prepare_gates_matrix() { using Field = libff::Fr; // Test for 10 random values of num_public_inputs @@ -1405,7 +1405,7 @@ TEST(TestPlonk, BLS12_381) test_plonk_prepare_gates_matrix< libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); - test_plonk_gates_matrix(); + test_plonk_prepare_gates_matrix(); } } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/utils.hpp b/libsnark/zk_proof_systems/plonk/utils.hpp index 615026046..52a7bd1f6 100644 --- a/libsnark/zk_proof_systems/plonk/utils.hpp +++ b/libsnark/zk_proof_systems/plonk/utils.hpp @@ -245,10 +245,10 @@ std::vector> plonk_public_input_values_from_indices( /// A wrapper for plonk_public_input_values_from_indices. Extracts the /// values corresponing to the public inputs from the witness, assuming /// that they are in the first num_public_inputs positions. In other -/// words extracts the values of the public inputs from the *length* of +/// words extracts the values of the public inputs given the *length* of /// the public input vector. template -std::vector> plonk_public_input_values_from_length( +std::vector> plonk_public_input_values( const std::vector> &witness, const size_t &num_public_inputs); diff --git a/libsnark/zk_proof_systems/plonk/utils.tcc b/libsnark/zk_proof_systems/plonk/utils.tcc index ccda500ee..bb91002c6 100644 --- a/libsnark/zk_proof_systems/plonk/utils.tcc +++ b/libsnark/zk_proof_systems/plonk/utils.tcc @@ -395,14 +395,6 @@ bool plonk_are_valid_constants_k1_k2(const FieldT &k1, const FieldT &k2) // // Therefore the top N rows of the initialized gates matrix will have // the above form. See also Section 6 [GWC19]. -// -// \attention The convention for selector vector values corresponding -// to public inputs (PI) used in this function follows [GWC19] (as -// shown above) and is different from the one used in the example -// circuit for BLS12-381 (class example) where q_R[i]=1 rather than -// q_L[i]=1 i.e. -// -// (q_L[i], q_R[i], q_O[i], q_M[i], q_C[i]) = (0, 1, 0, 0, 0) template std::vector>> plonk_prepare_gates_matrix( const size_t &num_public_inputs) @@ -436,26 +428,13 @@ std::vector> plonk_public_input_values_from_indices( return PI_value_list; } -// A wrapper for plonk_public_input_values_from_indices. Extracts the -// values corresponing to the public inputs from the witness, assuming -// that they are in the first num_public_inputs positions. In other -// words extracts the values of the public inputs from the *length* of -// the public input vector. template -std::vector> plonk_public_input_values_from_length( +std::vector> plonk_public_input_values( const std::vector> &witness, const size_t &num_public_inputs) { assert(num_public_inputs <= witness.size()); - - using FieldT = libff::Fr; - std::vector PI_wire_indices; - // store the indices of the PIs - for (size_t i = 0; i < num_public_inputs; ++i) { - PI_wire_indices.push_back(i); - } - std::vector PI_value_list = - plonk_public_input_values_from_indices(witness, PI_wire_indices); - return PI_value_list; + return std::vector>( + witness.begin(), witness.begin() + num_public_inputs); } } // namespace libsnark From be861805d14a9b80fd5f502a0094f5151106888e Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 19 Jan 2023 14:17:08 +0000 Subject: [PATCH 153/154] plonk: added dummy transcript hasher specialized for all curves; added unit tests for the simple quadratic residue circuit for all curves (addresses issue https://github.com/clearmatics/libsnark/issues/103) --- .../plonk/tests/dummy_transcript_hasher.hpp | 59 +++++++++++ .../plonk/tests/dummy_transcript_hasher.tcc | 99 +++++++++++++++++++ .../plonk/tests/test_plonk.cpp | 60 +++++++---- 3 files changed, 197 insertions(+), 21 deletions(-) create mode 100644 libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp create mode 100644 libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc diff --git a/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp new file mode 100644 index 000000000..25a8dfa04 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp @@ -0,0 +1,59 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_HPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_HPP_ + +#include "libsnark/zk_proof_systems/plonk/utils.hpp" + +#include + +namespace libsnark +{ + +/// Implementation of a dummy transcript hasher interface (see +/// transcript_hasher.hpp). It returns the number of the elemnts in +/// the hash buffer as an Fr element. Specialized over the curve +/// field. See also class bls12_381_test_vector_transcript_hasher, +/// which is specific to the BLS12_381 curve. +template class dummy_transcript_hasher +{ +private: + // buffer accumulating data to be hashed + std::vector buffer; + +public: + dummy_transcript_hasher(); + + // Add an Fr element to the transcript buffer for hashing. + void add_element(const libff::Fr &element); + // Add the coordinates of a G1 curve point to the transcript buffer for + // hashing. + void add_element(const libff::G1 &element); + // Add the coordinates of a G2 curve point to the transcript buffer for + // hashing. + void add_element(const libff::G2 &element); + + // Dummy implementation of get_hash that simply returns the number + // of elements in the buffer as an Fr value for the purposes of + // unit testing. TODO: to be replaced by a call to a proper hash + // function e.g. SHA2, BLAKE, etc. + libff::Fr get_hash(); + + // clear the buffer (for now only for testing) + void buffer_clear(); + + // get buffer size + size_t buffer_size(); +}; + +} // namespace libsnark + +#include "libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc" + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_DUMMY_TRANSCRIPT_HASHER_HPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc new file mode 100644 index 000000000..d1bc45275 --- /dev/null +++ b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc @@ -0,0 +1,99 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_CPP_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_CPP_ + +#include "libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp" + +// Implementation of the dummy transcript hasher interface. See +// dummy_transcript_hasher.hpp. +namespace libsnark +{ + +template dummy_transcript_hasher::dummy_transcript_hasher() +{ +} + +template void dummy_transcript_hasher::buffer_clear() +{ + this->buffer.clear(); +} + +template size_t dummy_transcript_hasher::buffer_size() +{ + return this->buffer.size(); +} + +template +void dummy_transcript_hasher::add_element(const libff::Fr &element) +{ + // convert the Fr element into a string + std::string str; + { + std::ostringstream ss; + libff::field_write( + element, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +template +void dummy_transcript_hasher::add_element(const libff::G1 &element) +{ + libff::G1 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +template +void dummy_transcript_hasher::add_element(const libff::G2 &element) +{ + libff::G2 element_aff(element); + element_aff.to_affine_coordinates(); + + // convert the affine coordinates of the curve point into a string + std::string str; + { + std::ostringstream ss; + libff::group_write< + libff::encoding_binary, + libff::form_plain, + libff::compression_off>(element_aff, ss); + str = ss.str(); + } + // copy the string as a sequence of uint8_t elements at the end of + // the buffer + std::copy(str.begin(), str.end(), std::back_inserter(this->buffer)); +} + +template libff::Fr dummy_transcript_hasher::get_hash() +{ + libff::Fr buffer_len = libff::Fr(this->buffer.size()); + return buffer_len; +} + +} // namespace libsnark + +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_CPP_ diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index ad19495ca..9210db102 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -8,6 +8,7 @@ #include "libsnark/zk_proof_systems/plonk/prover.hpp" #include "libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp" +#include "libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp" #include "libsnark/zk_proof_systems/plonk/verifier.hpp" #include @@ -1148,9 +1149,10 @@ template void test_plonk_gates_matrix_transpose() // ( x y / y / x) // (a1 a2 b1 b2 c1 c2) -> (1 2 3 4 5 6) // (c2 b2 b1 a2 c1 a1) -> (6 4 3 2 5 1) -template -void test_plonk_prepare_gates_matrix() +template void test_plonk_simple_circuit() { + ppT::init_public_params(); + using Field = libff::Fr; // 0 Arithmetization of test circuit y^2 = x mod r @@ -1337,57 +1339,70 @@ void test_plonk_constants_k1_k2_bls12_381() } } -TEST(TestPlonkConstantsK1K2, Edwards) +TEST(TestPlonk, Edwards) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); + // TODO add test_plonk_simple_circuit } -TEST(TestPlonkConstantsK1K2, Mnt4) +TEST(TestPlonk, BN128) +{ + test_plonk_constants_k1_k2(); + test_plonk_random_constants_k1_k2(); + // TODO add test_plonk_simple_circuit +} + +TEST(TestPlonk, Mnt4) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); + test_plonk_simple_circuit< + libff::mnt4_pp, + dummy_transcript_hasher>(); } -TEST(TestPlonkConstantsK1K2, Mnt6) +TEST(TestPlonk, Mnt6) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); + test_plonk_simple_circuit< + libff::mnt6_pp, + dummy_transcript_hasher>(); } -TEST(TestPlonkConstantsK1K2, BW6_761) +TEST(TestPlonk, BW6_761) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); + test_plonk_simple_circuit< + libff::bw6_761_pp, + dummy_transcript_hasher>(); } -TEST(TestPlonkConstantsK1K2, BN128) -{ - test_plonk_constants_k1_k2(); - test_plonk_random_constants_k1_k2(); -} - -TEST(TestPlonkConstantsK1K2, ALT_BN128) +TEST(TestPlonk, ALT_BN128) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); + test_plonk_simple_circuit< + libff::alt_bn128_pp, + dummy_transcript_hasher>(); } -TEST(TestPlonkConstantsK1K2, BLS12_377) +TEST(TestPlonk, BLS12_377) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); + test_plonk_simple_circuit< + libff::bls12_377_pp, + dummy_transcript_hasher>(); } -TEST(TestPlonkConstantsK1K2, BLS12_381) +TEST(TestPlonk, BLS12_381) { test_plonk_constants_k1_k2(); test_plonk_random_constants_k1_k2(); test_plonk_constants_k1_k2_bls12_381(); -} - -TEST(TestPlonk, BLS12_381) -{ test_plonk_srs(); test_plonk_prover_rounds< libff::bls12_381_pp, @@ -1402,10 +1417,13 @@ TEST(TestPlonk, BLS12_381) libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); test_plonk_gates_matrix_transpose(); - test_plonk_prepare_gates_matrix< + test_plonk_prepare_gates_matrix(); + test_plonk_simple_circuit< libff::bls12_381_pp, bls12_381_test_vector_transcript_hasher>(); - test_plonk_prepare_gates_matrix(); + test_plonk_simple_circuit< + libff::bls12_381_pp, + dummy_transcript_hasher>(); } } // namespace libsnark From 3603f95445c00eb56a00299fd1e2730d08dfb21b Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Fri, 3 Feb 2023 12:50:26 +0000 Subject: [PATCH 154/154] plonk: removed unused method buffer_size (https://github.com/clearmatics/libsnark/pull/107#discussion_r1095727785); renamed method buffer_clear to reset (https://github.com/clearmatics/libsnark/pull/107#discussion_r1095728696); minor edits in comments (https://github.com/clearmatics/libsnark/pull/107#discussion_r1095722640). --- ...ls12_381_test_vector_transcript_hasher.cpp | 10 +---- ...ls12_381_test_vector_transcript_hasher.hpp | 5 +-- .../plonk/tests/dummy_transcript_hasher.hpp | 17 ++++----- .../plonk/tests/dummy_transcript_hasher.tcc | 13 ++----- .../plonk/tests/test_plonk.cpp | 38 +++++++++---------- 5 files changed, 32 insertions(+), 51 deletions(-) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp index fb9094bad..1af67ffc5 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.cpp @@ -40,15 +40,7 @@ bls12_381_test_vector_transcript_hasher:: }; } -void bls12_381_test_vector_transcript_hasher::buffer_clear() -{ - this->buffer.clear(); -} - -size_t bls12_381_test_vector_transcript_hasher::buffer_size() -{ - return this->buffer.size(); -} +void bls12_381_test_vector_transcript_hasher::reset() { this->buffer.clear(); } void bls12_381_test_vector_transcript_hasher::add_element( const libff::Fr &element) diff --git a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp index 027afff2b..baa34d32b 100644 --- a/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/bls12_381_test_vector_transcript_hasher.hpp @@ -114,10 +114,7 @@ class bls12_381_test_vector_transcript_hasher libff::Fr get_hash(); // clear the buffer (for now only for testing) - void buffer_clear(); - - // get buffer size - size_t buffer_size(); + void reset(); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp index 25a8dfa04..328165719 100644 --- a/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp +++ b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp @@ -17,10 +17,10 @@ namespace libsnark { /// Implementation of a dummy transcript hasher interface (see -/// transcript_hasher.hpp). It returns the number of the elemnts in -/// the hash buffer as an Fr element. Specialized over the curve -/// field. See also class bls12_381_test_vector_transcript_hasher, -/// which is specific to the BLS12_381 curve. +/// transcript_hasher.hpp). It returns the number of bytes in the hash +/// buffer as an Fr element. Specialized over the curve field. See +/// also class bls12_381_test_vector_transcript_hasher, which is +/// specific to the BLS12_381 curve. template class dummy_transcript_hasher { private: @@ -40,16 +40,13 @@ template class dummy_transcript_hasher void add_element(const libff::G2 &element); // Dummy implementation of get_hash that simply returns the number - // of elements in the buffer as an Fr value for the purposes of - // unit testing. TODO: to be replaced by a call to a proper hash + // bytes in the buffer as an Fr value for the purposes of unit + // testing. TODO: to be replaced by a call to a proper hash // function e.g. SHA2, BLAKE, etc. libff::Fr get_hash(); // clear the buffer (for now only for testing) - void buffer_clear(); - - // get buffer size - size_t buffer_size(); + void reset(); }; } // namespace libsnark diff --git a/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc index d1bc45275..85542a259 100644 --- a/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc +++ b/libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.tcc @@ -6,8 +6,8 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ -#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_CPP_ -#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_CPP_ +#ifndef LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_TCC_ +#define LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_TCC_ #include "libsnark/zk_proof_systems/plonk/tests/dummy_transcript_hasher.hpp" @@ -20,16 +20,11 @@ template dummy_transcript_hasher::dummy_transcript_hasher() { } -template void dummy_transcript_hasher::buffer_clear() +template void dummy_transcript_hasher::reset() { this->buffer.clear(); } -template size_t dummy_transcript_hasher::buffer_size() -{ - return this->buffer.size(); -} - template void dummy_transcript_hasher::add_element(const libff::Fr &element) { @@ -96,4 +91,4 @@ template libff::Fr dummy_transcript_hasher::get_hash() } // namespace libsnark -#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_CPP_ +#endif // LIBSNARK_ZK_PROOF_SYSTEMS_PLONK_TESTS_DUMMY_TRANSCRIPT_HASHER_TCC_ diff --git a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp index 9210db102..f24a78a0f 100644 --- a/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp +++ b/libsnark/zk_proof_systems/plonk/tests/test_plonk.cpp @@ -65,7 +65,7 @@ void test_verify_invalid_proof( for (size_t i = 0; i < valid_proof.W_polys_blinded_at_secret_g1.size(); ++i) { // re-initialize the manipulated proof - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_polys_blinded_at_secret_g1[i] = @@ -74,7 +74,7 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } // manipulate [z]_1 - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.z_poly_at_secret_g1 = proof.z_poly_at_secret_g1 + G1_noise; @@ -83,7 +83,7 @@ void test_verify_invalid_proof( // manipulate [t_lo]_1, [t_mi]_1, [t_hi]_1 for (size_t i = 0; i < valid_proof.t_poly_at_secret_g1.size(); ++i) { // re-initialize the manipulated proof - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.t_poly_at_secret_g1[i] = proof.t_poly_at_secret_g1[i] + G1_noise; @@ -91,63 +91,63 @@ void test_verify_invalid_proof( ASSERT_FALSE(b_accept); } // manipulate \bar{a} - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.a_zeta = proof.a_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{b} - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.b_zeta = proof.b_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{c} - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.c_zeta = proof.c_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma1} - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_0_zeta = proof.S_0_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{S_sigma2} - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.S_1_zeta = proof.S_1_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate \bar{z_w} - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.z_poly_xomega_zeta = proof.z_poly_xomega_zeta + Fr_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate [W_zeta]_1 - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_at_secret = proof.W_zeta_at_secret + G1_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate [W_{zeta omega_roots}]_1 - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; G1_noise = libff::G1::random_element(); proof.W_zeta_omega_at_secret = proof.W_zeta_omega_at_secret + G1_noise; b_accept = verifier.verify_proof(proof, srs, PI_value_list, hasher); ASSERT_FALSE(b_accept); // manipulate r_zeta - hasher.buffer_clear(); + hasher.reset(); proof = valid_proof; Fr_noise = libff::Fr::random_element(); proof.r_zeta = proof.r_zeta + Fr_noise; @@ -433,7 +433,7 @@ template void test_plonk_prover_rounds() plonk_prover::round_one( round_zero_out, blind_scalars, witness, srs, domain, hasher); // clear hash buffer - hasher.buffer_clear(); + hasher.reset(); // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); @@ -470,7 +470,7 @@ template void test_plonk_prover_rounds() domain, hasher); // Clear hash buffer. - hasher.buffer_clear(); + hasher.reset(); // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); @@ -505,7 +505,7 @@ template void test_plonk_prover_rounds() srs, hasher); // Clear hash buffer. - hasher.buffer_clear(); + hasher.reset(); // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); @@ -527,7 +527,7 @@ template void test_plonk_prover_rounds() plonk_prover::round_four( zeta, round_one_out, round_three_out, srs, hasher); // Clear hash buffer. - hasher.buffer_clear(); + hasher.reset(); // Add outputs from Round 1 to the hash buffer. hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[a]); hasher.add_element(round_one_out.W_polys_blinded_at_secret_g1[b]); @@ -937,7 +937,7 @@ template void test_plonk_verifier_steps() // Clear the hasher buffer in order to re-use the same // transcript_hasher object for the verifier. - hasher.buffer_clear(); + hasher.reset(); // Unit test verifier preprocessed input. test_plonk_verifier_preprocessed_input( @@ -1061,7 +1061,7 @@ template void test_plonk_verifier() // Clear the hasher buffer in order to re-use the same // transcript_hasher object for the verifier. - hasher.buffer_clear(); + hasher.reset(); // Initialize verifier. plonk_verifier verifier; @@ -1078,7 +1078,7 @@ template void test_plonk_verifier() // Clear the hasher buffer in order to re-use the same // transcript_hasher object. - hasher.buffer_clear(); + hasher.reset(); // Assert that proof verification fails when the proof is // manipulated. test_verify_invalid_proof(proof, srs, PI_value_list, hasher);