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)
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++) {
197 auto [pairing_points, merged_table_commitments, degree_check_passed, concatenation_check_passed] =
202 bool pairing_verified =
204 bool verified = pairing_verified && degree_check_passed && concatenation_check_passed;
205 EXPECT_EQ(verified, expected);
209 for (
size_t idx = 0; idx <
NUM_WIRES; idx++) {
210 EXPECT_EQ(
to_native(merged_table_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;
236 auto merge_proof = merge_prover.construct_proof();
238 EXPECT_EQ(merge_proof.size(), MERGE_PROOF_SIZE);
247 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
250 InnerBuilder circuit{ op_queue };
262 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
267 InnerBuilder circuit1{ op_queue };
272 InnerBuilder circuit2{ op_queue };
277 InnerBuilder circuit3{ op_queue };
288 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
293 InnerBuilder circuit1{ op_queue };
298 InnerBuilder circuit2{ op_queue };
303 InnerBuilder circuit3{ op_queue };
314 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
317 InnerBuilder circuit{ op_queue };
329 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
332 InnerBuilder circuit{ op_queue };
344 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
347 InnerBuilder circuit{ op_queue };
355using CurveTypes = ::testing::Types<curve::BN254,
356 stdlib::bn254<MegaCircuitBuilder>,
357 stdlib::bn254<UltraCircuitBuilder>>;
363 TestFixture::test_merge_proof_size();
368 TestFixture::test_single_merge();
373 TestFixture::test_multiple_merges_prepend();
378 TestFixture::test_merge_prepend_then_append();
426 if constexpr (!TestFixture::IsRecursive) {
427 GTEST_SKIP() <<
"OriginTag tests only apply to recursive context";
430 using BuilderType =
typename TestFixture::BuilderType;
431 using MergeVerifierType =
typename TestFixture::MergeVerifierType;
432 using Transcript =
typename TestFixture::Transcript;
434 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
435 constexpr size_t NUM_WIRES = TestFixture::NUM_WIRES;
442 InnerBuilder circuit_1{ op_queue_1 };
448 InnerBuilder circuit_2{ op_queue_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.verify_proof(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) {
552 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_0");
553 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_1");
554 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_2");
555 manifest_expected.
add_challenge(round,
"LEFT_TABLE_DEGREE_CHECK_3");
559 for (
size_t idx = 0; idx < 13; ++idx) {
562 manifest_expected.
add_entry(round,
"REVERSED_BATCHED_LEFT_TABLES", frs_per_G);
570 manifest_expected.
add_challenge(round,
"shplonk_opening_challenge");
571 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
574 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
577 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
580 manifest_expected.
add_entry(round,
"REVERSED_BATCHED_LEFT_TABLES_EVAL", frs_per_Fr);
581 manifest_expected.
add_entry(round,
"SHPLONK_BATCHED_QUOTIENT", frs_per_G);
585 manifest_expected.
add_challenge(round,
"KZG:masking_challenge");
586 manifest_expected.
add_entry(round,
"KZG:W", frs_per_G);
588 return manifest_expected;
598 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
602 InnerBuilder circuit{ op_queue };
607 transcript->enable_manifest();
610 auto merge_proof = merge_prover.construct_proof();
613 auto manifest_expected = construct_merge_manifest();
614 auto prover_manifest = merge_prover.transcript->get_manifest();
616 ASSERT_GT(manifest_expected.size(), 0);
617 ASSERT_EQ(prover_manifest.size(), manifest_expected.size())
618 <<
"Prover manifest has " << prover_manifest.size() <<
" rounds, expected " << manifest_expected.size();
620 for (
size_t round = 0; round < manifest_expected.size(); ++round) {
621 ASSERT_EQ(prover_manifest[round], manifest_expected[round]) <<
"Prover manifest discrepancy in round " << round;
631 using InnerBuilder =
typename InnerFlavor::CircuitBuilder;
635 InnerBuilder circuit{ op_queue };
640 prover_transcript->enable_manifest();
643 auto merge_proof = merge_prover.construct_proof();
647 auto t_current = op_queue->construct_current_ultra_ops_subtable_columns();
648 auto T_prev = op_queue->construct_previous_ultra_ops_table_columns();
650 merge_commitments.
t_commitments[idx] = merge_prover.pcs_commitment_key.commit(t_current[idx]);
651 merge_commitments.
T_prev_commitments[idx] = merge_prover.pcs_commitment_key.commit(T_prev[idx]);
656 verifier_transcript->enable_manifest();
658 auto [pairing_points, _, degree_check_passed, concatenation_check_passed] =
659 merge_verifier.
verify_proof(merge_proof, merge_commitments);
662 ASSERT_TRUE(pairing_points.check() && degree_check_passed && concatenation_check_passed);
665 auto prover_manifest = merge_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_OR_ABORT(statement, matcher)
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
CommitmentKey object over a pairing group 𝔾₁.
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
Defines the circuit block types for the Mega arithmetization.
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
VerificationResult verify_proof(const Proof &proof, const InputCommitments &input_commitments)
Verify the merge proof.
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(ShpleminiTest, TestSettings)
field< Bn254FrParams > fr
::testing::Types< curve::BN254, curve::Grumpkin > CurveTypes
OriginTag extract_transcript_tag(const TranscriptType &transcript)
Extract origin tag context from a transcript.
MergeSettings
The MergeSettings define whether an current subtable will be added at the beginning (PREPEND) or at t...
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
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