From 73f65c12e7169b68013912b067745a882c23bc5f Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 7 Apr 2022 15:23:06 +0100 Subject: [PATCH 01/12] fix variable name typo --- libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp index 3b1200364..a8917b095 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp @@ -118,7 +118,7 @@ class kzg10_verifier_gadget : public gadget> kzg10_verifier_gadget( protoboard> &pb, const kzg10_srs_variable &srs, - const kzg10_commitment_variable &commitmennt, + const kzg10_commitment_variable &commitment, pb_linear_combination> i, pb_linear_combination> poly_eval, const kzg10_witness_variable &witness, From cdabbd9460882840a7f35666d0cb2869613a03cf Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 7 Apr 2022 19:05:27 +0100 Subject: [PATCH 02/12] abstact out kzg10 pairing check to make kzg10 gadget simpler, and allow it to be reused --- .../verifiers/kzg10_verifier_gadget.hpp | 49 +++++++--- .../verifiers/kzg10_verifier_gadget.tcc | 93 +++++++++++++------ 2 files changed, 101 insertions(+), 41 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp index a8917b095..9be1f0007 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp @@ -52,6 +52,41 @@ template using kzg10_commitment_variable = G1_variable; /// This is also a single G1_variable (see the native implementation). template using kzg10_witness_variable = G1_variable; +/// A pairing check specific to the KZG10 scheme. +/// Check: +/// +/// e(A, B) = e(C, D) +/// +/// where D is a fixed constant (and thereby some the precompute step for D is +/// baked into the circuit). +template class kzg10_pairing_check_gadget : gadget> +{ +public: + G1_precomputation A_precomp; + precompute_G1_gadget compute_A_precomp; + G2_precomputation B_precomp; + precompute_G2_gadget compute_B_precomp; + G1_precomputation C_precomp; + precompute_G1_gadget compute_C_precomp; + // D_precomp is statically computed from a constant, so does not need a + // precompute gadget. + G2_precomputation D_precomp; + + check_e_equals_e_gadget check_pairing_equality; + + kzg10_pairing_check_gadget( + protoboard> &pb, + const G1_variable &A, + const G2_variable &B, + const G1_variable &C, + const libff::G2> &D, + pb_variable> &result, + const std::string annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + /// Uses a nested pairing (via a pairing selector) to implement the /// verification step of [KZG10]. See the native implementation for details. /// @@ -94,19 +129,9 @@ class kzg10_verifier_gadget : public gadget> G1_variable C; G1_add_gadget compute_C; - // Pairing computation - G1_precomputation A_precomp; - precompute_G1_gadget compute_A_precomp; - G2_precomputation B_precomp; - precompute_G2_gadget compute_B_precomp; - G1_precomputation C_precomp; - precompute_G1_gadget compute_C_precomp; - // D_precomp is computed from (constant) G2::one(), and baked into the - // circuit, saving a few constraints. - G2_precomputation D_precomp; - + // Pairing check pb_variable> check_result; - check_e_equals_e_gadget check_pairing_equality; + kzg10_pairing_check_gadget pairing_check; // group_elements_non_zero = // (1 - i_in_G2.is_zero) * (1 - poly_eval_in_G1.is_zero) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.tcc b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.tcc index 61bed590e..686b0c318 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.tcc +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.tcc @@ -14,6 +14,8 @@ namespace libsnark { +// kzg10_srs_variable + template kzg10_srs_variable::kzg10_srs_variable( protoboard> &pb, @@ -41,6 +43,60 @@ void kzg10_srs_variable::generate_r1cs_witness( alpha_g2.generate_r1cs_witness(srs.alpha_g2); } +// kzg10_pairing_check_gadget + +template +kzg10_pairing_check_gadget::kzg10_pairing_check_gadget( + protoboard> &pb, + const G1_variable &A, + const G2_variable &B, + const G1_variable &C, + const libff::G2> &D, + pb_variable> &result, + const std::string annotation_prefix) + : gadget>(pb, annotation_prefix) + , A_precomp() + , compute_A_precomp( + pb, A, A_precomp, FMT(annotation_prefix, " compute_A_precomp")) + , B_precomp() + , compute_B_precomp( + pb, B, B_precomp, FMT(annotation_prefix, " compute_B_precomp")) + , C_precomp() + , compute_C_precomp( + pb, C, C_precomp, FMT(annotation_prefix, " compute_C_precomp")) + , D_precomp(pb, D, FMT(annotation_prefix, " D_precomp")) + , check_pairing_equality( + pb, + A_precomp, + B_precomp, + C_precomp, + D_precomp, + result, + FMT(annotation_prefix, " check_pairing_equality")) + +{ +} + +template +void kzg10_pairing_check_gadget::generate_r1cs_constraints() +{ + compute_A_precomp.generate_r1cs_constraints(); + compute_B_precomp.generate_r1cs_constraints(); + compute_C_precomp.generate_r1cs_constraints(); + check_pairing_equality.generate_r1cs_constraints(); +} + +template +void kzg10_pairing_check_gadget::generate_r1cs_witness() +{ + compute_A_precomp.generate_r1cs_witness(); + compute_B_precomp.generate_r1cs_witness(); + compute_C_precomp.generate_r1cs_witness(); + check_pairing_equality.generate_r1cs_witness(); +} + +// kzg10_verifier_gadget + template kzg10_verifier_gadget::kzg10_verifier_gadget( protoboard> &pb, @@ -90,31 +146,16 @@ kzg10_verifier_gadget::kzg10_verifier_gadget( -poly_eval_in_G1.value, C, FMT(annotation_prefix, " compute_C")) - - , A_precomp() - , compute_A_precomp( - pb, witness, A_precomp, FMT(annotation_prefix, " compute_A_precomp")) - , B_precomp() - , compute_B_precomp( - pb, B, B_precomp, FMT(annotation_prefix, " compute_B_precomp")) - , C_precomp() - , compute_C_precomp( - pb, C, C_precomp, FMT(annotation_prefix, " compute_C_precomp")) - , D_precomp( - pb, - libff::G2>::one(), - FMT(annotation_prefix, " D_precomp")) - , check_result(pb_variable_allocate( pb, FMT(annotation_prefix, " check_result"))) - , check_pairing_equality( + , pairing_check( pb, - A_precomp, - B_precomp, - C_precomp, - D_precomp, + witness, + B, + C, + libff::G2>::one(), check_result, - FMT(annotation_prefix, " check_pairing_equality")) + FMT(annotation_prefix, "pairing_check")) , group_elements_non_zero(pb_variable_allocate( pb, FMT(annotation_prefix, " group_elements_non_zero"))) @@ -129,10 +170,7 @@ void kzg10_verifier_gadget::generate_r1cs_constraints() compute_B.generate_r1cs_constraints(); compute_poly_eval_in_G1.generate_r1cs_constraints(); compute_C.generate_r1cs_constraints(); - compute_A_precomp.generate_r1cs_constraints(); - compute_B_precomp.generate_r1cs_constraints(); - compute_C_precomp.generate_r1cs_constraints(); - check_pairing_equality.generate_r1cs_constraints(); + pairing_check.generate_r1cs_constraints(); // group_elements_non_zero = // (1 - i_in_G2.is_identity) * (1 - poly_eval_in_G1.is_identity) @@ -159,10 +197,7 @@ template void kzg10_verifier_gadget::generate_r1cs_witness() // compute_C.B = -poly_eval_in_G1.value. Evaluate the result of negation. compute_C.B.Y.evaluate(this->pb); compute_C.generate_r1cs_witness(); - compute_A_precomp.generate_r1cs_witness(); - compute_B_precomp.generate_r1cs_witness(); - compute_C_precomp.generate_r1cs_witness(); - check_pairing_equality.generate_r1cs_witness(); + pairing_check.generate_r1cs_witness(); const FieldT group_elements_non_zero_val = (FieldT::one() - this->pb.lc_val(i_in_G2.is_identity)) * From db6a6ff82e631539605258b86ad811bade183d08 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 8 Apr 2022 13:55:15 +0100 Subject: [PATCH 03/12] scalar multiplication of variable_or_identity curve points --- .../gadgets/curves/scalar_multiplication.hpp | 47 ++++++++++- .../gadgets/curves/scalar_multiplication.tcc | 78 +++++++++++++++++++ .../gadgets/curves/weierstrass_g1_gadget.hpp | 10 +++ .../gadgets/curves/weierstrass_g2_gadget.hpp | 10 +++ .../gadgetlib1/tests/test_curve_gadgets.cpp | 43 +++++++++- 5 files changed, 184 insertions(+), 4 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp index 438f0cf3a..00e074fb2 100644 --- a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp +++ b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp @@ -72,7 +72,8 @@ class variable_or_identity : public gadget> pb_variable is_identity_var; }; -/// Selector gadget for variable_or_identity +/// Selector gadget for variable_or_identity. Outputs one of two +/// variable_or_identity objeects, depending on a scalar parameter. template< typename ppT, typename groupT, @@ -401,6 +402,50 @@ class point_mul_by_scalar_gadget : public gadget protoboard &pb, const std::string &annotation_prefix); }; +/// Generic gadget to perform scalar multiplication of variable_or_identity +/// group points by scalar variables. Used by the individual group element +/// implementations. +template< + typename ppT, + typename groupT, + typename groupVarT, + typename selectorGadgetT, + typename addGadgetT, + typename dblGadgetT> +class point_variable_or_identity_mul_by_scalar_gadget + : public gadget +{ +public: + using Field = libff::Fr; + using nFr = libff::Fr>; + + using varMulByScalar = point_mul_by_scalar_gadget< + ppT, + groupT, + groupVarT, + selectorGadgetT, + addGadgetT, + dblGadgetT>; + + using groupVarOrIdentity = variable_or_identity; + using selectVarIdentityGadget = + variable_or_identity_selector; + + groupVarOrIdentity scalar_mul_result; + varMulByScalar scalar_mul; + selectVarIdentityGadget select_result; + + point_variable_or_identity_mul_by_scalar_gadget( + protoboard &pb, + const pb_linear_combination &scalar, + const groupVarOrIdentity &P, + const groupVarOrIdentity &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + } // namespace libsnark #include "libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc" diff --git a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc index 0e34c1308..9ace08cad 100644 --- a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc +++ b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc @@ -821,6 +821,84 @@ pb_variable_array> point_mul_by_scalar_gadget< return bits; } +template< + typename ppT, + typename groupT, + typename groupVarT, + typename selectorGadgetT, + typename addGadgetT, + typename dblGadgetT> +point_variable_or_identity_mul_by_scalar_gadget< + ppT, + groupT, + groupVarT, + selectorGadgetT, + addGadgetT, + dblGadgetT>:: + point_variable_or_identity_mul_by_scalar_gadget( + protoboard &pb, + const pb_linear_combination &scalar, + const groupVarOrIdentity &P, + const groupVarOrIdentity &result, + const std::string &annotation_prefix) + : gadget>(pb, annotation_prefix) + , scalar_mul_result(pb, FMT(annotation_prefix, " scalar_mul_result")) + , scalar_mul( + pb, + scalar, + P.value, + scalar_mul_result, + FMT(annotation_prefix, " scalar_mul")) + // result = P.is_identity ? P : scalar_mul_result + // = select(P.is_identity, scalar_mul_result, P) + , select_result( + pb, + P.is_identity, + scalar_mul_result, + P, + result, + FMT(annotation_prefix, " select_result")) +{ +} + +template< + typename ppT, + typename groupT, + typename groupVarT, + typename selectorGadgetT, + typename addGadgetT, + typename dblGadgetT> +void point_variable_or_identity_mul_by_scalar_gadget< + ppT, + groupT, + groupVarT, + selectorGadgetT, + addGadgetT, + dblGadgetT>::generate_r1cs_constraints() +{ + scalar_mul.generate_r1cs_constraints(); + select_result.generate_r1cs_constraints(); +} + +template< + typename ppT, + typename groupT, + typename groupVarT, + typename selectorGadgetT, + typename addGadgetT, + typename dblGadgetT> +void point_variable_or_identity_mul_by_scalar_gadget< + ppT, + groupT, + groupVarT, + selectorGadgetT, + addGadgetT, + dblGadgetT>::generate_r1cs_witness() +{ + scalar_mul.generate_r1cs_witness(); + select_result.generate_r1cs_witness(); +} + } // namespace libsnark #endif // LIBSNARK_GADGETLIB1_GADGETS_CURVE_SCALAR_MULTIPLICATION_TCC_ diff --git a/libsnark/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp b/libsnark/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp index 87f0b6f69..d70dcc402 100644 --- a/libsnark/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/curves/weierstrass_g1_gadget.hpp @@ -254,6 +254,16 @@ using G1_mul_by_scalar_gadget = point_mul_by_scalar_gadget< G1_add_gadget, G1_dbl_gadget>; +template +using G1_variable_or_identity_mul_by_scalar_gadget = + point_variable_or_identity_mul_by_scalar_gadget< + wppT, + libff::G1>, + G1_variable, + G1_variable_selector_gadget, + G1_add_gadget, + G1_dbl_gadget>; + } // namespace libsnark #include diff --git a/libsnark/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp b/libsnark/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp index 47112130a..9fb51698b 100644 --- a/libsnark/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/curves/weierstrass_g2_gadget.hpp @@ -292,6 +292,16 @@ using G2_mul_by_scalar_gadget = point_mul_by_scalar_gadget< G2_add_gadget, G2_dbl_gadget>; +template +using G2_variable_or_identity_mul_by_scalar_gadget = + point_variable_or_identity_mul_by_scalar_gadget< + wppT, + libff::G2>, + G2_variable, + G2_variable_selector_gadget, + G2_add_gadget, + G2_dbl_gadget>; + } // namespace libsnark #include diff --git a/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp b/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp index 2042089be..f77f0c627 100644 --- a/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp +++ b/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp @@ -469,10 +469,10 @@ TEST(TestCurveGadgets, G1MulByConstScalar) // Circuit protoboard> pb; G1_variable P(pb, "P"); - G1_variable result_a(pb, "result"); + G1_variable result_a(pb, "result_a"); G1_mul_by_const_scalar_gadget::num_limbs> mul_gadget_a( pb, scalar_val_a.as_bigint(), P, result_a, "mul_gadget_a"); - G1_variable result_b(pb, "result"); + G1_variable result_b(pb, "result_b"); G1_mul_by_const_scalar_gadget::num_limbs> mul_gadget_b( pb, scalar_val_b.as_bigint(), P, result_b, "mul_gadget_b"); @@ -700,7 +700,7 @@ void test_mul_by_scalar_gadget( generate_and_check_proof(pb); } -TEST(TestCurveGadgets, G1MulScalarVar) +TEST(TestCurveGadgets, MulScalarVar) { auto test_g1_mul_by_scalar_gadget = test_mul_by_scalar_gadget< wpp, @@ -725,6 +725,43 @@ TEST(TestCurveGadgets, G1MulScalarVar) test_g2_mul_by_scalar_gadget(libff::Fr(13), -libff::Fr::one()); } +TEST(TestCurveGadgets, VarOrIdentityMulScalarVar) +{ + auto test_g1_var_or_identity_mul_by_scalar_gadget = + test_mul_by_scalar_gadget< + wpp, + libff::G1, + G1_variable_or_identity, + G1_variable_or_identity, + G1_variable_or_identity_mul_by_scalar_gadget>; + + auto test_g2_var_or_identity_mul_by_scalar_gadget = + test_mul_by_scalar_gadget< + wpp, + libff::G2, + G2_variable_or_identity, + G2_variable_or_identity, + G2_variable_or_identity_mul_by_scalar_gadget>; + + test_g1_var_or_identity_mul_by_scalar_gadget( + libff::Fr(13), libff::Fr::zero()); + test_g1_var_or_identity_mul_by_scalar_gadget( + libff::Fr::zero(), libff::Fr(13)); + test_g1_var_or_identity_mul_by_scalar_gadget( + libff::Fr(13), libff::Fr(127)); + test_g1_var_or_identity_mul_by_scalar_gadget( + libff::Fr(13), -libff::Fr::one()); + + test_g2_var_or_identity_mul_by_scalar_gadget( + libff::Fr(13), libff::Fr::zero()); + test_g2_var_or_identity_mul_by_scalar_gadget( + libff::Fr::zero(), libff::Fr(13)); + test_g2_var_or_identity_mul_by_scalar_gadget( + libff::Fr(13), libff::Fr(127)); + test_g2_var_or_identity_mul_by_scalar_gadget( + libff::Fr(13), -libff::Fr::one()); +} + } // namespace int main(int argc, char **argv) From f922d27dd7cd58c9cb63c60e7f7dc25165bada80 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 11:04:49 +0100 Subject: [PATCH 04/12] make point_variable_or_identity_mul_by_scalar_gadget interface consistent with point_mul_by_scalar_gadget --- .../gadgets/curves/scalar_multiplication.hpp | 3 ++- .../gadgets/curves/scalar_multiplication.tcc | 27 ++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp index 00e074fb2..280faa212 100644 --- a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp +++ b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp @@ -431,8 +431,8 @@ class point_variable_or_identity_mul_by_scalar_gadget using selectVarIdentityGadget = variable_or_identity_selector; - groupVarOrIdentity scalar_mul_result; varMulByScalar scalar_mul; + groupVarOrIdentity selected_result; selectVarIdentityGadget select_result; point_variable_or_identity_mul_by_scalar_gadget( @@ -444,6 +444,7 @@ class point_variable_or_identity_mul_by_scalar_gadget void generate_r1cs_constraints(); void generate_r1cs_witness(); + const groupVarOrIdentity &result() const; }; } // namespace libsnark diff --git a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc index 9ace08cad..97d6b848e 100644 --- a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc +++ b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.tcc @@ -842,21 +842,21 @@ point_variable_or_identity_mul_by_scalar_gadget< const groupVarOrIdentity &result, const std::string &annotation_prefix) : gadget>(pb, annotation_prefix) - , scalar_mul_result(pb, FMT(annotation_prefix, " scalar_mul_result")) , scalar_mul( pb, scalar, P.value, - scalar_mul_result, + groupVarOrIdentity(pb, FMT(annotation_prefix, " scalar_mul_result")), FMT(annotation_prefix, " scalar_mul")) // result = P.is_identity ? P : scalar_mul_result // = select(P.is_identity, scalar_mul_result, P) + , selected_result(result) , select_result( pb, P.is_identity, - scalar_mul_result, + scalar_mul.result(), P, - result, + selected_result, FMT(annotation_prefix, " select_result")) { } @@ -899,6 +899,25 @@ void point_variable_or_identity_mul_by_scalar_gadget< select_result.generate_r1cs_witness(); } +template< + typename ppT, + typename groupT, + typename groupVarT, + typename selectorGadgetT, + typename addGadgetT, + typename dblGadgetT> +const variable_or_identity + &point_variable_or_identity_mul_by_scalar_gadget< + ppT, + groupT, + groupVarT, + selectorGadgetT, + addGadgetT, + dblGadgetT>::result() const +{ + return selected_result; +} + } // namespace libsnark #endif // LIBSNARK_GADGETLIB1_GADGETS_CURVE_SCALAR_MULTIPLICATION_TCC_ From 85bc935277b796886da5cb8550649e91109e6dfe Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 14 Apr 2022 16:15:57 +0100 Subject: [PATCH 05/12] factor out some calculations from kzg10_batched verifier --- .../polynomial_commitments/kzg10_batched.tcc | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/libsnark/polynomial_commitments/kzg10_batched.tcc b/libsnark/polynomial_commitments/kzg10_batched.tcc index 49032436d..e1420a0d5 100644 --- a/libsnark/polynomial_commitments/kzg10_batched.tcc +++ b/libsnark/polynomial_commitments/kzg10_batched.tcc @@ -91,6 +91,35 @@ static polynomial polynomial_accumulate_with_power_factors( return f_accum; } +// Compute terms of the form: +// +// \sum_i \gamma^{i-1} (cm_i - [eval_i]_1) +template +static libff::G1 gamma_times_commit_minus_eval_sum( + const libff::Fr &gamma, + const std::vector> &evals, + const std::vector> &cms) +{ + // Compute: + // + // eval_accum = \sum_i gamma^{i-1} evals_i + // cm_accum = \sum_i gamma^{i-1} cm_i + // result = cm_accum - (eval_accum * G1::one()) + + const size_t t = evals.size(); + assert(cms.size() == t); + + libff::Fr eval_accum = evals[t - 1]; + libff::G1 cm_accum = cms[t - 1]; + // Note use of underflow to terminate after i = 0. + for (size_t i = t - 2; i < t; --i) { + cm_accum = (gamma * cm_accum) + cms[i]; + eval_accum = (eval_accum * gamma) + evals[i]; + } + + return cm_accum - eval_accum * libff::G1::one(); +} + } // namespace internal template @@ -222,50 +251,25 @@ bool kzg10_batched_2_point::verify_evaluations( { // See Section 3, p13 of [GWC19]. - const size_t t1 = cm_1s.size(); - const size_t t2 = cm_2s.size(); - assert(t1 == evaluations.s_1s.size()); - assert(t2 == evaluations.s_2s.size()); + assert(cm_1s.size() == evaluations.s_1s.size()); + assert(cm_2s.size() == evaluations.s_2s.size()); // Compute: // - // F = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) + (G) - // r \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) (H) - - const std::vector &s_1s = evaluations.s_1s; - const std::vector &s_2s = evaluations.s_2s; - - // Compute: + // F = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) + + // r \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) + // = G + r * H // - // s_1_accum = \sum_i \gamma_1^{i-1} s_1[i] (in the scalar field) - // cm_1_accum = \sum_i \gamma_1^{i-1} cm_1[i] (in G1) - // G = cm_1_accum - s_1_accum * G1::one() - - Field s_1_accum = s_1s[t1 - 1]; - libff::G1 cm_1_accum = cm_1s[t1 - 1]; - // Note use of underflow to terminate after i = 0. - for (size_t i = t1 - 2; i < t1; --i) { - cm_1_accum = (gamma_1 * cm_1_accum) + cm_1s[i]; - s_1_accum = (s_1_accum * gamma_1) + s_1s[i]; - } - const libff::G1 G = cm_1_accum - s_1_accum * libff::G1::one(); - - // Similarly: + // where: // - // s_2_accum = \sum_i \gamma_2^{i-1} s_2[i] (in the scalar field) - // cm_2_accum = \sum_i \gamma_2^{i-1} cm_2[i] (in G1) - // H = cm_2_accum - s_2_accum * G1::one() - - Field s_2_accum = s_2s[t2 - 1]; - libff::G1 cm_2_accum = cm_2s[t2 - 1]; - for (size_t i = t2 - 2; i < t2; --i) { - cm_2_accum = gamma_2 * cm_2_accum + cm_2s[i]; - s_2_accum = (s_2_accum * gamma_2) + s_2s[i]; - } - const libff::G1 H = - r * (cm_2_accum - s_2_accum * libff::G1::one()); - - const libff::G1 F = G + H; + // G = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) + // H = \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) + + const libff::G1 G = internal::gamma_times_commit_minus_eval_sum( + gamma_1, evaluations.s_1s, cm_1s); + const libff::G1 H = internal::gamma_times_commit_minus_eval_sum( + gamma_2, evaluations.s_2s, cm_2s); + const libff::G1 F = G + r * H; // The pairing check takes the form: // From 4c50622404c16683c88c76d77228f35aede997db Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 14 Apr 2022 16:28:03 +0100 Subject: [PATCH 06/12] util gadget for kzg_batched to sum commitments minus encoded evaluations --- .../kzg10_batched_verifier_gadget.hpp | 104 ++++++ .../kzg10_batched_verifier_gadget.tcc | 347 ++++++++++++++++++ .../tests/test_kzg10_verifier_gadget.cpp | 110 +++++- 3 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp create mode 100644 libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp new file mode 100644 index 000000000..fadc3cec9 --- /dev/null +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp @@ -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_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_HPP_ +#define LIBSNARK_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_HPP_ + +#include "libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp" +#include "libsnark/polynomial_commitments/kzg10_batched.hpp" + +namespace libsnark +{ + +/// Given an array of commitments, and array of evaluations, and some field +/// element gamma, compute terms of the form: +/// +/// \sum_{i=1}^{t_1} \gamma^{i-1} (cm_i - [s_i]_1) +/// +/// The `num_entries` parameter here is intended to reflect the fact that this +/// must be statically defined, although all internal structures are currently +/// dynamic. This also allows specialization for the case of 2 entries. +template +class kzg10_batched_compute_commit_minus_eval_sum : gadget> +{ + static_assert(num_entries > 2, "num_entries must be greater that 2"); + +public: + using Field = libff::Fr; + + // These are the negative encoded evaluations: + // + // encoded_evals[i] = G1_mul(evals[i], -G1::one()); + std::vector> encoded_evals; + std::vector> compute_encoded_evals; + + // Negative evals are added to commits to compute cm_i - [s_i]_1: + // + // commit_minus_encoded_eval[i] = cm_i - [s_i]_1 + std::vector> commit_minus_encoded_eval; + std::vector> + compute_commit_minus_encoded_eval; + + // result = sum_{i=0}^{n-1} gamma^i commit_minus_encoded_eval[i] + kzg10_batched_compute_gamma_powers_times_points + compute_gamma_power_times_commit_minus_encoded_eval; + + kzg10_batched_compute_commit_minus_eval_sum( + protoboard> &pb, + const pb_linear_combination> &gamma, + const std::vector> &commitments, + const pb_linear_combination_array> &evals, + G1_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + const G1_variable &result() const; +}; + +// Specialization for num_entries == 2 (in which we do not need to compute +// further powers of gamma). This simplifies the generic (num_entries >= 3) +// version, since it does not need to account for special cases. +template +class kzg10_batched_compute_commit_minus_eval_sum + : gadget> +{ +public: + // encoded_evals[i] = evals[i] * -G1::one() + std::vector> compute_encoded_evals; + + // cm_minus_encoded_eval[i] = commits[i] - encoded_evals[i] + std::vector> + compute_cm_minus_eval; + + // gamma_term = gamma * commit_minus_encoded_eval[1] + // return = gamma_term + (commit_minus_encoded_eval[0] + std::shared_ptr> compute_gamma_term; + std::shared_ptr> + compute_result; + + kzg10_batched_compute_commit_minus_eval_sum( + protoboard> &pb, + pb_linear_combination> gamma, + const std::vector> commitments, + const pb_linear_combination_array> &evals, + G1_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); + + const G1_variable &result() const; +}; + +} // namespace libsnark + +#include "libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc" + +#endif // LIBSNARK_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_HPP_ diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc new file mode 100644 index 000000000..7b81a81f5 --- /dev/null +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc @@ -0,0 +1,347 @@ +/** @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_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_TCC_ +#define LIBSNARK_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_TCC_ + +#include "libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp" + +namespace libsnark +{ + +namespace internal +{ + +// TODO: It may make sense to expose this more widely if we start to create +// other gadgets which allocate and process arrays of curve points, etc. We may +// also make this more generic and add constructor args etc. + +// Convenience function to allocate vectors of complex variables. +template +std::vector allocate_variable_array( + protoboard> &pb, + const size_t length, + const std::string &annotation_prefix) +{ + std::vector variables; + variables.reserve(length); + for (size_t i = 0; i < length; ++i) { + variables.emplace_back(pb, FMT(annotation_prefix, "[%zu]", i)); + } + + return variables; +} + +} // namespace internal + +// +// kzg10_batched_compute_commit_minus_eval_sum +// + +// specialization for 2 entries +template +kzg10_batched_compute_commit_minus_eval_sum:: + kzg10_batched_compute_commit_minus_eval_sum( + protoboard> &pb, + pb_linear_combination> gamma, + const std::vector> commits, + const pb_linear_combination_array> &evals, + G1_variable &result, + const std::string &annotation_prefix) + : gadget>(pb, annotation_prefix) +{ + G1_variable g1_minus_1( + pb, + -libff::G1>::one(), + FMT(annotation_prefix, " g1_minus_1")); + + // encoded_evals[i] = evals[i] * -G1::one() + compute_encoded_evals.emplace_back( + pb, + evals[0], + g1_minus_1, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " encoded_evals[0]")), + FMT(annotation_prefix, " compute_encoded_evals[0]")); + compute_encoded_evals.emplace_back( + pb, + evals[1], + g1_minus_1, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " encoded_evals[1]")), + FMT(annotation_prefix, " compute_encoded_evals[1]")); + + // cm_minus_encoded_eval[i] = commits[i] - encoded_evals[i] + compute_cm_minus_eval.emplace_back( + pb, + compute_encoded_evals[0].result(), + commits[0], + G1_variable(pb, FMT(annotation_prefix, " cm_minus_eval[0]")), + FMT(annotation_prefix, " compute_cm_minus_eval[0]")); + compute_cm_minus_eval.emplace_back( + pb, + compute_encoded_evals[1].result(), + commits[1], + G1_variable(pb, FMT(annotation_prefix, " cm_minus_eval[1]")), + FMT(annotation_prefix, " compute_cm_minus_eval[1]")); + + // gamma_term = gamma * commit_minus_encoded_eval[1] + // return = gamma_term + (commit_minus_encoded_eval[0] + compute_gamma_term = std::make_shared>( + pb, + gamma, + compute_cm_minus_eval[1].result, + G1_variable_or_identity(pb, FMT(annotation_prefix, " gamma_term")), + FMT(annotation_prefix, " compute_gamma_term")); + + compute_result = + std::make_shared>( + pb, + compute_gamma_term->result(), + compute_cm_minus_eval[0].result, + result, + FMT(annotation_prefix, " compute_result")); +} + +template +void kzg10_batched_compute_commit_minus_eval_sum:: + generate_r1cs_constraints() +{ + compute_encoded_evals[0].generate_r1cs_constraints(); + compute_encoded_evals[1].generate_r1cs_constraints(); + compute_cm_minus_eval[0].generate_r1cs_constraints(); + compute_cm_minus_eval[1].generate_r1cs_constraints(); + compute_gamma_term->generate_r1cs_constraints(); + compute_result->generate_r1cs_constraints(); +} + +template +void kzg10_batched_compute_commit_minus_eval_sum:: + generate_r1cs_witness() +{ + compute_encoded_evals[0].generate_r1cs_witness(); + compute_encoded_evals[1].generate_r1cs_witness(); + compute_cm_minus_eval[0].generate_r1cs_witness(); + compute_cm_minus_eval[1].generate_r1cs_witness(); + compute_gamma_term->generate_r1cs_witness(); + compute_result->generate_r1cs_witness(); +} + +template +const G1_variable + &kzg10_batched_compute_commit_minus_eval_sum::result() const +{ + return compute_result->result; +} + +// specialization for >2 entries +template +kzg10_batched_compute_commit_minus_eval_sum:: + kzg10_batched_compute_commit_minus_eval_sum( + protoboard> &pb, + const pb_linear_combination> &gamma, + const std::vector> &commitments, + const pb_linear_combination_array> &evals, + G1_variable &result, + const std::string &annotation_prefix) + : gadget>(pb, annotation_prefix) + , encoded_evals( + internal::allocate_variable_array>( + pb, num_entries, FMT(annotation_prefix, " encoded_evals"))) + , compute_encoded_evals() + , commit_minus_encoded_eval( + internal::allocate_variable_array>( + pb, + num_entries, + FMT(annotation_prefix, " commit_minus_encoded_eval"))) + , compute_commit_minus_encoded_eval() + // , gamma(gamma) + // , gamma_powers() + // , gamma_power_times_commit_minus_encoded_eval( + // internal::allocate_variable_array>( + // pb, + // num_entries - 1, + // FMT(annotation_prefix, + // " gamma_power_times_commit_minus_encoded_eval"))) + // , compute_gamma_power_times_commit_minus_encoded_eval() + // , intermediate_sum(internal::allocate_variable_array>( + // pb, num_entries - 2, FMT(annotation_prefix, " intermediate_sum"))) + // , compute_intermediate_sum() + , compute_gamma_power_times_commit_minus_encoded_eval( + pb, + gamma, + commit_minus_encoded_eval, + result, + FMT(annotation_prefix, + " compute_gamma_power_times_commit_minus_encoded_eval")) +{ + // encoded_eval[i] = G1_mul_by_scalar(evals[i], G1::one()) + // len(encoded_eval) = num_entries + G1_variable g1_minus_one( + pb, + -libff::G1>::one(), + FMT(annotation_prefix, " g1_one")); + compute_encoded_evals.reserve(num_entries); + for (size_t i = 0; i < num_entries; ++i) { + compute_encoded_evals.emplace_back( + pb, + evals[i], + g1_minus_one, + encoded_evals[i], + FMT(annotation_prefix, " compute_encoded_evals[%zu]", i)); + } + + // commit_minus_encoded_eval[i] = cm_i - [s_i]_1 + compute_commit_minus_encoded_eval.reserve(num_entries); + for (size_t i = 0; i < num_entries; ++i) { + compute_commit_minus_encoded_eval.emplace_back( + pb, + encoded_evals[i], + commitments[i], + commit_minus_encoded_eval[i], + FMT(annotation_prefix, " compute_commit_minus_encoded_eval")); + } + + // // gamma_powers[0] = gamma * gamma + // // gamma_powers[i>0] = gamma * gamma_powers[i-1] + // gamma_powers.allocate( + // pb, num_entries - 2, FMT(annotation_prefix, " gamma_powers")); + // this->pb.add_r1cs_constraint( + // r1cs_constraint(gamma, gamma, gamma_powers[0]), + // FMT(annotation_prefix, " compute_gamma_power[0](gamma^2)")); + // for (size_t i = 1; i < num_entries - 2; ++i) { + // this->pb.add_r1cs_constraint( + // r1cs_constraint(gamma, gamma_powers[i - 1], + // gamma_powers[i]), FMT(annotation_prefix, + // " compute_gamma_power[%zu](gamma^%zu)", + // i, + // i + 2)); + // } + + // // gamma_power_times_commit_minus_encoded_eval[0] = + // // G1_mul(gamma, compute_commit_minus_encoded_eval[1]) + // // gamma_power_times_commit_minus_encoded_eval[i>0] = + // // G1_mul(gamma_powers[i-1], commit_minus_encoded_eval[i+1] + // compute_gamma_power_times_commit_minus_encoded_eval.reserve( + // num_entries - 1); + // compute_gamma_power_times_commit_minus_encoded_eval.emplace_back( + // pb, + // gamma, + // commit_minus_encoded_eval[1], + // gamma_power_times_commit_minus_encoded_eval[0], + // FMT(annotation_prefix, + // "compute_gamma_power_times_commit_minus_encoded_eval[0]")); + // for (size_t i = 1; i < num_entries - 1; ++i) { + // compute_gamma_power_times_commit_minus_encoded_eval.emplace_back( + // pb, + // gamma_powers[i - 1], + // commit_minus_encoded_eval[i + 1], + // gamma_power_times_commit_minus_encoded_eval[i], + // FMT(annotation_prefix, + // "compute_gamma_power_times_commit_minus_encoded_eval[0]")); + // } + + // // intermediate_sum[0] = G1_add( + // // commit_minus_encoded_eval[0], + // // gamma_power_times_commit_minus_encoded_eval[0]) + // // intermediate_sum[0 +void kzg10_batched_compute_commit_minus_eval_sum:: + generate_r1cs_constraints() +{ + for (auto &gadget : compute_encoded_evals) { + gadget.generate_r1cs_constraints(); + } + + for (auto &gadget : compute_commit_minus_encoded_eval) { + gadget.generate_r1cs_constraints(); + } + + compute_gamma_power_times_commit_minus_encoded_eval + .generate_r1cs_constraints(); + + // for (auto &gadget : compute_gamma_power_times_commit_minus_encoded_eval) + // { + // gadget.generate_r1cs_constraints(); + // } + + // for (auto &gadget : compute_intermediate_sum) { + // gadget.generate_r1cs_constraints(); + // } +} + +template +void kzg10_batched_compute_commit_minus_eval_sum:: + generate_r1cs_witness() +{ + for (auto &gadget : compute_encoded_evals) { + gadget.generate_r1cs_witness(); + } + + for (auto &gadget : compute_commit_minus_encoded_eval) { + gadget.generate_r1cs_witness(); + } + + compute_gamma_power_times_commit_minus_encoded_eval.generate_r1cs_witness(); + + // const Field gamma_val = this->pb.lc_val(gamma); + // Field gamma_power_val = gamma_val; + + // for (auto &gamma_power : gamma_powers) { + // gamma_power_val = gamma_power_val * gamma_val; + // this->pb.val(gamma_power) = gamma_power_val; + // } + + // for (auto &gadget : compute_gamma_power_times_commit_minus_encoded_eval) + // { + // gadget.generate_r1cs_witness(); + // } + + // for (auto &gadget : compute_intermediate_sum) { + // gadget.generate_r1cs_witness(); + // } +} + +} // namespace libsnark + +#endif // LIBSNARK_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_TCC_ diff --git a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp index 85c0e66e6..ef25781a5 100644 --- a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp +++ b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp @@ -7,8 +7,9 @@ *****************************************************************************/ #include "libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp" +#include "libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp" #include "libsnark/gadgetlib1/gadgets/verifiers/kzg10_verifier_gadget.hpp" -#include "libsnark/polynomial_commitments/kzg10.hpp" +#include "libsnark/polynomial_commitments/kzg10_batched.hpp" #include "libsnark/polynomial_commitments/tests/polynomial_commitment_test_utils.hpp" #include "libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp" @@ -155,11 +156,118 @@ template void test_kzg10_verifier_gadget() } } +template +void do_test_kzg10_batched_commit_minus_eval_sum( + const libff::Fr> &gamma, + const std::vector>> &evals, + const std::vector>::commitment> &cms, + const libff::G1> &r, + const bool expected_result) +{ + using Field = libff::Fr; + + ASSERT_EQ(num_entries, evals.size()); + ASSERT_EQ(num_entries, cms.size()); + + // Protoboard and constraints + + protoboard pb; + + pb_variable gamma_var = pb_variable_allocate(pb, "gamma_var"); + std::vector> cms_var = + internal::allocate_variable_array>( + pb, num_entries, "cms_var"); + pb_variable_array evals_var; + evals_var.allocate(pb, num_entries, "evals_var"); + G1_variable result_var(pb, "result_var"); + + kzg10_batched_compute_commit_minus_eval_sum compute_sum( + pb, gamma_var, cms_var, evals_var, result_var, "compute_sum"); + + compute_sum.generate_r1cs_constraints(); + + // Witness + + Field wrapping_gamma; + fp_from_fp(wrapping_gamma, gamma); + pb.val(gamma_var) = wrapping_gamma; + + for (size_t i = 0; i < num_entries; ++i) { + cms_var[i].generate_r1cs_witness(cms[i]); + + Field wrapping_eval; + fp_from_fp(wrapping_eval, evals[i]); + pb.val(evals_var[i]) = wrapping_eval; + } + compute_sum.generate_r1cs_witness(); + + // Check result value + + if (expected_result) { + ASSERT_TRUE(pb.is_satisfied()); + ASSERT_EQ(r, result_var.get_element()); + } else { + ASSERT_NE(r, result_var.get_element()); + } + + // Test in proof + + const r1cs_gg_ppzksnark_keypair keypair = + r1cs_gg_ppzksnark_generator(pb.get_constraint_system(), true); + const r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_prover( + keypair.pk, pb.primary_input(), pb.auxiliary_input(), true); + ASSERT_TRUE(r1cs_gg_ppzksnark_verifier_strong_IC( + keypair.vk, pb.primary_input(), proof)); +} + +template void test_kzg10_batched_commit_minus_eval_sum_gadget() +{ + using nField = libff::Fr>; + using nG1 = libff::G1>; + + const nField gamma("51"); + const std::vector evals{{"3"}, {"5"}, {"7"}, {"11"}}; + const std::vector cms{{ + nField("13") * nG1::one(), + nField("17") * nG1::one(), + nField("19") * nG1::one(), + nField("23") * nG1::one(), + }}; + + // 2-entry case + const nG1 r_2 = nField((13 - 3) + 51 * (17 - 5)) * nG1::one(); + do_test_kzg10_batched_commit_minus_eval_sum( + gamma, {evals[0], evals[1]}, {cms[0], cms[1]}, r_2, true); + + // 3-entry case + const nG1 r_3 = + nField((13 - 3) + 51 * (17 - 5) + (51 * 51) * (19 - 7)) * nG1::one(); + do_test_kzg10_batched_commit_minus_eval_sum( + gamma, + {evals[0], evals[1], evals[2]}, + {cms[0], cms[1], cms[2]}, + r_3, + true); + + // 4-entry case + const nG1 r_4 = nField( + (13 - 3) + 51 * (17 - 5) + (51 * 51) * (19 - 7) + + (51 * 51 * 51) * (23 - 11)) * + nG1::one(); + do_test_kzg10_batched_commit_minus_eval_sum( + gamma, evals, cms, r_4, true); +} + TEST(TestKZG10VerifierGadget, ValidEvaluation) { test_kzg10_verifier_gadget(); } +TEST(TestKZG10VerifierGadget, BatchedCommitMinusEvalSum) +{ + test_kzg10_batched_commit_minus_eval_sum_gadget(); +} + } // namespace int main(int argc, char **argv) From 100ef28ce99145bfe035af8207adeb48b62f78e3 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 21 Apr 2022 15:33:22 +0100 Subject: [PATCH 07/12] kzg10_batched_compute_gamma_powers_times_points util gadget --- .../kzg10_batched_verifier_gadget.hpp | 148 +++++++ .../kzg10_batched_verifier_gadget.tcc | 247 ++++++++++- .../tests/test_kzg10_verifier_gadget.cpp | 382 +++++++++++++++++- 3 files changed, 769 insertions(+), 8 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp index fadc3cec9..0d85eadba 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp @@ -15,6 +15,59 @@ namespace libsnark { +// TODO: create an "evaluations variable object" + +template class kzg10_batched_witness_variable +{ +public: + kzg10_witness_variable W_1; + kzg10_witness_variable W_2; + + kzg10_batched_witness_variable( + protoboard> &pb, const std::string &annotation_prefix); + + void generate_r1cs_witness( + const typename kzg10_batched_2_point< + other_curve>::evaluation_witness &eval_witness); +}; + +/// Given a value `gamma` and a vector `points` of `n` group variables, compute: +/// +/// result = \sum_{i=0}^{n-1} gamma^i * points[n] +/// +/// by computing: +/// +/// intermediate[0] = gamma * points[n] + points[n-1] +/// intermediate[i>0] = gamma * intermediate[i-1] + points[n-1-i] +/// result = gamma * intermediate[n-2] + points[0] +template +class kzg10_batched_compute_gamma_powers_times_points : gadget> +{ +public: + // Full calculation is as follows: + // + // intermediate_mul[0] = gamma * points[n-1] + // intermediate_sum[0] = intermediate_mul[0] + points[n-2] + // intermediate_mul[i=1..n-2] = gamma * intermediate_sum[i-1] + // intermediate_sum[i=1..n-3] = intermediate_mul[i] + points[n-2-i] + // intermediate_sum[n-2] = result = intermediate_mul[n-2] + points[0] + // + // so intermediate_mul.size() = intermediate_sum.size() = n-1 + std::vector> intermediate_mul; + std::vector> + intermediate_sum; + + kzg10_batched_compute_gamma_powers_times_points( + protoboard> &pb, + const pb_linear_combination> &gamma, + const std::vector> &points, + G1_variable &result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + /// Given an array of commitments, and array of evaluations, and some field /// element gamma, compute terms of the form: /// @@ -97,6 +150,101 @@ class kzg10_batched_compute_commit_minus_eval_sum const G1_variable &result() const; }; +/// Gadget version of the native KZG10 batched verifier in +/// libsnark/polynomial_commitments/kzg10_batched.hpp. +/// +/// Each polynomials can be evaluated at 1 of 2 points. `polyomials_1` +/// determines the number of polynomials evaluated at the first point `z_1`, +/// and `polynomials_2` determines the number to be evaluated at the second +/// point `z_2`. Hence these also determine the number of commitments and +/// evaluation points. +/// +/// The number of polynomials inn each group is intentionally a template +/// parameter, reflecting the fact that it must be statically defined for a +/// given circuit. +template +class kzg10_batched_verifier_gadget : public gadget> +{ +public: + using Field = libff::Fr; + + // Matching the native calculations in kzg10_batched.tcc, compute: + // + // F = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) + + // r \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) + // = G + r * H + // + // where: + // + // G = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) + // H = \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) + G1_variable G; + kzg10_batched_compute_commit_minus_eval_sum + compute_G; + G1_variable H; + kzg10_batched_compute_commit_minus_eval_sum + compute_H; + G1_variable_or_identity rH; + G1_mul_by_scalar_gadget compute_rH; + G1_variable F; + G1_add_variable_and_variable_or_identity_gadget compute_F; + + // Expression to check is: + // e(W_1 + r * W_2, srs.alpha_g2) * + // e(F + z_1 * W_1 + r * z_2 * W_2, -[1]_2) + // = 1 + // = e(A, srs.alpha_g2) * e(B, -[1]_2) + // + // where + // A = W_1 + r * W_2 + // B = F + z_1 * W_1 + r * z_2 * W_2 + + G1_variable_or_identity r_times_W_2; + G1_mul_by_scalar_gadget compute_r_times_W_2; + + G1_variable A; + G1_add_variable_and_variable_or_identity_gadget compute_A; + + G1_variable_or_identity r_times_z_2_times_W_2; + G1_variable_or_identity_mul_by_scalar_gadget + compute_r_times_z_2_times_W_2; + + G1_variable_or_identity z_1_times_W_1; + G1_mul_by_scalar_gadget compute_z_1_times_W_1; + + G1_variable F_plus_z_1_times_W_1; + G1_add_variable_and_variable_or_identity_gadget + compute_F_plus_z_1_times_W_1; + + G1_variable B; + G1_add_variable_and_variable_or_identity_gadget compute_B; + + kzg10_pairing_check_gadget pairing_check; + + // TODO: Since polyomials_1 and polyomials_2 are statically defined, we + // could use statically sized containers here. For now, the interfaces and + // initialization make this a bit inconvenient (requiring default + // constructors for the contained types). + kzg10_batched_verifier_gadget( + protoboard> &pb, + pb_linear_combination> z_1, + pb_linear_combination> z_2, + const pb_linear_combination_array> &poly_evals_1, + const pb_linear_combination_array> &poly_evals_2, + const kzg10_srs_variable &srs, + pb_linear_combination> gamma_1, + pb_linear_combination> gamma_2, + const kzg10_batched_witness_variable &eval_witness, + const std::vector> &commitments_1, + const std::vector> &commitments_2, + pb_linear_combination> r, + pb_variable> result, + const std::string &annotation_prefix); + + void generate_r1cs_constraints(); + void generate_r1cs_witness(); +}; + } // namespace libsnark #include "libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc" diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc index 7b81a81f5..cce953247 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc @@ -39,6 +39,112 @@ std::vector allocate_variable_array( } // namespace internal +// +// kzg10_batched_witness_variable +// + +template +kzg10_batched_witness_variable::kzg10_batched_witness_variable( + protoboard> &pb, const std::string &annotation_prefix) + : W_1(pb, FMT(annotation_prefix, " W_1")) + , W_2(pb, FMT(annotation_prefix, " W_2")) +{ +} + +template +void kzg10_batched_witness_variable::generate_r1cs_witness( + const typename kzg10_batched_2_point>::evaluation_witness + &eval_witness) +{ + W_1.generate_r1cs_witness(eval_witness.W_1); + W_2.generate_r1cs_witness(eval_witness.W_2); +} + +// +// kzg10_batched_compute_gamma_powers_times_points +// + +template +kzg10_batched_compute_gamma_powers_times_points:: + kzg10_batched_compute_gamma_powers_times_points( + protoboard> &pb, + const pb_linear_combination> &gamma, + const std::vector> &points, + G1_variable &result, + const std::string &annotation_prefix) + : gadget>(pb, annotation_prefix) +{ + intermediate_mul.reserve(n - 1); + intermediate_sum.reserve(n - 1); + + // intermediate_mul_result[0] = gamma * points[n-1] + intermediate_mul.emplace_back( + pb, + gamma, + points[n - 1], + G1_variable_or_identity( + pb, FMT(annotation_prefix, " intermediate_mul_result[0]")), + FMT(annotation_prefix, " intermediate_mul[0]")); + + // intermediate_sum[i=0..n-3] = intermediate_mul[i] + points[n-2-i] + // intermediate_mul[i=1..n-2] = gamma * intermediate_sum[i-1] + for (size_t i = 1; i < n - 1; ++i) { + intermediate_sum.emplace_back( + pb, + intermediate_mul.back().result(), + points[n - 1 - i], + G1_variable( + pb, + FMT(annotation_prefix, " intermediate_sum_result[%zu]", i - 1)), + FMT(annotation_prefix, " intermediate_sum[%zu]", i - 1)); + + intermediate_mul.emplace_back( + pb, + gamma, + intermediate_sum.back().result, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " intermediate_mul_result[%zu]", i)), + FMT(annotation_prefix, " intermediate_mul[%zu]", i)); + } + + // intermediate_sum[n-2] = result = intermediate_mul[n-2] + points[0] + intermediate_sum.emplace_back( + pb, + intermediate_mul[n - 2].result(), + points[0], + result, + FMT(annotation_prefix, " intermediate_sum[%zu]", n - 2)); + + assert(intermediate_mul.size() == n - 1); + assert(intermediate_sum.size() == n - 1); +} + +template +void kzg10_batched_compute_gamma_powers_times_points:: + generate_r1cs_constraints() +{ + assert(intermediate_mul.size() == n - 1); + assert(intermediate_sum.size() == n - 1); + + for (size_t i = 0; i < n - 1; ++i) { + intermediate_mul[i].generate_r1cs_constraints(); + intermediate_sum[i].generate_r1cs_constraints(); + } +} + +template +void kzg10_batched_compute_gamma_powers_times_points:: + generate_r1cs_witness() +{ + assert(intermediate_mul.size() == n - 1); + assert(intermediate_sum.size() == n - 1); + + for (size_t i = 0; i < n - 1; ++i) { + intermediate_mul[i].generate_r1cs_witness(); + intermediate_sum[i].generate_r1cs_witness(); + } +} + // // kzg10_batched_compute_commit_minus_eval_sum // @@ -182,7 +288,7 @@ kzg10_batched_compute_commit_minus_eval_sum:: FMT(annotation_prefix, " compute_gamma_power_times_commit_minus_encoded_eval")) { - // encoded_eval[i] = G1_mul_by_scalar(evals[i], G1::one()) + // encoded_eval[i] = G1_mul_by_scalar(evals[i], -G1::one()) // len(encoded_eval) = num_entries G1_variable g1_minus_one( pb, @@ -342,6 +448,145 @@ void kzg10_batched_compute_commit_minus_eval_sum:: // } } +// +// kzg10_batched_verifier_gadget +// + +template +kzg10_batched_verifier_gadget:: + kzg10_batched_verifier_gadget( + protoboard> &pb, + pb_linear_combination> z_1, + pb_linear_combination> z_2, + const pb_linear_combination_array> &poly_evals_1, + const pb_linear_combination_array> &poly_evals_2, + const kzg10_srs_variable &srs, + pb_linear_combination> gamma_1, + pb_linear_combination> gamma_2, + const kzg10_batched_witness_variable &eval_witness, + const std::vector> &commitments_1, + const std::vector> &commitments_2, + pb_linear_combination> r, + pb_variable> result, + const std::string &annotation_prefix) + : gadget>(pb, annotation_prefix) + , G(pb, FMT(annotation_prefix, " G")) + , compute_G( + pb, + gamma_1, + commitments_1, + poly_evals_1, + G, + FMT(annotation_prefix, " compute_G")) + , H(pb, FMT(annotation_prefix, " H")) + , compute_H( + pb, + gamma_2, + commitments_2, + poly_evals_2, + H, + FMT(annotation_prefix, " compute_H")) + , rH(pb, FMT(annotation_prefix, " rH")) + // NOTE: this ignores H.is_identity + , compute_rH(pb, r, H, rH, FMT(annotation_prefix, " compute_rH")) + , F(pb, FMT(annotation_prefix, " F")) + , compute_F(pb, rH, G, F, FMT(annotation_prefix, " compute_F")) + // A = W_1 + r * W_2 + , r_times_W_2(pb, FMT(annotation_prefix, " r_times_W_2")) + , compute_r_times_W_2( + pb, + r, + eval_witness.W_2, + r_times_W_2, + FMT(annotation_prefix, " compute_r_times_W_2")) + , A(pb, FMT(annotation_prefix, " A")) + , compute_A( + pb, + r_times_W_2, + eval_witness.W_1, + A, + FMT(annotation_prefix, " compute_A")) + // B = F + z_1 * W_1 + r * z_2 * W_2 + , r_times_z_2_times_W_2( + pb, FMT(annotation_prefix, " r_times_z_2_times_W_2")) + , compute_r_times_z_2_times_W_2( + pb, + z_2, + r_times_W_2, + r_times_z_2_times_W_2, + FMT(annotation_prefix, " compute_r_times_z_2_times_W_2")) + , z_1_times_W_1(pb, FMT(annotation_prefix, " z_1_times_W_1")) + , compute_z_1_times_W_1( + pb, + z_1, + eval_witness.W_1, + z_1_times_W_1, + FMT(annotation_prefix, " compute_z_1_times_W_1")) + , F_plus_z_1_times_W_1(pb, FMT(annotation_prefix, " F_plus_z_1_times_W_1")) + , compute_F_plus_z_1_times_W_1( + pb, + z_1_times_W_1, + F, + F_plus_z_1_times_W_1, + FMT(annotation_prefix, " compute_F_plus_z_1_times_W_1")) + , B(pb, FMT(annotation_prefix, " B")) + , compute_B( + pb, + r_times_z_2_times_W_2, + F_plus_z_1_times_W_1, + B, + FMT(annotation_prefix, " compute_B")) + , pairing_check( + pb, + A, + srs.alpha_g2, + B, + libff::G2>::one(), + result, + FMT(annotation_prefix, " pairing_check")) +{ +} + +template +void kzg10_batched_verifier_gadget:: + generate_r1cs_constraints() +{ + compute_G.generate_r1cs_constraints(); + compute_H.generate_r1cs_constraints(); + compute_rH.generate_r1cs_constraints(); + compute_F.generate_r1cs_constraints(); + compute_r_times_W_2.generate_r1cs_constraints(); + compute_A.generate_r1cs_constraints(); + compute_r_times_z_2_times_W_2.generate_r1cs_constraints(); + compute_z_1_times_W_1.generate_r1cs_constraints(); + compute_F_plus_z_1_times_W_1.generate_r1cs_constraints(); + compute_B.generate_r1cs_constraints(); + pairing_check.generate_r1cs_constraints(); +} + +template +void kzg10_batched_verifier_gadget:: + generate_r1cs_witness() +{ + compute_G.generate_r1cs_witness(); + compute_H.generate_r1cs_witness(); + compute_rH.generate_r1cs_witness(); + compute_F.generate_r1cs_witness(); + compute_r_times_W_2.generate_r1cs_witness(); + compute_A.generate_r1cs_witness(); + compute_r_times_z_2_times_W_2.generate_r1cs_witness(); + compute_z_1_times_W_1.generate_r1cs_witness(); + compute_F_plus_z_1_times_W_1.generate_r1cs_witness(); + compute_B.generate_r1cs_witness(); + pairing_check.generate_r1cs_witness(); + + // // result = (1 - B.is_identity) * pairing_check_result + // const Field pairing_check_result_val = + // this->pb.val(pairing_check_result); const Field B_is_identity_val = + // this->pb.lc_val(B.is_identity); this->pb.val(result) = + // (Field::one() - B_is_identity_val) * pairing_check_result_val; +} + } // namespace libsnark #endif // LIBSNARK_GADGETLIB1_GADGETS_VERIFIERS_KZG10_BATCHED_VERIFIER_GADGET_TCC_ diff --git a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp index ef25781a5..19d06fb11 100644 --- a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp +++ b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp @@ -225,7 +225,7 @@ template void test_kzg10_batched_commit_minus_eval_sum_gadget() using nField = libff::Fr>; using nG1 = libff::G1>; - const nField gamma("51"); + const nField gamma = -nField("51"); const std::vector evals{{"3"}, {"5"}, {"7"}, {"11"}}; const std::vector cms{{ nField("13") * nG1::one(), @@ -234,14 +234,14 @@ template void test_kzg10_batched_commit_minus_eval_sum_gadget() nField("23") * nG1::one(), }}; - // 2-entry case - const nG1 r_2 = nField((13 - 3) + 51 * (17 - 5)) * nG1::one(); - do_test_kzg10_batched_commit_minus_eval_sum( - gamma, {evals[0], evals[1]}, {cms[0], cms[1]}, r_2, true); + // // 2-entry case + // const nG1 r_2 = nField((13 - 3) - 51 * (17 - 5)) * nG1::one(); + // do_test_kzg10_batched_commit_minus_eval_sum( + // gamma, {evals[0], evals[1]}, {cms[0], cms[1]}, r_2, true); // 3-entry case const nG1 r_3 = - nField((13 - 3) + 51 * (17 - 5) + (51 * 51) * (19 - 7)) * nG1::one(); + nField((13 - 3) - 51 * (17 - 5) + (51 * 51) * (19 - 7)) * nG1::one(); do_test_kzg10_batched_commit_minus_eval_sum( gamma, {evals[0], evals[1], evals[2]}, @@ -251,13 +251,376 @@ template void test_kzg10_batched_commit_minus_eval_sum_gadget() // 4-entry case const nG1 r_4 = nField( - (13 - 3) + 51 * (17 - 5) + (51 * 51) * (19 - 7) + + (13 - 3) - 51 * (17 - 5) + (51 * 51) * (19 - 7) - (51 * 51 * 51) * (23 - 11)) * nG1::one(); do_test_kzg10_batched_commit_minus_eval_sum( gamma, evals, cms, r_4, true); } +template +void do_test_kzg10_batched_verifier_gadget( + const libff::Fr> &z_1, + const libff::Fr> &z_2, + const typename kzg10_batched_2_point>::evaluations + &evaluations, + const typename kzg10>::srs &srs, + const libff::Fr> &gamma_1, + const libff::Fr> &gamma_2, + const typename kzg10_batched_2_point>::evaluation_witness + &eval_witness, + const std::vector>::commitment> &cm_1s, + const std::vector>::commitment> &cm_2s, + const libff::Fr> &r, + const bool expected_result) +{ + using Field = libff::Fr; + using npp = other_curve; + using nG1 = libff::G1; + + protoboard pb; + + // z_1 and z_2 + pb_variable z_1_var; + z_1_var.allocate(pb, "z_1_var"); + pb_variable z_2_var; + z_2_var.allocate(pb, "z_2_var"); + + // Evaluations + pb_variable_array poly_1_evals_var; + poly_1_evals_var.allocate(pb, evaluations.s_1s.size(), "poly_1_evals_var"); + + pb_variable_array poly_2_evals_var; + poly_2_evals_var.allocate(pb, evaluations.s_2s.size(), "poly_2_evals_var"); + + // srs + kzg10_srs_variable srs_var(pb, POLYNOMIAL_MAX_DEGREE, "srs_var"); + + // Gammas + pb_variable gamma_1_var; + gamma_1_var.allocate(pb, "gamma_1_var"); + pb_variable gamma_2_var; + gamma_2_var.allocate(pb, "gamma_2_var"); + + // Witness + kzg10_batched_witness_variable eval_witness_var( + pb, "eval_witness_var"); + + // Commitments + std::vector> cm_1s_var; + std::vector> cm_2s_var; + + for (size_t i = 0; i < cm_1s.size(); ++i) { + cm_1s_var.push_back( + kzg10_commitment_variable(pb, FMT("", "cm_1s_var[%zu]", i))); + } + + for (size_t i = 0; i < cm_2s.size(); ++i) { + cm_2s_var.push_back( + kzg10_commitment_variable(pb, FMT("", "cm_2s_var[%zu]", i))); + } + + // r + pb_variable r_var; + r_var.allocate(pb, "r_var"); + + // result + pb_variable result_var; + result_var.allocate(pb, "result_var"); + + // Verifier gadget + kzg10_batched_verifier_gadget + verifier_gadget( + pb, + z_1_var, + z_2_var, + poly_1_evals_var, + poly_2_evals_var, + srs_var, + gamma_1_var, + gamma_2_var, + eval_witness_var, + cm_1s_var, + cm_2s_var, + r_var, + result_var, + "verifier_gadget"); + + verifier_gadget.generate_r1cs_constraints(); + + // Field containers of nField elements + Field wrapping_z_1; + libff::fp_from_fp(wrapping_z_1, z_1); + Field wrapping_z_2; + libff::fp_from_fp(wrapping_z_2, z_2); + std::vector wrapping_poly_1_evals(evaluations.s_1s.size()); + for (size_t i = 0; i < evaluations.s_1s.size(); ++i) { + libff::fp_from_fp(wrapping_poly_1_evals[i], evaluations.s_1s[i]); + } + std::vector wrapping_poly_2_evals(evaluations.s_2s.size()); + for (size_t i = 0; i < evaluations.s_2s.size(); ++i) { + libff::fp_from_fp(wrapping_poly_2_evals[i], evaluations.s_2s[i]); + } + Field wrapping_gamma_1; + libff::fp_from_fp(wrapping_gamma_1, gamma_1); + Field wrapping_gamma_2; + libff::fp_from_fp(wrapping_gamma_2, gamma_2); + Field wrapping_r; + libff::fp_from_fp(wrapping_r, r); + + // Assign witnesses to all parameters + pb.val(z_1_var) = wrapping_z_1; + pb.val(z_2_var) = wrapping_z_2; + poly_1_evals_var.fill_with_field_elements(pb, wrapping_poly_1_evals); + poly_2_evals_var.fill_with_field_elements(pb, wrapping_poly_2_evals); + srs_var.generate_r1cs_witness(srs); + pb.val(gamma_1_var) = wrapping_gamma_1; + pb.val(gamma_2_var) = wrapping_gamma_2; + eval_witness_var.generate_r1cs_witness(eval_witness); + for (size_t i = 0; i < cm_1s.size(); ++i) { + cm_1s_var[i].generate_r1cs_witness(cm_1s[i]); + } + for (size_t i = 0; i < cm_2s.size(); ++i) { + cm_2s_var[i].generate_r1cs_witness(cm_2s[i]); + } + pb.val(r_var) = wrapping_r; + + verifier_gadget.generate_r1cs_witness(); + + // Check intermediate values + + if (expected_result) { + const nG1 G_expect = internal::gamma_times_commit_minus_eval_sum( + gamma_1, evaluations.s_1s, cm_1s); + const nG1 H_expect = internal::gamma_times_commit_minus_eval_sum( + gamma_2, evaluations.s_2s, cm_2s); + const nG1 F_expect = G_expect + r * H_expect; + + const nG1 r_times_W_2_expect = r * eval_witness.W_2; + const nG1 A_expect = eval_witness.W_1 + r_times_W_2_expect; + + const nG1 r_times_z_2_times_W_2_expect = z_2 * r_times_W_2_expect; + const nG1 z_1_times_W_1_expect = z_1 * eval_witness.W_1; + const nG1 F_plus_z_1_times_W_1_expect = F_expect + z_1_times_W_1_expect; + const nG1 B_expect = + F_plus_z_1_times_W_1_expect + r_times_z_2_times_W_2_expect; + + ASSERT_EQ(G_expect, verifier_gadget.G.get_element()); + ASSERT_EQ(H_expect, verifier_gadget.H.get_element()); + ASSERT_EQ(F_expect, verifier_gadget.F.get_element()); + ASSERT_EQ( + r_times_W_2_expect, verifier_gadget.r_times_W_2.get_element()); + ASSERT_EQ(A_expect, verifier_gadget.A.get_element()); + ASSERT_EQ( + r_times_z_2_times_W_2_expect, + verifier_gadget.r_times_z_2_times_W_2.get_element()); + ASSERT_EQ( + z_1_times_W_1_expect, verifier_gadget.z_1_times_W_1.get_element()); + ASSERT_EQ( + F_plus_z_1_times_W_1_expect, + verifier_gadget.F_plus_z_1_times_W_1.get_element()); + ASSERT_EQ(B_expect, verifier_gadget.B.get_element()); + } + + // Check the result. + + ASSERT_TRUE(pb.is_satisfied()); + ASSERT_EQ( + expected_result ? Field::one() : Field::zero(), pb.val(result_var)); + + // Test proof gen + + const r1cs_gg_ppzksnark_keypair keypair = + r1cs_gg_ppzksnark_generator(pb.get_constraint_system(), true); + const r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_prover( + keypair.pk, pb.primary_input(), pb.auxiliary_input(), true); + ASSERT_TRUE(r1cs_gg_ppzksnark_verifier_strong_IC( + keypair.vk, pb.primary_input(), proof)); +} + +template void test_kzg10_batched_verifier_gadget() +{ + using npp = other_curve; + using scheme = kzg10; + + using nField = libff::Fr; + + // 2 polynomials to be evaluated at the first point, 3 at the second. + const size_t num_polynomials_1 = 2; + const size_t num_polynomials_2 = 3; + + // SRS + const typename scheme::srs srs = scheme::setup(POLYNOMIAL_MAX_DEGREE); + + // Generate polynomials and commitment + std::vector> polynomials_1; + std::vector> polynomials_2; + std::vector::commitment> cm_1s; + std::vector::commitment> cm_2s; + + for (size_t i = 0; i < num_polynomials_1; ++i) { + polynomials_1.push_back(gen_polynomial(POLYNOMIAL_SIZE)); + cm_1s.push_back(kzg10::commit(srs, polynomials_1.back())); + } + + for (size_t i = 0; i < num_polynomials_2; ++i) { + polynomials_2.push_back(gen_polynomial(POLYNOMIAL_SIZE)); + cm_2s.push_back(kzg10::commit(srs, polynomials_2.back())); + } + + std::vector::commitment> cm_1s_invalid{ + cm_1s[0] + cm_1s[0], cm_1s[1]}; + std::vector::commitment> cm_2s_invalid{ + cm_2s[0] + cm_2s[0], cm_2s[1], cm_2s[2]}; + + // Evaluations + const nField z_1 = nField("13"); + const nField z_2 = nField("17"); + + const typename kzg10_batched_2_point::evaluations evals = + kzg10_batched_2_point::evaluate_polynomials( + polynomials_1, polynomials_2, z_1, z_2); + + // Witness + const nField gamma_1 = nField("3"); + const nField gamma_2 = -nField("5"); + + const typename kzg10_batched_2_point::evaluation_witness eval_witness = + kzg10_batched_2_point::create_evaluation_witness( + polynomials_1, + polynomials_2, + z_1, + z_2, + evals, + srs, + gamma_1, + gamma_2); + + // Check evaluations and witness natively + const nField r = nField("7"); + ASSERT_TRUE(kzg10_batched_2_point::verify_evaluations( + z_1, z_2, evals, srs, gamma_1, gamma_2, eval_witness, cm_1s, cm_2s, r)); + + // Test gadget in the positive case + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1, + z_2, + evals, + srs, + gamma_1, + gamma_2, + eval_witness, + cm_1s, + cm_2s, + r, + true); + + // Test some failure cases: + + // Invalid cases + { + // Invalid evaluation point + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1 + z_1, + z_2, + evals, + srs, + gamma_1, + gamma_2, + eval_witness, + cm_1s, + cm_2s, + r, + false); + + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1, + z_2 + z_2, + evals, + srs, + gamma_1, + gamma_2, + eval_witness, + cm_1s, + cm_2s, + r, + false); + + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1, + z_2, + evals, + srs, + gamma_1 + gamma_1, + gamma_2, + eval_witness, + cm_1s, + cm_2s, + r, + false); + + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1, + z_2, + evals, + srs, + gamma_1, + gamma_2 + gamma_2, + eval_witness, + cm_1s, + cm_2s, + r, + false); + + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1, + z_2, + evals, + srs, + gamma_1, + gamma_2, + eval_witness, + cm_1s_invalid, + cm_2s, + r, + false); + + do_test_kzg10_batched_verifier_gadget< + wppT, + num_polynomials_1, + num_polynomials_2>( + z_1, + z_2, + evals, + srs, + gamma_1, + gamma_2, + eval_witness, + cm_1s, + cm_2s_invalid, + r, + false); + } +} + TEST(TestKZG10VerifierGadget, ValidEvaluation) { test_kzg10_verifier_gadget(); @@ -268,6 +631,11 @@ TEST(TestKZG10VerifierGadget, BatchedCommitMinusEvalSum) test_kzg10_batched_commit_minus_eval_sum_gadget(); } +TEST(TestKZG10VerifierGadget, BatchedValidEvaluation) +{ + test_kzg10_batched_verifier_gadget(); +} + } // namespace int main(int argc, char **argv) From 92263ca7d5d97958cbc163a6fa2022ceb21414b7 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 21 Apr 2022 17:17:55 +0100 Subject: [PATCH 08/12] refactor kzg10_batched util gadgets --- .../kzg10_batched_verifier_gadget.hpp | 17 ++++++++----- .../kzg10_batched_verifier_gadget.tcc | 25 +++++++++++-------- .../tests/test_kzg10_verifier_gadget.cpp | 19 ++++++++------ 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp index 0d85eadba..f1815c873 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp @@ -77,7 +77,8 @@ class kzg10_batched_compute_gamma_powers_times_points : gadget> /// must be statically defined, although all internal structures are currently /// dynamic. This also allows specialization for the case of 2 entries. template -class kzg10_batched_compute_commit_minus_eval_sum : gadget> +class kzg10_batched_compute_gamma_powers_commit_minus_eval_sum + : gadget> { static_assert(num_entries > 2, "num_entries must be greater that 2"); @@ -101,7 +102,7 @@ class kzg10_batched_compute_commit_minus_eval_sum : gadget> kzg10_batched_compute_gamma_powers_times_points compute_gamma_power_times_commit_minus_encoded_eval; - kzg10_batched_compute_commit_minus_eval_sum( + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, const pb_linear_combination> &gamma, const std::vector> &commitments, @@ -119,7 +120,7 @@ class kzg10_batched_compute_commit_minus_eval_sum : gadget> // further powers of gamma). This simplifies the generic (num_entries >= 3) // version, since it does not need to account for special cases. template -class kzg10_batched_compute_commit_minus_eval_sum +class kzg10_batched_compute_gamma_powers_commit_minus_eval_sum : gadget> { public: @@ -136,7 +137,7 @@ class kzg10_batched_compute_commit_minus_eval_sum std::shared_ptr> compute_result; - kzg10_batched_compute_commit_minus_eval_sum( + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, pb_linear_combination> gamma, const std::vector> commitments, @@ -179,10 +180,14 @@ class kzg10_batched_verifier_gadget : public gadget> // G = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) // H = \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) G1_variable G; - kzg10_batched_compute_commit_minus_eval_sum + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< + ppT, + num_polyomials_1> compute_G; G1_variable H; - kzg10_batched_compute_commit_minus_eval_sum + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< + ppT, + num_polyomials_2> compute_H; G1_variable_or_identity rH; G1_mul_by_scalar_gadget compute_rH; diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc index cce953247..27e09163c 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc @@ -151,8 +151,8 @@ void kzg10_batched_compute_gamma_powers_times_points:: // specialization for 2 entries template -kzg10_batched_compute_commit_minus_eval_sum:: - kzg10_batched_compute_commit_minus_eval_sum( +kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, pb_linear_combination> gamma, const std::vector> commits, @@ -215,7 +215,7 @@ kzg10_batched_compute_commit_minus_eval_sum:: } template -void kzg10_batched_compute_commit_minus_eval_sum:: +void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: generate_r1cs_constraints() { compute_encoded_evals[0].generate_r1cs_constraints(); @@ -227,7 +227,7 @@ void kzg10_batched_compute_commit_minus_eval_sum:: } template -void kzg10_batched_compute_commit_minus_eval_sum:: +void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: generate_r1cs_witness() { compute_encoded_evals[0].generate_r1cs_witness(); @@ -240,15 +240,16 @@ void kzg10_batched_compute_commit_minus_eval_sum:: template const G1_variable - &kzg10_batched_compute_commit_minus_eval_sum::result() const + &kzg10_batched_compute_gamma_powers_commit_minus_eval_sum::result() + const { return compute_result->result; } // specialization for >2 entries template -kzg10_batched_compute_commit_minus_eval_sum:: - kzg10_batched_compute_commit_minus_eval_sum( +kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, const pb_linear_combination> &gamma, const std::vector> &commitments, @@ -392,8 +393,9 @@ kzg10_batched_compute_commit_minus_eval_sum:: } template -void kzg10_batched_compute_commit_minus_eval_sum:: - generate_r1cs_constraints() +void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< + ppT, + num_entries>::generate_r1cs_constraints() { for (auto &gadget : compute_encoded_evals) { gadget.generate_r1cs_constraints(); @@ -417,8 +419,9 @@ void kzg10_batched_compute_commit_minus_eval_sum:: } template -void kzg10_batched_compute_commit_minus_eval_sum:: - generate_r1cs_witness() +void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< + ppT, + num_entries>::generate_r1cs_witness() { for (auto &gadget : compute_encoded_evals) { gadget.generate_r1cs_witness(); diff --git a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp index 19d06fb11..828ed0545 100644 --- a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp +++ b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp @@ -157,7 +157,7 @@ template void test_kzg10_verifier_gadget() } template -void do_test_kzg10_batched_commit_minus_eval_sum( +void do_test_kzg10_batched_gamma_powers_commit_minus_eval_sum( const libff::Fr> &gamma, const std::vector>> &evals, const std::vector>::commitment> &cms, @@ -181,8 +181,9 @@ void do_test_kzg10_batched_commit_minus_eval_sum( evals_var.allocate(pb, num_entries, "evals_var"); G1_variable result_var(pb, "result_var"); - kzg10_batched_compute_commit_minus_eval_sum compute_sum( - pb, gamma_var, cms_var, evals_var, result_var, "compute_sum"); + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum + compute_sum( + pb, gamma_var, cms_var, evals_var, result_var, "compute_sum"); compute_sum.generate_r1cs_constraints(); @@ -220,7 +221,8 @@ void do_test_kzg10_batched_commit_minus_eval_sum( keypair.vk, pb.primary_input(), proof)); } -template void test_kzg10_batched_commit_minus_eval_sum_gadget() +template +void test_kzg10_batched_gamma_powers_commit_minus_eval_sum_gadget() { using nField = libff::Fr>; using nG1 = libff::G1>; @@ -242,7 +244,7 @@ template void test_kzg10_batched_commit_minus_eval_sum_gadget() // 3-entry case const nG1 r_3 = nField((13 - 3) - 51 * (17 - 5) + (51 * 51) * (19 - 7)) * nG1::one(); - do_test_kzg10_batched_commit_minus_eval_sum( + do_test_kzg10_batched_gamma_powers_commit_minus_eval_sum( gamma, {evals[0], evals[1], evals[2]}, {cms[0], cms[1], cms[2]}, @@ -254,7 +256,7 @@ template void test_kzg10_batched_commit_minus_eval_sum_gadget() (13 - 3) - 51 * (17 - 5) + (51 * 51) * (19 - 7) - (51 * 51 * 51) * (23 - 11)) * nG1::one(); - do_test_kzg10_batched_commit_minus_eval_sum( + do_test_kzg10_batched_gamma_powers_commit_minus_eval_sum( gamma, evals, cms, r_4, true); } @@ -626,9 +628,10 @@ TEST(TestKZG10VerifierGadget, ValidEvaluation) test_kzg10_verifier_gadget(); } -TEST(TestKZG10VerifierGadget, BatchedCommitMinusEvalSum) +TEST(TestKZG10VerifierGadget, BatchedGammaPowersCommitMinusEvalSum) { - test_kzg10_batched_commit_minus_eval_sum_gadget(); + test_kzg10_batched_gamma_powers_commit_minus_eval_sum_gadget< + libff::bw6_761_pp>(); } TEST(TestKZG10VerifierGadget, BatchedValidEvaluation) From 342dc975388a67a626b394609d97882c7065d819 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 21 Apr 2022 18:08:19 +0100 Subject: [PATCH 09/12] kzg10_batched util gadget result handling improvement --- .../kzg10_batched_verifier_gadget.hpp | 14 +- .../kzg10_batched_verifier_gadget.tcc | 218 ++++++++++-------- 2 files changed, 125 insertions(+), 107 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp index f1815c873..f1eab3623 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp @@ -61,11 +61,13 @@ class kzg10_batched_compute_gamma_powers_times_points : gadget> protoboard> &pb, const pb_linear_combination> &gamma, const std::vector> &points, - G1_variable &result, + const G1_variable &result, const std::string &annotation_prefix); void generate_r1cs_constraints(); void generate_r1cs_witness(); + + const G1_variable &result() const; }; /// Given an array of commitments, and array of evaluations, and some field @@ -105,9 +107,9 @@ class kzg10_batched_compute_gamma_powers_commit_minus_eval_sum kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, const pb_linear_combination> &gamma, - const std::vector> &commitments, + const std::vector> &commits, const pb_linear_combination_array> &evals, - G1_variable &result, + const G1_variable &result, const std::string &annotation_prefix); void generate_r1cs_constraints(); @@ -139,10 +141,10 @@ class kzg10_batched_compute_gamma_powers_commit_minus_eval_sum kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, - pb_linear_combination> gamma, - const std::vector> commitments, + const pb_linear_combination> &gamma, + const std::vector> &commitments, const pb_linear_combination_array> &evals, - G1_variable &result, + const G1_variable &result, const std::string &annotation_prefix); void generate_r1cs_constraints(); diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc index 27e09163c..b808337fc 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc @@ -70,7 +70,7 @@ kzg10_batched_compute_gamma_powers_times_points:: protoboard> &pb, const pb_linear_combination> &gamma, const std::vector> &points, - G1_variable &result, + const G1_variable &result, const std::string &annotation_prefix) : gadget>(pb, annotation_prefix) { @@ -145,116 +145,26 @@ void kzg10_batched_compute_gamma_powers_times_points:: } } -// -// kzg10_batched_compute_commit_minus_eval_sum -// - -// specialization for 2 entries -template -kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: - kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( - protoboard> &pb, - pb_linear_combination> gamma, - const std::vector> commits, - const pb_linear_combination_array> &evals, - G1_variable &result, - const std::string &annotation_prefix) - : gadget>(pb, annotation_prefix) -{ - G1_variable g1_minus_1( - pb, - -libff::G1>::one(), - FMT(annotation_prefix, " g1_minus_1")); - - // encoded_evals[i] = evals[i] * -G1::one() - compute_encoded_evals.emplace_back( - pb, - evals[0], - g1_minus_1, - G1_variable_or_identity( - pb, FMT(annotation_prefix, " encoded_evals[0]")), - FMT(annotation_prefix, " compute_encoded_evals[0]")); - compute_encoded_evals.emplace_back( - pb, - evals[1], - g1_minus_1, - G1_variable_or_identity( - pb, FMT(annotation_prefix, " encoded_evals[1]")), - FMT(annotation_prefix, " compute_encoded_evals[1]")); - - // cm_minus_encoded_eval[i] = commits[i] - encoded_evals[i] - compute_cm_minus_eval.emplace_back( - pb, - compute_encoded_evals[0].result(), - commits[0], - G1_variable(pb, FMT(annotation_prefix, " cm_minus_eval[0]")), - FMT(annotation_prefix, " compute_cm_minus_eval[0]")); - compute_cm_minus_eval.emplace_back( - pb, - compute_encoded_evals[1].result(), - commits[1], - G1_variable(pb, FMT(annotation_prefix, " cm_minus_eval[1]")), - FMT(annotation_prefix, " compute_cm_minus_eval[1]")); - - // gamma_term = gamma * commit_minus_encoded_eval[1] - // return = gamma_term + (commit_minus_encoded_eval[0] - compute_gamma_term = std::make_shared>( - pb, - gamma, - compute_cm_minus_eval[1].result, - G1_variable_or_identity(pb, FMT(annotation_prefix, " gamma_term")), - FMT(annotation_prefix, " compute_gamma_term")); - - compute_result = - std::make_shared>( - pb, - compute_gamma_term->result(), - compute_cm_minus_eval[0].result, - result, - FMT(annotation_prefix, " compute_result")); -} - -template -void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: - generate_r1cs_constraints() -{ - compute_encoded_evals[0].generate_r1cs_constraints(); - compute_encoded_evals[1].generate_r1cs_constraints(); - compute_cm_minus_eval[0].generate_r1cs_constraints(); - compute_cm_minus_eval[1].generate_r1cs_constraints(); - compute_gamma_term->generate_r1cs_constraints(); - compute_result->generate_r1cs_constraints(); -} - -template -void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: - generate_r1cs_witness() -{ - compute_encoded_evals[0].generate_r1cs_witness(); - compute_encoded_evals[1].generate_r1cs_witness(); - compute_cm_minus_eval[0].generate_r1cs_witness(); - compute_cm_minus_eval[1].generate_r1cs_witness(); - compute_gamma_term->generate_r1cs_witness(); - compute_result->generate_r1cs_witness(); -} - -template +template const G1_variable - &kzg10_batched_compute_gamma_powers_commit_minus_eval_sum::result() - const + &kzg10_batched_compute_gamma_powers_times_points::result() const { - return compute_result->result; + return intermediate_sum.back().result; } +// +// kzg10_batched_compute_gamma_powers_commit_minus_eval_sum +// + // specialization for >2 entries template kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( protoboard> &pb, const pb_linear_combination> &gamma, - const std::vector> &commitments, + const std::vector> &commits, const pb_linear_combination_array> &evals, - G1_variable &result, + const G1_variable &result, const std::string &annotation_prefix) : gadget>(pb, annotation_prefix) , encoded_evals( @@ -311,7 +221,7 @@ kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: compute_commit_minus_encoded_eval.emplace_back( pb, encoded_evals[i], - commitments[i], + commits[i], commit_minus_encoded_eval[i], FMT(annotation_prefix, " compute_commit_minus_encoded_eval")); } @@ -451,6 +361,112 @@ void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< // } } +template +const G1_variable + &kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< + ppT, + num_entries>::result() const +{ + return compute_gamma_power_times_commit_minus_encoded_eval.result(); +} + +// specialization for 2 entries +template +kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: + kzg10_batched_compute_gamma_powers_commit_minus_eval_sum( + protoboard> &pb, + const pb_linear_combination> &gamma, + const std::vector> &commits, + const pb_linear_combination_array> &evals, + const G1_variable &result, + const std::string &annotation_prefix) + : gadget>(pb, annotation_prefix) +{ + G1_variable g1_minus_1( + pb, + -libff::G1>::one(), + FMT(annotation_prefix, " g1_minus_1")); + + // encoded_evals[i] = evals[i] * -G1::one() + compute_encoded_evals.emplace_back( + pb, + evals[0], + g1_minus_1, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " encoded_evals[0]")), + FMT(annotation_prefix, " compute_encoded_evals[0]")); + compute_encoded_evals.emplace_back( + pb, + evals[1], + g1_minus_1, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " encoded_evals[1]")), + FMT(annotation_prefix, " compute_encoded_evals[1]")); + + // cm_minus_encoded_eval[i] = commits[i] - encoded_evals[i] + compute_cm_minus_eval.emplace_back( + pb, + compute_encoded_evals[0].result(), + commits[0], + G1_variable(pb, FMT(annotation_prefix, " cm_minus_eval[0]")), + FMT(annotation_prefix, " compute_cm_minus_eval[0]")); + compute_cm_minus_eval.emplace_back( + pb, + compute_encoded_evals[1].result(), + commits[1], + G1_variable(pb, FMT(annotation_prefix, " cm_minus_eval[1]")), + FMT(annotation_prefix, " compute_cm_minus_eval[1]")); + + // gamma_term = gamma * commit_minus_encoded_eval[1] + // return = gamma_term + (commit_minus_encoded_eval[0] + compute_gamma_term = std::make_shared>( + pb, + gamma, + compute_cm_minus_eval[1].result, + G1_variable_or_identity(pb, FMT(annotation_prefix, " gamma_term")), + FMT(annotation_prefix, " compute_gamma_term")); + + compute_result = + std::make_shared>( + pb, + compute_gamma_term->result(), + compute_cm_minus_eval[0].result, + result, + FMT(annotation_prefix, " compute_result")); +} + +template +void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: + generate_r1cs_constraints() +{ + compute_encoded_evals[0].generate_r1cs_constraints(); + compute_encoded_evals[1].generate_r1cs_constraints(); + compute_cm_minus_eval[0].generate_r1cs_constraints(); + compute_cm_minus_eval[1].generate_r1cs_constraints(); + compute_gamma_term->generate_r1cs_constraints(); + compute_result->generate_r1cs_constraints(); +} + +template +void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: + generate_r1cs_witness() +{ + compute_encoded_evals[0].generate_r1cs_witness(); + compute_encoded_evals[1].generate_r1cs_witness(); + compute_cm_minus_eval[0].generate_r1cs_witness(); + compute_cm_minus_eval[1].generate_r1cs_witness(); + compute_gamma_term->generate_r1cs_witness(); + compute_result->generate_r1cs_witness(); +} + +template +const G1_variable + &kzg10_batched_compute_gamma_powers_commit_minus_eval_sum::result() + const +{ + return compute_result->result; +} + // // kzg10_batched_verifier_gadget // From 230420c4134f7455f18f6b220a64ae97ace68574 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 10:40:08 +0100 Subject: [PATCH 10/12] kzg10_batched: remove some unnecessary intermediate values on gadget (simplify impl) --- .../kzg10_batched_verifier_gadget.hpp | 15 -- .../kzg10_batched_verifier_gadget.tcc | 182 +++--------------- .../tests/test_kzg10_verifier_gadget.cpp | 21 +- 3 files changed, 43 insertions(+), 175 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp index f1eab3623..1351515b7 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp @@ -181,19 +181,15 @@ class kzg10_batched_verifier_gadget : public gadget> // // G = \sum_{i=1}^{t1} \gamma_1^{i-1} (cm_1[i] - [s_1[i]]_1) // H = \sum_{i=1}^{t2} \gamma_2^{i-1} (cm_2[i] - [s_2[i]]_1) - G1_variable G; kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< ppT, num_polyomials_1> compute_G; - G1_variable H; kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< ppT, num_polyomials_2> compute_H; - G1_variable_or_identity rH; G1_mul_by_scalar_gadget compute_rH; - G1_variable F; G1_add_variable_and_variable_or_identity_gadget compute_F; // Expression to check is: @@ -206,24 +202,13 @@ class kzg10_batched_verifier_gadget : public gadget> // A = W_1 + r * W_2 // B = F + z_1 * W_1 + r * z_2 * W_2 - G1_variable_or_identity r_times_W_2; G1_mul_by_scalar_gadget compute_r_times_W_2; - - G1_variable A; G1_add_variable_and_variable_or_identity_gadget compute_A; - - G1_variable_or_identity r_times_z_2_times_W_2; G1_variable_or_identity_mul_by_scalar_gadget compute_r_times_z_2_times_W_2; - - G1_variable_or_identity z_1_times_W_1; G1_mul_by_scalar_gadget compute_z_1_times_W_1; - - G1_variable F_plus_z_1_times_W_1; G1_add_variable_and_variable_or_identity_gadget compute_F_plus_z_1_times_W_1; - - G1_variable B; G1_add_variable_and_variable_or_identity_gadget compute_B; kzg10_pairing_check_gadget pairing_check; diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc index b808337fc..0a45b5515 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.tcc @@ -177,20 +177,6 @@ kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: num_entries, FMT(annotation_prefix, " commit_minus_encoded_eval"))) , compute_commit_minus_encoded_eval() - // , gamma(gamma) - // , gamma_powers() - // , gamma_power_times_commit_minus_encoded_eval( - // internal::allocate_variable_array>( - // pb, - // num_entries - 1, - // FMT(annotation_prefix, - // " gamma_power_times_commit_minus_encoded_eval"))) - // , compute_gamma_power_times_commit_minus_encoded_eval() - // , intermediate_sum(internal::allocate_variable_array>( - // pb, num_entries - 2, FMT(annotation_prefix, " intermediate_sum"))) - // , compute_intermediate_sum() , compute_gamma_power_times_commit_minus_encoded_eval( pb, gamma, @@ -225,81 +211,6 @@ kzg10_batched_compute_gamma_powers_commit_minus_eval_sum:: commit_minus_encoded_eval[i], FMT(annotation_prefix, " compute_commit_minus_encoded_eval")); } - - // // gamma_powers[0] = gamma * gamma - // // gamma_powers[i>0] = gamma * gamma_powers[i-1] - // gamma_powers.allocate( - // pb, num_entries - 2, FMT(annotation_prefix, " gamma_powers")); - // this->pb.add_r1cs_constraint( - // r1cs_constraint(gamma, gamma, gamma_powers[0]), - // FMT(annotation_prefix, " compute_gamma_power[0](gamma^2)")); - // for (size_t i = 1; i < num_entries - 2; ++i) { - // this->pb.add_r1cs_constraint( - // r1cs_constraint(gamma, gamma_powers[i - 1], - // gamma_powers[i]), FMT(annotation_prefix, - // " compute_gamma_power[%zu](gamma^%zu)", - // i, - // i + 2)); - // } - - // // gamma_power_times_commit_minus_encoded_eval[0] = - // // G1_mul(gamma, compute_commit_minus_encoded_eval[1]) - // // gamma_power_times_commit_minus_encoded_eval[i>0] = - // // G1_mul(gamma_powers[i-1], commit_minus_encoded_eval[i+1] - // compute_gamma_power_times_commit_minus_encoded_eval.reserve( - // num_entries - 1); - // compute_gamma_power_times_commit_minus_encoded_eval.emplace_back( - // pb, - // gamma, - // commit_minus_encoded_eval[1], - // gamma_power_times_commit_minus_encoded_eval[0], - // FMT(annotation_prefix, - // "compute_gamma_power_times_commit_minus_encoded_eval[0]")); - // for (size_t i = 1; i < num_entries - 1; ++i) { - // compute_gamma_power_times_commit_minus_encoded_eval.emplace_back( - // pb, - // gamma_powers[i - 1], - // commit_minus_encoded_eval[i + 1], - // gamma_power_times_commit_minus_encoded_eval[i], - // FMT(annotation_prefix, - // "compute_gamma_power_times_commit_minus_encoded_eval[0]")); - // } - - // // intermediate_sum[0] = G1_add( - // // commit_minus_encoded_eval[0], - // // gamma_power_times_commit_minus_encoded_eval[0]) - // // intermediate_sum[0 @@ -317,15 +228,6 @@ void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< compute_gamma_power_times_commit_minus_encoded_eval .generate_r1cs_constraints(); - - // for (auto &gadget : compute_gamma_power_times_commit_minus_encoded_eval) - // { - // gadget.generate_r1cs_constraints(); - // } - - // for (auto &gadget : compute_intermediate_sum) { - // gadget.generate_r1cs_constraints(); - // } } template @@ -342,23 +244,6 @@ void kzg10_batched_compute_gamma_powers_commit_minus_eval_sum< } compute_gamma_power_times_commit_minus_encoded_eval.generate_r1cs_witness(); - - // const Field gamma_val = this->pb.lc_val(gamma); - // Field gamma_power_val = gamma_val; - - // for (auto &gamma_power : gamma_powers) { - // gamma_power_val = gamma_power_val * gamma_val; - // this->pb.val(gamma_power) = gamma_power_val; - // } - - // for (auto &gadget : compute_gamma_power_times_commit_minus_encoded_eval) - // { - // gadget.generate_r1cs_witness(); - // } - - // for (auto &gadget : compute_intermediate_sum) { - // gadget.generate_r1cs_witness(); - // } } template @@ -489,77 +374,78 @@ kzg10_batched_verifier_gadget:: pb_variable> result, const std::string &annotation_prefix) : gadget>(pb, annotation_prefix) - , G(pb, FMT(annotation_prefix, " G")) , compute_G( pb, gamma_1, commitments_1, poly_evals_1, - G, + G1_variable(pb, FMT(annotation_prefix, " G")), FMT(annotation_prefix, " compute_G")) - , H(pb, FMT(annotation_prefix, " H")) , compute_H( pb, gamma_2, commitments_2, poly_evals_2, - H, + G1_variable(pb, FMT(annotation_prefix, " H")), FMT(annotation_prefix, " compute_H")) - , rH(pb, FMT(annotation_prefix, " rH")) - // NOTE: this ignores H.is_identity - , compute_rH(pb, r, H, rH, FMT(annotation_prefix, " compute_rH")) - , F(pb, FMT(annotation_prefix, " F")) - , compute_F(pb, rH, G, F, FMT(annotation_prefix, " compute_F")) + , compute_rH( + pb, + r, + compute_H.result(), + G1_variable_or_identity(pb, FMT(annotation_prefix, " rH")), + FMT(annotation_prefix, " compute_rH")) + , compute_F( + pb, + compute_rH.result(), + compute_G.result(), + G1_variable(pb, FMT(annotation_prefix, " F")), + FMT(annotation_prefix, " compute_F")) // A = W_1 + r * W_2 - , r_times_W_2(pb, FMT(annotation_prefix, " r_times_W_2")) , compute_r_times_W_2( pb, r, eval_witness.W_2, - r_times_W_2, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " r_times_W_2")), FMT(annotation_prefix, " compute_r_times_W_2")) - , A(pb, FMT(annotation_prefix, " A")) , compute_A( pb, - r_times_W_2, + compute_r_times_W_2.result(), eval_witness.W_1, - A, + G1_variable(pb, FMT(annotation_prefix, " A")), FMT(annotation_prefix, " compute_A")) // B = F + z_1 * W_1 + r * z_2 * W_2 - , r_times_z_2_times_W_2( - pb, FMT(annotation_prefix, " r_times_z_2_times_W_2")) , compute_r_times_z_2_times_W_2( pb, z_2, - r_times_W_2, - r_times_z_2_times_W_2, + compute_r_times_W_2.result(), + G1_variable_or_identity( + pb, FMT(annotation_prefix, " r_times_z_2_times_W_2")), FMT(annotation_prefix, " compute_r_times_z_2_times_W_2")) - , z_1_times_W_1(pb, FMT(annotation_prefix, " z_1_times_W_1")) , compute_z_1_times_W_1( pb, z_1, eval_witness.W_1, - z_1_times_W_1, + G1_variable_or_identity( + pb, FMT(annotation_prefix, " z_1_times_W_1")), FMT(annotation_prefix, " compute_z_1_times_W_1")) - , F_plus_z_1_times_W_1(pb, FMT(annotation_prefix, " F_plus_z_1_times_W_1")) , compute_F_plus_z_1_times_W_1( pb, - z_1_times_W_1, - F, - F_plus_z_1_times_W_1, + compute_z_1_times_W_1.result(), + compute_F.result, + G1_variable(pb, FMT(annotation_prefix, " F_plus_z_1_times_W_1")), FMT(annotation_prefix, " compute_F_plus_z_1_times_W_1")) - , B(pb, FMT(annotation_prefix, " B")) , compute_B( pb, - r_times_z_2_times_W_2, - F_plus_z_1_times_W_1, - B, + compute_r_times_z_2_times_W_2.result(), + compute_F_plus_z_1_times_W_1.result, + G1_variable(pb, FMT(annotation_prefix, " B")), FMT(annotation_prefix, " compute_B")) , pairing_check( pb, - A, + compute_A.result, srs.alpha_g2, - B, + compute_B.result, libff::G2>::one(), result, FMT(annotation_prefix, " pairing_check")) @@ -598,12 +484,6 @@ void kzg10_batched_verifier_gadget:: compute_F_plus_z_1_times_W_1.generate_r1cs_witness(); compute_B.generate_r1cs_witness(); pairing_check.generate_r1cs_witness(); - - // // result = (1 - B.is_identity) * pairing_check_result - // const Field pairing_check_result_val = - // this->pb.val(pairing_check_result); const Field B_is_identity_val = - // this->pb.lc_val(B.is_identity); this->pb.val(result) = - // (Field::one() - B_is_identity_val) * pairing_check_result_val; } } // namespace libsnark diff --git a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp index 828ed0545..44ffccfa6 100644 --- a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp +++ b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp @@ -407,21 +407,24 @@ void do_test_kzg10_batched_verifier_gadget( const nG1 B_expect = F_plus_z_1_times_W_1_expect + r_times_z_2_times_W_2_expect; - ASSERT_EQ(G_expect, verifier_gadget.G.get_element()); - ASSERT_EQ(H_expect, verifier_gadget.H.get_element()); - ASSERT_EQ(F_expect, verifier_gadget.F.get_element()); + ASSERT_EQ(G_expect, verifier_gadget.compute_G.result().get_element()); + ASSERT_EQ(H_expect, verifier_gadget.compute_H.result().get_element()); + ASSERT_EQ(F_expect, verifier_gadget.compute_F.result.get_element()); ASSERT_EQ( - r_times_W_2_expect, verifier_gadget.r_times_W_2.get_element()); - ASSERT_EQ(A_expect, verifier_gadget.A.get_element()); + r_times_W_2_expect, + verifier_gadget.compute_r_times_W_2.result().get_element()); + ASSERT_EQ(A_expect, verifier_gadget.compute_A.result.get_element()); ASSERT_EQ( r_times_z_2_times_W_2_expect, - verifier_gadget.r_times_z_2_times_W_2.get_element()); + verifier_gadget.compute_r_times_z_2_times_W_2.result() + .get_element()); ASSERT_EQ( - z_1_times_W_1_expect, verifier_gadget.z_1_times_W_1.get_element()); + z_1_times_W_1_expect, + verifier_gadget.compute_z_1_times_W_1.result().get_element()); ASSERT_EQ( F_plus_z_1_times_W_1_expect, - verifier_gadget.F_plus_z_1_times_W_1.get_element()); - ASSERT_EQ(B_expect, verifier_gadget.B.get_element()); + verifier_gadget.compute_F_plus_z_1_times_W_1.result.get_element()); + ASSERT_EQ(B_expect, verifier_gadget.compute_B.result.get_element()); } // Check the result. From c0efd38b6e51f822b2c1fbf6c5ff7a2538363c5c Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 14:10:09 +0100 Subject: [PATCH 11/12] fix typo in scalar_multiplication.hpp --- libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp index 280faa212..1b1698860 100644 --- a/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp +++ b/libsnark/gadgetlib1/gadgets/curves/scalar_multiplication.hpp @@ -73,7 +73,7 @@ class variable_or_identity : public gadget> }; /// Selector gadget for variable_or_identity. Outputs one of two -/// variable_or_identity objeects, depending on a scalar parameter. +/// variable_or_identity objects, depending on a scalar parameter. template< typename ppT, typename groupT, From 6bc8517e5e7584e66805ac4393fa97488b207dd7 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 14:11:49 +0100 Subject: [PATCH 12/12] kzg10_batched: update doc comments on verifier gadget --- .../verifiers/kzg10_batched_verifier_gadget.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp index 1351515b7..e4ce96812 100644 --- a/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp +++ b/libsnark/gadgetlib1/gadgets/verifiers/kzg10_batched_verifier_gadget.hpp @@ -156,13 +156,13 @@ class kzg10_batched_compute_gamma_powers_commit_minus_eval_sum /// Gadget version of the native KZG10 batched verifier in /// libsnark/polynomial_commitments/kzg10_batched.hpp. /// -/// Each polynomials can be evaluated at 1 of 2 points. `polyomials_1` -/// determines the number of polynomials evaluated at the first point `z_1`, -/// and `polynomials_2` determines the number to be evaluated at the second -/// point `z_2`. Hence these also determine the number of commitments and -/// evaluation points. +/// Each polynomial in a batch can be evaluated at 1 of 2 points. +/// `polyomials_1` determines the number of polynomials evaluated at the first +/// point `z_1`, and `polynomials_2` determines the number to be evaluated at +/// the second point `z_2`. Hence these also determine the number of +/// commitments and evaluation points. /// -/// The number of polynomials inn each group is intentionally a template +/// The number of polynomials in each group is intentionally a template /// parameter, reflecting the fact that it must be statically defined for a /// given circuit. template