Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ template <typename Flavor> 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;

Expand All @@ -29,6 +31,16 @@ template <typename Flavor> 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<FF, 4> evaluate_small_ipa_witnesses(const std::array<Polynomial<FF>, 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<BN254Settings, GrumpkinSettings>;
Expand Down Expand Up @@ -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<Polynomial<FF>, NUM_LIBRA_EVALUATIONS> witness_polynomials =
small_subgroup_ipa_prover.get_witness_polynomials();

std::array<FF, NUM_LIBRA_EVALUATIONS> 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<FF, NUM_LIBRA_EVALUATIONS> 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);
}
Expand Down Expand Up @@ -231,18 +236,75 @@ TYPED_TEST(SmallSubgroupIPATest, ProverAndVerifierSimpleFailure)
// Tamper with witness polynomials
witness_polynomials[0].at(0) = FF::random_element();

std::array<FF, NUM_LIBRA_EVALUATIONS> 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<FF, NUM_LIBRA_EVALUATIONS> 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);
}

} // namespace bb
// 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<TypeParam, BN254Settings>) {
GTEST_SKIP();
} else {
using Curve = typename TypeParam::Curve;
using FF = typename Curve::ScalarField;
using Verifier = SmallSubgroupIPAVerifier<Curve>;
using Prover = SmallSubgroupIPAProver<TypeParam>;
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<size_t>(numeric::get_msb(Curve::SUBGROUP_SIZE));
std::shared_ptr<CK> ck =
create_commitment_key<CK>(std::max<size_t>(this->circuit_size, 1ULL << (log_subgroup_size + 1)));

// Generate transcript polynomials
std::vector<Polynomial<FF>> transcript_polynomials;

for (size_t idx = 0; idx < num_wires; idx++) {
transcript_polynomials.push_back(Polynomial<FF>::random(this->circuit_size));
}

TranslationData<typename TypeParam::Transcript> 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, num_wires);

Prover small_subgroup_ipa_prover(translation_data,
num_wires,
evaluation_challenge_x,
batching_challenge_v,
claimed_inner_product,
prover_transcript,
ck);

const std::array<FF, NUM_LIBRA_EVALUATIONS> 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,
this->evaluation_challenge,
evaluation_challenge_x,
batching_challenge_v,
claimed_inner_product);

EXPECT_TRUE(consistency_checked);
}
}

} // namespace bb
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
} // namespace bb
89 changes: 43 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
Copy Markdown
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);

// 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 };
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<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
Copy Markdown
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,46 @@ 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
Comment thread
iakovenkos marked this conversation as resolved.
Outdated
* 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()
Comment thread
iakovenkos marked this conversation as resolved.
Outdated
{
// 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<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(), 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<FF>("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 };
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;
}

return { .polynomial = batched_univariate, .opening_pair = { evaluation_challenge_x, batched_evaluation } };
}
} // namespace bb
6 changes: 6 additions & 0 deletions 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;

static constexpr 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 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);
}
}
90 changes: 90 additions & 0 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_translation_data.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#pragma once

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's a new class in a way similar to ZKSumcheckData. It is supposed to accept the eccvm transcript wires, extract, and concatenate the masking terms to prepare them for the SmallSubgroupIPA.

#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 <typename Transcript> 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_<FF, BF>;
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<FF, SUBGROUP_SIZE> interpolation_domain;

TranslationData(const RefVector<Polynomial>& transcript_polynomials,
const std::shared_ptr<Transcript>& transcript,
const std::shared_ptr<CommitmentKey>& 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<Polynomial>& transcript_polynomials)
{
const size_t circuit_size = transcript_polynomials[0].size();

std::array<FF, SUBGROUP_SIZE> 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 - MASKING_OFFSET + idx);
}
}
concatenated_masking_term_lagrange = Polynomial(coeffs_lagrange_subgroup);

// Generate the masking term
bb::Univariate<FF, 2> masking_scalars = bb::Univariate<FF, 2>::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
Loading