Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: translation evaluations: refactor + soundness fix #12051

Merged
merged 26 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ead1afc
small refactor of translation evals logic in eccvm
iakovenkos Feb 17, 2025
d9d9a1f
+ ECCVMTranslation Class; extended functionality in SmallSubgroupIPA
iakovenkos Feb 18, 2025
5504006
test added
iakovenkos Feb 18, 2025
acc8a51
test passes
iakovenkos Feb 18, 2025
4d4349e
cleaning up
iakovenkos Feb 18, 2025
3aa169b
small subgroup ipa test clean-up
iakovenkos Feb 19, 2025
6628ec7
propagate translation challenges from eccvm verifier to translator ve…
iakovenkos Feb 19, 2025
a51d492
slightly more sound
iakovenkos Feb 20, 2025
bfaab51
IndependentVKHash test added to Goblin
iakovenkos Feb 20, 2025
b4eaa6b
Merge branch 'master' into si/fix-translation-evaluations
iakovenkos Feb 20, 2025
b21a2b2
fix build
iakovenkos Feb 20, 2025
bcc3284
translation labels no longer constexpr to fix build
iakovenkos Feb 20, 2025
ae74a81
Merge branch 'master' into si/fix-translation-evaluations
iakovenkos Feb 20, 2025
7d8e932
renamed constants + docs
iakovenkos Feb 24, 2025
a18fc20
Merge branch 'master' into si/fix-translation-evaluations
iakovenkos Feb 24, 2025
98f29b0
fix build
iakovenkos Feb 24, 2025
9eec4c3
Merge branch 'si/fix-translation-evaluations' of github.com:AztecProt…
iakovenkos Feb 24, 2025
692619f
split small subgroup ipa
iakovenkos Feb 24, 2025
a1c3ebe
linker fixed
iakovenkos Feb 24, 2025
2eb4c43
SmallSubgroupIPA Verifier code simplified
iakovenkos Feb 24, 2025
3f95d0d
more changes in smallsubgroup ipa
iakovenkos Feb 24, 2025
1d41026
undo small subgroup ipa
iakovenkos Feb 25, 2025
a6c729d
Merge branch 'master' into si/fix-translation-evaluations
iakovenkos Feb 25, 2025
b77aa9e
empty lines clean-up
iakovenkos Feb 25, 2025
ae994d3
cleanup after the review
iakovenkos Feb 26, 2025
0da6dc1
Merge branch 'master' into si/fix-translation-evaluations
iakovenkos Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions barretenberg/cpp/src/barretenberg/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ 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;
// 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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the eccvm flavor might be a better place for this constant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was also implicitly used in TranslationEvaluations struct that is propagated to Translator, I just modified it to use this constant explicitly. It is also used by the SmallSubgroupIPA in #12244, so I'd keep it here. But probably we'll need to revise these constants at some point.

} // namespace bb
90 changes: 44 additions & 46 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isolated into a separate method

evaluation_challenge_x = transcript->template get_challenge<FF>("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::reduce_translation_evaluations();

// Get another challenge for batching the univariates and evaluations
FF ipa_batching_challenge = transcript->template get_challenge<FF>("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<FF, univariate_polynomials.size()> 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<OpeningClaim, 2> opening_claims = { multivariate_to_univariate_opening_claim,
translation_opening_claim };

Expand All @@ -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<FF>("Translation:batching_challenge");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a very strange step, the challenge that has to be propagated is the batching_challenge_v produced in reduce_translation_evaluations

}

ECCVMProof ECCVMProver::export_proof()
Expand All @@ -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 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<typename ECCVMFlavor::Curve>
*/
ProverOpeningClaim<typename ECCVMFlavor::Curve> ECCVMProver::reduce_translation_evaluations()
{
// 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<FF>("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<FF>("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
8 changes: 7 additions & 1 deletion barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ECCVMProver {
using CircuitBuilder = typename Flavor::CircuitBuilder;
using ZKData = ZKSumcheckData<Flavor>;
using SmallSubgroupIPA = SmallSubgroupIPAProver<Flavor>;
using OpeningClaim = ProverOpeningClaim<typename Flavor::Curve>;

explicit ECCVMProver(CircuitBuilder& builder,
const bool fixed_size = false,
Expand All @@ -44,6 +45,7 @@ class ECCVMProver {

ECCVMProof export_proof();
ECCVMProof construct_proof();
OpeningClaim reduce_translation_evaluations();

std::shared_ptr<Transcript> transcript;
std::shared_ptr<Transcript> ipa_transcript;
Expand All @@ -52,6 +54,10 @@ class ECCVMProver {

TranslationEvaluations translation_evaluations;

std::array<std::string, 5> translation_labels = {
"Translation:op", "Translation:Px", "Translation:Py", "Translation:z1", "Translation:z2"
};

std::vector<FF> public_inputs;

bb::RelationParameters<FF> relation_parameters;
Expand All @@ -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<Flavor> sumcheck_output;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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;
}

Expand Down Expand Up @@ -405,4 +402,4 @@ TEST_F(ECCVMTranscriptTests, StructureTest)
prover.transcript->deserialize_full_transcript();
EXPECT_EQ(static_cast<typename Flavor::Commitment>(prover.transcript->transcript_Px_comm),
one_group_val * rand_val);
}
}
76 changes: 45 additions & 31 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<FF>("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<Commitment, NUM_UNIVARIATES> transcript_commitments = { commitments.transcript_op,
commitments.transcript_Px,
commitments.transcript_Py,
commitments.transcript_z1,
commitments.transcript_z2 };
std::array<FF, NUM_UNIVARIATES> transcript_evaluations = {
transcript->template receive_from_prover<FF>("Translation:op"),
transcript->template receive_from_prover<FF>("Translation:Px"),
transcript->template receive_from_prover<FF>("Translation:Py"),
transcript->template receive_from_prover<FF>("Translation:z1"),
transcript->template receive_from_prover<FF>("Translation:z2")
};

// Get the batching challenge for commitments and evaluations
const FF ipa_batching_challenge = transcript->template get_challenge<FF>("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 = reduce_verify_translation_evaluations(translation_commitments);

const std::array<OpeningClaim, 2> opening_claims = { multivariate_to_univariate_opening_claim,
translation_opening_claim };
Expand All @@ -145,4 +121,42 @@ 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<typename ECCVMFlavor::Curve>
*/
OpeningClaim<typename ECCVMFlavor::Curve> ECCVMVerifier::reduce_verify_translation_evaluations(
const std::array<Commitment, NUM_TRANSLATION_EVALUATIONS>& translation_commitments)
{
evaluation_challenge_x = transcript->template get_challenge<FF>("Translation:evaluation_challenge_x");

// Construct arrays of commitments and evaluations to be batched, the evaluations being received from the prover

std::array<FF, NUM_TRANSLATION_EVALUATIONS> translation_evaluations = {
transcript->template receive_from_prover<FF>("Translation:op"),
transcript->template receive_from_prover<FF>("Translation:Px"),
transcript->template receive_from_prover<FF>("Translation:Py"),
transcript->template receive_from_prover<FF>("Translation:z1"),
transcript->template receive_from_prover<FF>("Translation:z2")
};

// Get the batching challenge for commitments and evaluations
batching_challenge_v = transcript->template get_challenge<FF>("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
7 changes: 7 additions & 0 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,17 @@ class ECCVMVerifier {
: ECCVMVerifier(std::make_shared<ECCVMFlavor::VerificationKey>(proving_key)){};

bool verify_proof(const ECCVMProof& proof);
OpeningClaim<typename ECCVMFlavor::Curve> reduce_verify_translation_evaluations(
const std::array<Commitment, NUM_TRANSLATION_EVALUATIONS>& translation_commitments);

std::array<Commitment, NUM_TRANSLATION_EVALUATIONS> translation_commitments;
std::shared_ptr<VerificationKey> key;
std::map<std::string, Commitment> commitments;
std::shared_ptr<Transcript> transcript;
std::shared_ptr<Transcript> ipa_transcript;

// Translation evaluations challenges. They are propagated to the TranslatorVerifier
FF evaluation_challenge_x;
FF batching_challenge_v;
};
} // namespace bb
3 changes: 2 additions & 1 deletion barretenberg/cpp/src/barretenberg/goblin/goblin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ template <typename BF, typename FF> struct TranslationEvaluations_ {
static constexpr uint32_t NUM_EVALUATIONS = 5;
static size_t size() { return field_conversion::calc_num_bn254_frs<BF>() * NUM_EVALUATIONS; }

std::array<BF*, NUM_EVALUATIONS> get_all() { return { &op, &Px, &Py, &z1, &z2 }; }

MSGPACK_FIELDS(op, Px, Py, z1, z2);
};
} // namespace bb
Loading
Loading