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
156 /***************************************************************************************************************
157 * Flag: --help-extended (detected early to set group visibility)
158 ***************************************************************************************************************/
159 // Check if --help-extended was passed before parsing (since we need to modify group visibility before CLI setup)
160 bool show_extended_help = false;
161 for (int i = 1; i < argc; ++i) {
162 if (std::string(argv[i]) == "--help-extended") {
163 show_extended_help = true;
164 break;
165 }
166 }
167 // Group names - empty string hides the group from help, non-empty shows it
168 const std::string advanced_group = show_extended_help ? "Advanced Options (Aztec/Power Users)" : "";
169 const std::string aztec_internal_group = show_extended_help ? "Aztec Internal Commands" : "";
170
171 const auto add_output_path_option = [&](CLI::App* subcommand, auto& _output_path) {
172 return subcommand->add_option("--output_path, -o",
173 _output_path,
174 "Directory to write files or path of file to write, depending on subcommand.");
175 };
176
177 // Helper to add --help-extended to subcommands (for help consistency)
178 const auto add_help_extended_flag = [&](CLI::App* subcommand) {
179 subcommand->add_flag("--help-extended", "Show all options including advanced ones.");
180 };
181
182 /***************************************************************************************************************
183 * Subcommand: Adders for options that we will create for more than one subcommand
184 ***************************************************************************************************************/
185
186 const auto add_ipa_accumulation_flag = [&](CLI::App* subcommand) {
187 return subcommand
188 ->add_flag("--ipa_accumulation",
189 flags.ipa_accumulation,
190 "Accumulate/Aggregate IPA (Inner Product Argument) claims")
191 ->group(advanced_group);
192 };
193
194 const auto add_scheme_option = [&](CLI::App* subcommand) {
195 return subcommand
196 ->add_option(
197 "--scheme, -s",
198 flags.scheme,
199 "The type of proof to be constructed. This can specify a proving system, an accumulation scheme, or a "
200 "particular type of circuit to be constructed and proven for some implicit scheme.")
201 ->envname("BB_SCHEME")
202 ->default_val("ultra_honk")
203 ->check(CLI::IsMember({ "chonk", "avm", "ultra_honk" }).name("is_member"))
204 ->group(advanced_group);
205 };
206
207 const auto add_crs_path_option = [&](CLI::App* subcommand) {
208 return subcommand
209 ->add_option("--crs_path, -c",
210 flags.crs_path,
211 "Path CRS directory. Missing CRS files will be retrieved from the internet.")
212 ->check(CLI::ExistingDirectory)
213 ->group(advanced_group);
214 };
215
216 const auto add_oracle_hash_option = [&](CLI::App* subcommand) {
217 return subcommand
218 ->add_option(
219 "--oracle_hash",
220 flags.oracle_hash_type,
221 "The hash function used by the prover as random oracle standing in for a verifier's challenge "
222 "generation. Poseidon2 is to be used for proofs that are intended to be verified inside of a "
223 "circuit. Keccak is optimized for verification in an Ethereum smart contract, where Keccak "
224 "has a privileged position due to the existence of an EVM precompile. Starknet is optimized "
225 "for verification in a Starknet smart contract, which can be generated using the Garaga library. "
226 "Prefer using --verifier_target instead.")
227 ->check(CLI::IsMember({ "poseidon2", "keccak", "starknet" }).name("is_member"))
228 ->group(advanced_group);
229 };
230
231 const auto add_verifier_target_option = [&](CLI::App* subcommand) {
232 return subcommand
233 ->add_option("--verifier_target, -t",
234 flags.verifier_target,
235 "Target verification environment. Determines hash function and ZK settings.\n"
236 "\n"
237 "Options:\n"
238 " evm Ethereum/Solidity (keccak, ZK)\n"
239 " evm-no-zk Ethereum/Solidity without ZK\n"
240 " noir-recursive Noir circuits (poseidon2, ZK)\n"
241 " noir-recursive-no-zk Noir circuits without ZK\n"
242 " noir-rollup Rollup with IPA (poseidon2, ZK)\n"
243 " noir-rollup-no-zk Rollup without ZK\n"
244 " starknet Starknet via Garaga (ZK)\n"
245 " starknet-no-zk Starknet without ZK")
246 ->envname("BB_VERIFIER_TARGET")
247 ->check(CLI::IsMember({ "evm",
248 "evm-no-zk",
249 "noir-recursive",
250 "noir-recursive-no-zk",
251 "noir-rollup",
252 "noir-rollup-no-zk",
253 "starknet",
254 "starknet-no-zk" }));
255 };
256
257 const auto add_write_vk_flag = [&](CLI::App* subcommand) {
258 return subcommand->add_flag("--write_vk", flags.write_vk, "Write the provided circuit's verification key");
259 };
260
261 const auto remove_zk_option = [&](CLI::App* subcommand) {
262 return subcommand
263 ->add_flag("--disable_zk",
264 flags.disable_zk,
265 "Use a non-zk version of --scheme. Prefer using --verifier_target *-no-zk variants instead.")
266 ->group(advanced_group);
267 };
268
269 const auto add_bytecode_path_option = [&](CLI::App* subcommand) {
270 subcommand->add_option("--bytecode_path, -b", bytecode_path, "Path to ACIR bytecode generated by Noir.")
271 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
272 };
273
274 const auto add_witness_path_option = [&](CLI::App* subcommand) {
275 subcommand->add_option("--witness_path, -w", witness_path, "Path to partial witness generated by Noir.")
276 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
277 };
278
279 const auto add_ivc_inputs_path_options = [&](CLI::App* subcommand) {
280 subcommand
281 ->add_option(
282 "--ivc_inputs_path", ivc_inputs_path, "For IVC, path to input stack with bytecode and witnesses.")
283 ->group(advanced_group);
284 };
285
286 const auto add_public_inputs_path_option = [&](CLI::App* subcommand) {
287 return subcommand->add_option(
288 "--public_inputs_path, -i", public_inputs_path, "Path to public inputs.") /* ->check(CLI::ExistingFile) */;
289 };
290
291 const auto add_proof_path_option = [&](CLI::App* subcommand) {
292 return subcommand->add_option(
293 "--proof_path, -p", proof_path, "Path to a proof.") /* ->check(CLI::ExistingFile) */;
294 };
295
296 const auto add_vk_path_option = [&](CLI::App* subcommand) {
297 return subcommand->add_option("--vk_path, -k", vk_path, "Path to a verification key.")
298 /* ->check(CLI::ExistingFile) */;
299 };
300
301 const auto add_verbose_flag = [&](CLI::App* subcommand) {
302 return subcommand->add_flag("--verbose, --verbose_logging, -v", flags.verbose, "Output all logs to stderr.")
303 ->group(advanced_group);
304 };
305
306 const auto add_debug_flag = [&](CLI::App* subcommand) {
307 return subcommand->add_flag("--debug_logging, -d", flags.debug, "Output debug logs to stderr.")
308 ->group(advanced_group);
309 };
310
311 const auto add_include_gates_per_opcode_flag = [&](CLI::App* subcommand) {
312 return subcommand->add_flag("--include_gates_per_opcode",
313 flags.include_gates_per_opcode,
314 "Include gates_per_opcode in the output of the gates command.");
315 };
316
317 const auto add_slow_low_memory_flag = [&](CLI::App* subcommand) {
318 return subcommand
319 ->add_flag("--slow_low_memory", flags.slow_low_memory, "Enable low memory mode (can be 2x slower or more).")
320 ->group(advanced_group);
321 };
322
323 const auto add_storage_budget_option = [&](CLI::App* subcommand) {
324 return subcommand
325 ->add_option("--storage_budget",
326 flags.storage_budget,
327 "Storage budget for FileBackedMemory (e.g. '500m', '2g'). When exceeded, falls "
328 "back to RAM (requires --slow_low_memory).")
329 ->group(advanced_group);
330 };
331
332 const auto add_vk_policy_option = [&](CLI::App* subcommand) {
333 return subcommand
334 ->add_option("--vk_policy",
335 flags.vk_policy,
336 "Policy for handling verification keys. 'default' uses the provided VK as-is, 'check' "
337 "verifies the provided VK matches the computed VK (throws error on mismatch), 'recompute' "
338 "always ignores the provided VK and treats it as nullptr, 'rewrite' checks the VK and "
339 "rewrites the input file with the correct VK if there's a mismatch (for check command).")
340 ->check(CLI::IsMember({ "default", "check", "recompute", "rewrite" }).name("is_member"))
341 ->group(advanced_group);
342 };
343
344 const auto add_optimized_solidity_verifier_flag = [&](CLI::App* subcommand) {
345 return subcommand->add_flag(
346 "--optimized", flags.optimized_solidity_verifier, "Use the optimized Solidity verifier.");
347 };
348
349 const auto add_output_format_option = [&](CLI::App* subcommand) {
350 return subcommand
351 ->add_option("--output_format",
352 flags.output_format,
353 "Output format for proofs and verification keys: 'binary' (default) or 'json'.\n"
354 "JSON format includes metadata like bb_version, scheme, and verifier_target.")
355 ->check(CLI::IsMember({ "binary", "json" }).name("is_member"));
356 };
357
358 bool print_bench = false;
359 const auto add_print_bench_flag = [&](CLI::App* subcommand) {
360 return subcommand
361 ->add_flag(
362 "--print_bench", print_bench, "Pretty print op counts to standard error in a human-readable format.")
363 ->group(advanced_group);
364 };
365
366 std::string bench_out;
367 const auto add_bench_out_option = [&](CLI::App* subcommand) {
368 return subcommand->add_option("--bench_out", bench_out, "Path to write the op counts in a json.")
369 ->group(advanced_group);
370 };
371 std::string bench_out_hierarchical;
372 const auto add_bench_out_hierarchical_option = [&](CLI::App* subcommand) {
373 return subcommand
374 ->add_option("--bench_out_hierarchical",
375 bench_out_hierarchical,
376 "Path to write the hierarchical benchmark data (op counts and timings with "
377 "parent-child relationships) as json.")
378 ->group(advanced_group);
379 };
380
381 /***************************************************************************************************************
382 * Top-level flags
383 ***************************************************************************************************************/
384 add_verbose_flag(&app);
385 add_debug_flag(&app);
386 add_crs_path_option(&app);
387
388 /***************************************************************************************************************
389 * Builtin flag: --version
390 ***************************************************************************************************************/
391 app.set_version_flag("--version", BB_VERSION, "Print the version string.");
392
393 /***************************************************************************************************************
394 * Flag: --help-extended (register with CLI11)
395 ***************************************************************************************************************/
396 app.add_flag("--help-extended", "Show all options including advanced and Aztec-specific commands.");
397
398 /***************************************************************************************************************
399 * Subcommand: check
400 ***************************************************************************************************************/
401 CLI::App* check = app.add_subcommand(
402 "check",
403 "A debugging tool to quickly check whether a witness satisfies a circuit The "
404 "function constructs the execution trace and iterates through it row by row, applying the "
405 "polynomial relations defining the gate types. For Chonk, we check the VKs in the folding stack.");
406
407 add_help_extended_flag(check);
408 add_scheme_option(check);
409 add_bytecode_path_option(check);
410 add_witness_path_option(check);
411 add_ivc_inputs_path_options(check);
412 add_vk_policy_option(check);
413
414 /***************************************************************************************************************
415 * Subcommand: gates
416 ***************************************************************************************************************/
417 CLI::App* gates = app.add_subcommand("gates",
418 "Construct a circuit from the given bytecode (in particular, expand black box "
419 "functions) and return the gate count information.");
420
421 add_help_extended_flag(gates);
422 add_scheme_option(gates);
423 add_verbose_flag(gates);
424 add_bytecode_path_option(gates);
425 add_include_gates_per_opcode_flag(gates);
426 add_verifier_target_option(gates);
427 add_oracle_hash_option(gates);
428 add_ipa_accumulation_flag(gates);
429
430 /***************************************************************************************************************
431 * Subcommand: prove
432 ***************************************************************************************************************/
433 CLI::App* prove = app.add_subcommand("prove", "Generate a proof.");
434
435 add_help_extended_flag(prove);
436 add_scheme_option(prove);
437 add_bytecode_path_option(prove);
438 add_witness_path_option(prove);
439 add_output_path_option(prove, output_path);
440 add_ivc_inputs_path_options(prove);
441 add_vk_path_option(prove);
442 add_vk_policy_option(prove);
443 add_verbose_flag(prove);
444 add_debug_flag(prove);
445 add_crs_path_option(prove);
446 add_verifier_target_option(prove);
447 add_oracle_hash_option(prove);
448 add_write_vk_flag(prove);
449 add_ipa_accumulation_flag(prove);
450 remove_zk_option(prove);
451 add_slow_low_memory_flag(prove);
452 add_print_bench_flag(prove);
453 add_bench_out_option(prove);
454 add_bench_out_hierarchical_option(prove);
455 add_storage_budget_option(prove);
456 add_output_format_option(prove);
457
458 prove->add_flag("--verify", "Verify the proof natively, resulting in a boolean output. Useful for testing.");
459
460 /***************************************************************************************************************
461 * Subcommand: write_vk
462 ***************************************************************************************************************/
463 CLI::App* write_vk =
464 app.add_subcommand("write_vk",
465 "Write the verification key of a circuit. The circuit is constructed using "
466 "quickly generated but invalid witnesses (which must be supplied in Barretenberg in order "
467 "to expand ACIR black box opcodes), and no proof is constructed.");
468
469 add_help_extended_flag(write_vk);
470 add_scheme_option(write_vk);
471 add_bytecode_path_option(write_vk);
472 add_output_path_option(write_vk, output_path);
473 add_ivc_inputs_path_options(write_vk);
474
475 add_verbose_flag(write_vk);
476 add_debug_flag(write_vk);
477 add_crs_path_option(write_vk);
478 add_verifier_target_option(write_vk);
479 add_oracle_hash_option(write_vk);
480 add_ipa_accumulation_flag(write_vk);
481 remove_zk_option(write_vk);
482 add_output_format_option(write_vk);
483
484 /***************************************************************************************************************
485 * Subcommand: verify
486 ***************************************************************************************************************/
487 CLI::App* verify = app.add_subcommand("verify", "Verify a proof.");
488
489 add_help_extended_flag(verify);
490 add_public_inputs_path_option(verify);
491 add_proof_path_option(verify);
492 add_vk_path_option(verify);
493
494 add_verbose_flag(verify);
495 add_debug_flag(verify);
496 add_scheme_option(verify);
497 add_crs_path_option(verify);
498 add_verifier_target_option(verify);
499 add_oracle_hash_option(verify);
500 remove_zk_option(verify);
501 add_ipa_accumulation_flag(verify);
502
503 /***************************************************************************************************************
504 * Subcommand: write_solidity_verifier
505 ***************************************************************************************************************/
506 CLI::App* write_solidity_verifier =
507 app.add_subcommand("write_solidity_verifier",
508 "Write a Solidity smart contract suitable for verifying proofs of circuit "
509 "satisfiability for the circuit with verification key at vk_path. Not all "
510 "hash types are implemented due to efficiency concerns.");
511
512 add_help_extended_flag(write_solidity_verifier);
513 add_scheme_option(write_solidity_verifier);
514 add_vk_path_option(write_solidity_verifier);
515 add_output_path_option(write_solidity_verifier, output_path);
516
517 add_verbose_flag(write_solidity_verifier);
518 add_verifier_target_option(write_solidity_verifier);
519 remove_zk_option(write_solidity_verifier);
520 add_crs_path_option(write_solidity_verifier);
521 add_optimized_solidity_verifier_flag(write_solidity_verifier);
522
523 std::filesystem::path avm_inputs_path{ "./target/avm_inputs.bin" };
524 const auto add_avm_inputs_option = [&](CLI::App* subcommand) {
525 return subcommand->add_option("--avm-inputs", avm_inputs_path, "");
526 };
527 std::filesystem::path avm_public_inputs_path{ "./target/avm_public_inputs.bin" };
528 const auto add_avm_public_inputs_option = [&](CLI::App* subcommand) {
529 return subcommand->add_option("--avm-public-inputs", avm_public_inputs_path, "");
530 };
531
532 /***************************************************************************************************************
533 * Subcommand: avm_simulate
534 ***************************************************************************************************************/
535 CLI::App* avm_simulate_command = app.add_subcommand("avm_simulate", "Simulate AVM execution.");
536 avm_simulate_command->group(aztec_internal_group);
537 add_verbose_flag(avm_simulate_command);
538 add_debug_flag(avm_simulate_command);
539 add_avm_inputs_option(avm_simulate_command);
540
541 /***************************************************************************************************************
542 * Subcommand: avm_prove
543 ***************************************************************************************************************/
544 CLI::App* avm_prove_command = app.add_subcommand("avm_prove", "Generate an AVM proof.");
545 avm_prove_command->group(aztec_internal_group);
546 add_verbose_flag(avm_prove_command);
547 add_debug_flag(avm_prove_command);
548 add_crs_path_option(avm_prove_command);
549 std::filesystem::path avm_prove_output_path{ "./proofs" };
550 add_output_path_option(avm_prove_command, avm_prove_output_path);
551 add_avm_inputs_option(avm_prove_command);
552
553 /***************************************************************************************************************
554 * Subcommand: avm_write_vk
555 ***************************************************************************************************************/
556 CLI::App* avm_write_vk_command = app.add_subcommand("avm_write_vk", "Write AVM verification key.");
557 avm_write_vk_command->group(aztec_internal_group);
558 add_verbose_flag(avm_write_vk_command);
559 add_debug_flag(avm_write_vk_command);
560 add_crs_path_option(avm_write_vk_command);
561 std::filesystem::path avm_write_vk_output_path{ "./keys" };
562 add_output_path_option(avm_write_vk_command, avm_write_vk_output_path);
563
564 /***************************************************************************************************************
565 * Subcommand: avm_check_circuit
566 ***************************************************************************************************************/
567 CLI::App* avm_check_circuit_command = app.add_subcommand("avm_check_circuit", "Check AVM circuit satisfiability.");
568 avm_check_circuit_command->group(aztec_internal_group);
569 add_verbose_flag(avm_check_circuit_command);
570 add_debug_flag(avm_check_circuit_command);
571 add_crs_path_option(avm_check_circuit_command);
572 add_avm_inputs_option(avm_check_circuit_command);
573
574 /***************************************************************************************************************
575 * Subcommand: avm_verify
576 ***************************************************************************************************************/
577 CLI::App* avm_verify_command = app.add_subcommand("avm_verify", "Verify an AVM proof.");
578 avm_verify_command->group(aztec_internal_group);
579 add_verbose_flag(avm_verify_command);
580 add_debug_flag(avm_verify_command);
581 add_crs_path_option(avm_verify_command);
582 add_avm_public_inputs_option(avm_verify_command);
583 add_proof_path_option(avm_verify_command);
584
585 /***************************************************************************************************************
586 * Subcommand: aztec_process_artifact
587 ***************************************************************************************************************/
588 CLI::App* aztec_process = app.add_subcommand(
589 "aztec_process",
590 "Process Aztec contract artifacts: transpile and generate verification keys for all private functions.\n"
591 "If input is a directory (and no output specified), recursively processes all artifacts found in the "
592 "directory.\n"
593 "Multiple -i flags can be specified when no -o flag is present for parallel processing.");
594 aztec_process->group(aztec_internal_group);
595
596 std::vector<std::string> artifact_input_paths;
597 std::string artifact_output_path;
598 bool force_regenerate = false;
599
600 aztec_process->add_option("-i,--input",
601 artifact_input_paths,
602 "Input artifact JSON path or directory to search (optional, defaults to current "
603 "directory). Can be specified multiple times when no -o flag is present.");
604 aztec_process->add_option(
605 "-o,--output",
606 artifact_output_path,
607 "Output artifact JSON path (optional, same as input if not specified). Cannot be used with multiple -i flags.");
608 aztec_process->add_flag("-f,--force", force_regenerate, "Force regeneration of verification keys");
609 add_verbose_flag(aztec_process);
610 add_debug_flag(aztec_process);
611
612 /***************************************************************************************************************
613 * Subcommand: aztec_process cache_paths
614 ***************************************************************************************************************/
615 CLI::App* cache_paths_command =
616 aztec_process->add_subcommand("cache_paths",
617 "Output cache paths for verification keys in an artifact.\n"
618 "Format: <hash>:<cache_path>:<function_name> (one per line).");
619
620 std::string cache_paths_input;
621 cache_paths_command->add_option("input", cache_paths_input, "Input artifact JSON path (required).")->required();
622 add_verbose_flag(cache_paths_command);
623 add_debug_flag(cache_paths_command);
624
625 /***************************************************************************************************************
626 * Subcommand: msgpack
627 ***************************************************************************************************************/
628 CLI::App* msgpack_command = app.add_subcommand("msgpack", "Msgpack API interface.");
629
630 // Subcommand: msgpack schema
631 CLI::App* msgpack_schema_command =
632 msgpack_command->add_subcommand("schema", "Output a msgpack schema encoded as JSON to stdout.");
633 add_verbose_flag(msgpack_schema_command);
634
635 // Subcommand: msgpack curve_constants
636 CLI::App* msgpack_curve_constants_command =
637 msgpack_command->add_subcommand("curve_constants", "Output curve constants as msgpack to stdout.");
638 add_verbose_flag(msgpack_curve_constants_command);
639
640 // Subcommand: msgpack run
641 CLI::App* msgpack_run_command =
642 msgpack_command->add_subcommand("run", "Execute msgpack API commands from stdin or file.");
643 add_verbose_flag(msgpack_run_command);
644 std::string msgpack_input_file;
645 msgpack_run_command->add_option(
646 "-i,--input", msgpack_input_file, "Input file containing msgpack buffers (defaults to stdin)");
647 size_t request_ring_size = 1024 * 1024; // 1MB default
648 msgpack_run_command
649 ->add_option(
650 "--request-ring-size", request_ring_size, "Request ring buffer size for shared memory IPC (default: 1MB)")
651 ->check(CLI::PositiveNumber);
652 size_t response_ring_size = 1024 * 1024; // 1MB default
653 msgpack_run_command
654 ->add_option("--response-ring-size",
655 response_ring_size,
656 "Response ring buffer size for shared memory IPC (default: 1MB)")
657 ->check(CLI::PositiveNumber);
658 int max_clients = 1;
659 msgpack_run_command
660 ->add_option("--max-clients",
661 max_clients,
662 "Maximum concurrent clients for socket IPC servers (default: 1, only used for .sock files)")
663 ->check(CLI::PositiveNumber);
664
665 /***************************************************************************************************************
666 * Build the CLI11 App
667 ***************************************************************************************************************/
668
669 CLI11_PARSE(app, argc, argv);
670
671 // Handle --help-extended: print help and exit
672 if (show_extended_help) {
673 std::cout << app.help() << '\n';
674 return 0;
675 }
676
677 // Apply verifier_target to derive oracle_hash_type, disable_zk, and ipa_accumulation
678 // This only applies when verifier_target is explicitly set
679 if (!flags.verifier_target.empty()) {
680 // Check for conflicting flags - verifier_target should not be combined with low-level flags
681 // We need to check the active subcommand for these options
682 CLI::App* active_sub = find_deepest_subcommand(&app);
683 if (active_sub != nullptr) {
684 // Helper to safely get option count (returns 0 if option doesn't exist)
685 auto get_option_count = [](CLI::App* sub, const std::string& name) -> size_t {
686 try {
687 return sub->get_option(name)->count();
688 } catch (const CLI::OptionNotFound&) {
689 return 0;
690 }
691 };
692
693 if (get_option_count(active_sub, "--oracle_hash") > 0) {
694 throw_or_abort("Cannot use --verifier_target with --oracle_hash. "
695 "The --verifier_target flag sets oracle_hash automatically.");
696 }
697 if (get_option_count(active_sub, "--disable_zk") > 0) {
698 throw_or_abort("Cannot use --verifier_target with --disable_zk. "
699 "Use a '-no-zk' variant of --verifier_target instead (e.g., 'evm-no-zk').");
700 }
701 if (get_option_count(active_sub, "--ipa_accumulation") > 0) {
702 throw_or_abort("Cannot use --verifier_target with --ipa_accumulation. "
703 "Use '--verifier_target noir-rollup' for IPA accumulation.");
704 }
705 }
706
707 // Map verifier_target to underlying flags
708 if (flags.verifier_target == "evm") {
709 flags.oracle_hash_type = "keccak";
710 } else if (flags.verifier_target == "evm-no-zk") {
711 flags.oracle_hash_type = "keccak";
712 flags.disable_zk = true;
713 } else if (flags.verifier_target == "noir-recursive") {
714 flags.oracle_hash_type = "poseidon2";
715 } else if (flags.verifier_target == "noir-recursive-no-zk") {
716 flags.oracle_hash_type = "poseidon2";
717 flags.disable_zk = true;
718 } else if (flags.verifier_target == "noir-rollup") {
719 flags.oracle_hash_type = "poseidon2";
720 flags.ipa_accumulation = true;
721 } else if (flags.verifier_target == "noir-rollup-no-zk") {
722 flags.oracle_hash_type = "poseidon2";
723 flags.ipa_accumulation = true;
724 flags.disable_zk = true;
725 } else if (flags.verifier_target == "starknet") {
726 flags.oracle_hash_type = "starknet";
727 } else if (flags.verifier_target == "starknet-no-zk") {
728 flags.oracle_hash_type = "starknet";
729 flags.disable_zk = true;
730 }
731 vinfo("verifier_target '",
732 flags.verifier_target,
733 "' -> oracle_hash_type='",
734 flags.oracle_hash_type,
735 "', disable_zk=",
736 flags.disable_zk,
737 ", ipa_accumulation=",
738 flags.ipa_accumulation);
739 }
740
741 // Immediately after parsing, we can init the global CRS factory. Note this does not yet read or download any
742 // points; that is done on-demand.
743 srs::init_net_crs_factory(flags.crs_path);
744 if ((prove->parsed() || write_vk->parsed()) && output_path != "-") {
745 // If writing to an output folder, make sure it exists.
746 std::filesystem::create_directories(output_path);
747 }
748 if (flags.debug) {
750 } else if (flags.verbose) {
752 }
753 slow_low_memory = flags.slow_low_memory;
754#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
755 if (!flags.storage_budget.empty()) {
756 storage_budget = parse_size_string(flags.storage_budget);
757 }
758 if (print_bench || !bench_out.empty() || !bench_out_hierarchical.empty()) {
760 vinfo("BB_BENCH enabled via --print_bench or --bench_out");
761 }
762#endif
763
765 info("Scheme is: ", flags.scheme, ", num threads: ", get_num_cpus());
766 if (CLI::App* deepest = find_deepest_subcommand(&app)) {
768 }
769
770 // TODO(AD): it is inflexible that Chonk shares an API command (prove) with UH this way. The base API class is a
771 // poor fit. It would be better to have a separate handling for each scheme with subcommands to prove.
772 const auto execute_non_prove_command = [&](API& api) {
773 if (check->parsed()) {
774 api.check(flags, bytecode_path, witness_path);
775 return 0;
776 }
777 if (gates->parsed()) {
778 api.gates(flags, bytecode_path);
779 return 0;
780 }
781 if (write_vk->parsed()) {
782 api.write_vk(flags, bytecode_path, output_path);
783 return 0;
784 }
785 if (verify->parsed()) {
786 const bool verified = api.verify(flags, public_inputs_path, proof_path, vk_path);
787 vinfo("verified: ", verified);
788 return verified ? 0 : 1;
789 }
790 if (write_solidity_verifier->parsed()) {
791 // Validate that verifier_target is compatible with Solidity verifier
792 if (!flags.verifier_target.empty() && flags.verifier_target != "evm" &&
793 flags.verifier_target != "evm-no-zk") {
794 throw_or_abort("write_solidity_verifier requires --verifier_target to be 'evm' or 'evm-no-zk', got '" +
795 flags.verifier_target + "'");
796 }
797 api.write_solidity_verifier(flags, output_path, vk_path);
798 return 0;
799 }
800 auto subcommands = app.get_subcommands();
801 const std::string message = std::string("No handler for subcommand ") + subcommands[0]->get_name();
802 throw_or_abort(message);
803 return 1;
804 };
805
806 try {
807 // MSGPACK
808 if (msgpack_schema_command->parsed()) {
810 return 0;
811 }
812 if (msgpack_curve_constants_command->parsed()) {
814 return 0;
815 }
816 if (msgpack_run_command->parsed()) {
817 return execute_msgpack_run(msgpack_input_file, max_clients, request_ring_size, response_ring_size);
818 }
819 if (aztec_process->parsed()) {
820#ifdef __wasm__
821 throw_or_abort("Aztec artifact processing is not supported in WASM builds.");
822#else
823 // Handle cache_paths subcommand
824 if (cache_paths_command->parsed()) {
825 return get_cache_paths(cache_paths_input) ? 0 : 1;
826 }
827
828 // Check for invalid combination of multiple inputs with output path
829 if (!artifact_output_path.empty() && artifact_input_paths.size() > 1) {
830 throw_or_abort("Cannot specify --output when multiple --input flags are provided.");
831 }
832
833 // Default to current directory if no inputs specified
834 if (artifact_input_paths.empty()) {
835 artifact_input_paths.push_back(".");
836 }
837
838 // Handle multiple inputs (process in parallel)
839 if (artifact_input_paths.size() > 1) {
840 // Validate all inputs are files, not directories
841 for (const auto& input : artifact_input_paths) {
842 if (std::filesystem::is_directory(input)) {
843 throw_or_abort("When using multiple --input flags, all inputs must be files, not directories.");
844 }
845 }
846
847 // Process all artifacts in parallel
848 std::atomic<bool> all_success = true;
849 std::vector<std::string> failures;
850 std::mutex failures_mutex;
851
852 parallel_for(artifact_input_paths.size(), [&](size_t i) {
853 const auto& input = artifact_input_paths[i];
854 if (!process_aztec_artifact(input, input, force_regenerate)) {
855 all_success = false;
856 std::lock_guard<std::mutex> lock(failures_mutex);
857 failures.push_back(input);
858 }
859 });
860
861 if (!all_success) {
862 info("Failed to process ", failures.size(), " artifact(s)");
863 return 1;
864 }
865 info("Successfully processed ", artifact_input_paths.size(), " artifact(s)");
866 return 0;
867 }
868
869 // Single input case
870 std::string input = artifact_input_paths[0];
871
872 // Check if input is a directory
873 if (std::filesystem::is_directory(input)) {
874 // If output specified for directory input, that's an error
875 if (!artifact_output_path.empty()) {
877 "Cannot specify --output when input is a directory. Artifacts are updated in-place.");
878 }
879 // Recursively process all artifacts in directory
880 return process_all_artifacts(input, force_regenerate) ? 0 : 1;
881 }
882
883 // Input is a file, process single artifact
884 std::string output = artifact_output_path.empty() ? input : artifact_output_path;
885 return process_aztec_artifact(input, output, force_regenerate) ? 0 : 1;
886#endif
887 }
888 // AVM - functions will throw at runtime if not supported (via stub module)
889 else if (avm_prove_command->parsed()) {
890 // This outputs both files: proof and vk, under the given directory.
891 avm_prove(avm_inputs_path, avm_prove_output_path);
892 } else if (avm_check_circuit_command->parsed()) {
893 avm_check_circuit(avm_inputs_path);
894 } else if (avm_verify_command->parsed()) {
895 return avm_verify(proof_path, avm_public_inputs_path) ? 0 : 1;
896 } else if (avm_simulate_command->parsed()) {
897 avm_simulate(avm_inputs_path);
898 } else if (avm_write_vk_command->parsed()) {
899 avm_write_verification_key(avm_write_vk_output_path);
900 } else if (flags.scheme == "chonk") {
901 ChonkAPI api;
902 if (prove->parsed()) {
903 if (!std::filesystem::exists(ivc_inputs_path)) {
904 throw_or_abort("The prove command for Chonk expect a valid file passed with --ivc_inputs_path "
905 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
906 }
907 api.prove(flags, ivc_inputs_path, output_path);
908#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
909 if (print_bench) {
910 vinfo("Printing BB_BENCH results...");
913 }
914 if (!bench_out.empty()) {
915 std::ofstream file(bench_out);
917 }
918 if (!bench_out_hierarchical.empty()) {
919 std::ofstream file(bench_out_hierarchical);
921 }
922#endif
923 return 0;
924 }
925 if (check->parsed()) {
926 if (!std::filesystem::exists(ivc_inputs_path)) {
927 throw_or_abort("The check command for Chonk expect a valid file passed with --ivc_inputs_path "
928 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
929 }
930 return api.check_precomputed_vks(flags, ivc_inputs_path) ? 0 : 1;
931 }
932 return execute_non_prove_command(api);
933 } else if (flags.scheme == "ultra_honk") {
934 UltraHonkAPI api;
935 if (prove->parsed()) {
936 api.prove(flags, bytecode_path, witness_path, vk_path, output_path);
937#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
938 if (print_bench) {
940 }
941 if (!bench_out.empty()) {
942 std::ofstream file(bench_out);
944 }
945 if (!bench_out_hierarchical.empty()) {
946 std::ofstream file(bench_out_hierarchical);
948 }
949#endif
950 return 0;
951 }
952 return execute_non_prove_command(api);
953 } else {
954 throw_or_abort("No match for API command");
955 return 1;
956 }
957 } catch (std::runtime_error const& err) {
958#ifndef BB_NO_EXCEPTIONS
959 std::cerr << err.what() << std::endl;
960 return 1;
961#endif
962 }
963 return 0;
964}
965} // 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
CLI API for Chonk (Aztec's client-side proving).
Definition api_chonk.hpp:33
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:51
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 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)
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:36
#define CLI11_PARSE(app,...)
#define info(...)
Definition log.hpp:93
#define vinfo(...)
Definition log.hpp:94
Programmatic interface for generating msgpack-encoded curve constants.
LogLevel bb_log_level
Definition log.cpp:9
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:77
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)
Verifies an avm proof and writes the result to stdout.
Definition api_avm.cpp:64
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:89
void avm_prove(const std::filesystem::path &inputs_path, const std::filesystem::path &output_path)
Writes an avm proof to a file.
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:52
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)