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"
19#include <algorithm>
20#include <stdexcept>
21
22namespace bb {
23namespace { // anonymous namespace
24
25CircuitKind parse_circuit_kind(const std::string& s)
26{
27 if (s == "app") {
28 return CircuitKind::App;
29 }
30 if (s == "kernel") {
32 }
33 if (s == "hiding") {
35 }
36 throw_or_abort("write_chonk_vk: --circuit_kind must be one of 'app' / 'kernel' / 'hiding' (got '" + s + "')");
37 __builtin_unreachable();
38}
39
45void write_chonk_vk(std::vector<uint8_t> bytecode, const std::filesystem::path& output_path, const API::Flags& flags)
46{
47 const CircuitKind kind = parse_circuit_kind(flags.circuit_kind);
48 auto response = bbapi::ChonkComputeVk{ .circuit = { .bytecode = std::move(bytecode) }, .kind = kind }.execute();
49
50 const bool is_stdout = output_path == "-";
51 if (is_stdout) {
52 write_bytes_to_stdout(response.bytes);
53 } else if (flags.output_format == "json") {
54 // Note: Chonk VK doesn't have a hash, so we pass an empty string
55 std::string json_content = VkJson::build(response.fields, "", flags.scheme);
56 write_file(output_path / "vk.json", std::vector<uint8_t>(json_content.begin(), json_content.end()));
57 info("VK (JSON) saved to ", output_path / "vk.json");
58 } else {
59 write_file(output_path / "vk", response.bytes);
60 }
61}
62} // anonymous namespace
63
64void ChonkAPI::prove(const Flags& flags,
65 const std::filesystem::path& input_path,
66 const std::filesystem::path& output_dir)
67{
68 BB_BENCH_NAME("ChonkAPI::prove");
69 bbapi::BBApiRequest request;
72
73 std::vector<CircuitKind> kinds;
74 kinds.reserve(raw_steps.size());
75 for (const auto& step : raw_steps) {
76 kinds.push_back(step.kind);
77 }
78 bbapi::ChonkStart{ .kinds = std::move(kinds) }.execute(request);
79 info("Chonk: starting with ", raw_steps.size(), " circuits");
80 for (size_t i = 0; i < raw_steps.size(); ++i) {
81 const auto& step = raw_steps[i];
83 .circuit = { .name = step.function_name, .bytecode = step.bytecode, .verification_key = step.vk },
84 .kind = step.kind,
85 }
86 .execute(request);
87
88 // NOLINTNEXTLINE(bugprone-unchecked-optional-access): we know the optional has been set here.
89 info("Chonk: accumulating " + step.function_name);
90 bbapi::ChonkAccumulate{ .witness = step.witness }.execute(request);
91 }
92
93 auto proof = bbapi::ChonkProve{}.execute(request).proof;
94
95 const bool output_to_stdout = output_dir == "-";
96
97 const auto write_proof = [&]() {
98 const auto proof_fields = proof.to_field_elements();
99 if (output_to_stdout) {
100 vinfo("writing Chonk proof to stdout");
101 write_bytes_to_stdout(to_buffer(proof_fields));
102 } else if (flags.output_format == "json") {
103 vinfo("writing Chonk proof (JSON) in directory ", output_dir);
104 // Note: Chonk proof doesn't have a vk_hash, so we pass an empty string
105 std::string json_content = ProofJson::build(proof_fields, "", flags.scheme);
106 write_file(output_dir / "proof.json", std::vector<uint8_t>(json_content.begin(), json_content.end()));
107 info("Proof (JSON) saved to ", output_dir / "proof.json");
108 } else {
109 vinfo("writing Chonk proof in directory ", output_dir);
110 write_file(output_dir / "proof", to_buffer(proof_fields));
111 }
112 };
113
114 write_proof();
115
116 if (flags.write_vk) {
117 vinfo("writing Chonk vk in directory ", output_dir);
118 // Write CHONK vk for the hiding kernel (last step) — proven as MegaZK.
119 Flags hiding_flags = flags;
120 hiding_flags.circuit_kind = "hiding";
121 write_chonk_vk(raw_steps[raw_steps.size() - 1].bytecode, output_dir, hiding_flags);
122 }
123}
124
125bool ChonkAPI::verify([[maybe_unused]] const Flags& flags,
126 [[maybe_unused]] const std::filesystem::path& public_inputs_path,
127 const std::filesystem::path& proof_path,
128 const std::filesystem::path& vk_path)
129{
130 BB_BENCH_NAME("ChonkAPI::verify");
131 auto proof_fields = many_from_buffer<fr>(read_file(proof_path));
132 auto proof = ChonkProof::from_field_elements(proof_fields);
133
134 auto vk_buffer = read_vk_file(vk_path);
135
136 auto response = bbapi::ChonkVerify{ .proof = std::move(proof), .vk = std::move(vk_buffer) }.execute();
137 return response.valid;
138}
139
140bool ChonkAPI::batch_verify([[maybe_unused]] const Flags& flags, const std::filesystem::path& proofs_dir)
141{
142 BB_BENCH_NAME("ChonkAPI::batch_verify");
143
146
147 for (size_t i = 0;; ++i) {
148 auto proof_file = proofs_dir / ("proof_" + std::to_string(i));
149 auto vk_file = proofs_dir / ("vk_" + std::to_string(i));
150
151 if (!std::filesystem::exists(proof_file) || !std::filesystem::exists(vk_file)) {
152 break;
153 }
154
155 auto proof_fields = many_from_buffer<fr>(read_file(proof_file));
156 proofs.push_back(ChonkProof::from_field_elements(proof_fields));
157 vks.push_back(read_vk_file(vk_file));
158 }
159
160 if (proofs.empty()) {
161 throw_or_abort("batch_verify: no proof_0/vk_0 pairs found in " + proofs_dir.string());
162 }
163
164 info("ChonkAPI::batch_verify - found ", proofs.size(), " proof/vk pairs in ", proofs_dir.string());
165
166 auto response = bbapi::ChonkBatchVerify{ .proofs = std::move(proofs), .vks = std::move(vks) }.execute();
167 return response.valid;
168}
169
170void ChonkAPI::proof_stats(const std::filesystem::path& proof_path, const std::filesystem::path& output_path)
171{
172 auto proof_fields = many_from_buffer<fr>(read_file(proof_path));
173 auto proof = ChonkProof::from_field_elements(proof_fields);
174
175 auto compressed = ProofCompressor::compress_chonk_proof(proof);
176
177 std::string json = "{\n"
178 " \"compressed_proof_size_bytes\": " +
179 std::to_string(compressed.size()) +
180 "\n"
181 "}";
182
183 if (output_path == "-") {
184 std::cout << json << std::endl;
185 } else {
186 write_file(output_path, std::vector<uint8_t>(json.begin(), json.end()));
187 // Write the compressed proof alongside the JSON for further processing (e.g. gzip)
188 auto compressed_proof_path = output_path;
189 compressed_proof_path.replace_extension(".bin");
190 write_file(compressed_proof_path, compressed);
191 info("Proof stats written to ", output_path);
192 }
193}
194
195// WORKTODO(bbapi) remove this
196bool ChonkAPI::prove_and_verify(const std::filesystem::path& input_path)
197{
200
202 // Construct the hiding kernel as the final step of the IVC
203
204 auto proof = ivc->prove();
205 auto vk_and_hash = ivc->get_hiding_kernel_vk_and_hash();
206 ChonkNativeVerifier verifier(vk_and_hash);
207 const bool verified = verifier.verify(proof);
208 return verified;
209}
210
211void ChonkAPI::gates(const Flags& flags, const std::filesystem::path& bytecode_path)
212{
213 BB_BENCH_NAME("ChonkAPI::gates");
214 chonk_gate_count(bytecode_path.string(), flags.include_gates_per_opcode);
215}
216
217void ChonkAPI::write_solidity_verifier([[maybe_unused]] const Flags& flags,
218 [[maybe_unused]] const std::filesystem::path& output_path,
219 [[maybe_unused]] const std::filesystem::path& vk_path)
220{
221 BB_BENCH_NAME("ChonkAPI::write_solidity_verifier");
222 throw_or_abort("API function contract not implemented");
223}
224
225bool ChonkAPI::check_precomputed_vks(const Flags& flags, const std::filesystem::path& input_path)
226{
227 BB_BENCH_NAME("ChonkAPI::check_precomputed_vks");
228 bbapi::BBApiRequest request;
230
232 bool check_failed = false;
233 for (size_t i = 0; i < raw_steps.size(); ++i) {
234 auto& step = raw_steps[i];
235 if (step.vk.empty()) {
236 info("FAIL: Expected precomputed vk for function ", step.function_name);
237 return false;
238 }
239 auto response =
241 .circuit = { .name = step.function_name, .bytecode = step.bytecode, .verification_key = step.vk },
242 .kind = step.kind,
243 }
244 .execute();
245
246 if (!response.valid) {
247 info("VK mismatch detected for function ", step.function_name);
248 if (vk_policy != bbapi::VkPolicy::REWRITE) {
249 info("Computed VK differs from precomputed VK in ivc-inputs.msgpack");
250 return false;
251 }
252 info("Updating VK in ivc-inputs.msgpack with computed value");
253 step.vk = response.actual_vk;
254 check_failed = true;
255 }
256 }
257 if (check_failed) {
259 return false;
260 }
261 return true;
262}
263
264void ChonkAPI::write_vk(const Flags& flags,
265 const std::filesystem::path& bytecode_path,
266 const std::filesystem::path& output_path)
267{
268 BB_BENCH_NAME("ChonkAPI::write_vk");
269 write_chonk_vk(get_bytecode(bytecode_path), output_path, flags);
270}
271
272bool ChonkAPI::check([[maybe_unused]] const Flags& flags,
273 [[maybe_unused]] const std::filesystem::path& bytecode_path,
274 [[maybe_unused]] const std::filesystem::path& witness_path)
275{
276 throw_or_abort("API function check_witness not implemented");
277 return false;
278}
279
280void chonk_gate_count(const std::string& bytecode_path, bool include_gates_per_opcode)
281{
282 BB_BENCH_NAME("chonk_gate_count");
283 // All circuit reports will be built into the std::string below
284 std::string functions_string = "{\"functions\": [\n ";
285
286 bbapi::BBApiRequest request;
287
288 auto bytecode = get_bytecode(bytecode_path);
289 auto response = bbapi::ChonkStats{ .circuit = { .name = "ivc_circuit", .bytecode = std::move(bytecode) },
290 .include_gates_per_opcode = include_gates_per_opcode }
291 .execute(request);
292
293 // Build the circuit report. It always has one function, corresponding to the ACIR constraint systems.
294 // NOTE: can be reconsidered
295 std::string gates_per_opcode_str;
296 if (include_gates_per_opcode && !response.gates_per_opcode.empty()) {
297 for (size_t j = 0; j < response.gates_per_opcode.size(); j++) {
298 gates_per_opcode_str += std::to_string(response.gates_per_opcode[j]);
299 if (j != response.gates_per_opcode.size() - 1) {
300 gates_per_opcode_str += ",";
301 }
302 }
303 }
304 auto result_string = format(
305 "{\n \"acir_opcodes\": ",
306 response.acir_opcodes,
307 ",\n \"circuit_size\": ",
308 response.circuit_size,
309 (include_gates_per_opcode ? format(",\n \"gates_per_opcode\": [", gates_per_opcode_str, "]") : ""),
310 "\n }");
311 functions_string = format(functions_string, result_string);
312 std::cout << format(functions_string, "\n]}");
313}
314
315} // 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
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
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:64
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 > bytecode
std::vector< uint8_t > get_bytecode(const std::string &bytecodePath)
VkPolicy
Policy for handling verification keys during IVC accumulation.
VkPolicy parse_vk_policy(const std::string &policy)
Convert VK policy string to enum for internal use.
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
std::string circuit_kind
Definition api.hpp:30
std::string output_format
Definition api.hpp:34
std::string scheme
Definition api.hpp:18
static ChonkProof_ from_field_elements(const std::vector< FF > &fields)
Reconstruct proof from field elements.
std::vector< FF > to_field_elements() const
Serialize proof to field elements (native mode)
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)
Accumulate the previously loaded circuit into the IVC proof.
std::vector< uint8_t > witness
Serialized witness data for the last loaded circuit.
Batch-verify multiple Chonk proofs with batched IPA SRS MSMs.
std::vector< ChonkProof > proofs
Verify that a precomputed verification key matches the circuit.
CircuitInput circuit
Circuit with its precomputed verification key.
Compute MegaHonk verification key for a circuit to be accumulated in Chonk.
Load a circuit into the Chonk instance for accumulation.
CircuitInput circuit
Circuit to be loaded with its bytecode and verification key.
ChonkProof proof
Complete IVC proof for all accumulated circuits.
Generate a proof for all accumulated circuits.
Response execute(BBApiRequest &request) &&
Initialize a new Chonk instance for incremental proof accumulation.
std::vector< CircuitKind > kinds
Get gate counts for a circuit.
CircuitInputNoVK circuit
The circuit to analyze.
Verify a Chonk proof with its verification key.
ChonkProof proof
The Chonk proof to verify.
std::string name
Human-readable name for the circuit.
std::string name
Human-readable name for the circuit.
std::vector< uint8_t > bytecode
Serialized bytecode representation of the circuit.
void throw_or_abort(std::string const &err)