10#include <condition_variable>
20static constexpr size_t SMALL_LOG_2_NUM_GATES = 5;
29 size_t num_app_circuits = 1)
32 const size_t num_circuits = circuit_producer.total_num_circuits;
33 Chonk ivc{ num_circuits };
34 TestSettings settings{ .log2_num_gates = SMALL_LOG_2_NUM_GATES };
35 for (
size_t j = 0; j < num_circuits; ++j) {
36 circuit_producer.construct_and_accumulate_next_circuit(ivc, settings);
38 return { ivc.prove(), ivc.get_hiding_kernel_vk_and_hash() };
46 constexpr size_t commitment_size = FrCodec::template calc_num_fields<IpaCommitment>();
47 constexpr size_t scalar_size = FrCodec::template calc_num_fields<IpaScalar>();
48 constexpr size_t g_zero_offset = 2 * CONST_ECCVM_LOG_N * commitment_size;
49 static_assert(g_zero_offset + commitment_size + scalar_size == IPA_PROOF_LENGTH);
50 ASSERT_LE(g_zero_offset + commitment_size, proof.
ipa_proof.size());
52 IpaCommitment wrong_g_zero = IpaCommitment::one() * IpaScalar(7);
53 auto wrong_g_zero_fields = FrCodec::serialize_to_fields<IpaCommitment>(wrong_g_zero);
55 wrong_g_zero_fields.end(),
70 std::lock_guard lock(
mutex);
75 void wait_for(
size_t count, std::chrono::seconds timeout = std::chrono::seconds(120))
78 std::unique_lock lock(
mutex);
79 ASSERT_TRUE(
cv.wait_for(lock, timeout, [&] { return results.size() >= expected; }))
80 <<
"Timed out waiting for " <<
expected <<
" results, got " <<
results.size();
87 auto [proof1, vk1] = generate_chonk_proof();
88 auto [proof2, vk2] = generate_chonk_proof();
90 ResultCollector collector;
100 collector.wait_for(2);
103 ASSERT_EQ(collector.results.size(), 2);
104 for (
auto& r : collector.results) {
105 EXPECT_TRUE(r.verified()) <<
"request_id=" << r.request_id <<
" error=" << r.error_message;
106 EXPECT_GT(r.time_in_verify_ms, 0);
113 auto [proof,
vk] = generate_chonk_proof();
115 ResultCollector collector;
125 ASSERT_EQ(collector.results.size(), 1);
126 EXPECT_TRUE(collector.results[0].verified());
127 EXPECT_EQ(collector.results[0].request_id, 42);
134 auto [good_proof, vk1] = generate_chonk_proof();
135 auto [bad_proof, vk2] = generate_chonk_proof();
138 ASSERT_FALSE(bad_proof.ipa_proof.empty());
139 bad_proof.ipa_proof[0] = bad_proof.ipa_proof[0] +
bb::fr(1);
141 ResultCollector collector;
150 collector.wait_for(2);
153 ASSERT_EQ(collector.results.size(), 2);
158 for (
auto& r : collector.results) {
159 if (r.request_id == 1) {
162 if (r.request_id == 2) {
167 ASSERT_NE(good,
nullptr);
168 ASSERT_NE(bad,
nullptr);
170 EXPECT_FALSE(bad->
verified()) <<
"bad proof should fail";
178 auto [good_proof,
vk] = generate_chonk_proof();
179 auto bad_proof = good_proof;
180 tamper_ipa_g_zero(bad_proof);
183 EXPECT_FALSE(direct_verifier.
verify(bad_proof));
185 ResultCollector collector;
193 collector.wait_for(2);
196 std::sort(collector.results.begin(), collector.results.end(), [](
auto&
a,
auto&
b) {
197 return a.request_id < b.request_id;
199 ASSERT_EQ(collector.results.size(), 2);
200 EXPECT_TRUE(collector.results[0].verified()) << collector.results[0].error_message;
201 EXPECT_FALSE(collector.results[1].verified());
206 auto [proof,
vk] = generate_chonk_proof();
208 ResultCollector collector;
215 ".*duplicate request_id.*");
217 collector.wait_for(1);
223 auto [proof,
vk] = generate_chonk_proof();
225 ResultCollector collector;
237 auto [proof,
vk] = generate_chonk_proof();
239 ResultCollector collector;
245 std::thread stop_a([&] { verifier.
stop(); });
246 std::thread stop_b([&] { verifier.
stop(); });
250 ASSERT_EQ(collector.results.size(), 1);
251 EXPECT_TRUE(collector.results[0].verified());
256 auto [proof,
vk] = generate_chonk_proof();
259 ResultCollector collector;
264 ".*already started.*");
270 auto [proof,
vk] = generate_chonk_proof();
271 proof.joint_proof.push_back(
bb::fr(1));
273 ResultCollector collector;
279 collector.wait_for(1);
282 ASSERT_EQ(collector.results.size(), 1);
283 EXPECT_FALSE(collector.results[0].verified());
284 EXPECT_NE(collector.results[0].error_message.find(
"wrong size"), std::string::npos);
289 auto [proof,
vk] = generate_chonk_proof();
293 size_t callback_count = 0;
298 std::lock_guard lock(mutex);
302 throw std::runtime_error(
"callback failed");
308 std::unique_lock lock(mutex);
309 ASSERT_TRUE(cv.wait_for(lock, std::chrono::seconds(120), [&] { return callback_count == 1; }));
323 auto [good_proof_template,
vk] = generate_chonk_proof();
334 { 42, 16, 0, 16, 4 },
336 { 8080, 30, 1, 30, 4 },
337 { 2025, 30, 10, 30, 4 },
338 { 6174, 30, 15, 30, 4 },
339 { 9999, 30, 29, 30, 4 },
340 { 1337, 30, 7, 8, 4 },
341 { 314, 12, 3, 12, 1 },
345 for (
const auto& [seed, total, num_bad, batch_size, num_cores] : cases) {
350 std::vector<size_t> indices(total);
351 std::iota(indices.begin(), indices.end(), 0);
353 for (
size_t i = total - 1; i > 0; --i) {
355 std::swap(indices[i], indices[dist(rng)]);
357 std::set<size_t> bad_indices(indices.begin(), indices.begin() +
static_cast<ptrdiff_t
>(num_bad));
361 proofs.reserve(total);
362 for (
size_t i = 0; i < total; ++i) {
363 proofs.push_back(good_proof_template);
364 if (bad_indices.count(i)) {
365 proofs.back().ipa_proof[0] = proofs.back().ipa_proof[0] +
bb::fr(1);
369 ResultCollector collector;
373 for (
size_t i = 0; i < total; ++i) {
378 collector.wait_for(total, std::chrono::seconds(300));
381 ASSERT_EQ(collector.results.size(), total);
382 std::sort(collector.results.begin(), collector.results.end(), [](
auto&
a,
auto&
b) {
383 return a.request_id < b.request_id;
385 for (
size_t i = 0; i < total; ++i) {
386 EXPECT_EQ(collector.results[i].request_id, i);
387 if (bad_indices.count(i)) {
388 EXPECT_FALSE(collector.results[i].verified()) <<
"proof " << i <<
" should fail";
390 EXPECT_TRUE(collector.results[i].verified()) <<
"proof " << i <<
" should pass";
398 auto [proof,
vk] = generate_chonk_proof();
400 ResultCollector collector;
409 collector.wait_for(1);
412 ASSERT_EQ(collector.results.size(), 1);
413 EXPECT_FALSE(collector.results[0].verified());
414 EXPECT_EQ(collector.results[0].request_id, 7);
415 EXPECT_NE(collector.results[0].error_message.find(
"invalid vk_index"), std::string::npos);
#define EXPECT_THROW_OR_ABORT(statement, matcher)
#define BB_DISABLE_ASSERTS()
TEST_F(ChonkBatchVerifierTests, BatchOfTwoValidProofs)
static void SetUpTestSuite()
PrivateFunctionExecutionMockCircuitProducer CircuitProducer
static std::pair< ChonkProof, std::shared_ptr< MegaZKFlavor::VKAndHash > > generate_chonk_proof(size_t num_app_circuits=1)
static void tamper_ipa_g_zero(ChonkProof &proof)
Asynchronous batch verifier for Chonk IVC proofs.
void enqueue(VerifyRequest request)
Enqueue a proof for verification.
void stop()
Stop the processor, flushing remaining proofs.
void start(std::vector< std::shared_ptr< MegaZKFlavor::VKAndHash > > vks, uint32_t num_cores, uint32_t batch_size, ResultCallback on_result)
Start the coordinator thread.
The IVC scheme used by the aztec client for private function execution.
Verifier for Chonk IVC proofs (both native and recursive).
Output verify(const Proof &proof)
Verify a Chonk proof.
typename Group::affine_element AffineElement
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
::testing::Types< BN254Settings, GrumpkinSettings > TestSettings
field< Bn254FrParams > fr
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)
Helper: collect results from the processor via callback.
std::condition_variable cv
void wait_for(size_t count, std::chrono::seconds timeout=std::chrono::seconds(120))
void on_result(VerifyResult r)
std::vector< VerifyResult > results
A request to verify a single Chonk proof.
Result of verifying a single proof within a batch.
uint32_t batch_failure_count
std::string error_message