5#include "barretenberg/bbapi/generated/bb_types.hpp"
24#ifdef BBAPI_CHONK_BATCH_VERIFIER_SUPPORTED
37#ifdef BB_NO_EXCEPTIONS
39#define catch(...) if (false)
40#define BBAPI_CHONK_UNDEF_TRY_CATCH
46#ifndef BB_NO_EXCEPTIONS
47#define BBAPI_CHONK_EXCEPTION_WHAT(exception) (exception).what()
49#define BBAPI_CHONK_EXCEPTION_WHAT(exception) "unknown exception"
52template <
typename VerificationKey>
bool has_expected_vk_size(
const std::vector<uint8_t>& vk_bytes,
const char* label)
55 if (vk_bytes.size() == expected_size) {
59 info(label,
": verification key has wrong size: expected ", expected_size,
", got ", vk_bytes.size());
118 const bool is_hiding_kernel = (request.
ivc_stack_depth + 1 == chonk->get_num_circuits());
121 auto circuit = acir_format::create_circuit<IVCBase::ClientCircuit>(program, metadata);
125 precomputed_vk =
nullptr;
127 if (!loaded_vk.empty()) {
128 validate_vk_size<Chonk::MegaVerificationKey>(loaded_vk);
129 precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(loaded_vk);
138 if (*precomputed_vk != *computed_vk) {
140 "': provided VK does not match computed VK");
145 throw_or_abort(
"Invalid VK policy. Valid options: default, check, recompute");
148 info(
"ChonkAccumulate - accumulating circuit '", circuit_name,
"'");
164 throw_or_abort(
"No circuits accumulated. Call ChonkAccumulate first.");
167 info(
"ChonkProve - generating proof for ", request.
ivc_stack_depth,
" accumulated circuits");
169 info(
"ChonkProve - using Chonk");
171 auto proof = chonk->prove();
172 auto vk_and_hash = chonk->get_hiding_kernel_vk_and_hash();
176 info(
"ChonkProve - verifying the generated proof as a sanity check");
178 bool verification_passed = verifier.
verify(proof);
179 if (!verification_passed) {
194 if (!has_expected_vk_size<VerificationKey>(cmd.vk,
"ChonkVerify")) {
195 return { .valid =
false };
202 const size_t expected_proof_size =
204 if (proof.size() != expected_proof_size) {
205 info(
"ChonkVerify: proof has wrong size: expected ", expected_proof_size,
", got ", proof.size());
206 return { .valid =
false };
211 return { .valid = verifier.
verify(proof) };
212 }
catch (
const std::exception& e) {
214 return { .valid =
false };
216 info(
"ChonkVerify: malformed input: unknown exception");
217 return { .valid =
false };
222 wire::ChonkVerifyFromFields&& cmd)
228 if (!has_expected_vk_size<VerificationKey>(cmd.vk,
"ChonkVerifyFromFields")) {
229 return { .valid =
false };
236 const size_t expected_field_count =
238 if (proof.size() != expected_field_count) {
239 info(
"ChonkVerifyFromFields: proof has wrong field count: expected ",
240 expected_field_count,
243 return { .valid =
false };
251 return { .valid = verifier.
verify(structured) };
252 }
catch (
const std::exception& e) {
254 return { .valid =
false };
256 info(
"ChonkVerifyFromFields: malformed input: unknown exception");
257 return { .valid =
false };
266 if (cmd.proofs.size() != cmd.vks.size()) {
267 info(
"ChonkBatchVerify: proofs.size() (", cmd.proofs.size(),
") != vks.size() (", cmd.vks.size(),
")");
268 return { .valid =
false };
270 if (cmd.proofs.empty()) {
271 info(
"ChonkBatchVerify: no proofs provided");
272 return { .valid =
false };
279 ipa_claims.reserve(cmd.proofs.size());
280 ipa_transcripts.reserve(cmd.proofs.size());
283 for (
size_t i = 0; i < proofs.size(); ++i) {
284 if (!has_expected_vk_size<VerificationKey>(cmd.vks[i],
"ChonkBatchVerify")) {
285 return { .valid =
false };
289 const size_t expected_proof_size =
291 if (proofs[i].size() != expected_proof_size) {
292 info(
"ChonkBatchVerify: proof[",
294 "] has wrong size: expected ",
298 return { .valid =
false };
304 if (!result.all_checks_passed) {
305 return { .valid =
false };
307 ipa_claims.push_back(
std::move(result.ipa_claim));
313 }
catch (
const std::exception& e) {
315 return { .valid =
false };
317 info(
"ChonkBatchVerify: malformed input: unknown exception");
318 return { .valid =
false };
338 info(
"ChonkComputeVk - deriving MegaVerificationKey for circuit '",
341 cmd.use_zk_flavor ?
" (MegaZK)" :
"");
345 auto verification_key = compute_chonk_vk_from_program(program, cmd.use_zk_flavor);
347 info(
"ChonkComputeVk - VK derived, size: ",
to_buffer(*verification_key).size(),
" bytes");
349 return { .bytes =
to_buffer(*verification_key), .fields =
fr_vec_to_wire(verification_key->to_field_elements()) };
353 wire::ChonkCheckPrecomputedVk&& cmd)
358 auto computed_vk = compute_chonk_vk_from_program(program, cmd.use_zk_flavor);
360 if (cmd.circuit.verification_key.empty()) {
361 info(
"FAIL: Expected precomputed vk for function ", cmd.circuit.name);
365 validate_vk_size<Chonk::MegaVerificationKey>(cmd.circuit.verification_key);
366 auto precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(cmd.circuit.verification_key);
368 wire::ChonkCheckPrecomputedVkResponse response;
369 response.valid =
true;
370 if (*computed_vk != *precomputed_vk) {
371 response.valid =
false;
372 response.actual_vk =
to_buffer(computed_vk);
383 const auto& ivc_constraints = constraint_system.hn_recursion_constraints;
387 .collect_gates_per_opcode = cmd.include_gates_per_opcode
390 auto builder = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
393 wire::ChonkStatsResponse response;
395 response.circuit_size =
static_cast<uint32_t
>(
builder.num_gates());
396 if (cmd.include_gates_per_opcode) {
401 info(
"ChonkStats - circuit: ",
404 response.acir_opcodes,
406 response.circuit_size);
419 wire::ChonkDecompressProof&& cmd)
429#ifdef BBAPI_CHONK_BATCH_VERIFIER_SUPPORTED
433bool write_all(
int fd,
const uint8_t* ptr,
size_t len)
436 const auto chunk_len =
437 static_cast<unsigned int>(
std::min<size_t>(
len, std::numeric_limits<unsigned int>::max()));
438 const ssize_t written =
::write(fd, ptr, chunk_len);
441 len -=
static_cast<size_t>(written);
444 if (written < 0 && errno == EINTR) {
447 if (written < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
448 std::this_thread::sleep_for(std::chrono::milliseconds(1));
456bool write_frame(
int fd,
const void*
data,
size_t len)
458 if (
len > UINT32_MAX) {
461 auto len32 =
static_cast<uint32_t
>(
len);
462 std::vector<uint8_t> header = {
463 static_cast<uint8_t
>((len32 >> 24) & 0xFF),
464 static_cast<uint8_t
>((len32 >> 16) & 0xFF),
465 static_cast<uint8_t
>((len32 >> 8) & 0xFF),
466 static_cast<uint8_t
>(len32 & 0xFF),
469 return write_all(fd, header.data(), header.size()) && write_all(fd,
reinterpret_cast<const uint8_t*
>(
data),
len);
477 const std::string& fifo_path)
479 bool expected =
false;
480 if (!
running_.compare_exchange_strong(expected,
true)) {
484 if (num_cores == 0) {
485 num_cores =
static_cast<uint32_t
>(std::thread::hardware_concurrency());
486 if (num_cores == 0) {
505 info(
"ChonkBatchVerifierService started, fifo=", fifo_path);
535 info(
"ChonkBatchVerifierService stopped");
556 if (lstat(
fifo_path_.c_str(), &statbuf) != 0) {
560 if (!S_ISFIFO(statbuf.st_mode)) {
561 info(
"ChonkBatchVerifierService: result path is not a FIFO: ",
fifo_path_);
566 for (
size_t attempt = 0; attempt < 100; ++attempt) {
574 struct stat opened_statbuf;
575 if (fstat(
fifo_fd_, &opened_statbuf) != 0 || !S_ISFIFO(opened_statbuf.st_mode)) {
576 info(
"ChonkBatchVerifierService: opened result path is not a FIFO: ",
fifo_path_);
584 if (errno != ENXIO && errno != EINTR) {
588 std::this_thread::sleep_for(std::chrono::milliseconds(1));
590 info(
"ChonkBatchVerifierService: no FIFO reader connected for '",
fifo_path_,
"'");
605 info(
"ChonkBatchVerifierService: ", message);
614 msgpack::sbuffer buf;
615 msgpack::pack(buf, result);
625 if (!write_frame(
fifo_fd_, buf.data(), buf.size())) {
634 wire::ChonkBatchVerifierStart&& cmd)
636 if (request.batch_verifier_service && request.batch_verifier_service->is_running()) {
637 throw_or_abort(
"ChonkBatchVerifierStart: service already running. Call ChonkBatchVerifierStop first.");
643 parsed_vks.reserve(cmd.vks.size());
645 for (
size_t i = 0; i < cmd.vks.size(); ++i) {
646 validate_vk_size<VerificationKey>(cmd.vks[i]);
652 request.batch_verifier_service->start(
std::move(parsed_vks), cmd.num_cores, cmd.batch_size, cmd.fifo_path);
657 wire::ChonkBatchVerifierQueue&& cmd)
659 if (!request.batch_verifier_service || !request.batch_verifier_service->is_running()) {
660 throw_or_abort(
"ChonkBatchVerifierQueue: service not running. Call ChonkBatchVerifierStart first.");
666 }
catch (
const std::exception& e) {
667 request.batch_verifier_service->fail_request(cmd.request_id,
668 std::string(
"malformed proof fields: ") + e.what());
671 request.batch_verifier_service->fail_request(cmd.request_id,
"malformed proof fields: unknown exception");
678 .vk_index = cmd.vk_index,
681 }
catch (
const std::exception& e) {
682 request.batch_verifier_service->fail_request(cmd.request_id, e.what());
684 request.batch_verifier_service->fail_request(cmd.request_id,
"failed to enqueue proof: unknown exception");
691 wire::ChonkBatchVerifierStop&& )
693 if (!request.batch_verifier_service || !request.batch_verifier_service->is_running()) {
697 request.batch_verifier_service->stop();
698 request.batch_verifier_service.reset();
705 wire::ChonkBatchVerifierStart&& )
707 throw_or_abort(
"ChonkBatchVerifierStart is not supported in this build");
711 wire::ChonkBatchVerifierQueue&& )
713 throw_or_abort(
"ChonkBatchVerifierQueue is not supported in this build");
717 wire::ChonkBatchVerifierStop&& )
719 throw_or_abort(
"ChonkBatchVerifierStop is not supported in this build");
724#undef BBAPI_CHONK_EXCEPTION_WHAT
725#ifdef BBAPI_CHONK_UNDEF_TRY_CATCH
728#undef BBAPI_CHONK_UNDEF_TRY_CATCH
#define BB_BENCH_NAME(name)
#define BBAPI_CHONK_EXCEPTION_WHAT(exception)
Stateful Chonk batch-verifier service used by the IPC handlers.
Non-template handler declarations for the bb service.
Shared type definitions for the Barretenberg RPC API.
Wire <-> domain conversion helpers for the bbapi handlers.
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.
Flavor::VerificationKey MegaVerificationKey
Verifier for Chonk IVC proofs (both native and recursive).
IPAReductionResult reduce_to_ipa_claim(const Proof &proof)
Run Chonk verification up to but not including IPA, returning the IPA claim for deferred verification...
Output verify(const Proof &proof)
Verify a Chonk proof.
static constexpr size_t ECCVM_FIXED_SIZE
IPA (inner product argument) commitment scheme class.
Base Native verification key class.
static constexpr size_t calc_num_data_types()
Calculate the number of field elements needed for serialization.
static std::vector< uint8_t > compress_chonk_proof(const ChonkProof &proof)
static ChonkProof decompress_chonk_proof(const std::vector< uint8_t > &compressed, size_t mega_num_public_inputs)
static size_t compressed_mega_num_public_inputs(size_t compressed_bytes)
Derive mega_num_public_inputs from compressed proof size.
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
void enqueue(VerifyRequest request)
~ChonkBatchVerifierService()
std::atomic_bool running_
ChonkBatchVerifier verifier_
void fail_request(uint64_t request_id, std::string error_message)
bool write_result(VerifyResult result)
void start(std::vector< std::shared_ptr< MegaZKFlavor::VKAndHash > > vks, uint32_t num_cores, uint32_t batch_size, const std::string &fifo_path)
std::atomic_bool fifo_failed_
bool fail_fifo_locked(const std::string &message)
wire::ChonkBatchVerifierStartResponse handle_chonk_batch_verifier_start(BBApiRequest &, wire::ChonkBatchVerifierStart &&)
bool has_expected_vk_size(const std::vector< uint8_t > &vk_bytes, const char *label)
wire::ChonkBatchVerifyResponse handle_chonk_batch_verify(BBApiRequest &, wire::ChonkBatchVerify &&cmd)
wire::ChonkVerifyResponse handle_chonk_verify(BBApiRequest &, wire::ChonkVerify &&cmd)
wire::ChonkProveResponse handle_chonk_prove(BBApiRequest &request, wire::ChonkProve &&)
wire::ChonkDecompressProofResponse handle_chonk_decompress_proof(BBApiRequest &, wire::ChonkDecompressProof &&cmd)
wire::ChonkProof chonk_proof_to_wire(const ChonkProof &d)
wire::ChonkCompressProofResponse handle_chonk_compress_proof(BBApiRequest &, wire::ChonkCompressProof &&cmd)
wire::ChonkAccumulateResponse handle_chonk_accumulate(BBApiRequest &request, wire::ChonkAccumulate &&cmd)
wire::ChonkLoadResponse handle_chonk_load(BBApiRequest &request, wire::ChonkLoad &&cmd)
ChonkProof chonk_proof_from_wire(wire::ChonkProof &&w)
wire::ChonkStartResponse handle_chonk_start(BBApiRequest &request, wire::ChonkStart &&cmd)
wire::ChonkBatchVerifierStopResponse handle_chonk_batch_verifier_stop(BBApiRequest &, wire::ChonkBatchVerifierStop &&)
std::vector< Fr > fr_vec_to_wire(const std::vector< bb::fr > &d)
wire::ChonkComputeVkResponse handle_chonk_compute_vk(BBApiRequest &, wire::ChonkComputeVk &&cmd)
wire::ChonkVerifyFromFieldsResponse handle_chonk_verify_from_fields(BBApiRequest &, wire::ChonkVerifyFromFields &&cmd)
wire::ChonkCheckPrecomputedVkResponse handle_chonk_check_precomputed_vk(BBApiRequest &, wire::ChonkCheckPrecomputedVk &&cmd)
std::vector< ChonkProof > chonk_proof_vec_from_wire(std::vector< wire::ChonkProof > &&w)
wire::ChonkBatchVerifierQueueResponse handle_chonk_batch_verifier_queue(BBApiRequest &, wire::ChonkBatchVerifierQueue &&)
std::vector< bb::fr > fr_vec_from_wire(const std::vector< Fr > &w)
wire::ChonkStatsResponse handle_chonk_stats(BBApiRequest &, wire::ChonkStats &&cmd)
MemoryProfile GLOBAL_MEMORY_PROFILE
field< Bn254FrParams > fr
void write(B &buf, field2< base_field, Params > const &value)
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::vector< uint8_t > to_buffer(T const &value)
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
static ChonkProof_ from_field_elements(const std::vector< FF > &fields)
Reconstruct proof from field elements.
A request to verify a single Chonk proof.
Result of verifying a single proof within a batch.
static VerifyResult failed(uint64_t id, std::string msg)
std::string loaded_circuit_name
std::shared_ptr< IVCBase > ivc_in_progress
std::vector< uint8_t > loaded_circuit_vk
std::optional< acir_format::AcirFormat > loaded_circuit_constraints
void set_circuit_name(const std::string &name)
void throw_or_abort(std::string const &err)