35#ifndef BB_NO_EXCEPTIONS
36#define BBAPI_CHONK_EXCEPTION_WHAT(exception) (exception).what()
38#define BBAPI_CHONK_EXCEPTION_WHAT(exception) "unknown exception"
41template <
typename VerificationKey>
bool has_expected_vk_size(
const std::vector<uint8_t>& vk_bytes,
const char* label)
44 if (vk_bytes.size() == expected_size) {
48 info(label,
": verification key has wrong size: expected ", expected_size,
", got ", vk_bytes.size());
57 request.ivc_stack_depth = 0;
61 request.loaded_circuit_name.clear();
62 request.loaded_circuit_constraints.reset();
63 request.loaded_circuit_vk.clear();
71 if (!request.ivc_in_progress) {
75 request.loaded_circuit_name = circuit.name;
77 request.loaded_circuit_vk = circuit.verification_key;
79 info(
"ChonkLoad - loaded circuit '", request.loaded_circuit_name,
"'");
87 if (!request.ivc_in_progress) {
91 if (!request.loaded_circuit_constraints.has_value()) {
101 auto loaded_vk =
std::move(request.loaded_circuit_vk);
102 auto circuit_name =
std::move(request.loaded_circuit_name);
103 request.loaded_circuit_constraints.reset();
104 request.loaded_circuit_vk.clear();
105 request.loaded_circuit_name.clear();
109 const bool is_hiding_kernel = (request.ivc_stack_depth + 1 == chonk->get_num_circuits());
112 auto circuit = acir_format::create_circuit<IVCBase::ClientCircuit>(program, metadata);
117 precomputed_vk =
nullptr;
119 if (!loaded_vk.empty()) {
120 validate_vk_size<Chonk::MegaVerificationKey>(loaded_vk);
121 precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(loaded_vk);
132 if (*precomputed_vk != *computed_vk) {
134 "': provided VK does not match computed VK");
139 throw_or_abort(
"Invalid VK policy. Valid options: default, check, recompute");
142 info(
"ChonkAccumulate - accumulating circuit '", circuit_name,
"'");
146 request.ivc_in_progress->accumulate(circuit, precomputed_vk);
147 request.ivc_stack_depth++;
155 if (!request.ivc_in_progress) {
159 if (request.ivc_stack_depth == 0) {
160 throw_or_abort(
"No circuits accumulated. Call ChonkAccumulate first.");
163 info(
"ChonkProve - generating proof for ", request.ivc_stack_depth,
" accumulated circuits");
167 bool verification_passed =
false;
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 verification_passed = verifier.
verify(proof);
180 if (!verification_passed) {
186 request.ivc_in_progress.reset();
187 request.ivc_stack_depth = 0;
198 if (!has_expected_vk_size<VerificationKey>(
vk,
"ChonkVerify")) {
199 return { .valid =
false };
206 const size_t expected_proof_size =
208 if (proof.size() != expected_proof_size) {
209 info(
"ChonkVerify: proof has wrong size: expected ", expected_proof_size,
", got ", proof.size());
210 return { .valid =
false };
216 const bool verified = verifier.
verify(proof);
218 return { .valid = verified };
219 }
catch (
const std::exception& e) {
221 return { .valid =
false };
223 info(
"ChonkVerify: malformed input: unknown exception");
224 return { .valid =
false };
234 if (!has_expected_vk_size<VerificationKey>(
vk,
"ChonkVerifyFromFields")) {
235 return { .valid =
false };
241 const size_t expected_field_count =
243 if (proof.size() != expected_field_count) {
244 info(
"ChonkVerifyFromFields: proof has wrong field count: expected ",
245 expected_field_count,
248 return { .valid =
false };
256 const bool verified = verifier.
verify(structured);
258 return { .valid = verified };
259 }
catch (
const std::exception& e) {
261 return { .valid =
false };
263 info(
"ChonkVerifyFromFields: malformed input: unknown exception");
264 return { .valid =
false };
273 if (proofs.size() != vks.size()) {
274 info(
"ChonkBatchVerify: proofs.size() (", proofs.size(),
") != vks.size() (", vks.size(),
")");
275 return { .valid =
false };
277 if (proofs.empty()) {
278 info(
"ChonkBatchVerify: no proofs provided");
279 return { .valid =
false };
287 ipa_claims.reserve(proofs.size());
288 ipa_transcripts.reserve(proofs.size());
290 for (
size_t i = 0; i < proofs.size(); ++i) {
291 if (!has_expected_vk_size<VerificationKey>(vks[i],
"ChonkBatchVerify")) {
292 return { .valid =
false };
296 const size_t expected_proof_size =
298 if (proofs[i].size() != expected_proof_size) {
299 info(
"ChonkBatchVerify: proof[",
301 "] has wrong size: expected ",
305 return { .valid =
false };
311 if (!result.all_checks_passed) {
312 return { .valid =
false };
314 ipa_claims.push_back(
std::move(result.ipa_claim));
322 return { .valid = verified };
323 }
catch (
const std::exception& e) {
325 return { .valid =
false };
327 info(
"ChonkBatchVerify: malformed input: unknown exception");
328 return { .valid =
false };
346 info(
"ChonkComputeVk - deriving MegaVerificationKey for circuit '",
349 use_zk_flavor ?
" (MegaZK)" :
"");
354 auto verification_key = compute_chonk_vk_from_program(program, use_zk_flavor);
356 info(
"ChonkComputeVk - VK derived, size: ",
to_buffer(*verification_key).size(),
" bytes");
358 return { .bytes =
to_buffer(*verification_key), .fields = verification_key->to_field_elements() };
367 auto computed_vk = compute_chonk_vk_from_program(program, use_zk_flavor);
369 if (circuit.verification_key.empty()) {
370 info(
"FAIL: Expected precomputed vk for function ", circuit.name);
374 validate_vk_size<Chonk::MegaVerificationKey>(circuit.verification_key);
377 auto precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(circuit.verification_key);
380 response.
valid =
true;
381 if (*computed_vk != *precomputed_vk) {
382 response.valid =
false;
383 response.actual_vk =
to_buffer(computed_vk);
397 const auto& ivc_constraints = constraint_system.hn_recursion_constraints;
402 .collect_gates_per_opcode = include_gates_per_opcode
406 auto builder = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
414 if (include_gates_per_opcode) {
420 info(
"ChonkStats - circuit: ",
452bool write_all(
int fd,
const uint8_t* ptr,
size_t len)
455 const auto chunk_len =
456 static_cast<unsigned int>(
std::min<size_t>(
len, std::numeric_limits<unsigned int>::max()));
457 const ssize_t written =
::write(fd, ptr, chunk_len);
460 len -=
static_cast<size_t>(written);
463 if (written < 0 && errno == EINTR) {
466 if (written < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
467 std::this_thread::sleep_for(std::chrono::milliseconds(1));
480bool write_frame(
int fd,
const void*
data,
size_t len)
482 if (
len > UINT32_MAX) {
485 auto len32 =
static_cast<uint32_t
>(
len);
486 std::vector<uint8_t> header = {
487 static_cast<uint8_t
>((len32 >> 24) & 0xFF),
488 static_cast<uint8_t
>((len32 >> 16) & 0xFF),
489 static_cast<uint8_t
>((len32 >> 8) & 0xFF),
490 static_cast<uint8_t
>(len32 & 0xFF),
493 return write_all(fd, header.data(), header.size()) && write_all(fd,
reinterpret_cast<const uint8_t*
>(
data),
len);
501 const std::string& fifo_path)
503 bool expected =
false;
504 if (!
running_.compare_exchange_strong(expected,
true)) {
508 if (num_cores == 0) {
509 num_cores =
static_cast<uint32_t
>(std::thread::hardware_concurrency());
510 if (num_cores == 0) {
529 info(
"ChonkBatchVerifierService started, fifo=", fifo_path);
560 info(
"ChonkBatchVerifierService stopped");
581 if (lstat(
fifo_path_.c_str(), &statbuf) != 0) {
585 if (!S_ISFIFO(statbuf.st_mode)) {
586 info(
"ChonkBatchVerifierService: result path is not a FIFO: ",
fifo_path_);
591 for (
size_t attempt = 0; attempt < 100; ++attempt) {
599 struct stat opened_statbuf;
600 if (fstat(
fifo_fd_, &opened_statbuf) != 0 || !S_ISFIFO(opened_statbuf.st_mode)) {
601 info(
"ChonkBatchVerifierService: opened result path is not a FIFO: ",
fifo_path_);
609 if (errno != ENXIO && errno != EINTR) {
613 std::this_thread::sleep_for(std::chrono::milliseconds(1));
615 info(
"ChonkBatchVerifierService: no FIFO reader connected for '",
fifo_path_,
"'");
631 info(
"ChonkBatchVerifierService: ", message);
640 msgpack::sbuffer buf;
641 msgpack::pack(buf, result);
651 if (!write_frame(
fifo_fd_, buf.data(), buf.size())) {
659 if (request.batch_verifier_service && request.batch_verifier_service->is_running()) {
660 throw_or_abort(
"ChonkBatchVerifierStart: service already running. Call ChonkBatchVerifierStop first.");
666 parsed_vks.reserve(vks.size());
668 for (
size_t i = 0; i < vks.size(); ++i) {
669 validate_vk_size<VerificationKey>(vks[i]);
675 request.batch_verifier_service->start(
std::move(parsed_vks), num_cores, batch_size, fifo_path);
682 if (!request.batch_verifier_service || !request.batch_verifier_service->is_running()) {
683 throw_or_abort(
"ChonkBatchVerifierQueue: service not running. Call ChonkBatchVerifierStart first.");
689 }
catch (
const std::exception& e) {
690 request.batch_verifier_service->fail_request(request_id, std::string(
"malformed proof fields: ") + e.what());
693 request.batch_verifier_service->fail_request(request_id,
"malformed proof fields: unknown exception");
700 .vk_index = vk_index,
703 }
catch (
const std::exception& e) {
704 request.batch_verifier_service->fail_request(request_id, e.what());
706 request.batch_verifier_service->fail_request(request_id,
"failed to enqueue proof: unknown exception");
714 if (!request.batch_verifier_service || !request.batch_verifier_service->is_running()) {
718 request.batch_verifier_service->stop();
719 request.batch_verifier_service.reset();
727 throw_or_abort(
"ChonkBatchVerifierStart is not supported in WASM builds");
732 throw_or_abort(
"ChonkBatchVerifierQueue is not supported in WASM builds");
737 throw_or_abort(
"ChonkBatchVerifierStop is not supported in WASM builds");
742#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.
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)
bool has_expected_vk_size(const std::vector< uint8_t > &vk_bytes, const char *label)
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)
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.
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 set_circuit_name(const std::string &name)
void throw_or_abort(std::string const &err)