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