Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
translator_recursive_verifier.test.cpp
Go to the documentation of this file.
9#include <gtest/gtest.h>
10namespace bb {
11
18class TranslatorRecursiveTests : public ::testing::Test {
19 public:
29
31
37
39
41
43
44 // Helper function to add no-ops
45 static void add_random_ops(std::shared_ptr<bb::ECCOpQueue>& op_queue, size_t count)
46 {
47 for (size_t i = 0; i < count; i++) {
48 op_queue->random_op_ultra_only();
49 }
50 }
51
52 // Helper function to create an MSM
53 static void add_mixed_ops(std::shared_ptr<bb::ECCOpQueue>& op_queue, size_t count = 100)
54 {
55 auto P1 = InnerG1::random_element();
56 auto P2 = InnerG1::random_element();
57 auto z = InnerFF::random_element();
58 for (size_t i = 0; i < count; i++) {
59 op_queue->add_accumulate(P1);
60 op_queue->mul_accumulate(P2, z);
61 }
62 op_queue->eq_and_reset();
63 }
64
65 // Construct a test circuit based on some random operations
66 static InnerBuilder generate_test_circuit(const InnerBF& batching_challenge_v,
67 const InnerBF& evaluation_challenge_x,
68 const size_t circuit_size_parameter = 500)
69 {
70
71 // Add the same operations to the ECC op queue; the native computation is performed under the hood.
72 auto op_queue = std::make_shared<bb::ECCOpQueue>();
73 op_queue->no_op_ultra_only();
75 add_mixed_ops(op_queue, circuit_size_parameter / 2);
76 op_queue->merge();
77 add_mixed_ops(op_queue, circuit_size_parameter / 2);
79 op_queue->merge(MergeSettings::APPEND, ECCOpQueue::OP_QUEUE_SIZE - op_queue->get_current_subtable_size());
80
81 return InnerBuilder{ batching_challenge_v, evaluation_challenge_x, op_queue };
82 }
83
84 // Helper to create native op queue commitments from proving key
85 static std::array<InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES> create_native_op_queue_commitments(
87 {
88 std::array<InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES> op_queue_commitments;
89 op_queue_commitments[0] =
90 proving_key->proving_key->commitment_key.commit(proving_key->proving_key->polynomials.op);
91 op_queue_commitments[1] =
92 proving_key->proving_key->commitment_key.commit(proving_key->proving_key->polynomials.x_lo_y_hi);
93 op_queue_commitments[2] =
94 proving_key->proving_key->commitment_key.commit(proving_key->proving_key->polynomials.x_hi_z_1);
95 op_queue_commitments[3] =
96 proving_key->proving_key->commitment_key.commit(proving_key->proving_key->polynomials.y_lo_z_2);
97 return op_queue_commitments;
98 }
99
100 // Helper to convert native op queue commitments to stdlib commitments
101 static std::array<RecursiveFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES> create_stdlib_op_queue_commitments(
102 OuterBuilder* builder, const std::array<InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES>& native_comms)
103 {
104 std::array<RecursiveFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES> stdlib_comms;
105 for (size_t i = 0; i < InnerFlavor::NUM_OP_QUEUE_WIRES; i++) {
106 stdlib_comms[i] = RecursiveFlavor::Commitment::from_witness(builder, native_comms[i]);
107 // Set empty origin tags for commitments (they're free witnesses from merge protocol)
108 stdlib_comms[i].set_origin_tag(OriginTag::constant());
109 }
110 return stdlib_comms;
111 }
112
113 // Helper struct to hold translator verification inputs as stdlib witnesses
118 std::array<RecursiveFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES> op_queue_commitments;
119 // Native values for native verifier
121 std::array<InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES> native_op_queue_commitments;
122 };
123
124 // Helper to create recursive verifier inputs from native values
126 const InnerProver& prover,
127 const InnerBF& evaluation_challenge_x,
128 const InnerBF& batching_challenge_v)
129 {
130 // Get accumulated_result from the prover
131 bb::fq accumulated_result_native = prover.get_accumulated_result();
132 auto accumulated_result = TranslatorBF::from_witness(builder, accumulated_result_native);
133 accumulated_result.set_origin_tag(OriginTag::constant());
134
135 // Convert challenges to circuit witnesses
136 auto stdlib_evaluation_challenge_x = TranslatorBF::from_witness(builder, evaluation_challenge_x);
137 auto stdlib_batching_challenge_v = TranslatorBF::from_witness(builder, batching_challenge_v);
138 stdlib_evaluation_challenge_x.set_origin_tag(OriginTag::constant());
139 stdlib_batching_challenge_v.set_origin_tag(OriginTag::constant());
140
141 // Create op queue commitments (normally provided by merge protocol)
142 auto native_op_queue_commitments = create_native_op_queue_commitments(prover.key);
143 auto op_queue_commitments = create_stdlib_op_queue_commitments(builder, native_op_queue_commitments);
144
145 return { accumulated_result, stdlib_evaluation_challenge_x, stdlib_batching_challenge_v,
146 op_queue_commitments, accumulated_result_native, native_op_queue_commitments };
147 }
148
149 // Shared helper to create and verify a translator proof recursively
150 // Includes native verification and consistency checks
152 size_t circuit_size_parameter = 500)
153 {
154
155 // Create fake ECCVM proof
156 auto prover_transcript = std::make_shared<Transcript>();
157
158 // Generate challenges
159 InnerBF batching_challenge_v = InnerBF::random_element();
160 InnerBF evaluation_challenge_x = InnerBF::random_element();
161
162 // Create inner translator circuit and generate proof
163 InnerBuilder circuit_builder =
164 generate_test_circuit(batching_challenge_v, evaluation_challenge_x, circuit_size_parameter);
165 auto proving_key = std::make_shared<TranslatorProvingKey>(circuit_builder);
166 InnerProver prover{ proving_key, prover_transcript };
167 auto proof = prover.construct_proof();
168
169 // Set up outer recursive circuit
170 OuterBuilder outer_circuit;
171 stdlib::Proof<OuterBuilder> stdlib_proof(outer_circuit, proof);
172 auto transcript = std::make_shared<RecursiveFlavor::Transcript>(stdlib_proof);
173
174 // Create recursive verifier inputs
175 auto recursive_inputs =
176 create_recursive_verifier_inputs(&outer_circuit, prover, evaluation_challenge_x, batching_challenge_v);
177
178 // Verify proof recursively
179 stdlib::Proof<OuterBuilder> stdlib_proof_for_verifier(outer_circuit, proof);
180 RecursiveVerifier verifier{ transcript,
181 stdlib_proof_for_verifier,
182 recursive_inputs.evaluation_challenge_x,
183 recursive_inputs.batching_challenge_v,
184 recursive_inputs.accumulated_result,
185 recursive_inputs.op_queue_commitments };
186 auto recursive_result = verifier.reduce_to_pairing_check();
187
189 inputs.pairing_inputs = recursive_result.pairing_points;
191
192 // Verify with native verifier and compare results
193 auto native_verifier_transcript = std::make_shared<Transcript>(proof);
194 InnerVerifier native_verifier(native_verifier_transcript,
195 proof,
196 evaluation_challenge_x,
197 batching_challenge_v,
198 recursive_inputs.accumulated_result_native,
199 recursive_inputs.native_op_queue_commitments);
200 auto native_result = native_verifier.reduce_to_pairing_check();
201 bool native_verified = native_result.pairing_points.check() && native_result.reduction_succeeded;
202
203 auto recursive_verified = recursive_result.pairing_points.check();
204 EXPECT_EQ(recursive_verified, native_verified);
205
206 // Verify VK commitments consistency between recursive and native verifiers
207 auto recursive_vk = verifier.get_verification_key();
208 auto native_vk = native_verifier.get_verification_key();
209 for (auto [vk_poly, native_vk_poly] : zip_view(recursive_vk->get_all(), native_vk->get_all())) {
210 EXPECT_EQ(vk_poly.get_value(), native_vk_poly);
211 }
212
213 auto outer_proving_key = std::make_shared<OuterProverInstance>(outer_circuit);
214 auto outer_verification_key =
215 std::make_shared<typename OuterFlavor::VerificationKey>(outer_proving_key->get_precomputed());
216
217 return { std::move(outer_circuit), outer_verification_key };
218 }
219
221 {
222 // Use the shared helper to create and verify the recursive circuit
223 auto [outer_circuit, outer_verification_key] = create_recursive_verifier_circuit();
224
225 info("Recursive Verifier: num gates = ", outer_circuit.num_gates());
226 EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err();
227
228 // Prove and verify the outer recursive circuit
229 auto prover_instance = std::make_shared<OuterProverInstance>(outer_circuit);
230 auto vk_and_hash = std::make_shared<OuterFlavor::VKAndHash>(outer_verification_key);
231 OuterProver prover(prover_instance, outer_verification_key);
232 OuterVerifier verifier(vk_and_hash);
233 auto proof = prover.construct_proof();
234 bool verified = verifier.verify_proof(proof).result;
235
236 ASSERT_TRUE(verified);
237 }
238
240 {
241 auto [outer_circuit_256, verification_key_256] = create_recursive_verifier_circuit(256);
242 auto [outer_circuit_512, verification_key_512] = create_recursive_verifier_circuit(512);
243
244 compare_ultra_blocks_and_verification_keys<OuterFlavor>({ outer_circuit_256.blocks, outer_circuit_512.blocks },
245 { verification_key_256, verification_key_512 });
246 };
247};
248
253
258} // namespace bb
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
static const size_t OP_QUEUE_SIZE
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
TranslatorCircuitBuilder creates a circuit that evaluates the correctness of the evaluation of EccOpQ...
BaseTranscript< Codec, HashFunction > Transcript
static constexpr size_t NUM_OP_QUEUE_WIRES
TranslatorCircuitBuilder CircuitBuilder
Curve::ScalarField FF
Curve::AffineElement Commitment
uint256_t get_accumulated_result() const
Extract the accumulated result from the circuit.
std::shared_ptr< TranslatorProvingKey > key
The recursive counterpart of the native Translator flavor.
Test suite for standalone recursive verification of translation proofs.
static void add_mixed_ops(std::shared_ptr< bb::ECCOpQueue > &op_queue, size_t count=100)
static InnerBuilder generate_test_circuit(const InnerBF &batching_challenge_v, const InnerBF &evaluation_challenge_x, const size_t circuit_size_parameter=500)
std::conditional_t< IsMegaBuilder< OuterBuilder >, MegaFlavor, UltraFlavor > OuterFlavor
static RecursiveVerifierInputs create_recursive_verifier_inputs(OuterBuilder *builder, const InnerProver &prover, const InnerBF &evaluation_challenge_x, const InnerBF &batching_challenge_v)
static void add_random_ops(std::shared_ptr< bb::ECCOpQueue > &op_queue, size_t count)
static std::array< RecursiveFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES > create_stdlib_op_queue_commitments(OuterBuilder *builder, const std::array< InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES > &native_comms)
static std::tuple< OuterBuilder, std::shared_ptr< OuterFlavor::VerificationKey > > create_recursive_verifier_circuit(size_t circuit_size_parameter=500)
static std::array< InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES > create_native_op_queue_commitments(const std::shared_ptr< TranslatorProvingKey > &proving_key)
Translator verifier class that verifies the proof of the Translator circuit.
ReductionResult reduce_to_pairing_check()
Reduce the translator proof to a pairing check.
std::shared_ptr< VerificationKey > get_verification_key() const
Get the verification key.
Output verify_proof(const Proof &proof)
Perform ultra verification.
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
Manages the data that is propagated on the public inputs of an application/function circuit.
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
AvmProvingInputs inputs
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TranslatorVerifier_< TranslatorRecursiveFlavor > TranslatorRecursiveVerifier
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:142
TranslatorVerifier_< TranslatorFlavor > TranslatorVerifier
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
static OriginTag constant()
std::array< RecursiveFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES > op_queue_commitments
std::array< InnerFlavor::Commitment, InnerFlavor::NUM_OP_QUEUE_WIRES > native_op_queue_commitments
static field random_element(numeric::RNG *engine=nullptr) noexcept
uint32_t set_public()
Set the witness indices for the pairing points to public.