20#ifdef BB_HAS_BATCH_VERIFIER_SERVICE
49 throw_or_abort(
"Invalid VK policy. Valid options: default, check, recompute");
55#ifndef BB_NO_EXCEPTIONS
56#define BBAPI_CHONK_EXCEPTION_WHAT(exception) (exception).what()
58#define BBAPI_CHONK_EXCEPTION_WHAT(exception) "unknown exception"
64 if (vk_bytes.size() == expected_size) {
68 info(
label,
": verification key has wrong size: expected ", expected_size,
", got ", vk_bytes.size());
80 request.loaded_circuit_name.clear();
81 request.loaded_circuit_constraints.reset();
82 request.loaded_circuit_vk.clear();
91 if (!request.ivc_in_progress) {
95 request.loaded_circuit_name = circuit.name;
97 request.loaded_circuit_vk = circuit.verification_key;
98 request.loaded_circuit_kind = kind;
100 info(
"ChonkLoad - loaded circuit '", request.loaded_circuit_name,
"'");
108 if (!request.ivc_in_progress) {
112 if (!request.loaded_circuit_constraints.has_value()) {
122 auto loaded_vk =
std::move(request.loaded_circuit_vk);
123 auto circuit_name =
std::move(request.loaded_circuit_name);
124 const CircuitKind loaded_kind = request.loaded_circuit_kind;
125 request.loaded_circuit_constraints.reset();
126 request.loaded_circuit_vk.clear();
127 request.loaded_circuit_name.clear();
130 request.ivc_in_progress->process_step({ .name =
std::move(circuit_name),
133 .kind = loaded_kind },
134 to_chonk_vk_policy(request.vk_policy));
142 if (!request.ivc_in_progress) {
146 const size_t num_circuits_accumulated = request.ivc_in_progress->get_num_circuits_accumulated();
147 if (num_circuits_accumulated == 0) {
148 throw_or_abort(
"No circuits accumulated. Call ChonkAccumulate first.");
151 info(
"ChonkProve - generating proof for ", num_circuits_accumulated,
" accumulated circuits");
153 auto proof = request.ivc_in_progress->prove();
154 auto vk_and_hash = request.ivc_in_progress->get_hiding_kernel_vk_and_hash();
158 info(
"ChonkProve - verifying the generated proof as a sanity check");
160 if (!verifier.
verify(proof)) {
164 request.ivc_in_progress.reset();
175 if (!has_expected_vk_size<VerificationKey>(
vk,
"ChonkVerify")) {
176 return { .valid =
false };
183 const size_t expected_proof_size =
185 if (proof.size() != expected_proof_size) {
186 info(
"ChonkVerify: proof has wrong size: expected ", expected_proof_size,
", got ", proof.size());
187 return { .valid =
false };
193 const bool verified = verifier.
verify(proof);
195 return { .valid = verified };
196 }
catch (
const std::exception& e) {
198 return { .valid =
false };
200 info(
"ChonkVerify: malformed input: unknown exception");
201 return { .valid =
false };
211 if (!has_expected_vk_size<VerificationKey>(
vk,
"ChonkVerifyFromFields")) {
212 return { .valid =
false };
219 const size_t expected_field_count =
221 if (proof.size() != expected_field_count) {
222 info(
"ChonkVerifyFromFields: proof has wrong field count: expected ",
223 expected_field_count,
226 return { .valid =
false };
234 const bool verified = verifier.
verify(structured);
236 return { .valid = verified };
237 }
catch (
const std::exception& e) {
239 return { .valid =
false };
241 info(
"ChonkVerifyFromFields: malformed input: unknown exception");
242 return { .valid =
false };
251 if (proofs.size() != vks.size()) {
252 info(
"ChonkBatchVerify: proofs.size() (", proofs.size(),
") != vks.size() (", vks.size(),
")");
253 return { .valid =
false };
255 if (proofs.empty()) {
256 info(
"ChonkBatchVerify: no proofs provided");
257 return { .valid =
false };
264 reduced_results.reserve(proofs.size());
266 for (
size_t i = 0; i < proofs.size(); ++i) {
267 if (!has_expected_vk_size<VerificationKey>(vks[i],
"ChonkBatchVerify")) {
268 return { .valid =
false };
272 const size_t expected_proof_size =
274 if (proofs[i].size() != expected_proof_size) {
275 info(
"ChonkBatchVerify: proof[",
277 "] has wrong size: expected ",
281 return { .valid =
false };
287 if (!
result.all_checks_passed) {
288 return { .valid =
false };
295 ipa_accumulators.reserve(reduced_results.size());
296 for (
const auto&
result : reduced_results) {
297 ipa_accumulators.push_back(
result.triple_ipa_opening.reduce_to_accumulator());
301 return { .valid = verified };
302 }
catch (
const std::exception& e) {
304 return { .valid =
false };
306 info(
"ChonkBatchVerify: malformed input: unknown exception");
307 return { .valid =
false };
314 info(
"ChonkComputeVk - deriving Chonk verification key for circuit '",
317 static_cast<int>(kind),
324 info(
"ChonkComputeVk - VK derived, size: ", verification_key.bytes.size(),
" bytes");
325 return { .bytes =
std::move(verification_key.bytes), .fields =
std::move(verification_key.fields) };
334 if (circuit.verification_key.empty()) {
335 info(
"FAIL: Expected precomputed vk for function ", circuit.name);
341 response.
valid = check.valid;
355 const auto& ivc_constraints = constraint_system.hn_recursion_constraints;
360 .collect_gates_per_opcode = include_gates_per_opcode
364 auto builder = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
368 response.
acir_opcodes = program.constraints.num_acir_opcodes;
372 if (include_gates_per_opcode) {
373 response.
gates_per_opcode = std::vector<uint32_t>(program.constraints.gates_per_opcode.begin(),
374 program.constraints.gates_per_opcode.end());
378 info(
"ChonkStats - circuit: ",
406#ifdef BB_HAS_BATCH_VERIFIER_SERVICE
410bool write_all(
int fd,
const uint8_t* ptr,
size_t len)
415 const auto chunk =
static_cast<unsigned int>(std::min(
len,
static_cast<size_t>(INT_MAX)));
416 const ssize_t written =
::write(fd, ptr, chunk);
419 len -=
static_cast<size_t>(written);
422 if (written < 0 && errno == EINTR) {
425 if (written < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
426 std::this_thread::sleep_for(std::chrono::milliseconds(1));
439bool write_frame(
int fd,
const void*
data,
size_t len)
441 if (
len > UINT32_MAX) {
444 auto len32 =
static_cast<uint32_t
>(
len);
445 std::vector<uint8_t> header = {
446 static_cast<uint8_t
>((len32 >> 24) & 0xFF),
447 static_cast<uint8_t
>((len32 >> 16) & 0xFF),
448 static_cast<uint8_t
>((len32 >> 8) & 0xFF),
449 static_cast<uint8_t
>(len32 & 0xFF),
452 return write_all(fd, header.data(), header.size()) && write_all(fd,
reinterpret_cast<const uint8_t*
>(
data),
len);
460 const std::string& fifo_path)
462 bool expected =
false;
463 if (!running_.compare_exchange_strong(expected,
true)) {
467 if (num_cores == 0) {
468 num_cores =
static_cast<uint32_t
>(std::thread::hardware_concurrency());
469 if (num_cores == 0) {
477 fifo_path_ = fifo_path;
478 fifo_failed_.store(
false);
484 running_.store(
false);
488 info(
"ChonkBatchVerifierService started, fifo=", fifo_path);
491void ChonkBatchVerifierService::enqueue(
VerifyRequest request)
493 if (fifo_failed_.load()) {
499void ChonkBatchVerifierService::fail_request(uint64_t request_id, std::string error_message)
504void ChonkBatchVerifierService::stop()
506 if (!running_.exchange(
false)) {
514 std::lock_guard lock(fifo_mutex_);
519 info(
"ChonkBatchVerifierService stopped");
522ChonkBatchVerifierService::~ChonkBatchVerifierService()
524 if (running_.load()) {
529bool ChonkBatchVerifierService::ensure_fifo_open()
534 if (fifo_path_.empty()) {
540 if (lstat(fifo_path_.c_str(), &statbuf) != 0) {
541 info(
"ChonkBatchVerifierService: failed to stat FIFO '", fifo_path_,
"': ",
std::strerror(errno));
544 if (!S_ISFIFO(statbuf.st_mode)) {
545 info(
"ChonkBatchVerifierService: result path is not a FIFO: ", fifo_path_);
550 for (
size_t attempt = 0; attempt < 100; ++attempt) {
552 fifo_fd_ = open(fifo_path_.c_str(), O_WRONLY | O_NONBLOCK | O_CLOEXEC | O_NOFOLLOW);
554 fifo_fd_ = open(fifo_path_.c_str(), O_WRONLY);
558 struct stat opened_statbuf;
559 if (fstat(fifo_fd_, &opened_statbuf) != 0 || !S_ISFIFO(opened_statbuf.st_mode)) {
560 info(
"ChonkBatchVerifierService: opened result path is not a FIFO: ", fifo_path_);
568 if (errno != ENXIO && errno != EINTR) {
569 info(
"ChonkBatchVerifierService: failed to open FIFO '", fifo_path_,
"': ",
std::strerror(errno));
572 std::this_thread::sleep_for(std::chrono::milliseconds(1));
574 info(
"ChonkBatchVerifierService: no FIFO reader connected for '", fifo_path_,
"'");
578void ChonkBatchVerifierService::close_fifo_locked()
586bool ChonkBatchVerifierService::fail_fifo_locked(
const std::string& message)
588 if (!fifo_failed_.exchange(
true)) {
590 info(
"ChonkBatchVerifierService: ", message);
599 msgpack::sbuffer buf;
600 msgpack::pack(buf,
result);
602 std::lock_guard lock(fifo_mutex_);
603 if (fifo_failed_.load()) {
606 if (!ensure_fifo_open()) {
607 return fail_fifo_locked(
"result FIFO unavailable");
610 if (!write_frame(fifo_fd_, buf.data(), buf.size())) {
611 return fail_fifo_locked(std::string(
"FIFO write failed: ") +
std::strerror(errno));
618 if (request.batch_verifier_service && request.batch_verifier_service->is_running()) {
619 throw_or_abort(
"ChonkBatchVerifierStart: service already running. Call ChonkBatchVerifierStop first.");
623 parsed_vks.reserve(vks.size());
625 for (
size_t i = 0; i < vks.size(); ++i) {
630 request.batch_verifier_service->start(
std::move(parsed_vks), num_cores, batch_size, fifo_path);
637 if (!request.batch_verifier_service || !request.batch_verifier_service->is_running()) {
638 throw_or_abort(
"ChonkBatchVerifierQueue: service not running. Call ChonkBatchVerifierStart first.");
644 }
catch (
const std::exception& e) {
645 request.batch_verifier_service->fail_request(request_id, std::string(
"malformed proof fields: ") + e.what());
648 request.batch_verifier_service->fail_request(request_id,
"malformed proof fields: unknown exception");
655 .vk_index = vk_index,
658 }
catch (
const std::exception& e) {
659 request.batch_verifier_service->fail_request(request_id, e.what());
661 request.batch_verifier_service->fail_request(request_id,
"failed to enqueue proof: unknown exception");
669 if (!request.batch_verifier_service || !request.batch_verifier_service->is_running()) {
673 request.batch_verifier_service->stop();
674 request.batch_verifier_service.reset();
682 throw_or_abort(
"ChonkBatchVerifierStart is not supported on this platform (wasm/Windows)");
687 throw_or_abort(
"ChonkBatchVerifierQueue is not supported on this platform (wasm/Windows)");
692 throw_or_abort(
"ChonkBatchVerifierStop is not supported on this platform (wasm/Windows)");
697#undef BBAPI_CHONK_EXCEPTION_WHAT
#define BB_BENCH_NAME(name)
#define BBAPI_CHONK_EXCEPTION_WHAT(exception)
Chonk-specific command definitions for the Barretenberg RPC API.
MegaZKFlavor::VerificationKey MegaZKVerificationKey
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.
Output verify(const Proof &proof)
Verify a Chonk proof.
static bool batch_verify_accumulators(std::span< const TripleIpaAccumulator > accumulators)
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.
bool has_expected_vk_size(const std::vector< uint8_t > &vk_bytes, const char *label)
VkPolicy
Policy for handling verification keys during IVC accumulation.
field< Bn254FrParams > fr
void write(B &buf, field2< base_field, Params > const &value)
std::shared_ptr< MegaZKFlavor::VKAndHash > deserialize_chonk_vk_and_hash(const std::vector< uint8_t > &vk)
ChonkVkCheckResult check_precomputed_chonk_vk(acir_format::AcirProgram &program, const std::vector< uint8_t > &precomputed_vk, CircuitKind kind)
std::shared_ptr< Chonk::MegaZKVerificationKey > deserialize_chonk_vk(const std::vector< uint8_t > &vk)
ChonkVkData compute_chonk_vk(acir_format::AcirProgram &program, CircuitKind kind)
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
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)
Empty response indicating successful circuit accumulation.
Response execute(BBApiRequest &request) &&
Response execute(BBApiRequest &request) &&
Response execute(BBApiRequest &request) &&
Response execute(BBApiRequest &request) &&
Response execute(const BBApiRequest &request={}) &&
Contains the validation result.
std::vector< uint8_t > actual_vk
The actual VK it should be.
bool valid
True if the precomputed VK matches the circuit.
Response execute(const BBApiRequest &request={}) &&
Response execute(const BBApiRequest &request={}) &&
Contains the computed verification key in multiple formats.
Response execute(const BBApiRequest &request={}) &&
Response execute(const BBApiRequest &request={}) &&
Empty response indicating successful circuit loading.
Response execute(BBApiRequest &request) &&
Contains the generated IVC proof.
ChonkProof proof
Complete IVC proof for all accumulated circuits.
Response execute(BBApiRequest &request) &&
Empty response indicating successful initialization.
Response execute(BBApiRequest &request) &&
Contains gate count information.
uint32_t circuit_size
Circuit size (total number of gates)
uint32_t acir_opcodes
Number of ACIR opcodes.
std::vector< uint32_t > gates_per_opcode
Optional: gate counts per opcode.
Response execute(BBApiRequest &request) &&
Contains the verification result.
Response execute(const BBApiRequest &request={}) &&
Response execute(const BBApiRequest &request={}) &&
void throw_or_abort(std::string const &err)