From 7855e4ebd57a4e5d8d2d52d3bb0ab5b8d266eb7c Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Tue, 19 Apr 2022 17:18:23 +0100 Subject: [PATCH 01/21] fix inconsistency between default params and annotation asserts --- libsnark/gadgetlib1/gadget.hpp | 2 +- libsnark/gadgetlib1/gadget.tcc | 2 ++ libsnark/gadgetlib1/pb_variable.hpp | 4 ++-- libsnark/gadgetlib1/pb_variable.tcc | 7 +++++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libsnark/gadgetlib1/gadget.hpp b/libsnark/gadgetlib1/gadget.hpp index 2f3ad20ed..0dbcf2966 100644 --- a/libsnark/gadgetlib1/gadget.hpp +++ b/libsnark/gadgetlib1/gadget.hpp @@ -20,7 +20,7 @@ template class gadget const std::string annotation_prefix; public: - gadget(protoboard &pb, const std::string &annotation_prefix = ""); + gadget(protoboard &pb, const std::string &annotation_prefix); }; } // namespace libsnark diff --git a/libsnark/gadgetlib1/gadget.tcc b/libsnark/gadgetlib1/gadget.tcc index 654141d89..0d874e426 100644 --- a/libsnark/gadgetlib1/gadget.tcc +++ b/libsnark/gadgetlib1/gadget.tcc @@ -16,6 +16,8 @@ gadget::gadget( protoboard &pb, const std::string &annotation_prefix) : pb(pb), annotation_prefix(annotation_prefix) { + // Anotations may appear as "" (even if set by the calling code) unless + // DEBUG is set. See pb_variable.tcc. #ifdef DEBUG assert(annotation_prefix != ""); #endif diff --git a/libsnark/gadgetlib1/pb_variable.hpp b/libsnark/gadgetlib1/pb_variable.hpp index 5c4b05906..0ba6a24e4 100644 --- a/libsnark/gadgetlib1/pb_variable.hpp +++ b/libsnark/gadgetlib1/pb_variable.hpp @@ -26,7 +26,7 @@ template class pb_variable : public variable public: pb_variable(const var_index_t index = 0) : variable(index){}; - void allocate(protoboard &pb, const std::string &annotation = ""); + void allocate(protoboard &pb, const std::string &annotation); }; /// A utility function which creates and allocates a variable in a single step @@ -77,7 +77,7 @@ class pb_variable_array : private std::vector> void allocate( protoboard &pb, const size_t n, - const std::string &annotation_prefix = ""); + const std::string &annotation_prefix); void fill_with_field_elements( protoboard &pb, const std::vector &vals) const; diff --git a/libsnark/gadgetlib1/pb_variable.tcc b/libsnark/gadgetlib1/pb_variable.tcc index 15b8a0161..3bf2e810a 100644 --- a/libsnark/gadgetlib1/pb_variable.tcc +++ b/libsnark/gadgetlib1/pb_variable.tcc @@ -28,6 +28,13 @@ void pb_variable_array::allocate( const size_t n, const std::string &annotation_prefix) { + // The DEBUG variable controls whether or not the FMT macro actually + // performs string concatenation or simply returns "". Therefore, even + // though gadget code may always set an annotation, it may appear as "" + // unless DEBUG is set. + // + // TODO: control annotations via a variable such as + // LIBSNARK_ENABLE_ANNOTATIONS. #ifdef DEBUG assert(annotation_prefix != ""); #endif From c24710b2b1e854bd796c421cc735c67abf49e858 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Wed, 20 Apr 2022 15:21:26 +0100 Subject: [PATCH 02/21] disable some compiler optimization flags in debug mode --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12176bfdc..165eb9acc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,10 +133,12 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clan endif() # Default optimizations flags (to override, use -DOPT_FLAGS=...) if("${OPT_FLAGS}" STREQUAL "") - set( - OPT_FLAGS - "-ggdb3 -O2 -march=native -mtune=native" - ) + if (NOT ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")) + set( + OPT_FLAGS + "-ggdb3 -O2 -march=native -mtune=native" + ) + endif() endif() endif() From b5ef60d40729a89beb74e83f16dfe9eeb2389df7 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 14 Apr 2022 16:14:20 +0100 Subject: [PATCH 03/21] remove duplicate declaration of pb_variable util function --- libsnark/gadgetlib1/pb_variable.hpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libsnark/gadgetlib1/pb_variable.hpp b/libsnark/gadgetlib1/pb_variable.hpp index 0ba6a24e4..ef540b9b6 100644 --- a/libsnark/gadgetlib1/pb_variable.hpp +++ b/libsnark/gadgetlib1/pb_variable.hpp @@ -94,17 +94,6 @@ class pb_variable_array : private std::vector> FieldT get_field_element_from_bits(const protoboard &pb) const; }; -/// A utility function which creates and allocates a variable in a single step -/// (and can therefore be used in initalizer lists, which greatly simplifies -/// many constructors). -/// -/// TODO: Why does pb_variable not have an allocating constructor of this form, -/// even further simplifying a lot of code. Move this to an appropriate -/// constructor if there are no issues. -template -pb_variable pb_variable_allocate( - protoboard &pb, const std::string &annotation); - /* index 0 corresponds to the constant term (used in legacy code) */ #define ONE pb_variable(0) From 20fa7c3dff33fee3d7805e5a72538dafca43bcc0 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 7 Apr 2022 15:23:06 +0100 Subject: [PATCH 04/21] 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 bf6ad6722383609347d1a9be5393d801dc44df92 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 7 Apr 2022 19:05:27 +0100 Subject: [PATCH 05/21] 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 72431fce1e137d1ab1810d6da04061dfc07a9194 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 8 Apr 2022 13:55:15 +0100 Subject: [PATCH 06/21] 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 9225c16854bd9367556fe4811468c46ec5ed337d Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 11:04:49 +0100 Subject: [PATCH 07/21] 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 70de377975d4ad0a80036be0c654f9bb8c658590 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 14 Apr 2022 16:15:57 +0100 Subject: [PATCH 08/21] 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 2d0524eaae87ed65385739ac0ae6794516ae97e3 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 14 Apr 2022 16:28:03 +0100 Subject: [PATCH 09/21] 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 4f5afffd52d18461a47bc8e189f8690375c9fdca Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 21 Apr 2022 15:33:22 +0100 Subject: [PATCH 10/21] 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 577a4df4a7fd51ad899aeb477c9689d02f3b6d25 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 21 Apr 2022 17:17:55 +0100 Subject: [PATCH 11/21] 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 6b9b0b38f6a213c516f85fd05847ac3a1f10e2ad Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 21 Apr 2022 18:08:19 +0100 Subject: [PATCH 12/21] 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 fc037dae9fc06addd043afc1d059fca1d8e2ae5b Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 10:40:08 +0100 Subject: [PATCH 13/21] 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 68497abb5cc26b9c8c6d5cff5d0d56187aa4a8a3 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 14:10:09 +0100 Subject: [PATCH 14/21] 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 1a616fee16fa0d44e57762e4e332fef33ef8e6cd Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 22 Apr 2022 14:11:49 +0100 Subject: [PATCH 15/21] 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 From 3e31f5ffcb2d82274f0b31f3380c4b31b7a16892 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Mon, 25 Apr 2022 16:06:37 +0100 Subject: [PATCH 16/21] submodule: update libff [pairing_params_name] --- depends/libff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libff b/depends/libff index 5f9a4bdd9..87d8b4357 160000 --- a/depends/libff +++ b/depends/libff @@ -1 +1 @@ -Subproject commit 5f9a4bdd9bea61036b57cfe972354fc97c497457 +Subproject commit 87d8b435798f54918b355e4f47607f6a197561ff From c6f2ad4e4d7f867cf31cf4d1273a5fcea20e6504 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 4 Feb 2022 11:29:56 +0000 Subject: [PATCH 17/21] dump constraint counts from unit tests of curve and pairing check gadgets --- .../gadgetlib1/tests/test_curve_gadgets.cpp | 151 ++++++++++----- .../gadgetlib1/tests/test_pairing_checks.cpp | 178 ++++++++++++++++-- 2 files changed, 272 insertions(+), 57 deletions(-) diff --git a/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp b/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp index f77f0c627..7471dbe2d 100644 --- a/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp +++ b/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp @@ -26,12 +26,14 @@ namespace { template -void generate_and_check_proof(protoboard> &pb) +void generate_and_check_proof( + protoboard> &pb, const std::string &test_name) { // Generate and check the proof ASSERT_TRUE(pb.is_satisfied()); const r1cs_gg_ppzksnark_keypair keypair = r1cs_gg_ppzksnark_generator(pb.get_constraint_system(), true); + printf("%s: %zu constraints\n", test_name.c_str(), pb.num_constraints()); r1cs_primary_input> primary_input = pb.primary_input(); r1cs_auxiliary_input> auxiliary_input = pb.auxiliary_input(); r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_prover( @@ -72,7 +74,10 @@ template< typename VarR, typename AddGadgetT> void test_add_gadget( - const GroupT &a_val, const GroupT &b_val, const GroupT &expect_val) + const GroupT &a_val, + const GroupT &b_val, + const GroupT &expect_val, + const std::string &test_name) { ASSERT_EQ(expect_val, a_val + b_val); @@ -91,10 +96,13 @@ void test_add_gadget( const GroupT result_val = result.get_element(); ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_val, result_val); + + printf("%s: %zu constraints\n", test_name.c_str(), pb.num_constraints()); } template -void test_dbl_gadget(const GroupT &a_val, const GroupT &expect_val) +void test_dbl_gadget( + const GroupT &a_val, const GroupT &expect_val, const std::string &test_name) { ASSERT_EQ(expect_val, a_val + a_val); @@ -111,6 +119,8 @@ void test_dbl_gadget(const GroupT &a_val, const GroupT &expect_val) const GroupT result_val = result.get_element(); ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_val, result_val); + + printf("%s: %zu constraints\n", test_name.c_str(), pb.num_constraints()); } template< @@ -120,7 +130,8 @@ template< typename VarB, typename VarR, typename SelectorGadgetT> -void test_selector_gadget(GroupT a_val, GroupT b_val) +void test_selector_gadget( + GroupT a_val, GroupT b_val, const std::string &test_name) { a_val.to_affine_coordinates(); b_val.to_affine_coordinates(); @@ -171,11 +182,11 @@ void test_selector_gadget(GroupT a_val, GroupT b_val) ASSERT_EQ(b_val, one_result.get_element()); // Verify in a proof - generate_and_check_proof(pb); + generate_and_check_proof(pb, test_name); } template -void test_variable_or_identity_selector_gadget() +void test_variable_or_identity_selector_gadget(const std::string &test_name) { auto test_selector = test_selector_gadget; @@ -183,10 +194,10 @@ void test_variable_or_identity_selector_gadget() const GroupT a_val = GroupT::one() + GroupT::one(); const GroupT b_val = -GroupT::one(); - test_selector(a_val, b_val); - test_selector(GroupT::zero(), b_val); - test_selector(a_val, GroupT::zero()); - test_selector(GroupT::zero(), GroupT::zero()); + test_selector(a_val, b_val, "N_N_" + test_name); + test_selector(GroupT::zero(), b_val, "Z_N_" + test_name); + test_selector(a_val, GroupT::zero(), "N_Z_" + test_name); + test_selector(GroupT::zero(), GroupT::zero(), "Z_Z_" + test_name); } template< @@ -196,7 +207,8 @@ template< typename VarB, typename VarR, typename SelectorGadgetT> -void test_variable_and_variable_or_identity_selector_gadget() +void test_variable_and_variable_or_identity_selector_gadget( + const std::string &test_name) { auto test_selector = test_selector_gadget; @@ -204,8 +216,8 @@ void test_variable_and_variable_or_identity_selector_gadget() const GroupT a_val = GroupT::one() + GroupT::one(); const GroupT b_val = -GroupT::one(); - test_selector(a_val, b_val); - test_selector(GroupT::zero(), b_val); + test_selector(a_val, b_val, "V_V_" + test_name); + test_selector(GroupT::zero(), b_val, "N_V_" + test_name); } TEST(TestCurveGadgets, G2Checker) @@ -225,7 +237,8 @@ TEST(TestCurveGadgets, G1SelectorGadget) G1_variable, G1_variable_selector_gadget>; - test_selector(Group::one() + Group::one(), -Group::one()); + test_selector( + Group::one() + Group::one(), -Group::one(), "test_selector_g1_bw6_761"); } TEST(TestCurveGadgets, G2SelectorGadget) @@ -239,7 +252,8 @@ TEST(TestCurveGadgets, G2SelectorGadget) G2_variable, G2_variable_selector_gadget>; - test_selector(Group::one() + Group::one(), -Group::one()); + test_selector( + Group::one() + Group::one(), -Group::one(), "test_selector_g2_bw6_761"); } TEST(TestCurveGadgets, G1VarOrIdentitySelectorGadget) @@ -248,7 +262,8 @@ TEST(TestCurveGadgets, G1VarOrIdentitySelectorGadget) wpp, libff::G1, G1_variable_or_identity, - G1_variable_or_identity_selector_gadget>(); + G1_variable_or_identity_selector_gadget>( + "test_var_or_id_selector_gadget_g1_bw6_761"); } TEST(TestCurveGadgets, G2VarOrIdentitySelectorGadget) @@ -257,7 +272,8 @@ TEST(TestCurveGadgets, G2VarOrIdentitySelectorGadget) wpp, libff::G2, G2_variable_or_identity, - G2_variable_or_identity_selector_gadget>(); + G2_variable_or_identity_selector_gadget>( + "test_var_or_id_selector_gadget_g2_bw6_761"); } TEST(TestCurveGadgets, G1VarAndVarOrIdentitySelectorGadget) @@ -268,7 +284,8 @@ TEST(TestCurveGadgets, G1VarAndVarOrIdentitySelectorGadget) G1_variable_or_identity, G1_variable, G1_variable_or_identity, - G1_variable_and_variable_or_identity_selector_gadget>(); + G1_variable_and_variable_or_identity_selector_gadget>( + "test_var_and_var_or_id_selector_gasgete_g1_bw6_761"); } TEST(TestCurveGadgets, G2VarAndVarOrIdentitySelectorGadget) @@ -279,7 +296,8 @@ TEST(TestCurveGadgets, G2VarAndVarOrIdentitySelectorGadget) G2_variable_or_identity, G2_variable, G2_variable_or_identity, - G2_variable_and_variable_or_identity_selector_gadget>(); + G2_variable_and_variable_or_identity_selector_gadget>( + "test_var_and_var_or_id_selector_gasgete_g2_bw6_761"); } TEST(TestCurveGadgets, G1AddGadget) @@ -293,7 +311,8 @@ TEST(TestCurveGadgets, G1AddGadget) G1_add_gadget>( libff::Fr(13) * libff::G1::one(), libff::Fr(12) * libff::G1::one(), - libff::Fr(12 + 13) * libff::G1::one()); + libff::Fr(12 + 13) * libff::G1::one(), + "test_add_gadget_g1_bw6_761"); } TEST(TestCurveGadgets, G2AddGadget) @@ -307,7 +326,8 @@ TEST(TestCurveGadgets, G2AddGadget) G2_add_gadget>( libff::Fr(13) * libff::G2::one(), libff::Fr(12) * libff::G2::one(), - libff::Fr(12 + 13) * libff::G2::one()); + libff::Fr(12 + 13) * libff::G2::one(), + "test_add_gadget_g2_bw6_761"); } TEST(TestCurveGadgets, G1AddVarOrIdentityGadget) @@ -323,17 +343,20 @@ TEST(TestCurveGadgets, G1AddVarOrIdentityGadget) test_add_variable_or_identity( libff::Fr(13) * libff::G1::one(), libff::Fr(12) * libff::G1::one(), - libff::Fr(12 + 13) * libff::G1::one()); + libff::Fr(12 + 13) * libff::G1::one(), + "test_add_var_or_id_gadget_N_N_g1_bw6_761"); test_add_variable_or_identity( libff::Fr(0) * libff::G1::one(), libff::Fr(12) * libff::G1::one(), - libff::Fr(12) * libff::G1::one()); + libff::Fr(12) * libff::G1::one(), + "test_add_var_or_id_gadget_Z_N_g1_bw6_761"); test_add_variable_or_identity( libff::Fr(13) * libff::G1::one(), libff::Fr(0) * libff::G1::one(), - libff::Fr(13) * libff::G1::one()); + libff::Fr(13) * libff::G1::one(), + "test_add_var_or_id_gadget_N_Z_g1_bw6_761"); // Note, the 0 + 0 case is not supported. } @@ -351,17 +374,20 @@ TEST(TestCurveGadgets, G2AddVarOrIdentityGadget) test_add_variable_or_identity( libff::Fr(13) * libff::G2::one(), libff::Fr(12) * libff::G2::one(), - libff::Fr(12 + 13) * libff::G2::one()); + libff::Fr(12 + 13) * libff::G2::one(), + "test_add_var_or_id_gadget_N_N_g2_bw6_761"); test_add_variable_or_identity( libff::Fr(0) * libff::G2::one(), libff::Fr(12) * libff::G2::one(), - libff::Fr(12) * libff::G2::one()); + libff::Fr(12) * libff::G2::one(), + "test_add_var_or_id_gadget_Z_N_g2_bw6_761"); test_add_variable_or_identity( libff::Fr(13) * libff::G2::one(), libff::Fr(0) * libff::G2::one(), - libff::Fr(13) * libff::G2::one()); + libff::Fr(13) * libff::G2::one(), + "test_add_var_or_id_gadget_N_Z_g2_bw6_761"); // Note, the 0 + 0 case is not supported. } @@ -379,12 +405,14 @@ TEST(TestCurveGadgets, G1AddVarAndVarOrIdentityGadget) test_add_variable_and_variable_or_identity( libff::Fr(13) * libff::G1::one(), libff::Fr(12) * libff::G1::one(), - libff::Fr(12 + 13) * libff::G1::one()); + libff::Fr(12 + 13) * libff::G1::one(), + "test_add_var_and_var_or_id_N_g1_bw6_761"); test_add_variable_and_variable_or_identity( libff::Fr(0) * libff::G1::one(), libff::Fr(12) * libff::G1::one(), - libff::Fr(12) * libff::G1::one()); + libff::Fr(12) * libff::G1::one(), + "test_add_var_and_var_or_id_Z_g1_bw6_761"); // Note, the 0 + 0 case is not supported. } @@ -402,12 +430,14 @@ TEST(TestCurveGadgets, G2AddVarAndVarOrIdentityGadget) test_add_variable_and_variable_or_identity( libff::Fr(13) * libff::G2::one(), libff::Fr(12) * libff::G2::one(), - libff::Fr(12 + 13) * libff::G2::one()); + libff::Fr(12 + 13) * libff::G2::one(), + "test_add_var_and_var_or_id_N_g2_bw6_761"); test_add_variable_and_variable_or_identity( libff::Fr(0) * libff::G2::one(), libff::Fr(12) * libff::G2::one(), - libff::Fr(12) * libff::G2::one()); + libff::Fr(12) * libff::G2::one(), + "test_add_var_and_var_or_id_Z_g2_bw6_761"); // Note, the 0 + 0 case is not supported. } @@ -416,14 +446,16 @@ TEST(TestCurveGadgets, G1DblGadget) { test_dbl_gadget, G1_variable, G1_dbl_gadget>( libff::Fr(13) * libff::G1::one(), - libff::Fr(13 + 13) * libff::G1::one()); + libff::Fr(13 + 13) * libff::G1::one(), + "test_dbl_g1_bw6_761"); } TEST(TestCurveGadgets, G2DblGadget) { test_dbl_gadget, G2_variable, G2_dbl_gadget>( libff::Fr(13) * libff::G2::one(), - libff::Fr(13 + 13) * libff::G2::one()); + libff::Fr(13 + 13) * libff::G2::one(), + "test_dbl_g2_bw6_761"); } TEST(TestCurveGadgets, G1DblVarOrIdentityGadget) @@ -436,10 +468,13 @@ TEST(TestCurveGadgets, G1DblVarOrIdentityGadget) test_dbl_variable_or_identity( libff::Fr(13) * libff::G1::one(), - libff::Fr(13 + 13) * libff::G1::one()); + libff::Fr(13 + 13) * libff::G1::one(), + "test_dbl_var_or_id_N_g1_bw6_761"); test_dbl_variable_or_identity( - libff::G1::zero(), libff::G1::zero()); + libff::G1::zero(), + libff::G1::zero(), + "test_dbl_var_or_id_Z_g1_bw6_761"); } TEST(TestCurveGadgets, G2DblVarOrIdentityGadget) @@ -452,10 +487,13 @@ TEST(TestCurveGadgets, G2DblVarOrIdentityGadget) test_dbl_variable_or_identity( libff::Fr(13) * libff::G2::one(), - libff::Fr(13 + 13) * libff::G2::one()); + libff::Fr(13 + 13) * libff::G2::one(), + "test_dbl_var_or_id_N_g2_bw6_761"); test_dbl_variable_or_identity( - libff::G2::zero(), libff::G2::zero()); + libff::G2::zero(), + libff::G2::zero(), + "test_dbl_var_or_id_Z_g2_bw6_761"); } TEST(TestCurveGadgets, G1MulByConstScalar) @@ -644,7 +682,8 @@ template< typename scalarMulGadgetT> void test_mul_by_scalar_gadget( const libff::Fr> &base_scalar, - const libff::Fr> &scalar) + const libff::Fr> &scalar, + const std::string &test_name) { using nFr = libff::Fr>; @@ -697,7 +736,7 @@ void test_mul_by_scalar_gadget( // Check circuit satisfaction and proof generation. ASSERT_TRUE(pb.is_satisfied()); - generate_and_check_proof(pb); + generate_and_check_proof(pb, test_name); } TEST(TestCurveGadgets, MulScalarVar) @@ -716,13 +755,31 @@ TEST(TestCurveGadgets, MulScalarVar) G2_variable_or_identity, G2_mul_by_scalar_gadget>; - test_g1_mul_by_scalar_gadget(libff::Fr(13), libff::Fr::zero()); - test_g1_mul_by_scalar_gadget(libff::Fr(13), libff::Fr(127)); - test_g1_mul_by_scalar_gadget(libff::Fr(13), -libff::Fr::one()); - - test_g2_mul_by_scalar_gadget(libff::Fr(13), libff::Fr::zero()); - test_g2_mul_by_scalar_gadget(libff::Fr(13), libff::Fr(127)); - test_g2_mul_by_scalar_gadget(libff::Fr(13), -libff::Fr::one()); + test_g1_mul_by_scalar_gadget( + libff::Fr(13), + libff::Fr::zero(), + "test_mul_scalar_var_Z_g1_bw6_761"); + test_g1_mul_by_scalar_gadget( + libff::Fr(13), + libff::Fr(127), + "test_mul_scalar_var_N_g1_bw6_761"); + test_g1_mul_by_scalar_gadget( + libff::Fr(13), + -libff::Fr::one(), + "test_mul_scalar_var_minus_1_g1_bw6_761"); + + test_g2_mul_by_scalar_gadget( + libff::Fr(13), + libff::Fr::zero(), + "test_mul_scalar_var_Z_g2_bw6_761"); + test_g2_mul_by_scalar_gadget( + libff::Fr(13), + libff::Fr(127), + "test_mul_scalar_var_N_g2_bw6_761"); + test_g2_mul_by_scalar_gadget( + libff::Fr(13), + -libff::Fr::one(), + "test_mul_scalar_var_minus_1_g2_bw6_761"); } TEST(TestCurveGadgets, VarOrIdentityMulScalarVar) @@ -770,6 +827,8 @@ int main(int argc, char **argv) libff::bw6_761_pp::init_public_params(); libff::mnt4_pp::init_public_params(); libff::mnt6_pp::init_public_params(); + libff::inhibit_profiling_info = true; + libff::inhibit_profiling_counters = true; ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/libsnark/gadgetlib1/tests/test_pairing_checks.cpp b/libsnark/gadgetlib1/tests/test_pairing_checks.cpp index b127ccf30..196751b41 100644 --- a/libsnark/gadgetlib1/tests/test_pairing_checks.cpp +++ b/libsnark/gadgetlib1/tests/test_pairing_checks.cpp @@ -19,6 +19,91 @@ namespace libsnark { +/// Carry out a pairing check between elements of G1 and G2 defined over +/// other_curve, in a circuit defined over Fr. +template +bool test_check_e_equals_e_gadget( + libff::G1> l_P, + libff::G2> l_Q, + libff::G1> r_P, + libff::G2> r_Q, + libff::Fr expected_result, + const std::string &annotation_prefix) +{ + protoboard> pb; + G1_variable lhs_P(pb, FMT(annotation_prefix, " lhs_P")); + G2_variable lhs_Q(pb, FMT(annotation_prefix, " lhs_Q")); + G1_variable rhs_P(pb, FMT(annotation_prefix, " rhs_P")); + G2_variable rhs_Q(pb, FMT(annotation_prefix, " rhs_Q")); + + G1_precomputation lhs_prec_P; + precompute_G1_gadget compute_lhs_prec_P( + pb, lhs_P, lhs_prec_P, FMT(annotation_prefix, "compute_lhs_prec_P")); + G2_precomputation lhs_prec_Q; + precompute_G2_gadget compute_lhs_prec_Q( + pb, lhs_Q, lhs_prec_Q, FMT(annotation_prefix, "compute_lhs_prec_Q")); + + G1_precomputation rhs_prec_P; + precompute_G1_gadget compute_rhs_prec_P( + pb, rhs_P, rhs_prec_P, FMT(annotation_prefix, " compute_rhs_prec1_P")); + G2_precomputation rhs_prec_Q; + precompute_G2_gadget compute_rhs_prec_Q( + pb, rhs_Q, rhs_prec_Q, FMT(annotation_prefix, " compute_rhs_prec1_Q")); + + pb_variable> result; + result.allocate(pb, FMT(annotation_prefix, " result")); + + check_e_equals_e_gadget pairing_check( + pb, + lhs_prec_P, + lhs_prec_Q, + rhs_prec_P, + rhs_prec_Q, + result, + FMT(annotation_prefix, " pairing_check")); + + PROFILE_CONSTRAINTS(pb, "precompute P") + { + compute_lhs_prec_P.generate_r1cs_constraints(); + compute_rhs_prec_P.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "precompute Q") + { + compute_lhs_prec_Q.generate_r1cs_constraints(); + compute_rhs_prec_Q.generate_r1cs_constraints(); + } + PROFILE_CONSTRAINTS(pb, "Pairing check") + { + pairing_check.generate_r1cs_constraints(); + } + PRINT_CONSTRAINT_PROFILING(); + + generate_r1cs_equals_const_constraint>( + pb, result, expected_result, FMT(annotation_prefix, " result")); + + lhs_P.generate_r1cs_witness(l_P); + compute_lhs_prec_P.generate_r1cs_witness(); + lhs_Q.generate_r1cs_witness(l_Q); + compute_lhs_prec_Q.generate_r1cs_witness(); + + rhs_P.generate_r1cs_witness(r_P); + compute_rhs_prec_P.generate_r1cs_witness(); + rhs_Q.generate_r1cs_witness(r_Q); + compute_rhs_prec_Q.generate_r1cs_witness(); + + pairing_check.generate_r1cs_witness(); + + assert(pb.is_satisfied()); + printf( + "number of constraints for check_e_equals_e_gadget (Fr is " + "%s) = %zu\n", + annotation_prefix.c_str(), + pb.num_constraints()); + + bool test_success = (pb.val(result) == expected_result); + return test_success; +} + /// In this test we carry out - via a circuit defined over Fr - a pairing /// check between elements of G1 and G2 defined over other_curve template @@ -169,7 +254,7 @@ bool test_check_e_equals_eee_gadget( assert(pb.is_satisfied()); printf( "number of constraints for check_e_equals_eee_gadget (Fr is " - "%s) = %zu\n", + "%s) = %zu\n", annotation_prefix.c_str(), pb.num_constraints()); @@ -177,6 +262,59 @@ bool test_check_e_equals_eee_gadget( return test_success; } +template +void test_valid_pairing_check_e_equals_e_gadget(const std::string &pairing_name) +{ + const libff::G1> G1_base = + libff::G1>::one(); + const libff::G2> G2_base = + libff::G2>::one(); + + const libff::Fr> rhs_scalar1 = + libff::Fr>::random_element(); + const libff::Fr> rhs_scalar2 = + libff::Fr>::random_element(); + + const libff::G1> rhs_pairing_P = rhs_scalar1 * G1_base; + const libff::G2> rhs_pairing_Q = rhs_scalar2 * G2_base; + + // Set the LHS group elements such that the pairing check passes + const libff::G1> lhs_pairing_P = + (rhs_scalar1 * rhs_scalar2) * G1_base; + const libff::G2> lhs_pairing_Q = G2_base; + + // Compute pairings "outside the circuit" to check the value of the LHS + // against the value of the RHS, and see if the pairing check + // is succesfull + libff::GT> expected_pairing_lhs = + other_curve::final_exponentiation(other_curve::miller_loop( + other_curve::precompute_G1(lhs_pairing_P), + other_curve::precompute_G2(lhs_pairing_Q))); + + libff::GT> expected_pairing_rhs = + other_curve::final_exponentiation(other_curve::miller_loop( + other_curve::precompute_G1(rhs_pairing_P), + other_curve::precompute_G2(rhs_pairing_Q))); + + // Make sure that the pairing check succeeds and the gadget is tested + // with the right expected value + const bool check_result = (expected_pairing_lhs == expected_pairing_rhs); + ASSERT_TRUE(check_result); + + // Set the value of the expected value of the "output wire" + // of the pairing check gadget. + const libff::Fr expected_result = + check_result ? libff::Fr::one() : libff::Fr::zero(); + bool res = test_check_e_equals_e_gadget( + lhs_pairing_P, + lhs_pairing_Q, + rhs_pairing_P, + rhs_pairing_Q, + expected_result, + "test_check_e_equals_e_gadget_" + pairing_name); + ASSERT_TRUE(res); +} + /// Create VALID test case by instantiating points from G1 and G2 /// (over `other_curve`) that will be fed into the pairing check /// carried out inside the circuit, and so, over Fr @@ -184,7 +322,9 @@ bool test_check_e_equals_eee_gadget( /// As such, `ppT` represents the curve we use to encode the arithmetic /// circuit wire. In other words, the pairing check gadget called here /// will be instantiated from `libff::Fr`. -template void test_valid_pairing_check_e_equals_eee_gadget() +template +void test_valid_pairing_check_e_equals_eee_gadget( + const std::string &pairing_name) { const libff::G1> G1_base = libff::G1>::one(); @@ -265,7 +405,7 @@ template void test_valid_pairing_check_e_equals_eee_gadget() rhs_pairing3_P, rhs_pairing3_Q, expected_result, - " test_check_e_equals_eee_gadget"); + "test_check_e_equals_eee_gadget_" + pairing_name); // Check that the pairing check circuit returns the same result as // the one carried out "outside" the circuit (see above) @@ -279,7 +419,9 @@ template void test_valid_pairing_check_e_equals_eee_gadget() /// As such, `ppT` represents the curve we use to encode the arithmetic /// circuit wire. In other words, the pairing check gadget called here /// will be instantiated from `libff::Fr`. -template void test_invalid_pairing_check_e_equals_eee_gadget() +template +void test_invalid_pairing_check_e_equals_eee_gadget( + const std::string &pairing_name) { const libff::G1> G1_base = libff::G1>::one(); @@ -358,33 +500,45 @@ template void test_invalid_pairing_check_e_equals_eee_gadget() rhs_pairing3_P, rhs_pairing3_Q, expected_result, - " test_check_e_equals_eee_gadget"); + "test_check_e_equals_eee_gadget_" + pairing_name); // Check that the pairing check circuit returns the same result as // the one carried out "outside" the circuit (see above) ASSERT_TRUE(res); } +TEST(MainTests, TestMntValidCheckEequalsEgadget) +{ + test_valid_pairing_check_e_equals_e_gadget("mnt4"); + test_valid_pairing_check_e_equals_e_gadget("mnt6"); +} + +TEST(MainTests, TestBlsValidCheckEequalsEgadget) +{ + test_valid_pairing_check_e_equals_e_gadget("bw6_761"); +} + TEST(MainTests, TestMntValidCheckEequalsEEEgadget) { - test_valid_pairing_check_e_equals_eee_gadget(); - test_valid_pairing_check_e_equals_eee_gadget(); + test_valid_pairing_check_e_equals_eee_gadget("mnt4"); + test_valid_pairing_check_e_equals_eee_gadget("mnt6"); } TEST(MainTests, TestMntInvalidCheckEequalsEEEgadget) { - test_invalid_pairing_check_e_equals_eee_gadget(); - test_invalid_pairing_check_e_equals_eee_gadget(); + test_invalid_pairing_check_e_equals_eee_gadget("mnt4"); + test_invalid_pairing_check_e_equals_eee_gadget("mnt6"); } TEST(MainTests, TestBlsValidCheckEequalsEEEgadget) { - test_valid_pairing_check_e_equals_eee_gadget(); + test_valid_pairing_check_e_equals_eee_gadget("bw6_761"); } TEST(MainTests, TestBlsInvalidCheckEequalsEEEgadget) { - test_invalid_pairing_check_e_equals_eee_gadget(); + test_invalid_pairing_check_e_equals_eee_gadget( + "bw6_761"); } } // namespace libsnark @@ -395,6 +549,8 @@ int main(int argc, char **argv) libff::mnt6_pp::init_public_params(); libff::bw6_761_pp::init_public_params(); libff::bls12_377_pp::init_public_params(); + libff::inhibit_profiling_info = true; + libff::inhibit_profiling_counters = true; ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } From 3b0b74f2d25865bc3389f3924d59eeeaf6886303 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Mon, 25 Apr 2022 15:14:08 +0100 Subject: [PATCH 18/21] constraits_tracker class to better record and print gadget constraints --- .../constraints_tracker.cpp | 61 ++++++++++++++++ .../constraints_tracker.hpp | 72 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 libsnark/common/constraints_tracker/constraints_tracker.cpp create mode 100644 libsnark/common/constraints_tracker/constraints_tracker.hpp diff --git a/libsnark/common/constraints_tracker/constraints_tracker.cpp b/libsnark/common/constraints_tracker/constraints_tracker.cpp new file mode 100644 index 000000000..8574f0792 --- /dev/null +++ b/libsnark/common/constraints_tracker/constraints_tracker.cpp @@ -0,0 +1,61 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include "libsnark/common/constraints_tracker/constraints_tracker.hpp" + +#include +#include + +namespace libsnark +{ + +constraints_tracker::~constraints_tracker() +{ + // For now, just dump all entries to stdout + + std::cout << "====================\n" + << " CONSTRAINTS\n" + << "====================\n"; + + for (const auto &curve_it : _measurements) { + std::cout << "\nCURVE " << curve_it.first << ":\n"; + for (const auto &entry_it : curve_it.second) { + std::cout << " " << entry_it.first << ": " << entry_it.second + << "\n"; + } + } + + // Ensure everything is output before the process terminates. + std::cout.flush(); +} + +void constraints_tracker::add_measurement_for_curve( + const std::string &curve_name, + const std::string &name, + size_t num_constraints) +{ + std::map::iterator it = + _measurements.find(curve_name); + if (it == _measurements.end()) { + _measurements[curve_name] = {{name, num_constraints}}; + return; + } + +#ifndef NDEBUG + for (const auto &entry_it : it->second) { + if (entry_it.first == name) { + throw std::runtime_error( + "duplicate entry: " + name + " (curve: " + curve_name + ")"); + } + } +#endif + + it->second.emplace_back(name, num_constraints); +} + +} // namespace libsnark diff --git a/libsnark/common/constraints_tracker/constraints_tracker.hpp b/libsnark/common/constraints_tracker/constraints_tracker.hpp new file mode 100644 index 000000000..a85a9ebff --- /dev/null +++ b/libsnark/common/constraints_tracker/constraints_tracker.hpp @@ -0,0 +1,72 @@ +/** @file + ***************************************************************************** + * @author This file is part of libsnark, developed by Clearmatics Ltd + * (originally developed by SCIPR Lab) and contributors + * (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBSNARK_COMMON_CONSTRAINTS_TRACKER_HPP_ +#define LIBSNARK_COMMON_CONSTRAINTS_TRACKER_HPP_ + +#include +#include +#include + +namespace libsnark +{ + +/// Simple class to track a set of measurements (initially the number of +/// constraints required by a given gadget) during test or profiling code, and +/// present them together in a sensible format (rather than interspersed with +/// other output to stdout). +/// +/// Intended usage is in a test file, create a static global: +/// +/// static constraints_tracker constraints_tracker; +/// +/// and then later register measurements: +/// +/// TEST(TestSuite, SomeTest) +/// { +/// ... +/// constraints_tracker.add_measurement( +/// "some_gadget", num_constraints); +/// ... +/// } +/// +/// if the unit tests exits cleanly, all measurements should be printed to +/// stdout. +/// +/// In the future, this may be expanded to collect more data, or write it in +/// other formats to different places. +class constraints_tracker +{ +public: + ~constraints_tracker(); + + template + void add_measurement(const std::string &name, size_t num_constraints); + +protected: + using measurement = std::pair; + using measurements_for_curve = std::vector; + + void add_measurement_for_curve( + const std::string &curve_name, + const std::string &name, + size_t num_constraints); + + std::map _measurements; +}; + +template +void constraints_tracker::add_measurement( + const std::string &name, size_t num_constraints) +{ + add_measurement_for_curve(ppT::name, name, num_constraints); +} + +} // namespace libsnark + +#endif // LIBSNARK_COMMON_CONSTRAINTS_TRACKER_HPP_ From 03c73db68b86766d58bd41d91112b69ff33a8de3 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Mon, 25 Apr 2022 15:20:41 +0100 Subject: [PATCH 19/21] use constraint_tracker in unit tests that print constraint numbers --- .../gadgetlib1/tests/test_curve_gadgets.cpp | 50 +++++++---- libsnark/gadgetlib1/tests/test_pairing.cpp | 51 +++++------ .../gadgetlib1/tests/test_pairing_checks.cpp | 86 ++++++++----------- ...test_r1cs_gg_ppzksnark_verifier_gadget.cpp | 44 ++++------ 4 files changed, 108 insertions(+), 123 deletions(-) diff --git a/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp b/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp index 7471dbe2d..ceb85a3ea 100644 --- a/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp +++ b/libsnark/gadgetlib1/tests/test_curve_gadgets.cpp @@ -6,6 +6,7 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "libsnark/common/constraints_tracker/constraints_tracker.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/pairing_params.hpp" @@ -25,6 +26,8 @@ using npp = other_curve; namespace { +static constraints_tracker constraints; + template void generate_and_check_proof( protoboard> &pb, const std::string &test_name) @@ -33,7 +36,8 @@ void generate_and_check_proof( ASSERT_TRUE(pb.is_satisfied()); const r1cs_gg_ppzksnark_keypair keypair = r1cs_gg_ppzksnark_generator(pb.get_constraint_system(), true); - printf("%s: %zu constraints\n", test_name.c_str(), pb.num_constraints()); + + constraints.add_measurement(test_name, pb.num_constraints()); r1cs_primary_input> primary_input = pb.primary_input(); r1cs_auxiliary_input> auxiliary_input = pb.auxiliary_input(); r1cs_gg_ppzksnark_proof proof = r1cs_gg_ppzksnark_prover( @@ -50,20 +54,16 @@ void test_G2_checker_gadget(const std::string &annotation) G2_checker_gadget g_check(pb, g, "g_check"); g_check.generate_r1cs_constraints(); - printf("positive test\n"); g.generate_r1cs_witness(libff::G2>::one()); g_check.generate_r1cs_witness(); assert(pb.is_satisfied()); - printf("negative test\n"); g.generate_r1cs_witness(libff::G2>::zero()); g_check.generate_r1cs_witness(); assert(!pb.is_satisfied()); - printf( - "number of constraints for G2 checker (Fr is %s) = %zu\n", - annotation.c_str(), - pb.num_constraints()); + constraints.add_measurement( + "G2_checker_gadget - " + annotation, pb.num_constraints()); } template< @@ -97,7 +97,7 @@ void test_add_gadget( ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_val, result_val); - printf("%s: %zu constraints\n", test_name.c_str(), pb.num_constraints()); + constraints.add_measurement(test_name, pb.num_constraints()); } template @@ -120,7 +120,7 @@ void test_dbl_gadget( ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_val, result_val); - printf("%s: %zu constraints\n", test_name.c_str(), pb.num_constraints()); + constraints.add_measurement(test_name, pb.num_constraints()); } template< @@ -801,22 +801,38 @@ TEST(TestCurveGadgets, VarOrIdentityMulScalarVar) G2_variable_or_identity_mul_by_scalar_gadget>; test_g1_var_or_identity_mul_by_scalar_gadget( - libff::Fr(13), libff::Fr::zero()); + libff::Fr(13), + libff::Fr::zero(), + "G1_var_or_identity_mul_by_scalar_gadget (0*[13]_1)"); test_g1_var_or_identity_mul_by_scalar_gadget( - libff::Fr::zero(), libff::Fr(13)); + libff::Fr::zero(), + libff::Fr(13), + "G1_var_or_identity_mul_by_scalar_gadget (13*[0]_1)"); test_g1_var_or_identity_mul_by_scalar_gadget( - libff::Fr(13), libff::Fr(127)); + libff::Fr(13), + libff::Fr(127), + "G1_var_or_identity_mul_by_scalar_gadget (127*[13]_1)"); test_g1_var_or_identity_mul_by_scalar_gadget( - libff::Fr(13), -libff::Fr::one()); + libff::Fr(13), + -libff::Fr::one(), + "G1_var_or_identity_mul_by_scalar_gadget (-1*[13]_1)"); test_g2_var_or_identity_mul_by_scalar_gadget( - libff::Fr(13), libff::Fr::zero()); + libff::Fr(13), + libff::Fr::zero(), + "G2_var_or_identity_mul_by_scalar_gadget (0*[13]_2)"); test_g2_var_or_identity_mul_by_scalar_gadget( - libff::Fr::zero(), libff::Fr(13)); + libff::Fr::zero(), + libff::Fr(13), + "G2_var_or_identity_mul_by_scalar_gadget (13*[0]_2)"); test_g2_var_or_identity_mul_by_scalar_gadget( - libff::Fr(13), libff::Fr(127)); + libff::Fr(13), + libff::Fr(127), + "G2_var_or_identity_mul_by_scalar_gadget (127*[13]_2)"); test_g2_var_or_identity_mul_by_scalar_gadget( - libff::Fr(13), -libff::Fr::one()); + libff::Fr(13), + -libff::Fr::one(), + "G2_var_or_identity_mul_by_scalar_gadget (-1*[13]_2)"); } } // namespace diff --git a/libsnark/gadgetlib1/tests/test_pairing.cpp b/libsnark/gadgetlib1/tests/test_pairing.cpp index 7487dfd31..094a18222 100644 --- a/libsnark/gadgetlib1/tests/test_pairing.cpp +++ b/libsnark/gadgetlib1/tests/test_pairing.cpp @@ -6,6 +6,7 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "libsnark/common/constraints_tracker/constraints_tracker.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp" #include "libsnark/gadgetlib1/protoboard.hpp" @@ -19,6 +20,8 @@ namespace libsnark { +static constraints_tracker constraints; + template void test_G1_variable_precomp(const std::string &annotation) { @@ -47,10 +50,8 @@ void test_G1_variable_precomp(const std::string &annotation) const_precomp.PY_twist_squared->get_element(), native_precomp.PY_twist_squared); - printf( - "number of constraints for G1 precomp (Fr is %s) = %zu\n", - annotation.c_str(), - pb.num_constraints()); + constraints.add_measurement( + "G1 precomp - " + annotation, pb.num_constraints()); } template @@ -91,10 +92,8 @@ void test_G2_variable_precomp(const std::string &annotation) native_precomp.coeffs[i].gamma_X); } - printf( - "number of constraints for G2 precomp (Fr is %s) = %zu\n", - annotation.c_str(), - pb.num_constraints()); + constraints.add_measurement( + "G2 precomp - " + annotation, pb.num_constraints()); } template @@ -137,13 +136,12 @@ void test_miller_loop( Q.generate_r1cs_witness(Q_val); compute_prec_Q.generate_r1cs_witness(); miller.generate_r1cs_witness(); - ASSERT_TRUE(pb.is_satisfied()); + constraints.add_measurement( + "Miller loop + precomp - " + annotation, pb.num_constraints()); + + ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_result, result.get_element()); - printf( - "number of constraints for Miller loop (Fr is %s) = %zu\n", - annotation.c_str(), - pb.num_constraints()); } template void test_mnt_miller_loop(const std::string &annotation) @@ -244,13 +242,10 @@ void test_e_over_e_miller_loop( compute_prec_Q2.generate_r1cs_witness(); miller.generate_r1cs_witness(); - ASSERT_TRUE(pb.is_satisfied()); - - printf( - "number of constraints for e over e Miller loop (Fr is %s) = %zu\n", - annotation.c_str(), - pb.num_constraints()); + constraints.add_measurement( + "e_over_e_miller_loop + precomp - " + annotation, pb.num_constraints()); + ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_result, result.get_element()); } @@ -441,12 +436,11 @@ void test_mnt_e_times_e_over_e_miller_loop(const std::string &annotation) native_prec_P3, native_prec_Q3) .inverse()); - ASSERT_EQ(native_result, result.get_element()); - printf( - "number of constraints for e times e over e Miller loop (Fr is %s) = " - "%zu\n", - annotation.c_str(), + constraints.add_measurement( + "e_times_e_over_e_Miller_loop + precomp - " + annotation, pb.num_constraints()); + + ASSERT_EQ(native_result, result.get_element()); } template @@ -551,14 +545,11 @@ void test_e_times_e_times_e_over_e_miller_loop( compute_prec_Q4.generate_r1cs_witness(); miller.generate_r1cs_witness(); - ASSERT_TRUE(pb.is_satisfied()); - - printf( - "number of constraints for e times e times e over e Miller loop (Fr is " - "%s) = %zu\n", - annotation.c_str(), + constraints.add_measurement( + "e_times_e_times_e_over_e Miller loop + precomp - " + annotation, pb.num_constraints()); + ASSERT_TRUE(pb.is_satisfied()); ASSERT_EQ(expect_result, result.get_element()); } diff --git a/libsnark/gadgetlib1/tests/test_pairing_checks.cpp b/libsnark/gadgetlib1/tests/test_pairing_checks.cpp index 196751b41..f9a25d0f0 100644 --- a/libsnark/gadgetlib1/tests/test_pairing_checks.cpp +++ b/libsnark/gadgetlib1/tests/test_pairing_checks.cpp @@ -6,6 +6,7 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "libsnark/common/constraints_tracker/constraints_tracker.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/pairing_checks.hpp" @@ -19,6 +20,8 @@ namespace libsnark { +static constraints_tracker constraints; + /// Carry out a pairing check between elements of G1 and G2 defined over /// other_curve, in a circuit defined over Fr. template @@ -27,31 +30,30 @@ bool test_check_e_equals_e_gadget( libff::G2> l_Q, libff::G1> r_P, libff::G2> r_Q, - libff::Fr expected_result, - const std::string &annotation_prefix) + libff::Fr expected_result) { protoboard> pb; - G1_variable lhs_P(pb, FMT(annotation_prefix, " lhs_P")); - G2_variable lhs_Q(pb, FMT(annotation_prefix, " lhs_Q")); - G1_variable rhs_P(pb, FMT(annotation_prefix, " rhs_P")); - G2_variable rhs_Q(pb, FMT(annotation_prefix, " rhs_Q")); + G1_variable lhs_P(pb, "lhs_P"); + G2_variable lhs_Q(pb, "lhs_Q"); + G1_variable rhs_P(pb, "rhs_P"); + G2_variable rhs_Q(pb, "rhs_Q"); G1_precomputation lhs_prec_P; precompute_G1_gadget compute_lhs_prec_P( - pb, lhs_P, lhs_prec_P, FMT(annotation_prefix, "compute_lhs_prec_P")); + pb, lhs_P, lhs_prec_P, "compute_lhs_prec_P"); G2_precomputation lhs_prec_Q; precompute_G2_gadget compute_lhs_prec_Q( - pb, lhs_Q, lhs_prec_Q, FMT(annotation_prefix, "compute_lhs_prec_Q")); + pb, lhs_Q, lhs_prec_Q, "compute_lhs_prec_Q"); G1_precomputation rhs_prec_P; precompute_G1_gadget compute_rhs_prec_P( - pb, rhs_P, rhs_prec_P, FMT(annotation_prefix, " compute_rhs_prec1_P")); + pb, rhs_P, rhs_prec_P, "compute_rhs_prec1_P"); G2_precomputation rhs_prec_Q; precompute_G2_gadget compute_rhs_prec_Q( - pb, rhs_Q, rhs_prec_Q, FMT(annotation_prefix, " compute_rhs_prec1_Q")); + pb, rhs_Q, rhs_prec_Q, "compute_rhs_prec1_Q"); pb_variable> result; - result.allocate(pb, FMT(annotation_prefix, " result")); + result.allocate(pb, "result"); check_e_equals_e_gadget pairing_check( pb, @@ -60,7 +62,7 @@ bool test_check_e_equals_e_gadget( rhs_prec_P, rhs_prec_Q, result, - FMT(annotation_prefix, " pairing_check")); + "pairing_check"); PROFILE_CONSTRAINTS(pb, "precompute P") { @@ -79,7 +81,7 @@ bool test_check_e_equals_e_gadget( PRINT_CONSTRAINT_PROFILING(); generate_r1cs_equals_const_constraint>( - pb, result, expected_result, FMT(annotation_prefix, " result")); + pb, result, expected_result, "result"); lhs_P.generate_r1cs_witness(l_P); compute_lhs_prec_P.generate_r1cs_witness(); @@ -93,15 +95,10 @@ bool test_check_e_equals_e_gadget( pairing_check.generate_r1cs_witness(); - assert(pb.is_satisfied()); - printf( - "number of constraints for check_e_equals_e_gadget (Fr is " - "%s) = %zu\n", - annotation_prefix.c_str(), - pb.num_constraints()); + constraints.add_measurement( + "check_e_equals_e_gadget", pb.num_constraints()); - bool test_success = (pb.val(result) == expected_result); - return test_success; + return pb.is_satisfied() && (pb.val(result) == expected_result); } /// In this test we carry out - via a circuit defined over Fr - a pairing @@ -251,19 +248,14 @@ bool test_check_e_equals_eee_gadget( pairing_check.generate_r1cs_witness(); - assert(pb.is_satisfied()); - printf( - "number of constraints for check_e_equals_eee_gadget (Fr is " - "%s) = %zu\n", - annotation_prefix.c_str(), + constraints.add_measurement( + "check_e_equals_eee_gadget - " + annotation_prefix, pb.num_constraints()); - bool test_success = (pb.val(result) == expected_result); - return test_success; + return pb.is_satisfied() && (pb.val(result) == expected_result); } -template -void test_valid_pairing_check_e_equals_e_gadget(const std::string &pairing_name) +template void test_valid_pairing_check_e_equals_e_gadget() { const libff::G1> G1_base = libff::G1>::one(); @@ -310,8 +302,7 @@ void test_valid_pairing_check_e_equals_e_gadget(const std::string &pairing_name) lhs_pairing_Q, rhs_pairing_P, rhs_pairing_Q, - expected_result, - "test_check_e_equals_e_gadget_" + pairing_name); + expected_result); ASSERT_TRUE(res); } @@ -322,9 +313,7 @@ void test_valid_pairing_check_e_equals_e_gadget(const std::string &pairing_name) /// As such, `ppT` represents the curve we use to encode the arithmetic /// circuit wire. In other words, the pairing check gadget called here /// will be instantiated from `libff::Fr`. -template -void test_valid_pairing_check_e_equals_eee_gadget( - const std::string &pairing_name) +template void test_valid_pairing_check_e_equals_eee_gadget() { const libff::G1> G1_base = libff::G1>::one(); @@ -405,7 +394,7 @@ void test_valid_pairing_check_e_equals_eee_gadget( rhs_pairing3_P, rhs_pairing3_Q, expected_result, - "test_check_e_equals_eee_gadget_" + pairing_name); + "valid"); // Check that the pairing check circuit returns the same result as // the one carried out "outside" the circuit (see above) @@ -419,9 +408,7 @@ void test_valid_pairing_check_e_equals_eee_gadget( /// As such, `ppT` represents the curve we use to encode the arithmetic /// circuit wire. In other words, the pairing check gadget called here /// will be instantiated from `libff::Fr`. -template -void test_invalid_pairing_check_e_equals_eee_gadget( - const std::string &pairing_name) +template void test_invalid_pairing_check_e_equals_eee_gadget() { const libff::G1> G1_base = libff::G1>::one(); @@ -500,7 +487,7 @@ void test_invalid_pairing_check_e_equals_eee_gadget( rhs_pairing3_P, rhs_pairing3_Q, expected_result, - "test_check_e_equals_eee_gadget_" + pairing_name); + "invalid"); // Check that the pairing check circuit returns the same result as // the one carried out "outside" the circuit (see above) @@ -509,36 +496,35 @@ void test_invalid_pairing_check_e_equals_eee_gadget( TEST(MainTests, TestMntValidCheckEequalsEgadget) { - test_valid_pairing_check_e_equals_e_gadget("mnt4"); - test_valid_pairing_check_e_equals_e_gadget("mnt6"); + test_valid_pairing_check_e_equals_e_gadget(); + test_valid_pairing_check_e_equals_e_gadget(); } TEST(MainTests, TestBlsValidCheckEequalsEgadget) { - test_valid_pairing_check_e_equals_e_gadget("bw6_761"); + test_valid_pairing_check_e_equals_e_gadget(); } TEST(MainTests, TestMntValidCheckEequalsEEEgadget) { - test_valid_pairing_check_e_equals_eee_gadget("mnt4"); - test_valid_pairing_check_e_equals_eee_gadget("mnt6"); + test_valid_pairing_check_e_equals_eee_gadget(); + test_valid_pairing_check_e_equals_eee_gadget(); } TEST(MainTests, TestMntInvalidCheckEequalsEEEgadget) { - test_invalid_pairing_check_e_equals_eee_gadget("mnt4"); - test_invalid_pairing_check_e_equals_eee_gadget("mnt6"); + test_invalid_pairing_check_e_equals_eee_gadget(); + test_invalid_pairing_check_e_equals_eee_gadget(); } TEST(MainTests, TestBlsValidCheckEequalsEEEgadget) { - test_valid_pairing_check_e_equals_eee_gadget("bw6_761"); + test_valid_pairing_check_e_equals_eee_gadget(); } TEST(MainTests, TestBlsInvalidCheckEequalsEEEgadget) { - test_invalid_pairing_check_e_equals_eee_gadget( - "bw6_761"); + test_invalid_pairing_check_e_equals_eee_gadget(); } } // namespace libsnark diff --git a/libsnark/gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp b/libsnark/gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp index 211145853..f572f6c3c 100644 --- a/libsnark/gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp +++ b/libsnark/gadgetlib1/tests/test_r1cs_gg_ppzksnark_verifier_gadget.cpp @@ -6,6 +6,7 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "libsnark/common/constraints_tracker/constraints_tracker.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bw6_761_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp" #include "libsnark/gadgetlib1/gadgets/verifiers/r1cs_gg_ppzksnark_verifier_gadget.hpp" @@ -21,11 +22,11 @@ using namespace libsnark; namespace { +static constraints_tracker constraints; + /// This test generates a valid proof and checks that this valid proof /// is succesfully verified by the groth16 verifier gadget -template -void test_verifier( - const std::string &annotation_A, const std::string &annotation_B) +template void test_verifier() { using FieldT_A = libff::Fr; using FieldT_B = libff::Fr; @@ -101,17 +102,12 @@ void test_verifier( std::cout << "Negative test case" << std::endl; ASSERT_FALSE(pb.is_satisfied()); PRINT_CONSTRAINT_PROFILING(); - printf( - "number of constraints for verifier: %zu (verifier is implemented in " - "%s constraints and verifies %s proofs))\n", - pb.num_constraints(), - annotation_B.c_str(), - annotation_A.c_str()); + + constraints.add_measurement( + "r1cs_gg_ppzksnark_verifier - " + ppT_A::name, pb.num_constraints()); } -template -void test_hardcoded_verifier( - const std::string &annotation_A, const std::string &annotation_B) +template void test_hardcoded_verifier() { using FieldT_A = libff::Fr; using FieldT_B = libff::Fr; @@ -189,30 +185,26 @@ void test_hardcoded_verifier( printf("Negative test:\n"); ASSERT_FALSE(pb.is_satisfied()); PRINT_CONSTRAINT_PROFILING(); - printf( - "number of constraints for verifier: %zu (verifier is implemented in " - "%s constraints and verifies %s proofs))\n", - pb.num_constraints(), - annotation_B.c_str(), - annotation_A.c_str()); + + constraints.add_measurement( + "r1cs_gg_ppzksnark_verifier - hardcoded - " + ppT_A::name, + pb.num_constraints()); } TEST(Groth16VerifierGadgetTests, MntGroth16VerifierGadget) { - test_verifier("mnt4", "mnt6"); - test_verifier("mnt6", "mnt4"); + test_verifier(); + test_verifier(); - test_hardcoded_verifier("mnt4", "mnt6"); - test_hardcoded_verifier("mnt6", "mnt4"); + test_hardcoded_verifier(); + test_hardcoded_verifier(); } TEST(Groth16VerifierGadgetTests, BlsGroth16VerifierGadget) { - test_verifier( - "bls12-377", "bw6-761"); + test_verifier(); - test_hardcoded_verifier( - "bls12-377", "bw6-761"); + test_hardcoded_verifier(); } } // namespace From 6b21d53a0363c0441ed52f95f9f14b89d5bc9e51 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Tue, 26 Apr 2022 13:43:20 +0100 Subject: [PATCH 20/21] track constraints required by kzg10 verifier gadgets --- .../tests/test_kzg10_verifier_gadget.cpp | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp index 44ffccfa6..159368d55 100644 --- a/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp +++ b/libsnark/gadgetlib1/tests/test_kzg10_verifier_gadget.cpp @@ -6,6 +6,7 @@ * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include "libsnark/common/constraints_tracker/constraints_tracker.hpp" #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" @@ -26,6 +27,8 @@ static const size_t POLYNOMIAL_SIZE = 5; namespace { +static constraints_tracker constraints; + template void test_polynomial_commitment_verifier_gadget( const typename scheme::srs &srs, @@ -33,7 +36,8 @@ void test_polynomial_commitment_verifier_gadget( const libff::Fr> &i, const libff::Fr> &evaluation, const typename kzg10>::evaluation_witness &eval_witness, - const bool expected_result) + const bool expected_result, + const std::string &test_name) { using Field = libff::Fr; using npp = other_curve; @@ -83,6 +87,9 @@ void test_polynomial_commitment_verifier_gadget( witness_var.generate_r1cs_witness(eval_witness); verifier_gadget.generate_r1cs_witness(); + constraints.add_measurement( + "kzg10_verifier_gadget - " + test_name, pb.num_constraints()); + // Check some members of verifier_gadget { const libff::G2 i_in_G2_val = i * libff::G2::one(); @@ -135,7 +142,7 @@ template void test_kzg10_verifier_gadget() ASSERT_TRUE(scheme::verify_evaluation(i, evaluation, srs, eval_witness, C)); test_polynomial_commitment_verifier_gadget( - srs, C, i, evaluation, eval_witness, true); + srs, C, i, evaluation, eval_witness, true, "valid"); // Test some failure cases: @@ -143,16 +150,28 @@ template void test_kzg10_verifier_gadget() { // Invalid evaluation point test_polynomial_commitment_verifier_gadget( - srs, C, i + 1, evaluation, eval_witness, false); + srs, + C, + i + 1, + evaluation, + eval_witness, + false, + "invalid_eval_point"); // Invalid evaluation test_polynomial_commitment_verifier_gadget( - srs, C, i, evaluation + 1, eval_witness, false); + srs, C, i, evaluation + 1, eval_witness, false, "invalid_eval"); // Invalid evaluation witness test_polynomial_commitment_verifier_gadget( - srs, C, i, evaluation, eval_witness + eval_witness, false); + srs, + C, + i, + evaluation, + eval_witness + eval_witness, + false, + "invalid_witness"); // Invalid commitment test_polynomial_commitment_verifier_gadget( - srs, C + C, i, evaluation, eval_witness, false); + srs, C + C, i, evaluation, eval_witness, false, "invalid_commit"); } } @@ -162,7 +181,8 @@ void do_test_kzg10_batched_gamma_powers_commit_minus_eval_sum( const std::vector>> &evals, const std::vector>::commitment> &cms, const libff::G1> &r, - const bool expected_result) + const bool expected_result, + const std::string &test_name) { using Field = libff::Fr; @@ -202,6 +222,11 @@ void do_test_kzg10_batched_gamma_powers_commit_minus_eval_sum( } compute_sum.generate_r1cs_witness(); + constraints.add_measurement( + "kzg10_batched_compute_gamma_powers_commit_minus_eval_sum - " + + test_name, + pb.num_constraints()); + // Check result value if (expected_result) { @@ -249,7 +274,8 @@ void test_kzg10_batched_gamma_powers_commit_minus_eval_sum_gadget() {evals[0], evals[1], evals[2]}, {cms[0], cms[1], cms[2]}, r_3, - true); + true, + "n=3"); // 4-entry case const nG1 r_4 = nField( @@ -257,7 +283,7 @@ void test_kzg10_batched_gamma_powers_commit_minus_eval_sum_gadget() (51 * 51 * 51) * (23 - 11)) * nG1::one(); do_test_kzg10_batched_gamma_powers_commit_minus_eval_sum( - gamma, evals, cms, r_4, true); + gamma, evals, cms, r_4, true, "n=4"); } template @@ -274,7 +300,8 @@ void do_test_kzg10_batched_verifier_gadget( const std::vector>::commitment> &cm_1s, const std::vector>::commitment> &cm_2s, const libff::Fr> &r, - const bool expected_result) + const bool expected_result, + const std::string &test_name) { using Field = libff::Fr; using npp = other_curve; @@ -389,6 +416,9 @@ void do_test_kzg10_batched_verifier_gadget( verifier_gadget.generate_r1cs_witness(); + constraints.add_measurement( + "kzg10_batched_verifier_gadget - " + test_name, pb.num_constraints()); + // Check intermediate values if (expected_result) { @@ -521,7 +551,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s, cm_2s, r, - true); + true, + "valid"); // Test some failure cases: @@ -542,7 +573,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s, cm_2s, r, - false); + false, + "invalid_z1"); do_test_kzg10_batched_verifier_gadget< wppT, @@ -558,7 +590,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s, cm_2s, r, - false); + false, + "invalid_z2"); do_test_kzg10_batched_verifier_gadget< wppT, @@ -574,7 +607,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s, cm_2s, r, - false); + false, + "invalid_gamma_1"); do_test_kzg10_batched_verifier_gadget< wppT, @@ -590,7 +624,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s, cm_2s, r, - false); + false, + "invalid_gamma_2"); do_test_kzg10_batched_verifier_gadget< wppT, @@ -606,7 +641,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s_invalid, cm_2s, r, - false); + false, + "invalid_cm_1s"); do_test_kzg10_batched_verifier_gadget< wppT, @@ -622,7 +658,8 @@ template void test_kzg10_batched_verifier_gadget() cm_1s, cm_2s_invalid, r, - false); + false, + "invalid_cm_2s"); } } From 1b6312a965179f09df4b013fafcc454831a3ea75 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 28 Apr 2022 11:30:58 +0100 Subject: [PATCH 21/21] ci: dump output on test failure --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79801fd14..2fd725fe5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,4 +36,4 @@ jobs: - name: build run: cd build && make -j $(($(nproc)+1)) - name: test - run: cd build && make check -j $(($(nproc)+1)) + run: cd build && CTEST_OUTPUT_ON_FAILURE=1 make check -j $(($(nproc)+1))