From ead1afc8417dc2c440ca4746f7fecd1c068005fd Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 17 Feb 2025 17:03:18 +0000 Subject: [PATCH 01/20] small refactor of translation evals logic in eccvm --- .../src/barretenberg/eccvm/eccvm_prover.cpp | 85 +++++++++---------- .../src/barretenberg/eccvm/eccvm_prover.hpp | 6 ++ .../goblin/translation_evaluations.hpp | 4 +- .../translator_recursive_verifier.cpp | 5 +- .../translator_recursive_verifier.test.cpp | 4 +- .../translator_vm/translator.test.cpp | 2 +- .../translator_vm/translator_prover.cpp | 1 + .../translator_vm/translator_verifier.cpp | 4 +- 8 files changed, 57 insertions(+), 54 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index b70b2383a7c..6888fd3f264 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -157,50 +157,8 @@ void ECCVMProver::execute_pcs_rounds() sumcheck_output.round_univariates, sumcheck_output.round_univariate_evaluations); - // Get the challenge at which we evaluate all transcript polynomials as univariates - evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); - - // Evaluate the transcript polynomials at the challenge - translation_evaluations.op = key->polynomials.transcript_op.evaluate(evaluation_challenge_x); - translation_evaluations.Px = key->polynomials.transcript_Px.evaluate(evaluation_challenge_x); - translation_evaluations.Py = key->polynomials.transcript_Py.evaluate(evaluation_challenge_x); - translation_evaluations.z1 = key->polynomials.transcript_z1.evaluate(evaluation_challenge_x); - translation_evaluations.z2 = key->polynomials.transcript_z2.evaluate(evaluation_challenge_x); - - // Add the univariate evaluations to the transcript so the verifier can reconstruct the batched evaluation - transcript->send_to_verifier("Translation:op", translation_evaluations.op); - transcript->send_to_verifier("Translation:Px", translation_evaluations.Px); - transcript->send_to_verifier("Translation:Py", translation_evaluations.Py); - transcript->send_to_verifier("Translation:z1", translation_evaluations.z1); - transcript->send_to_verifier("Translation:z2", translation_evaluations.z2); - - // Get another challenge for batching the univariates and evaluations - FF ipa_batching_challenge = transcript->template get_challenge("Translation:ipa_batching_challenge"); - - // Collect the polynomials and evaluations to be batched - RefArray univariate_polynomials{ key->polynomials.transcript_op, - key->polynomials.transcript_Px, - key->polynomials.transcript_Py, - key->polynomials.transcript_z1, - key->polynomials.transcript_z2 }; - std::array univariate_evaluations{ translation_evaluations.op, - translation_evaluations.Px, - translation_evaluations.Py, - translation_evaluations.z1, - translation_evaluations.z2 }; + const OpeningClaim translation_opening_claim = ECCVMProver::reduce_translation_evaluations(); - // Construct the batched polynomial and batched evaluation to produce the batched opening claim - Polynomial batched_univariate{ key->circuit_size }; - FF batched_evaluation{ 0 }; - FF batching_scalar = FF(1); - for (auto [polynomial, eval] : zip_view(univariate_polynomials, univariate_evaluations)) { - batched_univariate.add_scaled(polynomial, batching_scalar); - batched_evaluation += eval * batching_scalar; - batching_scalar *= ipa_batching_challenge; - } - - const OpeningClaim translation_opening_claim = { .polynomial = batched_univariate, - .opening_pair = { evaluation_challenge_x, batched_evaluation } }; const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -209,9 +167,6 @@ void ECCVMProver::execute_pcs_rounds() // Compute the opening proof for the batched opening claim with the univariate PCS PCS::compute_opening_proof(key->commitment_key, batch_opening_claim, ipa_transcript); - - // Produce another challenge passed as input to the translator verifier - translation_batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); } ECCVMProof ECCVMProver::export_proof() @@ -237,4 +192,42 @@ ECCVMProof ECCVMProver::construct_proof() return export_proof(); } + +ProverOpeningClaim ECCVMProver::reduce_translation_evaluations() +{ + // Collect the polynomials and evaluations to be batched + RefArray univariate_polynomials{ key->polynomials.transcript_op, + key->polynomials.transcript_Px, + key->polynomials.transcript_Py, + key->polynomials.transcript_z1, + key->polynomials.transcript_z2 }; + + // Get the challenge at which we evaluate all transcript polynomials as univariates + evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); + + // Evaluate the transcript polynomials as univariates and add their evaluations at x to the transcript + for (auto [eval, poly, label] : + zip_view(translation_evaluations.get_all(), univariate_polynomials, translation_labels)) { + *eval = poly.evaluate(evaluation_challenge_x); + transcript->template send_to_verifier(label, *eval); + } + + // Get another challenge to batch the evaluations of the transcript polynomials + translation_batching_challenge_v = transcript->template get_challenge("Translation:ipa_batching_challenge"); + + // Construct the batched polynomial and batched evaluation to produce the batched opening claim + Polynomial batched_univariate{ key->circuit_size }; + FF batched_evaluation{ 0 }; + FF batching_scalar = FF(1); + for (auto [polynomial, eval] : zip_view(univariate_polynomials, translation_evaluations.get_all())) { + batched_univariate.add_scaled(polynomial, batching_scalar); + batched_evaluation += *eval * batching_scalar; + batching_scalar *= translation_batching_challenge_v; + } + + OpeningClaim translation_opening_claim = { .polynomial = batched_univariate, + .opening_pair = { evaluation_challenge_x, batched_evaluation } }; + + return translation_opening_claim; +} } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index e14a2b2ef02..26f5860dd18 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -28,6 +28,7 @@ class ECCVMProver { using CircuitBuilder = typename Flavor::CircuitBuilder; using ZKData = ZKSumcheckData; using SmallSubgroupIPA = SmallSubgroupIPAProver; + using OpeningClaim = ProverOpeningClaim; explicit ECCVMProver(CircuitBuilder& builder, const bool fixed_size = false, @@ -44,6 +45,7 @@ class ECCVMProver { ECCVMProof export_proof(); ECCVMProof construct_proof(); + OpeningClaim reduce_translation_evaluations(); std::shared_ptr transcript; std::shared_ptr ipa_transcript; @@ -52,6 +54,10 @@ class ECCVMProver { TranslationEvaluations translation_evaluations; + static constexpr std::array translation_labels = { + "Translation:op", "Translation:Px", "Translation:Py", "Translation:z1", "Translation:z2" + }; + std::vector public_inputs; bb::RelationParameters relation_parameters; diff --git a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp index 24196ae69dc..78ac883b378 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp @@ -14,6 +14,8 @@ template struct TranslationEvaluations_ { static constexpr uint32_t NUM_EVALUATIONS = 5; static size_t size() { return field_conversion::calc_num_bn254_frs() * NUM_EVALUATIONS; } + std::array get_all() { return { &op, &Px, &Py, &z1, &z2 }; } + MSGPACK_FIELDS(op, Px, Py, z1, z2); }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index b0a13bb542e..c608495a0aa 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -71,8 +71,6 @@ std::array TranslatorRecursiveVerifier_ stdlib_proof = bb::convert_native_proof_to_stdlib(builder, proof); transcript->load_proof(stdlib_proof); - batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); - VerifierCommitments commitments{ key }; CommitmentLabels commitment_labels; @@ -81,6 +79,9 @@ std::array TranslatorRecursiveVerifier_template receive_from_prover("Translation:batching_challenge"); + // Is this sound? evaluation_input_x = transcript->template receive_from_prover("evaluation_input_x"); const BF accumulated_result = transcript->template receive_from_prover("accumulated_result"); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index abe273f388c..a2c5125c542 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -67,7 +67,7 @@ template class TranslatorRecursiveTests : public ::te // normally this would be the eccvm proof auto fake_inital_proof = prover_transcript->export_proof(); InnerBF translation_batching_challenge = - prover_transcript->template get_challenge("Translation:batching_challenge"); + prover_transcript->template receive_from_prover("Translation:batching_challenge"); InnerBF translation_evaluation_challenge = InnerBF::random_element(); auto circuit_builder = InnerBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); @@ -199,4 +199,4 @@ TYPED_TEST(TranslatorRecursiveTests, IndependentVKHash) GTEST_SKIP() << "Not built for this parameter"; } }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp index ed0503a82e8..0beb7176ff8 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp @@ -47,7 +47,7 @@ TEST_F(TranslatorTests, Basic) auto prover_transcript = std::make_shared(); prover_transcript->send_to_verifier("init", Fq::random_element()); prover_transcript->export_proof(); - Fq translation_batching_challenge = prover_transcript->template get_challenge("Translation:batching_challenge"); + Fq translation_batching_challenge = Fq::random_element(); Fq translation_evaluation_challenge = Fq::random_element(); auto circuit_builder = CircuitBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index ea21bc68fd9..d6673cef1f7 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -35,6 +35,7 @@ void TranslatorProver::execute_preamble_round() uint256_t(key->proving_key->polynomials.accumulators_binary_limbs_2[1]) * SHIFTx2 + uint256_t(key->proving_key->polynomials.accumulators_binary_limbs_3[1]) * SHIFTx3); transcript->send_to_verifier("circuit_size", circuit_size); + transcript->send_to_verifier("Translation:batching_challenge", key->batching_challenge_v); transcript->send_to_verifier("evaluation_input_x", key->evaluation_input_x); transcript->send_to_verifier("accumulated_result", accumulated_result); } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index fbc029c55b0..077efb423a3 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -55,8 +55,6 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) using ClaimBatcher = ClaimBatcher_; using ClaimBatch = ClaimBatcher::Batch; - batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); - // Load the proof produced by the translator prover transcript->load_proof(proof); @@ -64,6 +62,8 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) Flavor::CommitmentLabels commitment_labels; const auto circuit_size = transcript->template receive_from_prover("circuit_size"); + + batching_challenge_v = transcript->template receive_from_prover("Translation:batching_challenge"); evaluation_input_x = transcript->template receive_from_prover("evaluation_input_x"); const BF accumulated_result = transcript->template receive_from_prover("accumulated_result"); From d9d9a1f1b5021ef2b5ee515631eb33b91a182d97 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 18 Feb 2025 11:23:06 +0000 Subject: [PATCH 02/20] + ECCVMTranslation Class; extended functionality in SmallSubgroupIPA --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 150 +++++++++++++++++- .../eccvm/eccvm_translation_data.hpp | 90 +++++++++++ 2 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 791bb6a601f..1f1e6efca5f 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -2,6 +2,7 @@ #include "barretenberg/constants.hpp" #include "barretenberg/ecc/curves/bn254/bn254.hpp" +#include "barretenberg/eccvm/eccvm_translation_data.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" @@ -168,6 +169,52 @@ template class SmallSubgroupIPAProver { } } + // A constructor to achieve ZK in TranslationEvaluations + SmallSubgroupIPAProver(TranslationData& translation_data, + const FF evaluation_challenge_x, + const FF batching_challenge_v, + const FF claimed_ipa_eval, + std::shared_ptr transcript, + std::shared_ptr& commitment_key) + : interpolation_domain(translation_data.interpolation_domain) // need to initialize + , concatenated_polynomial(std::move(translation_data.concatenated_masking_term)) // need to create + , libra_concatenated_lagrange_form( + std::move(translation_data.concatenated_masking_term_lagrange)) // same as above + , challenge_polynomial(SUBGROUP_SIZE) // will have a different form + , challenge_polynomial_lagrange(SUBGROUP_SIZE) + , big_sum_polynomial_unmasked(SUBGROUP_SIZE) + , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking + , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) + , batched_quotient(QUOTIENT_LENGTH) + + { + // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has + // polynomials that may exceed the circuit size. + if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { + commitment_key = std::make_shared(SUBGROUP_SIZE + 3); + } + + // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients + compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); + + // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it + compute_big_sum_polynomial(); + + // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 + transcript->template send_to_verifier("Translation:big_sum_commitment", + commitment_key->commit(big_sum_polynomial)); + + // Compute C(X) + compute_batched_polynomial(claimed_ipa_eval); + + // Compute Q(X) + compute_batched_quotient(); + + // Send commitment [Q] to the verifier + transcript->template send_to_verifier("Translation:quotient_commitment", + commitment_key->commit(batched_quotient)); + } + // Getter to pass the witnesses to ShpleminiProver. Big sum polynomial is evaluated at 2 points (and is small) std::array, NUM_LIBRA_EVALUATIONS> get_witness_polynomials() const { @@ -230,6 +277,30 @@ template class SmallSubgroupIPAProver { } } + void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v) + { + + std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); + coeffs_lagrange_basis[0] = FF{ 1 }; + + FF v_power{ 1 }; + + for (size_t v_exponent = 0; v_exponent < 5; v_exponent++) { + // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH + const size_t poly_to_concatenate_start = 1 + MASKING_OFFSET * v_exponent; + coeffs_lagrange_basis[poly_to_concatenate_start] = v_power; + for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + MASKING_OFFSET; idx++) { + // Recursively compute the powers of the challenge + coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; + } + v_power *= batching_challenge_v; + } + + challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); + + // Compute monomial coefficients + challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); + } /** * @brief Computes the big sum polynomial A(X) * @@ -505,6 +576,62 @@ template class SmallSubgroupIPAVerifier { }; } + static bool check_eccvm_evaluations_consistency(const std::array& libra_evaluations, + const FF& evaluation_challenge, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v, + const FF& inner_product_eval_claim) + { + + // Compute the evaluation of the vanishing polynomia Z_H(X) at X = gemini_evaluation_challenge + const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + bool evaluation_challenge_in_small_subgroup = false; + if constexpr (Curve::is_stdlib_type) { + evaluation_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); + } else { + evaluation_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); + } + // The probability of this event is negligible but it has to be processed correctly + if (evaluation_challenge_in_small_subgroup) { + throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); + } + // Construct the challenge polynomial from the sumcheck challenge, the verifier has to evaluate it on its own + const std::vector challenge_polynomial_lagrange = + compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); + + // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small + // subgroup + auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( + challenge_polynomial_lagrange, evaluation_challenge, vanishing_poly_eval); + + const FF& concatenated_at_r = libra_evaluations[0]; + const FF& big_sum_shifted_eval = libra_evaluations[1]; + const FF& big_sum_eval = libra_evaluations[2]; + const FF& quotient_eval = libra_evaluations[3]; + + // Compute the evaluation of + // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) + FF diff = lagrange_first * big_sum_eval; + diff += (evaluation_challenge - Curve::subgroup_generator_inverse) * + (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); + diff += lagrange_last * (big_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; + + if constexpr (Curve::is_stdlib_type) { + if constexpr (std::is_same_v>) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) + diff.self_reduce(); + } + diff.assert_equal(FF(0)); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + return (diff.get_value() == FF(0).get_value()); + } else { + return (diff == FF(0)); + }; + } + /** * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose @@ -534,6 +661,27 @@ template class SmallSubgroupIPAVerifier { return challenge_polynomial_lagrange; } + static std::vector compute_eccvm_challenge_polynomial(const FF& evaluation_challenge_x, + const FF& batching_challenge_v) + { + std::vector challenge_polynomial_lagrange(SUBGROUP_SIZE); + + challenge_polynomial_lagrange[0] = FF{ 1 }; + + // Populate the vector with the powers of the challenges + FF v_power{ 1 }; + for (size_t v_exponent = 0; v_exponent < MASKING_OFFSET; v_exponent++) { + size_t current_idx = 1 + MASKING_OFFSET * v_exponent; // Compute the current index into the vector + challenge_polynomial_lagrange[current_idx] = v_power; + for (size_t idx = current_idx + 1; idx < current_idx + MASKING_OFFSET; idx++) { + // Recursively compute the powers of the challenge up to the length of libra univariates + challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * evaluation_challenge_x; + } + v_power *= batching_challenge_v; + } + return challenge_polynomial_lagrange; + } + /** * @brief Efficient batch evaluation of the challenge polynomial, Lagrange first, and Lagrange last * @@ -580,4 +728,4 @@ template class SmallSubgroupIPAVerifier { return result; } }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp new file mode 100644 index 00000000000..39e617f4021 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp @@ -0,0 +1,90 @@ +#pragma once +#include "barretenberg/eccvm/eccvm_flavor.hpp" +#include "barretenberg/goblin/translation_evaluations.hpp" +#include "barretenberg/transcript/transcript.hpp" + +namespace bb { + +// We won't compile this class with Standard, but we will like want to compile it (at least for testing) +// with a flavor that uses the curve Grumpkin, or a flavor that does/does not have zk, etc. +class TranslationData { + public: + using Flavor = ECCVMFlavor; + using FF = typename Flavor::FF; + using BF = typename Flavor::BF; + using Commitment = typename Flavor::Commitment; + using PCS = typename Flavor::PCS; + using CommitmentKey = typename Flavor::CommitmentKey; + using Polynomial = typename Flavor::Polynomial; + using Transcript = typename Flavor::Transcript; + using TranslationEvaluations = bb::TranslationEvaluations_; + static constexpr size_t SUBGROUP_SIZE = Flavor::Curve::SUBGROUP_SIZE; + static constexpr size_t NUM_TRANSCRIPT_POLYNOMIALS = 5; + + Polynomial concatenated_masking_term; + Polynomial concatenated_masking_term_lagrange; + FF constant_term; + + std::array interpolation_domain; + + TranslationData(RefArray transcript_polynomials, + const std::shared_ptr& transcript, + const std::shared_ptr& commitment_key) + : concatenated_masking_term(SUBGROUP_SIZE + 2) + , concatenated_masking_term_lagrange(SUBGROUP_SIZE) + , constant_term(FF::random_element()) + { + // Create interpolation domain + interpolation_domain[0] = Flavor::Curve::subgroup_generator; + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + interpolation_domain[idx] = interpolation_domain[idx - 1] * interpolation_domain[0]; + } + + // Let m_0,..., m_4 be the vectors of last 4 coeffs in each transcript poly, we compute the concatenation + // (constant_term || m_0 || ... || m_4) in Lagrange and monomial basis and mask the latter. + compute_concatenated_polynomials(transcript_polynomials); + + // Commit to the concatenated masking term + transcript->template send_to_verifier("Translation:masking_term_commitment", + commitment_key->commit(concatenated_masking_term)); + }; + + void compute_concatenated_polynomials(RefArray transcript_polynomials) + { + const size_t circuit_size = transcript_polynomials[0].size(); + + std::array coeffs_lagrange_subgroup; + coeffs_lagrange_subgroup[0] = constant_term; + + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + coeffs_lagrange_subgroup[idx] = FF{ 0 }; + } + + // Extract the Lagrange coefficients of the concatenated masking term from the transcript polynomials + for (size_t poly_idx = 0; poly_idx < NUM_TRANSCRIPT_POLYNOMIALS; poly_idx++) { + for (size_t idx = 0; idx < MASKING_OFFSET; idx++) { + size_t idx_to_populate = 1 + poly_idx * MASKING_OFFSET + idx; + coeffs_lagrange_subgroup[idx_to_populate] = + transcript_polynomials[poly_idx].at(circuit_size - 1 - MASKING_OFFSET + idx); + } + } + concatenated_masking_term_lagrange = Polynomial(coeffs_lagrange_subgroup); + + // Generate the masking term + bb::Univariate masking_scalars = bb::Univariate::get_random(); + + // Compute monomial coefficients of the concatenated polynomial + Polynomial concatenated_monomial_form_unmasked(interpolation_domain, coeffs_lagrange_subgroup, SUBGROUP_SIZE); + + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + concatenated_masking_term.at(idx) = concatenated_monomial_form_unmasked.at(idx); + } + + // Mask the polynomial in monomial form + for (size_t idx = 0; idx < masking_scalars.size(); idx++) { + concatenated_masking_term.at(idx) -= masking_scalars.value_at(idx); + concatenated_masking_term.at(SUBGROUP_SIZE + idx) += masking_scalars.value_at(idx); + } + } +}; +} // namespace bb From 55040062f6e697b2c42a1ccfc6baaa65686b63dd Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 18 Feb 2025 12:29:19 +0000 Subject: [PATCH 03/20] test added --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 40 ++++++++++- .../small_subgroup_ipa.test.cpp | 66 ++++++++++++++++++- .../eccvm/eccvm_translation_data.hpp | 7 +- 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 1f1e6efca5f..ed1cf5313c5 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -170,7 +170,7 @@ template class SmallSubgroupIPAProver { } // A constructor to achieve ZK in TranslationEvaluations - SmallSubgroupIPAProver(TranslationData& translation_data, + SmallSubgroupIPAProver(TranslationData& translation_data, const FF evaluation_challenge_x, const FF batching_challenge_v, const FF claimed_ipa_eval, @@ -477,6 +477,44 @@ template class SmallSubgroupIPAProver { claimed_inner_product += zk_sumcheck_data.constant_term; return claimed_inner_product; } + /** + * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck + * challenges. + * + * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates + * @param multivariate_challenge Sumcheck challenge + * @param log_circuit_size + */ + static FF compute_claimed_inner_product(TranslationData& translation_data, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v) + { + FF claimed_inner_product{ 0 }; + + std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); + coeffs_lagrange_basis[0] = FF{ 1 }; + + FF v_power{ 1 }; + + for (size_t v_exponent = 0; v_exponent < 5; v_exponent++) { + // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH + const size_t poly_to_concatenate_start = 1 + MASKING_OFFSET * v_exponent; + coeffs_lagrange_basis[poly_to_concatenate_start] = v_power; + for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + MASKING_OFFSET; idx++) { + // Recursively compute the powers of the challenge + coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; + } + v_power *= batching_challenge_v; + } + + Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); + + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + claimed_inner_product += + translation_data.concatenated_masking_term_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); + } + return claimed_inner_product; + } }; /** diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index cd58a2c854a..9db8dd08665 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -245,4 +245,68 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) EXPECT_FALSE(consistency_checked); } -} // namespace bb \ No newline at end of file +// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the +// verifier. +TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) +{ + + if constexpr (std::is_same_v) { + GTEST_SKIP(); + } else { + using Curve = typename TypeParam::Curve; + using FF = typename Curve::ScalarField; + using Verifier = SmallSubgroupIPAVerifier; + using Prover = SmallSubgroupIPAProver; + using CK = typename TypeParam::CommitmentKey; + + auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + + // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. + static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); + std::shared_ptr ck = + create_commitment_key(std::max(this->circuit_size, 1ULL << (log_subgroup_size + 1))); + + // Generate transcript polynomials + std::vector> transcript_polynomials; + + for (size_t idx = 0; idx < 5; idx++) { + transcript_polynomials.push_back(Polynomial::random(this->circuit_size)); + } + + TranslationData translation_data( + RefVector(transcript_polynomials), prover_transcript, ck); + + const FF evaluation_challenge_x = FF::random_element(); + const FF batching_challenge_v = FF::random_element(); + + const FF claimed_inner_product = + Prover::compute_claimed_inner_product(translation_data, evaluation_challenge_x, batching_challenge_v); + + Prover small_subgroup_ipa_prover(translation_data, + evaluation_challenge_x, + batching_challenge_v, + claimed_inner_product, + prover_transcript, + ck); + + const std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = + small_subgroup_ipa_prover.get_witness_polynomials(); + + std::array libra_evaluations = { + witness_polynomials[0].evaluate(this->evaluation_challenge), + witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), + witness_polynomials[2].evaluate(this->evaluation_challenge), + witness_polynomials[3].evaluate(this->evaluation_challenge) + }; + + bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(libra_evaluations, + this->evaluation_challenge, + evaluation_challenge_x, + batching_challenge_v, + claimed_inner_product); + + EXPECT_TRUE(consistency_checked); + } +} + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp index 39e617f4021..5b1297d148b 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp @@ -7,7 +7,7 @@ namespace bb { // We won't compile this class with Standard, but we will like want to compile it (at least for testing) // with a flavor that uses the curve Grumpkin, or a flavor that does/does not have zk, etc. -class TranslationData { +template class TranslationData { public: using Flavor = ECCVMFlavor; using FF = typename Flavor::FF; @@ -16,7 +16,6 @@ class TranslationData { using PCS = typename Flavor::PCS; using CommitmentKey = typename Flavor::CommitmentKey; using Polynomial = typename Flavor::Polynomial; - using Transcript = typename Flavor::Transcript; using TranslationEvaluations = bb::TranslationEvaluations_; static constexpr size_t SUBGROUP_SIZE = Flavor::Curve::SUBGROUP_SIZE; static constexpr size_t NUM_TRANSCRIPT_POLYNOMIALS = 5; @@ -27,7 +26,7 @@ class TranslationData { std::array interpolation_domain; - TranslationData(RefArray transcript_polynomials, + TranslationData(const RefVector& transcript_polynomials, const std::shared_ptr& transcript, const std::shared_ptr& commitment_key) : concatenated_masking_term(SUBGROUP_SIZE + 2) @@ -49,7 +48,7 @@ class TranslationData { commitment_key->commit(concatenated_masking_term)); }; - void compute_concatenated_polynomials(RefArray transcript_polynomials) + void compute_concatenated_polynomials(const RefVector& transcript_polynomials) { const size_t circuit_size = transcript_polynomials[0].size(); From acc8a51f86094993dcb0dc187c17e4dbcc7911ac Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 18 Feb 2025 16:24:59 +0000 Subject: [PATCH 04/20] test passes --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 95 +++++++++++++------ .../small_subgroup_ipa.test.cpp | 4 +- .../eccvm/eccvm_translation_data.hpp | 9 +- 3 files changed, 72 insertions(+), 36 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index ed1cf5313c5..1e4f147d85c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -124,7 +124,7 @@ template class SmallSubgroupIPAProver { SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, const FF claimed_ipa_eval, - std::shared_ptr transcript, + std::shared_ptr& transcript, std::shared_ptr& commitment_key) : interpolation_domain(zk_sumcheck_data.interpolation_domain) , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) @@ -174,7 +174,7 @@ template class SmallSubgroupIPAProver { const FF evaluation_challenge_x, const FF batching_challenge_v, const FF claimed_ipa_eval, - std::shared_ptr transcript, + std::shared_ptr& transcript, std::shared_ptr& commitment_key) : interpolation_domain(translation_data.interpolation_domain) // need to initialize , concatenated_polynomial(std::move(translation_data.concatenated_masking_term)) // need to create @@ -276,25 +276,20 @@ template class SmallSubgroupIPAProver { challenge_polynomial = Polynomial(challenge_polynomial_ifft); } } - + /** + * @brief Compute a (public) challenge polynomial from the evaluation and batching challenges. + * @details While proving the batched evaluation of the masking term used to blind the ECCVM Transcript wires, the + * prover needs to compute the polynomial whose coefficients in the Lagrange basis over the small subgroup are given + * by \f$ (1, x , \ldots, x^{MASKING_OFFSET - 1}, v, x \cdot v, \ldots, x^{MASKING_OFFSET - 1}\cdot + * v^{NUM_TRANSCRIPT_WIRES - 1}, 0, \ldots, 0) \f$. + * @param evaluation_challenge_x + * @param batching_challenge_v + */ void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v) { - std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); - coeffs_lagrange_basis[0] = FF{ 1 }; - - FF v_power{ 1 }; - - for (size_t v_exponent = 0; v_exponent < 5; v_exponent++) { - // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH - const size_t poly_to_concatenate_start = 1 + MASKING_OFFSET * v_exponent; - coeffs_lagrange_basis[poly_to_concatenate_start] = v_power; - for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + MASKING_OFFSET; idx++) { - // Recursively compute the powers of the challenge - coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; - } - v_power *= batching_challenge_v; - } + std::vector coeffs_lagrange_basis = + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, MASKING_OFFSET); challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); @@ -478,12 +473,12 @@ template class SmallSubgroupIPAProver { return claimed_inner_product; } /** - * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck - * challenges. + * @brief For test purposes: compute the batched evaluation of the last MASKING_OFFSET rows of the ECCVM transcript + * polynomials Op, Px, Py, z1, z2. * - * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates - * @param multivariate_challenge Sumcheck challenge - * @param log_circuit_size + * @param translation_data Contains concatenated ECCVM Transcript polynomials. + * @param evaluation_challenge_x We evaluate the transcript polynomials at x as univariates. + * @param batching_challenge_v The evaluations at x are batched using v. */ static FF compute_claimed_inner_product(TranslationData& translation_data, const FF& evaluation_challenge_x, @@ -509,7 +504,7 @@ template class SmallSubgroupIPAProver { Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { claimed_inner_product += translation_data.concatenated_masking_term_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); } @@ -644,7 +639,7 @@ template class SmallSubgroupIPAVerifier { // subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( challenge_polynomial_lagrange, evaluation_challenge, vanishing_poly_eval); - + info("verifier challenge poly eval ", challenge_poly); const FF& concatenated_at_r = libra_evaluations[0]; const FF& big_sum_shifted_eval = libra_evaluations[1]; const FF& big_sum_eval = libra_evaluations[2]; @@ -708,11 +703,13 @@ template class SmallSubgroupIPAVerifier { // Populate the vector with the powers of the challenges FF v_power{ 1 }; - for (size_t v_exponent = 0; v_exponent < MASKING_OFFSET; v_exponent++) { - size_t current_idx = 1 + MASKING_OFFSET * v_exponent; // Compute the current index into the vector - challenge_polynomial_lagrange[current_idx] = v_power; - for (size_t idx = current_idx + 1; idx < current_idx + MASKING_OFFSET; idx++) { - // Recursively compute the powers of the challenge up to the length of libra univariates + + for (size_t v_exponent = 0; v_exponent < 5; v_exponent++) { + // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH + const size_t poly_to_concatenate_start = 1 + MASKING_OFFSET * v_exponent; + challenge_polynomial_lagrange[poly_to_concatenate_start] = v_power; + for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + MASKING_OFFSET; idx++) { + // Recursively compute the powers of the challenge challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * evaluation_challenge_x; } v_power *= batching_challenge_v; @@ -766,4 +763,42 @@ template class SmallSubgroupIPAVerifier { return result; } }; + +template +std::vector compute_eccvm_challenge_coeffs(const FF& evaluation_challenge_x, + const FF& batching_challenge_v, + size_t subgroup_size, + size_t masking_offset, + size_t num_blocks = 5) +{ + // The result is sized to SUBGROUP_SIZE, with 1 “leading” slot and then + // (1 + masking_offset * num_blocks) <= SUBGROUP_SIZE total elements set. + // The rest remain 0 by default if needed. + std::vector coeffs_lagrange_basis(subgroup_size, FF(0)); + + // The code in your current method: + // - The first entry is 1 + // - Then for each v_exponent in [0..4], we do a block of length `masking_offset`, + // multiplied by v^v_exponent and powers of x + coeffs_lagrange_basis[0] = FF(1); + + FF v_power = FF(1); + for (size_t block = 0; block < num_blocks; block++) { + // Start index of this block + const size_t start = 1 + masking_offset * block; + + // The first element in this block is v^block + coeffs_lagrange_basis[start] = v_power; + + // Next, fill in powers of x + for (size_t idx = start + 1; idx < start + masking_offset; idx++) { + coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; + } + + // Move on to next power of v + v_power *= batching_challenge_v; + } + + return coeffs_lagrange_basis; +} } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 9db8dd08665..d35c97766f8 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -292,14 +292,14 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) const std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = small_subgroup_ipa_prover.get_witness_polynomials(); - std::array libra_evaluations = { + std::array small_ipa_evaluations = { witness_polynomials[0].evaluate(this->evaluation_challenge), witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), witness_polynomials[2].evaluate(this->evaluation_challenge), witness_polynomials[3].evaluate(this->evaluation_challenge) }; - bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(libra_evaluations, + bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, this->evaluation_challenge, evaluation_challenge_x, batching_challenge_v, diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp index 5b1297d148b..2d71467fad5 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp @@ -31,12 +31,13 @@ template class TranslationData { const std::shared_ptr& commitment_key) : concatenated_masking_term(SUBGROUP_SIZE + 2) , concatenated_masking_term_lagrange(SUBGROUP_SIZE) - , constant_term(FF::random_element()) + , constant_term(FF{ 0 }) { // Create interpolation domain - interpolation_domain[0] = Flavor::Curve::subgroup_generator; + interpolation_domain[0] = FF{ 1 }; + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - interpolation_domain[idx] = interpolation_domain[idx - 1] * interpolation_domain[0]; + interpolation_domain[idx] = interpolation_domain[idx - 1] * Flavor::Curve::subgroup_generator; } // Let m_0,..., m_4 be the vectors of last 4 coeffs in each transcript poly, we compute the concatenation @@ -64,7 +65,7 @@ template class TranslationData { for (size_t idx = 0; idx < MASKING_OFFSET; idx++) { size_t idx_to_populate = 1 + poly_idx * MASKING_OFFSET + idx; coeffs_lagrange_subgroup[idx_to_populate] = - transcript_polynomials[poly_idx].at(circuit_size - 1 - MASKING_OFFSET + idx); + transcript_polynomials[poly_idx].at(circuit_size - MASKING_OFFSET + idx); } } concatenated_masking_term_lagrange = Polynomial(coeffs_lagrange_subgroup); From 4d4349e2c63feeff5b5e6446e3faf3724130147a Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 18 Feb 2025 19:00:15 +0000 Subject: [PATCH 05/20] cleaning up --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 158 +++++++----------- .../small_subgroup_ipa.test.cpp | 10 +- .../cpp/src/barretenberg/constants.hpp | 2 +- 3 files changed, 69 insertions(+), 101 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 1e4f147d85c..318cadadfac 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -120,6 +120,9 @@ template class SmallSubgroupIPAProver { // Quotient of the batched polynomial C(X) by the subgroup vanishing polynomial X^{|H|} - 1 Polynomial batched_quotient; + // Number of small univariate polynomials being batched. + size_t num_wires; + public: SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, @@ -171,6 +174,7 @@ template class SmallSubgroupIPAProver { // A constructor to achieve ZK in TranslationEvaluations SmallSubgroupIPAProver(TranslationData& translation_data, + const size_t num_wires, const FF evaluation_challenge_x, const FF batching_challenge_v, const FF claimed_ipa_eval, @@ -186,6 +190,7 @@ template class SmallSubgroupIPAProver { , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) , batched_quotient(QUOTIENT_LENGTH) + , num_wires(num_wires) // Number of transcript polynomials { // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has @@ -250,19 +255,8 @@ template class SmallSubgroupIPAProver { */ void compute_challenge_polynomial(const std::vector& multivariate_challenge) { - std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); - coeffs_lagrange_basis[0] = FF(1); - - for (size_t challenge_idx = 0; challenge_idx < CONST_PROOF_SIZE_LOG_N; challenge_idx++) { - // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH - const size_t poly_to_concatenate_start = 1 + LIBRA_UNIVARIATES_LENGTH * challenge_idx; - coeffs_lagrange_basis[poly_to_concatenate_start] = FF(1); - for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + LIBRA_UNIVARIATES_LENGTH; - idx++) { - // Recursively compute the powers of the challenge - coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * multivariate_challenge[challenge_idx]; - } - } + std::vector coeffs_lagrange_basis = + compute_challenge_polynomial_coeffs(multivariate_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); @@ -289,7 +283,7 @@ template class SmallSubgroupIPAProver { { std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, MASKING_OFFSET); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, num_wires); challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); @@ -482,25 +476,13 @@ template class SmallSubgroupIPAProver { */ static FF compute_claimed_inner_product(TranslationData& translation_data, const FF& evaluation_challenge_x, - const FF& batching_challenge_v) + const FF& batching_challenge_v, + const size_t num_wires) { FF claimed_inner_product{ 0 }; - std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); - coeffs_lagrange_basis[0] = FF{ 1 }; - - FF v_power{ 1 }; - - for (size_t v_exponent = 0; v_exponent < 5; v_exponent++) { - // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH - const size_t poly_to_concatenate_start = 1 + MASKING_OFFSET * v_exponent; - coeffs_lagrange_basis[poly_to_concatenate_start] = v_power; - for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + MASKING_OFFSET; idx++) { - // Recursively compute the powers of the challenge - coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; - } - v_power *= batching_challenge_v; - } + const std::vector coeffs_lagrange_basis = + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, num_wires); Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); @@ -577,7 +559,8 @@ template class SmallSubgroupIPAVerifier { throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); } // Construct the challenge polynomial from the sumcheck challenge, the verifier has to evaluate it on its own - const std::vector challenge_polynomial_lagrange = compute_challenge_polynomial(multilinear_challenge); + const std::vector challenge_polynomial_lagrange = + compute_challenge_polynomial_coeffs(multilinear_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small // subgroup @@ -609,7 +592,8 @@ template class SmallSubgroupIPAVerifier { }; } - static bool check_eccvm_evaluations_consistency(const std::array& libra_evaluations, + static bool check_eccvm_evaluations_consistency(const std::array& small_ipa_evaluations, + const size_t& num_wires, const FF& evaluation_challenge, const FF& evaluation_challenge_x, const FF& batching_challenge_v, @@ -631,19 +615,20 @@ template class SmallSubgroupIPAVerifier { if (evaluation_challenge_in_small_subgroup) { throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); } - // Construct the challenge polynomial from the sumcheck challenge, the verifier has to evaluate it on its own + // Construct the challenge polynomial from the evaluation and batching challenges, the verifier has to evaluate + // it on its own const std::vector challenge_polynomial_lagrange = - compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, num_wires); // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small // subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( challenge_polynomial_lagrange, evaluation_challenge, vanishing_poly_eval); info("verifier challenge poly eval ", challenge_poly); - const FF& concatenated_at_r = libra_evaluations[0]; - const FF& big_sum_shifted_eval = libra_evaluations[1]; - const FF& big_sum_eval = libra_evaluations[2]; - const FF& quotient_eval = libra_evaluations[3]; + const FF& concatenated_at_r = small_ipa_evaluations[0]; + const FF& big_sum_shifted_eval = small_ipa_evaluations[1]; + const FF& big_sum_eval = small_ipa_evaluations[2]; + const FF& quotient_eval = small_ipa_evaluations[3]; // Compute the evaluation of // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) @@ -665,58 +650,6 @@ template class SmallSubgroupIPAVerifier { }; } - /** - * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = - * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose - * coefficients are given by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend \f$ D \f$ - * multiplications to construct the coefficients. - * - * @param multivariate_challenge - * @return Polynomial - */ - static std::vector compute_challenge_polynomial(const std::vector& multivariate_challenge) - { - std::vector challenge_polynomial_lagrange(SUBGROUP_SIZE); - - challenge_polynomial_lagrange[0] = FF{ 1 }; - - // Populate the vector with the powers of the challenges - size_t round_idx = 0; - for (auto challenge : multivariate_challenge) { - size_t current_idx = 1 + LIBRA_UNIVARIATES_LENGTH * round_idx; // Compute the current index into the vector - challenge_polynomial_lagrange[current_idx] = FF(1); - for (size_t idx = current_idx + 1; idx < current_idx + LIBRA_UNIVARIATES_LENGTH; idx++) { - // Recursively compute the powers of the challenge up to the length of libra univariates - challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; - } - round_idx++; - } - return challenge_polynomial_lagrange; - } - - static std::vector compute_eccvm_challenge_polynomial(const FF& evaluation_challenge_x, - const FF& batching_challenge_v) - { - std::vector challenge_polynomial_lagrange(SUBGROUP_SIZE); - - challenge_polynomial_lagrange[0] = FF{ 1 }; - - // Populate the vector with the powers of the challenges - FF v_power{ 1 }; - - for (size_t v_exponent = 0; v_exponent < 5; v_exponent++) { - // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH - const size_t poly_to_concatenate_start = 1 + MASKING_OFFSET * v_exponent; - challenge_polynomial_lagrange[poly_to_concatenate_start] = v_power; - for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + MASKING_OFFSET; idx++) { - // Recursively compute the powers of the challenge - challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * evaluation_challenge_x; - } - v_power *= batching_challenge_v; - } - return challenge_polynomial_lagrange; - } - /** * @brief Efficient batch evaluation of the challenge polynomial, Lagrange first, and Lagrange last * @@ -764,12 +697,43 @@ template class SmallSubgroupIPAVerifier { } }; +/** + * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = + * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose + * coefficients are given by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend \f$ D \f$ + * multiplications to construct the coefficients. + * + * @param multivariate_challenge + * @return Polynomial + */ +template +static std::vector compute_challenge_polynomial_coeffs(const std::vector& multivariate_challenge, + const size_t subgroup_size, + const size_t libra_univariates_length) +{ + std::vector challenge_polynomial_lagrange(subgroup_size); + + challenge_polynomial_lagrange[0] = FF{ 1 }; + + // Populate the vector with the powers of the challenges + size_t round_idx = 0; + for (auto challenge : multivariate_challenge) { + size_t current_idx = 1 + libra_univariates_length * round_idx; // Compute the current index into the vector + challenge_polynomial_lagrange[current_idx] = FF(1); + for (size_t idx = current_idx + 1; idx < current_idx + libra_univariates_length; idx++) { + // Recursively compute the powers of the challenge up to the length of libra univariates + challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; + } + round_idx++; + } + return challenge_polynomial_lagrange; +} + template std::vector compute_eccvm_challenge_coeffs(const FF& evaluation_challenge_x, const FF& batching_challenge_v, - size_t subgroup_size, - size_t masking_offset, - size_t num_blocks = 5) + const size_t& subgroup_size, + const size_t& num_wires) { // The result is sized to SUBGROUP_SIZE, with 1 “leading” slot and then // (1 + masking_offset * num_blocks) <= SUBGROUP_SIZE total elements set. @@ -780,18 +744,18 @@ std::vector compute_eccvm_challenge_coeffs(const FF& evaluation_challenge_x, // - The first entry is 1 // - Then for each v_exponent in [0..4], we do a block of length `masking_offset`, // multiplied by v^v_exponent and powers of x - coeffs_lagrange_basis[0] = FF(1); + coeffs_lagrange_basis[0] = FF{ 1 }; FF v_power = FF(1); - for (size_t block = 0; block < num_blocks; block++) { + for (size_t poly_idx = 0; poly_idx < num_wires; poly_idx++) { // Start index of this block - const size_t start = 1 + masking_offset * block; + const size_t start = 1 + MASKING_OFFSET * poly_idx; // The first element in this block is v^block coeffs_lagrange_basis[start] = v_power; // Next, fill in powers of x - for (size_t idx = start + 1; idx < start + masking_offset; idx++) { + for (size_t idx = start + 1; idx < start + MASKING_OFFSET; idx++) { coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index d35c97766f8..6a8bb15734c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -260,6 +260,8 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) using CK = typename TypeParam::CommitmentKey; auto prover_transcript = TypeParam::Transcript::prover_init_empty(); + // Must satisfy num_wires * MASKING_OFFSET + 1 < SUBGROUP_SIZE + const size_t num_wires = 5; // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); @@ -269,7 +271,7 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) // Generate transcript polynomials std::vector> transcript_polynomials; - for (size_t idx = 0; idx < 5; idx++) { + for (size_t idx = 0; idx < num_wires; idx++) { transcript_polynomials.push_back(Polynomial::random(this->circuit_size)); } @@ -279,10 +281,11 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) const FF evaluation_challenge_x = FF::random_element(); const FF batching_challenge_v = FF::random_element(); - const FF claimed_inner_product = - Prover::compute_claimed_inner_product(translation_data, evaluation_challenge_x, batching_challenge_v); + const FF claimed_inner_product = Prover::compute_claimed_inner_product( + translation_data, evaluation_challenge_x, batching_challenge_v, num_wires); Prover small_subgroup_ipa_prover(translation_data, + num_wires, evaluation_challenge_x, batching_challenge_v, claimed_inner_product, @@ -300,6 +303,7 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) }; bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, + num_wires, this->evaluation_challenge, evaluation_challenge_x, batching_challenge_v, diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 53f097b30c4..d85f597edc7 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -24,4 +24,4 @@ static constexpr uint32_t MASKING_OFFSET = 4; // For ZK Flavors: the number of the commitments required by Libra and SmallSubgroupIPA. static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; static constexpr uint32_t NUM_LIBRA_EVALUATIONS = 4; -} // namespace bb \ No newline at end of file +} // namespace bb From 3aa169b7ff9cbe779c54691df05a4b0fcdcec496 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 19 Feb 2025 10:21:02 +0000 Subject: [PATCH 06/20] small subgroup ipa test clean-up --- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 4 +- .../small_subgroup_ipa.test.cpp | 48 ++++++++----------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 318cadadfac..a8df55f6eaa 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -613,7 +613,7 @@ template class SmallSubgroupIPAVerifier { } // The probability of this event is negligible but it has to be processed correctly if (evaluation_challenge_in_small_subgroup) { - throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); + throw_or_abort("Evaluation challenge is in the SmallSubgroup."); } // Construct the challenge polynomial from the evaluation and batching challenges, the verifier has to evaluate // it on its own @@ -624,7 +624,7 @@ template class SmallSubgroupIPAVerifier { // subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( challenge_polynomial_lagrange, evaluation_challenge, vanishing_poly_eval); - info("verifier challenge poly eval ", challenge_poly); + const FF& concatenated_at_r = small_ipa_evaluations[0]; const FF& big_sum_shifted_eval = small_ipa_evaluations[1]; const FF& big_sum_eval = small_ipa_evaluations[2]; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 6a8bb15734c..9d1e2cb7c6c 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -14,6 +14,8 @@ template class SmallSubgroupIPATest : public ::testing::Test { using Transcript = typename Flavor::Transcript; using FF = typename Curve::ScalarField; + static constexpr FF subgroup_generator = Curve::subgroup_generator; + static constexpr size_t log_circuit_size = 7; static constexpr size_t circuit_size = 1ULL << log_circuit_size; @@ -29,6 +31,16 @@ template class SmallSubgroupIPATest : public ::testing::Test { } return multivariate_challenge; } + + // A helper to evaluate the four IPA witness polynomials at x, x*g, x, x + std::array evaluate_small_ipa_witnesses(const std::array, 4>& witness_polynomials) + { + // Hard-coded pattern of evaluation: (x, x*g, x, x) + return { witness_polynomials[0].evaluate(evaluation_challenge), + witness_polynomials[1].evaluate(evaluation_challenge * subgroup_generator), + witness_polynomials[2].evaluate(evaluation_challenge), + witness_polynomials[3].evaluate(evaluation_challenge) }; + } }; using TestFlavors = ::testing::Types; @@ -182,18 +194,11 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimple) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - const std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = - small_subgroup_ipa_prover.get_witness_polynomials(); - - std::array libra_evaluations = { - witness_polynomials[0].evaluate(this->evaluation_challenge), - witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), - witness_polynomials[2].evaluate(this->evaluation_challenge), - witness_polynomials[3].evaluate(this->evaluation_challenge) - }; + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); bool consistency_checked = Verifier::check_evaluations_consistency( - libra_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); + small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); EXPECT_TRUE(consistency_checked); } @@ -231,15 +236,11 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) // Tamper with witness polynomials witness_polynomials[0].at(0) = FF::random_element(); - std::array libra_evaluations = { - witness_polynomials[0].evaluate(this->evaluation_challenge), - witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), - witness_polynomials[2].evaluate(this->evaluation_challenge), - witness_polynomials[3].evaluate(this->evaluation_challenge) - }; + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(witness_polynomials); bool consistency_checked = Verifier::check_evaluations_consistency( - libra_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); + small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); // Since witness polynomials were modified, the consistency check must fail EXPECT_FALSE(consistency_checked); @@ -249,7 +250,7 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) // verifier. TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) { - + // TranslationData class is Grumpkin-specific if constexpr (std::is_same_v) { GTEST_SKIP(); } else { @@ -292,15 +293,8 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) prover_transcript, ck); - const std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = - small_subgroup_ipa_prover.get_witness_polynomials(); - - std::array small_ipa_evaluations = { - witness_polynomials[0].evaluate(this->evaluation_challenge), - witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), - witness_polynomials[2].evaluate(this->evaluation_challenge), - witness_polynomials[3].evaluate(this->evaluation_challenge) - }; + const std::array small_ipa_evaluations = + this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, num_wires, From 6628ec70e2c35aa120e27537c4448d1c0a05739b Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 19 Feb 2025 15:15:45 +0000 Subject: [PATCH 07/20] propagate translation challenges from eccvm verifier to translator verifier --- .../src/barretenberg/eccvm/eccvm_prover.cpp | 12 ++- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 70 ++++++++++------- .../src/barretenberg/eccvm/eccvm_verifier.hpp | 10 +++ .../cpp/src/barretenberg/goblin/goblin.hpp | 5 +- .../eccvm_recursive_verifier.cpp | 75 +++++++++++-------- .../eccvm_recursive_verifier.hpp | 9 +++ .../goblin_recursive_verifier.cpp | 5 +- .../translator_recursive_verifier.cpp | 7 +- .../translator_recursive_verifier.hpp | 4 +- .../translator_vm/translator_prover.cpp | 2 - .../translator_vm/translator_verifier.cpp | 9 +-- .../translator_vm/translator_verifier.hpp | 2 +- 12 files changed, 128 insertions(+), 82 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 6888fd3f264..d6d6f1fefef 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -193,6 +193,13 @@ ECCVMProof ECCVMProver::construct_proof() return export_proof(); } +/** + * @brief The evaluations of the wires `op`, `Px`, `Py`, `z_1`, and `z_2` as univariate polynomials have to proved as + * they are used in the 'TranslatorVerifier::verify_translation' sub-protocol and its recursive counterpart. To increase + * the efficiency, we produce an OpeningClaim that is fed to Shplonk along with the OpeningClaim produced by Shplemini. + * + * @return ProverOpeningClaim + */ ProverOpeningClaim ECCVMProver::reduce_translation_evaluations() { // Collect the polynomials and evaluations to be batched @@ -225,9 +232,6 @@ ProverOpeningClaim ECCVMProver::reduce_translation_ batching_scalar *= translation_batching_challenge_v; } - OpeningClaim translation_opening_claim = { .polynomial = batched_univariate, - .opening_pair = { evaluation_challenge_x, batched_evaluation } }; - - return translation_opening_claim; + return { .polynomial = batched_univariate, .opening_pair = { evaluation_challenge_x, batched_evaluation } }; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 82606aa3729..4bd71d02978 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -99,16 +99,44 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) const OpeningClaim multivariate_to_univariate_opening_claim = PCS::reduce_batch_opening_claim(sumcheck_batch_opening_claims); - const FF evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); + // Produce the opening claim for batch opening of 'op', 'Px', 'Py', 'z1', and 'z2' wires as univariate polynomials + transcript_commitments = { commitments.transcript_op, + commitments.transcript_Px, + commitments.transcript_Py, + commitments.transcript_z1, + commitments.transcript_z2 }; + + const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(transcript_commitments); + + const std::array opening_claims = { multivariate_to_univariate_opening_claim, + translation_opening_claim }; + + // Construct and verify the combined opening claim + const OpeningClaim batch_opening_claim = + Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); + + const bool batched_opening_verified = + PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); + vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified); + vinfo("batch opening verified?: ", batched_opening_verified); + return sumcheck_output.verified && batched_opening_verified && consistency_checked; +} + +/** + * @brief To link the ECCVM Transcript wires 'op', 'Px', 'Py', 'z1', and 'z2' to the accumulator computed by the + * translator, we verify their evaluations as univariates. For efficiency reasons, we batch these evaluations. + * + * @param transcript_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' + * @return OpeningClaim + */ +OpeningClaim ECCVMVerifier::reduce_verify_translation_evaluations( + const std::array& transcript_commitments) +{ + evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); // Construct arrays of commitments and evaluations to be batched, the evaluations being received from the prover - const size_t NUM_UNIVARIATES = 5; - std::array transcript_commitments = { commitments.transcript_op, - commitments.transcript_Px, - commitments.transcript_Py, - commitments.transcript_z1, - commitments.transcript_z2 }; - std::array transcript_evaluations = { + + std::array transcript_evaluations = { transcript->template receive_from_prover("Translation:op"), transcript->template receive_from_prover("Translation:Px"), transcript->template receive_from_prover("Translation:Py"), @@ -117,32 +145,18 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) }; // Get the batching challenge for commitments and evaluations - const FF ipa_batching_challenge = transcript->template get_challenge("Translation:ipa_batching_challenge"); + batching_challenge_v = transcript->template get_challenge("Translation:ipa_batching_challenge"); // Compute the batched commitment and batched evaluation for the univariate opening claim Commitment batched_commitment = transcript_commitments[0]; FF batched_transcript_eval = transcript_evaluations[0]; - FF batching_scalar = ipa_batching_challenge; - for (size_t idx = 1; idx < NUM_UNIVARIATES; ++idx) { + FF batching_scalar = batching_challenge_v; + for (size_t idx = 1; idx < NUM_TRANSCRIPT_WIRES; ++idx) { batched_commitment = batched_commitment + transcript_commitments[idx] * batching_scalar; batched_transcript_eval += batching_scalar * transcript_evaluations[idx]; - batching_scalar *= ipa_batching_challenge; + batching_scalar *= batching_challenge_v; } - const OpeningClaim translation_opening_claim = { { evaluation_challenge_x, batched_transcript_eval }, - batched_commitment }; - - const std::array opening_claims = { multivariate_to_univariate_opening_claim, - translation_opening_claim }; - - // Construct and verify the combined opening claim - const OpeningClaim batch_opening_claim = - Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - - const bool batched_opening_verified = - PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript); - vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified); - vinfo("batch opening verified?: ", batched_opening_verified); - return sumcheck_output.verified && batched_opening_verified && consistency_checked; -} + return { { evaluation_challenge_x, batched_transcript_eval }, batched_commitment }; +}; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp index c772d99b517..597f4b37406 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp @@ -24,9 +24,19 @@ class ECCVMVerifier { bool verify_proof(const ECCVMProof& proof); + static constexpr size_t NUM_TRANSCRIPT_WIRES = 5; + std::array transcript_commitments; + + OpeningClaim reduce_verify_translation_evaluations( + const std::array& transcript_commitments); + std::shared_ptr key; std::map commitments; std::shared_ptr transcript; std::shared_ptr ipa_transcript; + + // Translation evaluations challenges. They are propagated to the TranslatorVerifier + FF evaluation_challenge_x; + FF batching_challenge_v; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 872b168f960..d238d5b6b94 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -296,7 +296,8 @@ class GoblinVerifier { TranslatorVerifier translator_verifier(translator_verification_key, eccvm_verifier.transcript); - bool accumulator_construction_verified = translator_verifier.verify_proof(proof.translator_proof); + bool accumulator_construction_verified = translator_verifier.verify_proof( + proof.translator_proof, eccvm_verifier.evaluation_challenge_x, eccvm_verifier.batching_challenge_v); // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed // correctly bool translation_verified = translator_verifier.verify_translation(proof.translation_evaluations); @@ -309,4 +310,4 @@ class GoblinVerifier { return merge_verified && eccvm_verified && accumulator_construction_verified && translation_verified; }; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 078049b831e..eac21e6c8a7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -68,9 +68,6 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) commitments.z_perm = transcript->template receive_from_prover(commitment_labels.z_perm); // Execute Sumcheck Verifier - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1009): probably the size of this should be fixed to the - // maximum possible size of an ECCVM circuit otherwise we might run into problem because the number of rounds of - // sumcheck is dependent on circuit size. const size_t log_circuit_size = numeric::get_msb(static_cast(circuit_size.get_value())); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); const FF alpha = transcript->template get_challenge("Sumcheck:alpha"); @@ -114,48 +111,64 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) const OpeningClaim multivariate_to_univariate_opening_claim = PCS::reduce_batch_opening_claim(sumcheck_batch_opening_claims); - const FF evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); + // Construct the vector of commitments (needs to be vector for the batch_mul) + const std::vector transcript_commitments = { commitments.transcript_op, + commitments.transcript_Px, + commitments.transcript_Py, + commitments.transcript_z1, + commitments.transcript_z2 }; + // Reduce the univariate evaluations claims to a single claim to be batched by Shplonk + const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(transcript_commitments); + // Construct and verify the combined opening claim + const std::array opening_claims = { multivariate_to_univariate_opening_claim, + translation_opening_claim }; + + const OpeningClaim batch_opening_claim = + Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - // Construct the vector of commitments (needs to be vector for the batch_mul) and array of evaluations to be batched - std::vector transcript_commitments = { commitments.transcript_op, - commitments.transcript_Px, - commitments.transcript_Py, - commitments.transcript_z1, - commitments.transcript_z2 }; + return { batch_opening_claim, ipa_transcript }; +} - std::vector transcript_evaluations = { transcript->template receive_from_prover("Translation:op"), - transcript->template receive_from_prover("Translation:Px"), - transcript->template receive_from_prover("Translation:Py"), - transcript->template receive_from_prover("Translation:z1"), - transcript->template receive_from_prover("Translation:z2") }; +/** + * @brief To link the ECCVM Transcript wires 'op', 'Px', 'Py', 'z1', and 'z2' to the accumulator computed by the + * translator, we verify their evaluations as univariates. For efficiency reasons, we batch these evaluations. + * + * @tparam Flavor ECCVMRecursiveFlavor_ + * @param transcript_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' + * @return OpeningClaim + */ +template +OpeningClaim ECCVMRecursiveVerifier_::reduce_verify_translation_evaluations( + const std::vector& transcript_commitments) +{ + evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); + + // Construct the array of evaluations to be batched, the evaluations being received from the prover + std::array transcript_evaluations = { + transcript->template receive_from_prover("Translation:op"), + transcript->template receive_from_prover("Translation:Px"), + transcript->template receive_from_prover("Translation:Py"), + transcript->template receive_from_prover("Translation:z1"), + transcript->template receive_from_prover("Translation:z2") + }; // Get the batching challenge for commitments and evaluations - const FF ipa_batching_challenge = transcript->template get_challenge("Translation:ipa_batching_challenge"); + batching_challenge_v = transcript->template get_challenge("Translation:ipa_batching_challenge"); // Compute the batched commitment and batched evaluation for the univariate opening claim auto batched_transcript_eval = transcript_evaluations[0]; - auto batching_scalar = ipa_batching_challenge; + auto batching_scalar = batching_challenge_v; std::vector batching_challenges = { FF::one() }; - for (size_t idx = 1; idx < transcript_commitments.size(); ++idx) { + for (size_t idx = 1; idx < NUM_TRANSCRIPT_WIRES; ++idx) { batched_transcript_eval += batching_scalar * transcript_evaluations[idx]; batching_challenges.emplace_back(batching_scalar); - batching_scalar *= ipa_batching_challenge; + batching_scalar *= batching_challenge_v; } const Commitment batched_commitment = Commitment::batch_mul(transcript_commitments, batching_challenges); - // Construct and verify the combined opening claim - const OpeningClaim translation_opening_claim = { { evaluation_challenge_x, batched_transcript_eval }, - batched_commitment }; - - const std::array opening_claims = { multivariate_to_univariate_opening_claim, - translation_opening_claim }; - - const OpeningClaim batch_opening_claim = - Shplonk::reduce_verification(key->pcs_verification_key->get_g1_identity(), opening_claims, transcript); - - return { batch_opening_claim, ipa_transcript }; -} + return { { evaluation_challenge_x, batched_transcript_eval }, batched_commitment }; +}; template class ECCVMRecursiveVerifier_>; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp index 729740aa707..56a106328d9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp @@ -28,5 +28,14 @@ template class ECCVMRecursiveVerifier_ { Builder* builder; std::shared_ptr transcript; std::shared_ptr ipa_transcript; + + static constexpr size_t NUM_TRANSCRIPT_WIRES = 5; + std::vector transcript_commitments; + + OpeningClaim reduce_verify_translation_evaluations(const std::vector& transcript_commitments); + + // Translation evaluations challenges. They are propagated to the TranslatorVerifier + FF evaluation_challenge_x; + FF batching_challenge_v; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp index b9bf165bc96..e35738eb943 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp @@ -18,7 +18,8 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof& TranslatorVerifier translator_verifier{ builder, verification_keys.translator_verification_key, eccvm_verifier.transcript }; - translator_verifier.verify_proof(proof.translator_proof); + translator_verifier.verify_proof( + proof.translator_proof, eccvm_verifier.evaluation_challenge_x, eccvm_verifier.batching_challenge_v); // Verify the consistency between the ECCVM and Translator transcript polynomial evaluations // In reality the Goblin Proof is going to already be a stdlib proof and this conversion is not going to happen here @@ -38,4 +39,4 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof& merge_verifier.verify_proof(proof.merge_proof); return { opening_claim, ipa_transcript }; } -} // namespace bb::stdlib::recursion::honk \ No newline at end of file +} // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index c608495a0aa..aa14a7f97da 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -57,7 +57,8 @@ void TranslatorRecursiveVerifier_::put_translation_data_in_relation_para * @brief This function verifies an TranslatorFlavor Honk proof for given program settings. */ template -std::array TranslatorRecursiveVerifier_::verify_proof(const HonkProof& proof) +std::array TranslatorRecursiveVerifier_::verify_proof( + const HonkProof& proof, const BF& evaluation_input_x, const BF& batching_challenge_v) { using Sumcheck = ::bb::SumcheckVerifier; using PCS = typename Flavor::PCS; @@ -79,10 +80,6 @@ std::array TranslatorRecursiveVerifier_template receive_from_prover("Translation:batching_challenge"); - // Is this sound? - evaluation_input_x = transcript->template receive_from_prover("evaluation_input_x"); const BF accumulated_result = transcript->template receive_from_prover("accumulated_result"); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp index 39742bb65cc..426dc687472 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp @@ -42,10 +42,10 @@ template class TranslatorRecursiveVerifier_ { const BF& batching_challenge_v, const BF& accumulated_result); - PairingPoints verify_proof(const HonkProof& proof); + PairingPoints verify_proof(const HonkProof& proof, const BF& evaluation_input_x, const BF& batching_challenge_v); // TODO(https://github.com/AztecProtocol/barretenberg/issues/986): Ensure the translation is also recursively // verified somewhere bool verify_translation(const TranslationEvaluations& translation_evaluations); }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index d6673cef1f7..d57028525e5 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -35,8 +35,6 @@ void TranslatorProver::execute_preamble_round() uint256_t(key->proving_key->polynomials.accumulators_binary_limbs_2[1]) * SHIFTx2 + uint256_t(key->proving_key->polynomials.accumulators_binary_limbs_3[1]) * SHIFTx3); transcript->send_to_verifier("circuit_size", circuit_size); - transcript->send_to_verifier("Translation:batching_challenge", key->batching_challenge_v); - transcript->send_to_verifier("evaluation_input_x", key->evaluation_input_x); transcript->send_to_verifier("accumulated_result", accumulated_result); } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index 077efb423a3..c83eaeb1643 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -45,9 +45,11 @@ void TranslatorVerifier::put_translation_data_in_relation_parameters(const uint2 }; /** - * @brief This function verifies an TranslatorFlavor Honk proof for given program settings. + * @brief This function verifies a TranslatorFlavor Honk proof for given program settings. */ -bool TranslatorVerifier::verify_proof(const HonkProof& proof) +bool TranslatorVerifier::verify_proof(const HonkProof& proof, + const uint256_t& evaluation_input_x, + const BF& batching_challenge_v) { using Curve = typename Flavor::Curve; using PCS = typename Flavor::PCS; @@ -63,9 +65,6 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) const auto circuit_size = transcript->template receive_from_prover("circuit_size"); - batching_challenge_v = transcript->template receive_from_prover("Translation:batching_challenge"); - evaluation_input_x = transcript->template receive_from_prover("evaluation_input_x"); - const BF accumulated_result = transcript->template receive_from_prover("accumulated_result"); put_translation_data_in_relation_parameters(evaluation_input_x, batching_challenge_v, accumulated_result); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.hpp index dbe0dc66cdb..acd003ff53b 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.hpp @@ -33,7 +33,7 @@ class TranslatorVerifier { void put_translation_data_in_relation_parameters(const uint256_t& evaluation_input_x, const BF& batching_challenge_v, const uint256_t& accumulated_result); - bool verify_proof(const HonkProof& proof); + bool verify_proof(const HonkProof& proof, const uint256_t& evaluation_input_x, const BF& batching_challenge_v); bool verify_translation(const TranslationEvaluations& translation_evaluations); }; } // namespace bb From a51d492f2ac62c235747a21633bbf49350ca4480 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 20 Feb 2025 13:19:22 +0000 Subject: [PATCH 08/20] slightly more sound --- .../src/barretenberg/eccvm/eccvm_prover.cpp | 2 +- .../eccvm/eccvm_transcript.test.cpp | 7 ++--- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 2 +- .../eccvm_recursive_verifier.cpp | 2 +- .../goblin_recursive_verifier.cpp | 7 +++-- .../translator_recursive_verifier.cpp | 4 +-- .../translator_recursive_verifier.hpp | 4 +-- .../translator_recursive_verifier.test.cpp | 27 ++++++++++--------- .../translator_vm/translator.test.cpp | 8 +++--- .../translator_circuit_builder.hpp | 2 +- 10 files changed, 32 insertions(+), 33 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index d6d6f1fefef..b29223014e0 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -220,7 +220,7 @@ ProverOpeningClaim ECCVMProver::reduce_translation_ } // Get another challenge to batch the evaluations of the transcript polynomials - translation_batching_challenge_v = transcript->template get_challenge("Translation:ipa_batching_challenge"); + translation_batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge_v"); // Construct the batched polynomial and batched evaluation to produce the batched opening claim Polynomial batched_univariate{ key->circuit_size }; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index 8eef6b58e48..c146e7ae1c6 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -191,7 +191,7 @@ class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "Translation:Py", frs_per_Fr); manifest_expected.add_entry(round, "Translation:z1", frs_per_Fr); manifest_expected.add_entry(round, "Translation:z2", frs_per_Fr); - manifest_expected.add_challenge(round, "Translation:ipa_batching_challenge"); + manifest_expected.add_challenge(round, "Translation:batching_challenge_v"); round++; manifest_expected.add_challenge(round, "Shplonk:nu"); @@ -200,9 +200,6 @@ class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G); manifest_expected.add_challenge(round, "Shplonk:z"); - round++; - manifest_expected.add_challenge(round, "Translation:batching_challenge"); - return manifest_expected; } @@ -405,4 +402,4 @@ TEST_F(ECCVMTranscriptTests, StructureTest) prover.transcript->deserialize_full_transcript(); EXPECT_EQ(static_cast(prover.transcript->transcript_Px_comm), one_group_val * rand_val); -} \ No newline at end of file +} diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 4bd71d02978..ed65411bef6 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -145,7 +145,7 @@ OpeningClaim ECCVMVerifier::reduce_verify_translati }; // Get the batching challenge for commitments and evaluations - batching_challenge_v = transcript->template get_challenge("Translation:ipa_batching_challenge"); + batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge_v"); // Compute the batched commitment and batched evaluation for the univariate opening claim Commitment batched_commitment = transcript_commitments[0]; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index eac21e6c8a7..baff48494aa 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -153,7 +153,7 @@ OpeningClaim ECCVMRecursiveVerifier_::reduce_ver }; // Get the batching challenge for commitments and evaluations - batching_challenge_v = transcript->template get_challenge("Translation:ipa_batching_challenge"); + batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge_v"); // Compute the batched commitment and batched evaluation for the univariate opening claim auto batched_transcript_eval = transcript_evaluations[0]; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp index e35738eb943..d18753face9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp @@ -18,8 +18,11 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof& TranslatorVerifier translator_verifier{ builder, verification_keys.translator_verification_key, eccvm_verifier.transcript }; - translator_verifier.verify_proof( - proof.translator_proof, eccvm_verifier.evaluation_challenge_x, eccvm_verifier.batching_challenge_v); + + auto evaluation_challenge_x = TranslatorBF::from_witness(builder, proof.evaluation_challenge_x); + auto batching_challenge_v = TranslatorBF::from_witness(builder, proof.batching_challenge_v); + + translator_verifier.verify_proof(proof.translator_proof, evaluation_challenge_x, batching_challenge_v); // Verify the consistency between the ECCVM and Translator transcript polynomial evaluations // In reality the Goblin Proof is going to already be a stdlib proof and this conversion is not going to happen here diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index aa14a7f97da..60fa119d0bd 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -154,9 +154,7 @@ bool TranslatorRecursiveVerifier_::verify_translation( typename Flavor::FF>& translation_evaluations) { const auto reconstruct_from_array = [&](const auto& arr) { - const BF reconstructed = BF::construct_from_limbs(arr[0], arr[1], arr[2], arr[3]); - - return reconstructed; + return BF::construct_from_limbs(arr[0], arr[1], arr[2], arr[3]); }; const auto& reconstruct_value_from_eccvm_evaluations = [&](const TranslationEvaluations& translation_evaluations, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp index 426dc687472..4e73b1bf049 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/goblin/translation_evaluations.hpp" +#include "barretenberg/goblin/types.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/stdlib/transcript/transcript.hpp" #include "barretenberg/stdlib/translator_vm_verifier/translator_recursive_flavor.hpp" @@ -24,9 +25,6 @@ template class TranslatorRecursiveVerifier_ { using Transcript = typename Flavor::Transcript; using RelationParams = ::bb::RelationParameters; - BF evaluation_input_x = 0; - BF batching_challenge_v = 0; - std::shared_ptr key; std::shared_ptr transcript; std::shared_ptr pcs_verification_key; // can remove maybe hopefully diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index a2c5125c542..ff9140b6cb5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -29,6 +29,7 @@ template class TranslatorRecursiveTests : public ::te using InnerBF = InnerFlavor::BF; using RecursiveVerifier = TranslatorRecursiveVerifier_; + using TranslatorBF = typename TranslatorRecursiveFlavor_::BF; using OuterBuilder = typename RecursiveFlavor::CircuitBuilder; using OuterFlavor = std::conditional_t, MegaFlavor, UltraFlavor>; @@ -66,11 +67,11 @@ template class TranslatorRecursiveTests : public ::te prover_transcript->send_to_verifier("init", InnerBF::random_element()); // normally this would be the eccvm proof auto fake_inital_proof = prover_transcript->export_proof(); - InnerBF translation_batching_challenge = - prover_transcript->template receive_from_prover("Translation:batching_challenge"); - InnerBF translation_evaluation_challenge = InnerBF::random_element(); - auto circuit_builder = InnerBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); + InnerBF batching_challenge_v = InnerBF::random_element(); + InnerBF evaluation_challenge_x = InnerBF::random_element(); + + auto circuit_builder = InnerBuilder(batching_challenge_v, evaluation_challenge_x, op_queue); EXPECT_TRUE(circuit_builder.check_circuit()); auto proving_key = std::make_shared(circuit_builder); InnerProver prover{ proving_key, prover_transcript }; @@ -85,7 +86,9 @@ template class TranslatorRecursiveTests : public ::te auto verification_key = std::make_shared(prover.key->proving_key); RecursiveVerifier verifier{ &outer_circuit, verification_key, transcript }; - auto pairing_points = verifier.verify_proof(proof); + verifier.verify_proof(inner_proof, + TranslatorBF::from_witness(&outer_circuit, evaluation_challenge_x), + TranslatorBF::from_witness(&outer_circuit, batching_challenge_v)); info("Recursive Verifier: num gates = ", outer_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit @@ -94,7 +97,7 @@ template class TranslatorRecursiveTests : public ::te auto native_verifier_transcript = std::make_shared(prover_transcript->proof_data); native_verifier_transcript->template receive_from_prover("init"); InnerVerifier native_verifier(verification_key, native_verifier_transcript); - bool native_result = native_verifier.verify_proof(proof); + bool native_result = native_verifier.verify_proof(proof, evaluation_challenge_x, batching_challenge_v); auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(recursive_result, native_result); @@ -138,12 +141,10 @@ template class TranslatorRecursiveTests : public ::te // normally this would be the eccvm proof auto fake_inital_proof = prover_transcript->export_proof(); - InnerBF translation_batching_challenge = - prover_transcript->template get_challenge("Translation:batching_challenge"); - InnerBF translation_evaluation_challenge = InnerBF::random_element(); + InnerBF batching_challenge_v = InnerBF::random_element(); + InnerBF evaluation_challenge_x = InnerBF::random_element(); - auto inner_circuit = - InnerBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); + auto inner_circuit = InnerBuilder(batching_challenge_v, evaluation_challenge_x, op_queue); // Generate a proof over the inner circuit auto inner_proving_key = std::make_shared(inner_circuit); @@ -163,7 +164,9 @@ template class TranslatorRecursiveTests : public ::te transcript->template receive_from_prover("init"); RecursiveVerifier verifier{ &outer_circuit, verification_key, transcript }; - verifier.verify_proof(inner_proof); + verifier.verify_proof(inner_proof, + TranslatorBF::from_witness(&outer_circuit, evaluation_challenge_x), + TranslatorBF::from_witness(&outer_circuit, batching_challenge_v)); auto outer_proving_key = std::make_shared(outer_circuit); auto outer_verification_key = diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp index 0beb7176ff8..62ad96c42ec 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp @@ -47,10 +47,10 @@ TEST_F(TranslatorTests, Basic) auto prover_transcript = std::make_shared(); prover_transcript->send_to_verifier("init", Fq::random_element()); prover_transcript->export_proof(); - Fq translation_batching_challenge = Fq::random_element(); - Fq translation_evaluation_challenge = Fq::random_element(); + Fq batching_challenge_v = Fq::random_element(); + Fq evaluation_challenge_x = Fq::random_element(); - auto circuit_builder = CircuitBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); + auto circuit_builder = CircuitBuilder(batching_challenge_v, evaluation_challenge_x, op_queue); EXPECT_TRUE(circuit_builder.check_circuit()); auto proving_key = std::make_shared(circuit_builder); TranslatorProver prover{ proving_key, prover_transcript }; @@ -60,6 +60,6 @@ TEST_F(TranslatorTests, Basic) verifier_transcript->template receive_from_prover("init"); auto verification_key = std::make_shared(proving_key->proving_key); TranslatorVerifier verifier(verification_key, verifier_transcript); - bool verified = verifier.verify_proof(proof); + bool verified = verifier.verify_proof(proof, evaluation_challenge_x, batching_challenge_v); EXPECT_TRUE(verified); } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp index cc10a1803a9..2ff8784502b 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp @@ -188,7 +188,7 @@ class TranslatorCircuitBuilder : public CircuitBuilderBase { // For context, minicircuit is the part of the final polynomials fed into the proving system, where we have all the // arithmetic logic. However, the full circuit is several times larger (we use a trick to bring down the degree of // the permutation argument) - static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH = 2048; + static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH = 8192; // Maximum size of a single limb is 68 bits static constexpr size_t NUM_LIMB_BITS = 68; From bfaab514d832fb98988d21e1bfb536970e945996 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 20 Feb 2025 14:35:12 +0000 Subject: [PATCH 09/20] IndependentVKHash test added to Goblin --- .../src/barretenberg/eccvm/eccvm_prover.hpp | 2 +- .../goblin_recursive_verifier.cpp | 6 ++-- .../goblin_recursive_verifier.test.cpp | 35 +++++++++++++++++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index 26f5860dd18..a4243cc8981 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -68,7 +68,7 @@ class ECCVMProver { ZKData zk_sumcheck_data; FF evaluation_challenge_x; - FF translation_batching_challenge_v; // to be rederived by the translator verifier + FF translation_batching_challenge_v; SumcheckOutput sumcheck_output; }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp index d18753face9..1ded2e85213 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.cpp @@ -19,10 +19,8 @@ GoblinRecursiveVerifierOutput GoblinRecursiveVerifier::verify(const GoblinProof& verification_keys.translator_verification_key, eccvm_verifier.transcript }; - auto evaluation_challenge_x = TranslatorBF::from_witness(builder, proof.evaluation_challenge_x); - auto batching_challenge_v = TranslatorBF::from_witness(builder, proof.batching_challenge_v); - - translator_verifier.verify_proof(proof.translator_proof, evaluation_challenge_x, batching_challenge_v); + translator_verifier.verify_proof( + proof.translator_proof, eccvm_verifier.evaluation_challenge_x, eccvm_verifier.batching_challenge_v); // Verify the consistency between the ECCVM and Translator transcript polynomial evaluations // In reality the Goblin Proof is going to already be a stdlib proof and this conversion is not going to happen here diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index bc3a1574ea6..a57eba3ebd5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -2,6 +2,7 @@ #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_verification_keys_comparator.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" @@ -41,12 +42,11 @@ class GoblinRecursiveVerifierTests : public testing::Test { * * @return ProverOutput */ - ProverOutput create_goblin_prover_output() + ProverOutput create_goblin_prover_output(const size_t NUM_CIRCUITS = 3) { GoblinProver goblin; // Construct and accumulate multiple circuits - size_t NUM_CIRCUITS = 3; for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { auto circuit = construct_mock_circuit(goblin.op_queue); goblin.merge(circuit); // appends a recurisve merge verifier if a merge proof exists @@ -103,6 +103,35 @@ TEST_F(GoblinRecursiveVerifierTests, Basic) } } +TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) +{ + // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit + auto get_blocks = [this](size_t inner_size) + -> std::tuple> { + auto [proof, verifier_input] = create_goblin_prover_output(inner_size); + + Builder builder; + GoblinRecursiveVerifier verifier{ &builder, verifier_input }; + verifier.verify(proof); + + info("Recursive Verifier: num gates = ", builder.num_gates); + + // Construct and verify a proof for the Goblin Recursive Verifier circuit + + auto proving_key = std::make_shared(builder); + OuterProver prover(proving_key); + auto outer_verification_key = std::make_shared(proving_key->proving_key); + OuterVerifier outer_verifier(outer_verification_key); + return { builder.blocks, outer_verification_key }; + }; + + auto [blocks_2, verification_key_2] = get_blocks(2); + auto [blocks_4, verification_key_4] = get_blocks(4); + + compare_ultra_blocks_and_verification_keys({ blocks_2, blocks_4 }, + { verification_key_2, verification_key_4 }); +} + /** * @brief Ensure failure of the goblin recursive verification circuit for a bad ECCVM proof * @@ -196,4 +225,4 @@ TEST_F(GoblinRecursiveVerifierTests, TranslationEvaluationsFailure) EXPECT_FALSE(CircuitChecker::check(builder)); } -} // namespace bb::stdlib::recursion::honk \ No newline at end of file +} // namespace bb::stdlib::recursion::honk From b21a2b291bedd1debaad2c21dd72728e8f0e7fb6 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 20 Feb 2025 15:42:39 +0000 Subject: [PATCH 10/20] fix build --- .../small_subgroup_ipa/small_subgroup_ipa.test.cpp | 2 +- .../goblin_verifier/goblin_recursive_verifier.test.cpp | 1 + .../translator_recursive_verifier.test.cpp | 7 +++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 9d1e2cb7c6c..090f5f93ec4 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -277,7 +277,7 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) } TranslationData translation_data( - RefVector(transcript_polynomials), prover_transcript, ck); + RefVector>(transcript_polynomials), prover_transcript, ck); const FF evaluation_challenge_x = FF::random_element(); const FF batching_challenge_v = FF::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index a57eba3ebd5..87d9b388957 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp @@ -103,6 +103,7 @@ TEST_F(GoblinRecursiveVerifierTests, Basic) } } +// Check that the GoblinRecursiveVerifier circuit does not depend on the inputs. TEST_F(GoblinRecursiveVerifierTests, IndependentVKHash) { // Retrieves the trace blocks (each consisting of a specific gate) from the recursive verifier circuit diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index ff9140b6cb5..4434b8ed0d8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp @@ -29,7 +29,6 @@ template class TranslatorRecursiveTests : public ::te using InnerBF = InnerFlavor::BF; using RecursiveVerifier = TranslatorRecursiveVerifier_; - using TranslatorBF = typename TranslatorRecursiveFlavor_::BF; using OuterBuilder = typename RecursiveFlavor::CircuitBuilder; using OuterFlavor = std::conditional_t, MegaFlavor, UltraFlavor>; @@ -37,6 +36,8 @@ template class TranslatorRecursiveTests : public ::te using OuterVerifier = UltraVerifier_; using OuterDeciderProvingKey = DeciderProvingKey_; + using TranslatorBF = typename TranslatorRecursiveFlavor_::BF; + using Transcript = InnerFlavor::Transcript; static void SetUpTestSuite() { bb::srs::init_crs_factory(bb::srs::get_ignition_crs_path()); } @@ -86,9 +87,7 @@ template class TranslatorRecursiveTests : public ::te auto verification_key = std::make_shared(prover.key->proving_key); RecursiveVerifier verifier{ &outer_circuit, verification_key, transcript }; - verifier.verify_proof(inner_proof, - TranslatorBF::from_witness(&outer_circuit, evaluation_challenge_x), - TranslatorBF::from_witness(&outer_circuit, batching_challenge_v)); + auto pairing_points = verifier.verify_proof(proof, evaluation_challenge_x, batching_challenge_v); info("Recursive Verifier: num gates = ", outer_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit From bcc3284049c8fe75bfda7cdb4314424b51803517 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Thu, 20 Feb 2025 16:04:13 +0000 Subject: [PATCH 11/20] translation labels no longer constexpr to fix build --- barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index a4243cc8981..172dcb6059d 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -54,7 +54,7 @@ class ECCVMProver { TranslationEvaluations translation_evaluations; - static constexpr std::array translation_labels = { + std::array translation_labels = { "Translation:op", "Translation:Px", "Translation:Py", "Translation:z1", "Translation:z2" }; From 7d8e9321713f2304d8592110fbf3d2bf30875e9c Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 24 Feb 2025 11:21:42 +0000 Subject: [PATCH 12/20] renamed constants + docs --- .../commitment_schemes/shplonk/shplemini.hpp | 22 +++---- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 65 +++++++++---------- .../small_subgroup_ipa.test.cpp | 8 +-- .../cpp/src/barretenberg/constants.hpp | 7 +- .../src/barretenberg/eccvm/eccvm_prover.cpp | 25 +++---- .../eccvm/eccvm_translation_data.hpp | 5 +- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 30 ++++----- .../src/barretenberg/eccvm/eccvm_verifier.hpp | 5 +- .../eccvm_recursive_verifier.cpp | 28 ++++---- .../eccvm_recursive_verifier.hpp | 5 +- 10 files changed, 98 insertions(+), 102 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 040c32cce97..01fac868a59 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -31,7 +31,7 @@ template class ShpleminiProver_ { std::span multilinear_challenge, const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, - const std::array& libra_polynomials = {}, + const std::array& libra_polynomials = {}, const std::vector& sumcheck_round_univariates = {}, const std::vector>& sumcheck_round_evaluations = {}, RefSpan concatenated_polynomials = {}, @@ -77,7 +77,7 @@ template class ShpleminiProver_ { template static std::vector compute_libra_opening_claims( const FF gemini_r, - const std::array& libra_polynomials, + const std::array& libra_polynomials, const std::shared_ptr& transcript) { OpeningClaim new_claim; @@ -86,10 +86,10 @@ template class ShpleminiProver_ { static constexpr FF subgroup_generator = Curve::subgroup_generator; - std::array libra_eval_labels = { + std::array libra_eval_labels = { "Libra:concatenation_eval", "Libra:shifted_big_sum_eval", "Libra:big_sum_eval", "Libra:quotient_eval" }; - const std::array evaluation_points = { + const std::array evaluation_points = { gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r }; for (size_t idx = 0; idx < 4; idx++) { @@ -251,7 +251,7 @@ template class ShpleminiVerifier_ { const std::vector gemini_eval_challenge_powers = gemini::powers_of_evaluation_challenge(gemini_evaluation_challenge, CONST_PROOF_SIZE_LOG_N); - std::array libra_evaluations; + std::array libra_evaluations; if (has_zk) { libra_evaluations[0] = transcript->template receive_from_prover("Libra:concatenation_eval"); libra_evaluations[1] = transcript->template receive_from_prover("Libra:shifted_big_sum_eval"); @@ -664,7 +664,7 @@ template class ShpleminiVerifier_ { std::vector& scalars, Fr& constant_term_accumulator, const std::array& libra_commitments, - const std::array& libra_evaluations, + const std::array& libra_evaluations, const Fr& gemini_evaluation_challenge, const Fr& shplonk_batching_challenge, const Fr& shplonk_evaluation_challenge) @@ -682,8 +682,8 @@ template class ShpleminiVerifier_ { } // compute corresponding scalars and the correction to the constant term - std::array denominators; - std::array batching_scalars; + std::array denominators; + std::array batching_scalars; // compute Shplonk denominators and invert them denominators[0] = Fr(1) / (shplonk_evaluation_challenge - gemini_evaluation_challenge); denominators[1] = @@ -693,7 +693,7 @@ template class ShpleminiVerifier_ { // compute the scalars to be multiplied against the commitments [libra_concatenated], [big_sum], [big_sum], and // [libra_quotient] - for (size_t idx = 0; idx < NUM_LIBRA_EVALUATIONS; idx++) { + for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) { Fr scaling_factor = denominators[idx] * shplonk_challenge_power; batching_scalars[idx] = -scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; @@ -763,7 +763,7 @@ template class ShpleminiVerifier_ { // Compute the next power of Shplonk batching challenge \nu Fr shplonk_challenge_power = Fr{ 1 }; - for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_EVALUATIONS; ++j) { + for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_SMALL_IPA_EVALUATIONS; ++j) { shplonk_challenge_power *= shplonk_batching_challenge; } @@ -834,4 +834,4 @@ template class ShpleminiVerifier_ { } }; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index a8df55f6eaa..30ee6c0436d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -120,9 +120,6 @@ template class SmallSubgroupIPAProver { // Quotient of the batched polynomial C(X) by the subgroup vanishing polynomial X^{|H|} - 1 Polynomial batched_quotient; - // Number of small univariate polynomials being batched. - size_t num_wires; - public: SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, @@ -172,9 +169,8 @@ template class SmallSubgroupIPAProver { } } - // A constructor to achieve ZK in TranslationEvaluations + // Construct prover from TranslationData. Used by ECCVMProver. SmallSubgroupIPAProver(TranslationData& translation_data, - const size_t num_wires, const FF evaluation_challenge_x, const FF batching_challenge_v, const FF claimed_ipa_eval, @@ -190,7 +186,6 @@ template class SmallSubgroupIPAProver { , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) , batched_quotient(QUOTIENT_LENGTH) - , num_wires(num_wires) // Number of transcript polynomials { // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has @@ -221,7 +216,7 @@ template class SmallSubgroupIPAProver { } // Getter to pass the witnesses to ShpleminiProver. Big sum polynomial is evaluated at 2 points (and is small) - std::array, NUM_LIBRA_EVALUATIONS> get_witness_polynomials() const + std::array, NUM_SMALL_IPA_EVALUATIONS> get_witness_polynomials() const { return { concatenated_polynomial, big_sum_polynomial, big_sum_polynomial, batched_quotient }; } @@ -275,7 +270,7 @@ template class SmallSubgroupIPAProver { * @details While proving the batched evaluation of the masking term used to blind the ECCVM Transcript wires, the * prover needs to compute the polynomial whose coefficients in the Lagrange basis over the small subgroup are given * by \f$ (1, x , \ldots, x^{MASKING_OFFSET - 1}, v, x \cdot v, \ldots, x^{MASKING_OFFSET - 1}\cdot - * v^{NUM_TRANSCRIPT_WIRES - 1}, 0, \ldots, 0) \f$. + * v^{NUM_TRANSLATION_EVALUATIONS - 1}, 0, \ldots, 0) \f$. * @param evaluation_challenge_x * @param batching_challenge_v */ @@ -283,7 +278,7 @@ template class SmallSubgroupIPAProver { { std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, num_wires); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); @@ -476,17 +471,16 @@ template class SmallSubgroupIPAProver { */ static FF compute_claimed_inner_product(TranslationData& translation_data, const FF& evaluation_challenge_x, - const FF& batching_challenge_v, - const size_t num_wires) + const FF& batching_challenge_v) { FF claimed_inner_product{ 0 }; const std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, num_wires); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { claimed_inner_product += translation_data.concatenated_masking_term_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); } @@ -537,7 +531,7 @@ template class SmallSubgroupIPAVerifier { * @param eval_claim The claimed inner proudct of the coefficients of \f$G\f$ and \f$F\f$. * @return True if the consistency check passes, false otherwise. */ - static bool check_evaluations_consistency(const std::array& libra_evaluations, + static bool check_evaluations_consistency(const std::array& libra_evaluations, const FF& gemini_evaluation_challenge, const std::vector& multilinear_challenge, const FF& inner_product_eval_claim) @@ -592,12 +586,12 @@ template class SmallSubgroupIPAVerifier { }; } - static bool check_eccvm_evaluations_consistency(const std::array& small_ipa_evaluations, - const size_t& num_wires, - const FF& evaluation_challenge, - const FF& evaluation_challenge_x, - const FF& batching_challenge_v, - const FF& inner_product_eval_claim) + static bool check_eccvm_evaluations_consistency( + const std::array& small_ipa_evaluations, + const FF& evaluation_challenge, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v, + const FF& inner_product_eval_claim) { // Compute the evaluation of the vanishing polynomia Z_H(X) at X = gemini_evaluation_challenge @@ -618,7 +612,7 @@ template class SmallSubgroupIPAVerifier { // Construct the challenge polynomial from the evaluation and batching challenges, the verifier has to evaluate // it on its own const std::vector challenge_polynomial_lagrange = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE, num_wires); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small // subgroup @@ -729,37 +723,36 @@ static std::vector compute_challenge_polynomial_coeffs(const std::vector return challenge_polynomial_lagrange; } +/** + * @brief Denote \f$ M = \text{MASKING_OFFSET} \f$ and \f$ N = NUM_SMALL_IPA_EVALUTIONS\f$. Given an evaluation + * challenge \f$ x \f$ and a batching challenge \f$v\f$, compute the polynomial whose coefficients are given by the + * vector \f$ (1, x , x^2 , \ldots, x^{M - 1 }, v\cdot x, \ldots, v^{N-1} \cdot x^{M-2}, v^{N-1}, \cdot x^{M-1}, 0, + * \ldots, 0)\f$ in the Lagrange basis over the Small Subgroup. + * + * @tparam FF + * @param evaluation_challenge_x + * @param batching_challenge_v + * @param subgroup_size + * @return std::vector + */ template std::vector compute_eccvm_challenge_coeffs(const FF& evaluation_challenge_x, const FF& batching_challenge_v, - const size_t& subgroup_size, - const size_t& num_wires) + const size_t& subgroup_size) { - // The result is sized to SUBGROUP_SIZE, with 1 “leading” slot and then - // (1 + masking_offset * num_blocks) <= SUBGROUP_SIZE total elements set. - // The rest remain 0 by default if needed. std::vector coeffs_lagrange_basis(subgroup_size, FF(0)); - // The code in your current method: - // - The first entry is 1 - // - Then for each v_exponent in [0..4], we do a block of length `masking_offset`, - // multiplied by v^v_exponent and powers of x coeffs_lagrange_basis[0] = FF{ 1 }; FF v_power = FF(1); - for (size_t poly_idx = 0; poly_idx < num_wires; poly_idx++) { - // Start index of this block + for (size_t poly_idx = 0; poly_idx < NUM_SMALL_IPA_EVALUATIONS; poly_idx++) { const size_t start = 1 + MASKING_OFFSET * poly_idx; - - // The first element in this block is v^block coeffs_lagrange_basis[start] = v_power; - // Next, fill in powers of x for (size_t idx = start + 1; idx < start + MASKING_OFFSET; idx++) { coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; } - // Move on to next power of v v_power *= batching_challenge_v; } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 090f5f93ec4..27226dd75c7 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -194,7 +194,7 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimple) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - const std::array small_ipa_evaluations = + const std::array small_ipa_evaluations = this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); bool consistency_checked = Verifier::check_evaluations_consistency( @@ -230,13 +230,13 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = + std::array, NUM_SMALL_IPA_EVALUATIONS> witness_polynomials = small_subgroup_ipa_prover.get_witness_polynomials(); // Tamper with witness polynomials witness_polynomials[0].at(0) = FF::random_element(); - const std::array small_ipa_evaluations = + const std::array small_ipa_evaluations = this->evaluate_small_ipa_witnesses(witness_polynomials); bool consistency_checked = Verifier::check_evaluations_consistency( @@ -293,7 +293,7 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) prover_transcript, ck); - const std::array small_ipa_evaluations = + const std::array small_ipa_evaluations = this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index d85f597edc7..0103af3b21a 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -23,5 +23,10 @@ static constexpr uint32_t MAX_DATABUS_SIZE = 10000; static constexpr uint32_t MASKING_OFFSET = 4; // For ZK Flavors: the number of the commitments required by Libra and SmallSubgroupIPA. static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; -static constexpr uint32_t NUM_LIBRA_EVALUATIONS = 4; +// The SmallSubgroupIPA is a sub-protocol used in several Flavors, to prove claimed inner product, the Prover sends 4 +// extra evaluations +static constexpr uint32_t NUM_SMALL_IPA_EVALUATIONS = 4; +// There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between +// ECCVM and Translator +static constexpr uint32_t NUM_TRANSLATION_EVALUATIONS = 5; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index b29223014e0..60d920ca6af 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -203,18 +203,18 @@ ECCVMProof ECCVMProver::construct_proof() ProverOpeningClaim ECCVMProver::reduce_translation_evaluations() { // Collect the polynomials and evaluations to be batched - RefArray univariate_polynomials{ key->polynomials.transcript_op, - key->polynomials.transcript_Px, - key->polynomials.transcript_Py, - key->polynomials.transcript_z1, - key->polynomials.transcript_z2 }; + RefArray translation_polynomials{ key->polynomials.transcript_op, + key->polynomials.transcript_Px, + key->polynomials.transcript_Py, + key->polynomials.transcript_z1, + key->polynomials.transcript_z2 }; // Get the challenge at which we evaluate all transcript polynomials as univariates evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); // Evaluate the transcript polynomials as univariates and add their evaluations at x to the transcript for (auto [eval, poly, label] : - zip_view(translation_evaluations.get_all(), univariate_polynomials, translation_labels)) { + zip_view(translation_evaluations.get_all(), translation_polynomials, translation_labels)) { *eval = poly.evaluate(evaluation_challenge_x); transcript->template send_to_verifier(label, *eval); } @@ -223,15 +223,16 @@ ProverOpeningClaim ECCVMProver::reduce_translation_ translation_batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge_v"); // Construct the batched polynomial and batched evaluation to produce the batched opening claim - Polynomial batched_univariate{ key->circuit_size }; - FF batched_evaluation{ 0 }; + Polynomial batched_translation_univariate{ key->circuit_size }; + FF batched_translation_evaluation{ 0 }; FF batching_scalar = FF(1); - for (auto [polynomial, eval] : zip_view(univariate_polynomials, translation_evaluations.get_all())) { - batched_univariate.add_scaled(polynomial, batching_scalar); - batched_evaluation += *eval * batching_scalar; + for (auto [polynomial, eval] : zip_view(translation_polynomials, translation_evaluations.get_all())) { + batched_translation_univariate.add_scaled(polynomial, batching_scalar); + batched_translation_evaluation += *eval * batching_scalar; batching_scalar *= translation_batching_challenge_v; } - return { .polynomial = batched_univariate, .opening_pair = { evaluation_challenge_x, batched_evaluation } }; + return { .polynomial = batched_translation_univariate, + .opening_pair = { evaluation_challenge_x, batched_translation_evaluation } }; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp index 2d71467fad5..b31a4346890 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp @@ -18,7 +18,6 @@ template class TranslationData { using Polynomial = typename Flavor::Polynomial; using TranslationEvaluations = bb::TranslationEvaluations_; static constexpr size_t SUBGROUP_SIZE = Flavor::Curve::SUBGROUP_SIZE; - static constexpr size_t NUM_TRANSCRIPT_POLYNOMIALS = 5; Polynomial concatenated_masking_term; Polynomial concatenated_masking_term_lagrange; @@ -31,7 +30,7 @@ template class TranslationData { const std::shared_ptr& commitment_key) : concatenated_masking_term(SUBGROUP_SIZE + 2) , concatenated_masking_term_lagrange(SUBGROUP_SIZE) - , constant_term(FF{ 0 }) + , constant_term(FF::random_element()) { // Create interpolation domain interpolation_domain[0] = FF{ 1 }; @@ -61,7 +60,7 @@ template class TranslationData { } // Extract the Lagrange coefficients of the concatenated masking term from the transcript polynomials - for (size_t poly_idx = 0; poly_idx < NUM_TRANSCRIPT_POLYNOMIALS; poly_idx++) { + for (size_t poly_idx = 0; poly_idx < NUM_TRANSLATION_EVALUATIONS; poly_idx++) { for (size_t idx = 0; idx < MASKING_OFFSET; idx++) { size_t idx_to_populate = 1 + poly_idx * MASKING_OFFSET + idx; coeffs_lagrange_subgroup[idx_to_populate] = diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index ed65411bef6..3b2709d5b6d 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -100,13 +100,13 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) PCS::reduce_batch_opening_claim(sumcheck_batch_opening_claims); // Produce the opening claim for batch opening of 'op', 'Px', 'Py', 'z1', and 'z2' wires as univariate polynomials - transcript_commitments = { commitments.transcript_op, - commitments.transcript_Px, - commitments.transcript_Py, - commitments.transcript_z1, - commitments.transcript_z2 }; + translation_commitments = { commitments.transcript_op, + commitments.transcript_Px, + commitments.transcript_Py, + commitments.transcript_z1, + commitments.transcript_z2 }; - const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(transcript_commitments); + const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(translation_commitments); const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -126,17 +126,17 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) * @brief To link the ECCVM Transcript wires 'op', 'Px', 'Py', 'z1', and 'z2' to the accumulator computed by the * translator, we verify their evaluations as univariates. For efficiency reasons, we batch these evaluations. * - * @param transcript_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' + * @param translation_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' * @return OpeningClaim */ OpeningClaim ECCVMVerifier::reduce_verify_translation_evaluations( - const std::array& transcript_commitments) + const std::array& translation_commitments) { evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); // Construct arrays of commitments and evaluations to be batched, the evaluations being received from the prover - std::array transcript_evaluations = { + std::array translation_evaluations = { transcript->template receive_from_prover("Translation:op"), transcript->template receive_from_prover("Translation:Px"), transcript->template receive_from_prover("Translation:Py"), @@ -148,15 +148,15 @@ OpeningClaim ECCVMVerifier::reduce_verify_translati batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge_v"); // Compute the batched commitment and batched evaluation for the univariate opening claim - Commitment batched_commitment = transcript_commitments[0]; - FF batched_transcript_eval = transcript_evaluations[0]; + Commitment batched_commitment = translation_commitments[0]; + FF batched_translation_evaluation = translation_evaluations[0]; FF batching_scalar = batching_challenge_v; - for (size_t idx = 1; idx < NUM_TRANSCRIPT_WIRES; ++idx) { - batched_commitment = batched_commitment + transcript_commitments[idx] * batching_scalar; - batched_transcript_eval += batching_scalar * transcript_evaluations[idx]; + for (size_t idx = 1; idx < NUM_TRANSLATION_EVALUATIONS; ++idx) { + batched_commitment = batched_commitment + translation_commitments[idx] * batching_scalar; + batched_translation_evaluation += batching_scalar * translation_evaluations[idx]; batching_scalar *= batching_challenge_v; } - return { { evaluation_challenge_x, batched_transcript_eval }, batched_commitment }; + return { { evaluation_challenge_x, batched_translation_evaluation }, batched_commitment }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp index 597f4b37406..f057689b2e5 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp @@ -24,11 +24,10 @@ class ECCVMVerifier { bool verify_proof(const ECCVMProof& proof); - static constexpr size_t NUM_TRANSCRIPT_WIRES = 5; - std::array transcript_commitments; + std::array translation_commitments; OpeningClaim reduce_verify_translation_evaluations( - const std::array& transcript_commitments); + const std::array& translation_commitments); std::shared_ptr key; std::map commitments; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index baff48494aa..318e634d4d5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -112,13 +112,13 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) PCS::reduce_batch_opening_claim(sumcheck_batch_opening_claims); // Construct the vector of commitments (needs to be vector for the batch_mul) - const std::vector transcript_commitments = { commitments.transcript_op, - commitments.transcript_Px, - commitments.transcript_Py, - commitments.transcript_z1, - commitments.transcript_z2 }; + const std::vector translation_commitments = { commitments.transcript_op, + commitments.transcript_Px, + commitments.transcript_Py, + commitments.transcript_z1, + commitments.transcript_z2 }; // Reduce the univariate evaluations claims to a single claim to be batched by Shplonk - const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(transcript_commitments); + const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(translation_commitments); // Construct and verify the combined opening claim const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -134,17 +134,17 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) * translator, we verify their evaluations as univariates. For efficiency reasons, we batch these evaluations. * * @tparam Flavor ECCVMRecursiveFlavor_ - * @param transcript_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' + * @param translation_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' * @return OpeningClaim */ template OpeningClaim ECCVMRecursiveVerifier_::reduce_verify_translation_evaluations( - const std::vector& transcript_commitments) + const std::vector& translation_commitments) { evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); // Construct the array of evaluations to be batched, the evaluations being received from the prover - std::array transcript_evaluations = { + std::array translation_evaluations = { transcript->template receive_from_prover("Translation:op"), transcript->template receive_from_prover("Translation:Px"), transcript->template receive_from_prover("Translation:Py"), @@ -156,18 +156,18 @@ OpeningClaim ECCVMRecursiveVerifier_::reduce_ver batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge_v"); // Compute the batched commitment and batched evaluation for the univariate opening claim - auto batched_transcript_eval = transcript_evaluations[0]; + auto batched_translation_evaluation = translation_evaluations[0]; auto batching_scalar = batching_challenge_v; std::vector batching_challenges = { FF::one() }; - for (size_t idx = 1; idx < NUM_TRANSCRIPT_WIRES; ++idx) { - batched_transcript_eval += batching_scalar * transcript_evaluations[idx]; + for (size_t idx = 1; idx < NUM_TRANSLATION_EVALUATIONS; ++idx) { + batched_translation_evaluation += batching_scalar * translation_evaluations[idx]; batching_challenges.emplace_back(batching_scalar); batching_scalar *= batching_challenge_v; } - const Commitment batched_commitment = Commitment::batch_mul(transcript_commitments, batching_challenges); + const Commitment batched_commitment = Commitment::batch_mul(translation_commitments, batching_challenges); - return { { evaluation_challenge_x, batched_transcript_eval }, batched_commitment }; + return { { evaluation_challenge_x, batched_translation_evaluation }, batched_commitment }; }; template class ECCVMRecursiveVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp index 56a106328d9..8ce3007d793 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp @@ -29,10 +29,9 @@ template class ECCVMRecursiveVerifier_ { std::shared_ptr transcript; std::shared_ptr ipa_transcript; - static constexpr size_t NUM_TRANSCRIPT_WIRES = 5; - std::vector transcript_commitments; + std::vector translation_commitments; - OpeningClaim reduce_verify_translation_evaluations(const std::vector& transcript_commitments); + OpeningClaim reduce_verify_translation_evaluations(const std::vector& translation_commitments); // Translation evaluations challenges. They are propagated to the TranslatorVerifier FF evaluation_challenge_x; From 98f29b0390a1256b6428dba1c5b750c5c3eba59d Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 24 Feb 2025 12:09:23 +0000 Subject: [PATCH 13/20] fix build --- .../small_subgroup_ipa/small_subgroup_ipa.test.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 27226dd75c7..5664ff587ef 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -282,11 +282,10 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) const FF evaluation_challenge_x = FF::random_element(); const FF batching_challenge_v = FF::random_element(); - const FF claimed_inner_product = Prover::compute_claimed_inner_product( - translation_data, evaluation_challenge_x, batching_challenge_v, num_wires); + const FF claimed_inner_product = + Prover::compute_claimed_inner_product(translation_data, evaluation_challenge_x, batching_challenge_v); Prover small_subgroup_ipa_prover(translation_data, - num_wires, evaluation_challenge_x, batching_challenge_v, claimed_inner_product, @@ -297,7 +296,6 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, - num_wires, this->evaluation_challenge, evaluation_challenge_x, batching_challenge_v, From 692619f548b5f1e824f704df8e84c32d7aa9f560 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 24 Feb 2025 20:18:07 +0000 Subject: [PATCH 14/20] split small subgroup ipa --- .../small_subgroup_ipa/small_subgroup_ipa.cpp | 465 ++++++++++++++ .../small_subgroup_ipa/small_subgroup_ipa.hpp | 569 ++++-------------- .../small_subgroup_ipa.test.cpp | 4 +- .../eccvm/eccvm_translation_data.hpp | 2 +- 4 files changed, 581 insertions(+), 459 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp new file mode 100644 index 00000000000..e5c0370d1b9 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp @@ -0,0 +1,465 @@ +#include "barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp" +#include "barretenberg/commitment_schemes/utils/test_settings.hpp" +#include "barretenberg/constants.hpp" +#include "barretenberg/ecc/curves/bn254/bn254.hpp" +#include "barretenberg/eccvm/eccvm_flavor.hpp" +#include "barretenberg/eccvm/eccvm_translation_data.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" +#include "barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp" +#include "barretenberg/sumcheck/zk_sumcheck_data.hpp" +#include "barretenberg/translator_vm/translator_flavor.hpp" + +#include +#include + +namespace bb { + +/** + * @brief Small Subgroup IPA Prover for Zero-Knowledge Opening of Libra Polynomials. + * + * @details Implements a less general version of the protocol described in + * [Ariel's HackMD](https://hackmd.io/xYHn1qqvQjey1yJutcuXdg). This version is specialized for making + * commitments and openings of Libra polynomials zero-knowledge. + * + * ### Overview + * + * Let \f$ G \f$ be the masked concatenated Libra polynomial. Without masking, it is defined by concatenating Libra + * constant term and the monomial coefficients of the Libra univariates \f$ g_i \f$ in the Lagrange basis over \f$ H + * \f$. More explicitly, unmasked concatenated Libra polynomial is given by the following vector of coefficients: + * \f[ \big( \text{libra_constant_term}, g_{0,0}, \ldots, g_{0, + * \text{LIBRA_UNIVARIATES_LENGTH} - 1}, \ldots, g_{d-1, 0}, g_{d-1, \text{LIBRA_UNIVARIATES_LENGTH} - 1} \big) \f], + * where \f$ d = \text{log_circuit_size}\f$. + * It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ Z_H(X) \f$ is the vanishing polynomial for \f$ H \f$. + * + * This class enables the prover to: + * + * - Open the commitment to concatenated Libra polynomial with zero-knowledge while proving correctness of the claimed + * inner product. The concatenated polynomial is commited to during the construction of ZKSumcheckData structure. + * + * ### Inputs + * The prover receives: + * - **ZKSumcheckData:** Contains: + * - Monomial coefficients of the masked concatenated Libra polynomial \f$ G \f$. + * - Interpolation domain for a small subgroup \( H \subset \mathbb{F}^\ast \), where \(\mathbb{F} \) is the + * ScalarField of a given curve. + * - **Sumcheck challenges:** \( u_0, \ldots, u_{D-1} \), where \( D = \text{CONST_PROOF_SIZE_LOG_N} \). + * - **Claimed inner product:** \( s = \text{claimed\_ipa\_eval} \), defined as: + * \f[ + * s = \sum_{i=1}^{|H|} F(g^i) G(g^i), + * \f] + * where \( F(X) \) is the ``challenge`` polynomial constructed from the Sumcheck round challenges (see the formula + * below) and \( G(X) \) is the concatenated Libra polynomial. + * + * ### Prover's Construction + * 1. Define a polynomial \( A(X) \), called the **big sum polynomial**, which is analogous to the big product + * polynomial used to prove claims about \f$ \prod_{h\in H} f(h) \cdot g(h) \f$. It is uniquely defined by the + * following: + * - \( A(1) = 0 \), + * - \( A(g^i) = A(g^{i-1}) + F(g^{i-1}) G(g^{i-1}) \) for \( i = 1, \ldots, |H|-1 \). + * 2. Mask \( A(X) \) by adding \( Z_H(X) R(X) \), where \( R(X) \) is a random polynomial of degree 3. + * 3. Commit to \( A(X) \) and send the commitment to the verifier. + * + * ### Key Identity + * \( A(X) \) is honestly constructed, i.e. + * - \f$ A_0 = 0\f$, + * - \f$ A_{i} = A_{i-1} + F_{i-1} * G_{i-1}\f$ (Lagrange coefficients over \f$ H \f$) for \f$ i = 1,\ldots, |H|\f$ + * - \f$ A_{|H|} \f$ is equal to the claimed inner product \f$s\f$. + * if and only if the following identity holds: + * \f[ L_1(X) A(X) + (X - g^{-1}) (A(g \cdot X) - A(X) - + * F(X) G(X)) + L_{|H|}(X) (A(X) - s) = Z_H(X) Q(X), \f] where \( Q(X) \) is the quotient of the left-hand side by \( + * Z_H(X) \). The second summand is the translation of the second condition using the fact that the coefficients of \f$ + * A(gX) \f$ are given by a cyclic shift of the coefficients of \f$ A(X) \f$. + * + * The methods of this class allow the prover to compute \( A(X) \) and \( Q(X) \). + * + * After receiveing a random evaluation challenge \f$ r \f$ , the prover sends \f$ G(r), A(g\cdot r), A(r), Q(r) \f$ to + * the verifier. In our case, \f$ r \f$ is the Gemini evaluation challenge, and this part is taken care of by Shplemini. + */ +template +SmallSubgroupIPAProver::SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, + const std::vector& multivariate_challenge, + const FF claimed_ipa_eval, + std::shared_ptr& transcript, + std::shared_ptr& commitment_key) + : interpolation_domain(zk_sumcheck_data.interpolation_domain) + , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) + , libra_concatenated_lagrange_form(zk_sumcheck_data.libra_concatenated_lagrange_form) + , challenge_polynomial(SUBGROUP_SIZE) + , challenge_polynomial_lagrange(SUBGROUP_SIZE) + , big_sum_polynomial_unmasked(SUBGROUP_SIZE) + , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking + , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) + , batched_quotient(QUOTIENT_LENGTH) + +{ + // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has + // polynomials that may exceed the circuit size. + if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { + commitment_key = std::make_shared(SUBGROUP_SIZE + 3); + } + // Extract the evaluation domain computed by ZKSumcheckData + if constexpr (std::is_same_v) { + bn_evaluation_domain = std::move(zk_sumcheck_data.bn_evaluation_domain); + } + + // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients + compute_challenge_polynomial(multivariate_challenge); + + // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it + compute_big_sum_polynomial(); + + // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 + transcript->template send_to_verifier("Libra:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); + + // Compute C(X) + compute_batched_polynomial(claimed_ipa_eval); + + // Compute Q(X) + compute_batched_quotient(); + + // Send commitment [Q] to the verifier + if (commitment_key) { + transcript->template send_to_verifier("Libra:quotient_commitment", commitment_key->commit(batched_quotient)); + } +} + +// Construct prover from TranslationData. Used by ECCVMProver. +template +SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationData& translation_data, + const FF evaluation_challenge_x, + const FF batching_challenge_v, + const FF claimed_ipa_eval, + std::shared_ptr& transcript, + std::shared_ptr& commitment_key) + : interpolation_domain{} + , concatenated_polynomial(Polynomial(SUBGROUP_SIZE + 2)) + , libra_concatenated_lagrange_form(Polynomial(SUBGROUP_SIZE)) + , challenge_polynomial(SUBGROUP_SIZE) // will have a different form + , challenge_polynomial_lagrange(SUBGROUP_SIZE) + , big_sum_polynomial_unmasked(SUBGROUP_SIZE) + , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking + , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) + , batched_quotient(QUOTIENT_LENGTH) + +{ + if constexpr (IsAnyOf) { + + interpolation_domain = translation_data.interpolation_domain; + concatenated_polynomial = std::move(translation_data.concatenated_masking_term); + libra_concatenated_lagrange_form = std::move(translation_data.concatenated_masking_term_lagrange); + } + // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has + // polynomials that may exceed the circuit size. + if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { + commitment_key = std::make_shared(SUBGROUP_SIZE + 3); + } + + // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients + compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); + + // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it + compute_big_sum_polynomial(); + + // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 + transcript->template send_to_verifier("Translation:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); + + // Compute C(X) + compute_batched_polynomial(claimed_ipa_eval); + + // Compute Q(X) + compute_batched_quotient(); + + // Send commitment [Q] to the verifier + transcript->template send_to_verifier("Translation:quotient_commitment", commitment_key->commit(batched_quotient)); +} + +/** + * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. + * + * This method generates a polynomial in both Lagrange basis and monomial basis from Sumcheck's + * multivariate_challenge vector. The result is stored in `challenge_polynomial_lagrange` and + * `challenge_polynomial`. The former is re-used in the computation of the big sum polynomial A(X) + * + * ### Lagrange Basis + * The Lagrange basis polynomial is constructed as follows: + * - Initialize the first coefficient as `1`. + * - For each challenge index `idx_poly` in the `CONST_PROOF_SIZE_LOG_N` range, compute a sequence of coefficients + * recursively as powers of the corresponding multivariate challenge. + * - Store these coefficients in `coeffs_lagrange_basis`. + * More explicitly, + * \f$ F = (1 , 1 , u_0, \ldots, u_0^{LIBRA_UNIVARIATES_LENGTH-1}, \ldots, 1, u_{D-1}, \ldots, + * u_{D-1}^{LIBRA_UNIVARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. + * + * ### Monomial Basis + * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange + * interpolation. Otherwise, an IFFT is used to convert the Lagrange basis coefficients into monomial basis + * coefficients. + * + * @param multivariate_challenge A vector of field elements used to compute the challenge polynomial. + */ +template +void SmallSubgroupIPAProver::compute_challenge_polynomial(const std::vector& multivariate_challenge) +{ + std::vector coeffs_lagrange_basis = + compute_challenge_polynomial_coeffs(multivariate_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); + + challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); + + // Compute monomial coefficients + if constexpr (!std::is_same_v) { + challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); + } else { + std::vector challenge_polynomial_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft( + coeffs_lagrange_basis.data(), challenge_polynomial_ifft.data(), bn_evaluation_domain); + challenge_polynomial = Polynomial(challenge_polynomial_ifft); + } +} +/** + * @brief Compute a (public) challenge polynomial from the evaluation and batching challenges. + * @details While proving the batched evaluation of the masking term used to blind the ECCVM Transcript wires, the + * prover needs to compute the polynomial whose coefficients in the Lagrange basis over the small subgroup are given + * by \f$ (1, x , \ldots, x^{MASKING_OFFSET - 1}, v, x \cdot v, \ldots, x^{MASKING_OFFSET - 1}\cdot + * v^{NUM_TRANSLATION_EVALUATIONS - 1}, 0, \ldots, 0) \f$. + * @param evaluation_challenge_x + * @param batching_challenge_v + */ +template +void SmallSubgroupIPAProver::compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, + const FF batching_challenge_v) +{ + + std::vector coeffs_lagrange_basis = + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); + + challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); + + // Compute monomial coefficients + challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); +} +/** + * @brief Computes the big sum polynomial A(X) + * + * #### Lagrange Basis + * - First, we recursively compute the coefficients of the unmasked big sum polynomial, i.e. we set the first + * coefficient to `0`. + * - For each i, the coefficient is updated as: + * \f$ \texttt{big_sum_lagrange_coeffs} (g^{i}) = + * \texttt{big_sum_lagrange_coeffs} (g^{i-1}) + + * \texttt{challenge_polynomial_lagrange[prev_idx]} (g^{i-1}) \cdot + * \texttt{libra_concatenated_lagrange_form[prev_idx]} (g^{i-1}) \f$ + * #### Masking Term + * - A random polynomial of degree 2 is generated and added to the Big Sum Polynomial. + * - The masking term is applied as \f$ Z_H(X) \cdot \texttt{masking_term} \f$, where \f$ Z_H(X) \f$ is the + * vanishing polynomial. + * + */ +template void SmallSubgroupIPAProver::compute_big_sum_polynomial() +{ + big_sum_lagrange_coeffs[0] = 0; + + // Compute the big sum coefficients recursively + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + size_t prev_idx = idx - 1; + big_sum_lagrange_coeffs[idx] = + big_sum_lagrange_coeffs[prev_idx] + + challenge_polynomial_lagrange.at(prev_idx) * libra_concatenated_lagrange_form.at(prev_idx); + }; + + // Get the coefficients in the monomial basis + if constexpr (!std::is_same_v) { + big_sum_polynomial_unmasked = Polynomial(interpolation_domain, big_sum_lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector big_sum_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(big_sum_lagrange_coeffs.data(), big_sum_ifft.data(), bn_evaluation_domain); + big_sum_polynomial_unmasked = Polynomial(big_sum_ifft); + } + // Generate random masking_term of degree 2, add Z_H(X) * masking_term + bb::Univariate masking_term = bb::Univariate::get_random(); + big_sum_polynomial += big_sum_polynomial_unmasked; + + for (size_t idx = 0; idx < masking_term.size(); idx++) { + big_sum_polynomial.at(idx) -= masking_term.value_at(idx); + big_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx); + } +}; + +/** + * @brief Compute \f$ L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) \f$, where \f$ g + * \f$ is the fixed generator of \f$ H \f$. + * + */ +template +void SmallSubgroupIPAProver::SmallSubgroupIPAProver::compute_batched_polynomial( + const FF& claimed_evaluation) +{ + // Compute shifted big sum polynomial A(gX) + Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); + + for (size_t idx = 0; idx < SUBGROUP_SIZE + 3; idx++) { + shifted_big_sum.at(idx) = big_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE]; + } + + const auto& [lagrange_first, lagrange_last] = + compute_lagrange_polynomials(interpolation_domain, bn_evaluation_domain); + + // Compute -F(X)*G(X), the negated product of challenge_polynomial and libra_concatenated_monomial_form + for (size_t i = 0; i < concatenated_polynomial.size(); ++i) { + for (size_t j = 0; j < challenge_polynomial.size(); ++j) { + batched_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j); + } + } + + // Compute - F(X) * G(X) + A(gX) - A(X) + for (size_t idx = 0; idx < shifted_big_sum.size(); idx++) { + batched_polynomial.at(idx) += shifted_big_sum.at(idx) - big_sum_polynomial.at(idx); + } + + // Mutiply - F(X) * G(X) + A(gX) - A(X) by X-g: + // 1. Multiply by X + for (size_t idx = batched_polynomial.size() - 1; idx > 0; idx--) { + batched_polynomial.at(idx) = batched_polynomial.at(idx - 1); + } + batched_polynomial.at(0) = FF(0); + // 2. Subtract 1/g(A(gX) - A(X) - F(X) * G(X)) + for (size_t idx = 0; idx < batched_polynomial.size() - 1; idx++) { + batched_polynomial.at(idx) -= batched_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1]; + } + + // Add (L_1 + L_{|H|}) * A(X) to the result + for (size_t i = 0; i < big_sum_polynomial.size(); ++i) { + for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { + batched_polynomial.at(i + j) += big_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j)); + } + } + // Subtract L_{|H|} * s + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_evaluation; + } +} +/** + * @brief Compute monomial coefficients of the first and last Lagrange polynomials + * + * @param interpolation_domain + * @param bn_evaluation_domain + * @return std::array, 2> + */ +template +std::array, 2> SmallSubgroupIPAProver< + Flavor>::compute_lagrange_polynomials(const std::array& interpolation_domain, + const EvaluationDomain& bn_evaluation_domain) +{ + // Compute the monomial coefficients of L_1 + std::array lagrange_coeffs; + lagrange_coeffs[0] = FF(1); + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + lagrange_coeffs[idx] = FF(0); + } + + Polynomial lagrange_first_monomial(SUBGROUP_SIZE); + if constexpr (!std::is_same_v) { + lagrange_first_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector lagrange_first_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_first_ifft.data(), bn_evaluation_domain); + lagrange_first_monomial = Polynomial(lagrange_first_ifft); + } + + // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial + lagrange_coeffs[0] = FF(0); + lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1); + + Polynomial lagrange_last_monomial; + if constexpr (!std::is_same_v) { + lagrange_last_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector lagrange_last_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain); + lagrange_last_monomial = Polynomial(lagrange_last_ifft); + } + + return { lagrange_first_monomial, lagrange_last_monomial }; +} +/** @brief Efficiently compute the quotient of batched_polynomial by Z_H = X ^ { | H | } - 1 + */ +template void SmallSubgroupIPAProver::compute_batched_quotient() +{ + + auto remainder = batched_polynomial; + for (size_t idx = BATCHED_POLYNOMIAL_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) { + batched_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx); + remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx); + } +} + +/** + * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck + * challenges. + * + * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates + * @param multivariate_challenge Sumcheck challenge + * @param log_circuit_size + */ +template +typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_claimed_inner_product( + ZKSumcheckData& zk_sumcheck_data, + const std::vector& multivariate_challenge, + const size_t& log_circuit_size) +{ + const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert(); + // Compute claimed inner product similarly to the SumcheckProver + FF claimed_inner_product = FF{ 0 }; + size_t idx = 0; + for (const auto& univariate : zk_sumcheck_data.libra_univariates) { + claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]); + idx++; + } + // Libra Univariates are mutiplied by the Libra challenge in setup_auxiliary_data(), needs to be undone + claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1)); + claimed_inner_product += zk_sumcheck_data.constant_term; + return claimed_inner_product; +} +/** + * @brief For test purposes: compute the batched evaluation of the last MASKING_OFFSET rows of the ECCVM transcript + * polynomials Op, Px, Py, z1, z2. + * + * @param translation_data Contains concatenated ECCVM Transcript polynomials. + * @param evaluation_challenge_x We evaluate the transcript polynomials at x as univariates. + * @param batching_challenge_v The evaluations at x are batched using v. + */ +template +typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_claimed_translation_inner_product( + TranslationData& translation_data, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v) +{ + FF claimed_inner_product{ 0 }; + if constexpr (IsAnyOf) { + const std::vector coeffs_lagrange_basis = + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); + + Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); + + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + claimed_inner_product += + translation_data.concatenated_masking_term_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); + } + } + return claimed_inner_product; +} + +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; + +// Instantiations used in tests +template class SmallSubgroupIPAProver; +template class SmallSubgroupIPAProver; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 30ee6c0436d..98b67713161 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -1,5 +1,6 @@ #pragma once +#include "barretenberg/commitment_schemes/utils/test_settings.hpp" #include "barretenberg/constants.hpp" #include "barretenberg/ecc/curves/bn254/bn254.hpp" #include "barretenberg/eccvm/eccvm_translation_data.hpp" @@ -13,67 +14,6 @@ namespace bb { -/** - * @brief Small Subgroup IPA Prover for Zero-Knowledge Opening of Libra Polynomials. - * - * @details Implements a less general version of the protocol described in - * [Ariel's HackMD](https://hackmd.io/xYHn1qqvQjey1yJutcuXdg). This version is specialized for making - * commitments and openings of Libra polynomials zero-knowledge. - * - * ### Overview - * - * Let \f$ G \f$ be the masked concatenated Libra polynomial. Without masking, it is defined by concatenating Libra - * constant term and the monomial coefficients of the Libra univariates \f$ g_i \f$ in the Lagrange basis over \f$ H - * \f$. More explicitly, unmasked concatenated Libra polynomial is given by the following vector of coefficients: - * \f[ \big( \text{libra_constant_term}, g_{0,0}, \ldots, g_{0, - * \text{LIBRA_UNIVARIATES_LENGTH} - 1}, \ldots, g_{d-1, 0}, g_{d-1, \text{LIBRA_UNIVARIATES_LENGTH} - 1} \big) \f], - * where \f$ d = \text{log_circuit_size}\f$. - * It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ Z_H(X) \f$ is the vanishing polynomial for \f$ H \f$. - * - * This class enables the prover to: - * - * - Open the commitment to concatenated Libra polynomial with zero-knowledge while proving correctness of the claimed - * inner product. The concatenated polynomial is commited to during the construction of ZKSumcheckData structure. - * - * ### Inputs - * The prover receives: - * - **ZKSumcheckData:** Contains: - * - Monomial coefficients of the masked concatenated Libra polynomial \f$ G \f$. - * - Interpolation domain for a small subgroup \( H \subset \mathbb{F}^\ast \), where \(\mathbb{F} \) is the - * ScalarField of a given curve. - * - **Sumcheck challenges:** \( u_0, \ldots, u_{D-1} \), where \( D = \text{CONST_PROOF_SIZE_LOG_N} \). - * - **Claimed inner product:** \( s = \text{claimed\_ipa\_eval} \), defined as: - * \f[ - * s = \sum_{i=1}^{|H|} F(g^i) G(g^i), - * \f] - * where \( F(X) \) is the ``challenge`` polynomial constructed from the Sumcheck round challenges (see the formula - * below) and \( G(X) \) is the concatenated Libra polynomial. - * - * ### Prover's Construction - * 1. Define a polynomial \( A(X) \), called the **big sum polynomial**, which is analogous to the big product - * polynomial used to prove claims about \f$ \prod_{h\in H} f(h) \cdot g(h) \f$. It is uniquely defined by the - * following: - * - \( A(1) = 0 \), - * - \( A(g^i) = A(g^{i-1}) + F(g^{i-1}) G(g^{i-1}) \) for \( i = 1, \ldots, |H|-1 \). - * 2. Mask \( A(X) \) by adding \( Z_H(X) R(X) \), where \( R(X) \) is a random polynomial of degree 3. - * 3. Commit to \( A(X) \) and send the commitment to the verifier. - * - * ### Key Identity - * \( A(X) \) is honestly constructed, i.e. - * - \f$ A_0 = 0\f$, - * - \f$ A_{i} = A_{i-1} + F_{i-1} * G_{i-1}\f$ (Lagrange coefficients over \f$ H \f$) for \f$ i = 1,\ldots, |H|\f$ - * - \f$ A_{|H|} \f$ is equal to the claimed inner product \f$s\f$. - * if and only if the following identity holds: - * \f[ L_1(X) A(X) + (X - g^{-1}) (A(g \cdot X) - A(X) - - * F(X) G(X)) + L_{|H|}(X) (A(X) - s) = Z_H(X) Q(X), \f] where \( Q(X) \) is the quotient of the left-hand side by \( - * Z_H(X) \). The second summand is the translation of the second condition using the fact that the coefficients of \f$ - * A(gX) \f$ are given by a cyclic shift of the coefficients of \f$ A(X) \f$. - * - * The methods of this class allow the prover to compute \( A(X) \) and \( Q(X) \). - * - * After receiveing a random evaluation challenge \f$ r \f$ , the prover sends \f$ G(r), A(g\cdot r), A(r), Q(r) \f$ to - * the verifier. In our case, \f$ r \f$ is the Gemini evaluation challenge, and this part is taken care of by Shplemini. - */ template class SmallSubgroupIPAProver { using Curve = typename Flavor::Curve; using FF = typename Curve::ScalarField; @@ -125,49 +65,7 @@ template class SmallSubgroupIPAProver { const std::vector& multivariate_challenge, const FF claimed_ipa_eval, std::shared_ptr& transcript, - std::shared_ptr& commitment_key) - : interpolation_domain(zk_sumcheck_data.interpolation_domain) - , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) - , libra_concatenated_lagrange_form(zk_sumcheck_data.libra_concatenated_lagrange_form) - , challenge_polynomial(SUBGROUP_SIZE) - , challenge_polynomial_lagrange(SUBGROUP_SIZE) - , big_sum_polynomial_unmasked(SUBGROUP_SIZE) - , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking - , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) - , batched_quotient(QUOTIENT_LENGTH) - - { - // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has - // polynomials that may exceed the circuit size. - if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { - commitment_key = std::make_shared(SUBGROUP_SIZE + 3); - } - // Extract the evaluation domain computed by ZKSumcheckData - if constexpr (std::is_same_v) { - bn_evaluation_domain = std::move(zk_sumcheck_data.bn_evaluation_domain); - } - - // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients - compute_challenge_polynomial(multivariate_challenge); - - // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it - compute_big_sum_polynomial(); - - // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 - transcript->template send_to_verifier("Libra:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); - - // Compute C(X) - compute_batched_polynomial(claimed_ipa_eval); - - // Compute Q(X) - compute_batched_quotient(); - - // Send commitment [Q] to the verifier - if (commitment_key) { - transcript->template send_to_verifier("Libra:quotient_commitment", - commitment_key->commit(batched_quotient)); - } - } + std::shared_ptr& commitment_key); // Construct prover from TranslationData. Used by ECCVMProver. SmallSubgroupIPAProver(TranslationData& translation_data, @@ -175,45 +73,7 @@ template class SmallSubgroupIPAProver { const FF batching_challenge_v, const FF claimed_ipa_eval, std::shared_ptr& transcript, - std::shared_ptr& commitment_key) - : interpolation_domain(translation_data.interpolation_domain) // need to initialize - , concatenated_polynomial(std::move(translation_data.concatenated_masking_term)) // need to create - , libra_concatenated_lagrange_form( - std::move(translation_data.concatenated_masking_term_lagrange)) // same as above - , challenge_polynomial(SUBGROUP_SIZE) // will have a different form - , challenge_polynomial_lagrange(SUBGROUP_SIZE) - , big_sum_polynomial_unmasked(SUBGROUP_SIZE) - , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking - , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) - , batched_quotient(QUOTIENT_LENGTH) - - { - // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has - // polynomials that may exceed the circuit size. - if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { - commitment_key = std::make_shared(SUBGROUP_SIZE + 3); - } - - // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients - compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); - - // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it - compute_big_sum_polynomial(); - - // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 - transcript->template send_to_verifier("Translation:big_sum_commitment", - commitment_key->commit(big_sum_polynomial)); - - // Compute C(X) - compute_batched_polynomial(claimed_ipa_eval); - - // Compute Q(X) - compute_batched_quotient(); - - // Send commitment [Q] to the verifier - transcript->template send_to_verifier("Translation:quotient_commitment", - commitment_key->commit(batched_quotient)); - } + std::shared_ptr& commitment_key); // Getter to pass the witnesses to ShpleminiProver. Big sum polynomial is evaluated at 2 points (and is small) std::array, NUM_SMALL_IPA_EVALUATIONS> get_witness_polynomials() const @@ -224,311 +84,82 @@ template class SmallSubgroupIPAProver { const Polynomial& get_batched_polynomial() const { return batched_polynomial; } const Polynomial& get_challenge_polynomial() const { return challenge_polynomial; } - /** - * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. - * - * This method generates a polynomial in both Lagrange basis and monomial basis from Sumcheck's - * multivariate_challenge vector. The result is stored in `challenge_polynomial_lagrange` and - * `challenge_polynomial`. The former is re-used in the computation of the big sum polynomial A(X) - * - * ### Lagrange Basis - * The Lagrange basis polynomial is constructed as follows: - * - Initialize the first coefficient as `1`. - * - For each challenge index `idx_poly` in the `CONST_PROOF_SIZE_LOG_N` range, compute a sequence of coefficients - * recursively as powers of the corresponding multivariate challenge. - * - Store these coefficients in `coeffs_lagrange_basis`. - * More explicitly, - * \f$ F = (1 , 1 , u_0, \ldots, u_0^{LIBRA_UNIVARIATES_LENGTH-1}, \ldots, 1, u_{D-1}, \ldots, - * u_{D-1}^{LIBRA_UNIVARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. - * - * ### Monomial Basis - * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange - * interpolation. Otherwise, an IFFT is used to convert the Lagrange basis coefficients into monomial basis - * coefficients. - * - * @param multivariate_challenge A vector of field elements used to compute the challenge polynomial. - */ - void compute_challenge_polynomial(const std::vector& multivariate_challenge) - { - std::vector coeffs_lagrange_basis = - compute_challenge_polynomial_coeffs(multivariate_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); - - challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); - - // Compute monomial coefficients - if constexpr (!std::is_same_v) { - challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); - } else { - std::vector challenge_polynomial_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft( - coeffs_lagrange_basis.data(), challenge_polynomial_ifft.data(), bn_evaluation_domain); - challenge_polynomial = Polynomial(challenge_polynomial_ifft); - } - } - /** - * @brief Compute a (public) challenge polynomial from the evaluation and batching challenges. - * @details While proving the batched evaluation of the masking term used to blind the ECCVM Transcript wires, the - * prover needs to compute the polynomial whose coefficients in the Lagrange basis over the small subgroup are given - * by \f$ (1, x , \ldots, x^{MASKING_OFFSET - 1}, v, x \cdot v, \ldots, x^{MASKING_OFFSET - 1}\cdot - * v^{NUM_TRANSLATION_EVALUATIONS - 1}, 0, \ldots, 0) \f$. - * @param evaluation_challenge_x - * @param batching_challenge_v - */ - void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v) - { - - std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); + void compute_challenge_polynomial(const std::vector& multivariate_challenge); - challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); + void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v); - // Compute monomial coefficients - challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); - } - /** - * @brief Computes the big sum polynomial A(X) - * - * #### Lagrange Basis - * - First, we recursively compute the coefficients of the unmasked big sum polynomial, i.e. we set the first - * coefficient to `0`. - * - For each i, the coefficient is updated as: - * \f$ \texttt{big_sum_lagrange_coeffs} (g^{i}) = - * \texttt{big_sum_lagrange_coeffs} (g^{i-1}) + - * \texttt{challenge_polynomial_lagrange[prev_idx]} (g^{i-1}) \cdot - * \texttt{libra_concatenated_lagrange_form[prev_idx]} (g^{i-1}) \f$ - * #### Masking Term - * - A random polynomial of degree 2 is generated and added to the Big Sum Polynomial. - * - The masking term is applied as \f$ Z_H(X) \cdot \texttt{masking_term} \f$, where \f$ Z_H(X) \f$ is the - * vanishing polynomial. - * - */ - void compute_big_sum_polynomial() - { - big_sum_lagrange_coeffs[0] = 0; - - // Compute the big sum coefficients recursively - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - size_t prev_idx = idx - 1; - big_sum_lagrange_coeffs[idx] = - big_sum_lagrange_coeffs[prev_idx] + - challenge_polynomial_lagrange.at(prev_idx) * libra_concatenated_lagrange_form.at(prev_idx); - }; + void compute_big_sum_polynomial(); - // Get the coefficients in the monomial basis - if constexpr (!std::is_same_v) { - big_sum_polynomial_unmasked = Polynomial(interpolation_domain, big_sum_lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector big_sum_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(big_sum_lagrange_coeffs.data(), big_sum_ifft.data(), bn_evaluation_domain); - big_sum_polynomial_unmasked = Polynomial(big_sum_ifft); - } - // Generate random masking_term of degree 2, add Z_H(X) * masking_term - bb::Univariate masking_term = bb::Univariate::get_random(); - big_sum_polynomial += big_sum_polynomial_unmasked; + void compute_batched_polynomial(const FF& claimed_evaluation); - for (size_t idx = 0; idx < masking_term.size(); idx++) { - big_sum_polynomial.at(idx) -= masking_term.value_at(idx); - big_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx); - } - }; - - /** - * @brief Compute \f$ L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) \f$, where \f$ g - * \f$ is the fixed generator of \f$ H \f$. - * - */ - void compute_batched_polynomial(const FF& claimed_evaluation) - { - // Compute shifted big sum polynomial A(gX) - Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); - - for (size_t idx = 0; idx < SUBGROUP_SIZE + 3; idx++) { - shifted_big_sum.at(idx) = big_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE]; - } - - const auto& [lagrange_first, lagrange_last] = - compute_lagrange_polynomials(interpolation_domain, bn_evaluation_domain); - - // Compute -F(X)*G(X), the negated product of challenge_polynomial and libra_concatenated_monomial_form - for (size_t i = 0; i < concatenated_polynomial.size(); ++i) { - for (size_t j = 0; j < challenge_polynomial.size(); ++j) { - batched_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j); - } - } - - // Compute - F(X) * G(X) + A(gX) - A(X) - for (size_t idx = 0; idx < shifted_big_sum.size(); idx++) { - batched_polynomial.at(idx) += shifted_big_sum.at(idx) - big_sum_polynomial.at(idx); - } - - // Mutiply - F(X) * G(X) + A(gX) - A(X) by X-g: - // 1. Multiply by X - for (size_t idx = batched_polynomial.size() - 1; idx > 0; idx--) { - batched_polynomial.at(idx) = batched_polynomial.at(idx - 1); - } - batched_polynomial.at(0) = FF(0); - // 2. Subtract 1/g(A(gX) - A(X) - F(X) * G(X)) - for (size_t idx = 0; idx < batched_polynomial.size() - 1; idx++) { - batched_polynomial.at(idx) -= batched_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1]; - } - - // Add (L_1 + L_{|H|}) * A(X) to the result - for (size_t i = 0; i < big_sum_polynomial.size(); ++i) { - for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { - batched_polynomial.at(i + j) += big_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j)); - } - } - // Subtract L_{|H|} * s - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_evaluation; - } - } - /** - * @brief Compute monomial coefficients of the first and last Lagrange polynomials - * - * @param interpolation_domain - * @param bn_evaluation_domain - * @return std::array, 2> - */ std::array, 2> static compute_lagrange_polynomials( - const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain) - { - // Compute the monomial coefficients of L_1 - std::array lagrange_coeffs; - lagrange_coeffs[0] = FF(1); - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - lagrange_coeffs[idx] = FF(0); - } - - Polynomial lagrange_first_monomial(SUBGROUP_SIZE); - if constexpr (!std::is_same_v) { - lagrange_first_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector lagrange_first_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_first_ifft.data(), bn_evaluation_domain); - lagrange_first_monomial = Polynomial(lagrange_first_ifft); - } + const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain); - // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial - lagrange_coeffs[0] = FF(0); - lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1); + void compute_batched_quotient(); - Polynomial lagrange_last_monomial; - if constexpr (!std::is_same_v) { - lagrange_last_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector lagrange_last_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain); - lagrange_last_monomial = Polynomial(lagrange_last_ifft); - } - - return { lagrange_first_monomial, lagrange_last_monomial }; - } - /** @brief Efficiently compute the quotient of batched_polynomial by Z_H = X ^ { | H | } - 1 - */ - void compute_batched_quotient() - { - - auto remainder = batched_polynomial; - for (size_t idx = BATCHED_POLYNOMIAL_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) { - batched_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx); - remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx); - } - } - - /** - * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck - * challenges. - * - * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates - * @param multivariate_challenge Sumcheck challenge - * @param log_circuit_size - */ static FF compute_claimed_inner_product(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, - const size_t& log_circuit_size) - { - const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert(); - // Compute claimed inner product similarly to the SumcheckProver - FF claimed_inner_product = FF{ 0 }; - size_t idx = 0; - for (const auto& univariate : zk_sumcheck_data.libra_univariates) { - claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]); - idx++; - } - // Libra Univariates are mutiplied by the Libra challenge in setup_auxiliary_data(), needs to be undone - claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1)); - claimed_inner_product += zk_sumcheck_data.constant_term; - return claimed_inner_product; - } - /** - * @brief For test purposes: compute the batched evaluation of the last MASKING_OFFSET rows of the ECCVM transcript - * polynomials Op, Px, Py, z1, z2. - * - * @param translation_data Contains concatenated ECCVM Transcript polynomials. - * @param evaluation_challenge_x We evaluate the transcript polynomials at x as univariates. - * @param batching_challenge_v The evaluations at x are batched using v. - */ - static FF compute_claimed_inner_product(TranslationData& translation_data, - const FF& evaluation_challenge_x, - const FF& batching_challenge_v) - { - FF claimed_inner_product{ 0 }; - - const std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); + const size_t& log_circuit_size); - Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); - - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - claimed_inner_product += - translation_data.concatenated_masking_term_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); - } - return claimed_inner_product; - } + static FF compute_claimed_translation_inner_product(TranslationData& translation_data, + const FF& evaluation_challenge_x, + const FF& batching_challenge_v); }; /** * @brief Verifier class for Small Subgroup IPA Prover. * - * @details Checks the consistency of polynomial evaluations provided by the prover against - * the values derived from the sumcheck challenge and a random evaluation challenge. + * @details Checks the consistency of polynomial evaluations provided by the + * prover against the values derived from the sumcheck challenge and a + * random evaluation challenge. */ template class SmallSubgroupIPAVerifier { using FF = typename Curve::ScalarField; static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE; - // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we - // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length - // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the - // required length from 23 to 3. + // The length of a random polynomial masking Prover's Sumcheck + // Univariates. In the case of BN254-based Flavors, we send the + // coefficients of the univariates, hence we choose these value to be + // the max sumcheck univariate length over Translator, Ultra, and Mega. + // In ECCVM, the Sumcheck prover will commit to its univariates, which + // reduces the required length from 23 to 3. static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Curve::LIBRA_UNIVARIATES_LENGTH; public: /*! - * @brief Verifies the consistency of polynomial evaluations provided by the prover. + * @brief Verifies the consistency of polynomial evaluations provided by + * the prover. * * @details - * Given a subgroup of \f$ \mathbb{F}^\ast \f$, its generator \f$ g\f$, this function checks whether the following - * equation holds: - * \f[ L_1(r) A(r) + (r - g^{-1}) \left( A(g*r) - A(r) - F(r) G(r) \right) + L_{|H|}(r) \left( A(r) - s - * \right) = T(r) Z_H(r) \f] Where the following are sent by the prover - * - \f$ A(r), A(g\cdot r) \f$ are the evaluation of the "big sum polynomial" - * - \f$ G(r) \f$ is the evaluation of the concatenation of the coefficients of the masking Libra polynomials + * Given a subgroup of \f$ \mathbb{F}^\ast \f$, its generator \f$ g\f$, + * this function checks whether the following equation holds: \f[ L_1(r) + * A(r) + (r - g^{-1}) \left( A(g*r) - A(r) - F(r) G(r) \right) + + * L_{|H|}(r) \left( A(r) - s \right) = T(r) Z_H(r) \f] Where the + * following are sent by the prover + * - \f$ A(r), A(g\cdot r) \f$ are the evaluation of the "big sum + * polynomial" + * - \f$ G(r) \f$ is the evaluation of the concatenation of the + * coefficients of the masking Libra polynomials * - * - \f$ T(r) \f$ is the evaluation of the quotient of the left hand side above by the vanishing polynomial for - * \f$H\f$ - * and the following evaluations computed by the verifier - * - \f$ L_1 \f$ and \f$ L_{|H|} \f$ are the Lagrange polynomials corresponding to \f$ 1 \f$ and \f$ g^{-1} \f$. - * - \f$ F(r) \f$ is the evaluation of the polynomial obtained by concatenating powers of sumcheck round challenges - * - \f$ Z_H(r) \f$ is the vanishing polynomial \f$ X^{|H|} - 1\f$ evaluated at the challenge point. + * - \f$ T(r) \f$ is the evaluation of the quotient of the left hand + * side above by the vanishing polynomial for \f$H\f$ and the following + * evaluations computed by the verifier + * - \f$ L_1 \f$ and \f$ L_{|H|} \f$ are the Lagrange polynomials + * corresponding to \f$ 1 \f$ and \f$ g^{-1} \f$. + * - \f$ F(r) \f$ is the evaluation of the polynomial obtained by + * concatenating powers of sumcheck round challenges + * - \f$ Z_H(r) \f$ is the vanishing polynomial \f$ X^{|H|} - 1\f$ + * evaluated at the challenge point. * - * @param libra_evaluations A vector of polynomial evaluations containing: + * @param libra_evaluations A vector of polynomial evaluations + * containing: * - \f$ G(r), A(g\cdot r), A(r), T(r) \f$. - * @param gemini_evaluation_challenge The challenge point \f$ r \f$ at which evaluations are verified. + * @param gemini_evaluation_challenge The challenge point \f$ r \f$ at + * which evaluations are verified. * @param multilinear_challenge A vector of sumcheck round challenges. - * @param eval_claim The claimed inner proudct of the coefficients of \f$G\f$ and \f$F\f$. + * @param eval_claim The claimed inner proudct of the coefficients of + * \f$G\f$ and \f$F\f$. * @return True if the consistency check passes, false otherwise. */ static bool check_evaluations_consistency(const std::array& libra_evaluations, @@ -537,27 +168,32 @@ template class SmallSubgroupIPAVerifier { const FF& inner_product_eval_claim) { - // Compute the evaluation of the vanishing polynomia Z_H(X) at X = gemini_evaluation_challenge + // Compute the evaluation of the vanishing polynomia Z_H(X) at X = + // gemini_evaluation_challenge const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). + // Handle edge cases in PCS + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). + // Insecure pattern. bool gemini_challenge_in_small_subgroup = false; if constexpr (Curve::is_stdlib_type) { gemini_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); } else { gemini_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); } - // The probability of this event is negligible but it has to be processed correctly + // The probability of this event is negligible but it has to be + // processed correctly if (gemini_challenge_in_small_subgroup) { throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); } - // Construct the challenge polynomial from the sumcheck challenge, the verifier has to evaluate it on its own + // Construct the challenge polynomial from the sumcheck challenge, + // the verifier has to evaluate it on its own const std::vector challenge_polynomial_lagrange = compute_challenge_polynomial_coeffs(multilinear_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); - // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small - // subgroup + // Compute the evaluations of the challenge polynomial, Lagrange + // first, and Lagrange last for the fixed small subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( challenge_polynomial_lagrange, gemini_evaluation_challenge, vanishing_poly_eval); @@ -567,7 +203,8 @@ template class SmallSubgroupIPAVerifier { const FF& quotient_eval = libra_evaluations[3]; // Compute the evaluation of - // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) + // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + + // L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) FF diff = lagrange_first * big_sum_eval; diff += (gemini_evaluation_challenge - Curve::subgroup_generator_inverse) * (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); @@ -579,7 +216,8 @@ template class SmallSubgroupIPAVerifier { diff.self_reduce(); } diff.assert_equal(FF(0)); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). + // Insecure pattern. return (diff.get_value() == FF(0).get_value()); } else { return (diff == FF(0)); @@ -594,28 +232,32 @@ template class SmallSubgroupIPAVerifier { const FF& inner_product_eval_claim) { - // Compute the evaluation of the vanishing polynomia Z_H(X) at X = gemini_evaluation_challenge + // Compute the evaluation of the vanishing polynomia Z_H(X) at X = + // gemini_evaluation_challenge const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). + // Handle edge cases in PCS + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). + // Insecure pattern. bool evaluation_challenge_in_small_subgroup = false; if constexpr (Curve::is_stdlib_type) { evaluation_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); } else { evaluation_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); } - // The probability of this event is negligible but it has to be processed correctly + // The probability of this event is negligible but it has to be + // processed correctly if (evaluation_challenge_in_small_subgroup) { throw_or_abort("Evaluation challenge is in the SmallSubgroup."); } - // Construct the challenge polynomial from the evaluation and batching challenges, the verifier has to evaluate - // it on its own + // Construct the challenge polynomial from the evaluation and + // batching challenges, the verifier has to evaluate it on its own const std::vector challenge_polynomial_lagrange = compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); - // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small - // subgroup + // Compute the evaluations of the challenge polynomial, Lagrange + // first, and Lagrange last for the fixed small subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( challenge_polynomial_lagrange, evaluation_challenge, vanishing_poly_eval); @@ -625,7 +267,8 @@ template class SmallSubgroupIPAVerifier { const FF& quotient_eval = small_ipa_evaluations[3]; // Compute the evaluation of - // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) + // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + + // L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) FF diff = lagrange_first * big_sum_eval; diff += (evaluation_challenge - Curve::subgroup_generator_inverse) * (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); @@ -637,7 +280,8 @@ template class SmallSubgroupIPAVerifier { diff.self_reduce(); } diff.assert_equal(FF(0)); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). + // Insecure pattern. return (diff.get_value() == FF(0).get_value()); } else { return (diff == FF(0)); @@ -645,16 +289,23 @@ template class SmallSubgroupIPAVerifier { } /** - * @brief Efficient batch evaluation of the challenge polynomial, Lagrange first, and Lagrange last + * @brief Efficient batch evaluation of the challenge polynomial, + * Lagrange first, and Lagrange last * - * @details It is a modification of \ref bb::polynomial_arithmetic::compute_barycentric_evaluation - * "compute_barycentric_evaluation" method that does not require EvaluationDomain object and outputs the barycentric - * evaluation of a polynomial along with the evaluations of the first and last Lagrange polynomials. The - * interpolation domain is given by \f$ (1, g, g^2, \ldots, g^{|H| -1 } )\f$ + * @details It is a modification of \ref + * bb::polynomial_arithmetic::compute_barycentric_evaluation + * "compute_barycentric_evaluation" method that does not require + * EvaluationDomain object and outputs the barycentric evaluation of a + * polynomial along with the evaluations of the first and last Lagrange + * polynomials. The interpolation domain is given by \f$ (1, g, g^2, + * \ldots, g^{|H| -1 } )\f$ * - * @param coeffs Coefficients of the polynomial to be evaluated, in our case it is the challenge polynomial - * @param r Evaluation point, we are using the Gemini evaluation challenge - * @param inverse_root_of_unity Inverse of the generator of the subgroup H + * @param coeffs Coefficients of the polynomial to be evaluated, in our + * case it is the challenge polynomial + * @param r Evaluation point, we are using the Gemini evaluation + * challenge + * @param inverse_root_of_unity Inverse of the generator of the subgroup + * H * @return std::array */ static std::array compute_batched_barycentric_evaluations(const std::vector& coeffs, @@ -663,7 +314,8 @@ template class SmallSubgroupIPAVerifier { { FF one = FF{ 1 }; - // Construct the denominators of the Lagrange polynomials evaluated at r + // Construct the denominators of the Lagrange polynomials evaluated + // at r std::array denominators; FF running_power = one; for (size_t i = 0; i < SUBGROUP_SIZE; ++i) { @@ -679,8 +331,9 @@ template class SmallSubgroupIPAVerifier { FF::batch_invert(&denominators[0], SUBGROUP_SIZE); } - // Construct the evaluation of the polynomial using its evaluations over H, Lagrange first evaluated at r, - // Lagrange last evaluated at r + // Construct the evaluation of the polynomial using its evaluations + // over H, Lagrange first evaluated at r, Lagrange last evaluated at + // r FF numerator = vanishing_poly_eval * FF(SUBGROUP_SIZE).invert(); // (r^n - 1) / n std::array result{ std::inner_product(coeffs.begin(), coeffs.end(), denominators.begin(), FF(0)), denominators[0], @@ -692,10 +345,11 @@ template class SmallSubgroupIPAVerifier { }; /** - * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = - * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose - * coefficients are given by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend \f$ D \f$ - * multiplications to construct the coefficients. + * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, + * u_{D-1})\f$, where \f$ D = \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier + * has to construct and evaluate the polynomial whose coefficients are given + * by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend + * \f$ D \f$ multiplications to construct the coefficients. * * @param multivariate_challenge * @return Polynomial @@ -715,7 +369,8 @@ static std::vector compute_challenge_polynomial_coeffs(const std::vector size_t current_idx = 1 + libra_univariates_length * round_idx; // Compute the current index into the vector challenge_polynomial_lagrange[current_idx] = FF(1); for (size_t idx = current_idx + 1; idx < current_idx + libra_univariates_length; idx++) { - // Recursively compute the powers of the challenge up to the length of libra univariates + // Recursively compute the powers of the challenge up to the + // length of libra univariates challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; } round_idx++; @@ -724,10 +379,12 @@ static std::vector compute_challenge_polynomial_coeffs(const std::vector } /** - * @brief Denote \f$ M = \text{MASKING_OFFSET} \f$ and \f$ N = NUM_SMALL_IPA_EVALUTIONS\f$. Given an evaluation - * challenge \f$ x \f$ and a batching challenge \f$v\f$, compute the polynomial whose coefficients are given by the - * vector \f$ (1, x , x^2 , \ldots, x^{M - 1 }, v\cdot x, \ldots, v^{N-1} \cdot x^{M-2}, v^{N-1}, \cdot x^{M-1}, 0, - * \ldots, 0)\f$ in the Lagrange basis over the Small Subgroup. + * @brief Denote \f$ M = \text{MASKING_OFFSET} \f$ and \f$ N = + * NUM_SMALL_IPA_EVALUTIONS\f$. Given an evaluation challenge \f$ x \f$ and + * a batching challenge \f$v\f$, compute the polynomial whose coefficients + * are given by the vector \f$ (1, x , x^2 , \ldots, x^{M - 1 }, v\cdot x, + * \ldots, v^{N-1} \cdot x^{M-2}, v^{N-1}, \cdot x^{M-1}, 0, \ldots, 0)\f$ + * in the Lagrange basis over the Small Subgroup. * * @tparam FF * @param evaluation_challenge_x diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 5664ff587ef..b2f1ed4a370 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -282,8 +282,8 @@ TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) const FF evaluation_challenge_x = FF::random_element(); const FF batching_challenge_v = FF::random_element(); - const FF claimed_inner_product = - Prover::compute_claimed_inner_product(translation_data, evaluation_challenge_x, batching_challenge_v); + const FF claimed_inner_product = Prover::compute_claimed_translation_inner_product( + translation_data, evaluation_challenge_x, batching_challenge_v); Prover small_subgroup_ipa_prover(translation_data, evaluation_challenge_x, diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp index b31a4346890..8166ff00c2d 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp @@ -30,7 +30,7 @@ template class TranslationData { const std::shared_ptr& commitment_key) : concatenated_masking_term(SUBGROUP_SIZE + 2) , concatenated_masking_term_lagrange(SUBGROUP_SIZE) - , constant_term(FF::random_element()) + , constant_term(FF{ 0 }) { // Create interpolation domain interpolation_domain[0] = FF{ 1 }; From a1c3ebe935062913d7aaea2e6442a99d43cc65a7 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 24 Feb 2025 20:39:45 +0000 Subject: [PATCH 15/20] linker fixed --- barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt | 2 +- barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt | 2 +- barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt index 55caefab48f..b49a7f9ded4 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(eccvm sumcheck) \ No newline at end of file +barretenberg_module(eccvm commitment_schemes sumcheck) diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt index 74967d50486..492ba2d5bcd 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(translator_vm sumcheck) \ No newline at end of file +barretenberg_module(translator_vm sumcheck commitment_schemes) diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt index cc7df8118f2..2d4ac70e7ef 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(ultra_honk sumcheck stdlib_primitives stdlib_keccak stdlib_sha256) \ No newline at end of file +barretenberg_module(ultra_honk sumcheck commitment_schemes stdlib_primitives stdlib_keccak stdlib_sha256) From 2eb4c43249bc3ca31f75b7515acaae1c7b9178ab Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 24 Feb 2025 21:31:28 +0000 Subject: [PATCH 16/20] SmallSubgroupIPA Verifier code simplified --- .../small_subgroup_ipa/small_subgroup_ipa.cpp | 10 +- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 139 +++++++----------- 2 files changed, 60 insertions(+), 89 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp index e5c0370d1b9..88db3241675 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp @@ -205,7 +205,7 @@ template void SmallSubgroupIPAProver::compute_challenge_polynomial(const std::vector& multivariate_challenge) { std::vector coeffs_lagrange_basis = - compute_challenge_polynomial_coeffs(multivariate_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); + compute_challenge_polynomial_coeffs(multivariate_challenge); challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); @@ -234,7 +234,7 @@ void SmallSubgroupIPAProver::compute_eccvm_challenge_polynomial(const FF { std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v); challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); @@ -293,9 +293,7 @@ template void SmallSubgroupIPAProver::compute_big_sum_ * \f$ is the fixed generator of \f$ H \f$. * */ -template -void SmallSubgroupIPAProver::SmallSubgroupIPAProver::compute_batched_polynomial( - const FF& claimed_evaluation) +template void SmallSubgroupIPAProver::compute_batched_polynomial(const FF& claimed_evaluation) { // Compute shifted big sum polynomial A(gX) Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); @@ -440,7 +438,7 @@ typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_clai FF claimed_inner_product{ 0 }; if constexpr (IsAnyOf) { const std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v); Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 98b67713161..dcf7f784cb4 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -162,51 +162,27 @@ template class SmallSubgroupIPAVerifier { * \f$G\f$ and \f$F\f$. * @return True if the consistency check passes, false otherwise. */ - static bool check_evaluations_consistency(const std::array& libra_evaluations, - const FF& gemini_evaluation_challenge, - const std::vector& multilinear_challenge, - const FF& inner_product_eval_claim) + static bool check_consistency(const std::array& small_ipa_evaluations, + const FF& small_ipa_eval_challenge, + const std::vector& challenge_polynomial, + const FF& inner_product_eval_claim, + const FF& vanishing_poly_eval) { - - // Compute the evaluation of the vanishing polynomia Z_H(X) at X = - // gemini_evaluation_challenge - const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). - // Handle edge cases in PCS - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). - // Insecure pattern. - bool gemini_challenge_in_small_subgroup = false; - if constexpr (Curve::is_stdlib_type) { - gemini_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); - } else { - gemini_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); - } - // The probability of this event is negligible but it has to be - // processed correctly - if (gemini_challenge_in_small_subgroup) { - throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); - } - // Construct the challenge polynomial from the sumcheck challenge, - // the verifier has to evaluate it on its own - const std::vector challenge_polynomial_lagrange = - compute_challenge_polynomial_coeffs(multilinear_challenge, SUBGROUP_SIZE, LIBRA_UNIVARIATES_LENGTH); - - // Compute the evaluations of the challenge polynomial, Lagrange + handle_edge_cases(vanishing_poly_eval); // first, and Lagrange last for the fixed small subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( - challenge_polynomial_lagrange, gemini_evaluation_challenge, vanishing_poly_eval); + challenge_polynomial, small_ipa_eval_challenge, vanishing_poly_eval); - const FF& concatenated_at_r = libra_evaluations[0]; - const FF& big_sum_shifted_eval = libra_evaluations[1]; - const FF& big_sum_eval = libra_evaluations[2]; - const FF& quotient_eval = libra_evaluations[3]; + const FF& concatenated_at_r = small_ipa_evaluations[0]; + const FF& big_sum_shifted_eval = small_ipa_evaluations[1]; + const FF& big_sum_eval = small_ipa_evaluations[2]; + const FF& quotient_eval = small_ipa_evaluations[3]; // Compute the evaluation of // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + // L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) FF diff = lagrange_first * big_sum_eval; - diff += (gemini_evaluation_challenge - Curve::subgroup_generator_inverse) * + diff += (small_ipa_eval_challenge - Curve::subgroup_generator_inverse) * (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); diff += lagrange_last * (big_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; @@ -222,6 +198,22 @@ template class SmallSubgroupIPAVerifier { } else { return (diff == FF(0)); }; + }; + static bool check_libra_evaluations_consistency(const std::array& libra_evaluations, + const FF& gemini_evaluation_challenge, + const std::vector& multilinear_challenge, + const FF& inner_product_eval_claim) + { + + // Compute the evaluation of the vanishing polynomia Z_H(X) at X = + // gemini_evaluation_challenge + const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); + + return check_consistency(libra_evaluations, + gemini_evaluation_challenge, + compute_challenge_polynomial_coeffs(multilinear_challenge), + inner_product_eval_claim, + vanishing_poly_eval); } static bool check_eccvm_evaluations_consistency( @@ -236,6 +228,21 @@ template class SmallSubgroupIPAVerifier { // gemini_evaluation_challenge const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); + return check_consistency(small_ipa_evaluations, + evaluation_challenge, + compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v), + inner_product_eval_claim, + vanishing_poly_eval); + } + + /** + * @brief Check if the random evaluation challenge is in the SmallSubgroup. + * + * @param vanishing_poly_eval \f$ Z_H(r) = r^{\text{SUBGROUP_SIZE}} \f$. + */ + static void handle_edge_cases(const FF& vanishing_poly_eval) + { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). // Handle edge cases in PCS // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). @@ -251,43 +258,7 @@ template class SmallSubgroupIPAVerifier { if (evaluation_challenge_in_small_subgroup) { throw_or_abort("Evaluation challenge is in the SmallSubgroup."); } - // Construct the challenge polynomial from the evaluation and - // batching challenges, the verifier has to evaluate it on its own - const std::vector challenge_polynomial_lagrange = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v, SUBGROUP_SIZE); - - // Compute the evaluations of the challenge polynomial, Lagrange - // first, and Lagrange last for the fixed small subgroup - auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( - challenge_polynomial_lagrange, evaluation_challenge, vanishing_poly_eval); - - const FF& concatenated_at_r = small_ipa_evaluations[0]; - const FF& big_sum_shifted_eval = small_ipa_evaluations[1]; - const FF& big_sum_eval = small_ipa_evaluations[2]; - const FF& quotient_eval = small_ipa_evaluations[3]; - - // Compute the evaluation of - // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + - // L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) - FF diff = lagrange_first * big_sum_eval; - diff += (evaluation_challenge - Curve::subgroup_generator_inverse) * - (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); - diff += lagrange_last * (big_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; - - if constexpr (Curve::is_stdlib_type) { - if constexpr (std::is_same_v>) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1197) - diff.self_reduce(); - } - diff.assert_equal(FF(0)); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). - // Insecure pattern. - return (diff.get_value() == FF(0).get_value()); - } else { - return (diff == FF(0)); - }; } - /** * @brief Efficient batch evaluation of the challenge polynomial, * Lagrange first, and Lagrange last @@ -354,12 +325,14 @@ template class SmallSubgroupIPAVerifier { * @param multivariate_challenge * @return Polynomial */ -template -static std::vector compute_challenge_polynomial_coeffs(const std::vector& multivariate_challenge, - const size_t subgroup_size, - const size_t libra_univariates_length) +template +static std::vector compute_challenge_polynomial_coeffs( + const std::vector& multivariate_challenge) { - std::vector challenge_polynomial_lagrange(subgroup_size); + using FF = typename Curve::ScalarField; + + std::vector challenge_polynomial_lagrange(Curve::SUBGROUP_SIZE); + static constexpr size_t libra_univariates_length = Curve::LIBRA_UNIVARIATES_LENGTH; challenge_polynomial_lagrange[0] = FF{ 1 }; @@ -392,16 +365,16 @@ static std::vector compute_challenge_polynomial_coeffs(const std::vector * @param subgroup_size * @return std::vector */ -template -std::vector compute_eccvm_challenge_coeffs(const FF& evaluation_challenge_x, - const FF& batching_challenge_v, - const size_t& subgroup_size) +template +std::vector compute_eccvm_challenge_coeffs( + const typename Curve::ScalarField& evaluation_challenge_x, const typename Curve::ScalarField& batching_challenge_v) { - std::vector coeffs_lagrange_basis(subgroup_size, FF(0)); + using FF = typename Curve::ScalarField; + std::vector coeffs_lagrange_basis(Curve::SUBGROUP_SIZE, FF{ 0 }); coeffs_lagrange_basis[0] = FF{ 1 }; - FF v_power = FF(1); + FF v_power = FF{ 1 }; for (size_t poly_idx = 0; poly_idx < NUM_SMALL_IPA_EVALUATIONS; poly_idx++) { const size_t start = 1 + MASKING_OFFSET * poly_idx; coeffs_lagrange_basis[start] = v_power; From 3f95d0dc10f523ec1e1056189713d526e7da7861 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Mon, 24 Feb 2025 21:59:00 +0000 Subject: [PATCH 17/20] more changes in smallsubgroup ipa --- .../commitment_schemes/shplonk/shplemini.hpp | 2 +- .../small_subgroup_ipa/small_subgroup_ipa.cpp | 43 ++++++++----------- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 16 +++---- .../small_subgroup_ipa.test.cpp | 4 +- 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 01fac868a59..f448b36a088 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -373,7 +373,7 @@ template class ShpleminiVerifier_ { shplonk_batching_challenge, shplonk_evaluation_challenge); - *consistency_checked = SmallSubgroupIPAVerifier::check_evaluations_consistency( + *consistency_checked = SmallSubgroupIPAVerifier::check_libra_evaluations_consistency( libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation); } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp index 88db3241675..54a140bafc3 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp @@ -82,10 +82,11 @@ namespace bb { template SmallSubgroupIPAProver::SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, - const FF claimed_ipa_eval, + const FF claimed_inner_product, std::shared_ptr& transcript, std::shared_ptr& commitment_key) - : interpolation_domain(zk_sumcheck_data.interpolation_domain) + : claimed_inner_product(claimed_inner_product) + , interpolation_domain(zk_sumcheck_data.interpolation_domain) , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) , libra_concatenated_lagrange_form(zk_sumcheck_data.libra_concatenated_lagrange_form) , challenge_polynomial(SUBGROUP_SIZE) @@ -94,6 +95,8 @@ SmallSubgroupIPAProver::SmallSubgroupIPAProver(ZKSumcheckData& z , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) , batched_quotient(QUOTIENT_LENGTH) + , transcript(transcript) + , commitment_key(commitment_key) { // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has @@ -108,23 +111,6 @@ SmallSubgroupIPAProver::SmallSubgroupIPAProver(ZKSumcheckData& z // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients compute_challenge_polynomial(multivariate_challenge); - - // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it - compute_big_sum_polynomial(); - - // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 - transcript->template send_to_verifier("Libra:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); - - // Compute C(X) - compute_batched_polynomial(claimed_ipa_eval); - - // Compute Q(X) - compute_batched_quotient(); - - // Send commitment [Q] to the verifier - if (commitment_key) { - transcript->template send_to_verifier("Libra:quotient_commitment", commitment_key->commit(batched_quotient)); - } } // Construct prover from TranslationData. Used by ECCVMProver. @@ -132,18 +118,21 @@ template SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationData& translation_data, const FF evaluation_challenge_x, const FF batching_challenge_v, - const FF claimed_ipa_eval, + const FF claimed_inner_product, std::shared_ptr& transcript, std::shared_ptr& commitment_key) - : interpolation_domain{} + : claimed_inner_product(claimed_inner_product) + , interpolation_domain{} , concatenated_polynomial(Polynomial(SUBGROUP_SIZE + 2)) , libra_concatenated_lagrange_form(Polynomial(SUBGROUP_SIZE)) - , challenge_polynomial(SUBGROUP_SIZE) // will have a different form + , challenge_polynomial(SUBGROUP_SIZE) , challenge_polynomial_lagrange(SUBGROUP_SIZE) , big_sum_polynomial_unmasked(SUBGROUP_SIZE) , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) , batched_quotient(QUOTIENT_LENGTH) + , transcript(transcript) + , commitment_key(commitment_key) { if constexpr (IsAnyOf) { @@ -160,7 +149,10 @@ SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationData void SmallSubgroupIPAProver::prove() +{ // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it compute_big_sum_polynomial(); @@ -168,7 +160,7 @@ SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationDatatemplate send_to_verifier("Translation:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); // Compute C(X) - compute_batched_polynomial(claimed_ipa_eval); + compute_batched_polynomial(); // Compute Q(X) compute_batched_quotient(); @@ -176,7 +168,6 @@ SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationDatatemplate send_to_verifier("Translation:quotient_commitment", commitment_key->commit(batched_quotient)); } - /** * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. * @@ -293,7 +284,7 @@ template void SmallSubgroupIPAProver::compute_big_sum_ * \f$ is the fixed generator of \f$ H \f$. * */ -template void SmallSubgroupIPAProver::compute_batched_polynomial(const FF& claimed_evaluation) +template void SmallSubgroupIPAProver::compute_batched_polynomial() { // Compute shifted big sum polynomial A(gX) Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); @@ -336,7 +327,7 @@ template void SmallSubgroupIPAProver::compute_batched_ } // Subtract L_{|H|} * s for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_evaluation; + batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_inner_product; } } /** diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index dcf7f784cb4..3345bc2150d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -31,6 +31,7 @@ template class SmallSubgroupIPAProver { // Fixed generator of H static constexpr FF subgroup_generator = Curve::subgroup_generator; + FF claimed_inner_product; // Interpolation domain {1, g, \ldots, g^{SUBGROUP_SIZE - 1}} used by ECCVM std::array interpolation_domain; // We use IFFT over BN254 scalar field @@ -41,10 +42,6 @@ template class SmallSubgroupIPAProver { // Lagrange coefficeints of the concatenated Libra masking polynomial = constant_term || g_0 || ... || g_{d-1} Polynomial libra_concatenated_lagrange_form; - // Claimed evaluation s = constant_term + g_0(u_0) + ... + g_{d-1}(u_{d-1}), where g_i is the i'th Libra masking - // univariate - FF claimed_evaluation; - // The polynomial obtained by concatenated powers of sumcheck challenges Polynomial challenge_polynomial; Polynomial challenge_polynomial_lagrange; @@ -60,10 +57,13 @@ template class SmallSubgroupIPAProver { // Quotient of the batched polynomial C(X) by the subgroup vanishing polynomial X^{|H|} - 1 Polynomial batched_quotient; + std::shared_ptr transcript; + std::shared_ptr commitment_key; + public: SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, - const FF claimed_ipa_eval, + const FF claimed_inner_product, std::shared_ptr& transcript, std::shared_ptr& commitment_key); @@ -71,10 +71,10 @@ template class SmallSubgroupIPAProver { SmallSubgroupIPAProver(TranslationData& translation_data, const FF evaluation_challenge_x, const FF batching_challenge_v, - const FF claimed_ipa_eval, + const FF claimed_inner_product, std::shared_ptr& transcript, std::shared_ptr& commitment_key); - + void prove(); // Getter to pass the witnesses to ShpleminiProver. Big sum polynomial is evaluated at 2 points (and is small) std::array, NUM_SMALL_IPA_EVALUATIONS> get_witness_polynomials() const { @@ -90,7 +90,7 @@ template class SmallSubgroupIPAProver { void compute_big_sum_polynomial(); - void compute_batched_polynomial(const FF& claimed_evaluation); + void compute_batched_polynomial(); std::array, 2> static compute_lagrange_polynomials( const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index b2f1ed4a370..d8711fbdb09 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -197,7 +197,7 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimple) const std::array small_ipa_evaluations = this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); - bool consistency_checked = Verifier::check_evaluations_consistency( + bool consistency_checked = Verifier::check_libra_evaluations_consistency( small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); EXPECT_TRUE(consistency_checked); @@ -239,7 +239,7 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) const std::array small_ipa_evaluations = this->evaluate_small_ipa_witnesses(witness_polynomials); - bool consistency_checked = Verifier::check_evaluations_consistency( + bool consistency_checked = Verifier::check_libra_evaluations_consistency( small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); // Since witness polynomials were modified, the consistency check must fail From 1d4102646297ef1afd19a6153fe44e8437aaeea3 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 25 Feb 2025 14:18:03 +0000 Subject: [PATCH 18/20] undo small subgroup ipa --- .../commitment_schemes/shplonk/shplemini.hpp | 22 +- .../small_subgroup_ipa/small_subgroup_ipa.cpp | 454 ------------ .../small_subgroup_ipa/small_subgroup_ipa.hpp | 650 ++++++++++++------ .../small_subgroup_ipa.test.cpp | 100 +-- .../cpp/src/barretenberg/constants.hpp | 4 +- .../cpp/src/barretenberg/eccvm/CMakeLists.txt | 2 +- .../eccvm/eccvm_translation_data.hpp | 89 --- .../barretenberg/translator_vm/CMakeLists.txt | 2 +- .../barretenberg/ultra_honk/CMakeLists.txt | 2 +- 9 files changed, 456 insertions(+), 869 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index f448b36a088..fd25c094fd1 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -31,7 +31,7 @@ template class ShpleminiProver_ { std::span multilinear_challenge, const std::shared_ptr>& commitment_key, const std::shared_ptr& transcript, - const std::array& libra_polynomials = {}, + const std::array& libra_polynomials = {}, const std::vector& sumcheck_round_univariates = {}, const std::vector>& sumcheck_round_evaluations = {}, RefSpan concatenated_polynomials = {}, @@ -77,7 +77,7 @@ template class ShpleminiProver_ { template static std::vector compute_libra_opening_claims( const FF gemini_r, - const std::array& libra_polynomials, + const std::array& libra_polynomials, const std::shared_ptr& transcript) { OpeningClaim new_claim; @@ -86,10 +86,10 @@ template class ShpleminiProver_ { static constexpr FF subgroup_generator = Curve::subgroup_generator; - std::array libra_eval_labels = { + std::array libra_eval_labels = { "Libra:concatenation_eval", "Libra:shifted_big_sum_eval", "Libra:big_sum_eval", "Libra:quotient_eval" }; - const std::array evaluation_points = { + const std::array evaluation_points = { gemini_r, gemini_r * subgroup_generator, gemini_r, gemini_r }; for (size_t idx = 0; idx < 4; idx++) { @@ -251,7 +251,7 @@ template class ShpleminiVerifier_ { const std::vector gemini_eval_challenge_powers = gemini::powers_of_evaluation_challenge(gemini_evaluation_challenge, CONST_PROOF_SIZE_LOG_N); - std::array libra_evaluations; + std::array libra_evaluations; if (has_zk) { libra_evaluations[0] = transcript->template receive_from_prover("Libra:concatenation_eval"); libra_evaluations[1] = transcript->template receive_from_prover("Libra:shifted_big_sum_eval"); @@ -373,7 +373,7 @@ template class ShpleminiVerifier_ { shplonk_batching_challenge, shplonk_evaluation_challenge); - *consistency_checked = SmallSubgroupIPAVerifier::check_libra_evaluations_consistency( + *consistency_checked = SmallSubgroupIPAVerifier::check_evaluations_consistency( libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation); } @@ -664,7 +664,7 @@ template class ShpleminiVerifier_ { std::vector& scalars, Fr& constant_term_accumulator, const std::array& libra_commitments, - const std::array& libra_evaluations, + const std::array& libra_evaluations, const Fr& gemini_evaluation_challenge, const Fr& shplonk_batching_challenge, const Fr& shplonk_evaluation_challenge) @@ -682,8 +682,8 @@ template class ShpleminiVerifier_ { } // compute corresponding scalars and the correction to the constant term - std::array denominators; - std::array batching_scalars; + std::array denominators; + std::array batching_scalars; // compute Shplonk denominators and invert them denominators[0] = Fr(1) / (shplonk_evaluation_challenge - gemini_evaluation_challenge); denominators[1] = @@ -693,7 +693,7 @@ template class ShpleminiVerifier_ { // compute the scalars to be multiplied against the commitments [libra_concatenated], [big_sum], [big_sum], and // [libra_quotient] - for (size_t idx = 0; idx < NUM_SMALL_IPA_EVALUATIONS; idx++) { + for (size_t idx = 0; idx < NUM_LIBRA_EVALUATIONS; idx++) { Fr scaling_factor = denominators[idx] * shplonk_challenge_power; batching_scalars[idx] = -scaling_factor; shplonk_challenge_power *= shplonk_batching_challenge; @@ -763,7 +763,7 @@ template class ShpleminiVerifier_ { // Compute the next power of Shplonk batching challenge \nu Fr shplonk_challenge_power = Fr{ 1 }; - for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_SMALL_IPA_EVALUATIONS; ++j) { + for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_EVALUATIONS; ++j) { shplonk_challenge_power *= shplonk_batching_challenge; } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp deleted file mode 100644 index 54a140bafc3..00000000000 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.cpp +++ /dev/null @@ -1,454 +0,0 @@ -#include "barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp" -#include "barretenberg/commitment_schemes/utils/test_settings.hpp" -#include "barretenberg/constants.hpp" -#include "barretenberg/ecc/curves/bn254/bn254.hpp" -#include "barretenberg/eccvm/eccvm_flavor.hpp" -#include "barretenberg/eccvm/eccvm_translation_data.hpp" -#include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" -#include "barretenberg/stdlib_circuit_builders/mega_zk_flavor.hpp" -#include "barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp" -#include "barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp" -#include "barretenberg/sumcheck/zk_sumcheck_data.hpp" -#include "barretenberg/translator_vm/translator_flavor.hpp" - -#include -#include - -namespace bb { - -/** - * @brief Small Subgroup IPA Prover for Zero-Knowledge Opening of Libra Polynomials. - * - * @details Implements a less general version of the protocol described in - * [Ariel's HackMD](https://hackmd.io/xYHn1qqvQjey1yJutcuXdg). This version is specialized for making - * commitments and openings of Libra polynomials zero-knowledge. - * - * ### Overview - * - * Let \f$ G \f$ be the masked concatenated Libra polynomial. Without masking, it is defined by concatenating Libra - * constant term and the monomial coefficients of the Libra univariates \f$ g_i \f$ in the Lagrange basis over \f$ H - * \f$. More explicitly, unmasked concatenated Libra polynomial is given by the following vector of coefficients: - * \f[ \big( \text{libra_constant_term}, g_{0,0}, \ldots, g_{0, - * \text{LIBRA_UNIVARIATES_LENGTH} - 1}, \ldots, g_{d-1, 0}, g_{d-1, \text{LIBRA_UNIVARIATES_LENGTH} - 1} \big) \f], - * where \f$ d = \text{log_circuit_size}\f$. - * It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ Z_H(X) \f$ is the vanishing polynomial for \f$ H \f$. - * - * This class enables the prover to: - * - * - Open the commitment to concatenated Libra polynomial with zero-knowledge while proving correctness of the claimed - * inner product. The concatenated polynomial is commited to during the construction of ZKSumcheckData structure. - * - * ### Inputs - * The prover receives: - * - **ZKSumcheckData:** Contains: - * - Monomial coefficients of the masked concatenated Libra polynomial \f$ G \f$. - * - Interpolation domain for a small subgroup \( H \subset \mathbb{F}^\ast \), where \(\mathbb{F} \) is the - * ScalarField of a given curve. - * - **Sumcheck challenges:** \( u_0, \ldots, u_{D-1} \), where \( D = \text{CONST_PROOF_SIZE_LOG_N} \). - * - **Claimed inner product:** \( s = \text{claimed\_ipa\_eval} \), defined as: - * \f[ - * s = \sum_{i=1}^{|H|} F(g^i) G(g^i), - * \f] - * where \( F(X) \) is the ``challenge`` polynomial constructed from the Sumcheck round challenges (see the formula - * below) and \( G(X) \) is the concatenated Libra polynomial. - * - * ### Prover's Construction - * 1. Define a polynomial \( A(X) \), called the **big sum polynomial**, which is analogous to the big product - * polynomial used to prove claims about \f$ \prod_{h\in H} f(h) \cdot g(h) \f$. It is uniquely defined by the - * following: - * - \( A(1) = 0 \), - * - \( A(g^i) = A(g^{i-1}) + F(g^{i-1}) G(g^{i-1}) \) for \( i = 1, \ldots, |H|-1 \). - * 2. Mask \( A(X) \) by adding \( Z_H(X) R(X) \), where \( R(X) \) is a random polynomial of degree 3. - * 3. Commit to \( A(X) \) and send the commitment to the verifier. - * - * ### Key Identity - * \( A(X) \) is honestly constructed, i.e. - * - \f$ A_0 = 0\f$, - * - \f$ A_{i} = A_{i-1} + F_{i-1} * G_{i-1}\f$ (Lagrange coefficients over \f$ H \f$) for \f$ i = 1,\ldots, |H|\f$ - * - \f$ A_{|H|} \f$ is equal to the claimed inner product \f$s\f$. - * if and only if the following identity holds: - * \f[ L_1(X) A(X) + (X - g^{-1}) (A(g \cdot X) - A(X) - - * F(X) G(X)) + L_{|H|}(X) (A(X) - s) = Z_H(X) Q(X), \f] where \( Q(X) \) is the quotient of the left-hand side by \( - * Z_H(X) \). The second summand is the translation of the second condition using the fact that the coefficients of \f$ - * A(gX) \f$ are given by a cyclic shift of the coefficients of \f$ A(X) \f$. - * - * The methods of this class allow the prover to compute \( A(X) \) and \( Q(X) \). - * - * After receiveing a random evaluation challenge \f$ r \f$ , the prover sends \f$ G(r), A(g\cdot r), A(r), Q(r) \f$ to - * the verifier. In our case, \f$ r \f$ is the Gemini evaluation challenge, and this part is taken care of by Shplemini. - */ -template -SmallSubgroupIPAProver::SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, - const std::vector& multivariate_challenge, - const FF claimed_inner_product, - std::shared_ptr& transcript, - std::shared_ptr& commitment_key) - : claimed_inner_product(claimed_inner_product) - , interpolation_domain(zk_sumcheck_data.interpolation_domain) - , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) - , libra_concatenated_lagrange_form(zk_sumcheck_data.libra_concatenated_lagrange_form) - , challenge_polynomial(SUBGROUP_SIZE) - , challenge_polynomial_lagrange(SUBGROUP_SIZE) - , big_sum_polynomial_unmasked(SUBGROUP_SIZE) - , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking - , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) - , batched_quotient(QUOTIENT_LENGTH) - , transcript(transcript) - , commitment_key(commitment_key) - -{ - // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has - // polynomials that may exceed the circuit size. - if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { - commitment_key = std::make_shared(SUBGROUP_SIZE + 3); - } - // Extract the evaluation domain computed by ZKSumcheckData - if constexpr (std::is_same_v) { - bn_evaluation_domain = std::move(zk_sumcheck_data.bn_evaluation_domain); - } - - // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients - compute_challenge_polynomial(multivariate_challenge); -} - -// Construct prover from TranslationData. Used by ECCVMProver. -template -SmallSubgroupIPAProver::SmallSubgroupIPAProver(TranslationData& translation_data, - const FF evaluation_challenge_x, - const FF batching_challenge_v, - const FF claimed_inner_product, - std::shared_ptr& transcript, - std::shared_ptr& commitment_key) - : claimed_inner_product(claimed_inner_product) - , interpolation_domain{} - , concatenated_polynomial(Polynomial(SUBGROUP_SIZE + 2)) - , libra_concatenated_lagrange_form(Polynomial(SUBGROUP_SIZE)) - , challenge_polynomial(SUBGROUP_SIZE) - , challenge_polynomial_lagrange(SUBGROUP_SIZE) - , big_sum_polynomial_unmasked(SUBGROUP_SIZE) - , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking - , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) - , batched_quotient(QUOTIENT_LENGTH) - , transcript(transcript) - , commitment_key(commitment_key) - -{ - if constexpr (IsAnyOf) { - - interpolation_domain = translation_data.interpolation_domain; - concatenated_polynomial = std::move(translation_data.concatenated_masking_term); - libra_concatenated_lagrange_form = std::move(translation_data.concatenated_masking_term_lagrange); - } - // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has - // polynomials that may exceed the circuit size. - if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { - commitment_key = std::make_shared(SUBGROUP_SIZE + 3); - } - - // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients - compute_eccvm_challenge_polynomial(evaluation_challenge_x, batching_challenge_v); -} - -template void SmallSubgroupIPAProver::prove() -{ - // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it - compute_big_sum_polynomial(); - - // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 - transcript->template send_to_verifier("Translation:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); - - // Compute C(X) - compute_batched_polynomial(); - - // Compute Q(X) - compute_batched_quotient(); - - // Send commitment [Q] to the verifier - transcript->template send_to_verifier("Translation:quotient_commitment", commitment_key->commit(batched_quotient)); -} -/** - * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. - * - * This method generates a polynomial in both Lagrange basis and monomial basis from Sumcheck's - * multivariate_challenge vector. The result is stored in `challenge_polynomial_lagrange` and - * `challenge_polynomial`. The former is re-used in the computation of the big sum polynomial A(X) - * - * ### Lagrange Basis - * The Lagrange basis polynomial is constructed as follows: - * - Initialize the first coefficient as `1`. - * - For each challenge index `idx_poly` in the `CONST_PROOF_SIZE_LOG_N` range, compute a sequence of coefficients - * recursively as powers of the corresponding multivariate challenge. - * - Store these coefficients in `coeffs_lagrange_basis`. - * More explicitly, - * \f$ F = (1 , 1 , u_0, \ldots, u_0^{LIBRA_UNIVARIATES_LENGTH-1}, \ldots, 1, u_{D-1}, \ldots, - * u_{D-1}^{LIBRA_UNIVARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. - * - * ### Monomial Basis - * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange - * interpolation. Otherwise, an IFFT is used to convert the Lagrange basis coefficients into monomial basis - * coefficients. - * - * @param multivariate_challenge A vector of field elements used to compute the challenge polynomial. - */ -template -void SmallSubgroupIPAProver::compute_challenge_polynomial(const std::vector& multivariate_challenge) -{ - std::vector coeffs_lagrange_basis = - compute_challenge_polynomial_coeffs(multivariate_challenge); - - challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); - - // Compute monomial coefficients - if constexpr (!std::is_same_v) { - challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); - } else { - std::vector challenge_polynomial_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft( - coeffs_lagrange_basis.data(), challenge_polynomial_ifft.data(), bn_evaluation_domain); - challenge_polynomial = Polynomial(challenge_polynomial_ifft); - } -} -/** - * @brief Compute a (public) challenge polynomial from the evaluation and batching challenges. - * @details While proving the batched evaluation of the masking term used to blind the ECCVM Transcript wires, the - * prover needs to compute the polynomial whose coefficients in the Lagrange basis over the small subgroup are given - * by \f$ (1, x , \ldots, x^{MASKING_OFFSET - 1}, v, x \cdot v, \ldots, x^{MASKING_OFFSET - 1}\cdot - * v^{NUM_TRANSLATION_EVALUATIONS - 1}, 0, \ldots, 0) \f$. - * @param evaluation_challenge_x - * @param batching_challenge_v - */ -template -void SmallSubgroupIPAProver::compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, - const FF batching_challenge_v) -{ - - std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v); - - challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); - - // Compute monomial coefficients - challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); -} -/** - * @brief Computes the big sum polynomial A(X) - * - * #### Lagrange Basis - * - First, we recursively compute the coefficients of the unmasked big sum polynomial, i.e. we set the first - * coefficient to `0`. - * - For each i, the coefficient is updated as: - * \f$ \texttt{big_sum_lagrange_coeffs} (g^{i}) = - * \texttt{big_sum_lagrange_coeffs} (g^{i-1}) + - * \texttt{challenge_polynomial_lagrange[prev_idx]} (g^{i-1}) \cdot - * \texttt{libra_concatenated_lagrange_form[prev_idx]} (g^{i-1}) \f$ - * #### Masking Term - * - A random polynomial of degree 2 is generated and added to the Big Sum Polynomial. - * - The masking term is applied as \f$ Z_H(X) \cdot \texttt{masking_term} \f$, where \f$ Z_H(X) \f$ is the - * vanishing polynomial. - * - */ -template void SmallSubgroupIPAProver::compute_big_sum_polynomial() -{ - big_sum_lagrange_coeffs[0] = 0; - - // Compute the big sum coefficients recursively - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - size_t prev_idx = idx - 1; - big_sum_lagrange_coeffs[idx] = - big_sum_lagrange_coeffs[prev_idx] + - challenge_polynomial_lagrange.at(prev_idx) * libra_concatenated_lagrange_form.at(prev_idx); - }; - - // Get the coefficients in the monomial basis - if constexpr (!std::is_same_v) { - big_sum_polynomial_unmasked = Polynomial(interpolation_domain, big_sum_lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector big_sum_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(big_sum_lagrange_coeffs.data(), big_sum_ifft.data(), bn_evaluation_domain); - big_sum_polynomial_unmasked = Polynomial(big_sum_ifft); - } - // Generate random masking_term of degree 2, add Z_H(X) * masking_term - bb::Univariate masking_term = bb::Univariate::get_random(); - big_sum_polynomial += big_sum_polynomial_unmasked; - - for (size_t idx = 0; idx < masking_term.size(); idx++) { - big_sum_polynomial.at(idx) -= masking_term.value_at(idx); - big_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx); - } -}; - -/** - * @brief Compute \f$ L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) \f$, where \f$ g - * \f$ is the fixed generator of \f$ H \f$. - * - */ -template void SmallSubgroupIPAProver::compute_batched_polynomial() -{ - // Compute shifted big sum polynomial A(gX) - Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); - - for (size_t idx = 0; idx < SUBGROUP_SIZE + 3; idx++) { - shifted_big_sum.at(idx) = big_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE]; - } - - const auto& [lagrange_first, lagrange_last] = - compute_lagrange_polynomials(interpolation_domain, bn_evaluation_domain); - - // Compute -F(X)*G(X), the negated product of challenge_polynomial and libra_concatenated_monomial_form - for (size_t i = 0; i < concatenated_polynomial.size(); ++i) { - for (size_t j = 0; j < challenge_polynomial.size(); ++j) { - batched_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j); - } - } - - // Compute - F(X) * G(X) + A(gX) - A(X) - for (size_t idx = 0; idx < shifted_big_sum.size(); idx++) { - batched_polynomial.at(idx) += shifted_big_sum.at(idx) - big_sum_polynomial.at(idx); - } - - // Mutiply - F(X) * G(X) + A(gX) - A(X) by X-g: - // 1. Multiply by X - for (size_t idx = batched_polynomial.size() - 1; idx > 0; idx--) { - batched_polynomial.at(idx) = batched_polynomial.at(idx - 1); - } - batched_polynomial.at(0) = FF(0); - // 2. Subtract 1/g(A(gX) - A(X) - F(X) * G(X)) - for (size_t idx = 0; idx < batched_polynomial.size() - 1; idx++) { - batched_polynomial.at(idx) -= batched_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1]; - } - - // Add (L_1 + L_{|H|}) * A(X) to the result - for (size_t i = 0; i < big_sum_polynomial.size(); ++i) { - for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { - batched_polynomial.at(i + j) += big_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j)); - } - } - // Subtract L_{|H|} * s - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_inner_product; - } -} -/** - * @brief Compute monomial coefficients of the first and last Lagrange polynomials - * - * @param interpolation_domain - * @param bn_evaluation_domain - * @return std::array, 2> - */ -template -std::array, 2> SmallSubgroupIPAProver< - Flavor>::compute_lagrange_polynomials(const std::array& interpolation_domain, - const EvaluationDomain& bn_evaluation_domain) -{ - // Compute the monomial coefficients of L_1 - std::array lagrange_coeffs; - lagrange_coeffs[0] = FF(1); - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - lagrange_coeffs[idx] = FF(0); - } - - Polynomial lagrange_first_monomial(SUBGROUP_SIZE); - if constexpr (!std::is_same_v) { - lagrange_first_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector lagrange_first_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_first_ifft.data(), bn_evaluation_domain); - lagrange_first_monomial = Polynomial(lagrange_first_ifft); - } - - // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial - lagrange_coeffs[0] = FF(0); - lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1); - - Polynomial lagrange_last_monomial; - if constexpr (!std::is_same_v) { - lagrange_last_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); - } else { - std::vector lagrange_last_ifft(SUBGROUP_SIZE); - polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain); - lagrange_last_monomial = Polynomial(lagrange_last_ifft); - } - - return { lagrange_first_monomial, lagrange_last_monomial }; -} -/** @brief Efficiently compute the quotient of batched_polynomial by Z_H = X ^ { | H | } - 1 - */ -template void SmallSubgroupIPAProver::compute_batched_quotient() -{ - - auto remainder = batched_polynomial; - for (size_t idx = BATCHED_POLYNOMIAL_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) { - batched_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx); - remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx); - } -} - -/** - * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck - * challenges. - * - * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates - * @param multivariate_challenge Sumcheck challenge - * @param log_circuit_size - */ -template -typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_claimed_inner_product( - ZKSumcheckData& zk_sumcheck_data, - const std::vector& multivariate_challenge, - const size_t& log_circuit_size) -{ - const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert(); - // Compute claimed inner product similarly to the SumcheckProver - FF claimed_inner_product = FF{ 0 }; - size_t idx = 0; - for (const auto& univariate : zk_sumcheck_data.libra_univariates) { - claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]); - idx++; - } - // Libra Univariates are mutiplied by the Libra challenge in setup_auxiliary_data(), needs to be undone - claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1)); - claimed_inner_product += zk_sumcheck_data.constant_term; - return claimed_inner_product; -} -/** - * @brief For test purposes: compute the batched evaluation of the last MASKING_OFFSET rows of the ECCVM transcript - * polynomials Op, Px, Py, z1, z2. - * - * @param translation_data Contains concatenated ECCVM Transcript polynomials. - * @param evaluation_challenge_x We evaluate the transcript polynomials at x as univariates. - * @param batching_challenge_v The evaluations at x are batched using v. - */ -template -typename Flavor::Curve::ScalarField SmallSubgroupIPAProver::compute_claimed_translation_inner_product( - TranslationData& translation_data, - const FF& evaluation_challenge_x, - const FF& batching_challenge_v) -{ - FF claimed_inner_product{ 0 }; - if constexpr (IsAnyOf) { - const std::vector coeffs_lagrange_basis = - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v); - - Polynomial challenge_polynomial_lagrange(coeffs_lagrange_basis); - - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - claimed_inner_product += - translation_data.concatenated_masking_term_lagrange.at(idx) * challenge_polynomial_lagrange.at(idx); - } - } - return claimed_inner_product; -} - -template class SmallSubgroupIPAProver; -template class SmallSubgroupIPAProver; -template class SmallSubgroupIPAProver; -template class SmallSubgroupIPAProver; -template class SmallSubgroupIPAProver; - -// Instantiations used in tests -template class SmallSubgroupIPAProver; -template class SmallSubgroupIPAProver; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 3345bc2150d..345d561c1b8 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -1,9 +1,7 @@ #pragma once -#include "barretenberg/commitment_schemes/utils/test_settings.hpp" #include "barretenberg/constants.hpp" #include "barretenberg/ecc/curves/bn254/bn254.hpp" -#include "barretenberg/eccvm/eccvm_translation_data.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" @@ -14,6 +12,67 @@ namespace bb { +/** + * @brief Small Subgroup IPA Prover for Zero-Knowledge Opening of Libra Polynomials. + * + * @details Implements a less general version of the protocol described in + * [Ariel's HackMD](https://hackmd.io/xYHn1qqvQjey1yJutcuXdg). This version is specialized for making + * commitments and openings of Libra polynomials zero-knowledge. + * + * ### Overview + * + * Let \f$ G \f$ be the masked concatenated Libra polynomial. Without masking, it is defined by concatenating Libra + * constant term and the monomial coefficients of the Libra univariates \f$ g_i \f$ in the Lagrange basis over \f$ H + * \f$. More explicitly, unmasked concatenated Libra polynomial is given by the following vector of coefficients: + * \f[ \big( \text{libra_constant_term}, g_{0,0}, \ldots, g_{0, + * \text{LIBRA_UNIVARIATES_LENGTH} - 1}, \ldots, g_{d-1, 0}, g_{d-1, \text{LIBRA_UNIVARIATES_LENGTH} - 1} \big) \f], + * where \f$ d = \text{log_circuit_size}\f$. + * It is masked by adding \f$ (r_0 + r_1 X) Z_{H}(X)\f$, where \f$ Z_H(X) \f$ is the vanishing polynomial for \f$ H \f$. + * + * This class enables the prover to: + * + * - Open the commitment to concatenated Libra polynomial with zero-knowledge while proving correctness of the claimed + * inner product. The concatenated polynomial is commited to during the construction of ZKSumcheckData structure. + * + * ### Inputs + * The prover receives: + * - **ZKSumcheckData:** Contains: + * - Monomial coefficients of the masked concatenated Libra polynomial \f$ G \f$. + * - Interpolation domain for a small subgroup \( H \subset \mathbb{F}^\ast \), where \(\mathbb{F} \) is the + * ScalarField of a given curve. + * - **Sumcheck challenges:** \( u_0, \ldots, u_{D-1} \), where \( D = \text{CONST_PROOF_SIZE_LOG_N} \). + * - **Claimed inner product:** \( s = \text{claimed\_ipa\_eval} \), defined as: + * \f[ + * s = \sum_{i=1}^{|H|} F(g^i) G(g^i), + * \f] + * where \( F(X) \) is the ``challenge`` polynomial constructed from the Sumcheck round challenges (see the formula + * below) and \( G(X) \) is the concatenated Libra polynomial. + * + * ### Prover's Construction + * 1. Define a polynomial \( A(X) \), called the **big sum polynomial**, which is analogous to the big product + * polynomial used to prove claims about \f$ \prod_{h\in H} f(h) \cdot g(h) \f$. It is uniquely defined by the + * following: + * - \( A(1) = 0 \), + * - \( A(g^i) = A(g^{i-1}) + F(g^{i-1}) G(g^{i-1}) \) for \( i = 1, \ldots, |H|-1 \). + * 2. Mask \( A(X) \) by adding \( Z_H(X) R(X) \), where \( R(X) \) is a random polynomial of degree 3. + * 3. Commit to \( A(X) \) and send the commitment to the verifier. + * + * ### Key Identity + * \( A(X) \) is honestly constructed, i.e. + * - \f$ A_0 = 0\f$, + * - \f$ A_{i} = A_{i-1} + F_{i-1} * G_{i-1}\f$ (Lagrange coefficients over \f$ H \f$) for \f$ i = 1,\ldots, |H|\f$ + * - \f$ A_{|H|} \f$ is equal to the claimed inner product \f$s\f$. + * if and only if the following identity holds: + * \f[ L_1(X) A(X) + (X - g^{-1}) (A(g \cdot X) - A(X) - + * F(X) G(X)) + L_{|H|}(X) (A(X) - s) = Z_H(X) Q(X), \f] where \( Q(X) \) is the quotient of the left-hand side by \( + * Z_H(X) \). The second summand is the translation of the second condition using the fact that the coefficients of \f$ + * A(gX) \f$ are given by a cyclic shift of the coefficients of \f$ A(X) \f$. + * + * The methods of this class allow the prover to compute \( A(X) \) and \( Q(X) \). + * + * After receiveing a random evaluation challenge \f$ r \f$ , the prover sends \f$ G(r), A(g\cdot r), A(r), Q(r) \f$ to + * the verifier. In our case, \f$ r \f$ is the Gemini evaluation challenge, and this part is taken care of by Shplemini. + */ template class SmallSubgroupIPAProver { using Curve = typename Flavor::Curve; using FF = typename Curve::ScalarField; @@ -31,7 +90,6 @@ template class SmallSubgroupIPAProver { // Fixed generator of H static constexpr FF subgroup_generator = Curve::subgroup_generator; - FF claimed_inner_product; // Interpolation domain {1, g, \ldots, g^{SUBGROUP_SIZE - 1}} used by ECCVM std::array interpolation_domain; // We use IFFT over BN254 scalar field @@ -42,6 +100,10 @@ template class SmallSubgroupIPAProver { // Lagrange coefficeints of the concatenated Libra masking polynomial = constant_term || g_0 || ... || g_{d-1} Polynomial libra_concatenated_lagrange_form; + // Claimed evaluation s = constant_term + g_0(u_0) + ... + g_{d-1}(u_{d-1}), where g_i is the i'th Libra masking + // univariate + FF claimed_evaluation; + // The polynomial obtained by concatenated powers of sumcheck challenges Polynomial challenge_polynomial; Polynomial challenge_polynomial_lagrange; @@ -57,26 +119,57 @@ template class SmallSubgroupIPAProver { // Quotient of the batched polynomial C(X) by the subgroup vanishing polynomial X^{|H|} - 1 Polynomial batched_quotient; - std::shared_ptr transcript; - std::shared_ptr commitment_key; - public: SmallSubgroupIPAProver(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, - const FF claimed_inner_product, - std::shared_ptr& transcript, - std::shared_ptr& commitment_key); - - // Construct prover from TranslationData. Used by ECCVMProver. - SmallSubgroupIPAProver(TranslationData& translation_data, - const FF evaluation_challenge_x, - const FF batching_challenge_v, - const FF claimed_inner_product, - std::shared_ptr& transcript, - std::shared_ptr& commitment_key); - void prove(); + const FF claimed_ipa_eval, + std::shared_ptr transcript, + std::shared_ptr& commitment_key) + : interpolation_domain(zk_sumcheck_data.interpolation_domain) + , concatenated_polynomial(zk_sumcheck_data.libra_concatenated_monomial_form) + , libra_concatenated_lagrange_form(zk_sumcheck_data.libra_concatenated_lagrange_form) + , challenge_polynomial(SUBGROUP_SIZE) + , challenge_polynomial_lagrange(SUBGROUP_SIZE) + , big_sum_polynomial_unmasked(SUBGROUP_SIZE) + , big_sum_polynomial(SUBGROUP_SIZE + 3) // + 3 to account for masking + , batched_polynomial(BATCHED_POLYNOMIAL_LENGTH) + , batched_quotient(QUOTIENT_LENGTH) + + { + // Reallocate the commitment key if necessary. This is an edge case with SmallSubgroupIPA since it has + // polynomials that may exceed the circuit size. + if (commitment_key->dyadic_size < SUBGROUP_SIZE + 3) { + commitment_key = std::make_shared(SUBGROUP_SIZE + 3); + } + // Extract the evaluation domain computed by ZKSumcheckData + if constexpr (std::is_same_v) { + bn_evaluation_domain = std::move(zk_sumcheck_data.bn_evaluation_domain); + } + + // Construct the challenge polynomial in Lagrange basis, compute its monomial coefficients + compute_challenge_polynomial(multivariate_challenge); + + // Construct unmasked big sum polynomial in Lagrange basis, compute its monomial coefficients and mask it + compute_big_sum_polynomial(); + + // Send masked commitment [A + Z_H * R] to the verifier, where R is of degree 2 + transcript->template send_to_verifier("Libra:big_sum_commitment", commitment_key->commit(big_sum_polynomial)); + + // Compute C(X) + compute_batched_polynomial(claimed_ipa_eval); + + // Compute Q(X) + compute_batched_quotient(); + + // Send commitment [Q] to the verifier + if (commitment_key) { + transcript->template send_to_verifier("Libra:quotient_commitment", + commitment_key->commit(batched_quotient)); + } + } + // Getter to pass the witnesses to ShpleminiProver. Big sum polynomial is evaluated at 2 points (and is small) - std::array, NUM_SMALL_IPA_EVALUATIONS> get_witness_polynomials() const + std::array, NUM_LIBRA_EVALUATIONS> get_witness_polynomials() const { return { concatenated_polynomial, big_sum_polynomial, big_sum_polynomial, batched_quotient }; } @@ -84,105 +177,318 @@ template class SmallSubgroupIPAProver { const Polynomial& get_batched_polynomial() const { return batched_polynomial; } const Polynomial& get_challenge_polynomial() const { return challenge_polynomial; } - void compute_challenge_polynomial(const std::vector& multivariate_challenge); + /** + * @brief Computes the challenge polynomial F(X) based on the provided multivariate challenges. + * + * This method generates a polynomial in both Lagrange basis and monomial basis from Sumcheck's + * multivariate_challenge vector. The result is stored in `challenge_polynomial_lagrange` and + * `challenge_polynomial`. The former is re-used in the computation of the big sum polynomial A(X) + * + * ### Lagrange Basis + * The Lagrange basis polynomial is constructed as follows: + * - Initialize the first coefficient as `1`. + * - For each challenge index `idx_poly` in the `CONST_PROOF_SIZE_LOG_N` range, compute a sequence of coefficients + * recursively as powers of the corresponding multivariate challenge. + * - Store these coefficients in `coeffs_lagrange_basis`. + * More explicitly, + * \f$ F = (1 , 1 , u_0, \ldots, u_0^{LIBRA_UNIVARIATES_LENGTH-1}, \ldots, 1, u_{D-1}, \ldots, + * u_{D-1}^{LIBRA_UNIVARIATES_LENGTH-1} ) \f$ in the Lagrange basis over \f$ H \f$. + * + * ### Monomial Basis + * If the curve is not `BN254`, the monomial polynomial is constructed directly using un-optimized Lagrange + * interpolation. Otherwise, an IFFT is used to convert the Lagrange basis coefficients into monomial basis + * coefficients. + * + * @param multivariate_challenge A vector of field elements used to compute the challenge polynomial. + */ + void compute_challenge_polynomial(const std::vector& multivariate_challenge) + { + std::vector coeffs_lagrange_basis(SUBGROUP_SIZE); + coeffs_lagrange_basis[0] = FF(1); + + for (size_t challenge_idx = 0; challenge_idx < CONST_PROOF_SIZE_LOG_N; challenge_idx++) { + // We concatenate 1 with CONST_PROOF_SIZE_LOG_N Libra Univariates of length LIBRA_UNIVARIATES_LENGTH + const size_t poly_to_concatenate_start = 1 + LIBRA_UNIVARIATES_LENGTH * challenge_idx; + coeffs_lagrange_basis[poly_to_concatenate_start] = FF(1); + for (size_t idx = poly_to_concatenate_start + 1; idx < poly_to_concatenate_start + LIBRA_UNIVARIATES_LENGTH; + idx++) { + // Recursively compute the powers of the challenge + coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * multivariate_challenge[challenge_idx]; + } + } - void compute_eccvm_challenge_polynomial(const FF evaluation_challenge_x, const FF batching_challenge_v); + challenge_polynomial_lagrange = Polynomial(coeffs_lagrange_basis); - void compute_big_sum_polynomial(); + // Compute monomial coefficients + if constexpr (!std::is_same_v) { + challenge_polynomial = Polynomial(interpolation_domain, coeffs_lagrange_basis, SUBGROUP_SIZE); + } else { + std::vector challenge_polynomial_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft( + coeffs_lagrange_basis.data(), challenge_polynomial_ifft.data(), bn_evaluation_domain); + challenge_polynomial = Polynomial(challenge_polynomial_ifft); + } + } + + /** + * @brief Computes the big sum polynomial A(X) + * + * #### Lagrange Basis + * - First, we recursively compute the coefficients of the unmasked big sum polynomial, i.e. we set the first + * coefficient to `0`. + * - For each i, the coefficient is updated as: + * \f$ \texttt{big_sum_lagrange_coeffs} (g^{i}) = + * \texttt{big_sum_lagrange_coeffs} (g^{i-1}) + + * \texttt{challenge_polynomial_lagrange[prev_idx]} (g^{i-1}) \cdot + * \texttt{libra_concatenated_lagrange_form[prev_idx]} (g^{i-1}) \f$ + * #### Masking Term + * - A random polynomial of degree 2 is generated and added to the Big Sum Polynomial. + * - The masking term is applied as \f$ Z_H(X) \cdot \texttt{masking_term} \f$, where \f$ Z_H(X) \f$ is the + * vanishing polynomial. + * + */ + void compute_big_sum_polynomial() + { + big_sum_lagrange_coeffs[0] = 0; + + // Compute the big sum coefficients recursively + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + size_t prev_idx = idx - 1; + big_sum_lagrange_coeffs[idx] = + big_sum_lagrange_coeffs[prev_idx] + + challenge_polynomial_lagrange.at(prev_idx) * libra_concatenated_lagrange_form.at(prev_idx); + }; + + // Get the coefficients in the monomial basis + if constexpr (!std::is_same_v) { + big_sum_polynomial_unmasked = Polynomial(interpolation_domain, big_sum_lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector big_sum_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(big_sum_lagrange_coeffs.data(), big_sum_ifft.data(), bn_evaluation_domain); + big_sum_polynomial_unmasked = Polynomial(big_sum_ifft); + } + // Generate random masking_term of degree 2, add Z_H(X) * masking_term + bb::Univariate masking_term = bb::Univariate::get_random(); + big_sum_polynomial += big_sum_polynomial_unmasked; + + for (size_t idx = 0; idx < masking_term.size(); idx++) { + big_sum_polynomial.at(idx) -= masking_term.value_at(idx); + big_sum_polynomial.at(idx + SUBGROUP_SIZE) += masking_term.value_at(idx); + } + }; + + /** + * @brief Compute \f$ L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) \f$, where \f$ g + * \f$ is the fixed generator of \f$ H \f$. + * + */ + void compute_batched_polynomial(const FF& claimed_evaluation) + { + // Compute shifted big sum polynomial A(gX) + Polynomial shifted_big_sum(SUBGROUP_SIZE + 3); + + for (size_t idx = 0; idx < SUBGROUP_SIZE + 3; idx++) { + shifted_big_sum.at(idx) = big_sum_polynomial.at(idx) * interpolation_domain[idx % SUBGROUP_SIZE]; + } + + const auto& [lagrange_first, lagrange_last] = + compute_lagrange_polynomials(interpolation_domain, bn_evaluation_domain); + + // Compute -F(X)*G(X), the negated product of challenge_polynomial and libra_concatenated_monomial_form + for (size_t i = 0; i < concatenated_polynomial.size(); ++i) { + for (size_t j = 0; j < challenge_polynomial.size(); ++j) { + batched_polynomial.at(i + j) -= concatenated_polynomial.at(i) * challenge_polynomial.at(j); + } + } + + // Compute - F(X) * G(X) + A(gX) - A(X) + for (size_t idx = 0; idx < shifted_big_sum.size(); idx++) { + batched_polynomial.at(idx) += shifted_big_sum.at(idx) - big_sum_polynomial.at(idx); + } - void compute_batched_polynomial(); + // Mutiply - F(X) * G(X) + A(gX) - A(X) by X-g: + // 1. Multiply by X + for (size_t idx = batched_polynomial.size() - 1; idx > 0; idx--) { + batched_polynomial.at(idx) = batched_polynomial.at(idx - 1); + } + batched_polynomial.at(0) = FF(0); + // 2. Subtract 1/g(A(gX) - A(X) - F(X) * G(X)) + for (size_t idx = 0; idx < batched_polynomial.size() - 1; idx++) { + batched_polynomial.at(idx) -= batched_polynomial.at(idx + 1) * interpolation_domain[SUBGROUP_SIZE - 1]; + } + // Add (L_1 + L_{|H|}) * A(X) to the result + for (size_t i = 0; i < big_sum_polynomial.size(); ++i) { + for (size_t j = 0; j < SUBGROUP_SIZE; ++j) { + batched_polynomial.at(i + j) += big_sum_polynomial.at(i) * (lagrange_first.at(j) + lagrange_last.at(j)); + } + } + // Subtract L_{|H|} * s + for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { + batched_polynomial.at(idx) -= lagrange_last.at(idx) * claimed_evaluation; + } + } + /** + * @brief Compute monomial coefficients of the first and last Lagrange polynomials + * + * @param interpolation_domain + * @param bn_evaluation_domain + * @return std::array, 2> + */ std::array, 2> static compute_lagrange_polynomials( - const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain); + const std::array& interpolation_domain, const EvaluationDomain& bn_evaluation_domain) + { + // Compute the monomial coefficients of L_1 + std::array lagrange_coeffs; + lagrange_coeffs[0] = FF(1); + for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { + lagrange_coeffs[idx] = FF(0); + } + + Polynomial lagrange_first_monomial(SUBGROUP_SIZE); + if constexpr (!std::is_same_v) { + lagrange_first_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector lagrange_first_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_first_ifft.data(), bn_evaluation_domain); + lagrange_first_monomial = Polynomial(lagrange_first_ifft); + } - void compute_batched_quotient(); + // Compute the monomial coefficients of L_{|H|}, the last Lagrange polynomial + lagrange_coeffs[0] = FF(0); + lagrange_coeffs[SUBGROUP_SIZE - 1] = FF(1); + Polynomial lagrange_last_monomial; + if constexpr (!std::is_same_v) { + lagrange_last_monomial = Polynomial(interpolation_domain, lagrange_coeffs, SUBGROUP_SIZE); + } else { + std::vector lagrange_last_ifft(SUBGROUP_SIZE); + polynomial_arithmetic::ifft(lagrange_coeffs.data(), lagrange_last_ifft.data(), bn_evaluation_domain); + lagrange_last_monomial = Polynomial(lagrange_last_ifft); + } + + return { lagrange_first_monomial, lagrange_last_monomial }; + } + /** @brief Efficiently compute the quotient of batched_polynomial by Z_H = X ^ { | H | } - 1 + */ + void compute_batched_quotient() + { + + auto remainder = batched_polynomial; + for (size_t idx = BATCHED_POLYNOMIAL_LENGTH - 1; idx >= SUBGROUP_SIZE; idx--) { + batched_quotient.at(idx - SUBGROUP_SIZE) = remainder.at(idx); + remainder.at(idx - SUBGROUP_SIZE) += remainder.at(idx); + } + } + + /** + * @brief For test purposes: Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck + * challenges. + * + * @param zk_sumcheck_data Contains Libra constant term and scaled Libra univariates + * @param multivariate_challenge Sumcheck challenge + * @param log_circuit_size + */ static FF compute_claimed_inner_product(ZKSumcheckData& zk_sumcheck_data, const std::vector& multivariate_challenge, - const size_t& log_circuit_size); - - static FF compute_claimed_translation_inner_product(TranslationData& translation_data, - const FF& evaluation_challenge_x, - const FF& batching_challenge_v); + const size_t& log_circuit_size) + { + const FF libra_challenge_inv = zk_sumcheck_data.libra_challenge.invert(); + // Compute claimed inner product similarly to the SumcheckProver + FF claimed_inner_product = FF{ 0 }; + size_t idx = 0; + for (const auto& univariate : zk_sumcheck_data.libra_univariates) { + claimed_inner_product += univariate.evaluate(multivariate_challenge[idx]); + idx++; + } + // Libra Univariates are mutiplied by the Libra challenge in setup_auxiliary_data(), needs to be undone + claimed_inner_product *= libra_challenge_inv / FF(1 << (log_circuit_size - 1)); + claimed_inner_product += zk_sumcheck_data.constant_term; + return claimed_inner_product; + } }; /** * @brief Verifier class for Small Subgroup IPA Prover. * - * @details Checks the consistency of polynomial evaluations provided by the - * prover against the values derived from the sumcheck challenge and a - * random evaluation challenge. + * @details Checks the consistency of polynomial evaluations provided by the prover against + * the values derived from the sumcheck challenge and a random evaluation challenge. */ template class SmallSubgroupIPAVerifier { using FF = typename Curve::ScalarField; static constexpr size_t SUBGROUP_SIZE = Curve::SUBGROUP_SIZE; - // The length of a random polynomial masking Prover's Sumcheck - // Univariates. In the case of BN254-based Flavors, we send the - // coefficients of the univariates, hence we choose these value to be - // the max sumcheck univariate length over Translator, Ultra, and Mega. - // In ECCVM, the Sumcheck prover will commit to its univariates, which - // reduces the required length from 23 to 3. + // The length of a random polynomial masking Prover's Sumcheck Univariates. In the case of BN254-based Flavors, we + // send the coefficients of the univariates, hence we choose these value to be the max sumcheck univariate length + // over Translator, Ultra, and Mega. In ECCVM, the Sumcheck prover will commit to its univariates, which reduces the + // required length from 23 to 3. static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Curve::LIBRA_UNIVARIATES_LENGTH; public: /*! - * @brief Verifies the consistency of polynomial evaluations provided by - * the prover. + * @brief Verifies the consistency of polynomial evaluations provided by the prover. * * @details - * Given a subgroup of \f$ \mathbb{F}^\ast \f$, its generator \f$ g\f$, - * this function checks whether the following equation holds: \f[ L_1(r) - * A(r) + (r - g^{-1}) \left( A(g*r) - A(r) - F(r) G(r) \right) + - * L_{|H|}(r) \left( A(r) - s \right) = T(r) Z_H(r) \f] Where the - * following are sent by the prover - * - \f$ A(r), A(g\cdot r) \f$ are the evaluation of the "big sum - * polynomial" - * - \f$ G(r) \f$ is the evaluation of the concatenation of the - * coefficients of the masking Libra polynomials + * Given a subgroup of \f$ \mathbb{F}^\ast \f$, its generator \f$ g\f$, this function checks whether the following + * equation holds: + * \f[ L_1(r) A(r) + (r - g^{-1}) \left( A(g*r) - A(r) - F(r) G(r) \right) + L_{|H|}(r) \left( A(r) - s + * \right) = T(r) Z_H(r) \f] Where the following are sent by the prover + * - \f$ A(r), A(g\cdot r) \f$ are the evaluation of the "big sum polynomial" + * - \f$ G(r) \f$ is the evaluation of the concatenation of the coefficients of the masking Libra polynomials * - * - \f$ T(r) \f$ is the evaluation of the quotient of the left hand - * side above by the vanishing polynomial for \f$H\f$ and the following - * evaluations computed by the verifier - * - \f$ L_1 \f$ and \f$ L_{|H|} \f$ are the Lagrange polynomials - * corresponding to \f$ 1 \f$ and \f$ g^{-1} \f$. - * - \f$ F(r) \f$ is the evaluation of the polynomial obtained by - * concatenating powers of sumcheck round challenges - * - \f$ Z_H(r) \f$ is the vanishing polynomial \f$ X^{|H|} - 1\f$ - * evaluated at the challenge point. + * - \f$ T(r) \f$ is the evaluation of the quotient of the left hand side above by the vanishing polynomial for + * \f$H\f$ + * and the following evaluations computed by the verifier + * - \f$ L_1 \f$ and \f$ L_{|H|} \f$ are the Lagrange polynomials corresponding to \f$ 1 \f$ and \f$ g^{-1} \f$. + * - \f$ F(r) \f$ is the evaluation of the polynomial obtained by concatenating powers of sumcheck round challenges + * - \f$ Z_H(r) \f$ is the vanishing polynomial \f$ X^{|H|} - 1\f$ evaluated at the challenge point. * - * @param libra_evaluations A vector of polynomial evaluations - * containing: + * @param libra_evaluations A vector of polynomial evaluations containing: * - \f$ G(r), A(g\cdot r), A(r), T(r) \f$. - * @param gemini_evaluation_challenge The challenge point \f$ r \f$ at - * which evaluations are verified. + * @param gemini_evaluation_challenge The challenge point \f$ r \f$ at which evaluations are verified. * @param multilinear_challenge A vector of sumcheck round challenges. - * @param eval_claim The claimed inner proudct of the coefficients of - * \f$G\f$ and \f$F\f$. + * @param eval_claim The claimed inner proudct of the coefficients of \f$G\f$ and \f$F\f$. * @return True if the consistency check passes, false otherwise. */ - static bool check_consistency(const std::array& small_ipa_evaluations, - const FF& small_ipa_eval_challenge, - const std::vector& challenge_polynomial, - const FF& inner_product_eval_claim, - const FF& vanishing_poly_eval) + static bool check_evaluations_consistency(const std::array& libra_evaluations, + const FF& gemini_evaluation_challenge, + const std::vector& multilinear_challenge, + const FF& inner_product_eval_claim) { - handle_edge_cases(vanishing_poly_eval); - // first, and Lagrange last for the fixed small subgroup + + // Compute the evaluation of the vanishing polynomia Z_H(X) at X = gemini_evaluation_challenge + const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). Handle edge cases in PCS + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. + bool gemini_challenge_in_small_subgroup = false; + if constexpr (Curve::is_stdlib_type) { + gemini_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); + } else { + gemini_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); + } + // The probability of this event is negligible but it has to be processed correctly + if (gemini_challenge_in_small_subgroup) { + throw_or_abort("Gemini evaluation challenge is in the SmallSubgroup."); + } + // Construct the challenge polynomial from the sumcheck challenge, the verifier has to evaluate it on its own + const std::vector challenge_polynomial_lagrange = compute_challenge_polynomial(multilinear_challenge); + + // Compute the evaluations of the challenge polynomial, Lagrange first, and Lagrange last for the fixed small + // subgroup auto [challenge_poly, lagrange_first, lagrange_last] = compute_batched_barycentric_evaluations( - challenge_polynomial, small_ipa_eval_challenge, vanishing_poly_eval); + challenge_polynomial_lagrange, gemini_evaluation_challenge, vanishing_poly_eval); - const FF& concatenated_at_r = small_ipa_evaluations[0]; - const FF& big_sum_shifted_eval = small_ipa_evaluations[1]; - const FF& big_sum_eval = small_ipa_evaluations[2]; - const FF& quotient_eval = small_ipa_evaluations[3]; + const FF& concatenated_at_r = libra_evaluations[0]; + const FF& big_sum_shifted_eval = libra_evaluations[1]; + const FF& big_sum_eval = libra_evaluations[2]; + const FF& quotient_eval = libra_evaluations[3]; // Compute the evaluation of - // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + - // L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) + // L_1(X) * A(X) + (X - 1/g) (A(gX) - A(X) - F(X) G(X)) + L_{|H|}(X)(A(X) - s) - Z_H(X) * Q(X) FF diff = lagrange_first * big_sum_eval; - diff += (small_ipa_eval_challenge - Curve::subgroup_generator_inverse) * + diff += (gemini_evaluation_challenge - Curve::subgroup_generator_inverse) * (big_sum_shifted_eval - big_sum_eval - concatenated_at_r * challenge_poly); diff += lagrange_last * (big_sum_eval - inner_product_eval_claim) - vanishing_poly_eval * quotient_eval; @@ -192,91 +498,53 @@ template class SmallSubgroupIPAVerifier { diff.self_reduce(); } diff.assert_equal(FF(0)); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). - // Insecure pattern. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). Insecure pattern. return (diff.get_value() == FF(0).get_value()); } else { return (diff == FF(0)); }; - }; - static bool check_libra_evaluations_consistency(const std::array& libra_evaluations, - const FF& gemini_evaluation_challenge, - const std::vector& multilinear_challenge, - const FF& inner_product_eval_claim) - { - - // Compute the evaluation of the vanishing polynomia Z_H(X) at X = - // gemini_evaluation_challenge - const FF vanishing_poly_eval = gemini_evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); - - return check_consistency(libra_evaluations, - gemini_evaluation_challenge, - compute_challenge_polynomial_coeffs(multilinear_challenge), - inner_product_eval_claim, - vanishing_poly_eval); - } - - static bool check_eccvm_evaluations_consistency( - const std::array& small_ipa_evaluations, - const FF& evaluation_challenge, - const FF& evaluation_challenge_x, - const FF& batching_challenge_v, - const FF& inner_product_eval_claim) - { - - // Compute the evaluation of the vanishing polynomia Z_H(X) at X = - // gemini_evaluation_challenge - const FF vanishing_poly_eval = evaluation_challenge.pow(SUBGROUP_SIZE) - FF(1); - - return check_consistency(small_ipa_evaluations, - evaluation_challenge, - compute_eccvm_challenge_coeffs(evaluation_challenge_x, batching_challenge_v), - inner_product_eval_claim, - vanishing_poly_eval); } /** - * @brief Check if the random evaluation challenge is in the SmallSubgroup. + * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, u_{D-1})\f$, where \f$ D = + * \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier has to construct and evaluate the polynomial whose + * coefficients are given by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend \f$ D \f$ + * multiplications to construct the coefficients. * - * @param vanishing_poly_eval \f$ Z_H(r) = r^{\text{SUBGROUP_SIZE}} \f$. + * @param multivariate_challenge + * @return Polynomial */ - static void handle_edge_cases(const FF& vanishing_poly_eval) + static std::vector compute_challenge_polynomial(const std::vector& multivariate_challenge) { - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1194). - // Handle edge cases in PCS - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1186). - // Insecure pattern. - bool evaluation_challenge_in_small_subgroup = false; - if constexpr (Curve::is_stdlib_type) { - evaluation_challenge_in_small_subgroup = (vanishing_poly_eval.get_value() == FF(0).get_value()); - } else { - evaluation_challenge_in_small_subgroup = (vanishing_poly_eval == FF(0)); - } - // The probability of this event is negligible but it has to be - // processed correctly - if (evaluation_challenge_in_small_subgroup) { - throw_or_abort("Evaluation challenge is in the SmallSubgroup."); + std::vector challenge_polynomial_lagrange(SUBGROUP_SIZE); + + challenge_polynomial_lagrange[0] = FF{ 1 }; + + // Populate the vector with the powers of the challenges + size_t round_idx = 0; + for (auto challenge : multivariate_challenge) { + size_t current_idx = 1 + LIBRA_UNIVARIATES_LENGTH * round_idx; // Compute the current index into the vector + challenge_polynomial_lagrange[current_idx] = FF(1); + for (size_t idx = current_idx + 1; idx < current_idx + LIBRA_UNIVARIATES_LENGTH; idx++) { + // Recursively compute the powers of the challenge up to the length of libra univariates + challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; + } + round_idx++; } + return challenge_polynomial_lagrange; } + /** - * @brief Efficient batch evaluation of the challenge polynomial, - * Lagrange first, and Lagrange last + * @brief Efficient batch evaluation of the challenge polynomial, Lagrange first, and Lagrange last * - * @details It is a modification of \ref - * bb::polynomial_arithmetic::compute_barycentric_evaluation - * "compute_barycentric_evaluation" method that does not require - * EvaluationDomain object and outputs the barycentric evaluation of a - * polynomial along with the evaluations of the first and last Lagrange - * polynomials. The interpolation domain is given by \f$ (1, g, g^2, - * \ldots, g^{|H| -1 } )\f$ + * @details It is a modification of \ref bb::polynomial_arithmetic::compute_barycentric_evaluation + * "compute_barycentric_evaluation" method that does not require EvaluationDomain object and outputs the barycentric + * evaluation of a polynomial along with the evaluations of the first and last Lagrange polynomials. The + * interpolation domain is given by \f$ (1, g, g^2, \ldots, g^{|H| -1 } )\f$ * - * @param coeffs Coefficients of the polynomial to be evaluated, in our - * case it is the challenge polynomial - * @param r Evaluation point, we are using the Gemini evaluation - * challenge - * @param inverse_root_of_unity Inverse of the generator of the subgroup - * H + * @param coeffs Coefficients of the polynomial to be evaluated, in our case it is the challenge polynomial + * @param r Evaluation point, we are using the Gemini evaluation challenge + * @param inverse_root_of_unity Inverse of the generator of the subgroup H * @return std::array */ static std::array compute_batched_barycentric_evaluations(const std::vector& coeffs, @@ -285,8 +553,7 @@ template class SmallSubgroupIPAVerifier { { FF one = FF{ 1 }; - // Construct the denominators of the Lagrange polynomials evaluated - // at r + // Construct the denominators of the Lagrange polynomials evaluated at r std::array denominators; FF running_power = one; for (size_t i = 0; i < SUBGROUP_SIZE; ++i) { @@ -302,9 +569,8 @@ template class SmallSubgroupIPAVerifier { FF::batch_invert(&denominators[0], SUBGROUP_SIZE); } - // Construct the evaluation of the polynomial using its evaluations - // over H, Lagrange first evaluated at r, Lagrange last evaluated at - // r + // Construct the evaluation of the polynomial using its evaluations over H, Lagrange first evaluated at r, + // Lagrange last evaluated at r FF numerator = vanishing_poly_eval * FF(SUBGROUP_SIZE).invert(); // (r^n - 1) / n std::array result{ std::inner_product(coeffs.begin(), coeffs.end(), denominators.begin(), FF(0)), denominators[0], @@ -314,78 +580,4 @@ template class SmallSubgroupIPAVerifier { return result; } }; - -/** - * @brief Given the sumcheck multivariate challenge \f$ (u_0,\ldots, - * u_{D-1})\f$, where \f$ D = \text{CONST_PROOF_SIZE_LOG_N}\f$, the verifier - * has to construct and evaluate the polynomial whose coefficients are given - * by \f$ (1, u_0, u_0^2, u_1,\ldots, 1, u_{D-1}, u_{D-1}^2) \f$. We spend - * \f$ D \f$ multiplications to construct the coefficients. - * - * @param multivariate_challenge - * @return Polynomial - */ -template -static std::vector compute_challenge_polynomial_coeffs( - const std::vector& multivariate_challenge) -{ - using FF = typename Curve::ScalarField; - - std::vector challenge_polynomial_lagrange(Curve::SUBGROUP_SIZE); - static constexpr size_t libra_univariates_length = Curve::LIBRA_UNIVARIATES_LENGTH; - - challenge_polynomial_lagrange[0] = FF{ 1 }; - - // Populate the vector with the powers of the challenges - size_t round_idx = 0; - for (auto challenge : multivariate_challenge) { - size_t current_idx = 1 + libra_univariates_length * round_idx; // Compute the current index into the vector - challenge_polynomial_lagrange[current_idx] = FF(1); - for (size_t idx = current_idx + 1; idx < current_idx + libra_univariates_length; idx++) { - // Recursively compute the powers of the challenge up to the - // length of libra univariates - challenge_polynomial_lagrange[idx] = challenge_polynomial_lagrange[idx - 1] * challenge; - } - round_idx++; - } - return challenge_polynomial_lagrange; -} - -/** - * @brief Denote \f$ M = \text{MASKING_OFFSET} \f$ and \f$ N = - * NUM_SMALL_IPA_EVALUTIONS\f$. Given an evaluation challenge \f$ x \f$ and - * a batching challenge \f$v\f$, compute the polynomial whose coefficients - * are given by the vector \f$ (1, x , x^2 , \ldots, x^{M - 1 }, v\cdot x, - * \ldots, v^{N-1} \cdot x^{M-2}, v^{N-1}, \cdot x^{M-1}, 0, \ldots, 0)\f$ - * in the Lagrange basis over the Small Subgroup. - * - * @tparam FF - * @param evaluation_challenge_x - * @param batching_challenge_v - * @param subgroup_size - * @return std::vector - */ -template -std::vector compute_eccvm_challenge_coeffs( - const typename Curve::ScalarField& evaluation_challenge_x, const typename Curve::ScalarField& batching_challenge_v) -{ - using FF = typename Curve::ScalarField; - std::vector coeffs_lagrange_basis(Curve::SUBGROUP_SIZE, FF{ 0 }); - - coeffs_lagrange_basis[0] = FF{ 1 }; - - FF v_power = FF{ 1 }; - for (size_t poly_idx = 0; poly_idx < NUM_SMALL_IPA_EVALUATIONS; poly_idx++) { - const size_t start = 1 + MASKING_OFFSET * poly_idx; - coeffs_lagrange_basis[start] = v_power; - - for (size_t idx = start + 1; idx < start + MASKING_OFFSET; idx++) { - coeffs_lagrange_basis[idx] = coeffs_lagrange_basis[idx - 1] * evaluation_challenge_x; - } - - v_power *= batching_challenge_v; - } - - return coeffs_lagrange_basis; -} } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index d8711fbdb09..5c96a0e2624 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -14,8 +14,6 @@ template class SmallSubgroupIPATest : public ::testing::Test { using Transcript = typename Flavor::Transcript; using FF = typename Curve::ScalarField; - static constexpr FF subgroup_generator = Curve::subgroup_generator; - static constexpr size_t log_circuit_size = 7; static constexpr size_t circuit_size = 1ULL << log_circuit_size; @@ -31,16 +29,6 @@ template class SmallSubgroupIPATest : public ::testing::Test { } return multivariate_challenge; } - - // A helper to evaluate the four IPA witness polynomials at x, x*g, x, x - std::array evaluate_small_ipa_witnesses(const std::array, 4>& witness_polynomials) - { - // Hard-coded pattern of evaluation: (x, x*g, x, x) - return { witness_polynomials[0].evaluate(evaluation_challenge), - witness_polynomials[1].evaluate(evaluation_challenge * subgroup_generator), - witness_polynomials[2].evaluate(evaluation_challenge), - witness_polynomials[3].evaluate(evaluation_challenge) }; - } }; using TestFlavors = ::testing::Types; @@ -194,11 +182,18 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimple) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - const std::array small_ipa_evaluations = - this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); + const std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = + small_subgroup_ipa_prover.get_witness_polynomials(); + + std::array libra_evaluations = { + witness_polynomials[0].evaluate(this->evaluation_challenge), + witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), + witness_polynomials[2].evaluate(this->evaluation_challenge), + witness_polynomials[3].evaluate(this->evaluation_challenge) + }; - bool consistency_checked = Verifier::check_libra_evaluations_consistency( - small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); + bool consistency_checked = Verifier::check_evaluations_consistency( + libra_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); EXPECT_TRUE(consistency_checked); } @@ -230,79 +225,24 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) Prover small_subgroup_ipa_prover = Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck); - std::array, NUM_SMALL_IPA_EVALUATIONS> witness_polynomials = + std::array, NUM_LIBRA_EVALUATIONS> witness_polynomials = small_subgroup_ipa_prover.get_witness_polynomials(); // Tamper with witness polynomials witness_polynomials[0].at(0) = FF::random_element(); - const std::array small_ipa_evaluations = - this->evaluate_small_ipa_witnesses(witness_polynomials); + std::array libra_evaluations = { + witness_polynomials[0].evaluate(this->evaluation_challenge), + witness_polynomials[1].evaluate(this->evaluation_challenge * Curve::subgroup_generator), + witness_polynomials[2].evaluate(this->evaluation_challenge), + witness_polynomials[3].evaluate(this->evaluation_challenge) + }; - bool consistency_checked = Verifier::check_libra_evaluations_consistency( - small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); + bool consistency_checked = Verifier::check_evaluations_consistency( + libra_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product); // Since witness polynomials were modified, the consistency check must fail EXPECT_FALSE(consistency_checked); } -// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the -// verifier. -TYPED_TEST(SmallSubgroupIPATest, TranslationEvaluationsMaskingTerm) -{ - // TranslationData class is Grumpkin-specific - if constexpr (std::is_same_v) { - GTEST_SKIP(); - } else { - using Curve = typename TypeParam::Curve; - using FF = typename Curve::ScalarField; - using Verifier = SmallSubgroupIPAVerifier; - using Prover = SmallSubgroupIPAProver; - using CK = typename TypeParam::CommitmentKey; - - auto prover_transcript = TypeParam::Transcript::prover_init_empty(); - // Must satisfy num_wires * MASKING_OFFSET + 1 < SUBGROUP_SIZE - const size_t num_wires = 5; - - // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck. - static constexpr size_t log_subgroup_size = static_cast(numeric::get_msb(Curve::SUBGROUP_SIZE)); - std::shared_ptr ck = - create_commitment_key(std::max(this->circuit_size, 1ULL << (log_subgroup_size + 1))); - - // Generate transcript polynomials - std::vector> transcript_polynomials; - - for (size_t idx = 0; idx < num_wires; idx++) { - transcript_polynomials.push_back(Polynomial::random(this->circuit_size)); - } - - TranslationData translation_data( - RefVector>(transcript_polynomials), prover_transcript, ck); - - const FF evaluation_challenge_x = FF::random_element(); - const FF batching_challenge_v = FF::random_element(); - - const FF claimed_inner_product = Prover::compute_claimed_translation_inner_product( - translation_data, evaluation_challenge_x, batching_challenge_v); - - Prover small_subgroup_ipa_prover(translation_data, - evaluation_challenge_x, - batching_challenge_v, - claimed_inner_product, - prover_transcript, - ck); - - const std::array small_ipa_evaluations = - this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials()); - - bool consistency_checked = Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations, - this->evaluation_challenge, - evaluation_challenge_x, - batching_challenge_v, - claimed_inner_product); - - EXPECT_TRUE(consistency_checked); - } -} - } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 0103af3b21a..e13704e6ef8 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -23,9 +23,7 @@ static constexpr uint32_t MAX_DATABUS_SIZE = 10000; static constexpr uint32_t MASKING_OFFSET = 4; // For ZK Flavors: the number of the commitments required by Libra and SmallSubgroupIPA. static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; -// The SmallSubgroupIPA is a sub-protocol used in several Flavors, to prove claimed inner product, the Prover sends 4 -// extra evaluations -static constexpr uint32_t NUM_SMALL_IPA_EVALUATIONS = 4; +static constexpr uint32_t NUM_LIBRA_EVALUATIONS = 4; // There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between // ECCVM and Translator static constexpr uint32_t NUM_TRANSLATION_EVALUATIONS = 5; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt index b49a7f9ded4..76805121ccf 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(eccvm commitment_schemes sumcheck) +barretenberg_module(eccvm sumcheck) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp deleted file mode 100644 index 8166ff00c2d..00000000000 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include "barretenberg/eccvm/eccvm_flavor.hpp" -#include "barretenberg/goblin/translation_evaluations.hpp" -#include "barretenberg/transcript/transcript.hpp" - -namespace bb { - -// We won't compile this class with Standard, but we will like want to compile it (at least for testing) -// with a flavor that uses the curve Grumpkin, or a flavor that does/does not have zk, etc. -template class TranslationData { - public: - using Flavor = ECCVMFlavor; - using FF = typename Flavor::FF; - using BF = typename Flavor::BF; - using Commitment = typename Flavor::Commitment; - using PCS = typename Flavor::PCS; - using CommitmentKey = typename Flavor::CommitmentKey; - using Polynomial = typename Flavor::Polynomial; - using TranslationEvaluations = bb::TranslationEvaluations_; - static constexpr size_t SUBGROUP_SIZE = Flavor::Curve::SUBGROUP_SIZE; - - Polynomial concatenated_masking_term; - Polynomial concatenated_masking_term_lagrange; - FF constant_term; - - std::array interpolation_domain; - - TranslationData(const RefVector& transcript_polynomials, - const std::shared_ptr& transcript, - const std::shared_ptr& commitment_key) - : concatenated_masking_term(SUBGROUP_SIZE + 2) - , concatenated_masking_term_lagrange(SUBGROUP_SIZE) - , constant_term(FF{ 0 }) - { - // Create interpolation domain - interpolation_domain[0] = FF{ 1 }; - - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - interpolation_domain[idx] = interpolation_domain[idx - 1] * Flavor::Curve::subgroup_generator; - } - - // Let m_0,..., m_4 be the vectors of last 4 coeffs in each transcript poly, we compute the concatenation - // (constant_term || m_0 || ... || m_4) in Lagrange and monomial basis and mask the latter. - compute_concatenated_polynomials(transcript_polynomials); - - // Commit to the concatenated masking term - transcript->template send_to_verifier("Translation:masking_term_commitment", - commitment_key->commit(concatenated_masking_term)); - }; - - void compute_concatenated_polynomials(const RefVector& transcript_polynomials) - { - const size_t circuit_size = transcript_polynomials[0].size(); - - std::array coeffs_lagrange_subgroup; - coeffs_lagrange_subgroup[0] = constant_term; - - for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) { - coeffs_lagrange_subgroup[idx] = FF{ 0 }; - } - - // Extract the Lagrange coefficients of the concatenated masking term from the transcript polynomials - for (size_t poly_idx = 0; poly_idx < NUM_TRANSLATION_EVALUATIONS; poly_idx++) { - for (size_t idx = 0; idx < MASKING_OFFSET; idx++) { - size_t idx_to_populate = 1 + poly_idx * MASKING_OFFSET + idx; - coeffs_lagrange_subgroup[idx_to_populate] = - transcript_polynomials[poly_idx].at(circuit_size - MASKING_OFFSET + idx); - } - } - concatenated_masking_term_lagrange = Polynomial(coeffs_lagrange_subgroup); - - // Generate the masking term - bb::Univariate masking_scalars = bb::Univariate::get_random(); - - // Compute monomial coefficients of the concatenated polynomial - Polynomial concatenated_monomial_form_unmasked(interpolation_domain, coeffs_lagrange_subgroup, SUBGROUP_SIZE); - - for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) { - concatenated_masking_term.at(idx) = concatenated_monomial_form_unmasked.at(idx); - } - - // Mask the polynomial in monomial form - for (size_t idx = 0; idx < masking_scalars.size(); idx++) { - concatenated_masking_term.at(idx) -= masking_scalars.value_at(idx); - concatenated_masking_term.at(SUBGROUP_SIZE + idx) += masking_scalars.value_at(idx); - } - } -}; -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt index 492ba2d5bcd..6021b903af8 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(translator_vm sumcheck commitment_schemes) +barretenberg_module(translator_vm sumcheck) diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt index 2d4ac70e7ef..fb84d7b4c74 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(ultra_honk sumcheck commitment_schemes stdlib_primitives stdlib_keccak stdlib_sha256) +barretenberg_module(ultra_honk sumcheck stdlib_primitives stdlib_keccak stdlib_sha256) From b77aa9e8aff264bbb82790628b87ff6183cfe2ef Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Tue, 25 Feb 2025 17:09:21 +0000 Subject: [PATCH 19/20] empty lines clean-up --- .../barretenberg/commitment_schemes/shplonk/shplemini.hpp | 2 +- .../small_subgroup_ipa/small_subgroup_ipa.hpp | 2 +- .../small_subgroup_ipa/small_subgroup_ipa.test.cpp | 2 +- barretenberg/cpp/src/barretenberg/constants.hpp | 2 +- barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt | 2 +- .../cpp/src/barretenberg/eccvm/eccvm_verifier.hpp | 4 +--- .../src/barretenberg/goblin/translation_evaluations.hpp | 2 +- .../stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp | 8 ++++---- .../cpp/src/barretenberg/translator_vm/CMakeLists.txt | 2 +- .../translator_vm/translator_circuit_builder.hpp | 2 +- .../cpp/src/barretenberg/ultra_honk/CMakeLists.txt | 2 +- 11 files changed, 14 insertions(+), 16 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index fd25c094fd1..040c32cce97 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -834,4 +834,4 @@ template class ShpleminiVerifier_ { } }; }; -} // namespace bb +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp index 345d561c1b8..791bb6a601f 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.hpp @@ -580,4 +580,4 @@ template class SmallSubgroupIPAVerifier { return result; } }; -} // namespace bb +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp index 5c96a0e2624..cd58a2c854a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/small_subgroup_ipa/small_subgroup_ipa.test.cpp @@ -245,4 +245,4 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure) EXPECT_FALSE(consistency_checked); } -} // namespace bb +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index e13704e6ef8..db610d31bc6 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -27,4 +27,4 @@ static constexpr uint32_t NUM_LIBRA_EVALUATIONS = 4; // There are 5 distinguished wires in ECCVM that have to be opened as univariates to establish the connection between // ECCVM and Translator static constexpr uint32_t NUM_TRANSLATION_EVALUATIONS = 5; -} // namespace bb +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt index 76805121ccf..55caefab48f 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/eccvm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(eccvm sumcheck) +barretenberg_module(eccvm sumcheck) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp index f057689b2e5..98899ef77b5 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp @@ -23,12 +23,10 @@ class ECCVMVerifier { : ECCVMVerifier(std::make_shared(proving_key)){}; bool verify_proof(const ECCVMProof& proof); - - std::array translation_commitments; - OpeningClaim reduce_verify_translation_evaluations( const std::array& translation_commitments); + std::array translation_commitments; std::shared_ptr key; std::map commitments; std::shared_ptr transcript; diff --git a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp index 78ac883b378..2d9bd72e2ea 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp @@ -18,4 +18,4 @@ template struct TranslationEvaluations_ { MSGPACK_FIELDS(op, Px, Py, z1, z2); }; -} // namespace bb +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp index 8ce3007d793..f92f2cc0ea6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp @@ -29,12 +29,12 @@ template class ECCVMRecursiveVerifier_ { std::shared_ptr transcript; std::shared_ptr ipa_transcript; - std::vector translation_commitments; - - OpeningClaim reduce_verify_translation_evaluations(const std::vector& translation_commitments); - // Translation evaluations challenges. They are propagated to the TranslatorVerifier FF evaluation_challenge_x; FF batching_challenge_v; + + std::vector translation_commitments; + + OpeningClaim reduce_verify_translation_evaluations(const std::vector& translation_commitments); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt index 6021b903af8..74967d50486 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/translator_vm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(translator_vm sumcheck) +barretenberg_module(translator_vm sumcheck) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp index 2ff8784502b..cc10a1803a9 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_circuit_builder.hpp @@ -188,7 +188,7 @@ class TranslatorCircuitBuilder : public CircuitBuilderBase { // For context, minicircuit is the part of the final polynomials fed into the proving system, where we have all the // arithmetic logic. However, the full circuit is several times larger (we use a trick to bring down the degree of // the permutation argument) - static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH = 8192; + static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH = 2048; // Maximum size of a single limb is 68 bits static constexpr size_t NUM_LIMB_BITS = 68; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt index fb84d7b4c74..cc7df8118f2 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(ultra_honk sumcheck stdlib_primitives stdlib_keccak stdlib_sha256) +barretenberg_module(ultra_honk sumcheck stdlib_primitives stdlib_keccak stdlib_sha256) \ No newline at end of file From ae994d31eaf19a4054049432eb005014dc2be652 Mon Sep 17 00:00:00 2001 From: iakovenkos Date: Wed, 26 Feb 2025 17:02:41 +0000 Subject: [PATCH 20/20] cleanup after the review --- .../cpp/src/barretenberg/eccvm/eccvm_prover.cpp | 12 ++++++------ .../cpp/src/barretenberg/eccvm/eccvm_prover.hpp | 2 +- .../cpp/src/barretenberg/eccvm/eccvm_verifier.cpp | 5 ++--- .../cpp/src/barretenberg/eccvm/eccvm_verifier.hpp | 4 ++-- .../barretenberg/goblin/translation_evaluations.hpp | 9 +++++---- .../eccvm_verifier/eccvm_recursive_verifier.cpp | 4 ++-- .../eccvm_verifier/eccvm_recursive_verifier.hpp | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index 60d920ca6af..4cd0e95814c 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -157,7 +157,7 @@ void ECCVMProver::execute_pcs_rounds() sumcheck_output.round_univariates, sumcheck_output.round_univariate_evaluations); - const OpeningClaim translation_opening_claim = ECCVMProver::reduce_translation_evaluations(); + const OpeningClaim translation_opening_claim = ECCVMProver::compute_translation_opening_claim(); const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -194,13 +194,13 @@ ECCVMProof ECCVMProver::construct_proof() } /** - * @brief The evaluations of the wires `op`, `Px`, `Py`, `z_1`, and `z_2` as univariate polynomials have to proved as + * @brief The evaluations of the wires `op`, `Px`, `Py`, `z_1`, and `z_2` as univariate polynomials have to be proved as * they are used in the 'TranslatorVerifier::verify_translation' sub-protocol and its recursive counterpart. To increase * the efficiency, we produce an OpeningClaim that is fed to Shplonk along with the OpeningClaim produced by Shplemini. * * @return ProverOpeningClaim */ -ProverOpeningClaim ECCVMProver::reduce_translation_evaluations() +ProverOpeningClaim ECCVMProver::compute_translation_opening_claim() { // Collect the polynomials and evaluations to be batched RefArray translation_polynomials{ key->polynomials.transcript_op, @@ -215,8 +215,8 @@ ProverOpeningClaim ECCVMProver::reduce_translation_ // Evaluate the transcript polynomials as univariates and add their evaluations at x to the transcript for (auto [eval, poly, label] : zip_view(translation_evaluations.get_all(), translation_polynomials, translation_labels)) { - *eval = poly.evaluate(evaluation_challenge_x); - transcript->template send_to_verifier(label, *eval); + eval = poly.evaluate(evaluation_challenge_x); + transcript->template send_to_verifier(label, eval); } // Get another challenge to batch the evaluations of the transcript polynomials @@ -228,7 +228,7 @@ ProverOpeningClaim ECCVMProver::reduce_translation_ FF batching_scalar = FF(1); for (auto [polynomial, eval] : zip_view(translation_polynomials, translation_evaluations.get_all())) { batched_translation_univariate.add_scaled(polynomial, batching_scalar); - batched_translation_evaluation += *eval * batching_scalar; + batched_translation_evaluation += eval * batching_scalar; batching_scalar *= translation_batching_challenge_v; } diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index 172dcb6059d..e930f00d9c2 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -45,7 +45,7 @@ class ECCVMProver { ECCVMProof export_proof(); ECCVMProof construct_proof(); - OpeningClaim reduce_translation_evaluations(); + OpeningClaim compute_translation_opening_claim(); std::shared_ptr transcript; std::shared_ptr ipa_transcript; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 3b2709d5b6d..6aa86917754 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -106,7 +106,7 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) commitments.transcript_z1, commitments.transcript_z2 }; - const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(translation_commitments); + const OpeningClaim translation_opening_claim = compute_translation_opening_claim(translation_commitments); const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -129,13 +129,12 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) * @param translation_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' * @return OpeningClaim */ -OpeningClaim ECCVMVerifier::reduce_verify_translation_evaluations( +OpeningClaim ECCVMVerifier::compute_translation_opening_claim( const std::array& translation_commitments) { evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); // Construct arrays of commitments and evaluations to be batched, the evaluations being received from the prover - std::array translation_evaluations = { transcript->template receive_from_prover("Translation:op"), transcript->template receive_from_prover("Translation:Px"), diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp index 98899ef77b5..be7c71785f8 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp @@ -23,7 +23,7 @@ class ECCVMVerifier { : ECCVMVerifier(std::make_shared(proving_key)){}; bool verify_proof(const ECCVMProof& proof); - OpeningClaim reduce_verify_translation_evaluations( + OpeningClaim compute_translation_opening_claim( const std::array& translation_commitments); std::array translation_commitments; @@ -32,7 +32,7 @@ class ECCVMVerifier { std::shared_ptr transcript; std::shared_ptr ipa_transcript; - // Translation evaluations challenges. They are propagated to the TranslatorVerifier + // Translation evaluation and batching challenges. They are propagated to the TranslatorVerifier FF evaluation_challenge_x; FF batching_challenge_v; }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp index 2d9bd72e2ea..619314c59d8 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp @@ -1,4 +1,6 @@ #pragma once +#include "barretenberg/common/ref_array.hpp" +#include "barretenberg/constants.hpp" #include "barretenberg/ecc/curves/bn254/fq.hpp" #include "barretenberg/ecc/fields/field_conversion.hpp" @@ -11,11 +13,10 @@ namespace bb { */ template struct TranslationEvaluations_ { BF op, Px, Py, z1, z2; - static constexpr uint32_t NUM_EVALUATIONS = 5; - static size_t size() { return field_conversion::calc_num_bn254_frs() * NUM_EVALUATIONS; } + static size_t size() { return field_conversion::calc_num_bn254_frs() * NUM_TRANSLATION_EVALUATIONS; } - std::array get_all() { return { &op, &Px, &Py, &z1, &z2 }; } + RefArray get_all() { return { op, Px, Py, z1, z2 }; } MSGPACK_FIELDS(op, Px, Py, z1, z2); }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index 318e634d4d5..74ad13be570 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -118,7 +118,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) commitments.transcript_z1, commitments.transcript_z2 }; // Reduce the univariate evaluations claims to a single claim to be batched by Shplonk - const OpeningClaim translation_opening_claim = reduce_verify_translation_evaluations(translation_commitments); + const OpeningClaim translation_opening_claim = compute_translation_opening_claim(translation_commitments); // Construct and verify the combined opening claim const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -138,7 +138,7 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) * @return OpeningClaim */ template -OpeningClaim ECCVMRecursiveVerifier_::reduce_verify_translation_evaluations( +OpeningClaim ECCVMRecursiveVerifier_::compute_translation_opening_claim( const std::vector& translation_commitments) { evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp index f92f2cc0ea6..046a3bf6220 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.hpp @@ -29,12 +29,12 @@ template class ECCVMRecursiveVerifier_ { std::shared_ptr transcript; std::shared_ptr ipa_transcript; - // Translation evaluations challenges. They are propagated to the TranslatorVerifier + // Translation evaluation and batching challenges. They are propagated to the TranslatorVerifier FF evaluation_challenge_x; FF batching_challenge_v; std::vector translation_commitments; - OpeningClaim reduce_verify_translation_evaluations(const std::vector& translation_commitments); + OpeningClaim compute_translation_opening_claim(const std::vector& translation_commitments); }; } // namespace bb