22 using type =
typename Curve::Builder;
30template <
typename Curve>
class MergeTests :
public testing::Test {
56 template <
typename T>
static auto to_native(
const T& val)
59 return val.get_value();
72 auto commitment = Commitment::from_witness(&
builder, native_commitment);
73 commitment.unset_free_witness_tag();
77 return native_commitment;
117 const size_t shift_idx = 0;
118 const size_t m_commitment_idx = 1;
119 const size_t l_eval_idx = 22;
121 switch (tampering_mode) {
124 merge_proof[shift_idx] +=
bb::fr(1);
129 FrCodec::deserialize_from_fields<curve::BN254::AffineElement>(std::span{ merge_proof }.subspan(
130 m_commitment_idx, FrCodec::calc_num_fields<curve::BN254::AffineElement>()));
131 m_commitment = m_commitment + curve::BN254::AffineElement::one();
132 auto m_commitment_frs = FrCodec::serialize_to_fields<curve::BN254::AffineElement>(m_commitment);
133 for (
size_t idx = 0; idx < 4; ++idx) {
134 merge_proof[m_commitment_idx + idx] = m_commitment_frs[idx];
140 merge_proof[l_eval_idx] -=
bb::fr(1);
155 const bool expected =
true)
159 MergeProver merge_prover{ op_queue, prover_transcript, settings };
164 auto t_current = op_queue->construct_current_ultra_ops_subtable_columns();
165 auto T_prev = op_queue->construct_previous_ultra_ops_table_columns();
170 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
171 native_t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]);
172 native_T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]);
177 auto T_merged = op_queue->construct_ultra_ops_table_columns();
179 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
180 expected_merged_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_merged[idx]);
188 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
201 bool verified = pairing_verified && result.reduction_succeeded;
202 EXPECT_EQ(verified, expected);
206 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
207 EXPECT_EQ(
to_native(result.merged_commitments[idx]), expected_merged_commitments[idx])
208 <<
"Merged table commitment mismatch at index " << idx;
215 EXPECT_EQ(circuit_valid, expected);
226 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
234 auto merge_proof = merge_prover.construct_proof();
236 EXPECT_EQ(merge_proof.size(), MERGE_PROOF_SIZE);
245 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
248 InnerBuilder circuit{ op_queue };
260 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
265 InnerBuilder circuit1{ op_queue };
270 InnerBuilder circuit2{ op_queue };
275 InnerBuilder circuit3{ op_queue };
286 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
291 InnerBuilder circuit1{ op_queue };
296 InnerBuilder circuit2{ op_queue };
301 InnerBuilder circuit3{ op_queue };
312 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
315 InnerBuilder circuit{ op_queue };
327 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
330 InnerBuilder circuit{ op_queue };
342 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
345 InnerBuilder circuit{ op_queue };
353using CurveTypes = ::testing::Types<curve::BN254,
354 stdlib::bn254<MegaCircuitBuilder>,
355 stdlib::bn254<UltraCircuitBuilder>>;
361 TestFixture::test_merge_proof_size();
366 TestFixture::test_single_merge();
371 TestFixture::test_multiple_merges_prepend();
376 TestFixture::test_merge_prepend_then_append();
424 if constexpr (!TestFixture::IsRecursive) {
425 GTEST_SKIP() <<
"OriginTag tests only apply to recursive context";
428 using BuilderType =
typename TestFixture::BuilderType;
429 using MergeVerifierType =
typename TestFixture::MergeVerifierType;
430 using Transcript =
typename TestFixture::Transcript;
432 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
433 constexpr size_t NUM_WIRES = TestFixture::NUM_WIRES;
440 InnerBuilder circuit_1{ op_queue_1 };
443 MergeProver prover_1{ op_queue_1, prover_transcript_1 };
447 InnerBuilder circuit_2{ op_queue_2 };
450 MergeProver prover_2{ op_queue_2, prover_transcript_2 };
454 auto t_1 = op_queue_1->construct_current_ultra_ops_subtable_columns();
455 auto T_prev_1 = op_queue_1->construct_previous_ultra_ops_table_columns();
458 for (
size_t idx = 0; idx < NUM_WIRES; idx++) {
459 native_t_commitments_1[idx] = prover_1.pcs_commitment_key.commit(t_1[idx]);
460 native_T_prev_commitments_1[idx] = prover_1.pcs_commitment_key.commit(T_prev_1[idx]);
467 [[maybe_unused]]
auto proof_1_recursive = TestFixture::create_proof(
builder, proof_1);
471 typename MergeVerifierType::InputCommitments input_commitments_1;
472 for (
size_t idx = 0; idx < NUM_WIRES; idx++) {
473 input_commitments_1.t_commitments[idx] = TestFixture::create_commitment(
builder, native_t_commitments_1[idx]);
474 input_commitments_1.T_prev_commitments[idx] =
475 TestFixture::create_commitment(
builder, native_T_prev_commitments_1[idx]);
483 auto proof_2_recursive = TestFixture::create_proof(
builder, proof_2);
499 for (
size_t idx = 0; idx < NUM_WIRES; idx++) {
501 if constexpr (TestFixture::IsRecursive) {
502 input_commitments_1.t_commitments[idx].set_origin_tag(transcript_1_tag);
503 input_commitments_1.T_prev_commitments[idx].set_origin_tag(transcript_1_tag);
510 info(
"Attempting to mix transcript_1 commitments with transcript_2 proof verification...");
515 verifier_2.reduce_to_pairing_check(proof_2_recursive, input_commitments_1),
516 "Tags from different transcripts were involved in the same computation");
537 constexpr size_t NUM_WIRES = 4;
540 size_t frs_per_Fr = 1;
541 size_t frs_per_G = FrCodec::calc_num_fields<curve::BN254::AffineElement>();
542 size_t frs_per_uint32 = 1;
547 manifest_expected.
add_entry(round,
"shift_size", frs_per_uint32);
548 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
551 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_0");
552 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_1");
553 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_2");
554 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_3");
558 for (
size_t idx = 0; idx < 13; ++idx) {
562 manifest_expected.
add_entry(round,
"REVERSED_BATCHED_LEFT_TABLES", frs_per_G);
566 manifest_expected.
add_challenge(round,
"shplonk_opening_challenge");
567 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
570 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
573 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
576 manifest_expected.
add_entry(round,
"REVERSED_BATCHED_LEFT_TABLES_EVAL", frs_per_Fr);
577 manifest_expected.
add_entry(round,
"SHPLONK_BATCHED_QUOTIENT", frs_per_G);
581 manifest_expected.
add_entry(round,
"KZG:W", frs_per_G);
583 return manifest_expected;
593 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
597 InnerBuilder circuit{ op_queue };
602 transcript->enable_manifest();
607 auto manifest_expected = construct_merge_manifest();
608 auto prover_manifest = transcript->get_manifest();
610 ASSERT_GT(manifest_expected.size(), 0);
611 ASSERT_EQ(prover_manifest.size(), manifest_expected.size())
612 <<
"Prover manifest has " << prover_manifest.size() <<
" rounds, expected " << manifest_expected.size();
614 for (
size_t round = 0; round < manifest_expected.size(); ++round) {
615 ASSERT_EQ(prover_manifest[round], manifest_expected[round]) <<
"Prover manifest discrepancy in round " << round;
625 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
629 InnerBuilder circuit{ op_queue };
634 prover_transcript->enable_manifest();
635 MergeProver merge_prover{ op_queue, prover_transcript };
640 auto t_current = op_queue->construct_current_ultra_ops_subtable_columns();
641 auto T_prev = op_queue->construct_previous_ultra_ops_table_columns();
643 merge_commitments.
t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]);
644 merge_commitments.
T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]);
649 verifier_transcript->enable_manifest();
654 ASSERT_TRUE(result.pairing_points.check() && result.reduction_succeeded);
657 auto prover_manifest = prover_transcript->get_manifest();
658 auto verifier_manifest = verifier_transcript->get_manifest();
660 ASSERT_GT(prover_manifest.size(), 0);
661 ASSERT_EQ(prover_manifest.size(), verifier_manifest.size())
662 <<
"Prover has " << prover_manifest.size() <<
" rounds, verifier has " << verifier_manifest.size();
664 for (
size_t round = 0; round < prover_manifest.size(); ++round) {
665 ASSERT_EQ(prover_manifest[round], verifier_manifest[round])
666 <<
"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.
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
PairingPoints pairing_points