Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
cli.cpp
Go to the documentation of this file.
1
35#include <atomic>
36#include <fstream>
37#include <iostream>
38#include <mutex>
39
40namespace bb {
41
42// TODO(https://github.com/AztecProtocol/barretenberg/issues/1257): Remove unused/seemingly unnecessary flags.
43// TODO(https://github.com/AztecProtocol/barretenberg/issues/1258): Improve defaults.
44
45// Helper function to recursively print active subcommands for CLI11 app debugging
46void print_active_subcommands(const CLI::App& app, const std::string& prefix = "bb command: ")
47{
48 // get_subcommands() returns a vector of pointers to subcommands
49 for (auto* subcmd : app.get_subcommands()) {
50 // Check if this subcommand was activated (nonzero count)
51 if (subcmd->count() > 0) {
52 vinfo(prefix, subcmd->get_name());
53 // Recursively print any subcommands of this subcommand
54 print_active_subcommands(*subcmd, prefix + " ");
55 }
56 }
57}
58
59// Recursive helper to find the deepest parsed subcommand.
60CLI::App* find_deepest_subcommand(CLI::App* app)
61{
62 for (auto& sub : app->get_subcommands()) {
63 if (sub->parsed()) {
64 // Check recursively if this subcommand has a deeper parsed subcommand.
65 if (CLI::App* deeper = find_deepest_subcommand(sub); deeper != nullptr) {
66 return deeper;
67 }
68 return sub;
69 }
70 }
71 return nullptr;
72}
73
74// Helper function to print options for a given subcommand.
75void print_subcommand_options(const CLI::App* sub)
76{
77 for (const auto& opt : sub->get_options()) {
78 if (opt->count() > 0) { // Only print options that were set.
79 if (opt->results().size() > 1) {
80 vinfo(" Warning: the following option is called more than once");
81 }
82 vinfo(" ", opt->get_name(), ": ", opt->results()[0]);
83 }
84 }
85}
86
106int parse_and_run_cli_command(int argc, char* argv[])
107{
108 std::string name = "Barretenberg\nYour favo(u)rite zkSNARK library written in C++, a perfectly good computer "
109 "programming language.";
110
111 // Check AVM support at runtime via global boolean
112 if (avm_enabled) {
113 name += "\nAztec Virtual Machine (AVM): enabled";
114 } else {
115 name += "\nAztec Virtual Machine (AVM): disabled";
116 }
117#ifdef ENABLE_AVM_TRANSPILER
118 name += "\nAVM Transpiler: enabled";
119#else
120 name += "\nAVM Transpiler: disabled";
121#endif
122#ifdef STARKNET_GARAGA_FLAVORS
123 name += "\nStarknet Garaga Extensions: enabled";
124#else
125 name += "\nStarknet Garaga Extensions: disabled";
126#endif
127 CLI::App app{ name };
128 argv = app.ensure_utf8(argv);
129 app.formatter(std::make_shared<Formatter>());
130
131 // If no arguments are provided, print help and exit.
132 if (argc == 1) {
133 std::cout << app.help() << std::endl;
134 return 0;
135 }
136
137 // prevent two or more subcommands being executed
138 app.require_subcommand(0, 1);
139
140 API::Flags flags{};
141 // Some paths, with defaults, that may or may not be set by commands
142 std::filesystem::path bytecode_path{ "./target/program.json" };
143 std::filesystem::path witness_path{ "./target/witness.gz" };
144 std::filesystem::path ivc_inputs_path{ "./ivc-inputs.msgpack" };
145 std::filesystem::path output_path{
146 "./out"
147 }; // sometimes a directory where things will be written, sometimes the path of a file to be written
148 std::filesystem::path public_inputs_path{ "./target/public_inputs" };
149 std::filesystem::path proof_path{ "./target/proof" };
150 std::filesystem::path vk_path{ "./target/vk" };
151 flags.scheme = "";
152 flags.oracle_hash_type = "poseidon2";
153 flags.crs_path = srs::bb_crs_path();
154 flags.include_gates_per_opcode = false;
155 const auto add_output_path_option = [&](CLI::App* subcommand, auto& _output_path) {
156 return subcommand->add_option("--output_path, -o",
157 _output_path,
158 "Directory to write files or path of file to write, depending on subcommand.");
159 };
160
161 /***************************************************************************************************************
162 * Subcommand: Adders for options that we will create for more than one subcommand
163 ***************************************************************************************************************/
164
165 const auto add_ipa_accumulation_flag = [&](CLI::App* subcommand) {
166 return subcommand->add_flag(
167 "--ipa_accumulation", flags.ipa_accumulation, "Accumulate/Aggregate IPA (Inner Product Argument) claims");
168 };
169
170 const auto add_scheme_option = [&](CLI::App* subcommand) {
171 return subcommand
172 ->add_option(
173 "--scheme, -s",
174 flags.scheme,
175 "The type of proof to be constructed. This can specify a proving system, an accumulation scheme, or a "
176 "particular type of circuit to be constructed and proven for some implicit scheme.")
177 ->envname("BB_SCHEME")
178 ->default_val("ultra_honk")
179 ->check(CLI::IsMember({ "chonk", "avm", "ultra_honk" }).name("is_member"));
180 };
181
182 const auto add_crs_path_option = [&](CLI::App* subcommand) {
183 return subcommand
184 ->add_option("--crs_path, -c",
185 flags.crs_path,
186 "Path CRS directory. Missing CRS files will be retrieved from the internet.")
187 ->check(CLI::ExistingDirectory);
188 };
189
190 const auto add_oracle_hash_option = [&](CLI::App* subcommand) {
191 return subcommand
192 ->add_option(
193 "--oracle_hash",
194 flags.oracle_hash_type,
195 "The hash function used by the prover as random oracle standing in for a verifier's challenge "
196 "generation. Poseidon2 is to be used for proofs that are intended to be verified inside of a "
197 "circuit. Keccak is optimized for verification in an Ethereum smart contract, where Keccak "
198 "has a privileged position due to the existence of an EVM precompile. Starknet is optimized "
199 "for verification in a Starknet smart contract, which can be generated using the Garaga library.")
200 ->check(CLI::IsMember({ "poseidon2", "keccak", "starknet" }).name("is_member"));
201 };
202
203 const auto add_write_vk_flag = [&](CLI::App* subcommand) {
204 return subcommand->add_flag("--write_vk", flags.write_vk, "Write the provided circuit's verification key");
205 };
206
207 const auto remove_zk_option = [&](CLI::App* subcommand) {
208 return subcommand->add_flag("--disable_zk",
209 flags.disable_zk,
210 "Use a non-zk version of --scheme. This flag is set to false by default.");
211 };
212
213 const auto add_bytecode_path_option = [&](CLI::App* subcommand) {
214 subcommand->add_option("--bytecode_path, -b", bytecode_path, "Path to ACIR bytecode generated by Noir.")
215 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
216 };
217
218 const auto add_witness_path_option = [&](CLI::App* subcommand) {
219 subcommand->add_option("--witness_path, -w", witness_path, "Path to partial witness generated by Noir.")
220 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
221 };
222
223 const auto add_ivc_inputs_path_options = [&](CLI::App* subcommand) {
224 subcommand->add_option(
225 "--ivc_inputs_path", ivc_inputs_path, "For IVC, path to input stack with bytecode and witnesses.")
226 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
227 };
228
229 const auto add_public_inputs_path_option = [&](CLI::App* subcommand) {
230 return subcommand->add_option(
231 "--public_inputs_path, -i", public_inputs_path, "Path to public inputs.") /* ->check(CLI::ExistingFile) */;
232 };
233
234 const auto add_proof_path_option = [&](CLI::App* subcommand) {
235 return subcommand->add_option(
236 "--proof_path, -p", proof_path, "Path to a proof.") /* ->check(CLI::ExistingFile) */;
237 };
238
239 const auto add_vk_path_option = [&](CLI::App* subcommand) {
240 return subcommand->add_option("--vk_path, -k", vk_path, "Path to a verification key.")
241 /* ->check(CLI::ExistingFile) */;
242 };
243
244 const auto add_verifier_type_option = [&](CLI::App* subcommand) {
245 return subcommand
246 ->add_option("--verifier_type",
247 flags.verifier_type,
248 "Is a verification key for use a standalone single circuit verifier (e.g. a SNARK or folding "
249 "recursive verifier) or is it for an ivc verifier? `standalone` produces a verification key "
250 "is sufficient for verifying proofs about a single circuit (including the non-encsapsulated "
251 "use case where an IVC scheme is manually constructed via recursive UltraHonk proof "
252 "verification). `standalone_hiding` is similar to `standalone` but is used for the last step "
253 "where the structured trace is not utilized. `ivc` produces a verification key for verifying "
254 "the stack of run though a dedicated ivc verifier class (currently the only option is the "
255 "Chonk class)")
256 ->check(CLI::IsMember({ "standalone", "standalone_hiding", "ivc" }).name("is_member"));
257 };
258
259 const auto add_verbose_flag = [&](CLI::App* subcommand) {
260 return subcommand->add_flag("--verbose, --verbose_logging, -v", flags.verbose, "Output all logs to stderr.");
261 };
262
263 const auto add_debug_flag = [&](CLI::App* subcommand) {
264 return subcommand->add_flag("--debug_logging, -d", flags.debug, "Output debug logs to stderr.");
265 };
266
267 const auto add_include_gates_per_opcode_flag = [&](CLI::App* subcommand) {
268 return subcommand->add_flag("--include_gates_per_opcode",
269 flags.include_gates_per_opcode,
270 "Include gates_per_opcode in the output of the gates command.");
271 };
272
273 const auto add_slow_low_memory_flag = [&](CLI::App* subcommand) {
274 return subcommand->add_flag(
275 "--slow_low_memory", flags.slow_low_memory, "Enable low memory mode (can be 2x slower or more).");
276 };
277
278 const auto add_storage_budget_option = [&](CLI::App* subcommand) {
279 return subcommand->add_option("--storage_budget",
280 flags.storage_budget,
281 "Storage budget for FileBackedMemory (e.g. '500m', '2g'). When exceeded, falls "
282 "back to RAM (requires --slow_low_memory).");
283 };
284
285 const auto add_vk_policy_option = [&](CLI::App* subcommand) {
286 return subcommand
287 ->add_option("--vk_policy",
288 flags.vk_policy,
289 "Policy for handling verification keys. 'default' uses the provided VK as-is, 'check' "
290 "verifies the provided VK matches the computed VK (throws error on mismatch), 'recompute' "
291 "always ignores the provided VK and treats it as nullptr, 'rewrite' checks the VK and "
292 "rewrites the input file with the correct VK if there's a mismatch (for check command).")
293 ->check(CLI::IsMember({ "default", "check", "recompute", "rewrite" }).name("is_member"));
294 };
295
296 const auto add_optimized_solidity_verifier_flag = [&](CLI::App* subcommand) {
297 return subcommand->add_flag(
298 "--optimized", flags.optimized_solidity_verifier, "Use the optimized Solidity verifier.");
299 };
300
301 bool print_bench = false;
302 const auto add_print_bench_flag = [&](CLI::App* subcommand) {
303 return subcommand->add_flag(
304 "--print_bench", print_bench, "Pretty print op counts to standard error in a human-readable format.");
305 };
306
307 std::string bench_out;
308 const auto add_bench_out_option = [&](CLI::App* subcommand) {
309 return subcommand->add_option("--bench_out", bench_out, "Path to write the op counts in a json.");
310 };
311 std::string bench_out_hierarchical;
312 const auto add_bench_out_hierarchical_option = [&](CLI::App* subcommand) {
313 return subcommand->add_option("--bench_out_hierarchical",
314 bench_out_hierarchical,
315 "Path to write the hierarchical benchmark data (op counts and timings with "
316 "parent-child relationships) as json.");
317 };
318
319 /***************************************************************************************************************
320 * Top-level flags
321 ***************************************************************************************************************/
322 add_verbose_flag(&app);
323 add_debug_flag(&app);
324 add_crs_path_option(&app);
325
326 /***************************************************************************************************************
327 * Builtin flag: --version
328 ***************************************************************************************************************/
329 app.set_version_flag("--version", BB_VERSION, "Print the version string.");
330
331 /***************************************************************************************************************
332 * Subcommand: check
333 ***************************************************************************************************************/
334 CLI::App* check = app.add_subcommand(
335 "check",
336 "A debugging tool to quickly check whether a witness satisfies a circuit The "
337 "function constructs the execution trace and iterates through it row by row, applying the "
338 "polynomial relations defining the gate types. For Chonk, we check the VKs in the folding stack.");
339
340 add_scheme_option(check);
341 add_bytecode_path_option(check);
342 add_witness_path_option(check);
343 add_ivc_inputs_path_options(check);
344 add_vk_policy_option(check);
345
346 /***************************************************************************************************************
347 * Subcommand: gates
348 ***************************************************************************************************************/
349 CLI::App* gates = app.add_subcommand("gates",
350 "Construct a circuit from the given bytecode (in particular, expand black box "
351 "functions) and return the gate count information.");
352
353 add_scheme_option(gates);
354 add_verbose_flag(gates);
355 add_bytecode_path_option(gates);
356 add_include_gates_per_opcode_flag(gates);
357 add_oracle_hash_option(gates);
358 add_ipa_accumulation_flag(gates);
359
360 /***************************************************************************************************************
361 * Subcommand: prove
362 ***************************************************************************************************************/
363 CLI::App* prove = app.add_subcommand("prove", "Generate a proof.");
364
365 add_scheme_option(prove);
366 add_bytecode_path_option(prove);
367 add_witness_path_option(prove);
368 add_output_path_option(prove, output_path);
369 add_ivc_inputs_path_options(prove);
370 add_vk_path_option(prove);
371 add_vk_policy_option(prove);
372 add_verbose_flag(prove);
373 add_debug_flag(prove);
374 add_crs_path_option(prove);
375 add_oracle_hash_option(prove);
376 add_write_vk_flag(prove);
377 add_ipa_accumulation_flag(prove);
378 remove_zk_option(prove);
379 add_slow_low_memory_flag(prove);
380 add_print_bench_flag(prove);
381 add_bench_out_option(prove);
382 add_bench_out_hierarchical_option(prove);
383 add_storage_budget_option(prove);
384
385 prove->add_flag("--verify", "Verify the proof natively, resulting in a boolean output. Useful for testing.");
386
387 /***************************************************************************************************************
388 * Subcommand: write_vk
389 ***************************************************************************************************************/
390 CLI::App* write_vk =
391 app.add_subcommand("write_vk",
392 "Write the verification key of a circuit. The circuit is constructed using "
393 "quickly generated but invalid witnesses (which must be supplied in Barretenberg in order "
394 "to expand ACIR black box opcodes), and no proof is constructed.");
395
396 add_scheme_option(write_vk);
397 add_bytecode_path_option(write_vk);
398 add_output_path_option(write_vk, output_path);
399 add_ivc_inputs_path_options(write_vk);
400
401 add_verbose_flag(write_vk);
402 add_debug_flag(write_vk);
403 add_crs_path_option(write_vk);
404 add_oracle_hash_option(write_vk);
405 add_ipa_accumulation_flag(write_vk);
406 add_verifier_type_option(write_vk)->default_val("standalone");
407 remove_zk_option(write_vk);
408
409 /***************************************************************************************************************
410 * Subcommand: verify
411 ***************************************************************************************************************/
412 CLI::App* verify = app.add_subcommand("verify", "Verify a proof.");
413
414 add_public_inputs_path_option(verify);
415 add_proof_path_option(verify);
416 add_vk_path_option(verify);
417
418 add_verbose_flag(verify);
419 add_debug_flag(verify);
420 add_scheme_option(verify);
421 add_crs_path_option(verify);
422 add_oracle_hash_option(verify);
423 remove_zk_option(verify);
424 add_ipa_accumulation_flag(verify);
425
426 /***************************************************************************************************************
427 * Subcommand: write_solidity_verifier
428 ***************************************************************************************************************/
429 CLI::App* write_solidity_verifier =
430 app.add_subcommand("write_solidity_verifier",
431 "Write a Solidity smart contract suitable for verifying proofs of circuit "
432 "satisfiability for the circuit with verification key at vk_path. Not all "
433 "hash types are implemented due to efficiency concerns.");
434
435 add_scheme_option(write_solidity_verifier);
436 add_vk_path_option(write_solidity_verifier);
437 add_output_path_option(write_solidity_verifier, output_path);
438
439 add_verbose_flag(write_solidity_verifier);
440 remove_zk_option(write_solidity_verifier);
441 add_crs_path_option(write_solidity_verifier);
442 add_optimized_solidity_verifier_flag(write_solidity_verifier);
443
444 std::filesystem::path avm_inputs_path{ "./target/avm_inputs.bin" };
445 const auto add_avm_inputs_option = [&](CLI::App* subcommand) {
446 return subcommand->add_option("--avm-inputs", avm_inputs_path, "");
447 };
448 std::filesystem::path avm_public_inputs_path{ "./target/avm_public_inputs.bin" };
449 const auto add_avm_public_inputs_option = [&](CLI::App* subcommand) {
450 return subcommand->add_option("--avm-public-inputs", avm_public_inputs_path, "");
451 };
452
453 /***************************************************************************************************************
454 * Subcommand: avm_simulate
455 ***************************************************************************************************************/
456 CLI::App* avm_simulate_command = app.add_subcommand("avm_simulate", "");
457 avm_simulate_command->group(""); // hide from list of subcommands
458 add_verbose_flag(avm_simulate_command);
459 add_debug_flag(avm_simulate_command);
460 add_avm_inputs_option(avm_simulate_command);
461
462 /***************************************************************************************************************
463 * Subcommand: avm_prove
464 ***************************************************************************************************************/
465 CLI::App* avm_prove_command = app.add_subcommand("avm_prove", "");
466 avm_prove_command->group(""); // hide from list of subcommands
467 add_verbose_flag(avm_prove_command);
468 add_debug_flag(avm_prove_command);
469 add_crs_path_option(avm_prove_command);
470 std::filesystem::path avm_prove_output_path{ "./proofs" };
471 add_output_path_option(avm_prove_command, avm_prove_output_path);
472 add_avm_inputs_option(avm_prove_command);
473
474 /***************************************************************************************************************
475 * Subcommand: avm_write_vk
476 ***************************************************************************************************************/
477 CLI::App* avm_write_vk_command = app.add_subcommand("avm_write_vk", "");
478 avm_write_vk_command->group(""); // hide from list of subcommands
479 add_verbose_flag(avm_write_vk_command);
480 add_debug_flag(avm_write_vk_command);
481 add_crs_path_option(avm_write_vk_command);
482 std::filesystem::path avm_write_vk_output_path{ "./keys" };
483 add_output_path_option(avm_write_vk_command, avm_write_vk_output_path);
484
485 /***************************************************************************************************************
486 * Subcommand: avm_check_circuit
487 ***************************************************************************************************************/
488 CLI::App* avm_check_circuit_command = app.add_subcommand("avm_check_circuit", "");
489 avm_check_circuit_command->group(""); // hide from list of subcommands
490 add_verbose_flag(avm_check_circuit_command);
491 add_debug_flag(avm_check_circuit_command);
492 add_crs_path_option(avm_check_circuit_command);
493 add_avm_inputs_option(avm_check_circuit_command);
494
495 /***************************************************************************************************************
496 * Subcommand: avm_verify
497 ***************************************************************************************************************/
498 CLI::App* avm_verify_command = app.add_subcommand("avm_verify", "");
499 avm_verify_command->group(""); // hide from list of subcommands
500 add_verbose_flag(avm_verify_command);
501 add_debug_flag(avm_verify_command);
502 add_crs_path_option(avm_verify_command);
503 add_avm_public_inputs_option(avm_verify_command);
504 add_proof_path_option(avm_verify_command);
505 add_vk_path_option(avm_verify_command);
506
507 /***************************************************************************************************************
508 * Subcommand: aztec_process_artifact
509 ***************************************************************************************************************/
510 CLI::App* aztec_process = app.add_subcommand(
511 "aztec_process",
512 "Process Aztec contract artifacts: transpile and generate verification keys for all private functions.\n"
513 "If input is a directory (and no output specified), recursively processes all artifacts found in the "
514 "directory.\n"
515 "Multiple -i flags can be specified when no -o flag is present for parallel processing.");
516
517 std::vector<std::string> artifact_input_paths;
518 std::string artifact_output_path;
519 bool force_regenerate = false;
520
521 aztec_process->add_option("-i,--input",
522 artifact_input_paths,
523 "Input artifact JSON path or directory to search (optional, defaults to current "
524 "directory). Can be specified multiple times when no -o flag is present.");
525 aztec_process->add_option(
526 "-o,--output",
527 artifact_output_path,
528 "Output artifact JSON path (optional, same as input if not specified). Cannot be used with multiple -i flags.");
529 aztec_process->add_flag("-f,--force", force_regenerate, "Force regeneration of verification keys");
530 add_verbose_flag(aztec_process);
531 add_debug_flag(aztec_process);
532
533 /***************************************************************************************************************
534 * Subcommand: aztec_process cache_paths
535 ***************************************************************************************************************/
536 CLI::App* cache_paths_command =
537 aztec_process->add_subcommand("cache_paths",
538 "Output cache paths for verification keys in an artifact.\n"
539 "Format: <hash>:<cache_path>:<function_name> (one per line).");
540
541 std::string cache_paths_input;
542 cache_paths_command->add_option("input", cache_paths_input, "Input artifact JSON path (required).")->required();
543 add_verbose_flag(cache_paths_command);
544 add_debug_flag(cache_paths_command);
545
546 /***************************************************************************************************************
547 * Subcommand: msgpack
548 ***************************************************************************************************************/
549 CLI::App* msgpack_command = app.add_subcommand("msgpack", "Msgpack API interface.");
550
551 // Subcommand: msgpack schema
552 CLI::App* msgpack_schema_command =
553 msgpack_command->add_subcommand("schema", "Output a msgpack schema encoded as JSON to stdout.");
554 add_verbose_flag(msgpack_schema_command);
555
556 // Subcommand: msgpack curve_constants
557 CLI::App* msgpack_curve_constants_command =
558 msgpack_command->add_subcommand("curve_constants", "Output curve constants as msgpack to stdout.");
559 add_verbose_flag(msgpack_curve_constants_command);
560
561 // Subcommand: msgpack run
562 CLI::App* msgpack_run_command =
563 msgpack_command->add_subcommand("run", "Execute msgpack API commands from stdin or file.");
564 add_verbose_flag(msgpack_run_command);
565 std::string msgpack_input_file;
566 msgpack_run_command->add_option(
567 "-i,--input", msgpack_input_file, "Input file containing msgpack buffers (defaults to stdin)");
568 size_t request_ring_size = 1024 * 1024; // 1MB default
569 msgpack_run_command
570 ->add_option(
571 "--request-ring-size", request_ring_size, "Request ring buffer size for shared memory IPC (default: 1MB)")
572 ->check(CLI::PositiveNumber);
573 size_t response_ring_size = 1024 * 1024; // 1MB default
574 msgpack_run_command
575 ->add_option("--response-ring-size",
576 response_ring_size,
577 "Response ring buffer size for shared memory IPC (default: 1MB)")
578 ->check(CLI::PositiveNumber);
579 int max_clients = 1;
580 msgpack_run_command
581 ->add_option("--max-clients",
582 max_clients,
583 "Maximum concurrent clients for socket IPC servers (default: 1, only used for .sock files)")
584 ->check(CLI::PositiveNumber);
585
586 /***************************************************************************************************************
587 * Build the CLI11 App
588 ***************************************************************************************************************/
589
590 CLI11_PARSE(app, argc, argv);
591 // Immediately after parsing, we can init the global CRS factory. Note this does not yet read or download any
592 // points; that is done on-demand.
593 srs::init_net_crs_factory(flags.crs_path);
594 if ((prove->parsed() || write_vk->parsed()) && output_path != "-") {
595 // If writing to an output folder, make sure it exists.
596 std::filesystem::create_directories(output_path);
597 }
598 debug_logging = flags.debug;
599 verbose_logging = debug_logging || flags.verbose;
600 slow_low_memory = flags.slow_low_memory;
601#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
602 if (!flags.storage_budget.empty()) {
603 storage_budget = parse_size_string(flags.storage_budget);
604 }
605 if (print_bench || !bench_out.empty() || !bench_out_hierarchical.empty()) {
607 vinfo("BB_BENCH enabled via --print_bench or --bench_out");
608 }
609#endif
610
612 info("Scheme is: ", flags.scheme, ", num threads: ", get_num_cpus());
613 if (CLI::App* deepest = find_deepest_subcommand(&app)) {
615 }
616
617 // TODO(AD): it is inflexible that Chonk shares an API command (prove) with UH this way. The base API class is a
618 // poor fit. It would be better to have a separate handling for each scheme with subcommands to prove.
619 const auto execute_non_prove_command = [&](API& api) {
620 if (check->parsed()) {
621 api.check(flags, bytecode_path, witness_path);
622 return 0;
623 }
624 if (gates->parsed()) {
625 api.gates(flags, bytecode_path);
626 return 0;
627 }
628 if (write_vk->parsed()) {
629 api.write_vk(flags, bytecode_path, output_path);
630 return 0;
631 }
632 if (verify->parsed()) {
633 const bool verified = api.verify(flags, public_inputs_path, proof_path, vk_path);
634 vinfo("verified: ", verified);
635 return verified ? 0 : 1;
636 }
637 if (write_solidity_verifier->parsed()) {
638 api.write_solidity_verifier(flags, output_path, vk_path);
639 return 0;
640 }
641 auto subcommands = app.get_subcommands();
642 const std::string message = std::string("No handler for subcommand ") + subcommands[0]->get_name();
643 throw_or_abort(message);
644 return 1;
645 };
646
647 try {
648 // MSGPACK
649 if (msgpack_schema_command->parsed()) {
651 return 0;
652 }
653 if (msgpack_curve_constants_command->parsed()) {
655 return 0;
656 }
657 if (msgpack_run_command->parsed()) {
658 return execute_msgpack_run(msgpack_input_file, max_clients, request_ring_size, response_ring_size);
659 }
660 if (aztec_process->parsed()) {
661#ifdef __wasm__
662 throw_or_abort("Aztec artifact processing is not supported in WASM builds.");
663#else
664 // Handle cache_paths subcommand
665 if (cache_paths_command->parsed()) {
666 return get_cache_paths(cache_paths_input) ? 0 : 1;
667 }
668
669 // Check for invalid combination of multiple inputs with output path
670 if (!artifact_output_path.empty() && artifact_input_paths.size() > 1) {
671 throw_or_abort("Cannot specify --output when multiple --input flags are provided.");
672 }
673
674 // Default to current directory if no inputs specified
675 if (artifact_input_paths.empty()) {
676 artifact_input_paths.push_back(".");
677 }
678
679 // Handle multiple inputs (process in parallel)
680 if (artifact_input_paths.size() > 1) {
681 // Validate all inputs are files, not directories
682 for (const auto& input : artifact_input_paths) {
683 if (std::filesystem::is_directory(input)) {
684 throw_or_abort("When using multiple --input flags, all inputs must be files, not directories.");
685 }
686 }
687
688 // Process all artifacts in parallel
689 std::atomic<bool> all_success = true;
690 std::vector<std::string> failures;
691 std::mutex failures_mutex;
692
693 parallel_for(artifact_input_paths.size(), [&](size_t i) {
694 const auto& input = artifact_input_paths[i];
695 if (!process_aztec_artifact(input, input, force_regenerate)) {
696 all_success = false;
697 std::lock_guard<std::mutex> lock(failures_mutex);
698 failures.push_back(input);
699 }
700 });
701
702 if (!all_success) {
703 info("Failed to process ", failures.size(), " artifact(s)");
704 return 1;
705 }
706 info("Successfully processed ", artifact_input_paths.size(), " artifact(s)");
707 return 0;
708 }
709
710 // Single input case
711 std::string input = artifact_input_paths[0];
712
713 // Check if input is a directory
714 if (std::filesystem::is_directory(input)) {
715 // If output specified for directory input, that's an error
716 if (!artifact_output_path.empty()) {
718 "Cannot specify --output when input is a directory. Artifacts are updated in-place.");
719 }
720 // Recursively process all artifacts in directory
721 return process_all_artifacts(input, force_regenerate) ? 0 : 1;
722 }
723
724 // Input is a file, process single artifact
725 std::string output = artifact_output_path.empty() ? input : artifact_output_path;
726 return process_aztec_artifact(input, output, force_regenerate) ? 0 : 1;
727#endif
728 }
729 // AVM - functions will throw at runtime if not supported (via stub module)
730 else if (avm_prove_command->parsed()) {
731 // This outputs both files: proof and vk, under the given directory.
732 avm_prove(avm_inputs_path, avm_prove_output_path);
733 } else if (avm_check_circuit_command->parsed()) {
734 avm_check_circuit(avm_inputs_path);
735 } else if (avm_verify_command->parsed()) {
736 return avm_verify(proof_path, avm_public_inputs_path, vk_path) ? 0 : 1;
737 } else if (avm_simulate_command->parsed()) {
738 avm_simulate(avm_inputs_path);
739 } else if (avm_write_vk_command->parsed()) {
740 avm_write_verification_key(avm_write_vk_output_path);
741 } else if (flags.scheme == "chonk") {
742 ChonkAPI api;
743 if (prove->parsed()) {
744 if (!std::filesystem::exists(ivc_inputs_path)) {
745 throw_or_abort("The prove command for Chonk expect a valid file passed with --ivc_inputs_path "
746 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
747 }
748 api.prove(flags, ivc_inputs_path, output_path);
749#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
750 if (print_bench) {
751 vinfo("Printing BB_BENCH results...");
754 }
755 if (!bench_out.empty()) {
756 std::ofstream file(bench_out);
758 }
759 if (!bench_out_hierarchical.empty()) {
760 std::ofstream file(bench_out_hierarchical);
762 }
763#endif
764 return 0;
765 }
766 if (check->parsed()) {
767 if (!std::filesystem::exists(ivc_inputs_path)) {
768 throw_or_abort("The check command for Chonk expect a valid file passed with --ivc_inputs_path "
769 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
770 }
771 return api.check_precomputed_vks(flags, ivc_inputs_path) ? 0 : 1;
772 }
773 return execute_non_prove_command(api);
774 } else if (flags.scheme == "ultra_honk") {
775 UltraHonkAPI api;
776 if (prove->parsed()) {
777 api.prove(flags, bytecode_path, witness_path, vk_path, output_path);
778#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
779 if (print_bench) {
781 }
782 if (!bench_out.empty()) {
783 std::ofstream file(bench_out);
785 }
786 if (!bench_out_hierarchical.empty()) {
787 std::ofstream file(bench_out_hierarchical);
789 }
790#endif
791 return 0;
792 }
793 return execute_non_prove_command(api);
794 } else {
795 throw_or_abort("No match for API command");
796 return 1;
797 }
798 } catch (std::runtime_error const& err) {
799#ifndef BB_NO_EXCEPTIONS
800 std::cerr << err.what() << std::endl;
801 return 1;
802#endif
803 }
804 return 0;
805}
806} // namespace bb
size_t parse_size_string(const std::string &size_str)
bool slow_low_memory
size_t storage_budget
UltraHonk-specific command definitions for the Barretenberg RPC API.
Definition api.hpp:7
void prove(const Flags &flags, const std::filesystem::path &input_path, const std::filesystem::path &output_dir)
Definition api_chonk.cpp:58
bool check_precomputed_vks(const Flags &flags, const std::filesystem::path &input_path)
void prove(const Flags &flags, const std::filesystem::path &bytecode_path, const std::filesystem::path &witness_path, const std::filesystem::path &vk_path, const std::filesystem::path &output_dir)
#define CLI11_PARSE(app,...)
#define vinfo(...)
Definition log.hpp:80
void info(Args... args)
Definition log.hpp:75
Programmatic interface for generating msgpack-encoded curve constants.
bool debug_logging
Definition log.cpp:12
bool verbose_logging
Definition log.cpp:6
std::string get_msgpack_schema_as_json()
GlobalBenchStatsContainer GLOBAL_BENCH_STATS
Definition bb_bench.cpp:621
bool use_bb_bench
Definition bb_bench.cpp:173
void init_net_crs_factory(const std::filesystem::path &path)
std::filesystem::path bb_crs_path()
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void print_subcommand_options(const CLI::App *sub)
Definition cli.cpp:75
void avm_simulate(const std::filesystem::path &inputs_path)
Simulates an public transaction.
Definition api_avm.cpp:81
int execute_msgpack_run(const std::string &msgpack_input_file, int max_clients, size_t request_ring_size, size_t response_ring_size)
Execute msgpack run command.
int parse_and_run_cli_command(int argc, char *argv[])
Parse command line arguments and run the corresponding command.
Definition cli.cpp:106
bool process_all_artifacts(const std::string &search_path, bool force)
Process all discovered contract artifacts in a directory tree.
bool get_cache_paths(const std::string &input_path)
Get cache paths for all verification keys in an artifact.
void write_curve_constants_msgpack_to_stdout()
Write msgpack-encoded curve constants to stdout.
bool process_aztec_artifact(const std::string &input_path, const std::string &output_path, bool force)
Process Aztec contract artifacts: transpile and generate verification keys.
size_t get_num_cpus()
Definition thread.cpp:33
bool avm_verify(const std::filesystem::path &proof_path, const std::filesystem::path &public_inputs_path, const std::filesystem::path &vk_path)
Verifies an avm proof and writes the result to stdout.
Definition api_avm.cpp:65
void print_active_subcommands(const CLI::App &app, const std::string &prefix="bb command: ")
Definition cli.cpp:46
void avm_write_verification_key(const std::filesystem::path &output_path)
Writes an avm (incomplete) verification key to a file.
Definition api_avm.cpp:93
void avm_prove(const std::filesystem::path &inputs_path, const std::filesystem::path &output_path)
Writes an avm proof and corresponding (incomplete) verification key to files.
Definition api_avm.cpp:30
const char * BB_VERSION
Definition version.hpp:14
void avm_check_circuit(const std::filesystem::path &inputs_path)
Stub - throws runtime error if called.
Definition api_avm.cpp:53
const bool avm_enabled
Definition api_avm.cpp:14
CLI::App * find_deepest_subcommand(CLI::App *app)
Definition cli.cpp:60
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string scheme
Definition api.hpp:18
void print_aggregate_counts_hierarchical(std::ostream &) const
Definition bb_bench.cpp:351
void print_aggregate_counts(std::ostream &, size_t) const
Definition bb_bench.cpp:274
void serialize_aggregate_data_json(std::ostream &) const
Definition bb_bench.cpp:313
void throw_or_abort(std::string const &err)