diff --git a/barretenberg/cpp/src/barretenberg/constants.hpp b/barretenberg/cpp/src/barretenberg/constants.hpp index 8ef4e4707240..29192b6016a8 100644 --- a/barretenberg/cpp/src/barretenberg/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/constants.hpp @@ -26,4 +26,7 @@ static constexpr uint32_t NUM_LIBRA_COMMITMENTS = 3; static constexpr uint32_t NUM_LIBRA_EVALUATIONS = 4; static constexpr uint32_t MERGE_PROOF_SIZE = 65; // used to ensure mock proofs are generated correctly +// 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 b70b2383a7cc..4cd0e95814c9 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); + const OpeningClaim translation_opening_claim = ECCVMProver::compute_translation_opening_claim(); - // 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 }; - - // 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,47 @@ 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 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::compute_translation_opening_claim() +{ + // Collect the polynomials and evaluations to be batched + 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(), translation_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:batching_challenge_v"); + + // Construct the batched polynomial and batched evaluation to produce the batched opening claim + Polynomial batched_translation_univariate{ key->circuit_size }; + FF batched_translation_evaluation{ 0 }; + 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; + batching_scalar *= translation_batching_challenge_v; + } + + return { .polynomial = batched_translation_univariate, + .opening_pair = { evaluation_challenge_x, batched_translation_evaluation } }; +} } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index e14a2b2ef029..e930f00d9c27 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 compute_translation_opening_claim(); std::shared_ptr transcript; std::shared_ptr ipa_transcript; @@ -52,6 +54,10 @@ class ECCVMProver { TranslationEvaluations translation_evaluations; + std::array translation_labels = { + "Translation:op", "Translation:Px", "Translation:Py", "Translation:z1", "Translation:z2" + }; + std::vector public_inputs; bb::RelationParameters relation_parameters; @@ -62,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/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index 3adb4631676c..c146e7ae1c69 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; } diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 82606aa37299..6aa86917754f 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -99,38 +99,14 @@ 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 + translation_commitments = { commitments.transcript_op, + commitments.transcript_Px, + commitments.transcript_Py, + commitments.transcript_z1, + commitments.transcript_z2 }; - // 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 = { - 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"); - - // 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) { - batched_commitment = batched_commitment + transcript_commitments[idx] * batching_scalar; - batched_transcript_eval += batching_scalar * transcript_evaluations[idx]; - batching_scalar *= ipa_batching_challenge; - } - - const OpeningClaim translation_opening_claim = { { evaluation_challenge_x, batched_transcript_eval }, - batched_commitment }; + const OpeningClaim translation_opening_claim = compute_translation_opening_claim(translation_commitments); const std::array opening_claims = { multivariate_to_univariate_opening_claim, translation_opening_claim }; @@ -145,4 +121,41 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) 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 translation_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' + * @return OpeningClaim + */ +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"), + 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 + 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 = translation_commitments[0]; + FF batched_translation_evaluation = translation_evaluations[0]; + FF batching_scalar = batching_challenge_v; + 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_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 c772d99b5171..be7c71785f82 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp @@ -23,10 +23,17 @@ class ECCVMVerifier { : ECCVMVerifier(std::make_shared(proving_key)){}; bool verify_proof(const ECCVMProof& proof); + OpeningClaim compute_translation_opening_claim( + const std::array& translation_commitments); + std::array translation_commitments; std::shared_ptr key; std::map commitments; std::shared_ptr transcript; std::shared_ptr ipa_transcript; + + // Translation evaluation and batching 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 785e9fcc4c5f..1c0205e2c965 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); diff --git a/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp b/barretenberg/cpp/src/barretenberg/goblin/translation_evaluations.hpp index 24196ae69dc8..619314c59d82 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,9 +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; } + + 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 078049b831e4..74ad13be5708 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 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 = 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 }; + + 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 translation_commitments Commitments to 'op', 'Px', 'Py', 'z1', and 'z2' + * @return OpeningClaim + */ +template +OpeningClaim ECCVMRecursiveVerifier_::compute_translation_opening_claim( + 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 translation_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:batching_challenge_v"); // 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 batched_translation_evaluation = translation_evaluations[0]; + auto batching_scalar = batching_challenge_v; std::vector batching_challenges = { FF::one() }; - for (size_t idx = 1; idx < transcript_commitments.size(); ++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 *= 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); + const Commitment batched_commitment = Commitment::batch_mul(translation_commitments, batching_challenges); - return { batch_opening_claim, ipa_transcript }; -} + return { { evaluation_challenge_x, batched_translation_evaluation }, 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 729740aa7075..046a3bf62206 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,13 @@ template class ECCVMRecursiveVerifier_ { Builder* builder; std::shared_ptr transcript; std::shared_ptr ipa_transcript; + + // Translation evaluation and batching challenges. They are propagated to the TranslatorVerifier + FF evaluation_challenge_x; + FF batching_challenge_v; + + std::vector translation_commitments; + + OpeningClaim compute_translation_opening_claim(const std::vector& translation_commitments); }; } // 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 b9bf165bc966..1ded2e85213e 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,9 @@ 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 +40,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/goblin_verifier/goblin_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/goblin_verifier/goblin_recursive_verifier.test.cpp index bc3a1574ea64..87d9b3889572 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,36 @@ 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 + 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 +226,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 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 b0a13bb542e8..60fa119d0bdb 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; @@ -71,8 +72,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,7 +80,6 @@ std::array TranslatorRecursiveVerifier_template receive_from_prover("evaluation_input_x"); const BF accumulated_result = transcript->template receive_from_prover("accumulated_result"); @@ -156,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 39742bb65ccf..4e73b1bf0498 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 @@ -42,10 +40,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/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.test.cpp index 6e6780293d99..4434b8ed0d8c 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 @@ -36,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()); } @@ -66,11 +68,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 get_challenge("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 +87,7 @@ 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); + 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 @@ -94,7 +96,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 +140,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 +163,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 ed0503a82e81..62ad96c42ec6 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 = prover_transcript->template get_challenge("Translation:batching_challenge"); - 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_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp index ea21bc68fd97..d57028525e5c 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_prover.cpp @@ -35,7 +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("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 fbc029c55b0a..c83eaeb1643a 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; @@ -55,8 +57,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,7 +64,6 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) Flavor::CommitmentLabels commitment_labels; const auto circuit_size = transcript->template receive_from_prover("circuit_size"); - 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/translator_vm/translator_verifier.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.hpp index dbe0dc66cdbf..acd003ff53ba 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