106 std::string name =
"Barretenberg\nYour favo(u)rite zkSNARK library written in C++, a perfectly good computer "
107 "programming language.";
109#ifdef DISABLE_AZTEC_VM
110 name +=
"\nAztec Virtual Machine (AVM): disabled";
112 name +=
"\nAztec Virtual Machine (AVM): enabled";
114#ifdef STARKNET_GARAGA_FLAVORS
115 name +=
"\nStarknet Garaga Extensions: enabled";
117 name +=
"\nStarknet Garaga Extensions: disabled";
119 CLI::App app{ name };
120 argv = app.ensure_utf8(argv);
130 app.require_subcommand(0, 1);
134 std::filesystem::path bytecode_path{
"./target/program.json" };
135 std::filesystem::path witness_path{
"./target/witness.gz" };
136 std::filesystem::path ivc_inputs_path{
"./ivc-inputs.msgpack" };
137 std::filesystem::path output_path{
140 std::filesystem::path public_inputs_path{
"./target/public_inputs" };
141 std::filesystem::path proof_path{
"./target/proof" };
142 std::filesystem::path vk_path{
"./target/vk" };
144 flags.oracle_hash_type =
"poseidon2";
145 flags.output_format =
"bytes";
147 flags.include_gates_per_opcode =
false;
148 const auto add_output_path_option = [&](CLI::App* subcommand,
auto& _output_path) {
149 return subcommand->add_option(
"--output_path, -o",
151 "Directory to write files or path of file to write, depending on subcommand.");
158 const auto add_ipa_accumulation_flag = [&](CLI::App* subcommand) {
159 return subcommand->add_flag(
160 "--ipa_accumulation", flags.ipa_accumulation,
"Accumulate/Aggregate IPA (Inner Product Argument) claims");
163 const auto add_scheme_option = [&](CLI::App* subcommand) {
168 "The type of proof to be constructed. This can specify a proving system, an accumulation scheme, or a "
169 "particular type of circuit to be constructed and proven for some implicit scheme.")
170 ->envname(
"BB_SCHEME")
171 ->default_val(
"ultra_honk")
172 ->check(CLI::IsMember({
"client_ivc",
"avm",
"ultra_honk" }).name(
"is_member"));
175 const auto add_crs_path_option = [&](CLI::App* subcommand) {
177 ->add_option(
"--crs_path, -c",
179 "Path CRS directory. Missing CRS files will be retrieved from the internet.")
180 ->check(CLI::ExistingDirectory);
183 const auto add_oracle_hash_option = [&](CLI::App* subcommand) {
187 flags.oracle_hash_type,
188 "The hash function used by the prover as random oracle standing in for a verifier's challenge "
189 "generation. Poseidon2 is to be used for proofs that are intended to be verified inside of a "
190 "circuit. Keccak is optimized for verification in an Ethereum smart contract, where Keccak "
191 "has a privileged position due to the existence of an EVM precompile. Starknet is optimized "
192 "for verification in a Starknet smart contract, which can be generated using the Garaga library.")
193 ->check(CLI::IsMember({
"poseidon2",
"keccak",
"starknet" }).name(
"is_member"));
196 const auto add_output_format_option = [&](CLI::App* subcommand) {
201 "The type of the data to be written by the command. If bytes, output the raw bytes prefixed with "
202 "header information for deserialization. If fields, output a string representation of an array of "
203 "field elements. If bytes_and_fields do both. If fields_msgpack, outputs a msgpack buffer of Fr "
205 ->check(CLI::IsMember({
"bytes",
"fields",
"bytes_and_fields",
"fields_msgpack" }).name(
"is_member"));
208 const auto add_write_vk_flag = [&](CLI::App* subcommand) {
209 return subcommand->add_flag(
"--write_vk", flags.write_vk,
"Write the provided circuit's verification key");
212 const auto remove_zk_option = [&](CLI::App* subcommand) {
213 return subcommand->add_flag(
"--disable_zk",
215 "Use a non-zk version of --scheme. This flag is set to false by default.");
218 const auto add_bytecode_path_option = [&](CLI::App* subcommand) {
219 subcommand->add_option(
"--bytecode_path, -b", bytecode_path,
"Path to ACIR bytecode generated by Noir.")
223 const auto add_witness_path_option = [&](CLI::App* subcommand) {
224 subcommand->add_option(
"--witness_path, -w", witness_path,
"Path to partial witness generated by Noir.")
228 const auto add_ivc_inputs_path_options = [&](CLI::App* subcommand) {
229 subcommand->add_option(
230 "--ivc_inputs_path", ivc_inputs_path,
"For IVC, path to input stack with bytecode and witnesses.")
234 const auto add_public_inputs_path_option = [&](CLI::App* subcommand) {
235 return subcommand->add_option(
236 "--public_inputs_path, -i", public_inputs_path,
"Path to public inputs.") ;
239 const auto add_proof_path_option = [&](CLI::App* subcommand) {
240 return subcommand->add_option(
241 "--proof_path, -p", proof_path,
"Path to a proof.") ;
244 const auto add_vk_path_option = [&](CLI::App* subcommand) {
245 return subcommand->add_option(
"--vk_path, -k", vk_path,
"Path to a verification key.")
249 const auto add_verifier_type_option = [&](CLI::App* subcommand) {
251 ->add_option(
"--verifier_type",
253 "Is a verification key for use a standalone single circuit verifier (e.g. a SNARK or folding "
254 "recursive verifier) or is it for an ivc verifier? `standalone` produces a verification key "
255 "is sufficient for verifying proofs about a single circuit (including the non-encsapsulated "
256 "use case where an IVC scheme is manually constructed via recursive UltraHonk proof "
257 "verification). `ivc` produces a verification key for verifying the stack of run though a "
258 "dedicated ivc verifier class (currently the only option is the ClientIVC class) ")
259 ->check(CLI::IsMember({
"standalone",
"ivc" }).name(
"is_member"));
262 const auto add_verbose_flag = [&](CLI::App* subcommand) {
263 return subcommand->add_flag(
"--verbose, --verbose_logging, -v", flags.verbose,
"Output all logs to stderr.");
266 const auto add_debug_flag = [&](CLI::App* subcommand) {
267 return subcommand->add_flag(
"--debug_logging, -d", flags.debug,
"Output debug logs to stderr.");
270 const auto add_include_gates_per_opcode_flag = [&](CLI::App* subcommand) {
271 return subcommand->add_flag(
"--include_gates_per_opcode",
272 flags.include_gates_per_opcode,
273 "Include gates_per_opcode in the output of the gates command.");
276 const auto add_slow_low_memory_flag = [&](CLI::App* subcommand) {
277 return subcommand->add_flag(
278 "--slow_low_memory", flags.slow_low_memory,
"Enable low memory mode (can be 2x slower or more).");
281 const auto add_update_inputs_flag = [&](CLI::App* subcommand) {
282 return subcommand->add_flag(
"--update_inputs", flags.update_inputs,
"Update inputs if vk check fails.");
285 bool print_op_counts =
false;
286 const auto add_print_op_counts_flag = [&](CLI::App* subcommand) {
287 return subcommand->add_flag(
"--print_op_counts", print_op_counts,
"Print op counts to json on one line.");
290 std::string op_counts_out;
291 const auto add_op_counts_out_option = [&](CLI::App* subcommand) {
292 return subcommand->add_option(
"--op_counts_out", op_counts_out,
"Path to write the op counts in a json.");
298 add_verbose_flag(&app);
299 add_debug_flag(&app);
300 add_crs_path_option(&app);
310 CLI::App* check = app.add_subcommand(
312 "A debugging tool to quickly check whether a witness satisfies a circuit The "
313 "function constructs the execution trace and iterates through it row by row, applying the "
314 "polynomial relations defining the gate types. For client IVC, we check the VKs in the folding stack.");
316 add_scheme_option(check);
317 add_bytecode_path_option(check);
318 add_witness_path_option(check);
319 add_ivc_inputs_path_options(check);
320 add_update_inputs_flag(check);
325 CLI::App* gates = app.add_subcommand(
"gates",
326 "Construct a circuit from the given bytecode (in particular, expand black box "
327 "functions) and return the gate count information.");
329 add_scheme_option(gates);
330 add_verbose_flag(gates);
331 add_bytecode_path_option(gates);
332 add_include_gates_per_opcode_flag(gates);
337 CLI::App* prove = app.add_subcommand(
"prove",
"Generate a proof.");
339 add_scheme_option(prove);
340 add_bytecode_path_option(prove);
341 add_witness_path_option(prove);
342 add_output_path_option(prove, output_path);
343 add_ivc_inputs_path_options(prove);
344 add_vk_path_option(prove);
345 add_verbose_flag(prove);
346 add_debug_flag(prove);
347 add_crs_path_option(prove);
348 add_oracle_hash_option(prove);
349 add_output_format_option(prove);
350 add_write_vk_flag(prove);
351 add_ipa_accumulation_flag(prove);
352 remove_zk_option(prove);
353 add_slow_low_memory_flag(prove);
354 add_print_op_counts_flag(prove);
355 add_op_counts_out_option(prove);
357 prove->add_flag(
"--verify",
"Verify the proof natively, resulting in a boolean output. Useful for testing.");
363 app.add_subcommand(
"write_vk",
364 "Write the verification key of a circuit. The circuit is constructed using "
365 "quickly generated but invalid witnesses (which must be supplied in Barretenberg in order "
366 "to expand ACIR black box opcodes), and no proof is constructed.");
368 add_scheme_option(write_vk);
369 add_bytecode_path_option(write_vk);
370 add_output_path_option(write_vk, output_path);
371 add_ivc_inputs_path_options(write_vk);
373 add_verbose_flag(write_vk);
374 add_debug_flag(write_vk);
375 add_output_format_option(write_vk);
376 add_crs_path_option(write_vk);
377 add_oracle_hash_option(write_vk);
378 add_ipa_accumulation_flag(write_vk);
379 add_verifier_type_option(write_vk)->default_val(
"standalone");
380 remove_zk_option(write_vk);
385 CLI::App* verify = app.add_subcommand(
"verify",
"Verify a proof.");
387 add_public_inputs_path_option(verify);
388 add_proof_path_option(verify);
389 add_vk_path_option(verify);
391 add_verbose_flag(verify);
392 add_debug_flag(verify);
393 add_scheme_option(verify);
394 add_crs_path_option(verify);
395 add_oracle_hash_option(verify);
396 remove_zk_option(verify);
397 add_ipa_accumulation_flag(verify);
402 CLI::App* write_solidity_verifier =
403 app.add_subcommand(
"write_solidity_verifier",
404 "Write a Solidity smart contract suitable for verifying proofs of circuit "
405 "satisfiability for the circuit with verification key at vk_path. Not all "
406 "hash types are implemented due to efficiency concerns.");
408 add_scheme_option(write_solidity_verifier);
409 add_vk_path_option(write_solidity_verifier);
410 add_output_path_option(write_solidity_verifier, output_path);
412 add_verbose_flag(write_solidity_verifier);
413 remove_zk_option(write_solidity_verifier);
414 add_crs_path_option(write_solidity_verifier);
419 CLI::App* OLD_API = app.add_subcommand(
"OLD_API",
"Access some old API commands");
424 CLI::App* OLD_API_write_arbitrary_valid_client_ivc_proof_and_vk_to_file =
425 OLD_API->add_subcommand(
"write_arbitrary_valid_client_ivc_proof_and_vk_to_file",
"");
426 add_verbose_flag(OLD_API_write_arbitrary_valid_client_ivc_proof_and_vk_to_file);
427 add_debug_flag(OLD_API_write_arbitrary_valid_client_ivc_proof_and_vk_to_file);
428 add_crs_path_option(OLD_API_write_arbitrary_valid_client_ivc_proof_and_vk_to_file);
429 std::string arbitrary_valid_proof_path{
"./proofs/proof" };
430 add_output_path_option(OLD_API_write_arbitrary_valid_client_ivc_proof_and_vk_to_file, arbitrary_valid_proof_path);
435 CLI::App* OLD_API_gates = OLD_API->add_subcommand(
"gates",
"");
436 add_verbose_flag(OLD_API_gates);
437 add_debug_flag(OLD_API_gates);
438 add_crs_path_option(OLD_API_gates);
439 add_bytecode_path_option(OLD_API_gates);
444 CLI::App* OLD_API_verify = OLD_API->add_subcommand(
"verify",
"");
445 add_verbose_flag(OLD_API_verify);
446 add_debug_flag(OLD_API_verify);
447 add_crs_path_option(OLD_API_verify);
448 add_bytecode_path_option(OLD_API_verify);
449 add_proof_path_option(OLD_API_verify);
450 add_vk_path_option(OLD_API_verify);
455 CLI::App* OLD_API_prove_and_verify = OLD_API->add_subcommand(
"prove_and_verify",
"");
456 add_verbose_flag(OLD_API_prove_and_verify);
457 add_debug_flag(OLD_API_prove_and_verify);
458 add_crs_path_option(OLD_API_prove_and_verify);
459 add_bytecode_path_option(OLD_API_prove_and_verify);
461 std::filesystem::path avm_inputs_path{
"./target/avm_inputs.bin" };
462 const auto add_avm_inputs_option = [&](CLI::App* subcommand) {
463 return subcommand->add_option(
"--avm-inputs", avm_inputs_path,
"");
465 std::filesystem::path avm_public_inputs_path{
"./target/avm_public_inputs.bin" };
466 const auto add_avm_public_inputs_option = [&](CLI::App* subcommand) {
467 return subcommand->add_option(
"--avm-public-inputs", avm_public_inputs_path,
"");
473 CLI::App* avm_prove_command = app.add_subcommand(
"avm_prove",
"");
474 avm_prove_command->group(
"");
475 add_verbose_flag(avm_prove_command);
476 add_debug_flag(avm_prove_command);
477 add_crs_path_option(avm_prove_command);
478 std::filesystem::path avm_prove_output_path{
"./proofs" };
479 add_output_path_option(avm_prove_command, avm_prove_output_path);
480 add_avm_inputs_option(avm_prove_command);
485 CLI::App* avm_check_circuit_command = app.add_subcommand(
"avm_check_circuit",
"");
486 avm_check_circuit_command->group(
"");
487 add_verbose_flag(avm_check_circuit_command);
488 add_debug_flag(avm_check_circuit_command);
489 add_crs_path_option(avm_check_circuit_command);
490 add_avm_inputs_option(avm_check_circuit_command);
495 CLI::App* avm_verify_command = app.add_subcommand(
"avm_verify",
"");
496 avm_verify_command->group(
"");
497 add_verbose_flag(avm_verify_command);
498 add_debug_flag(avm_verify_command);
499 add_crs_path_option(avm_verify_command);
500 add_avm_public_inputs_option(avm_verify_command);
501 add_proof_path_option(avm_verify_command);
502 add_vk_path_option(avm_verify_command);
507 CLI::App* msgpack_command = app.add_subcommand(
"msgpack",
"Msgpack API interface.");
510 CLI::App* msgpack_schema_command =
511 msgpack_command->add_subcommand(
"schema",
"Output a msgpack schema encoded as JSON to stdout.");
512 add_verbose_flag(msgpack_schema_command);
515 CLI::App* msgpack_run_command =
516 msgpack_command->add_subcommand(
"run",
"Execute msgpack API commands from stdin or file.");
517 add_verbose_flag(msgpack_run_command);
518 std::string msgpack_input_file;
519 msgpack_run_command->add_option(
520 "-i,--input", msgpack_input_file,
"Input file containing msgpack buffers (defaults to stdin)");
525 CLI ::App* prove_tube_command = app.add_subcommand(
"prove_tube",
"");
526 prove_tube_command->group(
"");
527 add_verbose_flag(prove_tube_command);
528 add_debug_flag(prove_tube_command);
529 add_crs_path_option(prove_tube_command);
530 add_vk_path_option(prove_tube_command);
531 std::string prove_tube_output_path{
"./target" };
532 add_output_path_option(prove_tube_command, prove_tube_output_path);
537 CLI::App* verify_tube_command = app.add_subcommand(
"verify_tube",
"");
538 verify_tube_command->group(
"");
539 add_verbose_flag(verify_tube_command);
540 add_debug_flag(verify_tube_command);
541 add_crs_path_option(verify_tube_command);
543 std::string tube_proof_and_vk_path{
"./target" };
544 add_output_path_option(verify_tube_command, tube_proof_and_vk_path);
554 if ((prove->parsed() || write_vk->parsed()) && output_path !=
"-") {
556 std::filesystem::create_directories(output_path);
562 if (print_op_counts || !op_counts_out.empty()) {
578 const auto execute_non_prove_command = [&](
API& api) {
579 if (check->parsed()) {
580 api.check(flags, bytecode_path, witness_path);
583 if (gates->parsed()) {
584 api.gates(flags, bytecode_path);
587 if (write_vk->parsed()) {
588 api.write_vk(flags, bytecode_path, output_path);
591 if (verify->parsed()) {
592 const bool verified = api.verify(flags, public_inputs_path, proof_path, vk_path);
593 vinfo(
"verified: ", verified);
594 return verified ? 0 : 1;
596 if (write_solidity_verifier->parsed()) {
597 api.write_solidity_verifier(flags, output_path, vk_path);
600 auto subcommands = app.get_subcommands();
601 const std::string message = std::string(
"No handler for subcommand ") + subcommands[0]->get_name();
608 if (msgpack_schema_command->parsed()) {
612 if (msgpack_run_command->parsed()) {
616 if (prove_tube_command->parsed()) {
619 }
else if (verify_tube_command->parsed()) {
621 auto tube_public_inputs_path = tube_proof_and_vk_path +
"/public_inputs";
622 auto tube_proof_path = tube_proof_and_vk_path +
"/proof";
623 auto tube_vk_path = tube_proof_and_vk_path +
"/vk";
625 return api.
verify({ .ipa_accumulation =
true }, tube_public_inputs_path, tube_proof_path, tube_vk_path) ? 0
629#ifndef DISABLE_AZTEC_VM
630 else if (avm_prove_command->parsed()) {
632 avm_prove(avm_inputs_path, avm_prove_output_path);
633 }
else if (avm_check_circuit_command->parsed()) {
635 }
else if (avm_verify_command->parsed()) {
636 return avm_verify(proof_path, avm_public_inputs_path, vk_path) ? 0 : 1;
639 else if (avm_prove_command->parsed()) {
640 throw_or_abort(
"The Aztec Virtual Machine (AVM) is disabled in this environment!");
641 }
else if (avm_check_circuit_command->parsed()) {
642 throw_or_abort(
"The Aztec Virtual Machine (AVM) is disabled in this environment!");
643 }
else if (avm_verify_command->parsed()) {
644 throw_or_abort(
"The Aztec Virtual Machine (AVM) is disabled in this environment!");
647 else if (OLD_API_write_arbitrary_valid_client_ivc_proof_and_vk_to_file->parsed()) {
654 else if (flags.scheme ==
"client_ivc") {
656 if (prove->parsed()) {
657 if (!std::filesystem::exists(ivc_inputs_path)) {
658 throw_or_abort(
"The prove command for ClientIVC expect a valid file passed with --ivc_inputs_path "
659 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
661 api.
prove(flags, ivc_inputs_path, output_path);
663 if (print_op_counts) {
666 if (!op_counts_out.empty()) {
667 std::ofstream file(op_counts_out);
673 if (check->parsed()) {
674 if (!std::filesystem::exists(ivc_inputs_path)) {
675 throw_or_abort(
"The check command for ClientIVC expect a valid file passed with --ivc_inputs_path "
676 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
680 return execute_non_prove_command(api);
681 }
else if (flags.scheme ==
"ultra_honk") {
683 if (prove->parsed()) {
684 api.
prove(flags, bytecode_path, witness_path, vk_path, output_path);
686 if (print_op_counts) {
689 if (!op_counts_out.empty()) {
690 std::ofstream file(op_counts_out);
696 return execute_non_prove_command(api);
701 }
catch (std::runtime_error
const& err) {
702#ifndef BB_NO_EXCEPTIONS