diff --git a/Earthfile b/Earthfile index 6a43fdff5..6030d85a7 100644 --- a/Earthfile +++ b/Earthfile @@ -50,6 +50,7 @@ barretenberg-acir-tests-bb-ultra-plonk: # Run every acir test through native bb build prove_then_verify flow for UltraPlonk. # This ensures we test independent pk construction through real/garbage witness data paths. RUN FLOW=prove_then_verify ./run_acir_tests.sh + RUN FLOW=prove_then_verify RECURSIVE=true ./run_acir_tests.sh assert_statement double_verify_proof barretenberg-acir-tests-bb-ultra-honk: FROM ../build-images/+from-registry @@ -67,6 +68,7 @@ barretenberg-acir-tests-bb-ultra-honk: # Run the acir test through native bb build prove_then_verify_ultra_honk flow # Note that the script will skip the Plonk related tests RUN FLOW=prove_then_verify_ultra_honk HONK=true ./run_acir_tests.sh + RUN FLOW=prove_then_verify_ultra_honk HONK=true RECURSIVE=true ./run_acir_tests.sh assert_statement double_verify_honk_proof # Construct and verify a UltraHonk proof for a single program RUN FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh pedersen_hash @@ -173,4 +175,4 @@ barretenberg-acir-tests-bb.js: # Run fold_basic test through bb.js which runs ClientIVC on fold basic RUN BIN=../ts/dest/node/main.js FLOW=fold_and_verify_program ./run_acir_tests.sh fold_basic # Run 1_mul through bb.js build, all_cmds flow, to test all cli args. - RUN BIN=../ts/dest/node/main.js FLOW=all_cmds ./run_acir_tests.sh 1_mul + RUN BIN=../ts/dest/node/main.js FLOW=all_cmds ./run_acir_tests.sh 1_mul \ No newline at end of file diff --git a/acir_tests/Dockerfile.bb.sol b/acir_tests/Dockerfile.bb.sol index 2f89581c1..9b09ba86d 100644 --- a/acir_tests/Dockerfile.bb.sol +++ b/acir_tests/Dockerfile.bb.sol @@ -18,8 +18,7 @@ COPY . . # This includes the basic `assert_statement` test that contains a single public input # and the recursive aggregation circuits which use the Keccak based prover. # -# NOTE: When circuits are marked `recursive` it means the backend will use a prover that -# produces SNARK recursion friendly proofs, while the solidity verifier expects proofs -# whose transcript uses Keccak hashing. +# NOTE: The solidity verifier expects proofs whose transcript uses Keccak hashing, +# for which we have to invoke the backend prover without the `--recursive` flag. RUN (cd sol-test && yarn) RUN PARALLEL=1 FLOW=sol ./run_acir_tests.sh assert_statement double_verify_proof double_verify_nested_proof diff --git a/acir_tests/README.md b/acir_tests/README.md index 4d644c672..af6bc622d 100644 --- a/acir_tests/README.md +++ b/acir_tests/README.md @@ -49,14 +49,14 @@ $ FLOW=all_cmds ./run_acir_tests.sh 1_mul This means we have to generate the proof specific inputs using our backend and pass it back into `double_verify_proof` to regenerate the accurate witness. The following is a temporary solution to manually regenerate the inputs for `double_verify_proof` on a specific Noir branch. -First find `acir_tests/gen_inner_proof_inputs.sh`. Change the $BRANCH env var to your working branch and $PROOF_NAME to your first input you want to recursively verify. The script is going to generate the proof system specific verification key output and proof for the `assert_statement_recursive` test. +First find `acir_tests/gen_inner_proof_inputs.sh`. Change the $BRANCH env var to your working branch and $PROOF_NAME to your first input you want to recursively verify. The script is going to generate the proof system specific verification key output and proof for the `assert_statement` test. To run: ``` ./gen_inner_proof_inputs.sh ``` -To generate a new input you can run the script again. To generate a new file under `assert_statement_recursive/proofs/` be sure to change the $PROOF_NAME inside of the script. +To generate a new input you can run the script again. To generate a new file under `assert_statement/proofs/` be sure to change the $PROOF_NAME inside of the script. You can then copy these inputs over to your working branch in Noir and regenerate the witness for `double_verify_proof`. You can then change the branch in `run_acir_tests.sh` to this Noir working branch as well and `double_verify_proof` should pass. -The same process should then be repeated, but now `double_verify_proof_recursive` will be the circuit for which we will be generating recursive inputs using `gen_inner_proof_inputs.sh`. The recursive artifacts should then supplied as inputs to `double_verify_nested_proof`. \ No newline at end of file +The same process should then be repeated, but now `double_verify_proof_recursive` will be the circuit for which we will be generating recursive inputs using `gen_inner_proof_inputs.sh`. The recursive artifacts should then supplied as inputs to `double_verify_nested_proof`. \ No newline at end of file diff --git a/acir_tests/flows/prove_and_verify.sh b/acir_tests/flows/prove_and_verify.sh index 4d9055389..49dc9a860 100755 --- a/acir_tests/flows/prove_and_verify.sh +++ b/acir_tests/flows/prove_and_verify.sh @@ -2,7 +2,11 @@ set -eu VFLAG=${VERBOSE:+-v} +FLAGS="-c $CRS_PATH $VFLAG" +if [ "${RECURSIVE}" = "true" ]; then + FLAGS="$FLAGS --recursive" +fi # This is the fastest flow, because it only generates pk/vk once, gate count once, etc. # It may not catch all class of bugs. -$BIN prove_and_verify $VFLAG -c $CRS_PATH -b ./target/program.json +$BIN prove_and_verify $FLAGS -b ./target/program.json diff --git a/acir_tests/flows/prove_and_verify_ultra_honk.sh b/acir_tests/flows/prove_and_verify_ultra_honk.sh index 16f2fd7f3..be9ad0e12 100755 --- a/acir_tests/flows/prove_and_verify_ultra_honk.sh +++ b/acir_tests/flows/prove_and_verify_ultra_honk.sh @@ -2,5 +2,9 @@ set -eu VFLAG=${VERBOSE:+-v} +FLAGS="-c $CRS_PATH $VFLAG" +if [ "${RECURSIVE}" = "true" ]; then + FLAGS="$FLAGS --recursive" +fi -$BIN prove_and_verify_ultra_honk $VFLAG -c $CRS_PATH -b ./target/program.json +$BIN prove_and_verify_ultra_honk $FLAGS -b ./target/program.json diff --git a/acir_tests/flows/prove_and_verify_ultra_honk_program.sh b/acir_tests/flows/prove_and_verify_ultra_honk_program.sh index 65a6e4002..350bc5630 100755 --- a/acir_tests/flows/prove_and_verify_ultra_honk_program.sh +++ b/acir_tests/flows/prove_and_verify_ultra_honk_program.sh @@ -2,5 +2,9 @@ set -eu VFLAG=${VERBOSE:+-v} +FLAGS="-c $CRS_PATH $VFLAG" +if [ "${RECURSIVE}" = "true" ]; then + FLAGS="$FLAGS --recursive" +fi -$BIN prove_and_verify_ultra_honk_program $VFLAG -c $CRS_PATH -b ./target/program.json +$BIN prove_and_verify_ultra_honk_program $FLAGS -b ./target/program.json diff --git a/acir_tests/flows/prove_then_verify.sh b/acir_tests/flows/prove_then_verify.sh index 08d8ea210..d12a12de2 100755 --- a/acir_tests/flows/prove_then_verify.sh +++ b/acir_tests/flows/prove_then_verify.sh @@ -4,6 +4,9 @@ set -eu VFLAG=${VERBOSE:+-v} BFLAG="-b ./target/program.json" FLAGS="-c $CRS_PATH $VFLAG" +if [ "${RECURSIVE}" = "true" ]; then + FLAGS="$FLAGS --recursive" +fi # Test we can perform the proof/verify flow. # This ensures we test independent pk construction through real/garbage witness data paths. diff --git a/acir_tests/flows/prove_then_verify_ultra_honk.sh b/acir_tests/flows/prove_then_verify_ultra_honk.sh index ac3bb9bc9..aaec7e540 100755 --- a/acir_tests/flows/prove_then_verify_ultra_honk.sh +++ b/acir_tests/flows/prove_then_verify_ultra_honk.sh @@ -4,6 +4,9 @@ set -eux VFLAG=${VERBOSE:+-v} BFLAG="-b ./target/program.json" FLAGS="-c $CRS_PATH $VFLAG" +if [ "${RECURSIVE}" = "true" ]; then + FLAGS="$FLAGS --recursive" +fi # Test we can perform the proof/verify flow. # This ensures we test independent pk construction through real/garbage witness data paths. diff --git a/acir_tests/gen_inner_proof_inputs.sh b/acir_tests/gen_inner_proof_inputs.sh index 38392d84d..9b68f0a19 100755 --- a/acir_tests/gen_inner_proof_inputs.sh +++ b/acir_tests/gen_inner_proof_inputs.sh @@ -20,7 +20,7 @@ export BRANCH ./clone_test_vectors.sh -cd acir_tests/assert_statement_recursive +cd acir_tests/assert_statement PROOF_DIR=$PWD/proofs PROOF_PATH=$PROOF_DIR/$PROOF_NAME @@ -28,7 +28,7 @@ VFLAG=${VERBOSE:+-v} RFLAG=${RECURSIVE:+-r} echo "Write VK to file for assert_statement..." -$BIN write_vk $VFLAG -c $CRS_PATH -o ./target/vk +$BIN write_vk $VFLAG -c $CRS_PATH -o ./target/vk --recursive echo "Write VK as fields for recursion..." $BIN vk_as_fields $VFLAG -c $CRS_PATH -k ./target/vk -o ./target/vk_fields.json @@ -36,7 +36,7 @@ $BIN vk_as_fields $VFLAG -c $CRS_PATH -k ./target/vk -o ./target/vk_fields.json echo "Generate proof to file..." [ -d "$PROOF_DIR" ] || mkdir $PWD/proofs [ -e "$PROOF_PATH" ] || touch $PROOF_PATH -$BIN prove $VFLAG -c $CRS_PATH -b ./target/program.json -o "./proofs/$PROOF_NAME" +$BIN prove $VFLAG -c $CRS_PATH -b ./target/program.json -o "./proofs/$PROOF_NAME" --recursive echo "Write proof as fields for recursion..." $BIN proof_as_fields $VFLAG -c $CRS_PATH -p "./proofs/$PROOF_NAME" -k ./target/vk -o "./proofs/${PROOF_NAME}_fields.json" diff --git a/acir_tests/regenerate_verify_honk_proof_inputs.sh b/acir_tests/regenerate_verify_honk_proof_inputs.sh index ba8112465..e19abaabe 100755 --- a/acir_tests/regenerate_verify_honk_proof_inputs.sh +++ b/acir_tests/regenerate_verify_honk_proof_inputs.sh @@ -17,7 +17,7 @@ fi export BRANCH # the program for which a proof will be recursively verified -PROGRAM=assert_statement_recursive +PROGRAM=assert_statement # the program containing the recursive verifier RECURSIVE_PROGRAM=verify_honk_proof diff --git a/acir_tests/run_acir_tests.sh b/acir_tests/run_acir_tests.sh index 1b8d413af..b31b8708e 100755 --- a/acir_tests/run_acir_tests.sh +++ b/acir_tests/run_acir_tests.sh @@ -2,6 +2,7 @@ # Env var overrides: # BIN: to specify a different binary to test with (e.g. bb.js or bb.js-dev). # VERBOSE: to enable logging for each test. +# RECURSIVE: to enable --recursive for each test. set -eu # Catch when running in parallel @@ -19,6 +20,7 @@ VERBOSE=${VERBOSE:-} TEST_NAMES=("$@") # We get little performance benefit over 16 cores (in fact it can be worse). HARDWARE_CONCURRENCY=${HARDWARE_CONCURRENCY:-16} +RECURSIVE=${RECURSIVE:-false} FLOW_SCRIPT=$(realpath ./flows/${FLOW}.sh) @@ -28,7 +30,7 @@ else BIN=$(realpath $(which $BIN)) fi -export BIN CRS_PATH VERBOSE BRANCH +export BIN CRS_PATH VERBOSE BRANCH RECURSIVE # copy the gzipped acir test data from noir/noir-repo/test_programs to barretenberg/acir_tests ./clone_test_vectors.sh @@ -47,12 +49,12 @@ SKIP_ARRAY+=(regression_5045) # if HONK is false, we should skip verify_honk_proof if [ "$HONK" = false ]; then # Don't run programs with Honk recursive verifier - SKIP_ARRAY+=(verify_honk_proof double_verify_honk_proof double_verify_honk_proof_recursive) + SKIP_ARRAY+=(verify_honk_proof double_verify_honk_proof) fi if [ "$HONK" = true ]; then # Don't run programs with Plonk recursive verifier(s) - SKIP_ARRAY+=(single_verify_proof double_verify_proof double_verify_proof_recursive double_verify_nested_proof) + SKIP_ARRAY+=(single_verify_proof double_verify_proof double_verify_nested_proof) fi function test() { diff --git a/cpp/src/barretenberg/bb/main.cpp b/cpp/src/barretenberg/bb/main.cpp index 052ea3774..3cfad6d4e 100644 --- a/cpp/src/barretenberg/bb/main.cpp +++ b/cpp/src/barretenberg/bb/main.cpp @@ -148,13 +148,13 @@ std::string honk_vk_to_json(std::vector& data) * @return true if the proof is valid * @return false if the proof is invalid */ -bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessPath) +bool proveAndVerify(const std::string& bytecodePath, const bool recursive, const std::string& witnessPath) { auto constraint_system = get_constraint_system(bytecodePath, /*honk_recursion=*/false); auto witness = get_witness(witnessPath); acir_proofs::AcirComposer acir_composer{ 0, verbose_logging }; - acir_composer.create_finalized_circuit(constraint_system, witness); + acir_composer.create_finalized_circuit(constraint_system, recursive, witness); init_bn254_crs(acir_composer.get_finalized_dyadic_circuit_size()); Timer pk_timer; @@ -179,7 +179,9 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP } template -bool proveAndVerifyHonkAcirFormat(acir_format::AcirFormat constraint_system, acir_format::WitnessVector witness) +bool proveAndVerifyHonkAcirFormat(acir_format::AcirFormat constraint_system, + const bool recursive, + acir_format::WitnessVector witness) { using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; @@ -191,7 +193,7 @@ bool proveAndVerifyHonkAcirFormat(acir_format::AcirFormat constraint_system, aci honk_recursion = true; } // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit(constraint_system, 0, witness, honk_recursion); + auto builder = acir_format::create_circuit(constraint_system, recursive, 0, witness, honk_recursion); // Construct Honk proof Prover prover{ builder }; @@ -213,7 +215,8 @@ bool proveAndVerifyHonkAcirFormat(acir_format::AcirFormat constraint_system, aci * @param bytecodePath Path to serialized acir circuit data * @param witnessPath Path to serialized acir witness data */ -template bool proveAndVerifyHonk(const std::string& bytecodePath, const std::string& witnessPath) +template +bool proveAndVerifyHonk(const std::string& bytecodePath, const bool recursive, const std::string& witnessPath) { bool honk_recursion = false; if constexpr (IsAnyOf) { @@ -223,7 +226,7 @@ template bool proveAndVerifyHonk(const std::string& bytec auto constraint_system = get_constraint_system(bytecodePath, honk_recursion); auto witness = get_witness(witnessPath); - return proveAndVerifyHonkAcirFormat(constraint_system, witness); + return proveAndVerifyHonkAcirFormat(constraint_system, recursive, witness); } /** @@ -235,18 +238,16 @@ template bool proveAndVerifyHonk(const std::string& bytec * follow. */ template -bool proveAndVerifyHonkProgram(const std::string& bytecodePath, const std::string& witnessPath) +bool proveAndVerifyHonkProgram(const std::string& bytecodePath, const bool recursive, const std::string& witnessPath) { bool honk_recursion = false; if constexpr (IsAnyOf) { honk_recursion = true; } auto program_stack = acir_format::get_acir_program_stack(bytecodePath, witnessPath, honk_recursion); - while (!program_stack.empty()) { auto stack_item = program_stack.back(); - - if (!proveAndVerifyHonkAcirFormat(stack_item.constraints, stack_item.witness)) { + if (!proveAndVerifyHonkAcirFormat(stack_item.constraints, recursive, stack_item.witness)) { return false; } program_stack.pop_back(); @@ -366,7 +367,8 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath, bool is_kernel = false; for (Program& program : folding_stack) { // Construct a bberg circuit from the acir representation then accumulate it into the IVC - auto circuit = create_circuit(program.constraints, 0, program.witness, false, ivc.goblin.op_queue); + auto circuit = + create_circuit(program.constraints, true, 0, program.witness, false, ivc.goblin.op_queue); // Set the internal is_kernel flag based on the local mechanism only if it has not already been set to true if (!circuit.databus_propagation_data.is_kernel) { @@ -463,8 +465,12 @@ bool foldAndVerifyProgram(const std::string& bytecodePath, const std::string& wi auto stack_item = program_stack.back(); // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit( - stack_item.constraints, 0, stack_item.witness, /*honk_recursion=*/false, ivc.goblin.op_queue); + auto builder = acir_format::create_circuit(stack_item.constraints, + /*recursive=*/true, + 0, + stack_item.witness, + /*honk_recursion=*/false, + ivc.goblin.op_queue); // Set the internal is_kernel flag to trigger automatic appending of kernel logic if true builder.databus_propagation_data.is_kernel = is_kernel; @@ -514,7 +520,7 @@ void client_ivc_prove_output_all(const std::string& bytecodePath, // Construct a bberg circuit from the acir representation auto circuit = acir_format::create_circuit( - stack_item.constraints, 0, stack_item.witness, false, ivc.goblin.op_queue); + stack_item.constraints, true, 0, stack_item.witness, false, ivc.goblin.op_queue); circuit.databus_propagation_data.is_kernel = is_kernel; is_kernel = !is_kernel; // toggle on/off so every second circuit is intepreted as a kernel @@ -652,16 +658,19 @@ void prove_tube(const std::string& output_path) * * @param bytecodePath Path to the file containing the serialized circuit * @param witnessPath Path to the file containing the serialized witness - * @param recursive Whether to use recursive proof generation of non-recursive * @param outputPath Path to write the proof to + * @param recursive Whether to use recursive proof generation of non-recursive */ -void prove(const std::string& bytecodePath, const std::string& witnessPath, const std::string& outputPath) +void prove(const std::string& bytecodePath, + const std::string& witnessPath, + const std::string& outputPath, + const bool recursive) { auto constraint_system = get_constraint_system(bytecodePath, /*honk_recursion=*/false); auto witness = get_witness(witnessPath); acir_proofs::AcirComposer acir_composer{ 0, verbose_logging }; - acir_composer.create_finalized_circuit(constraint_system, witness); + acir_composer.create_finalized_circuit(constraint_system, recursive, witness); init_bn254_crs(acir_composer.get_finalized_dyadic_circuit_size()); acir_composer.init_proving_key(); auto proof = acir_composer.create_proof(); @@ -685,7 +694,8 @@ void prove(const std::string& bytecodePath, const std::string& witnessPath, cons * * @param bytecodePath Path to the file containing the serialized circuit */ -template void gateCount(const std::string& bytecodePath, bool honk_recursion) +template +void gateCount(const std::string& bytecodePath, bool recursive, bool honk_recursion) { // All circuit reports will be built into the string below std::string functions_string = "{\"functions\": [\n "; @@ -693,7 +703,7 @@ template void gateCount(const std::stri size_t i = 0; for (auto constraint_system : constraint_systems) { auto builder = acir_format::create_circuit( - constraint_system, 0, {}, honk_recursion, std::make_shared(), true); + constraint_system, recursive, 0, {}, honk_recursion, std::make_shared(), true); builder.finalize_circuit(/*ensure_nonzero=*/true); size_t circuit_size = builder.num_gates; vinfo("Calculated circuit size in gateCount: ", circuit_size); @@ -767,12 +777,13 @@ bool verify(const std::string& proof_path, const std::string& vk_path) * * @param bytecodePath Path to the file containing the serialized circuit * @param outputPath Path to write the verification key to + * @param recursive Whether to create a SNARK friendly circuit and key */ -void write_vk(const std::string& bytecodePath, const std::string& outputPath) +void write_vk(const std::string& bytecodePath, const std::string& outputPath, const bool recursive) { auto constraint_system = get_constraint_system(bytecodePath, false); acir_proofs::AcirComposer acir_composer{ 0, verbose_logging }; - acir_composer.create_finalized_circuit(constraint_system); + acir_composer.create_finalized_circuit(constraint_system, recursive); acir_composer.finalize_circuit(); init_bn254_crs(acir_composer.get_finalized_dyadic_circuit_size()); acir_composer.init_proving_key(); @@ -787,11 +798,11 @@ void write_vk(const std::string& bytecodePath, const std::string& outputPath) } } -void write_pk(const std::string& bytecodePath, const std::string& outputPath) +void write_pk(const std::string& bytecodePath, const std::string& outputPath, const bool recursive) { auto constraint_system = get_constraint_system(bytecodePath, /*honk_recursion=*/false); acir_proofs::AcirComposer acir_composer{ 0, verbose_logging }; - acir_composer.create_finalized_circuit(constraint_system); + acir_composer.create_finalized_circuit(constraint_system, recursive); acir_composer.finalize_circuit(); init_bn254_crs(acir_composer.get_finalized_dyadic_circuit_size()); auto pk = acir_composer.init_proving_key(); @@ -1069,7 +1080,9 @@ bool avm_verify(const std::filesystem::path& proof_path, const std::filesystem:: * @return UltraProver_ */ template -UltraProver_ compute_valid_prover(const std::string& bytecodePath, const std::string& witnessPath) +UltraProver_ compute_valid_prover(const std::string& bytecodePath, + const std::string& witnessPath, + const bool recursive) { using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; @@ -1084,7 +1097,7 @@ UltraProver_ compute_valid_prover(const std::string& bytecodePath, const witness = get_witness(witnessPath); } - auto builder = acir_format::create_circuit(constraint_system, 0, witness, honk_recursion); + auto builder = acir_format::create_circuit(constraint_system, recursive, 0, witness, honk_recursion); auto prover = Prover{ builder }; init_bn254_crs(prover.proving_key->proving_key.circuit_size); return std::move(prover); @@ -1102,13 +1115,16 @@ UltraProver_ compute_valid_prover(const std::string& bytecodePath, const * @param outputPath Path to write the proof to */ template -void prove_honk(const std::string& bytecodePath, const std::string& witnessPath, const std::string& outputPath) +void prove_honk(const std::string& bytecodePath, + const std::string& witnessPath, + const std::string& outputPath, + const bool recursive) { // using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; // Construct Honk proof - Prover prover = compute_valid_prover(bytecodePath, witnessPath); + Prover prover = compute_valid_prover(bytecodePath, witnessPath, recursive); auto proof = prover.construct_proof(); if (outputPath == "-") { writeRawBytesToStdout(to_buffer(proof)); @@ -1163,13 +1179,14 @@ template bool verify_honk(const std::string& proof_path, * @param bytecodePath Path to the file containing the serialized circuit * @param outputPath Path to write the verification key to */ -template void write_vk_honk(const std::string& bytecodePath, const std::string& outputPath) +template +void write_vk_honk(const std::string& bytecodePath, const std::string& outputPath, const bool recursive) { using Prover = UltraProver_; using VerificationKey = Flavor::VerificationKey; // Construct a verification key from a partial form of the proving key which only has precomputed entities - Prover prover = compute_valid_prover(bytecodePath, ""); + Prover prover = compute_valid_prover(bytecodePath, "", recursive); VerificationKey vk(prover.proving_key->proving_key); auto serialized_vk = to_buffer(vk); @@ -1193,7 +1210,8 @@ template void write_vk_honk(const std::string& bytecodePa template void write_recursion_inputs_honk(const std::string& bytecodePath, const std::string& witnessPath, - const std::string& outputPath) + const std::string& outputPath, + const bool recursive) { using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; @@ -1201,9 +1219,9 @@ void write_recursion_inputs_honk(const std::string& bytecodePath, using FF = Flavor::FF; bool honk_recursion = true; - auto constraints = get_constraint_system(bytecodePath, /*honk_recursion=*/true); + auto constraints = get_constraint_system(bytecodePath, honk_recursion); auto witness = get_witness(witnessPath); - auto builder = acir_format::create_circuit(constraints, 0, witness, honk_recursion); + auto builder = acir_format::create_circuit(constraints, recursive, 0, witness, honk_recursion); // Construct Honk proof and verification key Prover prover{ builder }; @@ -1282,14 +1300,18 @@ template void vk_as_fields_honk(const std::string& vk_pat * @param bytecodePath Path to the file containing the serialized circuit * @param witnessPath Path to the file containing the serialized witness * @param outputPath Directory into which we write the proof and verification key data + * @param recursive Whether to a build SNARK friendly proof */ -void prove_output_all(const std::string& bytecodePath, const std::string& witnessPath, const std::string& outputPath) +void prove_output_all(const std::string& bytecodePath, + const std::string& witnessPath, + const std::string& outputPath, + const bool recursive) { auto constraint_system = get_constraint_system(bytecodePath, /*honk_recursion=*/false); auto witness = get_witness(witnessPath); acir_proofs::AcirComposer acir_composer{ 0, verbose_logging }; - acir_composer.create_finalized_circuit(constraint_system, witness); + acir_composer.create_finalized_circuit(constraint_system, recursive, witness); acir_composer.finalize_circuit(); init_bn254_crs(acir_composer.get_finalized_dyadic_circuit_size()); acir_composer.init_proving_key(); @@ -1335,11 +1357,13 @@ void prove_output_all(const std::string& bytecodePath, const std::string& witnes * @param bytecodePath Path to the file containing the serialized circuit * @param witnessPath Path to the file containing the serialized witness * @param outputPath Directory into which we write the proof and verification key data + * @param recursive Whether to build a SNARK friendly proof */ template void prove_honk_output_all(const std::string& bytecodePath, const std::string& witnessPath, - const std::string& outputPath) + const std::string& outputPath, + const bool recursive) { using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; @@ -1353,7 +1377,7 @@ void prove_honk_output_all(const std::string& bytecodePath, auto constraint_system = get_constraint_system(bytecodePath, honk_recursion); auto witness = get_witness(witnessPath); - auto builder = acir_format::create_circuit(constraint_system, 0, witness, honk_recursion); + auto builder = acir_format::create_circuit(constraint_system, recursive, 0, witness, honk_recursion); // Construct Honk proof Prover prover{ builder }; @@ -1421,6 +1445,7 @@ int main(int argc, char* argv[]) std::string vk_path = get_option(args, "-k", "./target/vk"); std::string pk_path = get_option(args, "-r", "./target/pk"); bool honk_recursion = flag_present(args, "-h"); + bool recursive = flag_present(args, "--recursive"); // Not every flavor handles it. CRS_PATH = get_option(args, "-c", CRS_PATH); // Skip CRS initialization for any command which doesn't require the CRS. @@ -1429,21 +1454,20 @@ int main(int argc, char* argv[]) return 0; } if (command == "prove_and_verify") { - return proveAndVerify(bytecode_path, witness_path) ? 0 : 1; + return proveAndVerify(bytecode_path, recursive, witness_path) ? 0 : 1; } if (command == "prove_and_verify_ultra_honk") { - return proveAndVerifyHonk(bytecode_path, witness_path) ? 0 : 1; + return proveAndVerifyHonk(bytecode_path, recursive, witness_path) ? 0 : 1; } if (command == "prove_and_verify_mega_honk") { - return proveAndVerifyHonk(bytecode_path, witness_path) ? 0 : 1; + return proveAndVerifyHonk(bytecode_path, recursive, witness_path) ? 0 : 1; } if (command == "prove_and_verify_ultra_honk_program") { - return proveAndVerifyHonkProgram(bytecode_path, witness_path) ? 0 : 1; + return proveAndVerifyHonkProgram(bytecode_path, recursive, witness_path) ? 0 : 1; } if (command == "prove_and_verify_mega_honk_program") { - return proveAndVerifyHonkProgram(bytecode_path, witness_path) ? 0 : 1; + return proveAndVerifyHonkProgram(bytecode_path, recursive, witness_path) ? 0 : 1; } - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1050) we need a verify_client_ivc bb cli command // TODO(#7371): remove this if (command == "client_ivc_prove_output_all_msgpack") { std::filesystem::path output_dir = get_option(args, "-o", "./target"); @@ -1469,16 +1493,16 @@ int main(int argc, char* argv[]) if (command == "prove") { std::string output_path = get_option(args, "-o", "./proofs/proof"); - prove(bytecode_path, witness_path, output_path); + prove(bytecode_path, witness_path, output_path, recursive); } else if (command == "prove_output_all") { std::string output_path = get_option(args, "-o", "./proofs"); - prove_output_all(bytecode_path, witness_path, output_path); + prove_output_all(bytecode_path, witness_path, output_path, recursive); } else if (command == "prove_ultra_honk_output_all") { std::string output_path = get_option(args, "-o", "./proofs"); - prove_honk_output_all(bytecode_path, witness_path, output_path); + prove_honk_output_all(bytecode_path, witness_path, output_path, recursive); } else if (command == "prove_mega_honk_output_all") { std::string output_path = get_option(args, "-o", "./proofs"); - prove_honk_output_all(bytecode_path, witness_path, output_path); + prove_honk_output_all(bytecode_path, witness_path, output_path, recursive); } else if (command == "client_ivc_prove_output_all") { std::string output_path = get_option(args, "-o", "./target"); client_ivc_prove_output_all(bytecode_path, witness_path, output_path); @@ -1491,9 +1515,9 @@ int main(int argc, char* argv[]) auto tube_vk_path = output_path + "/vk"; return verify_honk(tube_proof_path, tube_vk_path) ? 0 : 1; } else if (command == "gates") { - gateCount(bytecode_path, honk_recursion); + gateCount(bytecode_path, recursive, honk_recursion); } else if (command == "gates_mega_honk") { - gateCount(bytecode_path, honk_recursion); + gateCount(bytecode_path, recursive, honk_recursion); } else if (command == "verify") { return verify(proof_path, vk_path) ? 0 : 1; } else if (command == "contract") { @@ -1504,10 +1528,10 @@ int main(int argc, char* argv[]) contract_honk(output_path, vk_path); } else if (command == "write_vk") { std::string output_path = get_option(args, "-o", "./target/vk"); - write_vk(bytecode_path, output_path); + write_vk(bytecode_path, output_path, recursive); } else if (command == "write_pk") { std::string output_path = get_option(args, "-o", "./target/pk"); - write_pk(bytecode_path, output_path); + write_pk(bytecode_path, output_path, recursive); } else if (command == "proof_as_fields") { std::string output_path = get_option(args, "-o", proof_path + "_fields.json"); proof_as_fields(proof_path, vk_path, output_path); @@ -1516,7 +1540,7 @@ int main(int argc, char* argv[]) vk_as_fields(vk_path, output_path); } else if (command == "write_recursion_inputs_honk") { std::string output_path = get_option(args, "-o", "./target"); - write_recursion_inputs_honk(bytecode_path, witness_path, output_path); + write_recursion_inputs_honk(bytecode_path, witness_path, output_path, recursive); #ifndef DISABLE_AZTEC_VM } else if (command == "avm_prove") { std::filesystem::path avm_calldata_path = get_option(args, "--avm-calldata", "./target/avm_calldata.bin"); @@ -1533,31 +1557,31 @@ int main(int argc, char* argv[]) #endif } else if (command == "prove_ultra_honk") { std::string output_path = get_option(args, "-o", "./proofs/proof"); - prove_honk(bytecode_path, witness_path, output_path); + prove_honk(bytecode_path, witness_path, output_path, recursive); } else if (command == "prove_ultra_keccak_honk") { std::string output_path = get_option(args, "-o", "./proofs/proof"); - prove_honk(bytecode_path, witness_path, output_path); + prove_honk(bytecode_path, witness_path, output_path, recursive); } else if (command == "prove_ultra_keccak_honk_output_all") { std::string output_path = get_option(args, "-o", "./proofs/proof"); - prove_honk_output_all(bytecode_path, witness_path, output_path); + prove_honk_output_all(bytecode_path, witness_path, output_path, recursive); } else if (command == "verify_ultra_honk") { return verify_honk(proof_path, vk_path) ? 0 : 1; } else if (command == "verify_ultra_keccak_honk") { return verify_honk(proof_path, vk_path) ? 0 : 1; } else if (command == "write_vk_ultra_honk") { std::string output_path = get_option(args, "-o", "./target/vk"); - write_vk_honk(bytecode_path, output_path); + write_vk_honk(bytecode_path, output_path, recursive); } else if (command == "write_vk_ultra_keccak_honk") { std::string output_path = get_option(args, "-o", "./target/vk"); - write_vk_honk(bytecode_path, output_path); + write_vk_honk(bytecode_path, output_path, recursive); } else if (command == "prove_mega_honk") { std::string output_path = get_option(args, "-o", "./proofs/proof"); - prove_honk(bytecode_path, witness_path, output_path); + prove_honk(bytecode_path, witness_path, output_path, recursive); } else if (command == "verify_mega_honk") { return verify_honk(proof_path, vk_path) ? 0 : 1; } else if (command == "write_vk_mega_honk") { std::string output_path = get_option(args, "-o", "./target/vk"); - write_vk_honk(bytecode_path, output_path); + write_vk_honk(bytecode_path, output_path, recursive); } else if (command == "proof_as_fields_honk") { std::string output_path = get_option(args, "-o", proof_path + "_fields.json"); proof_as_fields_honk(proof_path, output_path); diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 7b08678ad..4d5a83a30 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -399,15 +399,14 @@ AggregationObjectIndices process_avm_recursion_constraints(Builder& builder, */ template <> UltraCircuitBuilder create_circuit(AcirFormat& constraint_system, + bool recursive, const size_t size_hint, const WitnessVector& witness, bool honk_recursion, [[maybe_unused]] std::shared_ptr, bool collect_gates_per_opcode) { - Builder builder{ - size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, constraint_system.recursive - }; + Builder builder{ size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, recursive }; bool has_valid_witness_assignments = !witness.empty(); build_constraints( @@ -429,6 +428,7 @@ UltraCircuitBuilder create_circuit(AcirFormat& constraint_system, */ template <> MegaCircuitBuilder create_circuit(AcirFormat& constraint_system, + [[maybe_unused]] bool recursive, [[maybe_unused]] const size_t size_hint, const WitnessVector& witness, bool honk_recursion, @@ -470,6 +470,7 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, // Construct the main kernel circuit logic excluding recursive verifiers auto circuit = create_circuit(constraint_system, + /*recursive=*/false, size_hint, witness, /*honk_recursion=*/false, diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 79a750b2e..dba936225 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -75,7 +75,6 @@ struct AcirFormat { // of another SNARK. For example, a recursive friendly proof may use Blake3Pedersen for // hashing in its transcript, while we still want a prove that uses Keccak for its transcript in order // to be able to verify SNARKs on Ethereum. - bool recursive; uint32_t num_acir_opcodes; @@ -200,6 +199,12 @@ struct AcirProgramStack { template Builder create_circuit(AcirFormat& constraint_system, + // Specifies whether a prover that produces SNARK recursion friendly proofs should be used. + // The proof produced when this flag is true should be friendly for recursive verification inside + // of another SNARK. For example, a recursive friendly proof may use Blake3Pedersen for + // hashing in its transcript, while we still want a prove that uses Keccak for its transcript in + // order to be able to verify SNARKs on Ethereum. + bool recursive, const size_t size_hint = 0, const WitnessVector& witness = {}, bool honk_recursion = false, diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 199bfac3c..d3fb92273 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -39,7 +39,6 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) AcirFormat constraint_system{ .varnum = 4, - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -71,7 +70,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) }; mock_opcode_indices(constraint_system); WitnessVector witness{ 0, 0, 1 }; - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -160,7 +159,6 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) AcirFormat constraint_system{ .varnum = 6, - .recursive = false, .num_acir_opcodes = 7, .public_inputs = { 1 }, .logic_constraints = { logic_constraint }, @@ -196,7 +194,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) WitnessVector witness{ 5, 10, 15, 5, inverse_of_five, 1, }; - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -240,7 +238,6 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) AcirFormat constraint_system{ .varnum = 81, - .recursive = false, .num_acir_opcodes = 76, .public_inputs = {}, .logic_constraints = {}, @@ -302,7 +299,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) witness[i] = message_string[i]; } - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -346,7 +343,6 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) }; AcirFormat constraint_system{ .varnum = 81, - .recursive = false, .num_acir_opcodes = 76, .public_inputs = {}, .logic_constraints = {}, @@ -409,7 +405,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) } // TODO: actually sign a schnorr signature! - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -455,7 +451,6 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) AcirFormat constraint_system{ .varnum = 51, - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -491,7 +486,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 }; - auto builder = create_circuit(constraint_system, /*size_hint=*/0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint=*/0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); @@ -529,7 +524,6 @@ TEST_F(AcirFormatTests, TestCollectsGateCounts) AcirFormat constraint_system{ .varnum = 4, - .recursive = false, .num_acir_opcodes = 2, .public_inputs = {}, .logic_constraints = {}, @@ -561,8 +555,13 @@ TEST_F(AcirFormatTests, TestCollectsGateCounts) }; mock_opcode_indices(constraint_system); WitnessVector witness{ 5, 27, 32 }; - auto builder = - create_circuit(constraint_system, /*size_hint*/ 0, witness, false, std::make_shared(), true); + auto builder = create_circuit(constraint_system, + /*recursive*/ false, + /*size_hint*/ 0, + witness, + false, + std::make_shared(), + true); EXPECT_EQ(constraint_system.gates_per_opcode, std::vector({ 2, 1 })); } @@ -655,7 +654,6 @@ TEST_F(AcirFormatTests, TestBigAdd) size_t num_variables = witness_values.size(); AcirFormat constraint_system{ .varnum = static_cast(num_variables + 1), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -687,7 +685,7 @@ TEST_F(AcirFormatTests, TestBigAdd) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); auto composer = Composer(); auto prover = composer.create_prover(builder); diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp index 4420223e9..3719a9ec1 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp @@ -154,7 +154,8 @@ TEST_P(AcirIntegrationSingleTest, DISABLED_ProveAndVerifyProgram) false); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1013): Assumes Flavor is not UltraHonk // Construct a bberg circuit from the acir representation - Builder builder = acir_format::create_circuit(acir_program.constraints, 0, acir_program.witness); + Builder builder = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); // Construct and verify Honk proof if constexpr (IsPlonkFlavor) { @@ -192,7 +193,6 @@ INSTANTIATE_TEST_SUITE_P(AcirTests, "array_to_slice_constant_length", "assert", "assert_statement", - "assert_statement_recursive", "assign_ex", "bigint", "bit_and", @@ -259,7 +259,6 @@ INSTANTIATE_TEST_SUITE_P(AcirTests, "diamond_deps_0", "double_verify_nested_proof", "double_verify_proof", - "double_verify_proof_recursive", "ecdsa_secp256k1", "ecdsa_secp256r1", "ecdsa_secp256r1_3x", @@ -381,7 +380,8 @@ TEST_P(AcirIntegrationFoldingTest, DISABLED_ProveAndVerifyProgramStack) auto program = program_stack.back(); // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit(program.constraints, 0, program.witness); + auto builder = + acir_format::create_circuit(program.constraints, /*recursive*/ false, 0, program.witness); // Construct and verify Honk proof for the individidual circuit EXPECT_TRUE(prove_and_verify_honk(builder)); @@ -408,8 +408,8 @@ TEST_P(AcirIntegrationFoldingTest, DISABLED_FoldAndVerifyProgramStack) auto program = program_stack.back(); // Construct a bberg circuit from the acir representation - auto circuit = - acir_format::create_circuit(program.constraints, 0, program.witness, false, ivc.goblin.op_queue); + auto circuit = acir_format::create_circuit( + program.constraints, /*recursive*/ false, 0, program.witness, false, ivc.goblin.op_queue); ivc.accumulate(circuit); @@ -440,7 +440,8 @@ TEST_F(AcirIntegrationTest, DISABLED_Databus) acir_format::AcirProgram acir_program = get_program_data_from_test_file(test_name); // Construct a bberg circuit from the acir representation - Builder builder = acir_format::create_circuit(acir_program.constraints, 0, acir_program.witness); + Builder builder = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); // This prints a summary of the types of gates in the circuit builder.blocks.summarize(); @@ -464,7 +465,8 @@ TEST_F(AcirIntegrationTest, DISABLED_DatabusTwoCalldata) acir_format::AcirProgram acir_program = get_program_data_from_test_file(test_name); // Construct a bberg circuit from the acir representation - Builder builder = acir_format::create_circuit(acir_program.constraints, 0, acir_program.witness); + Builder builder = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); // Check that the databus columns in the builder have been populated as expected const auto& calldata = builder.get_calldata(); @@ -518,7 +520,8 @@ TEST_F(AcirIntegrationTest, DISABLED_UpdateAcirCircuit) // Assumes Flavor is not UltraHonk // Construct a bberg circuit from the acir representation - auto circuit = acir_format::create_circuit(acir_program.constraints, 0, acir_program.witness); + auto circuit = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); EXPECT_TRUE(CircuitChecker::check(circuit)); @@ -557,7 +560,8 @@ TEST_F(AcirIntegrationTest, DISABLED_HonkRecursion) /*honk_recursion=*/false); // Construct a bberg circuit from the acir representation - auto circuit = acir_format::create_circuit(acir_program.constraints, 0, acir_program.witness); + auto circuit = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); EXPECT_TRUE(CircuitChecker::check(circuit)); EXPECT_TRUE(prove_and_verify_honk(circuit)); diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp index bf7eb2dd8..2dd6e2df1 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp @@ -800,7 +800,6 @@ AcirFormat circuit_serde_to_acir_format(Program::Circuit const& circuit, bool ho AcirFormat af; // `varnum` is the true number of variables, thus we add one to the index which starts at zero af.varnum = circuit.current_witness_index + 1; - af.recursive = circuit.recursive; af.num_acir_opcodes = static_cast(circuit.opcodes.size()); af.public_inputs = join({ map(circuit.public_parameters.value, [](auto e) { return e.value; }), map(circuit.return_values.value, [](auto e) { return e.value; }) }); diff --git a/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.test.cpp index c4e98e0d8..bb49d13b0 100644 --- a/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/avm_recursion_constraint.test.cpp @@ -117,13 +117,13 @@ class AcirAvmRecursionConstraint : public ::testing::Test { AcirFormat constraint_system; constraint_system.varnum = static_cast(witness.size()); - constraint_system.recursive = false; constraint_system.num_acir_opcodes = static_cast(avm_recursion_constraints.size()); constraint_system.avm_recursion_constraints = avm_recursion_constraints; constraint_system.original_opcode_indices = create_empty_original_opcode_indices(); mock_opcode_indices(constraint_system); - auto outer_circuit = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk_recursion=*/true); + auto outer_circuit = + create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness, /*honk_recursion=*/true); return outer_circuit; } }; diff --git a/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 295b66cdb..fbb07a8bd 100644 --- a/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -172,7 +172,6 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) auto contraints5 = generate_big_int_op_constraint(BigIntOperationType::Div, fr(8), fr(2), witness); AcirFormat constraint_system{ .varnum = static_cast(witness.size() + 1), - .recursive = false, .num_acir_opcodes = 5, .public_inputs = {}, .logic_constraints = {}, @@ -210,7 +209,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) mock_opcode_indices(constraint_system); constraint_system.varnum = static_cast(witness.size() + 1); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -245,7 +244,6 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) AcirFormat constraint_system{ .varnum = 5, - .recursive = false, .num_acir_opcodes = 3, .public_inputs = {}, .logic_constraints = {}, @@ -280,7 +278,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) WitnessVector witness{ 0, 3, 6, 3, 0, }; - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); @@ -302,7 +300,6 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) AcirFormat constraint_system{ .varnum = static_cast(witness.size() + 1), - .recursive = false, .num_acir_opcodes = 5, .public_inputs = {}, .logic_constraints = {}, @@ -343,7 +340,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) constraint_system.varnum = static_cast(witness.size() + 1); mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -364,7 +361,6 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) AcirFormat constraint_system{ .varnum = static_cast(witness.size() + 1), - .recursive = false, .num_acir_opcodes = 5, .public_inputs = {}, .logic_constraints = {}, @@ -405,7 +401,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) constraint_system.varnum = static_cast(witness.size() + 1); mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); @@ -447,7 +443,6 @@ TEST_F(BigIntTests, TestBigIntDIV) AcirFormat constraint_system{ .varnum = 5, - .recursive = false, .num_acir_opcodes = 4, .public_inputs = {}, .logic_constraints = {}, @@ -482,13 +477,13 @@ TEST_F(BigIntTests, TestBigIntDIV) WitnessVector witness{ 0, 6, 3, 2, 0, }; - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); EXPECT_TRUE(CircuitChecker::check(builder)); - auto builder2 = create_circuit(constraint_system, /*size_hint*/ 0, WitnessVector{}); + auto builder2 = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, WitnessVector{}); EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier2 = composer.create_ultra_with_keccak_verifier(builder); EXPECT_EQ(verifier2.verify_proof(proof), true); diff --git a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 8aec43aa6..571172e68 100644 --- a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -140,7 +140,6 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) size_t num_variables = generate_block_constraint(block, witness_values); AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 7, .public_inputs = {}, .logic_constraints = {}, @@ -172,7 +171,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); auto composer = Composer(); auto prover = composer.create_prover(builder); @@ -191,7 +190,6 @@ TEST_F(MegaHonk, Databus) AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -224,7 +222,7 @@ TEST_F(MegaHonk, Databus) mock_opcode_indices(constraint_system); // Construct a bberg circuit from the acir representation - auto circuit = acir_format::create_circuit(constraint_system, 0, witness_values); + auto circuit = acir_format::create_circuit(constraint_system, /*recursive*/ false, 0, witness_values); EXPECT_TRUE(prove_and_verify(circuit)); } @@ -297,7 +295,6 @@ TEST_F(MegaHonk, DatabusReturn) AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 2, .public_inputs = {}, .logic_constraints = {}, @@ -330,7 +327,7 @@ TEST_F(MegaHonk, DatabusReturn) mock_opcode_indices(constraint_system); // Construct a bberg circuit from the acir representation - auto circuit = acir_format::create_circuit(constraint_system, 0, witness_values); + auto circuit = acir_format::create_circuit(constraint_system, /*recursive*/ false, 0, witness_values); EXPECT_TRUE(prove_and_verify(circuit)); } diff --git a/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index 193388efb..8f254c77c 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -62,7 +62,6 @@ TEST_F(EcOperations, TestECOperations) AcirFormat constraint_system{ .varnum = static_cast(num_variables + 1), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -94,7 +93,7 @@ TEST_F(EcOperations, TestECOperations) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); auto composer = Composer(); auto prover = composer.create_prover(builder); @@ -198,7 +197,6 @@ TEST_F(EcOperations, TestECMultiScalarMul) size_t num_variables = witness_values.size(); AcirFormat constraint_system{ .varnum = static_cast(num_variables + 1), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -230,7 +228,7 @@ TEST_F(EcOperations, TestECMultiScalarMul) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); auto composer = Composer(); auto prover = composer.create_prover(builder); diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 041c92512..e6a9245a6 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -94,7 +94,6 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) size_t num_variables = generate_ecdsa_constraint(ecdsa_k1_constraint, witness_values); AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -126,7 +125,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); EXPECT_EQ(builder.get_variable(ecdsa_k1_constraint.result), 1); @@ -148,7 +147,6 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) size_t num_variables = generate_ecdsa_constraint(ecdsa_k1_constraint, witness_values); AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -180,7 +178,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system); + auto builder = create_circuit(constraint_system, /*recursive*/ false); } TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) @@ -197,7 +195,6 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -229,7 +226,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); EXPECT_EQ(builder.get_variable(ecdsa_k1_constraint.result), 0); auto composer = Composer(); diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index b6d29989d..077f51b1b 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -128,7 +128,6 @@ TEST(ECDSASecp256r1, test_hardcoded) AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -165,7 +164,7 @@ TEST(ECDSASecp256r1, test_hardcoded) ecdsa_verify_signature(message, pub_key, signature); EXPECT_EQ(we_ballin, true); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); EXPECT_EQ(builder.get_variable(ecdsa_r1_constraint.result), 1); auto composer = Composer(); @@ -184,7 +183,6 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -216,7 +214,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); EXPECT_EQ(builder.get_variable(ecdsa_r1_constraint.result), 1); auto composer = Composer(); @@ -238,7 +236,6 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -270,7 +267,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system); + auto builder = create_circuit(constraint_system, /*recursive*/ false); } TEST(ECDSASecp256r1, TestECDSAConstraintFail) @@ -288,7 +285,6 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) AcirFormat constraint_system{ .varnum = static_cast(num_variables), - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -320,7 +316,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) }; mock_opcode_indices(constraint_system); - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); EXPECT_EQ(builder.get_variable(ecdsa_r1_constraint.result), 0); auto composer = Composer(); diff --git a/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp index 3914ef1c3..de6005c19 100644 --- a/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp @@ -90,7 +90,6 @@ class AcirHonkRecursionConstraint : public ::testing::Test { AcirFormat constraint_system{ .varnum = 6, - .recursive = true, .num_acir_opcodes = 7, .public_inputs = { 1, 2 }, .logic_constraints = { logic_constraint }, @@ -126,7 +125,8 @@ class AcirHonkRecursionConstraint : public ::testing::Test { WitnessVector witness{ 5, 10, 15, 5, inverse_of_five, 1, }; - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk recursion*/ true); + auto builder = + create_circuit(constraint_system, /*recursive*/ true, /*size_hint*/ 0, witness, /*honk recursion*/ true); return builder; } @@ -170,13 +170,13 @@ class AcirHonkRecursionConstraint : public ::testing::Test { AcirFormat constraint_system{}; constraint_system.varnum = static_cast(witness.size()); - constraint_system.recursive = true; constraint_system.num_acir_opcodes = static_cast(honk_recursion_constraints.size()); constraint_system.honk_recursion_constraints = honk_recursion_constraints; constraint_system.original_opcode_indices = create_empty_original_opcode_indices(); mock_opcode_indices(constraint_system); - auto outer_circuit = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk recursion*/ true); + auto outer_circuit = + create_circuit(constraint_system, /*recursive*/ true, /*size_hint*/ 0, witness, /*honk recursion*/ true); return outer_circuit; } diff --git a/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index a77b017fd..11339b3de 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -136,7 +136,6 @@ class IvcRecursionConstraintTest : public ::testing::Test { // Construct a constraint system containing the business logic and ivc recursion constraints program.constraints.varnum = static_cast(program.witness.size()); - program.constraints.recursive = false; program.constraints.num_acir_opcodes = static_cast(ivc_recursion_constraints.size()); program.constraints.poly_triple_constraints = { pub_input_constraint }; program.constraints.ivc_recursion_constraints = ivc_recursion_constraints; diff --git a/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.test.cpp b/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.test.cpp index bc8dd7d8c..fa8e711d0 100644 --- a/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.test.cpp @@ -62,7 +62,6 @@ TEST_F(MSMTests, TestMSM) AcirFormat constraint_system{ .varnum = 9, - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -101,12 +100,12 @@ TEST_F(MSMTests, TestMSM) fr(0), }; - auto builder = create_circuit(constraint_system, /*size_hint=*/0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint=*/0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); - auto builder2 = create_circuit(constraint_system, /*size_hint=*/0, {}); + auto builder2 = create_circuit(constraint_system, /*recursive*/ false, /*size_hint=*/0, {}); auto composer2 = Composer(); auto verifier = composer2.create_ultra_with_keccak_verifier(builder2); diff --git a/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp index 9c07431ab..6cb0592d9 100644 --- a/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp @@ -42,7 +42,6 @@ TEST_F(Poseidon2Tests, TestPoseidon2Permutation) AcirFormat constraint_system{ .varnum = 9, - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -86,7 +85,7 @@ TEST_F(Poseidon2Tests, TestPoseidon2Permutation) fr(std::string("0x2e11c5cff2a22c64d01304b778d78f6998eff1ab73163a35603f54794c30847a")), }; - auto builder = create_circuit(constraint_system, /*size_hint=*/0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint=*/0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); diff --git a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index 301bd9150..ddaf4e6ac 100644 --- a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -87,7 +87,6 @@ Builder create_inner_circuit() AcirFormat constraint_system{ .varnum = 6, - .recursive = true, .num_acir_opcodes = 7, .public_inputs = { 1, 2 }, .logic_constraints = { logic_constraint }, @@ -123,7 +122,7 @@ Builder create_inner_circuit() WitnessVector witness{ 5, 10, 15, 5, inverse_of_five, 1, }; - auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ true, /*size_hint*/ 0, witness); return builder; } @@ -248,7 +247,6 @@ Builder create_outer_circuit(std::vector& inner_circuits) AcirFormat constraint_system{ .varnum = static_cast(witness.size()), - .recursive = false, .num_acir_opcodes = static_cast(recursion_constraints.size()), .public_inputs = {}, .logic_constraints = {}, @@ -280,7 +278,7 @@ Builder create_outer_circuit(std::vector& inner_circuits) }; mock_opcode_indices(constraint_system); - auto outer_circuit = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto outer_circuit = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness); return outer_circuit; } diff --git a/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 7fd958cc6..d02312f3d 100644 --- a/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -1365,7 +1365,6 @@ struct Circuit { Program::PublicInputs public_parameters; Program::PublicInputs return_values; std::vector> assert_messages; - bool recursive; friend bool operator==(const Circuit&, const Circuit&); std::vector bincodeSerialize() const; @@ -6724,9 +6723,6 @@ inline bool operator==(const Circuit& lhs, const Circuit& rhs) if (!(lhs.assert_messages == rhs.assert_messages)) { return false; } - if (!(lhs.recursive == rhs.recursive)) { - return false; - } return true; } @@ -6761,7 +6757,6 @@ void serde::Serializable::serialize(const Program::Circuit& ob serde::Serializable::serialize(obj.public_parameters, serializer); serde::Serializable::serialize(obj.return_values, serializer); serde::Serializable::serialize(obj.assert_messages, serializer); - serde::Serializable::serialize(obj.recursive, serializer); serializer.decrease_container_depth(); } @@ -6778,7 +6773,6 @@ Program::Circuit serde::Deserializable::deserialize(Deserializ obj.public_parameters = serde::Deserializable::deserialize(deserializer); obj.return_values = serde::Deserializable::deserialize(deserializer); obj.assert_messages = serde::Deserializable::deserialize(deserializer); - obj.recursive = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } diff --git a/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp index b057ee174..f59dfb8b9 100644 --- a/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp @@ -37,7 +37,6 @@ TEST_F(Sha256Tests, TestSha256Compression) AcirFormat constraint_system{ .varnum = 34, - .recursive = false, .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, @@ -103,7 +102,7 @@ TEST_F(Sha256Tests, TestSha256Compression) 557795688, static_cast(3481642555) }; - auto builder = create_circuit(constraint_system, /*size_hint=*/0, witness); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint=*/0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index 341d06d35..fd1495414 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -30,12 +30,19 @@ AcirComposer::AcirComposer(size_t size_hint, bool verbose) */ template void AcirComposer::create_finalized_circuit(acir_format::AcirFormat& constraint_system, + bool recursive, WitnessVector const& witness, bool collect_gates_per_opcode) { vinfo("building circuit..."); - builder_ = acir_format::create_circuit( - constraint_system, size_hint_, witness, false, std::make_shared(), collect_gates_per_opcode); + vinfo("should be recursive friendly: ", recursive); + builder_ = acir_format::create_circuit(constraint_system, + recursive, + size_hint_, + witness, + false, + std::make_shared(), + collect_gates_per_opcode); finalize_circuit(); vinfo("gates: ", builder_.get_estimated_total_circuit_size()); vinfo("circuit is recursive friendly: ", builder_.is_recursive_circuit); @@ -60,9 +67,11 @@ std::vector AcirComposer::create_proof() vinfo("creating proof..."); std::vector proof; if (builder_.is_recursive_circuit) { + vinfo("creating recursive prover..."); auto prover = composer.create_prover(builder_); proof = prover.construct_proof().proof_data; } else { + vinfo("creating ultra with keccak prover..."); auto prover = composer.create_ultra_with_keccak_prover(builder_); proof = prover.construct_proof().proof_data; } @@ -149,6 +158,7 @@ std::vector AcirComposer::serialize_verification_key_into_fields() } template void AcirComposer::create_finalized_circuit(acir_format::AcirFormat& constraint_system, + bool recursive, WitnessVector const& witness, bool collect_gates_per_opcode); diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp index 73ca0b11e..682f3a51d 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp @@ -18,6 +18,7 @@ class AcirComposer { template void create_finalized_circuit(acir_format::AcirFormat& constraint_system, + bool recursive, WitnessVector const& witness = {}, bool collect_gates_per_opcode = false); diff --git a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index 48e9eb7ef..16553a32d 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -13,14 +13,12 @@ #include #include -WASM_EXPORT void acir_get_circuit_sizes(uint8_t const* acir_vec, - bool const* honk_recursion, - uint32_t* total, - uint32_t* subgroup) +WASM_EXPORT void acir_get_circuit_sizes( + uint8_t const* acir_vec, bool const* recursive, bool const* honk_recursion, uint32_t* total, uint32_t* subgroup) { auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), *honk_recursion); - auto builder = acir_format::create_circuit(constraint_system, 1 << 19, {}, *honk_recursion); + auto builder = acir_format::create_circuit(constraint_system, recursive, 1 << 19, {}, *honk_recursion); builder.finalize_circuit(/*ensure_nonzero=*/true); *total = htonl((uint32_t)builder.get_finalized_total_circuit_size()); *subgroup = htonl((uint32_t)builder.get_circuit_subgroup_size(builder.get_finalized_total_circuit_size())); @@ -36,41 +34,42 @@ WASM_EXPORT void acir_delete_acir_composer(in_ptr acir_composer_ptr) delete reinterpret_cast(*acir_composer_ptr); } -WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* acir_vec) +WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* acir_vec, bool const* recursive) { auto acir_composer = reinterpret_cast(*acir_composer_ptr); auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/false); - acir_composer->create_finalized_circuit(constraint_system); + acir_composer->create_finalized_circuit(constraint_system, *recursive); acir_composer->init_proving_key(); } -WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, - uint8_t const* acir_vec, - uint8_t const* witness_vec, - uint8_t** out) +WASM_EXPORT void acir_create_proof( + in_ptr acir_composer_ptr, uint8_t const* acir_vec, bool const* recursive, uint8_t const* witness_vec, uint8_t** out) { auto acir_composer = reinterpret_cast(*acir_composer_ptr); auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/false); auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - acir_composer->create_finalized_circuit(constraint_system, witness); + acir_composer->create_finalized_circuit(constraint_system, *recursive, witness); acir_composer->init_proving_key(); auto proof_data = acir_composer->create_proof(); *out = to_heap_buffer(proof_data); } -WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result) +WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* acir_vec, + bool const* recursive, + uint8_t const* witness_vec, + bool* result) { auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto builder = - acir_format::create_circuit(constraint_system, 0, witness, /*honk_recursion=*/true); + auto builder = acir_format::create_circuit( + constraint_system, *recursive, 0, witness, /*honk_recursion=*/true); UltraProver prover{ builder }; auto proof = prover.construct_proof(); @@ -82,7 +81,10 @@ WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* acir_vec, uint8 info("verified: ", *result); } -WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result) +WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* acir_vec, + bool const* recursive, + uint8_t const* witness_vec, + bool* result) { using ProgramStack = acir_format::AcirProgramStack; using Builder = MegaCircuitBuilder; @@ -102,8 +104,12 @@ WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* acir_vec, uin auto stack_item = program_stack.back(); // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit( - stack_item.constraints, 0, stack_item.witness, /*honk_recursion=*/false, ivc.goblin.op_queue); + auto builder = acir_format::create_circuit(stack_item.constraints, + *recursive, + 0, + stack_item.witness, + /*honk_recursion=*/false, + ivc.goblin.op_queue); builder.databus_propagation_data.is_kernel = is_kernel; is_kernel = !is_kernel; // toggle on/off so every second circuit is intepreted as a kernel @@ -116,14 +122,17 @@ WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* acir_vec, uin info("acir_fold_and_verify_program_stack result: ", *result); } -WASM_EXPORT void acir_prove_and_verify_mega_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result) +WASM_EXPORT void acir_prove_and_verify_mega_honk(uint8_t const* acir_vec, + bool const* recursive, + uint8_t const* witness_vec, + bool* result) { auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/false); auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto builder = - acir_format::create_circuit(constraint_system, 0, witness, /*honk_recursion=*/false); + auto builder = acir_format::create_circuit( + constraint_system, *recursive, 0, witness, /*honk_recursion=*/false); MegaProver prover{ builder }; auto proof = prover.construct_proof(); @@ -155,12 +164,15 @@ WASM_EXPORT void acir_get_verification_key(in_ptr acir_composer_ptr, uint8_t** o *out = to_heap_buffer(to_buffer(*vk)); } -WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, uint8_t const* acir_vec, uint8_t** out) +WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, + uint8_t const* acir_vec, + bool const* recursive, + uint8_t** out) { auto acir_composer = reinterpret_cast(*acir_composer_ptr); auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/false); - acir_composer->create_finalized_circuit(constraint_system); + acir_composer->create_finalized_circuit(constraint_system, *recursive); auto pk = acir_composer->init_proving_key(); // We flatten to a vector first, as that's how we treat it on the calling side. *out = to_heap_buffer(to_buffer(*pk)); @@ -206,14 +218,17 @@ WASM_EXPORT void acir_serialize_verification_key_into_fields(in_ptr acir_compose write(out_key_hash, vk_hash); } -WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out) +WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, + bool const* recursive, + uint8_t const* witness_vec, + uint8_t** out) { auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto builder = - acir_format::create_circuit(constraint_system, 0, witness, /*honk_recursion=*/true); + auto builder = acir_format::create_circuit( + constraint_system, *recursive, 0, witness, /*honk_recursion=*/true); UltraProver prover{ builder }; auto proof = prover.construct_proof(); @@ -235,14 +250,15 @@ WASM_EXPORT void acir_verify_ultra_honk(uint8_t const* proof_buf, uint8_t const* *result = verifier.verify_proof(proof); } -WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, uint8_t** out) +WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, bool const* recursive, uint8_t** out) { using DeciderProvingKey = DeciderProvingKey_; using VerificationKey = UltraFlavor::VerificationKey; auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); - auto builder = acir_format::create_circuit(constraint_system, 0, {}, /*honk_recursion=*/true); + auto builder = + acir_format::create_circuit(constraint_system, *recursive, 0, {}, /*honk_recursion=*/true); DeciderProvingKey proving_key(builder); VerificationKey vk(proving_key.proving_key); diff --git a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp index 9015aeaf9..2ed4613b6 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp @@ -7,6 +7,7 @@ using namespace bb; WASM_EXPORT void acir_get_circuit_sizes(uint8_t const* constraint_system_buf, + bool const* recursive, bool const* honk_recursion, uint32_t* total, uint32_t* subgroup); @@ -15,7 +16,9 @@ WASM_EXPORT void acir_new_acir_composer(uint32_t const* size_hint, out_ptr out); WASM_EXPORT void acir_delete_acir_composer(in_ptr acir_composer_ptr); -WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* constraint_system_buf); +WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, + uint8_t const* constraint_system_buf, + bool const* recursive); /** * It would have been nice to just hold onto the constraint_system in the acir_composer, but we can't waste the @@ -24,6 +27,7 @@ WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* */ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, uint8_t const* constraint_system_buf, + bool const* recursive, uint8_t const* witness_buf, uint8_t** out); @@ -32,6 +36,7 @@ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, * */ WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* constraint_system_buf, + bool const* recursive, uint8_t const* witness_buf, bool* result); @@ -40,6 +45,7 @@ WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* constraint_syst * */ WASM_EXPORT void acir_prove_and_verify_mega_honk(uint8_t const* constraint_system_buf, + bool const* recursive, uint8_t const* witness_buf, bool* result); @@ -48,6 +54,7 @@ WASM_EXPORT void acir_prove_and_verify_mega_honk(uint8_t const* constraint_syste * */ WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* constraint_system_buf, + bool const* recursive, uint8_t const* witness_buf, bool* result); @@ -57,7 +64,10 @@ WASM_EXPORT void acir_init_verification_key(in_ptr acir_composer_ptr); WASM_EXPORT void acir_get_verification_key(in_ptr acir_composer_ptr, uint8_t** out); -WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, uint8_t const* acir_vec, uint8_t** out); +WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, + uint8_t const* acir_vec, + bool const* recursive, + uint8_t** out); WASM_EXPORT void acir_verify_proof(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result); @@ -72,11 +82,14 @@ WASM_EXPORT void acir_serialize_verification_key_into_fields(in_ptr acir_compose fr::vec_out_buf out_vkey, fr::out_buf out_key_hash); -WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out); +WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, + bool const* recursive, + uint8_t const* witness_vec, + uint8_t** out); WASM_EXPORT void acir_verify_ultra_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result); -WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, uint8_t** out); +WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, bool const* recursive, uint8_t** out); WASM_EXPORT void acir_proof_as_fields_ultra_honk(uint8_t const* proof_buf, fr::vec_out_buf out); diff --git a/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp b/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp index 12ab5e5b5..238dcc86b 100644 --- a/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp +++ b/cpp/src/barretenberg/stdlib_circuit_builders/circuit_builder_base.hpp @@ -40,8 +40,8 @@ template class CircuitBuilderBase { AggregationObjectPubInputIndices recursive_proof_public_input_indices; bool contains_recursive_proof = false; - // We only know from the circuit description whether a circuit should use a prover which produces - // proofs that are friendly to verify in a circuit themselves. However, a verifier does not need a full circuit + // We know from the CLI arguments during proving whether a circuit should use a prover which produces + // proofs that are friendly to verify in a circuit themselves. A verifier does not need a full circuit // description and should be able to verify a proof with just the verification key and the proof. // This field exists to later set the same field in the verification key, and make sure // that we are using the correct prover/verifier. diff --git a/exports.json b/exports.json index d6819afe1..67c4854c6 100644 --- a/exports.json +++ b/exports.json @@ -505,6 +505,10 @@ "name": "constraint_system_buf", "type": "const uint8_t *" }, + { + "name": "recursive", + "type": "const bool *" + }, { "name": "honk_recursion", "type": "const bool *" @@ -563,6 +567,10 @@ { "name": "constraint_system_buf", "type": "const uint8_t *" + }, + { + "name": "recursive", + "type": "const bool *" } ], "outArgs": [], @@ -579,6 +587,10 @@ "name": "constraint_system_buf", "type": "const uint8_t *" }, + { + "name": "recursive", + "type": "const bool *" + }, { "name": "witness_buf", "type": "const uint8_t *" @@ -599,6 +611,10 @@ "name": "constraint_system_buf", "type": "const uint8_t *" }, + { + "name": "recursive", + "type": "const bool *" + }, { "name": "witness_buf", "type": "const uint8_t *" @@ -619,6 +635,10 @@ "name": "constraint_system_buf", "type": "const uint8_t *" }, + { + "name": "recursive", + "type": "const bool *" + }, { "name": "witness_buf", "type": "const uint8_t *" @@ -639,6 +659,10 @@ "name": "constraint_system_buf", "type": "const uint8_t *" }, + { + "name": "recursive", + "type": "const bool *" + }, { "name": "witness_buf", "type": "const uint8_t *" @@ -704,6 +728,10 @@ { "name": "acir_vec", "type": "const uint8_t *" + }, + { + "name": "recursive", + "type": "const bool *" } ], "outArgs": [ @@ -801,6 +829,10 @@ "name": "acir_vec", "type": "const uint8_t *" }, + { + "name": "recursive", + "type": "const bool *" + }, { "name": "witness_vec", "type": "const uint8_t *" @@ -840,6 +872,10 @@ { "name": "acir_vec", "type": "const uint8_t *" + }, + { + "name": "recursive", + "type": "const bool *" } ], "outArgs": [ @@ -882,4 +918,4 @@ ], "isAsync": false } -] +] \ No newline at end of file diff --git a/ts/src/barretenberg/backend.ts b/ts/src/barretenberg/backend.ts index 0919f030e..4657463be 100644 --- a/ts/src/barretenberg/backend.ts +++ b/ts/src/barretenberg/backend.ts @@ -1,4 +1,4 @@ -import { BackendOptions, Barretenberg } from './index.js'; +import { BackendOptions, Barretenberg, CircuitOptions } from './index.js'; import { RawBuffer } from '../types/raw_buffer.js'; import { decompressSync as gunzip } from 'fflate'; import { @@ -21,22 +21,30 @@ export class UltraPlonkBackend { protected acirUncompressedBytecode: Uint8Array; - constructor(acirBytecode: string, protected options: BackendOptions = { threads: 1 }) { + constructor( + acirBytecode: string, + protected backendOptions: BackendOptions = { threads: 1 }, + protected circuitOptions: CircuitOptions = { recursive: false }, + ) { this.acirUncompressedBytecode = acirToUint8Array(acirBytecode); } /** @ignore */ async instantiate(): Promise { if (!this.api) { - const api = await Barretenberg.new(this.options); + const api = await Barretenberg.new(this.backendOptions); const honkRecursion = false; // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_total, subgroupSize] = await api.acirGetCircuitSizes(this.acirUncompressedBytecode, honkRecursion); + const [_total, subgroupSize] = await api.acirGetCircuitSizes( + this.acirUncompressedBytecode, + this.circuitOptions.recursive, + honkRecursion, + ); await api.initSRSForCircuitSize(subgroupSize); this.acirComposer = await api.acirNewAcirComposer(subgroupSize); - await api.acirInitProvingKey(this.acirComposer, this.acirUncompressedBytecode); + await api.acirInitProvingKey(this.acirComposer, this.acirUncompressedBytecode, this.circuitOptions.recursive); this.api = api; } } @@ -47,6 +55,7 @@ export class UltraPlonkBackend { const proofWithPublicInputs = await this.api.acirCreateProof( this.acirComposer, this.acirUncompressedBytecode, + this.circuitOptions.recursive, gunzip(compressedWitness), ); @@ -69,8 +78,8 @@ export class UltraPlonkBackend { * Instead of passing the proof and verification key as a byte array, we pass them * as fields which makes it cheaper to verify in a circuit. * - * The proof that is passed here will have been created using a circuit - * that has the #[recursive] attribute on its `main` method. + * The proof that is passed here will have been created by passing the `recursive` + * parameter to a backend. * * The number of public inputs denotes how many public inputs are in the inner proof. * @@ -145,15 +154,19 @@ export class UltraHonkBackend { protected api!: Barretenberg; protected acirUncompressedBytecode: Uint8Array; - constructor(acirBytecode: string, protected options: BackendOptions = { threads: 1 }) { + constructor( + acirBytecode: string, + protected backendOptions: BackendOptions = { threads: 1 }, + protected circuitOptions: CircuitOptions = { recursive: false }, + ) { this.acirUncompressedBytecode = acirToUint8Array(acirBytecode); } /** @ignore */ async instantiate(): Promise { if (!this.api) { - const api = await Barretenberg.new(this.options); + const api = await Barretenberg.new(this.backendOptions); const honkRecursion = true; - await api.acirInitSRS(this.acirUncompressedBytecode, honkRecursion); + await api.acirInitSRS(this.acirUncompressedBytecode, this.circuitOptions.recursive, honkRecursion); // We don't init a proving key here in the Honk API // await api.acirInitProvingKey(this.acirComposer, this.acirUncompressedBytecode); @@ -165,6 +178,7 @@ export class UltraHonkBackend { await this.instantiate(); const proofWithPublicInputs = await this.api.acirProveUltraHonk( this.acirUncompressedBytecode, + this.circuitOptions.recursive, gunzip(compressedWitness), ); @@ -194,14 +208,14 @@ export class UltraHonkBackend { async verifyProof(proofData: ProofData): Promise { await this.instantiate(); const proof = reconstructHonkProof(flattenFieldsAsArray(proofData.publicInputs), proofData.proof); - const vkBuf = await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode); + const vkBuf = await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode, this.circuitOptions.recursive); return await this.api.acirVerifyUltraHonk(proof, new RawBuffer(vkBuf)); } async getVerificationKey(): Promise { await this.instantiate(); - return await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode); + return await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode, this.circuitOptions.recursive); } // TODO(https://github.com/noir-lang/noir/issues/5661): Update this to handle Honk recursive aggregation in the browser once it is ready in the backend itself @@ -222,7 +236,7 @@ export class UltraHonkBackend { // TODO: perhaps we should put this in the init function. Need to benchmark // TODO how long it takes. - const vkBuf = await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode); + const vkBuf = await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode, this.circuitOptions.recursive); const vk = await this.api.acirVkAsFieldsUltraHonk(vkBuf); return { diff --git a/ts/src/barretenberg/index.ts b/ts/src/barretenberg/index.ts index 5a0a14a2f..96b9b7d5c 100644 --- a/ts/src/barretenberg/index.ts +++ b/ts/src/barretenberg/index.ts @@ -24,6 +24,11 @@ export type BackendOptions = { crsPath?: string; }; +export type CircuitOptions = { + /** @description Whether to produce SNARK friendly proofs */ + recursive: boolean; +}; + /** * The main class library consumers interact with. * It extends the generated api, and provides a static constructor "new" to compose components. @@ -61,9 +66,9 @@ export class Barretenberg extends BarretenbergApi { await this.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); } - async acirInitSRS(bytecode: Uint8Array, honkRecursion: boolean): Promise { + async acirInitSRS(bytecode: Uint8Array, recursive: boolean, honkRecursion: boolean): Promise { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_total, subgroupSize] = await this.acirGetCircuitSizes(bytecode, honkRecursion); + const [_total, subgroupSize] = await this.acirGetCircuitSizes(bytecode, recursive, honkRecursion); return this.initSRSForCircuitSize(subgroupSize); } diff --git a/ts/src/barretenberg_api/index.ts b/ts/src/barretenberg_api/index.ts index dca7e7cab..06290eda2 100644 --- a/ts/src/barretenberg_api/index.ts +++ b/ts/src/barretenberg_api/index.ts @@ -328,8 +328,12 @@ export class BarretenbergApi { return; } - async acirGetCircuitSizes(constraintSystemBuf: Uint8Array, honkRecursion: boolean): Promise<[number, number]> { - const inArgs = [constraintSystemBuf, honkRecursion].map(serializeBufferable); + async acirGetCircuitSizes( + constraintSystemBuf: Uint8Array, + recursive: boolean, + honkRecursion: boolean, + ): Promise<[number, number]> { + const inArgs = [constraintSystemBuf, recursive, honkRecursion].map(serializeBufferable); const outTypes: OutputType[] = [NumberDeserializer(), NumberDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_get_circuit_sizes', @@ -364,8 +368,8 @@ export class BarretenbergApi { return; } - async acirInitProvingKey(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array): Promise { - const inArgs = [acirComposerPtr, constraintSystemBuf].map(serializeBufferable); + async acirInitProvingKey(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, recursive: boolean): Promise { + const inArgs = [acirComposerPtr, constraintSystemBuf, recursive].map(serializeBufferable); const outTypes: OutputType[] = []; const result = await this.wasm.callWasmExport( 'acir_init_proving_key', @@ -379,9 +383,10 @@ export class BarretenbergApi { async acirCreateProof( acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, + recursive: boolean, witnessBuf: Uint8Array, ): Promise { - const inArgs = [acirComposerPtr, constraintSystemBuf, witnessBuf].map(serializeBufferable); + const inArgs = [acirComposerPtr, constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_create_proof', @@ -392,8 +397,12 @@ export class BarretenbergApi { return out[0]; } - async acirProveAndVerifyUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Promise { - const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + async acirProveAndVerifyUltraHonk( + constraintSystemBuf: Uint8Array, + recursive: boolean, + witnessBuf: Uint8Array, + ): Promise { + const inArgs = [constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_prove_and_verify_ultra_honk', @@ -404,8 +413,12 @@ export class BarretenbergApi { return out[0]; } - async acirProveAndVerifyMegaHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Promise { - const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + async acirProveAndVerifyMegaHonk( + constraintSystemBuf: Uint8Array, + recursive: boolean, + witnessBuf: Uint8Array, + ): Promise { + const inArgs = [constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_prove_and_verify_mega_honk', @@ -416,8 +429,12 @@ export class BarretenbergApi { return out[0]; } - async acirFoldAndVerifyProgramStack(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Promise { - const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + async acirFoldAndVerifyProgramStack( + constraintSystemBuf: Uint8Array, + recursive: boolean, + witnessBuf: Uint8Array, + ): Promise { + const inArgs = [constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_fold_and_verify_program_stack', @@ -464,8 +481,8 @@ export class BarretenbergApi { return out[0]; } - async acirGetProvingKey(acirComposerPtr: Ptr, acirVec: Uint8Array): Promise { - const inArgs = [acirComposerPtr, acirVec].map(serializeBufferable); + async acirGetProvingKey(acirComposerPtr: Ptr, acirVec: Uint8Array, recursive: boolean): Promise { + const inArgs = [acirComposerPtr, acirVec, recursive].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_get_proving_key', @@ -528,8 +545,8 @@ export class BarretenbergApi { return out as any; } - async acirProveUltraHonk(acirVec: Uint8Array, witnessVec: Uint8Array): Promise { - const inArgs = [acirVec, witnessVec].map(serializeBufferable); + async acirProveUltraHonk(acirVec: Uint8Array, recursive: boolean, witnessVec: Uint8Array): Promise { + const inArgs = [acirVec, recursive, witnessVec].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_prove_ultra_honk', @@ -552,8 +569,8 @@ export class BarretenbergApi { return out[0]; } - async acirWriteVkUltraHonk(acirVec: Uint8Array): Promise { - const inArgs = [acirVec].map(serializeBufferable); + async acirWriteVkUltraHonk(acirVec: Uint8Array, recursive: boolean): Promise { + const inArgs = [acirVec, recursive].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = await this.wasm.callWasmExport( 'acir_write_vk_ultra_honk', @@ -904,8 +921,12 @@ export class BarretenbergApiSync { return; } - acirGetCircuitSizes(constraintSystemBuf: Uint8Array, honkRecursion: boolean): [number, number, number] { - const inArgs = [constraintSystemBuf, honkRecursion].map(serializeBufferable); + acirGetCircuitSizes( + constraintSystemBuf: Uint8Array, + recursive: boolean, + honkRecursion: boolean, + ): [number, number, number] { + const inArgs = [constraintSystemBuf, recursive, honkRecursion].map(serializeBufferable); const outTypes: OutputType[] = [NumberDeserializer(), NumberDeserializer()]; const result = this.wasm.callWasmExport( 'acir_get_circuit_sizes', @@ -940,8 +961,8 @@ export class BarretenbergApiSync { return; } - acirInitProvingKey(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array): void { - const inArgs = [acirComposerPtr, constraintSystemBuf].map(serializeBufferable); + acirInitProvingKey(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, recursive: boolean): void { + const inArgs = [acirComposerPtr, constraintSystemBuf, recursive].map(serializeBufferable); const outTypes: OutputType[] = []; const result = this.wasm.callWasmExport( 'acir_init_proving_key', @@ -952,8 +973,13 @@ export class BarretenbergApiSync { return; } - acirCreateProof(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Uint8Array { - const inArgs = [acirComposerPtr, constraintSystemBuf, witnessBuf].map(serializeBufferable); + acirCreateProof( + acirComposerPtr: Ptr, + constraintSystemBuf: Uint8Array, + recursive: boolean, + witnessBuf: Uint8Array, + ): Uint8Array { + const inArgs = [acirComposerPtr, constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = this.wasm.callWasmExport( 'acir_create_proof', @@ -964,8 +990,8 @@ export class BarretenbergApiSync { return out[0]; } - acirProveAndVerifyUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): boolean { - const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + acirProveAndVerifyUltraHonk(constraintSystemBuf: Uint8Array, recursive: boolean, witnessBuf: Uint8Array): boolean { + const inArgs = [constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; const result = this.wasm.callWasmExport( 'acir_prove_and_verify_ultra_honk', @@ -976,8 +1002,8 @@ export class BarretenbergApiSync { return out[0]; } - acirProveAndVerifyMegaHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): boolean { - const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + acirProveAndVerifyMegaHonk(constraintSystemBuf: Uint8Array, recursive: boolean, witnessBuf: Uint8Array): boolean { + const inArgs = [constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; const result = this.wasm.callWasmExport( 'acir_prove_and_verify_mega_honk', @@ -988,8 +1014,8 @@ export class BarretenbergApiSync { return out[0]; } - acirFoldAndVerifyProgramStack(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): boolean { - const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + acirFoldAndVerifyProgramStack(constraintSystemBuf: Uint8Array, recursive: boolean, witnessBuf: Uint8Array): boolean { + const inArgs = [constraintSystemBuf, recursive, witnessBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; const result = this.wasm.callWasmExport( 'acir_fold_and_verify_program_stack', @@ -1036,8 +1062,8 @@ export class BarretenbergApiSync { return out[0]; } - acirGetProvingKey(acirComposerPtr: Ptr, acirVec: Uint8Array): Uint8Array { - const inArgs = [acirComposerPtr, acirVec].map(serializeBufferable); + acirGetProvingKey(acirComposerPtr: Ptr, acirVec: Uint8Array, recursive: boolean): Uint8Array { + const inArgs = [acirComposerPtr, acirVec, recursive].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = this.wasm.callWasmExport( 'acir_get_proving_key', @@ -1096,8 +1122,8 @@ export class BarretenbergApiSync { return out as any; } - acirProveUltraHonk(acirVec: Uint8Array, witnessVec: Uint8Array): Uint8Array { - const inArgs = [acirVec, witnessVec].map(serializeBufferable); + acirProveUltraHonk(acirVec: Uint8Array, recursive: boolean, witnessVec: Uint8Array): Uint8Array { + const inArgs = [acirVec, recursive, witnessVec].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = this.wasm.callWasmExport( 'acir_prove_ultra_honk', @@ -1120,8 +1146,8 @@ export class BarretenbergApiSync { return out[0]; } - acirWriteVkUltraHonk(acirVec: Uint8Array): Uint8Array { - const inArgs = [acirVec].map(serializeBufferable); + acirWriteVkUltraHonk(acirVec: Uint8Array, recursive: boolean): Uint8Array { + const inArgs = [acirVec, recursive].map(serializeBufferable); const outTypes: OutputType[] = [BufferDeserializer()]; const result = this.wasm.callWasmExport( 'acir_write_vk_ultra_honk', diff --git a/ts/src/main.ts b/ts/src/main.ts index 389f554be..1d3af06dd 100755 --- a/ts/src/main.ts +++ b/ts/src/main.ts @@ -34,8 +34,8 @@ function getBytecode(bytecodePath: string) { } // TODO(https://github.com/AztecProtocol/barretenberg/issues/1126): split this into separate Plonk and Honk functions as their gate count differs -async function getGatesUltra(bytecodePath: string, honkRecursion: boolean, api: Barretenberg) { - const { total } = await computeCircuitSize(bytecodePath, honkRecursion, api); +async function getGatesUltra(bytecodePath: string, recursive: boolean, honkRecursion: boolean, api: Barretenberg) { + const { total } = await computeCircuitSize(bytecodePath, recursive, honkRecursion, api); return total; } @@ -45,18 +45,24 @@ function getWitness(witnessPath: string) { return decompressed; } -async function computeCircuitSize(bytecodePath: string, honkRecursion: boolean, api: Barretenberg) { +async function computeCircuitSize(bytecodePath: string, recursive: boolean, honkRecursion: boolean, api: Barretenberg) { debug(`computing circuit size...`); const bytecode = getBytecode(bytecodePath); - const [total, subgroup] = await api.acirGetCircuitSizes(bytecode, honkRecursion); + const [total, subgroup] = await api.acirGetCircuitSizes(bytecode, recursive, honkRecursion); return { total, subgroup }; } -async function initUltraPlonk(bytecodePath: string, crsPath: string, subgroupSizeOverride = -1, honkRecursion = false) { +async function initUltraPlonk( + bytecodePath: string, + recursive: boolean, + crsPath: string, + subgroupSizeOverride = -1, + honkRecursion = false, +) { const api = await Barretenberg.new({ threads }); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1126): use specific UltraPlonk function - const circuitSize = await getGatesUltra(bytecodePath, honkRecursion, api); + const circuitSize = await getGatesUltra(bytecodePath, recursive, honkRecursion, api); // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): remove subgroupSizeOverride hack for goblin const subgroupSize = Math.max(subgroupSizeOverride, Math.pow(2, Math.ceil(Math.log2(circuitSize)))); @@ -80,11 +86,11 @@ async function initUltraPlonk(bytecodePath: string, crsPath: string, subgroupSiz return { api, acirComposer, circuitSize, subgroupSize }; } -async function initUltraHonk(bytecodePath: string, crsPath: string) { +async function initUltraHonk(bytecodePath: string, recursive: boolean, crsPath: string) { const api = await Barretenberg.new({ threads }); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1126): use specific UltraHonk function - const circuitSize = await getGatesUltra(bytecodePath, /*honkRecursion=*/ true, api); + const circuitSize = await getGatesUltra(bytecodePath, recursive, /*honkRecursion=*/ true, api); // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): remove subgroupSizeOverride hack for goblin const dyadicCircuitSize = Math.pow(2, Math.ceil(Math.log2(circuitSize))); @@ -99,7 +105,7 @@ async function initUltraHonk(bytecodePath: string, crsPath: string) { return { api, circuitSize, dyadicCircuitSize }; } -async function initClientIVC(bytecodePath: string, crsPath: string) { +async function initClientIVC(bytecodePath: string, recursive: boolean, crsPath: string) { const api = await Barretenberg.new({ threads }); debug('loading BN254 and Grumpkin crs...'); @@ -126,24 +132,24 @@ async function initLite() { return { api, acirComposer }; } -export async function proveAndVerify(bytecodePath: string, witnessPath: string, crsPath: string) { +export async function proveAndVerify(bytecodePath: string, recursive: boolean, witnessPath: string, crsPath: string) { /* eslint-disable camelcase */ const acir_test = path.basename(process.cwd()); - const { api, acirComposer, circuitSize, subgroupSize } = await initUltraPlonk(bytecodePath, crsPath); + const { api, acirComposer, circuitSize, subgroupSize } = await initUltraPlonk(bytecodePath, recursive, crsPath); try { debug(`creating proof...`); const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); const pkTimer = new Timer(); - await api.acirInitProvingKey(acirComposer, bytecode); + await api.acirInitProvingKey(acirComposer, bytecode, recursive); writeBenchmark('pk_construction_time', pkTimer.ms(), { acir_test, threads }); writeBenchmark('gate_count', circuitSize, { acir_test, threads }); writeBenchmark('subgroup_size', subgroupSize, { acir_test, threads }); const proofTimer = new Timer(); - const proof = await api.acirCreateProof(acirComposer, bytecode, witness); + const proof = await api.acirCreateProof(acirComposer, bytecode, recursive, witness); writeBenchmark('proof_construction_time', proofTimer.ms(), { acir_test, threads }); debug(`verifying...`); @@ -156,14 +162,19 @@ export async function proveAndVerify(bytecodePath: string, witnessPath: string, /* eslint-enable camelcase */ } -export async function proveAndVerifyUltraHonk(bytecodePath: string, witnessPath: string, crsPath: string) { +export async function proveAndVerifyUltraHonk( + bytecodePath: string, + recursive: boolean, + witnessPath: string, + crsPath: string, +) { /* eslint-disable camelcase */ - const { api } = await initUltraHonk(bytecodePath, crsPath); + const { api } = await initUltraHonk(bytecodePath, false, crsPath); try { const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); - const verified = await api.acirProveAndVerifyUltraHonk(bytecode, witness); + const verified = await api.acirProveAndVerifyUltraHonk(bytecode, recursive, witness); return verified; } finally { await api.destroy(); @@ -171,14 +182,19 @@ export async function proveAndVerifyUltraHonk(bytecodePath: string, witnessPath: /* eslint-enable camelcase */ } -export async function proveAndVerifyMegaHonk(bytecodePath: string, witnessPath: string, crsPath: string) { +export async function proveAndVerifyMegaHonk( + bytecodePath: string, + recursive: boolean, + witnessPath: string, + crsPath: string, +) { /* eslint-disable camelcase */ - const { api } = await initUltraPlonk(bytecodePath, crsPath); + const { api } = await initUltraPlonk(bytecodePath, false, crsPath); try { const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); - const verified = await api.acirProveAndVerifyMegaHonk(bytecode, witness); + const verified = await api.acirProveAndVerifyMegaHonk(bytecode, recursive, witness); return verified; } finally { await api.destroy(); @@ -186,14 +202,19 @@ export async function proveAndVerifyMegaHonk(bytecodePath: string, witnessPath: /* eslint-enable camelcase */ } -export async function foldAndVerifyProgram(bytecodePath: string, witnessPath: string, crsPath: string) { +export async function foldAndVerifyProgram( + bytecodePath: string, + recursive: boolean, + witnessPath: string, + crsPath: string, +) { /* eslint-disable camelcase */ - const { api } = await initClientIVC(bytecodePath, crsPath); + const { api } = await initClientIVC(bytecodePath, recursive, crsPath); try { const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); - const verified = await api.acirFoldAndVerifyProgramStack(bytecode, witness); + const verified = await api.acirFoldAndVerifyProgramStack(bytecode, recursive, witness); debug(`verified: ${verified}`); return verified; } finally { @@ -202,13 +223,19 @@ export async function foldAndVerifyProgram(bytecodePath: string, witnessPath: st /* eslint-enable camelcase */ } -export async function prove(bytecodePath: string, witnessPath: string, crsPath: string, outputPath: string) { - const { api, acirComposer } = await initUltraPlonk(bytecodePath, crsPath); +export async function prove( + bytecodePath: string, + recursive: boolean, + witnessPath: string, + crsPath: string, + outputPath: string, +) { + const { api, acirComposer } = await initUltraPlonk(bytecodePath, recursive, crsPath); try { debug(`creating proof...`); const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); - const proof = await api.acirCreateProof(acirComposer, bytecode, witness); + const proof = await api.acirCreateProof(acirComposer, bytecode, recursive, witness); debug(`done.`); if (outputPath === '-') { @@ -223,10 +250,10 @@ export async function prove(bytecodePath: string, witnessPath: string, crsPath: } } -export async function gateCountUltra(bytecodePath: string, honkRecursion: boolean) { +export async function gateCountUltra(bytecodePath: string, recursive: boolean, honkRecursion: boolean) { const api = await Barretenberg.new({ threads: 1 }); try { - const numberOfGates = await getGatesUltra(bytecodePath, honkRecursion, api); + const numberOfGates = await getGatesUltra(bytecodePath, recursive, honkRecursion, api); debug(`number of gates: : ${numberOfGates}`); // Create an 8-byte buffer and write the number into it. // Writing number directly to stdout will result in a variable sized @@ -270,12 +297,12 @@ export async function contract(outputPath: string, vkPath: string) { } } -export async function writeVk(bytecodePath: string, crsPath: string, outputPath: string) { - const { api, acirComposer } = await initUltraPlonk(bytecodePath, crsPath); +export async function writeVk(bytecodePath: string, recursive: boolean, crsPath: string, outputPath: string) { + const { api, acirComposer } = await initUltraPlonk(bytecodePath, recursive, crsPath); try { debug('initing proving key...'); const bytecode = getBytecode(bytecodePath); - await api.acirInitProvingKey(acirComposer, bytecode); + await api.acirInitProvingKey(acirComposer, bytecode, recursive); debug('initing verification key...'); const vk = await api.acirGetVerificationKey(acirComposer); @@ -292,12 +319,12 @@ export async function writeVk(bytecodePath: string, crsPath: string, outputPath: } } -export async function writePk(bytecodePath: string, crsPath: string, outputPath: string) { - const { api, acirComposer } = await initUltraPlonk(bytecodePath, crsPath); +export async function writePk(bytecodePath: string, recursive: boolean, crsPath: string, outputPath: string) { + const { api, acirComposer } = await initUltraPlonk(bytecodePath, recursive, crsPath); try { debug('initing proving key...'); const bytecode = getBytecode(bytecodePath); - const pk = await api.acirGetProvingKey(acirComposer, bytecode); + const pk = await api.acirGetProvingKey(acirComposer, bytecode, recursive); if (outputPath === '-') { process.stdout.write(pk); @@ -362,13 +389,19 @@ export async function vkAsFields(vkPath: string, vkeyOutputPath: string) { } } -export async function proveUltraHonk(bytecodePath: string, witnessPath: string, crsPath: string, outputPath: string) { - const { api } = await initUltraHonk(bytecodePath, crsPath); +export async function proveUltraHonk( + bytecodePath: string, + recursive: boolean, + witnessPath: string, + crsPath: string, + outputPath: string, +) { + const { api } = await initUltraHonk(bytecodePath, recursive, crsPath); try { debug(`creating proof...`); const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); - const proof = await api.acirProveUltraHonk(bytecode, witness); + const proof = await api.acirProveUltraHonk(bytecode, recursive, witness); debug(`done.`); if (outputPath === '-') { @@ -383,12 +416,12 @@ export async function proveUltraHonk(bytecodePath: string, witnessPath: string, } } -export async function writeVkUltraHonk(bytecodePath: string, crsPath: string, outputPath: string) { - const { api } = await initUltraHonk(bytecodePath, crsPath); +export async function writeVkUltraHonk(bytecodePath: string, recursive: boolean, crsPath: string, outputPath: string) { + const { api } = await initUltraHonk(bytecodePath, recursive, crsPath); try { const bytecode = getBytecode(bytecodePath); debug('initing verification key...'); - const vk = await api.acirWriteVkUltraHonk(bytecode); + const vk = await api.acirWriteVkUltraHonk(bytecode, recursive); if (outputPath === '-') { process.stdout.write(vk); @@ -471,10 +504,11 @@ program .command('prove_and_verify') .description('Generate a proof and verify it. Process exits with success or failure code.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Whether to use a SNARK friendly proof', false) .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') - .action(async ({ bytecodePath, witnessPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, witnessPath, crsPath }) => { handleGlobalOptions(); - const result = await proveAndVerify(bytecodePath, witnessPath, crsPath); + const result = await proveAndVerify(bytecodePath, recursive, witnessPath, crsPath); process.exit(result ? 0 : 1); }); @@ -482,10 +516,11 @@ program .command('prove_and_verify_ultra_honk') .description('Generate an UltraHonk proof and verify it. Process exits with success or failure code.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Whether to use a SNARK friendly proof', false) .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') - .action(async ({ bytecodePath, witnessPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, witnessPath, crsPath }) => { handleGlobalOptions(); - const result = await proveAndVerifyUltraHonk(bytecodePath, witnessPath, crsPath); + const result = await proveAndVerifyUltraHonk(bytecodePath, recursive, witnessPath, crsPath); process.exit(result ? 0 : 1); }); @@ -493,10 +528,11 @@ program .command('prove_and_verify_mega_honk') .description('Generate a MegaHonk proof and verify it. Process exits with success or failure code.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Whether to use a SNARK friendly proof', false) .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') - .action(async ({ bytecodePath, witnessPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, witnessPath, crsPath }) => { handleGlobalOptions(); - const result = await proveAndVerifyMegaHonk(bytecodePath, witnessPath, crsPath); + const result = await proveAndVerifyMegaHonk(bytecodePath, recursive, witnessPath, crsPath); process.exit(result ? 0 : 1); }); @@ -504,10 +540,11 @@ program .command('fold_and_verify_program') .description('Accumulate a set of circuits using ClientIvc then verify. Process exits with success or failure code.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') - .action(async ({ bytecodePath, witnessPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, witnessPath, crsPath }) => { handleGlobalOptions(); - const result = await foldAndVerifyProgram(bytecodePath, witnessPath, crsPath); + const result = await foldAndVerifyProgram(bytecodePath, recursive, witnessPath, crsPath); process.exit(result ? 0 : 1); }); @@ -515,21 +552,23 @@ program .command('prove') .description('Generate a proof and write it to a file.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') .option('-o, --output-path ', 'Specify the proof output path', './proofs/proof') - .action(async ({ bytecodePath, witnessPath, outputPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, witnessPath, outputPath, crsPath }) => { handleGlobalOptions(); - await prove(bytecodePath, witnessPath, crsPath, outputPath); + await prove(bytecodePath, recursive, witnessPath, crsPath, outputPath); }); program .command('gates') .description('Print Ultra Builder gate count to standard output.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .option('-hr, --honk-recursion', 'Specify whether to use UltraHonk recursion', false) - .action(async ({ bytecodePath: bytecodePath, honkRecursion: honkRecursion }) => { + .action(async ({ bytecodePath, recursive, honkRecursion: honkRecursion }) => { handleGlobalOptions(); - await gateCountUltra(bytecodePath, honkRecursion); + await gateCountUltra(bytecodePath, recursive, honkRecursion); }); program @@ -558,20 +597,22 @@ program .command('write_vk') .description('Output verification key.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .option('-o, --output-path ', 'Specify the path to write the key') - .action(async ({ bytecodePath, outputPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, outputPath, crsPath }) => { handleGlobalOptions(); - await writeVk(bytecodePath, crsPath, outputPath); + await writeVk(bytecodePath, recursive, crsPath, outputPath); }); program .command('write_pk') .description('Output proving key.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .requiredOption('-o, --output-path ', 'Specify the path to write the key') - .action(async ({ bytecodePath, outputPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, outputPath, crsPath }) => { handleGlobalOptions(); - await writePk(bytecodePath, crsPath, outputPath); + await writePk(bytecodePath, recursive, crsPath, outputPath); }); program @@ -599,21 +640,23 @@ program .command('prove_ultra_honk') .description('Generate a proof and write it to a file.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') .option('-o, --output-path ', 'Specify the proof output path', './proofs/proof') - .action(async ({ bytecodePath, witnessPath, outputPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, witnessPath, outputPath, crsPath }) => { handleGlobalOptions(); - await proveUltraHonk(bytecodePath, witnessPath, crsPath, outputPath); + await proveUltraHonk(bytecodePath, recursive, witnessPath, crsPath, outputPath); }); program .command('write_vk_ultra_honk') .description('Output verification key.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/program.json') + .option('-r, --recursive', 'Create a SNARK friendly proof', false) .requiredOption('-o, --output-path ', 'Specify the path to write the key') - .action(async ({ bytecodePath, outputPath, crsPath }) => { + .action(async ({ bytecodePath, recursive, outputPath, crsPath }) => { handleGlobalOptions(); - await writeVkUltraHonk(bytecodePath, crsPath, outputPath); + await writeVkUltraHonk(bytecodePath, recursive, crsPath, outputPath); }); program