From 97206cde6bdc111fb0a7e80d74c0fece598592c8 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Wed, 16 Oct 2024 10:58:50 +0000 Subject: [PATCH 01/28] feat: Integrate verify_proof calls in mock protocol circuits --- noir-projects/mega_honk_circuits.json | 4 +++- .../mock-private-kernel-init/src/main.nr | 10 ++++++++-- .../mock-private-kernel-inner/src/main.nr | 12 ++++++++++-- .../mock-private-kernel-reset/src/main.nr | 8 +++++++- .../mock-private-kernel-tail/src/main.nr | 12 ++++++++++-- .../crates/mock-types/Nargo.toml | 3 ++- .../crates/mock-types/src/lib.nr | 2 ++ .../src/client_ivc_integration.test.ts | 13 +++++++++++++ yarn-project/ivc-integration/src/index.ts | 19 +++++++++++++++++++ 9 files changed, 74 insertions(+), 9 deletions(-) diff --git a/noir-projects/mega_honk_circuits.json b/noir-projects/mega_honk_circuits.json index 37b25115596..98b0104f17e 100644 --- a/noir-projects/mega_honk_circuits.json +++ b/noir-projects/mega_honk_circuits.json @@ -2,5 +2,7 @@ "private_kernel_init", "private_kernel_inner", "private_kernel_reset.*", - "private_kernel_tail.*" + "private_kernel_tail.*", + "app_creator", + "app_reader" ] \ No newline at end of file diff --git a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-init/src/main.nr b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-init/src/main.nr index d2585336fdb..dde87b9dd15 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-init/src/main.nr +++ b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-init/src/main.nr @@ -1,9 +1,15 @@ -use dep::mock_types::{TxRequest, PrivateKernelPublicInputs, PrivateKernelPublicInputsBuilder, AppPublicInputs}; +use dep::mock_types::{ + TxRequest, PrivateKernelPublicInputs, PrivateKernelPublicInputsBuilder, AppPublicInputs, + CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS, PROOF_TYPE_OINK +}; fn main( tx: TxRequest, - app_inputs: call_data(1) AppPublicInputs + app_inputs: call_data(1) AppPublicInputs, + app_vk: [Field; CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS] ) -> return_data PrivateKernelPublicInputs { + std::verify_proof_with_type(app_vk, [], [], 0, PROOF_TYPE_OINK); + let mut private_kernel_inputs = PrivateKernelPublicInputsBuilder::from_tx(tx); private_kernel_inputs.ingest_app_inputs(app_inputs); private_kernel_inputs.finish() diff --git a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-inner/src/main.nr b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-inner/src/main.nr index 0a6b4c11761..5eac3a6676c 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-inner/src/main.nr +++ b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-inner/src/main.nr @@ -1,9 +1,17 @@ -use dep::mock_types::{PrivateKernelPublicInputs, PrivateKernelPublicInputsBuilder, AppPublicInputs}; +use dep::mock_types::{ + PrivateKernelPublicInputs, PrivateKernelPublicInputsBuilder, AppPublicInputs, + CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS, PROOF_TYPE_PG +}; fn main( prev_kernel_public_inputs: call_data(0) PrivateKernelPublicInputs, - app_inputs: call_data(1) AppPublicInputs + kernel_vk: [Field; CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS], + app_inputs: call_data(1) AppPublicInputs, + app_vk: [Field; CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS] ) -> return_data PrivateKernelPublicInputs { + std::verify_proof_with_type(kernel_vk, [], [], 0, PROOF_TYPE_PG); + std::verify_proof_with_type(app_vk, [], [], 0, PROOF_TYPE_PG); + let mut private_kernel_inputs = PrivateKernelPublicInputsBuilder::from_previous_kernel(prev_kernel_public_inputs); private_kernel_inputs.ingest_app_inputs(app_inputs); private_kernel_inputs.finish() diff --git a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-reset/src/main.nr b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-reset/src/main.nr index f4e49af46d7..855c35cc03b 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-reset/src/main.nr +++ b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-reset/src/main.nr @@ -1,11 +1,17 @@ -use dep::mock_types::{PrivateKernelPublicInputs, MAX_COMMITMENT_READ_REQUESTS_PER_TX, MAX_COMMITMENTS_PER_TX}; +use dep::mock_types::{ + PrivateKernelPublicInputs, MAX_COMMITMENT_READ_REQUESTS_PER_TX, MAX_COMMITMENTS_PER_TX, + PROOF_TYPE_PG, CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS +}; // Mock reset kernel that reset read requests. // It needs hints to locate the commitment that matches the read requests. fn main( mut prev_kernel_public_inputs: call_data(0) PrivateKernelPublicInputs, + kernel_vk: [Field; CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS], commitment_read_hints: [u32; MAX_COMMITMENT_READ_REQUESTS_PER_TX] ) -> return_data PrivateKernelPublicInputs { + std::verify_proof_with_type(kernel_vk, [], [], 0, PROOF_TYPE_PG); + for i in 0..MAX_COMMITMENT_READ_REQUESTS_PER_TX { if commitment_read_hints[i] != MAX_COMMITMENTS_PER_TX { assert_eq( diff --git a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-tail/src/main.nr b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-tail/src/main.nr index 93bd23cf813..52a0dd09a42 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-tail/src/main.nr +++ b/noir-projects/mock-protocol-circuits/crates/mock-private-kernel-tail/src/main.nr @@ -1,7 +1,15 @@ -use dep::mock_types::{PrivateKernelPublicInputs, KernelPublicInputs, MAX_COMMITMENT_READ_REQUESTS_PER_TX}; +use dep::mock_types::{ + PrivateKernelPublicInputs, KernelPublicInputs, MAX_COMMITMENT_READ_REQUESTS_PER_TX, + CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS, PROOF_TYPE_PG +}; // The tail kernel finishes the client IVC chain exposing the final public inputs with no remaining calls or unfulfilled read requests. -fn main(prev_kernel_public_inputs: call_data(0) PrivateKernelPublicInputs) -> pub KernelPublicInputs { +fn main( + prev_kernel_public_inputs: call_data(0) PrivateKernelPublicInputs, + kernel_vk: [Field; CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS] +) -> pub KernelPublicInputs { + std::verify_proof_with_type(kernel_vk, [], [], 0, PROOF_TYPE_PG); + assert_eq(prev_kernel_public_inputs.remaining_calls, 0); for i in 0..MAX_COMMITMENT_READ_REQUESTS_PER_TX { assert_eq(prev_kernel_public_inputs.read_requests[i], 0); diff --git a/noir-projects/mock-protocol-circuits/crates/mock-types/Nargo.toml b/noir-projects/mock-protocol-circuits/crates/mock-types/Nargo.toml index d5f57873b0c..e9b0542224a 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-types/Nargo.toml +++ b/noir-projects/mock-protocol-circuits/crates/mock-types/Nargo.toml @@ -4,4 +4,5 @@ type = "lib" authors = [""] compiler_version = ">=0.32.0" -[dependencies] \ No newline at end of file +[dependencies] +protocol_types = { path = "../../../noir-protocol-circuits/crates/types" } diff --git a/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr b/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr index 46936a79499..cedad6abb1b 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr +++ b/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr @@ -3,6 +3,8 @@ global MAX_COMMITMENTS_PER_TX = 4; global MAX_COMMITMENT_READ_REQUESTS_PER_CALL = 2; global MAX_COMMITMENT_READ_REQUESTS_PER_TX = 4; +pub use protocol_types::constants::{PROOF_TYPE_OINK, PROOF_TYPE_PG, CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS}; + struct TxRequest { number_of_calls: u32, } diff --git a/yarn-project/ivc-integration/src/client_ivc_integration.test.ts b/yarn-project/ivc-integration/src/client_ivc_integration.test.ts index 1a8409f3588..214458e1e42 100644 --- a/yarn-project/ivc-integration/src/client_ivc_integration.test.ts +++ b/yarn-project/ivc-integration/src/client_ivc_integration.test.ts @@ -12,11 +12,17 @@ import { fileURLToPath } from 'url'; import { MOCK_MAX_COMMITMENTS_PER_TX, MockAppCreatorCircuit, + MockAppCreatorVk, MockAppReaderCircuit, + MockAppReaderVk, MockPrivateKernelInitCircuit, + MockPrivateKernelInitVk, MockPrivateKernelInnerCircuit, + MockPrivateKernelInnerVk, MockPrivateKernelResetCircuit, + MockPrivateKernelResetVk, MockPrivateKernelTailCircuit, + getVkAsFields, witnessGenCreatorAppMockCircuit, witnessGenMockPrivateKernelInitCircuit, witnessGenMockPrivateKernelInnerCircuit, @@ -77,10 +83,12 @@ describe('Client IVC Integration', () => { const initWitnessGenResult = await witnessGenMockPrivateKernelInitCircuit({ app_inputs: appWitnessGenResult.publicInputs, tx, + app_vk: getVkAsFields(MockAppCreatorVk), }); const tailWitnessGenResult = await witnessGenMockPrivateKernelTailCircuit({ prev_kernel_public_inputs: initWitnessGenResult.publicInputs, + kernel_vk: getVkAsFields(MockPrivateKernelInitVk), }); // Create client IVC proof const bytecodes = [ @@ -115,10 +123,13 @@ describe('Client IVC Integration', () => { const initWitnessGenResult = await witnessGenMockPrivateKernelInitCircuit({ app_inputs: creatorAppWitnessGenResult.publicInputs, tx, + app_vk: getVkAsFields(MockAppCreatorVk), }); const innerWitnessGenResult = await witnessGenMockPrivateKernelInnerCircuit({ prev_kernel_public_inputs: initWitnessGenResult.publicInputs, app_inputs: readerAppWitnessGenResult.publicInputs, + app_vk: getVkAsFields(MockAppReaderVk), + kernel_vk: getVkAsFields(MockPrivateKernelInitVk), }); const resetWitnessGenResult = await witnessGenMockPrivateKernelResetCircuit({ @@ -129,10 +140,12 @@ describe('Client IVC Integration', () => { MOCK_MAX_COMMITMENTS_PER_TX.toString(), MOCK_MAX_COMMITMENTS_PER_TX.toString(), ], + kernel_vk: getVkAsFields(MockPrivateKernelInnerVk), }); const tailWitnessGenResult = await witnessGenMockPrivateKernelTailCircuit({ prev_kernel_public_inputs: resetWitnessGenResult.publicInputs, + kernel_vk: getVkAsFields(MockPrivateKernelResetVk), }); // Create client IVC proof diff --git a/yarn-project/ivc-integration/src/index.ts b/yarn-project/ivc-integration/src/index.ts index dac0fd16ea8..fb5641bfac1 100644 --- a/yarn-project/ivc-integration/src/index.ts +++ b/yarn-project/ivc-integration/src/index.ts @@ -1,7 +1,15 @@ +import { type CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS } from '@aztec/circuits.js'; + import { type ForeignCallOutput, Noir } from '@noir-lang/noir_js'; import MockAppCreatorCircuit from '../artifacts/app_creator.json' assert { type: 'json' }; import MockAppReaderCircuit from '../artifacts/app_reader.json' assert { type: 'json' }; +import MockAppCreatorVk from '../artifacts/keys/app_creator.vk.data.json' assert { type: 'json' }; +import MockAppReaderVk from '../artifacts/keys/app_reader.vk.data.json' assert { type: 'json' }; +import MockPrivateKernelInitVk from '../artifacts/keys/mock_private_kernel_init.vk.data.json' assert { type: 'json' }; +import MockPrivateKernelInnerVk from '../artifacts/keys/mock_private_kernel_inner.vk.data.json' assert { type: 'json' }; +import MockPrivateKernelResetVk from '../artifacts/keys/mock_private_kernel_reset.vk.data.json' assert { type: 'json' }; +import MockPrivateKernelTailVk from '../artifacts/keys/mock_private_kernel_tail.vk.data.json' assert { type: 'json' }; import MockPrivateKernelInitCircuit from '../artifacts/mock_private_kernel_init.json' assert { type: 'json' }; import MockPrivateKernelInnerCircuit from '../artifacts/mock_private_kernel_inner.json' assert { type: 'json' }; import MockPrivateKernelResetCircuit from '../artifacts/mock_private_kernel_reset.json' assert { type: 'json' }; @@ -11,6 +19,7 @@ import type { AppCreatorInputType, AppPublicInputs, AppReaderInputType, + FixedLengthArray, KernelPublicInputs, MockPrivateKernelInitInputType, MockPrivateKernelInnerInputType, @@ -30,6 +39,12 @@ export { MockPrivateKernelResetCircuit, MockPrivateKernelTailCircuit, MockPublicKernelCircuit, + MockAppCreatorVk, + MockAppReaderVk, + MockPrivateKernelInitVk, + MockPrivateKernelInnerVk, + MockPrivateKernelResetVk, + MockPrivateKernelTailVk, }; export const MOCK_MAX_COMMITMENTS_PER_TX = 4; @@ -119,3 +134,7 @@ export async function witnessGenMockPublicKernelCircuit( publicInputs: returnValue as u8, }; } + +export function getVkAsFields(vk: any): FixedLengthArray { + return vk.keyAsFields as FixedLengthArray; +} From be16bfae1779699a16b60bb39b80a8f8f4ee7ccd Mon Sep 17 00:00:00 2001 From: sirasistant Date: Wed, 16 Oct 2024 11:01:30 +0000 Subject: [PATCH 02/28] type --- yarn-project/ivc-integration/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/yarn-project/ivc-integration/src/index.ts b/yarn-project/ivc-integration/src/index.ts index fb5641bfac1..b6df52bea7d 100644 --- a/yarn-project/ivc-integration/src/index.ts +++ b/yarn-project/ivc-integration/src/index.ts @@ -135,6 +135,9 @@ export async function witnessGenMockPublicKernelCircuit( }; } -export function getVkAsFields(vk: any): FixedLengthArray { +export function getVkAsFields(vk: { + keyAsBytes: string; + keyAsFields: string[]; +}): FixedLengthArray { return vk.keyAsFields as FixedLengthArray; } From ccf7f6b5f44790210efdefb3b00e7dffb7835e6d Mon Sep 17 00:00:00 2001 From: sirasistant Date: Wed, 16 Oct 2024 12:00:00 +0000 Subject: [PATCH 03/28] feat: add skip auto verify --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 8 +++++--- yarn-project/bb-prover/src/bb/execute.ts | 4 ++++ .../ivc-integration/src/client_ivc_integration.test.ts | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 4958dc7765e..3437f7827f3 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -324,7 +324,8 @@ std::vector decompressedBuffer(uint8_t* bytes, size_t size) void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath, const std::string& witnessPath, - const std::string& outputDir) + const std::string& outputDir, + bool auto_verify) { using Flavor = MegaFlavor; // This is the only option using Builder = Flavor::CircuitBuilder; @@ -357,7 +358,7 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath, // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc; - ivc.auto_verify_mode = true; + ivc.auto_verify_mode = auto_verify; ivc.trace_structure = TraceStructure::E2E_FULL_TEST; // Accumulate the entire program stack into the IVC @@ -1454,7 +1455,8 @@ int main(int argc, char* argv[]) // TODO(#7371): remove this if (command == "client_ivc_prove_output_all_msgpack") { std::filesystem::path output_dir = get_option(args, "-o", "./target"); - client_ivc_prove_output_all_msgpack(bytecode_path, witness_path, output_dir); + bool skip_auto_verify = flag_present(args, "--skip_auto_verify"); + client_ivc_prove_output_all_msgpack(bytecode_path, witness_path, output_dir, !skip_auto_verify); return 0; } if (command == "verify_client_ivc") { diff --git a/yarn-project/bb-prover/src/bb/execute.ts b/yarn-project/bb-prover/src/bb/execute.ts index d5fbcb06d76..0a06d1fe7d3 100644 --- a/yarn-project/bb-prover/src/bb/execute.ts +++ b/yarn-project/bb-prover/src/bb/execute.ts @@ -196,6 +196,7 @@ export async function executeBbClientIvcProof( bytecodeStackPath: string, witnessStackPath: string, log: LogFn, + skipAutoVerify = false, ): Promise { // Check that the working directory exists try { @@ -220,6 +221,9 @@ export async function executeBbClientIvcProof( log(`bytecodePath ${bytecodeStackPath}`); log(`outputPath ${outputPath}`); const args = ['-o', outputPath, '-b', bytecodeStackPath, '-w', witnessStackPath, '-v']; + if (skipAutoVerify) { + args.push('--skip_auto_verify'); + } const timer = new Timer(); const logFunction = (message: string) => { log(`client ivc proof BB out - ${message}`); diff --git a/yarn-project/ivc-integration/src/client_ivc_integration.test.ts b/yarn-project/ivc-integration/src/client_ivc_integration.test.ts index 214458e1e42..b0ac9d4d5c4 100644 --- a/yarn-project/ivc-integration/src/client_ivc_integration.test.ts +++ b/yarn-project/ivc-integration/src/client_ivc_integration.test.ts @@ -60,6 +60,7 @@ describe('Client IVC Integration', () => { path.join(bbWorkingDirectory, 'acir.msgpack'), path.join(bbWorkingDirectory, 'witnesses.msgpack'), logger.info, + true, ); if (provingResult.status === BB_RESULT.FAILURE) { From ffd40f77df9b39784f2520059f3e6bc9d1583449 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 16 Oct 2024 16:31:28 +0000 Subject: [PATCH 04/28] add a new ivc flow that properly handles kernels --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 88 ++++++++++++++++++- .../dsl/acir_format/block_constraint.cpp | 2 + 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 3437f7827f3..e633152e185 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -324,8 +324,7 @@ std::vector decompressedBuffer(uint8_t* bytes, size_t size) void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath, const std::string& witnessPath, - const std::string& outputDir, - bool auto_verify) + const std::string& outputDir) { using Flavor = MegaFlavor; // This is the only option using Builder = Flavor::CircuitBuilder; @@ -358,7 +357,7 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath, // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc; - ivc.auto_verify_mode = auto_verify; + ivc.auto_verify_mode = true; ivc.trace_structure = TraceStructure::E2E_FULL_TEST; // Accumulate the entire program stack into the IVC @@ -400,6 +399,83 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath, write_file(eccVkPath, to_buffer(eccvm_vk)); } +void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytecodePath, + const std::string& witnessPath, + const std::string& outputDir) +{ + using Flavor = MegaFlavor; // This is the only option + using Builder = Flavor::CircuitBuilder; + using Program = acir_format::AcirProgram; + using ECCVMVK = ECCVMFlavor::VerificationKey; + using TranslatorVK = TranslatorFlavor::VerificationKey; + using DeciderVerificationKey = ClientIVC::DeciderVerificationKey; + + using namespace acir_format; + + init_bn254_crs(1 << 24); + init_grumpkin_crs(1 << 15); + + auto gzipped_bincodes = unpack_from_file>(bytecodePath); + auto witness_data = unpack_from_file>(witnessPath); + std::vector folding_stack; + for (auto [bincode, wit] : zip_view(gzipped_bincodes, witness_data)) { + // TODO(#7371) there is a lot of copying going on in bincode, we should make sure this writes as a buffer in + // the future + std::vector constraint_buf = + decompressedBuffer(reinterpret_cast(bincode.data()), bincode.size()); // NOLINT + std::vector witness_buf = + decompressedBuffer(reinterpret_cast(wit.data()), wit.size()); // NOLINT + + AcirFormat constraints = circuit_buf_to_acir_format(constraint_buf, /*honk_recursion=*/false); + WitnessVector witness = witness_buf_to_witness_data(witness_buf); + + folding_stack.push_back(Program{ constraints, witness }); + } + // TODO(#7371) dedupe this with the rest of the similar code + ClientIVC ivc; + ivc.trace_structure = TraceStructure::E2E_FULL_TEST; + + // Accumulate the entire program stack into the IVC + for (Program& program : folding_stack) { + // Construct a bberg circuit from the acir representation then accumulate it into the IVC + MegaCircuitBuilder circuit; + + // Use the presence of IVC recursion constraints to indicate whether or not the program is a kernel + bool is_kernel = !program.constraints.ivc_recursion_constraints.empty(); + if (is_kernel) { + info("Creating circuit of type: KERNEL"); + auto circuit = create_kernel_circuit(program.constraints, ivc, program.witness); + } else { + info("Creating circuit of type: APP"); + auto circuit = create_circuit(program.constraints, 0, program.witness, false, ivc.goblin.op_queue); + } + + ivc.accumulate(circuit); + } + + // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems this + // directory is passed by bb.js) + std::string vkPath = outputDir + "/final_decider_vk"; // the vk of the last circuit in the stack + std::string accPath = outputDir + "/pg_acc"; + std::string proofPath = outputDir + "/client_ivc_proof"; + std::string translatorVkPath = outputDir + "/translator_vk"; + std::string eccVkPath = outputDir + "/ecc_vk"; + + auto proof = ivc.prove(); + auto eccvm_vk = std::make_shared(ivc.goblin.get_eccvm_proving_key()); + auto translator_vk = std::make_shared(ivc.goblin.get_translator_proving_key()); + + auto last_vk = std::make_shared(ivc.honk_vk); + vinfo("ensure valid proof: ", ivc.verify(proof, { ivc.verifier_accumulator, last_vk })); + + vinfo("write proof and vk data to files.."); + write_file(proofPath, to_buffer(proof)); + write_file(vkPath, to_buffer(ivc.honk_vk)); + write_file(accPath, to_buffer(ivc.verifier_accumulator)); + write_file(translatorVkPath, to_buffer(translator_vk)); + write_file(eccVkPath, to_buffer(eccvm_vk)); +} + template std::shared_ptr read_to_shared_ptr(const std::filesystem::path& path) { return std::make_shared(from_buffer(read_file(path))); @@ -1456,7 +1532,11 @@ int main(int argc, char* argv[]) if (command == "client_ivc_prove_output_all_msgpack") { std::filesystem::path output_dir = get_option(args, "-o", "./target"); bool skip_auto_verify = flag_present(args, "--skip_auto_verify"); - client_ivc_prove_output_all_msgpack(bytecode_path, witness_path, output_dir, !skip_auto_verify); + if (skip_auto_verify) { + client_ivc_prove_output_all_msgpack_no_auto_verify(bytecode_path, witness_path, output_dir); + } else { + client_ivc_prove_output_all_msgpack(bytecode_path, witness_path, output_dir); + } return 0; } if (command == "verify_client_ivc") { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp index 0e2bf5d74de..9315bb39db0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp @@ -87,6 +87,8 @@ void create_block_constraints(MegaCircuitBuilder& builder, // The presence of calldata is used to indicate that the present circuit is a kernel. This is needed in the // databus consistency checks to indicate that the corresponding return data belongs to a kernel (else an app). info("ACIR: Setting is_kernel to TRUE."); + // WORKTODO: this won't be sufficient since we currently need to distinguis between create_circuit and + // create_kernel_circuit builder.databus_propagation_data.is_kernel = true; } break; case BlockType::ReturnData: { From a7757e30b91fed9c4f40963ce86191e5f634ce3e Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 16 Oct 2024 17:46:54 +0000 Subject: [PATCH 05/28] let client ivc use internal vkeys --- .../cpp/src/barretenberg/dsl/acir_format/acir_format.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 3faba5e923d..9510733793e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -505,8 +505,9 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, StdlibVerificationKey::from_witness_indices(circuit, constraint.key))); } - // Create stdlib representations of each {proof, vkey} pair to be recursively verified - ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); + // DEBUG: allow client ivc to auto-populate valid keys + // // Create stdlib representations of each {proof, vkey} pair to be recursively verified + // ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal // verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly From 2ee99718b3a7be748d26e026b8b877123833323b Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 16 Oct 2024 18:16:16 +0000 Subject: [PATCH 06/28] handle ivc rec constraints in acir to buf --- .../barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp index dff52b89672..04539dd48cd 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.cpp @@ -686,6 +686,11 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, af.honk_recursion_constraints.push_back(c); af.original_opcode_indices.honk_recursion_constraints.push_back(opcode_index); break; + case OINK: + case PG: + af.ivc_recursion_constraints.push_back(c); + af.original_opcode_indices.ivc_recursion_constraints.push_back(opcode_index); + break; case AVM: af.avm_recursion_constraints.push_back(c); af.original_opcode_indices.avm_recursion_constraints.push_back(opcode_index); From 193bd1761069592e8c079097eb0ce2cbd81fe50b Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 18 Oct 2024 08:12:24 +0000 Subject: [PATCH 07/28] working without using the vks from the kernels --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 4 +-- .../dsl/acir_format/acir_format.cpp | 5 ++-- .../cpp/src/barretenberg/goblin/goblin.hpp | 6 +++- .../src/barretenberg/sumcheck/sumcheck.hpp | 4 +-- .../ultra_honk/decider_prover.cpp | 2 +- .../ultra_honk/decider_proving_key.hpp | 30 +++++++++---------- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index e633152e185..f0f958c3403 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -444,10 +444,10 @@ void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytec bool is_kernel = !program.constraints.ivc_recursion_constraints.empty(); if (is_kernel) { info("Creating circuit of type: KERNEL"); - auto circuit = create_kernel_circuit(program.constraints, ivc, program.witness); + circuit = create_kernel_circuit(program.constraints, ivc, program.witness); } else { info("Creating circuit of type: APP"); - auto circuit = create_circuit(program.constraints, 0, program.witness, false, ivc.goblin.op_queue); + circuit = create_circuit(program.constraints, 0, program.witness, false, ivc.goblin.op_queue); } ivc.accumulate(circuit); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 9510733793e..13a5a6a31a3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -505,9 +505,10 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, StdlibVerificationKey::from_witness_indices(circuit, constraint.key))); } - // DEBUG: allow client ivc to auto-populate valid keys - // // Create stdlib representations of each {proof, vkey} pair to be recursively verified + // Create stdlib representations of each {proof, vkey} pair to be recursively verified // ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); + // DEBUG: allow client ivc to auto-populate valid keys + ivc.instantiate_stdlib_verification_queue(circuit); // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal // verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index fcfd0d78913..61ffab32ddb 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -236,13 +236,14 @@ class GoblinProver { { PROFILE_THIS_NAME("prove_eccvm"); - + vinfo("prove ECCVM."); prove_eccvm(); } { PROFILE_THIS_NAME("prove_translator"); + vinfo("prove Translator."); prove_translator(); } return goblin_proof; @@ -293,11 +294,14 @@ class GoblinVerifier { TranslatorVerifier translator_verifier(translator_verification_key, eccvm_verifier.transcript); + vinfo("verify Translator."); bool accumulator_construction_verified = translator_verifier.verify_proof(proof.translator_proof); // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed // correctly + vinfo("verify Translation."); bool translation_verified = translator_verifier.verify_translation(proof.translation_evaluations); + vinfo("verification complete."); return merge_verified && eccvm_verified && accumulator_construction_verified && translation_verified; }; }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 083236863f0..d6a0803c757 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -227,7 +227,7 @@ template class SumcheckProver { // release memory? // All but final round // We operate on partially_evaluated_polynomials in place. } - vinfo("completed sumcheck round 0"); + // vinfo("completed sumcheck round 0"); for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { PROFILE_THIS_NAME("sumcheck loop"); @@ -252,7 +252,7 @@ template class SumcheckProver { gate_separators.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; - vinfo("completed sumcheck round ", round_idx); + // vinfo("completed sumcheck round ", round_idx); } // Check that the challenges \f$ u_0,\ldots, u_{d-1} \f$ do not satisfy the equation \f$ u_0(1-u_0) + \ldots + // u_{d-1} (1 - u_{d-1}) = 0 \f$. This equation is satisfied with probability ~ 1/|FF|, in such cases the prover diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp index 3f8fe01b3cc..08ae55ae376 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp @@ -83,7 +83,7 @@ template HonkProof DeciderProver_::construct_proo // Fiat-Shamir: rho, y, x, z // Execute Zeromorph multilinear PCS - vinfo("executing pcd opening rounds..."); + vinfo("executing pcs opening rounds..."); execute_pcs_rounds(); return export_proof(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp index 0d6eab716e2..71e8fefed21 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp @@ -78,7 +78,7 @@ template class DeciderProvingKey_ { { PROFILE_THIS_NAME("constructing proving key"); - vinfo("constructing proving key"); + // vinfo("constructing proving key"); proving_key = ProvingKey(dyadic_circuit_size, circuit.public_inputs.size(), commitment_key); if (IsGoblinFlavor && !is_structured) { @@ -88,7 +88,7 @@ template class DeciderProvingKey_ { // Allocate the wires and selectors polynomials { PROFILE_THIS_NAME("allocating wires"); - vinfo("allocating wires"); + // vinfo("allocating wires"); for (auto& wire : proving_key.polynomials.get_wires()) { wire = Polynomial::shiftable(proving_key.circuit_size); @@ -96,7 +96,7 @@ template class DeciderProvingKey_ { } { PROFILE_THIS_NAME("allocating gate selectors"); - vinfo("allocating gate selectors"); + // vinfo("allocating gate selectors"); // Define gate selectors over the block they are isolated to for (auto [selector, block] : @@ -118,7 +118,7 @@ template class DeciderProvingKey_ { } { PROFILE_THIS_NAME("allocating non-gate selectors"); - vinfo("allocating non-gate selectors"); + // vinfo("allocating non-gate selectors"); // Set the other non-gate selector polynomials to full size for (auto& selector : proving_key.polynomials.get_non_gate_selectors()) { @@ -127,7 +127,7 @@ template class DeciderProvingKey_ { } if constexpr (IsGoblinFlavor) { PROFILE_THIS_NAME("allocating ecc op wires and selector"); - vinfo("allocating ecc op wires and selector"); + // vinfo("allocating ecc op wires and selector"); // Allocate the ecc op wires and selector const size_t ecc_op_block_size = circuit.blocks.ecc_op.get_fixed_size(is_structured); @@ -166,7 +166,7 @@ template class DeciderProvingKey_ { size_t table_offset = dyadic_circuit_size - max_tables_size; { PROFILE_THIS_NAME("allocating table polynomials"); - vinfo("allocating table polynomials"); + // vinfo("allocating table polynomials"); ASSERT(dyadic_circuit_size > max_tables_size); @@ -179,7 +179,7 @@ template class DeciderProvingKey_ { } { PROFILE_THIS_NAME("allocating sigmas and ids"); - vinfo("allocating sigmas and ids"); + // vinfo("allocating sigmas and ids"); for (auto& sigma : proving_key.polynomials.get_sigmas()) { sigma = typename Flavor::Polynomial(proving_key.circuit_size); @@ -191,7 +191,7 @@ template class DeciderProvingKey_ { { ZoneScopedN("allocating lookup read counts and tags"); // Allocate the read counts and tags polynomials - vinfo("allocating lookup read counts and tags"); + // vinfo("allocating lookup read counts and tags"); proving_key.polynomials.lookup_read_counts = typename Flavor::Polynomial(max_tables_size, dyadic_circuit_size, table_offset); proving_key.polynomials.lookup_read_tags = @@ -200,7 +200,7 @@ template class DeciderProvingKey_ { { ZoneScopedN("allocating lookup and databus inverses"); // Allocate the lookup_inverses polynomial - vinfo("allocating lookup and databus inverses"); + // vinfo("allocating lookup and databus inverses"); const size_t lookup_offset = static_cast(circuit.blocks.lookup.trace_offset); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1033): construct tables and counts // at top of trace @@ -228,7 +228,7 @@ template class DeciderProvingKey_ { } { PROFILE_THIS_NAME("constructing z_perm"); - vinfo("constructing z_perm"); + // vinfo("constructing z_perm"); // Allocate the z_perm polynomial proving_key.polynomials.z_perm = Polynomial::shiftable(proving_key.circuit_size); @@ -236,7 +236,7 @@ template class DeciderProvingKey_ { { PROFILE_THIS_NAME("allocating lagrange polynomials"); - vinfo("allocating lagrange polynomials"); + // vinfo("allocating lagrange polynomials"); // First and last lagrange polynomials (in the full circuit size) proving_key.polynomials.lagrange_first = Polynomial(1, dyadic_circuit_size, 0); @@ -253,12 +253,12 @@ template class DeciderProvingKey_ { { PROFILE_THIS_NAME("constructing prover instance after trace populate"); - vinfo("constructing prover instance after trace populate"); + // vinfo("constructing prover instance after trace populate"); // If Goblin, construct the databus polynomials if constexpr (IsGoblinFlavor) { PROFILE_THIS_NAME("constructing databus polynomials"); - vinfo("constructing databus polynomials"); + // vinfo("constructing databus polynomials"); construct_databus_polynomials(circuit); } @@ -269,7 +269,7 @@ template class DeciderProvingKey_ { { PROFILE_THIS_NAME("constructing lookup table polynomials"); - vinfo("constructing lookup table polynomials"); + // vinfo("constructing lookup table polynomials"); construct_lookup_table_polynomials( proving_key.polynomials.get_tables(), circuit, dyadic_circuit_size); @@ -277,7 +277,7 @@ template class DeciderProvingKey_ { { PROFILE_THIS_NAME("constructing lookup read counts"); - vinfo("constructing lookup read counts"); + // vinfo("constructing lookup read counts"); construct_lookup_read_counts(proving_key.polynomials.lookup_read_counts, proving_key.polynomials.lookup_read_tags, From 3ad39c160914fbdbf5c80fa2b81daf9a22dabf5b Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 21 Oct 2024 18:37:56 +0000 Subject: [PATCH 08/28] remove outdated TODO --- .../src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp index bedd0fd974e..0e71e04d309 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp @@ -59,8 +59,6 @@ ProtogalaxyProver_::perturbator_round( : Polynomial(CONST_PG_LOG_N + 1); // Prover doesn't send the constant coefficient of F because this is supposed to be equal to the target sum of // the accumulator which the folding verifier has from the previous iteration. - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1087): Verifier circuit for first IVC step is - // different for (size_t idx = 1; idx <= CONST_PG_LOG_N; idx++) { transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); } From d6be6f6fb8d488918075a59de98a66618f308327 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 21 Oct 2024 22:22:29 +0000 Subject: [PATCH 09/28] come basic write vk infra in place but untested --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 108 ++++++++++++++++++ .../barretenberg/client_ivc/client_ivc.cpp | 8 ++ .../dsl/acir_format/recursion_constraint.cpp | 50 ++++++++ .../dsl/acir_format/recursion_constraint.hpp | 15 +++ 4 files changed, 181 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index f0f958c3403..e9f39ff9f22 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -1266,6 +1266,114 @@ template void write_vk_honk(const std::string& bytecodePa } } +/** + * @brief Compute and write to file the VK for a circuit to be accumulated in the IVC + * + * WORKTODO: I worry that this is too complicated/manual/brittle. I wonder if its possible to + * simply generate the vks by running a full ivc. For a given trace structure setting, a kernel + * of a given type has a fixed VK. E.g. the init will always have a single oink verifier, the + * reset will always have a single PG verifier etc. We could run the IVC on a given set of circuits + * that includes all these kernels.. eh no seems to interdependent. + * + * It seems like we really want something that can be called on an individual circuit and return + * a deterministic VK. The only issue with this is any location dependence on the kernels. I think + * the only place this could arise is in the databus but lets see. The propagation of return data + * commitments on the PI is just based on how many proofs are being recursively verified so thats + * fully determined by the number of ivc rec constraints. The consistency checks would seem to be + * somewhat order dependent because they check a transfer of data that happened in the past. This + * means that we can only independently compute the VKs for each kernel type if the ordering of + * those kernels is always predictable. I think this is likely not the case because take for example + * a kernel_final or whatever. This might fall after an inner-reset pair or maybe just after an + * inner. In general it would seem that the ordering will determine the databus consistency checks + * which add copy constraints and thus effect the circuit. + * + * Perhaps the only thing that could be done is simply enforce such copy constraints always. Not + * sure its possible but we would have to assume that an input proof always had the alloted + * public inputs for two databus commitments. We would then assert equality between those public + * inputs and the two calldata commitments in the proof. The only difficulty is I'm not sure we + * can assume the apps have these public inputs, se we'd have to somehow know whether the ivc + * recursion constraint in the program corresponds to the verification of an app or a kernel. + * I suppose we may be able to make assumptions about this though because I think certain kernels + * will only ever recursively verifiy kernels. Still tricky though because we dont know the type of + * kernel by the program data alone. Or do we? Maybe a reset/final are the only ones that will have + * a single PG rec verifier? So there are only so many options (1 Oink, 2 PG, 1 PG) and they all + * come with a different set of behaviors. (Or maybe 1 or 2 PG doesnt matter; its the data in a kernel + * proof that's used to set up copy constraints so if you have either 1 or 2 then one must be a kernel + * proof so you impose the copy constraints on that. Fine, but we also now need to ensure that the + * ordering of the verifiers in the kernels is always fixed, e.g. the kernel proof rec verifier always + * comes first/second. When generating the mock kernel completion logic, we'll need to create a mock + * "kernel" proof and a mock app proof - the only difference being the presence of the databus commit + * propagation data in the public inputs. Yikes very complicated. + * + * + * + * @param bytecodePath + * @param witnessPath + */ +void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnessPath, const std::string& outputPath) +{ + using Flavor = MegaFlavor; + using Builder = MegaCircuitBuilder; + using Prover = UltraProver_; + using VerificationKey = Flavor::VerificationKey; + using StdlibVerificationKey = MegaRecursiveFlavor_::VerificationKey; + using FF = Flavor::FF; + + auto constraint_system = get_constraint_system(bytecodePath, /*honk_recursion=*/false); + acir_format::WitnessVector witness = {}; + if (!witnessPath.empty()) { + witness = get_witness(witnessPath); + } + + // The presence of ivc recursion constraints determines whther or not the program is a kernel + bool is_kernel = !constraint_system.ivc_recursion_constraints.empty(); + + Builder builder; + if (is_kernel) { + // if its a kernel, need to populate an ivc with a verification queue corresponding to the ivc recursion + // constraints present in the program + ClientIVC ivc; + ivc.trace_structure = TraceStructure::E2E_FULL_TEST; + for (const auto& constraint : constraint_system.ivc_recursion_constraints) { + + // WORKTODO: I need the VKs from the constraints in order to construct the corresponding dummy proofs. Right + // now there is no constructor of a native VK from a vector of FFs so I'm using the stdlib version with a + // dummy builder. Solution is possibly just to add a constructor for the native vkey. + Builder dummy_builder; + auto stdlib_vk = StdlibVerificationKey::from_witness_indices(dummy_builder, constraint.key); + + // Construct a dummy proof corresponding to the known VK from the recursion constraint. + // databus_propagation_data is needed in order to append the correct number of public inputs due to + // propagated databus commitments. + std::vector proof = + acir_format::construct_dummy_proof_for_ivc(constraint.proof_type, stdlib_vk.databus_propagation_data); + auto proof_type = constraint.proof_type == acir_format::PROOF_TYPE::OINK ? bb::ClientIVC::QUEUE_TYPE::OINK + : bb::ClientIVC::QUEUE_TYPE::PG; + // The VK is known via the ivc recursion constraint and does not need to be populated here + std::shared_ptr vk = nullptr; + ivc.verification_queue.emplace_back(proof, vk, proof_type); + } + builder = acir_format::create_kernel_circuit(constraint_system, ivc, witness); + } else { + builder = acir_format::create_circuit(constraint_system, 0, witness, /*honk_recursion=*/false); + } + + // Construct the verification key via the prover-constructed proving key + Prover prover{ builder }; + init_bn254_crs(prover.proving_key->proving_key.circuit_size); + VerificationKey vk(prover.proving_key->proving_key); + + // Write the VK to file as a buffer + auto serialized_vk = to_buffer(vk); + if (outputPath == "-") { + writeRawBytesToStdout(serialized_vk); + vinfo("vk written to stdout"); + } else { + write_file(outputPath, serialized_vk); + vinfo("vk written to: ", outputPath); + } +} + /** * @brief Write a toml file containing recursive verifier inputs for a given program + witness * diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 66926c1a07d..d1c11a9a49f 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -129,6 +129,14 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) // Peform recursive verification and databus consistency checks for each entry in the verification queue for (auto& [proof, vkey, type] : stdlib_verification_queue) { + info(""); + info("Processing VK: "); + info("is_kernel = ", vkey->databus_propagation_data.is_kernel); + info("contains_app_return_data_commitment = ", + vkey->databus_propagation_data.contains_app_return_data_commitment); + info("contains_kernel_return_data_commitment = ", + vkey->databus_propagation_data.contains_kernel_return_data_commitment); + info(""); perform_recursive_verification_and_databus_consistency_checks(circuit, proof, vkey, type); } stdlib_verification_queue.clear(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp index f0f1fe1bff2..de1befc0eb5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -1,4 +1,5 @@ #include "recursion_constraint.hpp" +#include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" #include "barretenberg/plonk/transcript/transcript_wrappers.hpp" @@ -383,4 +384,53 @@ G1AsFields export_g1_affine_element_as_fields(const g1::affine_element& group_el return G1AsFields{ x_lo, x_hi, y_lo, y_hi }; } +/** + * @brief Construct a genuine but arbitrary proof/vk pair of a given type + * @details This is needed e.g. to pre-compute VKs for kernel circuits which include recursive verifications, + * the inputs of which (proofs, vks) are not known at the time of VK generation. The proofs/vks do not have to + * verify but they do have to have a particular structure. The easisest and most robust way to do this is to + * genuinely construct them for as-small-as-possible circuits for efficiency. + * + * WORKTODO: maybe this method belongs in ivc_recursion_constraint.hpp? + * + * @param proof_type + */ +std::vector construct_dummy_proof_for_ivc(uint32_t proof_type, bb::DatabusPropagationData propagation_data) +{ + using Builder = MegaCircuitBuilder; + + // This method only supports mock OINK or PG proofs + if (proof_type != PROOF_TYPE::OINK && proof_type != PROOF_TYPE::PG) { + info("Invalid type in dummy proof construction!"); + } + + // Construct a dummy circuit with the correct number of public inputs according to the databus propagation data + auto construct_dummy_circuit = [](bb::DatabusPropagationData propagation_data) { + Builder dummy_circuit; + uint32_t num_pub_inputs_to_add = 0; + num_pub_inputs_to_add += 8 * static_cast(propagation_data.contains_app_return_data_commitment); + num_pub_inputs_to_add += 8 * static_cast(propagation_data.contains_kernel_return_data_commitment); + for (size_t i = 0; i < num_pub_inputs_to_add; ++i) { + dummy_circuit.add_public_variable(0); + } + + // WORKTODO: do I need to add PI corresponding to an aggregation object here? + + return dummy_circuit; + }; + + // Construct a mock OINK/PG proof by performing the corresponding number of IVC accumulations of the mock circuit. + // One accumulation produces an oink proof, two produces a PG proof. + ClientIVC ivc; + size_t num_ivc_accumulations = (proof_type == PROOF_TYPE::OINK) ? 1 : 2; + for (size_t i = 0; i < num_ivc_accumulations; ++i) { + Builder dummy_circuit = construct_dummy_circuit(propagation_data); + ivc.accumulate(dummy_circuit); + } + + std::vector proof = ivc.verification_queue.back().proof; + + return proof; +} + } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp index 0c243e6f357..d8309e654b9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp @@ -2,6 +2,7 @@ #include "barretenberg/plonk/proof_system/constants.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" #include "barretenberg/plonk/transcript/transcript_wrappers.hpp" +#include "barretenberg/stdlib_circuit_builders/mega_flavor.hpp" #include namespace acir_format { @@ -108,4 +109,18 @@ template inline void write(B& buf, RecursionConstraint const& const write(buf, constraint.key_hash); } +/** + * @brief Construct a genuine but arbitrary proof/vk pair of a given type + * @details This is needed e.g. to pre-compute VKs for kernel circuits which include recursive verifications, + * the inputs of which (proofs, vks) are not known at the time of VK generation. The proofs/vks do not have to + * verify but they do have to have a particular structure. The easisest and most robust way to do this is to + * genuinely construct them for as-small-as-possible circuits for efficiency. + * + * WORKTODO: maybe this method belongs in ivc_recursion_constraint.hpp? + * + * @param proof_type + */ +std::vector construct_dummy_proof_for_ivc(uint32_t proof_type, + bb::DatabusPropagationData databus_propagation_data); + } // namespace acir_format From 7c36935de3c00d38a2a92d288d7cd4f10086820c Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 22 Oct 2024 17:26:38 +0000 Subject: [PATCH 10/28] move mocking method WiP to new file --- .../dsl/acir_format/acir_format.cpp | 2 + .../acir_format/ivc_recursion_constraint.cpp | 60 +++++++++++++++++++ .../acir_format/ivc_recursion_constraint.hpp | 14 +++++ 3 files changed, 76 insertions(+) create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 471c27e9a12..f17227f4bbc 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -482,6 +482,8 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, ASSERT(false); } + // WORKTODO: construct stdlib keys here only is !witness.empty() + // Construct a stdlib verification key for each constraint based on the verification key witness indices therein std::vector> stdlib_verification_keys; stdlib_verification_keys.reserve(constraint_system.ivc_recursion_constraints.size()); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp new file mode 100644 index 00000000000..942d85e8f53 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -0,0 +1,60 @@ +#include "ivc_recursion_constraint.hpp" +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/plonk_honk_shared/types/aggregation_object_type.hpp" +#include "barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.hpp" +#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" +#include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp" +#include "honk_recursion_constraint.hpp" +#include "proof_surgeon.hpp" + +namespace acir_format { + +using namespace bb; +using field_ct = stdlib::field_t; +using bn254 = stdlib::bn254; +using aggregation_state_ct = bb::stdlib::recursion::aggregation_state; + +ClientIVC create_mock_ivc_from_recursion_constraints( + [[maybe_unused]] const std::vector& ivc_recursion_constraints) +{ + using Builder = ClientIVC::ClientCircuit; + + // Construct a dummy circuit with the correct number of public inputs according to the databus propagation data + auto construct_dummy_circuit = [](bool is_kernel) { + Builder dummy_circuit; + uint32_t num_pub_inputs_to_add = is_kernel ? 16 : 0; + // WORKTODO: do I need to add PI corresponding to an aggregation object here? + for (size_t i = 0; i < num_pub_inputs_to_add; ++i) { + dummy_circuit.add_public_variable(0); + } + + return dummy_circuit; + }; + + // Construct a vector of flags indicating the type of circuit being verified in each recursion constraint + std::vector is_kernel_flags; + if (ivc_recursion_constraints.size() == 1) { + if (ivc_recursion_constraints[0].proof_type == PROOF_TYPE::OINK) { + is_kernel_flags.emplace_back(false); + } else { + is_kernel_flags.emplace_back(true); + } + } + if (ivc_recursion_constraints.size() == 2) { + is_kernel_flags.emplace_back(true); + is_kernel_flags.emplace_back(false); + } + + // Construct a mock ClientIVC corresponding to the above constraints + ClientIVC ivc; + for (const auto is_kernel : is_kernel_flags) { + Builder dummy_circuit = construct_dummy_circuit(is_kernel); + ivc.accumulate(dummy_circuit); + } + + return ClientIVC{}; +} + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp new file mode 100644 index 00000000000..9519abdf0c0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "barretenberg/client_ivc/client_ivc.hpp" +#include "barretenberg/dsl/acir_format/recursion_constraint.hpp" +#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" +#include + +namespace acir_format { +using Builder = bb::UltraCircuitBuilder; + +using namespace bb; + +ClientIVC create_mock_ivc_from_recursion_constraints(std::vector ivc_recursion_constraints); + +} // namespace acir_format From 7ec851b211ceb1bded1e2063c9b407dc119de908 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 11 Nov 2024 17:34:47 +0000 Subject: [PATCH 11/28] get things building again --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 12 +++-- .../barretenberg/client_ivc/client_ivc.cpp | 4 -- .../dsl/acir_format/recursion_constraint.cpp | 5 +- .../barretenberg/dsl/acir_proofs/c_bind.cpp | 2 +- .../ultra_honk/decider_proving_key.hpp | 53 +++++++++---------- 5 files changed, 36 insertions(+), 40 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 6ecba135941..2ade897670f 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -433,7 +433,7 @@ void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytec } // TODO(#7371) dedupe this with the rest of the similar code ClientIVC ivc; - ivc.trace_structure = TraceStructure::E2E_FULL_TEST; + ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; // Accumulate the entire program stack into the IVC for (Program& program : folding_stack) { @@ -447,7 +447,8 @@ void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytec circuit = create_kernel_circuit(program.constraints, ivc, program.witness); } else { info("Creating circuit of type: APP"); - circuit = create_circuit(program.constraints, 0, program.witness, false, ivc.goblin.op_queue); + circuit = create_circuit( + program.constraints, /*recursive=*/false, 0, program.witness, false, ivc.goblin.op_queue); } ivc.accumulate(circuit); @@ -466,7 +467,7 @@ void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytec auto translator_vk = std::make_shared(ivc.goblin.get_translator_proving_key()); auto last_vk = std::make_shared(ivc.honk_vk); - vinfo("ensure valid proof: ", ivc.verify(proof, { ivc.verifier_accumulator, last_vk })); + vinfo("ensure valid proof: ", ivc.verify(proof)); vinfo("write proof and vk data to files.."); write_file(proofPath, to_buffer(proof)); @@ -1327,7 +1328,7 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnes // if its a kernel, need to populate an ivc with a verification queue corresponding to the ivc recursion // constraints present in the program ClientIVC ivc; - ivc.trace_structure = TraceStructure::E2E_FULL_TEST; + ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; for (const auto& constraint : constraint_system.ivc_recursion_constraints) { // WORKTODO: I need the VKs from the constraints in order to construct the corresponding dummy proofs. Right @@ -1349,7 +1350,8 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnes } builder = acir_format::create_kernel_circuit(constraint_system, ivc, witness); } else { - builder = acir_format::create_circuit(constraint_system, 0, witness, /*honk_recursion=*/false); + builder = acir_format::create_circuit( + constraint_system, /*recursive=*/false, 0, witness, /*honk_recursion=*/false); } // Construct the verification key via the prover-constructed proving key diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index eeace507cf1..32163038f80 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -139,10 +139,6 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) info(""); info("Processing VK: "); info("is_kernel = ", vkey->databus_propagation_data.is_kernel); - info("contains_app_return_data_commitment = ", - vkey->databus_propagation_data.contains_app_return_data_commitment); - info("contains_kernel_return_data_commitment = ", - vkey->databus_propagation_data.contains_kernel_return_data_commitment); info(""); perform_recursive_verification_and_databus_consistency_checks(circuit, proof, vkey, type); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp index df991b11401..5711035f987 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -407,11 +407,10 @@ std::vector construct_dummy_proof_for_ivc(uint32_t proof_type, bb::Datab } // Construct a dummy circuit with the correct number of public inputs according to the databus propagation data - auto construct_dummy_circuit = [](bb::DatabusPropagationData propagation_data) { + auto construct_dummy_circuit = []([[maybe_unused]] bb::DatabusPropagationData propagation_data) { Builder dummy_circuit; uint32_t num_pub_inputs_to_add = 0; - num_pub_inputs_to_add += 8 * static_cast(propagation_data.contains_app_return_data_commitment); - num_pub_inputs_to_add += 8 * static_cast(propagation_data.contains_kernel_return_data_commitment); + num_pub_inputs_to_add += bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; for (size_t i = 0; i < num_pub_inputs_to_add; ++i) { dummy_circuit.add_public_variable(0); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index 343f10f134b..2af498e3585 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -239,7 +239,7 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack, // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc; ivc.auto_verify_mode = true; - ivc.trace_structure = TraceStructure::E2E_FULL_TEST; + ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; // Accumulate the entire program stack into the IVC // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once databus diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp index c903a552699..39f48b806c4 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp @@ -288,36 +288,35 @@ template class DeciderProvingKey_ { auto diff = std::chrono::duration_cast(end - start); vinfo("time to construct proving key: ", diff.count(), " ms."); } + } + } - DeciderProvingKey_() = default; - ~DeciderProvingKey_() = default; + DeciderProvingKey_() = default; + ~DeciderProvingKey_() = default; - bool get_is_structured() - { - return is_structured; - } + bool get_is_structured() { return is_structured; } - private: - static constexpr size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; - static constexpr size_t NUM_WIRES = Circuit::NUM_WIRES; - size_t dyadic_circuit_size = 0; // final power-of-2 circuit size - - size_t compute_dyadic_size(Circuit&); - - /** - * @brief Compute dyadic size based on a structured trace with fixed block size - * - */ - size_t compute_structured_dyadic_size(Circuit & circuit) - { - size_t minimum_size = circuit.blocks.get_total_structured_size(); - return circuit.get_circuit_subgroup_size(minimum_size); - } + private: + static constexpr size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; + static constexpr size_t NUM_WIRES = Circuit::NUM_WIRES; + size_t dyadic_circuit_size = 0; // final power-of-2 circuit size + + size_t compute_dyadic_size(Circuit&); + + /** + * @brief Compute dyadic size based on a structured trace with fixed block size + * + */ + size_t compute_structured_dyadic_size(Circuit& circuit) + { + size_t minimum_size = circuit.blocks.get_total_structured_size(); + return circuit.get_circuit_subgroup_size(minimum_size); + } - void construct_databus_polynomials(Circuit&) - requires IsGoblinFlavor; + void construct_databus_polynomials(Circuit&) + requires IsGoblinFlavor; - static void move_structured_trace_overflow_to_overflow_block(Circuit & circuit); - }; + static void move_structured_trace_overflow_to_overflow_block(Circuit& circuit); +}; - } // namespace bb +} // namespace bb From 4c8cb695889d2532f4bf0479c2c3b810838365c3 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 17:43:32 +0000 Subject: [PATCH 12/28] fix build --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 160 +++++++++--------- .../ultra_honk/decider_proving_key.hpp | 2 +- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index f31bf3520dc..4df0d7b2ef4 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -185,84 +185,85 @@ bool proveAndVerifyHonkProgram(const std::string& bytecodePath, const bool recur return true; } -// WORKTODO: this or something similar belongs in api_client_ivc! -void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytecodePath, - const std::string& witnessPath, - const std::string& outputDir) -{ - using Flavor = MegaFlavor; // This is the only option - using Builder = Flavor::CircuitBuilder; - using Program = acir_format::AcirProgram; - using ECCVMVK = ECCVMFlavor::VerificationKey; - using TranslatorVK = TranslatorFlavor::VerificationKey; - using DeciderVerificationKey = ClientIVC::DeciderVerificationKey; - - using namespace acir_format; - - init_bn254_crs(1 << 24); - init_grumpkin_crs(1 << 15); - - auto gzipped_bincodes = unpack_from_file>(bytecodePath); - auto witness_data = unpack_from_file>(witnessPath); - std::vector folding_stack; - for (auto [bincode, wit] : zip_view(gzipped_bincodes, witness_data)) { - // TODO(#7371) there is a lot of copying going on in bincode, we should make sure this writes as a buffer in - // the future - std::vector constraint_buf = - decompressedBuffer(reinterpret_cast(bincode.data()), bincode.size()); // NOLINT - std::vector witness_buf = - decompressedBuffer(reinterpret_cast(wit.data()), wit.size()); // NOLINT - - AcirFormat constraints = circuit_buf_to_acir_format(constraint_buf, /*honk_recursion=*/false); - WitnessVector witness = witness_buf_to_witness_data(witness_buf); - - folding_stack.push_back(Program{ constraints, witness }); - } - // TODO(#7371) dedupe this with the rest of the similar code - ClientIVC ivc; - ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; - - // Accumulate the entire program stack into the IVC - for (Program& program : folding_stack) { - // Construct a bberg circuit from the acir representation then accumulate it into the IVC - MegaCircuitBuilder circuit; - - // Use the presence of IVC recursion constraints to indicate whether or not the program is a kernel - bool is_kernel = !program.constraints.ivc_recursion_constraints.empty(); - if (is_kernel) { - info("Creating circuit of type: KERNEL"); - circuit = create_kernel_circuit(program.constraints, ivc, program.witness); - } else { - info("Creating circuit of type: APP"); - circuit = create_circuit( - program.constraints, /*recursive=*/false, 0, program.witness, false, ivc.goblin.op_queue); - } - - ivc.accumulate(circuit); - } - - // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems this - // directory is passed by bb.js) - std::string vkPath = outputDir + "/final_decider_vk"; // the vk of the last circuit in the stack - std::string accPath = outputDir + "/pg_acc"; - std::string proofPath = outputDir + "/client_ivc_proof"; - std::string translatorVkPath = outputDir + "/translator_vk"; - std::string eccVkPath = outputDir + "/ecc_vk"; - - auto proof = ivc.prove(); - auto eccvm_vk = std::make_shared(ivc.goblin.get_eccvm_proving_key()); - auto translator_vk = std::make_shared(ivc.goblin.get_translator_proving_key()); - - auto last_vk = std::make_shared(ivc.honk_vk); - vinfo("ensure valid proof: ", ivc.verify(proof)); - - vinfo("write proof and vk data to files.."); - write_file(proofPath, to_buffer(proof)); - write_file(vkPath, to_buffer(ivc.honk_vk)); - write_file(accPath, to_buffer(ivc.verifier_accumulator)); - write_file(translatorVkPath, to_buffer(translator_vk)); - write_file(eccVkPath, to_buffer(eccvm_vk)); -} +// // WORKTODO: this or something similar belongs in api_client_ivc! +// void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytecodePath, +// const std::string& witnessPath, +// const std::string& outputDir) +// { +// using Flavor = MegaFlavor; // This is the only option +// using Builder = Flavor::CircuitBuilder; +// using Program = acir_format::AcirProgram; +// using ECCVMVK = ECCVMFlavor::VerificationKey; +// using TranslatorVK = TranslatorFlavor::VerificationKey; +// using DeciderVerificationKey = ClientIVC::DeciderVerificationKey; + +// using namespace acir_format; + +// init_bn254_crs(1 << 24); +// init_grumpkin_crs(1 << 15); + +// auto gzipped_bincodes = unpack_from_file>(bytecodePath); +// auto witness_data = unpack_from_file>(witnessPath); +// std::vector folding_stack; +// for (auto [bincode, wit] : zip_view(gzipped_bincodes, witness_data)) { +// // TODO(#7371) there is a lot of copying going on in bincode, we should make sure this writes as a buffer in +// // the future +// std::vector constraint_buf = +// decompressedBuffer(reinterpret_cast(bincode.data()), bincode.size()); // NOLINT +// std::vector witness_buf = +// decompressedBuffer(reinterpret_cast(wit.data()), wit.size()); // NOLINT + +// AcirFormat constraints = circuit_buf_to_acir_format(constraint_buf, /*honk_recursion=*/false); +// WitnessVector witness = witness_buf_to_witness_data(witness_buf); + +// folding_stack.push_back(Program{ constraints, witness }); +// } +// // TODO(#7371) dedupe this with the rest of the similar code +// ClientIVC ivc; +// ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; + +// // Accumulate the entire program stack into the IVC +// for (Program& program : folding_stack) { +// // Construct a bberg circuit from the acir representation then accumulate it into the IVC +// MegaCircuitBuilder circuit; + +// // Use the presence of IVC recursion constraints to indicate whether or not the program is a kernel +// bool is_kernel = !program.constraints.ivc_recursion_constraints.empty(); +// if (is_kernel) { +// info("Creating circuit of type: KERNEL"); +// circuit = create_kernel_circuit(program.constraints, ivc, program.witness); +// } else { +// info("Creating circuit of type: APP"); +// circuit = create_circuit( +// program.constraints, /*recursive=*/false, 0, program.witness, false, ivc.goblin.op_queue); +// } + +// ivc.accumulate(circuit); +// } + +// // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems +// this +// // directory is passed by bb.js) +// std::string vkPath = outputDir + "/final_decider_vk"; // the vk of the last circuit in the stack +// std::string accPath = outputDir + "/pg_acc"; +// std::string proofPath = outputDir + "/client_ivc_proof"; +// std::string translatorVkPath = outputDir + "/translator_vk"; +// std::string eccVkPath = outputDir + "/ecc_vk"; + +// auto proof = ivc.prove(); +// auto eccvm_vk = std::make_shared(ivc.goblin.get_eccvm_proving_key()); +// auto translator_vk = std::make_shared(ivc.goblin.get_translator_proving_key()); + +// auto last_vk = std::make_shared(ivc.honk_vk); +// vinfo("ensure valid proof: ", ivc.verify(proof)); + +// vinfo("write proof and vk data to files.."); +// write_file(proofPath, to_buffer(proof)); +// write_file(vkPath, to_buffer(ivc.honk_vk)); +// write_file(accPath, to_buffer(ivc.verifier_accumulator)); +// write_file(translatorVkPath, to_buffer(translator_vk)); +// write_file(eccVkPath, to_buffer(eccvm_vk)); +// } /** * @brief Creates a Honk Proof for the Tube circuit responsible for recursively verifying a ClientIVC proof. @@ -978,8 +979,7 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnes if (is_kernel) { // if its a kernel, need to populate an ivc with a verification queue corresponding to the ivc recursion // constraints present in the program - ClientIVC ivc; - ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE } }; for (const auto& constraint : constraint_system.ivc_recursion_constraints) { // WORKTODO: I need the VKs from the constraints in order to construct the corresponding dummy proofs. Right diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp index 9ae43c30df5..91dbeb65121 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp @@ -307,7 +307,7 @@ template class DeciderProvingKey_ { circuit.pairing_point_accumulator_public_input_indices; proving_key.contains_pairing_point_accumulator = circuit.contains_pairing_point_accumulator; - if constexpr (IsGoblinFlavor) { // Set databus commitment propagation data + if constexpr (IsMegaFlavor) { // Set databus commitment propagation data proving_key.databus_propagation_data = circuit.databus_propagation_data; } auto end = std::chrono::steady_clock::now(); From 859d72275e2bbcd81ffcaa43f1fc51eb836610af Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 17:55:36 +0000 Subject: [PATCH 13/28] bit of cleanup --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 5 +- .../dsl/acir_format/recursion_constraint.cpp | 48 ------------------- .../dsl/acir_format/recursion_constraint.hpp | 14 ------ .../cpp/src/barretenberg/goblin/goblin.hpp | 2 - .../ultra_honk/decider_proving_key.hpp | 41 +++------------- 5 files changed, 10 insertions(+), 100 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 4df0d7b2ef4..aba304b3128 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -991,8 +991,9 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnes // Construct a dummy proof corresponding to the known VK from the recursion constraint. // databus_propagation_data is needed in order to append the correct number of public inputs due to // propagated databus commitments. - std::vector proof = - acir_format::construct_dummy_proof_for_ivc(constraint.proof_type, stdlib_vk.databus_propagation_data); + std::vector + proof; /* = + acir_format::construct_dummy_proof_for_ivc(constraint.proof_type, stdlib_vk.databus_propagation_data);*/ auto proof_type = constraint.proof_type == acir_format::PROOF_TYPE::OINK ? bb::ClientIVC::QUEUE_TYPE::OINK : bb::ClientIVC::QUEUE_TYPE::PG; // The VK is known via the ivc recursion constraint and does not need to be populated here diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp index 5711035f987..5263d2c7fc0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -386,52 +386,4 @@ G1AsFields export_g1_affine_element_as_fields(const g1::affine_element& group_el return G1AsFields{ x_lo, x_hi, y_lo, y_hi }; } -/** - * @brief Construct a genuine but arbitrary proof/vk pair of a given type - * @details This is needed e.g. to pre-compute VKs for kernel circuits which include recursive verifications, - * the inputs of which (proofs, vks) are not known at the time of VK generation. The proofs/vks do not have to - * verify but they do have to have a particular structure. The easisest and most robust way to do this is to - * genuinely construct them for as-small-as-possible circuits for efficiency. - * - * WORKTODO: maybe this method belongs in ivc_recursion_constraint.hpp? - * - * @param proof_type - */ -std::vector construct_dummy_proof_for_ivc(uint32_t proof_type, bb::DatabusPropagationData propagation_data) -{ - using Builder = MegaCircuitBuilder; - - // This method only supports mock OINK or PG proofs - if (proof_type != PROOF_TYPE::OINK && proof_type != PROOF_TYPE::PG) { - info("Invalid type in dummy proof construction!"); - } - - // Construct a dummy circuit with the correct number of public inputs according to the databus propagation data - auto construct_dummy_circuit = []([[maybe_unused]] bb::DatabusPropagationData propagation_data) { - Builder dummy_circuit; - uint32_t num_pub_inputs_to_add = 0; - num_pub_inputs_to_add += bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; - for (size_t i = 0; i < num_pub_inputs_to_add; ++i) { - dummy_circuit.add_public_variable(0); - } - - // WORKTODO: do I need to add PI corresponding to an aggregation object here? - - return dummy_circuit; - }; - - // Construct a mock OINK/PG proof by performing the corresponding number of IVC accumulations of the mock circuit. - // One accumulation produces an oink proof, two produces a PG proof. - ClientIVC ivc; - size_t num_ivc_accumulations = (proof_type == PROOF_TYPE::OINK) ? 1 : 2; - for (size_t i = 0; i < num_ivc_accumulations; ++i) { - Builder dummy_circuit = construct_dummy_circuit(propagation_data); - ivc.accumulate(dummy_circuit); - } - - std::vector proof = ivc.verification_queue.back().proof; - - return proof; -} - } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp index a45963ca770..b7f164c8925 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp @@ -110,18 +110,4 @@ template inline void write(B& buf, RecursionConstraint const& const write(buf, constraint.key_hash); } -/** - * @brief Construct a genuine but arbitrary proof/vk pair of a given type - * @details This is needed e.g. to pre-compute VKs for kernel circuits which include recursive verifications, - * the inputs of which (proofs, vks) are not known at the time of VK generation. The proofs/vks do not have to - * verify but they do have to have a particular structure. The easisest and most robust way to do this is to - * genuinely construct them for as-small-as-possible circuits for efficiency. - * - * WORKTODO: maybe this method belongs in ivc_recursion_constraint.hpp? - * - * @param proof_type - */ -std::vector construct_dummy_proof_for_ivc(uint32_t proof_type, - bb::DatabusPropagationData databus_propagation_data); - } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 80024caa9c2..fae8b19ec45 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -295,11 +295,9 @@ class GoblinVerifier { TranslatorVerifier translator_verifier(translator_verification_key, eccvm_verifier.transcript); - vinfo("verify Translator."); bool accumulator_construction_verified = translator_verifier.verify_proof(proof.translator_proof); // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed // correctly - vinfo("verify Translation."); bool translation_verified = translator_verifier.verify_translation(proof.translation_evaluations); vinfo("merge verified?: ", merge_verified); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp index 91dbeb65121..7e114c40a3f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_proving_key.hpp @@ -114,6 +114,12 @@ template class DeciderProvingKey_ { // Allocate the wires and selectors polynomials { PROFILE_THIS_NAME("allocating wires"); + + for (auto& wire : proving_key.polynomials.get_wires()) { + wire = Polynomial::shiftable(proving_key.circuit_size); + } + } + { PROFILE_THIS_NAME("allocating gate selectors"); // Define gate selectors over the block they are isolated to @@ -278,41 +284,8 @@ template class DeciderProvingKey_ { // If Goblin, construct the databus polynomials if constexpr (IsMegaFlavor) { PROFILE_THIS_NAME("constructing databus polynomials"); - proving_key.polynomials.lagrange_last.at(dyadic_circuit_size - 1) = 1; - - { - PROFILE_THIS_NAME("constructing lookup table polynomials"); - - construct_lookup_table_polynomials( - proving_key.polynomials.get_tables(), circuit, dyadic_circuit_size); - } - { - PROFILE_THIS_NAME("constructing lookup read counts"); - - construct_lookup_read_counts(proving_key.polynomials.lookup_read_counts, - proving_key.polynomials.lookup_read_tags, - circuit, - dyadic_circuit_size); - } - - // Construct the public inputs array - for (size_t i = 0; i < proving_key.num_public_inputs; ++i) { - size_t idx = i + proving_key.pub_inputs_offset; - proving_key.public_inputs.emplace_back(proving_key.polynomials.w_r[idx]); - } - - // Set the recursive proof indices - proving_key.pairing_point_accumulator_public_input_indices = - circuit.pairing_point_accumulator_public_input_indices; - proving_key.contains_pairing_point_accumulator = circuit.contains_pairing_point_accumulator; - - if constexpr (IsMegaFlavor) { // Set databus commitment propagation data - proving_key.databus_propagation_data = circuit.databus_propagation_data; - } - auto end = std::chrono::steady_clock::now(); - auto diff = std::chrono::duration_cast(end - start); - vinfo("time to construct proving key: ", diff.count(), " ms."); + construct_databus_polynomials(circuit); } } // Set the lagrange polynomials From 1301bd504c910e6ccb03162c5d401936ff1a3b35 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 19:42:35 +0000 Subject: [PATCH 14/28] update index ts with vk inputs --- noir-projects/mock-protocol-circuits/bootstrap.sh | 2 ++ noir-projects/scripts/generate_vk_json.js | 1 + yarn-project/ivc-integration/src/index.ts | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/noir-projects/mock-protocol-circuits/bootstrap.sh b/noir-projects/mock-protocol-circuits/bootstrap.sh index d4c4ecd8cfd..a3fad4464e5 100755 --- a/noir-projects/mock-protocol-circuits/bootstrap.sh +++ b/noir-projects/mock-protocol-circuits/bootstrap.sh @@ -24,6 +24,8 @@ mkdir -p "./target/keys" PARALLEL_VK=${PARALLEL_VK:-true} +# WORKTODO: VKs getting generated here + if [[ $PARALLEL_VK == "true" ]]; then echo "Generating vks in parallel..." for pathname in "./target"/*.json; do diff --git a/noir-projects/scripts/generate_vk_json.js b/noir-projects/scripts/generate_vk_json.js index c891d1f7ca4..693c8decff1 100644 --- a/noir-projects/scripts/generate_vk_json.js +++ b/noir-projects/scripts/generate_vk_json.js @@ -123,6 +123,7 @@ async function generateVKData( ); const jsonVkPath = vkJsonFileNameForArtifactName(outputFolder, artifactName); + // WORKTODO: possibly just co-opt write_vk_mega_honk to handle apps/kernels const writeVkCommand = `${BB_BIN_PATH} ${ isMegaHonk ? "write_vk_mega_honk" : "write_vk_ultra_honk" } -h -b "${artifactPath}" -o "${binaryVkPath}" ${ diff --git a/yarn-project/ivc-integration/src/index.ts b/yarn-project/ivc-integration/src/index.ts index 584a5760fa8..dab8804a187 100644 --- a/yarn-project/ivc-integration/src/index.ts +++ b/yarn-project/ivc-integration/src/index.ts @@ -160,11 +160,13 @@ export async function generate3FunctionTestingIVCStack(): Promise<[string[], Uin const initWitnessGenResult = await witnessGenMockPrivateKernelInitCircuit({ app_inputs: appWitnessGenResult.publicInputs, tx, + app_vk: getVkAsFields(MockAppCreatorVk), }); logger('generated mock private kernel init witness'); const tailWitnessGenResult = await witnessGenMockPrivateKernelTailCircuit({ prev_kernel_public_inputs: initWitnessGenResult.publicInputs, + kernel_vk: getVkAsFields(MockPrivateKernelResetVk), }); logger('generated mock private kernel tail witness'); @@ -190,10 +192,13 @@ export async function generate6FunctionTestingIVCStack(): Promise<[string[], Uin const initWitnessGenResult = await witnessGenMockPrivateKernelInitCircuit({ app_inputs: creatorAppWitnessGenResult.publicInputs, tx, + app_vk: getVkAsFields(MockAppCreatorVk), }); const innerWitnessGenResult = await witnessGenMockPrivateKernelInnerCircuit({ prev_kernel_public_inputs: initWitnessGenResult.publicInputs, app_inputs: readerAppWitnessGenResult.publicInputs, + app_vk: getVkAsFields(MockAppReaderVk), + kernel_vk: getVkAsFields(MockPrivateKernelInitVk), }); const resetWitnessGenResult = await witnessGenMockPrivateKernelResetCircuit({ @@ -204,10 +209,12 @@ export async function generate6FunctionTestingIVCStack(): Promise<[string[], Uin MOCK_MAX_COMMITMENTS_PER_TX.toString(), MOCK_MAX_COMMITMENTS_PER_TX.toString(), ], + kernel_vk: getVkAsFields(MockPrivateKernelInnerVk), }); const tailWitnessGenResult = await witnessGenMockPrivateKernelTailCircuit({ prev_kernel_public_inputs: resetWitnessGenResult.publicInputs, + kernel_vk: getVkAsFields(MockPrivateKernelResetVk), }); // Create client IVC proof From ba13fa3a37f9df7966666b8d308d7d735ab2b97d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 20:20:13 +0000 Subject: [PATCH 15/28] update write vk for ivc --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 91 ++++--------------- 1 file changed, 18 insertions(+), 73 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index aba304b3128..fa117e8c9a1 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -9,6 +9,7 @@ #include "barretenberg/constants.hpp" #include "barretenberg/dsl/acir_format/acir_format.hpp" #include "barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp" +#include "barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp" #include "barretenberg/dsl/acir_format/proof_surgeon.hpp" #include "barretenberg/dsl/acir_proofs/acir_composer.hpp" #include "barretenberg/dsl/acir_proofs/honk_contract.hpp" @@ -916,98 +917,42 @@ void write_vk_honk(const std::string& bytecodePath, const std::string& outputPat /** * @brief Compute and write to file the VK for a circuit to be accumulated in the IVC * - * WORKTODO: I worry that this is too complicated/manual/brittle. I wonder if its possible to - * simply generate the vks by running a full ivc. For a given trace structure setting, a kernel - * of a given type has a fixed VK. E.g. the init will always have a single oink verifier, the - * reset will always have a single PG verifier etc. We could run the IVC on a given set of circuits - * that includes all these kernels.. eh no seems to interdependent. - * - * It seems like we really want something that can be called on an individual circuit and return - * a deterministic VK. The only issue with this is any location dependence on the kernels. I think - * the only place this could arise is in the databus but lets see. The propagation of return data - * commitments on the PI is just based on how many proofs are being recursively verified so thats - * fully determined by the number of ivc rec constraints. The consistency checks would seem to be - * somewhat order dependent because they check a transfer of data that happened in the past. This - * means that we can only independently compute the VKs for each kernel type if the ordering of - * those kernels is always predictable. I think this is likely not the case because take for example - * a kernel_final or whatever. This might fall after an inner-reset pair or maybe just after an - * inner. In general it would seem that the ordering will determine the databus consistency checks - * which add copy constraints and thus effect the circuit. - * - * Perhaps the only thing that could be done is simply enforce such copy constraints always. Not - * sure its possible but we would have to assume that an input proof always had the alloted - * public inputs for two databus commitments. We would then assert equality between those public - * inputs and the two calldata commitments in the proof. The only difficulty is I'm not sure we - * can assume the apps have these public inputs, se we'd have to somehow know whether the ivc - * recursion constraint in the program corresponds to the verification of an app or a kernel. - * I suppose we may be able to make assumptions about this though because I think certain kernels - * will only ever recursively verifiy kernels. Still tricky though because we dont know the type of - * kernel by the program data alone. Or do we? Maybe a reset/final are the only ones that will have - * a single PG rec verifier? So there are only so many options (1 Oink, 2 PG, 1 PG) and they all - * come with a different set of behaviors. (Or maybe 1 or 2 PG doesnt matter; its the data in a kernel - * proof that's used to set up copy constraints so if you have either 1 or 2 then one must be a kernel - * proof so you impose the copy constraints on that. Fine, but we also now need to ensure that the - * ordering of the verifiers in the kernels is always fixed, e.g. the kernel proof rec verifier always - * comes first/second. When generating the mock kernel completion logic, we'll need to create a mock - * "kernel" proof and a mock app proof - the only difference being the presence of the databus commit - * propagation data in the public inputs. Yikes very complicated. - * - * - * * @param bytecodePath * @param witnessPath */ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnessPath, const std::string& outputPath) { - using Flavor = MegaFlavor; - using Builder = MegaCircuitBuilder; - using Prover = UltraProver_; - using VerificationKey = Flavor::VerificationKey; - using StdlibVerificationKey = MegaRecursiveFlavor_::VerificationKey; - using FF = Flavor::FF; + using Builder = ClientIVC::ClientCircuit; + using Prover = ClientIVC::MegaProver; + using DeciderProvingKey = ClientIVC::DeciderProvingKey; + using VerificationKey = ClientIVC::MegaVerificationKey; - auto constraint_system = get_constraint_system(bytecodePath, /*honk_recursion=*/false); + auto constraints = get_constraint_system(bytecodePath, /*honk_recursion=*/false); acir_format::WitnessVector witness = {}; if (!witnessPath.empty()) { witness = get_witness(witnessPath); } + // WORKTODO: should be based on some default maybe? + TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; // The presence of ivc recursion constraints determines whther or not the program is a kernel - bool is_kernel = !constraint_system.ivc_recursion_constraints.empty(); + bool is_kernel = !constraints.ivc_recursion_constraints.empty(); Builder builder; if (is_kernel) { - // if its a kernel, need to populate an ivc with a verification queue corresponding to the ivc recursion - // constraints present in the program - ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE } }; - for (const auto& constraint : constraint_system.ivc_recursion_constraints) { - - // WORKTODO: I need the VKs from the constraints in order to construct the corresponding dummy proofs. Right - // now there is no constructor of a native VK from a vector of FFs so I'm using the stdlib version with a - // dummy builder. Solution is possibly just to add a constructor for the native vkey. - Builder dummy_builder; - auto stdlib_vk = StdlibVerificationKey::from_witness_indices(dummy_builder, constraint.key); - - // Construct a dummy proof corresponding to the known VK from the recursion constraint. - // databus_propagation_data is needed in order to append the correct number of public inputs due to - // propagated databus commitments. - std::vector - proof; /* = - acir_format::construct_dummy_proof_for_ivc(constraint.proof_type, stdlib_vk.databus_propagation_data);*/ - auto proof_type = constraint.proof_type == acir_format::PROOF_TYPE::OINK ? bb::ClientIVC::QUEUE_TYPE::OINK - : bb::ClientIVC::QUEUE_TYPE::PG; - // The VK is known via the ivc recursion constraint and does not need to be populated here - std::shared_ptr vk = nullptr; - ivc.verification_queue.emplace_back(proof, vk, proof_type); - } - builder = acir_format::create_kernel_circuit(constraint_system, ivc, witness); + // Create a mock IVC instance from the IVC recursion constraints in the kernel program + ClientIVC mock_ivc = create_mock_ivc_from_constraints(constraints.ivc_recursion_constraints, trace_settings); + + builder = acir_format::create_kernel_circuit(constraints, mock_ivc, witness); + builder.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(builder)); } else { builder = acir_format::create_circuit( - constraint_system, /*recursive=*/false, 0, witness, /*honk_recursion=*/false); + constraints, /*recursive=*/false, 0, witness, /*honk_recursion=*/false); } - // Construct the verification key via the prover-constructed proving key - Prover prover{ builder }; + // Construct the verification key via the prover-constructed proving key with the proper trace settings + auto proving_key = std::make_shared(builder, trace_settings); + Prover prover{ proving_key }; init_bn254_crs(prover.proving_key->proving_key.circuit_size); VerificationKey vk(prover.proving_key->proving_key); From 357f4a72920e72f1ac06c1e867b50e810ab00d30 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 21:23:56 +0000 Subject: [PATCH 16/28] WiP skip auto verify path in ivc api --- barretenberg/cpp/src/barretenberg/bb/api.hpp | 5 +- .../src/barretenberg/bb/api_client_ivc.hpp | 48 ++++++++++++++++++- barretenberg/cpp/src/barretenberg/bb/main.cpp | 7 ++- .../src/native_client_ivc_integration.test.ts | 1 + 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api.hpp b/barretenberg/cpp/src/barretenberg/bb/api.hpp index f33568f1869..0a9cd0f8736 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api.hpp @@ -6,8 +6,9 @@ namespace bb { class API { public: struct Flags { - std::optional output_type; // bytes, fields, bytes_and_fields, fields_msgpack - std::optional input_type; // compiletime_stack, runtime_stack + std::optional output_type; // bytes, fields, bytes_and_fields, fields_msgpack + std::optional input_type; // compiletime_stack, runtime_stack + std::optional skip_auto_verify; // WORKTODO: will go away when this is only option }; virtual void prove(const Flags& flags, diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index 37b251bd8cf..7c924e73864 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -163,6 +163,44 @@ class ClientIVCAPI : public API { return ivc; }; + static ClientIVC _accumulate_without_auto_verify(std::vector& folding_stack) + { + using Builder = MegaCircuitBuilder; + using Program = acir_format::AcirProgram; + + using namespace acir_format; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); + + // TODO(#7371) dedupe this with the rest of the similar code + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; + + // Accumulate the entire program stack into the IVC + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once + // databus has been integrated into noir kernel programs + bool is_kernel = false; + for (Program& program : folding_stack) { + // Construct a bberg circuit from the acir representation then accumulate it into the IVC + Builder circuit = acir_format::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) { + circuit.databus_propagation_data.is_kernel = is_kernel; + } + is_kernel = !is_kernel; + + // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this + // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced. + ivc.accumulate(circuit, /*one_circuit=*/folding_stack.size() == 1); + } + + return ivc; + }; + public: void prove(const API::Flags& flags, const std::filesystem::path& bytecode_path, @@ -176,10 +214,16 @@ class ClientIVCAPI : public API { if (!flags.input_type || !(*flags.input_type == "compiletime_stack" || *flags.input_type == "runtime_stack")) { throw_or_abort("No input_type or input_type not supported"); } - std::vector folding_stack = _build_folding_stack(*flags.input_type, bytecode_path, witness_path); - ClientIVC ivc = _accumulate(folding_stack); + ClientIVC ivc; + if (flags.skip_auto_verify) { + vinfo("performing accumulation WITHOUT auto-verify"); + ivc = _accumulate_without_auto_verify(folding_stack); + } else { + vinfo("performing accumulation WITH auto-verify"); + ivc = _accumulate(folding_stack); + } ClientIVC::Proof proof = ivc.prove(); // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index fa117e8c9a1..0fe63823fc5 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -920,7 +920,7 @@ void write_vk_honk(const std::string& bytecodePath, const std::string& outputPat * @param bytecodePath * @param witnessPath */ -void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnessPath, const std::string& outputPath) +void write_vk_for_ivc(const std::string& bytecodePath, const std::string& outputPath) { using Builder = ClientIVC::ClientCircuit; using Prover = ClientIVC::MegaProver; @@ -929,9 +929,7 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& witnes auto constraints = get_constraint_system(bytecodePath, /*honk_recursion=*/false); acir_format::WitnessVector witness = {}; - if (!witnessPath.empty()) { - witness = get_witness(witnessPath); - } + // WORKTODO: should be based on some default maybe? TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; @@ -1361,6 +1359,7 @@ int main(int argc, char* argv[]) } else if (command == "write_vk_mega_honk") { std::string output_path = get_option(args, "-o", "./target/vk"); write_vk_honk(bytecode_path, output_path, recursive); + // write_vk_for_ivc(bytecode_path, output_path); } 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/yarn-project/ivc-integration/src/native_client_ivc_integration.test.ts b/yarn-project/ivc-integration/src/native_client_ivc_integration.test.ts index 6f413b19a94..2b891891043 100644 --- a/yarn-project/ivc-integration/src/native_client_ivc_integration.test.ts +++ b/yarn-project/ivc-integration/src/native_client_ivc_integration.test.ts @@ -40,6 +40,7 @@ describe('Client IVC Integration', () => { path.join(bbWorkingDirectory, 'acir.msgpack'), path.join(bbWorkingDirectory, 'witnesses.msgpack'), logger.info, + true, ); if (provingResult.status === BB_RESULT.FAILURE) { From 9c61152bd652d5123f9ce89c56167e5321ed3dac Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 01:16:58 +0000 Subject: [PATCH 17/28] delete old code --- .../src/wasm_client_ivc_integration.test.ts | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts b/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts index d183d347bd0..5f105b7f71e 100644 --- a/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts +++ b/yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts @@ -34,31 +34,6 @@ jest.setTimeout(120_000); describe('Client IVC Integration', () => { beforeEach(async () => {}); - // WORKTODO: need the 'true' below to skip auto verify. How to update new interface to use this? - // beforeEach(async () => { - // // Create a temp working dir - // bbWorkingDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-client-ivc-integration-')); - // bbBinaryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../barretenberg/cpp/build/bin', 'bb'); - // }); - - // async function createClientIvcProof(witnessStack: Uint8Array[], bytecodes: string[]): Promise { - // await fs.writeFile( - // path.join(bbWorkingDirectory, 'acir.msgpack'), - // encode(bytecodes.map(bytecode => Buffer.from(bytecode, 'base64'))), - // ); - - // await fs.writeFile(path.join(bbWorkingDirectory, 'witnesses.msgpack'), encode(witnessStack)); - // const provingResult = await executeBbClientIvcProof( - // bbBinaryPath, - // bbWorkingDirectory, - // path.join(bbWorkingDirectory, 'acir.msgpack'), - // path.join(bbWorkingDirectory, 'witnesses.msgpack'), - // logger.info, - // true, - // ); - - // if (provingResult.status === BB_RESULT.FAILURE) { - // throw new Error(provingResult.reason); function base64ToUint8Array(base64: string) { const binaryString = atob(base64); const len = binaryString.length; From 1b70bacab2852e1d332ff9123a0eab87cc2877b8 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 01:33:40 +0000 Subject: [PATCH 18/28] WiP; test passes with old settings --- .../cpp/src/barretenberg/bb/api_client_ivc.hpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index 7c924e73864..8ba87da1d01 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -133,6 +133,7 @@ class ClientIVCAPI : public API { using namespace acir_format; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + vinfo("initializing BN254 CRS..."); init_bn254_crs(1 << 20); init_grumpkin_crs(1 << 15); @@ -214,16 +215,17 @@ class ClientIVCAPI : public API { if (!flags.input_type || !(*flags.input_type == "compiletime_stack" || *flags.input_type == "runtime_stack")) { throw_or_abort("No input_type or input_type not supported"); } + vinfo("building folding stack..."); std::vector folding_stack = _build_folding_stack(*flags.input_type, bytecode_path, witness_path); - ClientIVC ivc; - if (flags.skip_auto_verify) { - vinfo("performing accumulation WITHOUT auto-verify"); - ivc = _accumulate_without_auto_verify(folding_stack); - } else { - vinfo("performing accumulation WITH auto-verify"); - ivc = _accumulate(folding_stack); - } + // ClientIVC ivc; + // if (flags.skip_auto_verify) { + // vinfo("performing accumulation WITHOUT auto-verify"); + // ivc = _accumulate_without_auto_verify(folding_stack); + // } else { + vinfo("performing accumulation WITH auto-verify"); + ClientIVC ivc = _accumulate(folding_stack); + // } ClientIVC::Proof proof = ivc.prove(); // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems From 3b47361a24b343ce1423f62bd93e0f7179ecea36 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 16:13:43 +0000 Subject: [PATCH 19/28] test passes with no auto verify and internal VKs --- barretenberg/cpp/src/barretenberg/bb/api.hpp | 6 +-- .../src/barretenberg/bb/api_client_ivc.hpp | 50 +++++++++++-------- barretenberg/cpp/src/barretenberg/bb/main.cpp | 3 +- yarn-project/bb-prover/src/bb/execute.ts | 6 +-- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api.hpp b/barretenberg/cpp/src/barretenberg/bb/api.hpp index 0a9cd0f8736..ad9bee63e40 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api.hpp @@ -6,9 +6,9 @@ namespace bb { class API { public: struct Flags { - std::optional output_type; // bytes, fields, bytes_and_fields, fields_msgpack - std::optional input_type; // compiletime_stack, runtime_stack - std::optional skip_auto_verify; // WORKTODO: will go away when this is only option + std::optional output_type; // bytes, fields, bytes_and_fields, fields_msgpack + std::optional input_type; // compiletime_stack, runtime_stack + std::optional no_auto_verify; // WORKTODO: will go away when this is only option }; virtual void prove(const Flags& flags, diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index 8ba87da1d01..d8768b70c88 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -132,10 +132,10 @@ class ClientIVCAPI : public API { using namespace acir_format; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically - vinfo("initializing BN254 CRS..."); - init_bn254_crs(1 << 20); - init_grumpkin_crs(1 << 15); + // // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + // vinfo("initializing BN254 CRS..."); + // init_bn254_crs(1 << 20); + // init_grumpkin_crs(1 << 15); // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode @@ -177,22 +177,25 @@ class ClientIVCAPI : public API { // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode - ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/false }; // Accumulate the entire program stack into the IVC // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once // databus has been integrated into noir kernel programs bool is_kernel = false; for (Program& program : folding_stack) { - // Construct a bberg circuit from the acir representation then accumulate it into the IVC - Builder circuit = acir_format::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) { - circuit.databus_propagation_data.is_kernel = is_kernel; + Builder circuit; + + is_kernel = !program.constraints.ivc_recursion_constraints.empty(); + if (is_kernel) { + vinfo("Accumulating KERNEL."); + circuit = create_kernel_circuit(program.constraints, ivc, program.witness); + } else { + vinfo("Accumulating APP."); + circuit = create_circuit( + program.constraints, /*recursive=*/false, 0, program.witness, false, ivc.goblin.op_queue); } - is_kernel = !is_kernel; // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced. @@ -218,14 +221,21 @@ class ClientIVCAPI : public API { vinfo("building folding stack..."); std::vector folding_stack = _build_folding_stack(*flags.input_type, bytecode_path, witness_path); - // ClientIVC ivc; - // if (flags.skip_auto_verify) { - // vinfo("performing accumulation WITHOUT auto-verify"); - // ivc = _accumulate_without_auto_verify(folding_stack); - // } else { - vinfo("performing accumulation WITH auto-verify"); - ClientIVC ivc = _accumulate(folding_stack); - // } + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + vinfo("initializing BN254 CRS..."); + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); + + ClientIVC ivc; + if (flags.no_auto_verify) { + // if (false) { + vinfo("performing accumulation WITHOUT auto-verify"); + ivc = _accumulate_without_auto_verify(folding_stack); + } else { + vinfo("performing accumulation WITH auto-verify"); + ivc = _accumulate(folding_stack); + } ClientIVC::Proof proof = ivc.prove(); // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 0fe63823fc5..8b3ced5d4eb 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -1205,7 +1205,8 @@ int main(int argc, char* argv[]) const API::Flags flags = [&args]() { return API::Flags{ .output_type = get_option(args, "--output_type", "fields_msgpack"), - .input_type = get_option(args, "--input_type", "compiletime_stack") }; + .input_type = get_option(args, "--input_type", "compiletime_stack"), + .no_auto_verify = flag_present(args, "--no_auto_verify") }; }(); const std::string command = args[0]; diff --git a/yarn-project/bb-prover/src/bb/execute.ts b/yarn-project/bb-prover/src/bb/execute.ts index 711a20a0028..1450fe215ac 100644 --- a/yarn-project/bb-prover/src/bb/execute.ts +++ b/yarn-project/bb-prover/src/bb/execute.ts @@ -202,7 +202,7 @@ export async function executeBbClientIvcProof( bytecodeStackPath: string, witnessStackPath: string, log: LogFn, - skipAutoVerify = false, + noAutoVerify = false, ): Promise { // Check that the working directory exists try { @@ -239,8 +239,8 @@ export async function executeBbClientIvcProof( '--input_type', 'runtime_stack', ]; - if (skipAutoVerify) { - args.push('--skip_auto_verify'); + if (noAutoVerify) { + args.push('--no_auto_verify'); } const timer = new Timer(); const logFunction = (message: string) => { From 7121402a3239ac4009878a6c04058fa124d8fbc1 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 16:18:17 +0000 Subject: [PATCH 20/28] clear out old method --- .../src/barretenberg/bb/api_client_ivc.hpp | 2 +- barretenberg/cpp/src/barretenberg/bb/main.cpp | 80 ------------------- 2 files changed, 1 insertion(+), 81 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index d8768b70c88..fd0139c408c 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -198,7 +198,7 @@ class ClientIVCAPI : public API { } // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this - // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced. + // case, no work is added to the Goblin opqueue, but VM proofs for trivial inputs are produced. ivc.accumulate(circuit, /*one_circuit=*/folding_stack.size() == 1); } diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 8b3ced5d4eb..c6e51f5b440 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -186,86 +186,6 @@ bool proveAndVerifyHonkProgram(const std::string& bytecodePath, const bool recur return true; } -// // WORKTODO: this or something similar belongs in api_client_ivc! -// void client_ivc_prove_output_all_msgpack_no_auto_verify(const std::string& bytecodePath, -// const std::string& witnessPath, -// const std::string& outputDir) -// { -// using Flavor = MegaFlavor; // This is the only option -// using Builder = Flavor::CircuitBuilder; -// using Program = acir_format::AcirProgram; -// using ECCVMVK = ECCVMFlavor::VerificationKey; -// using TranslatorVK = TranslatorFlavor::VerificationKey; -// using DeciderVerificationKey = ClientIVC::DeciderVerificationKey; - -// using namespace acir_format; - -// init_bn254_crs(1 << 24); -// init_grumpkin_crs(1 << 15); - -// auto gzipped_bincodes = unpack_from_file>(bytecodePath); -// auto witness_data = unpack_from_file>(witnessPath); -// std::vector folding_stack; -// for (auto [bincode, wit] : zip_view(gzipped_bincodes, witness_data)) { -// // TODO(#7371) there is a lot of copying going on in bincode, we should make sure this writes as a buffer in -// // the future -// std::vector constraint_buf = -// decompressedBuffer(reinterpret_cast(bincode.data()), bincode.size()); // NOLINT -// std::vector witness_buf = -// decompressedBuffer(reinterpret_cast(wit.data()), wit.size()); // NOLINT - -// AcirFormat constraints = circuit_buf_to_acir_format(constraint_buf, /*honk_recursion=*/false); -// WitnessVector witness = witness_buf_to_witness_data(witness_buf); - -// folding_stack.push_back(Program{ constraints, witness }); -// } -// // TODO(#7371) dedupe this with the rest of the similar code -// ClientIVC ivc; -// ivc.trace_settings.structure = TraceStructure::E2E_FULL_TEST; - -// // Accumulate the entire program stack into the IVC -// for (Program& program : folding_stack) { -// // Construct a bberg circuit from the acir representation then accumulate it into the IVC -// MegaCircuitBuilder circuit; - -// // Use the presence of IVC recursion constraints to indicate whether or not the program is a kernel -// bool is_kernel = !program.constraints.ivc_recursion_constraints.empty(); -// if (is_kernel) { -// info("Creating circuit of type: KERNEL"); -// circuit = create_kernel_circuit(program.constraints, ivc, program.witness); -// } else { -// info("Creating circuit of type: APP"); -// circuit = create_circuit( -// program.constraints, /*recursive=*/false, 0, program.witness, false, ivc.goblin.op_queue); -// } - -// ivc.accumulate(circuit); -// } - -// // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems -// this -// // directory is passed by bb.js) -// std::string vkPath = outputDir + "/final_decider_vk"; // the vk of the last circuit in the stack -// std::string accPath = outputDir + "/pg_acc"; -// std::string proofPath = outputDir + "/client_ivc_proof"; -// std::string translatorVkPath = outputDir + "/translator_vk"; -// std::string eccVkPath = outputDir + "/ecc_vk"; - -// auto proof = ivc.prove(); -// auto eccvm_vk = std::make_shared(ivc.goblin.get_eccvm_proving_key()); -// auto translator_vk = std::make_shared(ivc.goblin.get_translator_proving_key()); - -// auto last_vk = std::make_shared(ivc.honk_vk); -// vinfo("ensure valid proof: ", ivc.verify(proof)); - -// vinfo("write proof and vk data to files.."); -// write_file(proofPath, to_buffer(proof)); -// write_file(vkPath, to_buffer(ivc.honk_vk)); -// write_file(accPath, to_buffer(ivc.verifier_accumulator)); -// write_file(translatorVkPath, to_buffer(translator_vk)); -// write_file(eccVkPath, to_buffer(eccvm_vk)); -// } - /** * @brief Creates a Honk Proof for the Tube circuit responsible for recursively verifying a ClientIVC proof. * From d789d3298b654238bb65dc793b9cbd8589b25659 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 18:23:28 +0000 Subject: [PATCH 21/28] generate vks for ivc integration seems to work --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 8 ++++- noir-projects/ivc_integration_circuits.json | 8 +++++ noir-projects/mega_honk_circuits.json | 10 +++--- noir-projects/scripts/generate_vk_json.js | 34 ++++++++++++++++--- 4 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 noir-projects/ivc_integration_circuits.json diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index c6e51f5b440..f70e43abc71 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -847,6 +847,10 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& output using DeciderProvingKey = ClientIVC::DeciderProvingKey; using VerificationKey = ClientIVC::MegaVerificationKey; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); + auto constraints = get_constraint_system(bytecodePath, /*honk_recursion=*/false); acir_format::WitnessVector witness = {}; @@ -1280,7 +1284,9 @@ int main(int argc, char* argv[]) } else if (command == "write_vk_mega_honk") { std::string output_path = get_option(args, "-o", "./target/vk"); write_vk_honk(bytecode_path, output_path, recursive); - // write_vk_for_ivc(bytecode_path, output_path); + } else if (command == "write_vk_for_ivc") { + std::string output_path = get_option(args, "-o", "./target/vk"); + write_vk_for_ivc(bytecode_path, output_path); } 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/noir-projects/ivc_integration_circuits.json b/noir-projects/ivc_integration_circuits.json new file mode 100644 index 00000000000..01971872d1f --- /dev/null +++ b/noir-projects/ivc_integration_circuits.json @@ -0,0 +1,8 @@ +[ + "mock_private_kernel_init", + "mock_private_kernel_inner", + "mock_private_kernel_reset.*", + "mock_private_kernel_tail.*", + "app_creator", + "app_reader" +] \ No newline at end of file diff --git a/noir-projects/mega_honk_circuits.json b/noir-projects/mega_honk_circuits.json index 98b0104f17e..1db696b11e6 100644 --- a/noir-projects/mega_honk_circuits.json +++ b/noir-projects/mega_honk_circuits.json @@ -1,8 +1,6 @@ [ - "private_kernel_init", - "private_kernel_inner", - "private_kernel_reset.*", - "private_kernel_tail.*", - "app_creator", - "app_reader" + "^private_kernel_init", + "^private_kernel_inner", + "^private_kernel_reset.*", + "^private_kernel_tail.*" ] \ No newline at end of file diff --git a/noir-projects/scripts/generate_vk_json.js b/noir-projects/scripts/generate_vk_json.js index 693c8decff1..98f9b8f86ef 100644 --- a/noir-projects/scripts/generate_vk_json.js +++ b/noir-projects/scripts/generate_vk_json.js @@ -4,6 +4,7 @@ const child_process = require("child_process"); const crypto = require("crypto"); const megaHonkPatterns = require("../mega_honk_circuits.json"); +const ivcIntegrationPatterns = require("../ivc_integration_circuits.json"); const { readVKFromS3, writeVKToS3, @@ -32,13 +33,19 @@ async function getBytecodeHash(artifactPath) { return crypto.createHash("md5").update(bytecode).digest("hex"); } -async function getArtifactHash(artifactPath, isMegaHonk, isRecursive) { +async function getArtifactHash( + artifactPath, + isMegaHonk, + isIvcIntegration, + isRecursive +) { const bytecodeHash = await getBytecodeHash(artifactPath); const barretenbergHash = await getBarretenbergHash(); return generateArtifactHash( barretenbergHash, bytecodeHash, isMegaHonk, + isIvcIntegration, isRecursive ); } @@ -66,14 +73,21 @@ function isMegaHonkCircuit(artifactName) { artifactName.match(new RegExp(pattern)) ); } +function isIvcIntegrationCircuit(artifactName) { + return ivcIntegrationPatterns.some((pattern) => + artifactName.match(new RegExp(pattern)) + ); +} async function processArtifact(artifactPath, artifactName, outputFolder) { const isMegaHonk = isMegaHonkCircuit(artifactName); + const isIvcIntegration = isIvcIntegrationCircuit(artifactName); const isRecursive = true; const artifactHash = await getArtifactHash( artifactPath, isMegaHonk, + isIvcIntegration, isRecursive ); @@ -93,6 +107,7 @@ async function processArtifact(artifactPath, artifactName, outputFolder) { artifactPath, artifactHash, isMegaHonk, + isIvcIntegration, isRecursive ); await writeVKToS3(artifactName, artifactHash, JSON.stringify(vkData)); @@ -109,10 +124,13 @@ async function generateVKData( artifactPath, artifactHash, isMegaHonk, + isIvcIntegration, isRecursive ) { if (isMegaHonk) { console.log("Generating new mega honk vk for", artifactName); + } else if (isIvcIntegration) { + console.log("Generating new IVC vk for", artifactName); } else { console.log("Generating new vk for", artifactName); } @@ -123,17 +141,23 @@ async function generateVKData( ); const jsonVkPath = vkJsonFileNameForArtifactName(outputFolder, artifactName); + function getVkCommand() { + if (isMegaHonk) return "write_vk_mega_honk"; + if (isIvcIntegration) return "write_vk_for_ivc"; + return "write_vk_ultra_honk"; + } + // WORKTODO: possibly just co-opt write_vk_mega_honk to handle apps/kernels - const writeVkCommand = `${BB_BIN_PATH} ${ - isMegaHonk ? "write_vk_mega_honk" : "write_vk_ultra_honk" - } -h -b "${artifactPath}" -o "${binaryVkPath}" ${ + const writeVkCommand = `${BB_BIN_PATH} ${getVkCommand()} -h -b "${artifactPath}" -o "${binaryVkPath}" ${ isRecursive ? "--recursive" : "" }`; console.log("WRITE VK CMD: ", writeVkCommand); const vkAsFieldsCommand = `${BB_BIN_PATH} ${ - isMegaHonk ? "vk_as_fields_mega_honk" : "vk_as_fields_ultra_honk" + isMegaHonk || isIvcIntegration + ? "vk_as_fields_mega_honk" + : "vk_as_fields_ultra_honk" } -k "${binaryVkPath}" -o "${jsonVkPath}"`; await new Promise((resolve, reject) => { From c8acf05e1b030e63f81ae6f88393e2a2db2bb32f Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 19:56:46 +0000 Subject: [PATCH 22/28] tests pass with VKs generated via new flow --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 3 ++- .../cpp/src/barretenberg/dsl/acir_format/acir_format.cpp | 5 +++-- .../stdlib/honk_verifier/oink_recursive_verifier.cpp | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index f70e43abc71..44419853a87 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -866,11 +866,12 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& output ClientIVC mock_ivc = create_mock_ivc_from_constraints(constraints.ivc_recursion_constraints, trace_settings); builder = acir_format::create_kernel_circuit(constraints, mock_ivc, witness); - builder.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(builder)); } else { builder = acir_format::create_circuit( constraints, /*recursive=*/false, 0, witness, /*honk_recursion=*/false); } + // Add public inputs corresponding to pairing point accumulator + builder.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(builder)); // Construct the verification key via the prover-constructed proving key with the proper trace settings auto proving_key = std::make_shared(builder, trace_settings); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 51b06242d92..3091036b01b 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -495,9 +495,10 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, StdlibVerificationKey::from_witness_indices(circuit, constraint.key))); } // Create stdlib representations of each {proof, vkey} pair to be recursively verified - // ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); + ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); + // DEBUG: allow client ivc to auto-populate valid keys - ivc.instantiate_stdlib_verification_queue(circuit); + // ivc.instantiate_stdlib_verification_queue(circuit); // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal // verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp index d9974b8f056..f6adb02a7ea 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp @@ -48,12 +48,18 @@ template void OinkRecursiveVerifier_::verify() FF pub_inputs_offset = transcript->template receive_from_prover(domain_separator + "pub_inputs_offset"); if (static_cast(circuit_size.get_value()) != verification_key->verification_key->circuit_size) { + vinfo("Proof circuit size = ", circuit_size.get_value()); + vinfo("VK circuit size = ", verification_key->verification_key->circuit_size); throw_or_abort("OinkRecursiveVerifier::verify: proof circuit size does not match verification key"); } if (static_cast(public_input_size.get_value()) != verification_key->verification_key->num_public_inputs) { + vinfo("Proof num pub inputs = ", public_input_size.get_value()); + vinfo("VK num pub inputs = ", verification_key->verification_key->num_public_inputs); throw_or_abort("OinkRecursiveVerifier::verify: proof public input size does not match verification key"); } if (static_cast(pub_inputs_offset.get_value()) != verification_key->verification_key->pub_inputs_offset) { + vinfo("Proof pub inputs offset = ", pub_inputs_offset.get_value()); + vinfo("VK pub inputs offset = ", verification_key->verification_key->pub_inputs_offset); throw_or_abort("OinkRecursiveVerifier::verify: proof public input offset does not match verification key"); } From 49a39c43940a5853bcdbde008f62a9941e9f4682 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 21:10:34 +0000 Subject: [PATCH 23/28] cleaaaan --- barretenberg/cpp/src/barretenberg/bb/api.hpp | 2 +- .../cpp/src/barretenberg/bb/api_client_ivc.hpp | 11 ----------- barretenberg/cpp/src/barretenberg/bb/main.cpp | 7 ++++--- .../cpp/src/barretenberg/client_ivc/client_ivc.cpp | 4 ---- .../src/barretenberg/dsl/acir_format/acir_format.cpp | 3 --- .../barretenberg/dsl/acir_format/block_constraint.cpp | 4 ++-- .../dsl/acir_format/recursion_constraint.cpp | 1 - .../dsl/acir_format/recursion_constraint.hpp | 1 - .../protogalaxy/protogalaxy_prover_impl.hpp | 2 ++ .../stdlib/honk_verifier/oink_recursive_verifier.cpp | 6 ------ noir-projects/mock-protocol-circuits/bootstrap.sh | 2 -- noir-projects/scripts/generate_vk_json.js | 1 - 12 files changed, 9 insertions(+), 35 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api.hpp b/barretenberg/cpp/src/barretenberg/bb/api.hpp index ad9bee63e40..3e606f18a4a 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api.hpp @@ -8,7 +8,7 @@ class API { struct Flags { std::optional output_type; // bytes, fields, bytes_and_fields, fields_msgpack std::optional input_type; // compiletime_stack, runtime_stack - std::optional no_auto_verify; // WORKTODO: will go away when this is only option + std::optional no_auto_verify; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove }; virtual void prove(const Flags& flags, diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index fd0139c408c..3ae8961e44d 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -132,11 +132,6 @@ class ClientIVCAPI : public API { using namespace acir_format; - // // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically - // vinfo("initializing BN254 CRS..."); - // init_bn254_crs(1 << 20); - // init_grumpkin_crs(1 << 15); - // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; @@ -171,10 +166,6 @@ class ClientIVCAPI : public API { using namespace acir_format; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically - init_bn254_crs(1 << 20); - init_grumpkin_crs(1 << 15); - // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/false }; @@ -223,13 +214,11 @@ class ClientIVCAPI : public API { _build_folding_stack(*flags.input_type, bytecode_path, witness_path); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically - vinfo("initializing BN254 CRS..."); init_bn254_crs(1 << 20); init_grumpkin_crs(1 << 15); ClientIVC ivc; if (flags.no_auto_verify) { - // if (false) { vinfo("performing accumulation WITHOUT auto-verify"); ivc = _accumulate_without_auto_verify(folding_stack); } else { diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 44419853a87..3624847c967 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -835,7 +835,9 @@ void write_vk_honk(const std::string& bytecodePath, const std::string& outputPat } /** - * @brief Compute and write to file the VK for a circuit to be accumulated in the IVC + * @brief Compute and write to file a MegaHonk VK for a circuit to be accumulated in the IVC + * @note This method differes from write_vk_honk in that it handles kernel circuits which require special + * treatment. (i.e. they require construction of mock IVC state to correctly complete the kernel logic). * * @param bytecodePath * @param witnessPath @@ -862,9 +864,8 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& output Builder builder; if (is_kernel) { - // Create a mock IVC instance from the IVC recursion constraints in the kernel program + // Create a mock IVC instance based on the IVC recursion constraints in the kernel program ClientIVC mock_ivc = create_mock_ivc_from_constraints(constraints.ivc_recursion_constraints, trace_settings); - builder = acir_format::create_kernel_circuit(constraints, mock_ivc, witness); } else { builder = acir_format::create_circuit( diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 8287c318c6b..4ba9ae098c7 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -136,10 +136,6 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) // Peform recursive verification and databus consistency checks for each entry in the verification queue for (auto& [proof, vkey, type] : stdlib_verification_queue) { - info(""); - info("Processing VK: "); - info("is_kernel = ", vkey->databus_propagation_data.is_kernel); - info(""); perform_recursive_verification_and_databus_consistency_checks(circuit, proof, vkey, type); } stdlib_verification_queue.clear(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 3091036b01b..dd48e644a22 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -497,9 +497,6 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, // Create stdlib representations of each {proof, vkey} pair to be recursively verified ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); - // DEBUG: allow client ivc to auto-populate valid keys - // ivc.instantiate_stdlib_verification_queue(circuit); - // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal // verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly // connected to the constraints generated herein via the ivc scheme (e.g. recursive verifications). diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp index 234196d8bba..d6bf0d93323 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp @@ -86,8 +86,8 @@ void create_block_constraints(MegaCircuitBuilder& builder, process_call_data_operations(builder, constraint, has_valid_witness_assignments, init); // The presence of calldata is used to indicate that the present circuit is a kernel. This is needed in the // databus consistency checks to indicate that the corresponding return data belongs to a kernel (else an app). - // WORKTODO: this won't be sufficient since we currently need to distinguis between create_circuit and - // create_kernel_circuit + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1165): is_kernel must be known prior to this stage + // since we must determine whether to use create_circuit or create_kernel_circuit. Resolve. builder.databus_propagation_data.is_kernel = true; } break; case BlockType::ReturnData: { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp index 5263d2c7fc0..8a3234d8ee8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -1,5 +1,4 @@ #include "recursion_constraint.hpp" -#include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" #include "barretenberg/plonk/transcript/transcript_wrappers.hpp" diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp index b7f164c8925..6fa308df92c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.hpp @@ -2,7 +2,6 @@ #include "barretenberg/plonk/proof_system/constants.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" #include "barretenberg/plonk/transcript/transcript_wrappers.hpp" -#include "barretenberg/stdlib_circuit_builders/mega_flavor.hpp" #include namespace acir_format { diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp index ead4cee6280..6fbd2e47dc0 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover_impl.hpp @@ -59,6 +59,8 @@ ProtogalaxyProver_::perturbator_round( : Polynomial(CONST_PG_LOG_N + 1); // Prover doesn't send the constant coefficient of F because this is supposed to be equal to the target sum of // the accumulator which the folding verifier has from the previous iteration. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1087): Verifier circuit for first IVC step is + // different for (size_t idx = 1; idx <= CONST_PG_LOG_N; idx++) { transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp index f6adb02a7ea..d9974b8f056 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp @@ -48,18 +48,12 @@ template void OinkRecursiveVerifier_::verify() FF pub_inputs_offset = transcript->template receive_from_prover(domain_separator + "pub_inputs_offset"); if (static_cast(circuit_size.get_value()) != verification_key->verification_key->circuit_size) { - vinfo("Proof circuit size = ", circuit_size.get_value()); - vinfo("VK circuit size = ", verification_key->verification_key->circuit_size); throw_or_abort("OinkRecursiveVerifier::verify: proof circuit size does not match verification key"); } if (static_cast(public_input_size.get_value()) != verification_key->verification_key->num_public_inputs) { - vinfo("Proof num pub inputs = ", public_input_size.get_value()); - vinfo("VK num pub inputs = ", verification_key->verification_key->num_public_inputs); throw_or_abort("OinkRecursiveVerifier::verify: proof public input size does not match verification key"); } if (static_cast(pub_inputs_offset.get_value()) != verification_key->verification_key->pub_inputs_offset) { - vinfo("Proof pub inputs offset = ", pub_inputs_offset.get_value()); - vinfo("VK pub inputs offset = ", verification_key->verification_key->pub_inputs_offset); throw_or_abort("OinkRecursiveVerifier::verify: proof public input offset does not match verification key"); } diff --git a/noir-projects/mock-protocol-circuits/bootstrap.sh b/noir-projects/mock-protocol-circuits/bootstrap.sh index a3fad4464e5..d4c4ecd8cfd 100755 --- a/noir-projects/mock-protocol-circuits/bootstrap.sh +++ b/noir-projects/mock-protocol-circuits/bootstrap.sh @@ -24,8 +24,6 @@ mkdir -p "./target/keys" PARALLEL_VK=${PARALLEL_VK:-true} -# WORKTODO: VKs getting generated here - if [[ $PARALLEL_VK == "true" ]]; then echo "Generating vks in parallel..." for pathname in "./target"/*.json; do diff --git a/noir-projects/scripts/generate_vk_json.js b/noir-projects/scripts/generate_vk_json.js index 98f9b8f86ef..a2942e69cde 100644 --- a/noir-projects/scripts/generate_vk_json.js +++ b/noir-projects/scripts/generate_vk_json.js @@ -147,7 +147,6 @@ async function generateVKData( return "write_vk_ultra_honk"; } - // WORKTODO: possibly just co-opt write_vk_mega_honk to handle apps/kernels const writeVkCommand = `${BB_BIN_PATH} ${getVkCommand()} -h -b "${artifactPath}" -o "${binaryVkPath}" ${ isRecursive ? "--recursive" : "" }`; From 4e17f709613ba59a37af106557b9f55f119da01e Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 21:13:09 +0000 Subject: [PATCH 24/28] copy new ivc integration circuits in earthfile --- noir-projects/Earthfile | 1 + 1 file changed, 1 insertion(+) diff --git a/noir-projects/Earthfile b/noir-projects/Earthfile index 4627c747703..0a876ac39f7 100644 --- a/noir-projects/Earthfile +++ b/noir-projects/Earthfile @@ -20,6 +20,7 @@ source: RUN yarn COPY mega_honk_circuits.json . + COPY ivc_integration_circuits.json . COPY --dir aztec-nr noir-contracts noir-protocol-circuits mock-protocol-circuits scripts . build-contracts: From 3d7bc15f9acfcf72cfd97c6457aa179a65d7063d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 21:31:47 +0000 Subject: [PATCH 25/28] format noir --- .../mock-protocol-circuits/crates/mock-types/src/lib.nr | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr b/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr index 7822abd535b..c5f69e887a0 100644 --- a/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr +++ b/noir-projects/mock-protocol-circuits/crates/mock-types/src/lib.nr @@ -3,7 +3,9 @@ global MAX_COMMITMENTS_PER_TX: u32 = 4; global MAX_COMMITMENT_READ_REQUESTS_PER_CALL: u32 = 2; global MAX_COMMITMENT_READ_REQUESTS_PER_TX: u32 = 4; -pub use protocol_types::constants::{PROOF_TYPE_OINK, PROOF_TYPE_PG, CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS}; +pub use protocol_types::constants::{ + CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS, PROOF_TYPE_OINK, PROOF_TYPE_PG, +}; struct TxRequest { number_of_calls: u32, From 8d7cda2b34bcb4622e817c3a1fc3dfa2993a8ad3 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Wed, 4 Dec 2024 22:27:39 +0000 Subject: [PATCH 26/28] init srs within accum methods --- .../cpp/src/barretenberg/bb/api_client_ivc.hpp | 12 ++++++++++-- barretenberg/cpp/src/barretenberg/bb/main.cpp | 5 ++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index 3ae8961e44d..f363bf8433b 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -132,6 +132,10 @@ class ClientIVCAPI : public API { using namespace acir_format; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); + // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; @@ -166,6 +170,10 @@ class ClientIVCAPI : public API { using namespace acir_format; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); + // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/false }; @@ -209,7 +217,7 @@ class ClientIVCAPI : public API { if (!flags.input_type || !(*flags.input_type == "compiletime_stack" || *flags.input_type == "runtime_stack")) { throw_or_abort("No input_type or input_type not supported"); } - vinfo("building folding stack..."); + std::vector folding_stack = _build_folding_stack(*flags.input_type, bytecode_path, witness_path); @@ -222,7 +230,7 @@ class ClientIVCAPI : public API { vinfo("performing accumulation WITHOUT auto-verify"); ivc = _accumulate_without_auto_verify(folding_stack); } else { - vinfo("performing accumulation WITH auto-verify"); + vinfo("performing accumulation with auto-verify"); ivc = _accumulate(folding_stack); } ClientIVC::Proof proof = ivc.prove(); diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 3624847c967..5b8bc5041fd 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -837,7 +837,7 @@ void write_vk_honk(const std::string& bytecodePath, const std::string& outputPat /** * @brief Compute and write to file a MegaHonk VK for a circuit to be accumulated in the IVC * @note This method differes from write_vk_honk in that it handles kernel circuits which require special - * treatment. (i.e. they require construction of mock IVC state to correctly complete the kernel logic). + * treatment (i.e. construction of mock IVC state to correctly complete the kernel logic). * * @param bytecodePath * @param witnessPath @@ -856,10 +856,9 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& output auto constraints = get_constraint_system(bytecodePath, /*honk_recursion=*/false); acir_format::WitnessVector witness = {}; - // WORKTODO: should be based on some default maybe? TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; - // The presence of ivc recursion constraints determines whther or not the program is a kernel + // The presence of ivc recursion constraints determines whether or not the program is a kernel bool is_kernel = !constraints.ivc_recursion_constraints.empty(); Builder builder; From d480f34b1debd1df70b1762cad87548216a0ddca Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 5 Dec 2024 00:10:03 +0000 Subject: [PATCH 27/28] remove opt from no auto verify --- barretenberg/cpp/src/barretenberg/bb/api.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api.hpp b/barretenberg/cpp/src/barretenberg/bb/api.hpp index 3e606f18a4a..ab1a3628a4f 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api.hpp @@ -8,7 +8,7 @@ class API { struct Flags { std::optional output_type; // bytes, fields, bytes_and_fields, fields_msgpack std::optional input_type; // compiletime_stack, runtime_stack - std::optional no_auto_verify; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove + bool no_auto_verify; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove }; virtual void prove(const Flags& flags, From cee747229950ff75a984af5277e2b93d0fcc354d Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Thu, 5 Dec 2024 00:31:40 +0000 Subject: [PATCH 28/28] comment --- barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index f363bf8433b..8576f918d40 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -141,8 +141,7 @@ class ClientIVCAPI : public API { ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; // Accumulate the entire program stack into the IVC - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once - // databus has been integrated into noir kernel programs + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel bool is_kernel = false; for (Program& program : folding_stack) { // Construct a bberg circuit from the acir representation then accumulate it into the IVC