diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp index 2e9442c984dc..7c0bffa7bf09 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp @@ -113,7 +113,7 @@ constexpr std::tuple HONK_RECURSION_CONSTANTS( // ======================================== // Gate count for Chonk recursive verification (Ultra with RollupIO) -inline constexpr size_t CHONK_RECURSION_GATES = 1684546; +inline constexpr size_t CHONK_RECURSION_GATES = 1684865; // ======================================== // Hypernova Recursion Constants @@ -147,7 +147,7 @@ inline constexpr size_t HIDING_KERNEL_ULTRA_OPS = 124; // ======================================== // Gate count for ECCVM recursive verifier (Ultra-arithmetized) -inline constexpr size_t ECCVM_RECURSIVE_VERIFIER_GATE_COUNT = 224139; +inline constexpr size_t ECCVM_RECURSIVE_VERIFIER_GATE_COUNT = 224458; // ======================================== // Goblin AVM Recursive Verifier Constants diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp index b433c64e0283..1a955be8bba8 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp @@ -134,12 +134,16 @@ void complete_proving_key_for_test(bb::RelationParameters& relation_paramete const FF beta = FF::random_element(); const FF gamma = FF::random_element(); const FF beta_sqr = beta * beta; + const FF beta_quartic = beta_sqr * beta_sqr; relation_parameters.gamma = gamma; relation_parameters.beta = beta; relation_parameters.beta_sqr = beta_sqr; relation_parameters.beta_cube = beta_sqr * beta; - relation_parameters.eccvm_set_permutation_delta = - gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr); + relation_parameters.beta_quartic = beta_quartic; + auto first_term_tag = beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic + relation_parameters.eccvm_set_permutation_delta = (gamma + first_term_tag) * (gamma + beta_sqr + first_term_tag) * + (gamma + beta_sqr + beta_sqr + first_term_tag) * + (gamma + beta_sqr + beta_sqr + beta_sqr + first_term_tag); relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert(); const size_t unmasked_witness_size = pk->circuit_size - NUM_DISABLED_ROWS_IN_SUMCHECK; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index e784ad8fb198..065cb9c4b3e6 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -84,17 +84,22 @@ void ECCVMProver::execute_log_derivative_commitments_round() // TODO(#583)(@zac-williamson): fix Transcript to be able to generate more than 2 challenges per round! oof. auto beta_sqr = beta * beta; + auto beta_quartic = beta_sqr * beta_sqr; relation_parameters.gamma = gamma; relation_parameters.beta = beta; relation_parameters.beta_sqr = beta_sqr; relation_parameters.beta_cube = beta_sqr * beta; + relation_parameters.beta_quartic = beta_quartic; // `eccvm_set_permutation_delta` is used in the set membership gadget in eccvm/ecc_set_relation.hpp, specifically to // constrain (pc, round, wnaf_slice) to match between the MSM table and the Precomputed table. The number of rows we // add per short scalar `mul` is slightly less in the Precomputed table as in the MSM table, so to get the // permutation argument to work out, when `precompute_select == 0`, we must implicitly _remove_ (0, 0, 0) as a tuple - // on the wNAF side. This corresponds to dividing by (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²). - relation_parameters.eccvm_set_permutation_delta = - gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr); + // on the wNAF side. This corresponds to dividing by + // (γ+t·β⁴)·(γ+β²+t·β⁴)·(γ+2β²+t·β⁴)·(γ+3β²+t·β⁴), where t = FIRST_TERM_TAG. + auto first_term_tag = beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic + relation_parameters.eccvm_set_permutation_delta = (gamma + first_term_tag) * (gamma + beta_sqr + first_term_tag) * + (gamma + beta_sqr + beta_sqr + first_term_tag) * + (gamma + beta_sqr + beta_sqr + beta_sqr + first_term_tag); relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert(); // Compute inverse polynomial for our logarithmic-derivative lookup method compute_logderivative_inverse params{ .eta = 0, @@ -31,6 +34,7 @@ bool ECCVMTraceChecker::check(Builder& builder, .public_input_delta = 0, .beta_sqr = beta_sqr, .beta_cube = beta_cube, + .beta_quartic = beta_quartic, .eccvm_set_permutation_delta = eccvm_set_permutation_delta, }; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 1294cd410902..e4a9588aa091 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -48,12 +48,16 @@ typename ECCVMVerifier_::ReductionResult ECCVMVerifier_::reduce_ auto [beta, gamma] = transcript->template get_challenges(std::array{ "beta", "gamma" }); auto beta_sqr = beta * beta; + auto beta_quartic = beta_sqr * beta_sqr; relation_parameters.gamma = gamma; relation_parameters.beta = beta; - relation_parameters.beta_sqr = beta * beta; + relation_parameters.beta_sqr = beta_sqr; relation_parameters.beta_cube = beta_sqr * beta; - relation_parameters.eccvm_set_permutation_delta = - gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr); + relation_parameters.beta_quartic = beta_quartic; + auto first_term_tag = beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic + relation_parameters.eccvm_set_permutation_delta = (gamma + first_term_tag) * (gamma + beta_sqr + first_term_tag) * + (gamma + beta_sqr + beta_sqr + first_term_tag) * + (gamma + beta_sqr + beta_sqr + beta_sqr + first_term_tag); relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert(); // Get commitment to permutation and lookup grand products diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp index 7a2c7ff36820..c0f18ac081b8 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp @@ -18,6 +18,14 @@ template class ECCVMSetRelationImpl { public: using FF = FF_; + // Domain separation tags for the three tuple families in the set relation grand product. + // Each tuple family uses a distinct tag multiplied by beta^4 to prevent cross-family collisions. + // Without these tags, tuples from different families with identical packed values would produce + // identical fingerprints, allowing cross-family substitution in the multiset equality check. + static constexpr uint64_t FIRST_TERM_TAG = 1; // (pc, round, wnaf_slice) + static constexpr uint64_t SECOND_TERM_TAG = 2; // (pc, P.x, P.y, scalar) + static constexpr uint64_t THIRD_TERM_TAG = 3; // (pc, P.x, P.y, msm_size) + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 22, // grand product construction sub-relation 3 // left-shiftable polynomial sub-relation diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp index d0d387b350f4..107c9230b673 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp @@ -80,9 +80,15 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE const auto& beta = params.beta; const auto& beta_sqr = params.beta_sqr; const auto& beta_cube = params.beta_cube; + const auto& beta_quartic = params.beta_quartic; const auto& precompute_pc = View(in.precompute_pc); const auto& precompute_select = View(in.precompute_select); + // Domain separation: each tuple family includes a distinct tag * beta^4 term to prevent cross-family collisions. + const auto first_term_tag = beta_quartic * FIRST_TERM_TAG; + const auto second_term_tag = beta_quartic * SECOND_TERM_TAG; + const auto third_term_tag = beta_quartic * THIRD_TERM_TAG; + /** * @brief First term: tuple of (pc, round, wnaf_slice), computed when slicing scalar multipliers into slices, as * part of ECCVMWnafRelation. @@ -106,7 +112,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE wnaf_slice += wnaf_slice; wnaf_slice += s1; - const auto wnaf_slice_input0 = wnaf_slice + gamma + precompute_pc * beta + precompute_round4 * beta_sqr; + const auto wnaf_slice_input0 = + wnaf_slice + gamma + precompute_pc * beta + precompute_round4 * beta_sqr + first_term_tag; numerator *= wnaf_slice_input0; // degree-1 } { @@ -117,7 +124,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE wnaf_slice += wnaf_slice; wnaf_slice += s1; - const auto wnaf_slice_input1 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 1) * beta_sqr; + const auto wnaf_slice_input1 = + wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 1) * beta_sqr + first_term_tag; numerator *= wnaf_slice_input1; // degree-2 } { @@ -128,7 +136,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE wnaf_slice += wnaf_slice; wnaf_slice += s1; - const auto wnaf_slice_input2 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 2) * beta_sqr; + const auto wnaf_slice_input2 = + wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 2) * beta_sqr + first_term_tag; numerator *= wnaf_slice_input2; // degree-3 } { @@ -138,23 +147,22 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE auto wnaf_slice = s0 + s0; wnaf_slice += wnaf_slice; wnaf_slice += s1; - const auto wnaf_slice_input3 = wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 3) * beta_sqr; + const auto wnaf_slice_input3 = + wnaf_slice + gamma + precompute_pc * beta + (precompute_round4 + 3) * beta_sqr + first_term_tag; numerator *= wnaf_slice_input3; // degree-4 } { // skew product if relevant const auto& skew = View(in.precompute_skew); const auto& precompute_point_transition = View(in.precompute_point_transition); - const auto skew_input = - precompute_point_transition * (skew + gamma + precompute_pc * beta + (precompute_round4 + 4) * beta_sqr) + - (-precompute_point_transition + 1); + const auto skew_input = precompute_point_transition * (skew + gamma + precompute_pc * beta + + (precompute_round4 + 4) * beta_sqr + first_term_tag) + + (-precompute_point_transition + 1); numerator *= skew_input; // degree-5 } { // in `EccvmProver` and `ECCVMVerifier`, we see that `eccvm_set_permutation_delta` is initially computed as - // (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²) and _then_ inverted. Therefore, `eccvm_set_permutation_delta` == 1 / (γ)·(γ - // + β²)·(γ + 2β²)·(γ - // + 3β²) + // (γ+t·β⁴)·(γ+β²+t·β⁴)·(γ+2β²+t·β⁴)·(γ+3β²+t·β⁴) (where t = FIRST_TERM_TAG) and _then_ inverted. const auto& eccvm_set_permutation_delta = params.eccvm_set_permutation_delta; // if `precompute_select == 1`, don't change the numerator. if it is 0, then to get the grand product argument // to work (as we have zero-padded the rows of the MSM table), we must multiply by the inverse of the @@ -237,7 +245,7 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE auto precompute_point_transition = View(in.precompute_point_transition); auto point_table_init_read = - (precompute_pc + table_x * beta + table_y * beta_sqr + scalar_sum_full * beta_cube); + (precompute_pc + table_x * beta + table_y * beta_sqr + scalar_sum_full * beta_cube + second_term_tag); point_table_init_read = precompute_point_transition * (point_table_init_read + gamma) + (-precompute_point_transition + 1); @@ -282,7 +290,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_numerator(const AllE // at row i + 1 we have updated `pc` to be `(pc at start of msm) + msm_count` // at row i + 1 q_msm_transtiion = 1 - auto msm_result_write = msm_pc_shift + msm_x_shift * beta + msm_y_shift * beta_sqr + msm_size * beta_cube; + auto msm_result_write = + msm_pc_shift + msm_x_shift * beta + msm_y_shift * beta_sqr + msm_size * beta_cube + third_term_tag; // msm_result_write = degree 2 msm_result_write = msm_transition_shift * (msm_result_write + gamma) + (-msm_transition_shift + 1); @@ -303,10 +312,16 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_denominator(const Al const auto& beta = params.beta; const auto& beta_sqr = params.beta_sqr; const auto& beta_cube = params.beta_cube; + const auto& beta_quartic = params.beta_quartic; const auto& msm_pc = View(in.msm_pc); const auto& msm_count = View(in.msm_count); const auto& msm_round = View(in.msm_round); + // Domain separation: must match the tags used in the numerator. + const auto first_term_tag = beta_quartic * FIRST_TERM_TAG; + const auto second_term_tag = beta_quartic * SECOND_TERM_TAG; + const auto third_term_tag = beta_quartic * THIRD_TERM_TAG; + /** * @brief First term: tuple of (pc, round, wnaf_slice), used to determine which points we extract from lookup tables * when evaluaing MSMs in ECCVMMsmRelation. @@ -318,7 +333,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_denominator(const Al const auto& msm_slice1 = View(in.msm_slice1); auto wnaf_slice_output1 = - add1 * (msm_slice1 + gamma + (msm_pc - msm_count) * beta + msm_round * beta_sqr) + (-add1 + 1); + add1 * (msm_slice1 + gamma + (msm_pc - msm_count) * beta + msm_round * beta_sqr + first_term_tag) + + (-add1 + 1); denominator *= wnaf_slice_output1; // degree-2 } { @@ -326,7 +342,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_denominator(const Al const auto& msm_slice2 = View(in.msm_slice2); auto wnaf_slice_output2 = - add2 * (msm_slice2 + gamma + (msm_pc - msm_count - 1) * beta + msm_round * beta_sqr) + (-add2 + 1); + add2 * (msm_slice2 + gamma + (msm_pc - msm_count - 1) * beta + msm_round * beta_sqr + first_term_tag) + + (-add2 + 1); denominator *= wnaf_slice_output2; // degree-4 } { @@ -334,14 +351,16 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_denominator(const Al const auto& msm_slice3 = View(in.msm_slice3); auto wnaf_slice_output3 = - add3 * (msm_slice3 + gamma + (msm_pc - msm_count - 2) * beta + msm_round * beta_sqr) + (-add3 + 1); + add3 * (msm_slice3 + gamma + (msm_pc - msm_count - 2) * beta + msm_round * beta_sqr + first_term_tag) + + (-add3 + 1); denominator *= wnaf_slice_output3; // degree-6 } { const auto& add4 = View(in.msm_add4); const auto& msm_slice4 = View(in.msm_slice4); auto wnaf_slice_output4 = - add4 * (msm_slice4 + gamma + (msm_pc - msm_count - 3) * beta + msm_round * beta_sqr) + (-add4 + 1); + add4 * (msm_slice4 + gamma + (msm_pc - msm_count - 3) * beta + msm_round * beta_sqr + first_term_tag) + + (-add4 + 1); denominator *= wnaf_slice_output4; // degree-8 } @@ -371,10 +390,10 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_denominator(const Al const auto& lookup_second = (-z2_zero + 1); FF cube_root_unity = FF(bb::fq::cube_root_of_unity()); - auto transcript_input1 = - transcript_pc + transcript_Px * beta + transcript_Py * beta_sqr + z1 * beta_cube; // degree = 1 + auto transcript_input1 = transcript_pc + transcript_Px * beta + transcript_Py * beta_sqr + z1 * beta_cube + + second_term_tag; // degree = 1 auto transcript_input2 = (transcript_pc - 1) + transcript_Px * cube_root_unity * beta - - transcript_Py * beta_sqr + z2 * beta_cube; // degree = 2 + transcript_Py * beta_sqr + z2 * beta_cube + second_term_tag; // degree = 2 // The following diagram expresses a fingerprint of part of the tuple. It does not include `transcript_pc` and // has not weighted the X and Y with beta and beta_sqr respectively. The point is nonetheless to show exactly @@ -432,8 +451,8 @@ Accumulator ECCVMSetRelationImpl::compute_grand_product_denominator(const Al auto full_msm_count = transcript_msm_count + transcript_mul * ((-z1_zero + 1) + (-z2_zero + 1)) * (-base_infinity + 1); // msm_result_read = degree 2 - auto msm_result_read = - transcript_pc_shift + transcript_msm_x * beta + transcript_msm_y * beta_sqr + full_msm_count * beta_cube; + auto msm_result_read = transcript_pc_shift + transcript_msm_x * beta + transcript_msm_y * beta_sqr + + full_msm_count * beta_cube + third_term_tag; msm_result_read = transcript_msm_transition * (msm_result_read + gamma) + (-transcript_msm_transition + 1); denominator *= msm_result_read; // degree-20 } diff --git a/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp b/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp index c68f7e4889f9..da086e3d0fb8 100644 --- a/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/relation_parameters.hpp @@ -30,6 +30,7 @@ template struct RelationParameters { T public_input_delta{ 0 }; // Permutation T beta_sqr{ 0 }; T beta_cube{ 0 }; + T beta_quartic{ 0 }; // Compute eta powers from a single eta challenge void compute_eta_powers(const T& eta_challenge) @@ -49,7 +50,8 @@ template struct RelationParameters { // constrain (pc, round, wnaf_slice) to match between the MSM table and the Precomputed table. The number of rows we // add per short scalar `mul` is slightly less in the Precomputed table as in the MSM table, so to get the // permutation argument to work out, when `precompute_select == 0`, we must implicitly _remove_ (0, 0, 0) as a tuple - // on the wNAF side. This corresponds to dividing by (γ)·(γ + β²)·(γ + 2β²)·(γ + 3β²). + // on the wNAF side. This corresponds to dividing by (γ+t·β⁴)·(γ+β²+t·β⁴)·(γ+2β²+t·β⁴)·(γ+3β²+t·β⁴), where + // t = FIRST_TERM_TAG (the domain separation tag for WNAF slice tuples). // // We can remove this by modifying the relation, but this would increase the complexity. T eccvm_set_permutation_delta = T(0); @@ -63,7 +65,7 @@ template struct RelationParameters { { T(0), T(0), T(0), T(0), T(0) }, { T(0), T(0), T(0), T(0), T(0) }, { T(0), T(0), T(0), T(0), T(0) } } }; - + // only used for testing static RelationParameters get_random() { RelationParameters result; @@ -71,9 +73,11 @@ template struct RelationParameters { result.compute_beta_powers(T::random_element()); // beta, beta_sqr = beta², beta_cube = beta³ result.gamma = T::random_element(); result.public_input_delta = T::random_element(); - result.eccvm_set_permutation_delta = result.gamma * (result.gamma + result.beta_sqr) * - (result.gamma + result.beta_sqr + result.beta_sqr) * - (result.gamma + result.beta_sqr + result.beta_sqr + result.beta_sqr); + auto first_term_tag = result.beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic + result.eccvm_set_permutation_delta = + (result.gamma + first_term_tag) * (result.gamma + result.beta_sqr + first_term_tag) * + (result.gamma + result.beta_sqr + result.beta_sqr + first_term_tag) * + (result.gamma + result.beta_sqr + result.beta_sqr + result.beta_sqr + first_term_tag); result.accumulated_result = { T::random_element(), T::random_element(), T::random_element(), T::random_element() };