22 using type =
typename Curve::Builder;
30template <
typename Curve>
class MergeTests :
public testing::Test {
57 template <
typename T>
static auto to_native(
const T& val)
60 return val.get_value();
73 auto commitment = Commitment::from_witness(&
builder, native_commitment);
74 commitment.unset_free_witness_tag();
78 return native_commitment;
118 const size_t shift_idx = 0;
119 const size_t m_commitment_idx = 1;
120 const size_t l_eval_idx = 22;
122 switch (tampering_mode) {
125 merge_proof[shift_idx] +=
bb::fr(1);
130 FrCodec::deserialize_from_fields<curve::BN254::AffineElement>(std::span{ merge_proof }.subspan(
131 m_commitment_idx, FrCodec::calc_num_fields<curve::BN254::AffineElement>()));
132 m_commitment = m_commitment + curve::BN254::AffineElement::one();
133 auto m_commitment_frs = FrCodec::serialize_to_fields<curve::BN254::AffineElement>(m_commitment);
134 for (
size_t idx = 0; idx < 4; ++idx) {
135 merge_proof[m_commitment_idx + idx] = m_commitment_frs[idx];
141 merge_proof[l_eval_idx] -=
bb::fr(1);
156 const bool expected =
true)
160 MergeProver merge_prover{ op_queue, prover_transcript, settings };
165 auto t_current = op_queue->construct_current_ultra_ops_subtable_columns();
166 auto T_prev = op_queue->construct_previous_ultra_ops_table_columns();
171 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
172 native_t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]);
173 native_T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]);
178 auto T_merged = op_queue->construct_ultra_ops_table_columns();
180 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
181 expected_merged_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_merged[idx]);
189 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
204 bool verified = pairing_verified && result.reduction_succeeded;
205 EXPECT_EQ(verified, expected);
209 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
210 EXPECT_EQ(
to_native(result.merged_commitments[idx]), expected_merged_commitments[idx])
211 <<
"Merged table commitment mismatch at index " << idx;
218 EXPECT_EQ(circuit_valid, expected);
229 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
237 auto merge_proof = merge_prover.construct_proof();
239 EXPECT_EQ(merge_proof.size(), MERGE_PROOF_SIZE);
248 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
251 InnerBuilder circuit{ op_queue };
263 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
268 InnerBuilder circuit1{ op_queue };
273 InnerBuilder circuit2{ op_queue };
278 InnerBuilder circuit3{ op_queue };
289 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
294 InnerBuilder circuit1{ op_queue };
299 InnerBuilder circuit2{ op_queue };
304 InnerBuilder circuit3{ op_queue };
315 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
318 InnerBuilder circuit{ op_queue };
330 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
333 InnerBuilder circuit{ op_queue };
345 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
348 InnerBuilder circuit{ op_queue };
356using CurveTypes = ::testing::Types<curve::BN254,
357 stdlib::bn254<MegaCircuitBuilder>,
358 stdlib::bn254<UltraCircuitBuilder>>;
364 TestFixture::test_merge_proof_size();
369 TestFixture::test_single_merge();
374 TestFixture::test_multiple_merges_prepend();
379 TestFixture::test_merge_prepend_then_append();
427 if constexpr (!TestFixture::IsRecursive) {
428 GTEST_SKIP() <<
"OriginTag tests only apply to recursive context";
431 using BuilderType =
typename TestFixture::BuilderType;
432 using MergeVerifierType =
typename TestFixture::MergeVerifierType;
433 using Transcript =
typename TestFixture::Transcript;
435 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
436 constexpr size_t NUM_WIRES = TestFixture::NUM_WIRES;
443 InnerBuilder circuit_1{ op_queue_1 };
446 MergeProver prover_1{ op_queue_1, prover_transcript_1 };
450 InnerBuilder circuit_2{ op_queue_2 };
453 MergeProver prover_2{ op_queue_2, prover_transcript_2 };
457 auto t_1 = op_queue_1->construct_current_ultra_ops_subtable_columns();
458 auto T_prev_1 = op_queue_1->construct_previous_ultra_ops_table_columns();
461 for (
size_t idx = 0; idx < NUM_WIRES; idx++) {
462 native_t_commitments_1[idx] = prover_1.pcs_commitment_key.commit(t_1[idx]);
463 native_T_prev_commitments_1[idx] = prover_1.pcs_commitment_key.commit(T_prev_1[idx]);
470 [[maybe_unused]]
auto proof_1_recursive = TestFixture::create_proof(
builder, proof_1);
474 typename MergeVerifierType::InputCommitments input_commitments_1;
475 for (
size_t idx = 0; idx < NUM_WIRES; idx++) {
476 input_commitments_1.t_commitments[idx] = TestFixture::create_commitment(
builder, native_t_commitments_1[idx]);
477 input_commitments_1.T_prev_commitments[idx] =
478 TestFixture::create_commitment(
builder, native_T_prev_commitments_1[idx]);
486 auto proof_2_recursive = TestFixture::create_proof(
builder, proof_2);
502 for (
size_t idx = 0; idx < NUM_WIRES; idx++) {
504 if constexpr (TestFixture::IsRecursive) {
505 input_commitments_1.t_commitments[idx].set_origin_tag(transcript_1_tag);
506 input_commitments_1.T_prev_commitments[idx].set_origin_tag(transcript_1_tag);
513 info(
"Attempting to mix transcript_1 commitments with transcript_2 proof verification...");
518 verifier_2.verify_proof(proof_2_recursive, input_commitments_1),
519 "Tags from different transcripts were involved in the same computation");
540 constexpr size_t NUM_WIRES = 4;
543 size_t frs_per_Fr = 1;
544 size_t frs_per_G = FrCodec::calc_num_fields<curve::BN254::AffineElement>();
545 size_t frs_per_uint32 = 1;
550 manifest_expected.
add_entry(round,
"shift_size", frs_per_uint32);
551 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
555 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_0");
556 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_1");
557 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_2");
558 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_3");
562 for (
size_t idx = 0; idx < 13; ++idx) {
565 manifest_expected.
add_entry(round,
"REVERSED_BATCHED_LEFT_TABLES", frs_per_G);
573 manifest_expected.
add_challenge(round,
"shplonk_opening_challenge");
574 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
577 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
580 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
583 manifest_expected.
add_entry(round,
"REVERSED_BATCHED_LEFT_TABLES_EVAL", frs_per_Fr);
584 manifest_expected.
add_entry(round,
"SHPLONK_BATCHED_QUOTIENT", frs_per_G);
588 manifest_expected.
add_challenge(round,
"KZG:masking_challenge");
589 manifest_expected.
add_entry(round,
"KZG:W", frs_per_G);
591 return manifest_expected;
601 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
605 InnerBuilder circuit{ op_queue };
610 transcript->enable_manifest();
615 auto manifest_expected = construct_merge_manifest();
616 auto prover_manifest = transcript->get_manifest();
618 ASSERT_GT(manifest_expected.size(), 0);
619 ASSERT_EQ(prover_manifest.size(), manifest_expected.size())
620 <<
"Prover manifest has " << prover_manifest.size() <<
" rounds, expected " << manifest_expected.size();
622 for (
size_t round = 0; round < manifest_expected.size(); ++round) {
623 ASSERT_EQ(prover_manifest[round], manifest_expected[round]) <<
"Prover manifest discrepancy in round " << round;
633 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
637 InnerBuilder circuit{ op_queue };
642 prover_transcript->enable_manifest();
643 MergeProver merge_prover{ op_queue, prover_transcript };
648 auto t_current = op_queue->construct_current_ultra_ops_subtable_columns();
649 auto T_prev = op_queue->construct_previous_ultra_ops_table_columns();
651 merge_commitments.
t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]);
652 merge_commitments.
T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]);
657 verifier_transcript->enable_manifest();
662 ASSERT_TRUE(result.pairing_points.check() && result.reduction_succeeded);
665 auto prover_manifest = prover_transcript->get_manifest();
666 auto verifier_manifest = verifier_transcript->get_manifest();
668 ASSERT_GT(prover_manifest.size(), 0);
669 ASSERT_EQ(prover_manifest.size(), verifier_manifest.size())
670 <<
"Prover has " << prover_manifest.size() <<
" rounds, verifier has " << verifier_manifest.size();
672 for (
size_t round = 0; round < prover_manifest.size(); ++round) {
673 ASSERT_EQ(prover_manifest[round], verifier_manifest[round])
674 <<
"Prover/Verifier manifest discrepancy in round " << round;
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
static void construct_simple_circuit(MegaBuilder &builder)
Generate a simple test circuit with some ECC op gates and conventional arithmetic gates.
static constexpr size_t NUM_WIRES
static constexpr size_t NUM_WIRES
Prover class for the Goblin ECC op queue transcript merge protocol.
std::shared_ptr< ECCOpQueue > op_queue
BB_PROFILE MergeProof construct_proof()
Prove proper construction of the aggregate Goblin ECC op queue polynomials T_j.
Unified test fixture for native and recursive merge verification.
static void test_degree_check_failure(const MergeSettings settings=MergeSettings::PREPEND)
Test failure when degree(l) > shift_size (as read from the proof)
static bool check_circuit(BuilderType &builder)
Check circuit validity (only relevant in recursive context)
static void prove_and_verify_merge(const std::shared_ptr< ECCOpQueue > &op_queue, const MergeSettings settings=MergeSettings::PREPEND, const TamperProofMode tampering_mode=TamperProofMode::None, const bool expected=true)
Prove and verify a merge proof in both native and recursive contexts.
typename Curve::ScalarField FF
typename Curve::Element GroupElement
static Commitment create_commitment(BuilderType &builder, const curve::BN254::AffineElement &native_commitment)
Create a commitment from a native commitment value.
static void test_merge_failure(const MergeSettings settings=MergeSettings::PREPEND)
Test failure when m ≠ l + X^k r.
typename Curve::AffineElement Commitment
typename MergeVerifierType::Proof Proof
static void test_eval_failure(const MergeSettings settings=MergeSettings::PREPEND)
Test failure when g_j(kappa) ≠ kappa^{k-1} * l_j(1/kappa)
static constexpr bool IsRecursive
static void test_merge_proof_size()
Test that merge proof size matches the expected constant.
static auto to_native(const T &val)
Convert a stdlib type to its native value.
static void tamper_with_proof(std::vector< bb::fr > &merge_proof, const TamperProofMode tampering_mode)
Tamper with the merge proof for failure testing.
static Proof create_proof(BuilderType &builder, const std::vector< bb::fr > &native_proof)
Create a proof object from a vector of field elements.
typename MergeVerifierType::InputCommitments InputCommitments
typename MergeVerifierType::PairingPoints PairingPoints
static constexpr size_t NUM_WIRES
typename MergeVerifierType::Transcript Transcript
static void test_multiple_merges_prepend()
Test multiple merge proofs with prepend mode.
typename MergeVerifierType::TableCommitments TableCommitments
typename BuilderTypeHelper< Curve >::type BuilderType
static void SetUpTestSuite()
static void test_single_merge()
Test basic merge proof construction and verification.
static void test_merge_prepend_then_append()
Test merge proof with append mode.
Test class for merge protocol transcript pinning tests.
static void SetUpTestSuite()
static TranscriptManifest construct_merge_manifest()
Construct the expected manifest for a Merge protocol proof.
Unified verifier class for the Goblin ECC op queue transcript merge protocol.
TranscriptFor_t< Curve > Transcript
std::conditional_t< Curve::is_stdlib_type, stdlib::recursion::PairingPoints< Curve >, bb::PairingPoints< Curve > > PairingPoints
ReductionResult reduce_to_pairing_check(const Proof &proof, const InputCommitments &input_commitments)
Reduce the merge proof to a pairing check.
std::array< Commitment, NUM_WIRES > TableCommitments
void add_entry(size_t round, const std::string &element_label, size_t element_size)
void add_challenge(size_t round, const std::string &label)
Add a single challenge label to the manifest for the given round.
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
Specialization for bn254.
bool pairing_check(const GroupElement &p0, const GroupElement &p1)
verifies a pairing equation over 2 points using the verifier SRS
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::affine_element AffineElement
typename Group::element Element
static constexpr bool is_stdlib_type
typename Group::affine_element AffineElement
A simple wrapper around a vector of stdlib field elements representing a proof.
testing::Types< stdlib::secp256k1< UltraCircuitBuilder >, stdlib::secp256r1< UltraCircuitBuilder >, stdlib::secp256k1< MegaCircuitBuilder >, stdlib::secp256r1< MegaCircuitBuilder > > CurveTypes
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
TEST_F(IPATest, ChallengesAreZero)
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
field< Bn254FrParams > fr
::testing::Types< curve::BN254, curve::Grumpkin > CurveTypes
OriginTag extract_transcript_tag(const TranscriptType &transcript)
Extract origin tag context from a transcript.
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
MergeSettings
The MergeSettings define whether an current subtable will be added at the beginning (PREPEND) or at t...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
typename Curve::Builder type