Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
folding_test_utils.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
14
15namespace bb {
16
17// Purely static class containing utility methods for protogalaxy testing
18template <class Flavor> class ProtogalaxyTestUtilities {
19 public:
28 using FoldingData = std::tuple<std::shared_ptr<ProverInstance>, std::shared_ptr<VerifierInstance>>;
35
40 const size_t& log_num_gates = 9,
41 const size_t& log_num_gates_with_public_inputs = 9)
42 {
43 using Fr = typename Curve::ScalarField;
45 using FrNative = typename Curve::ScalarFieldNative;
46
47 // Create 2^log_n many add gates based on input log num gates
49
50 // Create 2^log_n many add gates with public inputs based on input log num gates
51 MockCircuits::add_arithmetic_gates_with_public_inputs(builder, 1 << log_num_gates_with_public_inputs);
52
53 // Create lookup gates
55
56 // Create RAM gates
58
59 if constexpr (IsMegaFlavor<Flavor>) {
60 // Create ecc gates
62 }
63
64 // Arbitrary non-trivial arithmetic logic
65 Fr a = Fr::from_witness(&builder, FrNative::random_element(&engine));
66 Fr b = Fr::from_witness(&builder, FrNative::random_element(&engine));
67 Fr c = Fr::from_witness(&builder, FrNative::random_element(&engine));
68
69 for (size_t i = 0; i < 32; ++i) {
70 a = (a * b) + b + a;
71 a = a.madd(b, c);
72 }
73
74 // Bigfield arithmetic
75 FrNative bigfield_data = FrNative::random_element(&engine);
76 FrNative bigfield_data_a{ bigfield_data.data[0], bigfield_data.data[1], 0, 0 };
77 FrNative bigfield_data_b{ bigfield_data.data[2], bigfield_data.data[3], 0, 0 };
78
79 Fq big_a(Fr::from_witness(&builder, bigfield_data_a.to_montgomery_form()), Fr::from_witness(&builder, 0));
80 Fq big_b(Fr::from_witness(&builder, bigfield_data_b.to_montgomery_form()), Fr::from_witness(&builder, 0));
81
82 [[maybe_unused]] Fq result = big_a * big_b;
83
84 // Add default IO
86 };
87
93 size_t idx = 0,
94 TraceSettings trace_settings = TraceSettings{})
95 {
96
97 auto prover_instance = std::make_shared<ProverInstance>(builder, trace_settings);
98 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
99 auto verifier_instances = std::make_shared<VerifierInstance>(verification_key);
100 get<0>(keys)[idx] = prover_instance;
101 get<1>(keys)[idx] = verifier_instances;
102 }
103
108 size_t idx = 0,
109 TraceSettings trace_settings = TraceSettings{})
110 {
111 TupleOfKeys instances = construct_instances(2, trace_settings, true);
112 FoldingData accumulators = fold_and_verify(get<0>(instances), get<1>(instances));
113
114 get<0>(keys)[idx] = get<0>(accumulators);
115 get<1>(keys)[idx] = get<1>(accumulators);
116 }
117
121 static TupleOfKeys construct_instances(size_t num_keys,
122 TraceSettings trace_settings = TraceSettings{},
123 bool circuits_of_different_size = false)
124 {
125 std::vector<Builder> builders(num_keys);
126 parallel_for([&builders, &num_keys, &circuits_of_different_size](const ThreadChunk& chunk) {
127 for (size_t idx : chunk.range(num_keys)) {
128 size_t log_num_gates = circuits_of_different_size ? 9 + (idx & 1) : 9;
130 create_function_circuit(builder, log_num_gates, log_num_gates);
131 builders[idx] = std::move(builder);
132 }
133 });
134
135 // The following loop cannot be parallelized because the construction of a ProverInstance already has a
136 // parallel_for call and nested parallel_for calls are not allowed
137 TupleOfKeys keys;
138 for (size_t idx = 0; idx < num_keys; idx++) {
139 construct_instances_and_add_to_tuple(keys, builders[idx], idx, trace_settings);
140 }
141 return keys;
142 }
143
147 static FoldingData get_folding_data(const TupleOfKeys& keys, size_t idx)
148 {
149 return FoldingData(get<0>(keys)[idx], get<1>(keys)[idx]);
150 }
151
155 static FoldingResult<Flavor> fold(const ProverInstances& prover_instances,
156 const VerifierInstances& verification_keys,
157 bool hash_accumulator = false,
159 {
161 prover_transcript->enable_manifest();
162 if (hash_accumulator) {
163 // We allow this option because otherwise in a recursive setting the folding verifier interacts with
164 // values that it has never seen before (because Oink is not run on an accumulator). By hashing the
165 // verifier accumulator, we ensure its origin is properly tracked
166 BB_ASSERT_EQ(get<0>(verification_keys)->is_complete, true);
167 auto accumulator_hash = get<0>(verification_keys)->hash_through_transcript("-", *prover_transcript);
168 prover_transcript->add_to_hash_buffer("accumulator_hash", accumulator_hash);
169 }
170 FoldingProver folding_prover(prover_instances, verification_keys, prover_transcript, trace_usage_tracker);
171
172 return folding_prover.prove();
173 }
174
179 const HonkProof& folding_proof,
180 bool hash_accumulator = false)
181 {
183 verifier_transcript->enable_manifest();
184 if (hash_accumulator) {
185 // We allow this option because otherwise in a recursive setting the folding verifier interacts with
186 // values that it has never seen before (because Oink is not run on an accumulator). By hashing the
187 // verifier accumulator, we ensure its origin is properly tracked
188 auto accumulator_hash = get<0>(verification_keys)->hash_through_transcript("-", *verifier_transcript);
189 verifier_transcript->add_to_hash_buffer("accumulator_hash", accumulator_hash);
190 }
191 FoldingVerifier folding_verifier(verification_keys, verifier_transcript);
192 auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof);
193
194 return { verifier_accumulator, verifier_transcript };
195 }
196
200 static FoldingData fold_and_verify(const ProverInstances& prover_instances,
201 const VerifierInstances& verification_keys,
203 bool hash_accumulator = false)
204 {
205 auto [prover_accumulator, folding_proof] =
206 fold(prover_instances, verification_keys, hash_accumulator, trace_usage_tracker);
207
208 auto [verifier_accumulator, _] = verify_folding_proof(verification_keys, folding_proof, hash_accumulator);
209
210 return FoldingData{ prover_accumulator, verifier_accumulator };
211 }
212
216 static bool run_decider(const std::shared_ptr<ProverInstance>& prover_accumulator,
217 const std::shared_ptr<VerifierInstance>& verifier_accumulator)
218 {
219 DeciderProver decider_prover(prover_accumulator);
220 DeciderVerifier decider_verifier(verifier_accumulator);
221 decider_prover.construct_proof();
222 HonkProof decider_proof = decider_prover.export_proof();
223 auto decider_output = decider_verifier.verify_proof(decider_proof);
224 bool result = decider_output.check();
225 return result;
226 }
227
231 static std::pair<bool, std::string> compare_accumulators(const std::shared_ptr<VerifierInstance>& lhs,
232 const std::shared_ptr<VerifierInstance>& rhs)
233 {
234 bool equal = true;
235 std::string msg;
236
237 auto compare_iterators = [&equal, &msg]<typename T>(const T& lhs, const T& rhs, const std::string& label) {
238 if (lhs.size() != rhs.size()) {
239 equal = false;
240 msg += "\nMistmatch in the sizes of the ";
241 msg += label;
242 }
243 for (size_t idx = 0; idx < lhs.size(); idx++) {
244 if (lhs[idx] != rhs[idx]) {
245 equal = false;
246 msg += "\nMismatch in the ";
247 msg += label;
248 msg += " at index ";
249 msg += std::to_string(idx);
250 }
251 }
252 };
253
254 BB_ASSERT_EQ(lhs->is_complete, rhs->is_complete);
255 BB_ASSERT_EQ(lhs->is_complete, true);
256
257 compare_iterators(lhs->alphas, rhs->alphas, "alphas");
258 compare_iterators(
259 lhs->relation_parameters.get_to_fold(), rhs->relation_parameters.get_to_fold(), "relation paramaters");
260 compare_iterators(lhs->gate_challenges, rhs->gate_challenges, "gate challenges");
261 compare_iterators(
262 lhs->witness_commitments.get_all(), rhs->witness_commitments.get_all(), "witness commitments");
263 compare_iterators(lhs->vk->get_all(), rhs->vk->get_all(), "vk commitments");
264 if (lhs->target_sum != rhs->target_sum) {
265 equal = false;
266 msg += "\nMismatch in target sum";
267 }
268
269 return { equal, msg };
270 }
271
276 static std::pair<bool, std::string> compare_accumulators(const std::shared_ptr<ProverInstance>& lhs,
277 const std::shared_ptr<VerifierInstance>& rhs)
278 {
279 BB_ASSERT_EQ(lhs->is_complete, rhs->is_complete);
280 BB_ASSERT_EQ(lhs->is_complete, true);
281
282 auto lhs_vk = std::make_shared<VerificationKey>(lhs->get_precomputed());
283 auto lhs_verifier_instance = std::make_shared<VerifierInstance>(lhs_vk);
284 lhs_verifier_instance->is_complete = lhs->is_complete;
285
286 lhs->commitment_key = CommitmentKey<typename Flavor::Curve>(lhs->get_precomputed().metadata.dyadic_size);
287 for (auto [poly, comm] :
288 zip_view(lhs->polynomials.get_witness(), lhs_verifier_instance->witness_commitments.get_all())) {
289 comm = lhs->commitment_key.commit(poly);
290 }
291 lhs_verifier_instance->alphas = lhs->alphas;
292 for (auto [verifier, prover] : zip_view(lhs_verifier_instance->relation_parameters.get_to_fold(),
293 lhs->relation_parameters.get_to_fold())) {
294 verifier = prover;
295 };
296 lhs_verifier_instance->gate_challenges = lhs->gate_challenges;
297 lhs_verifier_instance->target_sum = lhs->target_sum;
298
299 return compare_accumulators(lhs_verifier_instance, rhs);
300 }
301};
302
309template <typename Flavor>
310static Flavor::FF compute_accumulator_target_sum_manual(const std::shared_ptr<ProverInstance_<Flavor>>& accumulator)
311{
313 accumulator->is_complete, true, "Computing the target sum of an incomplete accumulator, indefinite behaviour.");
314
315 using PGInternal = ProtogalaxyProverInternal<ProverInstance_<Flavor>>;
316
317 const size_t accumulator_size = accumulator->dyadic_size();
318 PGInternal pg_internal;
319 const auto expected_honk_evals = pg_internal.compute_row_evaluations(
320 accumulator->polynomials, accumulator->alphas, accumulator->relation_parameters);
321 // Construct pow(\vec{betas*}) as in the paper
322 GateSeparatorPolynomial expected_gate_separators(accumulator->gate_challenges, accumulator->gate_challenges.size());
323
324 // Compute the corresponding target sum and create a dummy accumulator
325 typename Flavor::FF expected_target_sum{ 0 };
326 for (size_t idx = 0; idx < accumulator_size; idx++) {
327 expected_target_sum += expected_honk_evals[idx] * expected_gate_separators[idx];
328 }
329 return expected_target_sum;
330}
331
336template <typename Flavor>
337static bool check_accumulator_target_sum_manual(const std::shared_ptr<ProverInstance_<Flavor>>& accumulator)
338{
339 return accumulator->target_sum == compute_accumulator_target_sum_manual(accumulator);
340}
341} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
CommitmentKey object over a pairing group 𝔾₁.
Output verify_proof(const DeciderProof &)
Verify a decider proof relative to a decider verification key (ϕ, \vec{β*}, e*).
typename Curve::ScalarField FF
static void add_some_ecc_op_gates(MegaBuilder &builder)
Generate a simple test circuit with some ECC op gates and conventional arithmetic gates.
The verification key is responsible for storing the commitments to the precomputed (non-witness) poly...
MegaCircuitBuilder CircuitBuilder
static void add_RAM_gates(Builder &builder)
Add some simple RAM (memory) gates for testing memory read/write functionality.
static void add_arithmetic_gates_with_public_inputs(Builder &builder, const size_t num_gates=4)
Add a specified number of arithmetic gates (with public inputs) to the provided circuit.
static void add_lookup_gates(Builder &builder, size_t num_iterations=1)
Add lookup gates using the uint32 XOR lookup table (table size 4096)
static void add_arithmetic_gates(Builder &builder, const size_t num_gates=4)
Add a specified number of arithmetic gates to the provided circuit.
std::array< std::shared_ptr< VerifierInstance >, NUM_INSTANCES > VerifierInstances
typename Flavor::VerificationKey VerificationKey
static void create_function_circuit(Builder &builder, const size_t &log_num_gates=9, const size_t &log_num_gates_with_public_inputs=9)
Create a circuit with the specified number of arithmetic gates and arithmetic gates with public input...
static FoldingVerificationResult verify_folding_proof(const VerifierInstances &verification_keys, const HonkProof &folding_proof, bool hash_accumulator=false)
Verify a folding proof. Return the folded accumulator and the verifier transcript.
std::tuple< std::shared_ptr< ProverInstance >, std::shared_ptr< VerifierInstance > > FoldingData
static FoldingResult< Flavor > fold(const ProverInstances &prover_instances, const VerifierInstances &verification_keys, bool hash_accumulator=false, ExecutionTraceUsageTracker trace_usage_tracker=ExecutionTraceUsageTracker{})
Fold two prover instances. Return folded accumulator and folding proof.
static FoldingData fold_and_verify(const ProverInstances &prover_instances, const VerifierInstances &verification_keys, ExecutionTraceUsageTracker trace_usage_tracker=ExecutionTraceUsageTracker{}, bool hash_accumulator=false)
Fold two prover instances and generate folded verifier by running the PG verifier.
ProtogalaxyProver_< Flavor > FoldingProver
std::array< std::shared_ptr< ProverInstance >, NUM_INSTANCES > ProverInstances
std::tuple< ProverInstances, VerifierInstances > TupleOfKeys
std::tuple< std::shared_ptr< VerifierInstance >, std::shared_ptr< typename FoldingVerifier::Transcript > > FoldingVerificationResult
static bool run_decider(const std::shared_ptr< ProverInstance > &prover_accumulator, const std::shared_ptr< VerifierInstance > &verifier_accumulator)
Run the decider on the given accumulator.
static void construct_instances_and_add_to_tuple(TupleOfKeys &keys, Builder &builder, size_t idx=0, TraceSettings trace_settings=TraceSettings{})
Construct Prover and Verifier instances for a provided circuit and add to tuple.
static FoldingData get_folding_data(const TupleOfKeys &keys, size_t idx)
Get folding data at index idx in the tuple of keys.
static std::pair< bool, std::string > compare_accumulators(const std::shared_ptr< VerifierInstance > &lhs, const std::shared_ptr< VerifierInstance > &rhs)
Compare two accumulators. Return the result of the comparison and error message.
static TupleOfKeys construct_instances(size_t num_keys, TraceSettings trace_settings=TraceSettings{}, bool circuits_of_different_size=false)
Construct a given number of Prover and Verifier instances.
static std::pair< bool, std::string > compare_accumulators(const std::shared_ptr< ProverInstance > &lhs, const std::shared_ptr< VerifierInstance > &rhs)
Compare a Prover accumulator and a Verifier accumulator. Return the result of the comparison and erro...
static void construct_accumulator_and_add_to_tuple(TupleOfKeys &keys, size_t idx=0, TraceSettings trace_settings=TraceSettings{})
Construct Prover and Verifier accumulators and add to tuple.
std::shared_ptr< VerifierInstance > verify_folding_proof(const std::vector< FF > &)
Run the folding protocol on the verifier side to establish whether the public data ϕ of the new accum...
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
The VerifierInstance encapsulates all the necessary information for a Mega Honk Verifier to verify a ...
static void add_default(Builder &builder)
Add default public inputs when they are not present.
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
Entry point for Barretenberg command-line interface.
std::vector< fr > HonkProof
Definition proof.hpp:15
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
Tracks the cumulative usage of the execution trace across a series of circuits.
The result of one iteraton of Protogalaxy proving, containing a new accumulator as well as the proof ...
field_t< CircuitBuilder > ScalarField
Definition bn254.hpp:33
curve::BN254::ScalarField ScalarFieldNative
Definition bn254.hpp:24