18 std::lock_guard lock(
mutex_);
39 bool has_failure =
false;
41 std::lock_guard lock(
mutex_);
43 throw_or_abort(
"ChonkBatchVerifier: enqueue called while verifier is not running");
62 const size_t expected_proof_size =
static_cast<size_t>(
vks_[request.
vk_index]->vk->num_public_inputs) +
64 if (request.
proof.
size() != expected_proof_size) {
66 "proof has wrong size: expected " +
std::to_string(expected_proof_size) +
83 std::thread coordinator_thread;
85 std::unique_lock lock(
mutex_);
100 if (coordinator_thread.joinable()) {
101 coordinator_thread.join();
104 std::lock_guard lock(
mutex_);
111 info(
"ChonkBatchVerifier stopped");
116 bool should_stop =
false;
118 std::lock_guard lock(
mutex_);
128 const uint64_t request_id =
result.request_id;
134 }
catch (
const std::exception& e) {
135 info(
"ChonkBatchVerifier: result callback threw: ", e.what());
137 info(
"ChonkBatchVerifier: result callback threw unknown exception");
139 std::lock_guard lock(
mutex_);
149 std::unique_lock lock(
mutex_);
159 auto end =
queue_.begin() +
static_cast<ptrdiff_t
>(take);
179 auto reduce_start = std::chrono::steady_clock::now();
183 std::vector<size_t> passed_indices;
184 passed_indices.reserve(reduce_results.size());
185 for (
size_t i = 0; i < reduce_results.size(); ++i) {
186 auto& rr = reduce_results[i];
187 if (!rr.all_checks_passed) {
190 result.time_in_verify_ms = rr.reduce_ms;
193 passed_indices.push_back(i);
197 if (passed_indices.empty()) {
202 auto ipa_start = std::chrono::steady_clock::now();
203 bool ok =
batch_check(reduce_results, passed_indices);
204 const double ipa_ms =
ms_since(ipa_start);
205 const double reduce_ms =
ms_between(reduce_start, ipa_start);
207 info(
"ChonkBatchVerifier: batch of ",
208 passed_indices.size(),
214 ok ?
"OK" :
"BISECTING");
217 emit_ok(reduce_results, passed_indices, reduce_start, ipa_ms, 0);
219 bisect(reduce_results, passed_indices, 0, reduce_start);
227 const size_t num_proofs = batch.size();
229 std::atomic<size_t> work_index{ 0 };
231 uint32_t num_workers = std::min(
num_cores_,
static_cast<uint32_t
>(num_proofs));
232 std::vector<std::thread> workers;
233 workers.reserve(num_workers);
235 for (uint32_t w = 0; w < num_workers; ++w) {
236 workers.emplace_back([&]() {
241 if (idx >= num_proofs) {
244 auto& req = batch[idx];
245 auto t0 = std::chrono::steady_clock::now();
253 .triple_ipa_opening =
std::move(reduced.triple_ipa_opening),
254 .all_checks_passed = reduced.all_checks_passed,
255 .error_message = reduced.all_checks_passed ?
"" :
"reduction failed",
256 .enqueue_time = req.enqueue_time,
259 }
catch (
const std::exception& e) {
263 .all_checks_passed =
false,
264 .error_message = std::string(
"reduce_to_triple_ipa_opening threw: ") + e.what(),
265 .enqueue_time = req.enqueue_time,
272 .all_checks_passed =
false,
273 .error_message =
"reduce_to_triple_ipa_opening threw unknown exception",
274 .enqueue_time = req.enqueue_time,
281 for (
auto& t : workers) {
290 if (indices.empty()) {
298 accumulators.reserve(indices.size());
299 for (
size_t idx : indices) {
300 accumulators.push_back(results[idx].triple_ipa_opening.value().reduce_to_accumulator());
304 }
catch (
const std::exception& e) {
305 info(
"ChonkBatchVerifier: batch_check exception: ", e.what());
311 std::vector<size_t> indices,
313 std::chrono::steady_clock::time_point reduce_start)
316 if (indices.size() == 1) {
317 auto& rr = results[indices[0]];
319 result.time_in_queue_ms =
ms_between(rr.enqueue_time, std::chrono::steady_clock::now());
320 result.time_in_verify_ms = rr.reduce_ms;
321 result.batch_failure_count = depth + 1;
326 info(
"ChonkBatchVerifier: bisecting ", indices.size(),
" proofs at depth ", depth);
328 size_t mid = indices.size() / 2;
329 std::vector<size_t> left(indices.begin(), indices.begin() +
static_cast<ptrdiff_t
>(mid));
330 std::vector<size_t> right(indices.begin() +
static_cast<ptrdiff_t
>(mid), indices.end());
333 auto t0 = std::chrono::steady_clock::now();
338 emit_ok(results, left, reduce_start, left_ms, depth + 1);
345 auto t1 = std::chrono::steady_clock::now();
350 emit_ok(results, right, reduce_start, right_ms, depth + 1);
358 const std::vector<size_t>& indices,
359 std::chrono::steady_clock::time_point reduce_start,
363 for (
size_t idx : indices) {
364 auto& rr = results[idx];
369 .time_in_queue_ms =
ms_between(rr.enqueue_time, reduce_start),
370 .time_in_verify_ms = rr.reduce_ms + pcs_ms,
371 .batch_failure_count = depth,
std::vector< ReduceResult > parallel_reduce(const std::vector< VerifyRequest > &batch)
void bisect(std::vector< ReduceResult > &results, std::vector< size_t > indices, uint32_t depth, std::chrono::steady_clock::time_point reduce_start)
static double ms_between(std::chrono::steady_clock::time_point from, std::chrono::steady_clock::time_point to)
std::thread coordinator_thread_
std::function< void(VerifyResult)> ResultCallback
void dispatch(VerifyResult result)
bool batch_check(const std::vector< ReduceResult > &results, const std::vector< size_t > &indices)
std::condition_variable stopped_cv_
static double ms_since(std::chrono::steady_clock::time_point t)
static constexpr size_t MAX_QUEUE_SIZE
std::vector< std::shared_ptr< MegaZKFlavor::VKAndHash > > vks_
std::deque< VerifyRequest > queue_
std::unordered_set< uint64_t > in_flight_ids_
void enqueue(VerifyRequest request)
Enqueue a proof for verification.
void emit_ok(const std::vector< ReduceResult > &results, const std::vector< size_t > &indices, std::chrono::steady_clock::time_point reduce_start, double pcs_ms, uint32_t depth)
std::condition_variable cv_
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.
ResultCallback on_result_
Verifier for Chonk IVC proofs (both native and recursive).
TripleIpaReductionResult reduce_to_triple_ipa_opening(const Proof &proof)
Run Chonk verification up to but not including TripleIPA verification.
static bool batch_verify_accumulators(std::span< const TripleIpaAccumulator > accumulators)
Entry point for Barretenberg command-line interface.
void set_parallel_for_concurrency(size_t num_cores)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::string to_string(bb::avm2::ValueTag tag)
Per-proof result from the reduce phase.
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
A request to verify a single Chonk proof.
std::chrono::steady_clock::time_point enqueue_time
Result of verifying a single proof within a batch.
static VerifyResult failed(uint64_t id, std::string msg)
void throw_or_abort(std::string const &err)