Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
api_chonk.cpp
Go to the documentation of this file.
1#include "api_chonk.hpp"
8#include "barretenberg/bbapi/generated/bb_types.hpp"
22#include <algorithm>
23#include <stdexcept>
24
25namespace bb {
26namespace { // anonymous namespace
27
37void write_chonk_vk(std::vector<uint8_t> bytecode, const std::filesystem::path& output_path, const API::Flags& flags)
38{
39 bbapi::BBApiRequest request;
40 auto response =
42 bbapi::wire::ChonkComputeVk{
43 .circuit = bbapi::wire::CircuitInputNoVK{ .bytecode = std::move(bytecode) },
44 .use_zk_flavor = flags.use_zk_flavor,
45 });
46
47 const bool is_stdout = output_path == "-";
48 if (is_stdout) {
49 write_bytes_to_stdout(response.bytes);
50 } else if (flags.output_format == "json") {
51 // Note: Chonk VK doesn't have a hash, so we pass an empty string.
52 auto fields = bbapi::fr_vec_from_wire(response.fields);
53 std::string json_content = VkJson::build(fields, "", flags.scheme);
54 write_file(output_path / "vk.json", std::vector<uint8_t>(json_content.begin(), json_content.end()));
55 info("VK (JSON) saved to ", output_path / "vk.json");
56 } else {
57 write_file(output_path / "vk", response.bytes);
58 }
59}
60} // anonymous namespace
61
62void ChonkAPI::prove(const Flags& flags,
63 const std::filesystem::path& input_path,
64 const std::filesystem::path& output_dir)
65{
66 BB_BENCH_NAME("ChonkAPI::prove");
67 bbapi::BBApiRequest request;
70
72 bbapi::wire::ChonkStart{ .num_circuits = static_cast<uint32_t>(raw_steps.size()) });
73 info("Chonk: starting with ", raw_steps.size(), " circuits");
74 for (size_t i = 0; i < raw_steps.size(); ++i) {
75 const auto& step = raw_steps[i];
77 bbapi::wire::ChonkLoad{ .circuit = bbapi::wire::CircuitInput{
78 .name = step.function_name,
79 .bytecode = step.bytecode,
80 .verification_key = step.vk,
81 } });
82
83 // NOLINTNEXTLINE(bugprone-unchecked-optional-access): we know the optional has been set here.
84 info("Chonk: accumulating " + step.function_name);
85 bbapi::handle_chonk_accumulate(request, bbapi::wire::ChonkAccumulate{ .witness = step.witness });
86 }
87
88 auto wire_proof = bbapi::handle_chonk_prove(request, bbapi::wire::ChonkProve{}).proof;
89 auto proof = bbapi::chonk_proof_from_wire(std::move(wire_proof));
90
91 const bool output_to_stdout = output_dir == "-";
92
93 const auto write_proof = [&]() {
94 const auto proof_fields = proof.to_field_elements();
95 if (output_to_stdout) {
96 vinfo("writing Chonk proof to stdout");
97 write_bytes_to_stdout(to_buffer(proof_fields));
98 } else if (flags.output_format == "json") {
99 vinfo("writing Chonk proof (JSON) in directory ", output_dir);
100 // Note: Chonk proof doesn't have a vk_hash, so we pass an empty string
101 std::string json_content = ProofJson::build(proof_fields, "", flags.scheme);
102 write_file(output_dir / "proof.json", std::vector<uint8_t>(json_content.begin(), json_content.end()));
103 info("Proof (JSON) saved to ", output_dir / "proof.json");
104 } else {
105 vinfo("writing Chonk proof in directory ", output_dir);
106 write_file(output_dir / "proof", to_buffer(proof_fields));
107 }
108 };
109
110 write_proof();
111
112 if (flags.write_vk) {
113 vinfo("writing Chonk vk in directory ", output_dir);
114 // Write CHONK vk for the hiding kernel (last step) — proven as MegaZK.
115 Flags hiding_flags = flags;
116 hiding_flags.use_zk_flavor = true;
117 write_chonk_vk(raw_steps[raw_steps.size() - 1].bytecode, output_dir, hiding_flags);
118 }
119}
120
121bool ChonkAPI::verify([[maybe_unused]] const Flags& flags,
122 [[maybe_unused]] const std::filesystem::path& public_inputs_path,
123 const std::filesystem::path& proof_path,
124 const std::filesystem::path& vk_path)
125{
126 BB_BENCH_NAME("ChonkAPI::verify");
127 auto proof_fields = many_from_buffer<fr>(read_file(proof_path));
128 auto proof = ChonkProof::from_field_elements(proof_fields);
129
130 auto vk_buffer = read_vk_file(vk_path);
131
132 bbapi::BBApiRequest request;
133 auto response = bbapi::handle_chonk_verify(
134 request, bbapi::wire::ChonkVerify{ .proof = bbapi::chonk_proof_to_wire(proof), .vk = std::move(vk_buffer) });
135 return response.valid;
136}
137
138bool ChonkAPI::batch_verify([[maybe_unused]] const Flags& flags, const std::filesystem::path& proofs_dir)
139{
140 BB_BENCH_NAME("ChonkAPI::batch_verify");
141
144
145 for (size_t i = 0;; ++i) {
146 auto proof_file = proofs_dir / ("proof_" + std::to_string(i));
147 auto vk_file = proofs_dir / ("vk_" + std::to_string(i));
148
149 if (!std::filesystem::exists(proof_file) || !std::filesystem::exists(vk_file)) {
150 break;
151 }
152
153 auto proof_fields = many_from_buffer<fr>(read_file(proof_file));
154 proofs.push_back(ChonkProof::from_field_elements(proof_fields));
155 vks.push_back(read_vk_file(vk_file));
156 }
157
158 if (proofs.empty()) {
159 throw_or_abort("batch_verify: no proof_0/vk_0 pairs found in " + proofs_dir.string());
160 }
161
162 info("ChonkAPI::batch_verify - found ", proofs.size(), " proof/vk pairs in ", proofs_dir.string());
163
165 wire_proofs.reserve(proofs.size());
166 for (const auto& p : proofs) {
167 wire_proofs.push_back(bbapi::chonk_proof_to_wire(p));
168 }
169 bbapi::BBApiRequest request;
170 auto response = bbapi::handle_chonk_batch_verify(
171 request, bbapi::wire::ChonkBatchVerify{ .proofs = std::move(wire_proofs), .vks = std::move(vks) });
172 return response.valid;
173}
174
175void ChonkAPI::proof_stats(const std::filesystem::path& proof_path, const std::filesystem::path& output_path)
176{
177 auto proof_fields = many_from_buffer<fr>(read_file(proof_path));
178 auto proof = ChonkProof::from_field_elements(proof_fields);
179
180 auto compressed = ProofCompressor::compress_chonk_proof(proof);
181
182 std::string json = "{\n"
183 " \"compressed_proof_size_bytes\": " +
184 std::to_string(compressed.size()) +
185 "\n"
186 "}";
187
188 if (output_path == "-") {
189 std::cout << json << std::endl;
190 } else {
191 write_file(output_path, std::vector<uint8_t>(json.begin(), json.end()));
192 // Write the compressed proof alongside the JSON for further processing (e.g. gzip)
193 auto compressed_proof_path = output_path;
194 compressed_proof_path.replace_extension(".bin");
195 write_file(compressed_proof_path, compressed);
196 info("Proof stats written to ", output_path);
197 }
198}
199
200// WORKTODO(bbapi) remove this
201bool ChonkAPI::prove_and_verify(const std::filesystem::path& input_path)
202{
205
207 // Construct the hiding kernel as the final step of the IVC
208
209 auto proof = ivc->prove();
210 auto vk_and_hash = ivc->get_hiding_kernel_vk_and_hash();
211 ChonkNativeVerifier verifier(vk_and_hash);
212 const bool verified = verifier.verify(proof);
213 return verified;
214}
215
216void ChonkAPI::gates(const Flags& flags, const std::filesystem::path& bytecode_path)
217{
218 BB_BENCH_NAME("ChonkAPI::gates");
219 chonk_gate_count(bytecode_path.string(), flags.include_gates_per_opcode);
220}
221
222void ChonkAPI::write_solidity_verifier([[maybe_unused]] const Flags& flags,
223 [[maybe_unused]] const std::filesystem::path& output_path,
224 [[maybe_unused]] const std::filesystem::path& vk_path)
225{
226 BB_BENCH_NAME("ChonkAPI::write_solidity_verifier");
227 throw_or_abort("API function contract not implemented");
228}
229
230bool ChonkAPI::check_precomputed_vks(const Flags& flags, const std::filesystem::path& input_path)
231{
232 BB_BENCH_NAME("ChonkAPI::check_precomputed_vks");
233 bbapi::BBApiRequest request;
235
237 bool check_failed = false;
238 for (size_t i = 0; i < raw_steps.size(); ++i) {
239 auto& step = raw_steps[i];
240 if (step.vk.empty()) {
241 info("FAIL: Expected precomputed vk for function ", step.function_name);
242 return false;
243 }
244 const bool use_zk_flavor = (i == raw_steps.size() - 1);
246 request,
247 bbapi::wire::ChonkCheckPrecomputedVk{
248 .circuit = bbapi::wire::CircuitInput{ .name = step.function_name,
249 .bytecode = step.bytecode,
250 .verification_key = step.vk },
251 .use_zk_flavor = use_zk_flavor,
252 });
253
254 if (!response.valid) {
255 info("VK mismatch detected for function ", step.function_name);
256 if (vk_policy != bbapi::VkPolicy::REWRITE) {
257 info("Computed VK differs from precomputed VK in ivc-inputs.msgpack");
258 return false;
259 }
260 info("Updating VK in ivc-inputs.msgpack with computed value");
261 step.vk = response.actual_vk;
262 check_failed = true;
263 }
264 }
265 if (check_failed) {
267 return false;
268 }
269 return true;
270}
271
272void ChonkAPI::write_vk(const Flags& flags,
273 const std::filesystem::path& bytecode_path,
274 const std::filesystem::path& output_path)
275{
276 BB_BENCH_NAME("ChonkAPI::write_vk");
277 write_chonk_vk(get_bytecode(bytecode_path), output_path, flags);
278}
279
280bool ChonkAPI::check([[maybe_unused]] const Flags& flags,
281 [[maybe_unused]] const std::filesystem::path& bytecode_path,
282 [[maybe_unused]] const std::filesystem::path& witness_path)
283{
284 throw_or_abort("API function check_witness not implemented");
285 return false;
286}
287
288void chonk_gate_count(const std::string& bytecode_path, bool include_gates_per_opcode)
289{
290 BB_BENCH_NAME("chonk_gate_count");
291 // All circuit reports will be built into the std::string below
292 std::string functions_string = "{\"functions\": [\n ";
293
294 bbapi::BBApiRequest request;
295
296 auto bytecode = get_bytecode(bytecode_path);
297 auto response = bbapi::handle_chonk_stats(
298 request,
299 bbapi::wire::ChonkStats{
300 .circuit = bbapi::wire::CircuitInputNoVK{ .name = "ivc_circuit", .bytecode = std::move(bytecode) },
301 .include_gates_per_opcode = include_gates_per_opcode,
302 });
303
304 // Build the circuit report. It always has one function, corresponding to the ACIR constraint systems.
305 // NOTE: can be reconsidered
306 std::string gates_per_opcode_str;
307 if (include_gates_per_opcode && !response.gates_per_opcode.empty()) {
308 for (size_t j = 0; j < response.gates_per_opcode.size(); j++) {
309 gates_per_opcode_str += std::to_string(response.gates_per_opcode[j]);
310 if (j != response.gates_per_opcode.size() - 1) {
311 gates_per_opcode_str += ",";
312 }
313 }
314 }
315 auto result_string = format(
316 "{\n \"acir_opcodes\": ",
317 response.acir_opcodes,
318 ",\n \"circuit_size\": ",
319 response.circuit_size,
320 (include_gates_per_opcode ? format(",\n \"gates_per_opcode\": [", gates_per_opcode_str, "]") : ""),
321 "\n }");
322 functions_string = format(functions_string, result_string);
323 std::cout << format(functions_string, "\n]}");
324}
325
326} // namespace bb
void write_bytes_to_stdout(const std::vector< uint8_t > &data)
Writes raw bytes of the vector to stdout.
Definition log.hpp:21
std::shared_ptr< Napi::ThreadSafeFunction > bytecode
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Non-template handler declarations for the bb service.
Shared type definitions for the Barretenberg RPC API.
Wire <-> domain conversion helpers for the bbapi handlers.
bool prove_and_verify(const std::filesystem::path &input_path)
Test/debug function: prove and verify in one call (bypasses serialization).
void proof_stats(const std::filesystem::path &proof_path, const std::filesystem::path &output_path)
Output proof statistics: compressed proof and its size.
bool batch_verify(const Flags &flags, const std::filesystem::path &proofs_dir)
Batch-verify multiple Chonk proofs from a directory of proof_N/vk_N pairs.
bool verify(const Flags &flags, const std::filesystem::path &public_inputs_path, const std::filesystem::path &proof_path, const std::filesystem::path &vk_path) override
Verify a Chonk proof against a verification key.
void write_vk(const Flags &flags, const std::filesystem::path &bytecode_path, const std::filesystem::path &output_path) override
Compute and write a MegaHonk verification key for a circuit to be accumulated in Chonk.
void prove(const Flags &flags, const std::filesystem::path &input_path, const std::filesystem::path &output_dir)
Main production entry point: generate a Chonk proof from private execution steps.
Definition api_chonk.cpp:62
bool check(const Flags &flags, const std::filesystem::path &bytecode_path, const std::filesystem::path &witness_path) override
void gates(const Flags &flags, const std::filesystem::path &bytecode_path) override
Output gate count statistics for a circuit.
bool check_precomputed_vks(const Flags &flags, const std::filesystem::path &input_path)
Validate that precomputed VKs in ivc-inputs.msgpack match computed VKs.
void write_solidity_verifier(const Flags &flags, const std::filesystem::path &output_path, const std::filesystem::path &vk_path) override
Verifier for Chonk IVC proofs (both native and recursive).
Output verify(const Proof &proof)
Verify a Chonk proof.
static std::vector< uint8_t > compress_chonk_proof(const ChonkProof &proof)
std::string format(Args... args)
Definition log.hpp:23
#define info(...)
Definition log.hpp:93
#define vinfo(...)
Definition log.hpp:94
std::vector< uint8_t > get_bytecode(const std::string &bytecodePath)
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 &&)
VkPolicy
Policy for handling verification keys during IVC accumulation.
wire::ChonkProof chonk_proof_to_wire(const ChonkProof &d)
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)
VkPolicy parse_vk_policy(const std::string &policy)
Convert VK policy string to enum for internal use.
wire::ChonkComputeVkResponse handle_chonk_compute_vk(BBApiRequest &, wire::ChonkComputeVk &&cmd)
wire::ChonkCheckPrecomputedVkResponse handle_chonk_check_precomputed_vk(BBApiRequest &, wire::ChonkCheckPrecomputedVk &&cmd)
std::vector< bb::fr > fr_vec_from_wire(const std::vector< Fr > &w)
wire::ChonkStatsResponse handle_chonk_stats(BBApiRequest &, wire::ChonkStats &&cmd)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void chonk_gate_count(const std::string &bytecode_path, bool include_gates_per_opcode)
std::vector< uint8_t > read_vk_file(const std::filesystem::path &vk_path)
Read a verification key file with an actionable error message if not found.
Definition file_io.hpp:146
std::vector< uint8_t > read_file(const std::string &filename, size_t bytes=0)
Definition file_io.hpp:31
void write_file(const std::string &filename, std::span< const uint8_t > data)
Definition file_io.hpp:101
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
std::vector< uint8_t > to_buffer(T const &value)
bool include_gates_per_opcode
Definition api.hpp:22
bool write_vk
Definition api.hpp:21
std::string vk_policy
Definition api.hpp:25
bool use_zk_flavor
Definition api.hpp:26
std::string output_format
Definition api.hpp:30
std::string scheme
Definition api.hpp:18
static ChonkProof_ from_field_elements(const std::vector< FF > &fields)
Reconstruct proof from field elements.
static void compress_and_save(std::vector< PrivateExecutionStepRaw > &&steps, const std::filesystem::path &output_path)
static std::vector< PrivateExecutionStepRaw > load_and_decompress(const std::filesystem::path &input_path)
Parsed private execution steps ready for Chonk accumulation.
std::shared_ptr< Chonk > accumulate()
Creates a Chonk instance and accumulates each circuit in the folding stack. Uses precomputed VKs when...
void parse(std::vector< PrivateExecutionStepRaw > &&steps)
Converts PrivateExecutionStepRaw entries (which contain raw bytecode/witness bytes) into structured A...
static std::string build(const std::vector< T > &fields, const std::string &vk_hash, const std::string &scheme)
static std::string build(const std::vector< T > &fields, const std::string &hash, const std::string &scheme)
void throw_or_abort(std::string const &err)