From 61e4b326def6523421009786a0fe750d423f46b9 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sat, 11 Jan 2025 17:22:15 +0000 Subject: [PATCH 01/11] chore: enable check-circuit-only tests of AVM witgen/proving --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 58 +++--- .../barretenberg/vm/avm/trace/execution.cpp | 37 ++++ .../barretenberg/vm/avm/trace/execution.hpp | 2 + .../bb-prover/src/avm_proving.test.ts | 92 ++++++++-- yarn-project/bb-prover/src/bb/execute.ts | 2 + .../simulator/src/avm/avm_simulator.ts | 7 +- .../simulator/src/public/fixtures/index.ts | 173 ++++++++++++++++-- .../src/public/public_tx_simulator.ts | 2 +- 8 files changed, 311 insertions(+), 62 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index cf6f7fefba12..2f5f1348e464 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -683,14 +683,17 @@ void vk_as_fields(const std::string& vk_path, const std::string& output_path) */ void avm_prove(const std::filesystem::path& public_inputs_path, const std::filesystem::path& hints_path, - const std::filesystem::path& output_path) + const std::filesystem::path& output_path, + const bool check_circuit_only) { const auto avm_public_inputs = AvmPublicInputs::from(read_file(public_inputs_path)); const auto avm_hints = bb::avm_trace::ExecutionHints::from(read_file(hints_path)); - // Using [0] is fine now for the top-level call, but we might need to index by address in future - vinfo("bytecode size: ", avm_hints.all_contract_bytecode[0].bytecode.size()); + if (avm_hints.all_contract_bytecode.size() > 0) { + // Using [0] is fine now for the top-level call, but we might need to index by address in future + vinfo("bytecode size: ", avm_hints.all_contract_bytecode[0].bytecode.size()); + } vinfo("hints.storage_read_hints size: ", avm_hints.storage_read_hints.size()); vinfo("hints.storage_write_hints size: ", avm_hints.storage_write_hints.size()); vinfo("hints.nullifier_read_hints size: ", avm_hints.nullifier_read_hints.size()); @@ -704,27 +707,31 @@ void avm_prove(const std::filesystem::path& public_inputs_path, vinfo("initializing crs with size: ", avm_trace::Execution::SRS_SIZE); init_bn254_crs(avm_trace::Execution::SRS_SIZE); - // Prove execution and return vk - auto const [verification_key, proof] = - AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(avm_public_inputs, avm_hints)); - - std::vector vk_as_fields = verification_key.to_field_elements(); - - vinfo("vk fields size: ", vk_as_fields.size()); - vinfo("circuit size: ", static_cast(vk_as_fields[0])); - vinfo("num of pub inputs: ", static_cast(vk_as_fields[1])); - - std::string vk_json = to_json(vk_as_fields); - const auto proof_path = output_path / "proof"; - const auto vk_path = output_path / "vk"; - const auto vk_fields_path = output_path / "vk_fields.json"; - - write_file(proof_path, to_buffer(proof)); - vinfo("proof written to: ", proof_path); - write_file(vk_path, to_buffer(vk_as_fields)); - vinfo("vk written to: ", vk_path); - write_file(vk_fields_path, { vk_json.begin(), vk_json.end() }); - vinfo("vk as fields written to: ", vk_fields_path); + if (check_circuit_only) { + avm_trace::Execution::check_circuit(avm_public_inputs, avm_hints); + } else { + // Prove execution and return vk + auto const [verification_key, proof] = + AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(avm_public_inputs, avm_hints)); + + std::vector vk_as_fields = verification_key.to_field_elements(); + + vinfo("vk fields size: ", vk_as_fields.size()); + vinfo("circuit size: ", static_cast(vk_as_fields[0])); + vinfo("num of pub inputs: ", static_cast(vk_as_fields[1])); + + std::string vk_json = to_json(vk_as_fields); + const auto proof_path = output_path / "proof"; + const auto vk_path = output_path / "vk"; + const auto vk_fields_path = output_path / "vk_fields.json"; + + write_file(proof_path, to_buffer(proof)); + vinfo("proof written to: ", proof_path); + write_file(vk_path, to_buffer(vk_as_fields)); + vinfo("vk written to: ", vk_path); + write_file(vk_fields_path, { vk_json.begin(), vk_json.end() }); + vinfo("vk as fields written to: ", vk_fields_path); + } #ifdef AVM_TRACK_STATS info("------- STATS -------"); @@ -1390,7 +1397,8 @@ int main(int argc, char* argv[]) std::filesystem::path output_path = get_option(args, "-o", "./proofs"); extern std::filesystem::path avm_dump_trace_path; avm_dump_trace_path = get_option(args, "--avm-dump-trace", ""); - avm_prove(avm_public_inputs_path, avm_hints_path, output_path); + const bool check_circuit_only = flag_present(args, "--check-circuit-only"); + avm_prove(avm_public_inputs_path, avm_hints_path, output_path, check_circuit_only); } else if (command == "avm_verify") { return avm_verify(proof_path, vk_path) ? 0 : 1; #endif diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp index 7855c9915137..9d866b8a2086 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp @@ -241,6 +241,43 @@ std::vector Execution::getDefaultPublicInputs() return public_inputs_vec; } +/** + * @brief Run the bytecode, generate the corresponding execution trace and check the circuit for + * execution of the supplied bytecode. + * + * @throws runtime_error exception when the bytecode is invalid. + */ +void Execution::check_circuit(AvmPublicInputs const& public_inputs, ExecutionHints const& execution_hints) +{ + std::vector returndata; + std::vector calldata; + for (const auto& enqueued_call_hints : execution_hints.enqueued_call_hints) { + calldata.insert(calldata.end(), enqueued_call_hints.calldata.begin(), enqueued_call_hints.calldata.end()); + } + std::vector trace = AVM_TRACK_TIME_V( + "prove/gen_trace", gen_trace(public_inputs, returndata, execution_hints, /*apply_e2e_assertions=*/true)); + if (!avm_dump_trace_path.empty()) { + info("Dumping trace as CSV to: " + avm_dump_trace_path.string()); + dump_trace_as_csv(trace, avm_dump_trace_path); + } + auto circuit_builder = bb::avm::AvmCircuitBuilder(); + circuit_builder.set_trace(std::move(trace)); + vinfo("Circuit subgroup size: 2^", + // this calculates the integer log2 + std::bit_width(circuit_builder.get_circuit_subgroup_size()) - 1); + + if (circuit_builder.get_circuit_subgroup_size() > SRS_SIZE) { + throw_or_abort("Circuit subgroup size (" + std::to_string(circuit_builder.get_circuit_subgroup_size()) + + ") exceeds SRS_SIZE (" + std::to_string(SRS_SIZE) + ")"); + } + + vinfo("------- CHECKING CIRCUIT -------"); + AVM_TRACK_TIME("prove/check_circuit", circuit_builder.check_circuit()); + // Reclaim memory. Ideally this would be done as soon as the polynomials are created, but the above flow requires + // the trace both in creation of the prover and the verifier. + circuit_builder.clear_trace(); +} + /** * @brief Run the bytecode, generate the corresponding execution trace and prove the correctness * of the execution of the supplied bytecode. diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.hpp index c570a5ffe534..288535364fd1 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.hpp @@ -53,6 +53,8 @@ class Execution { static std::tuple prove( AvmPublicInputs const& public_inputs = AvmPublicInputs(), ExecutionHints const& execution_hints = {}); + static void check_circuit(AvmPublicInputs const& public_inputs = AvmPublicInputs(), + ExecutionHints const& execution_hints = {}); static bool verify(bb::avm::AvmFlavor::VerificationKey vk, HonkProof const& proof); private: diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 0adfbab06079..3f9d5847b36e 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -11,7 +11,7 @@ import { Fr } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; import { MockedAvmTestContractDataSource, - simulateAvmTestContractGenerateCircuitInputs, + simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs, } from '@aztec/simulator/public/fixtures'; import fs from 'node:fs/promises'; @@ -149,11 +149,7 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify a nested exceptional halt that is recovered from in caller', async () => { - await proveAndVerifyAvmTestContract( - 'external_call_to_divide_by_zero_recovers', - /*args=*/ [], - /*expectRevert=*/ false, - ); + await proveAndVerifyAvmTestContract('external_call_to_divide_by_zero_recovers'); }, TIMEOUT, ); @@ -183,6 +179,16 @@ describe('AVM WitGen, proof generation and verification', () => { }, TIMEOUT, ); + it( + 'Should prove and verify multiple app logic enqueued calls (like `enqueue_public_from_private`)', + async () => { + await checkCircuitAvmTestContractMultipleEnqueuedCalls( + ['set_opcode_u8', 'set_read_storage_single'], + /*args=*/ [[], [new Fr(5)]], + ); + }, + TIMEOUT, + ); }); async function proveAndVerifyAvmTestContract( @@ -192,8 +198,52 @@ async function proveAndVerifyAvmTestContract( skipContractDeployments = false, contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), ) { - const avmCircuitInputs = await simulateAvmTestContractGenerateCircuitInputs( - functionName, + await proveAndVerifyAvmTestContractMultipleEnqueuedCalls( + [functionName], + [args], + expectRevert, + skipContractDeployments, + contractDataSource, + ); +} + +//async function checkCircuitAvmTestContract( +// functionName: string, +// args: Fr[] = [], +// expectRevert = false, +// skipContractDeployments = false, +// contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), +//) { +// await proveAndVerifyAvmTestContractMultipleEnqueuedCalls([functionName], [args], expectRevert, skipContractDeployments, contractDataSource, /*checkCircuitOnly*/true); +//} + +async function checkCircuitAvmTestContractMultipleEnqueuedCalls( + functionNames: string[], + args: Fr[][] = [], + expectRevert = false, + skipContractDeployments = false, + contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), +) { + await proveAndVerifyAvmTestContractMultipleEnqueuedCalls( + functionNames, + args, + expectRevert, + skipContractDeployments, + contractDataSource, + /*checkCircuitOnly*/ true, + ); +} + +async function proveAndVerifyAvmTestContractMultipleEnqueuedCalls( + functionNames: string[], + args: Fr[][] = [], + expectRevert = false, + skipContractDeployments = false, + contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), + checkCircuitOnly = false, +) { + const avmCircuitInputs = await simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs( + functionNames, args, expectRevert, contractDataSource, @@ -207,19 +257,27 @@ async function proveAndVerifyAvmTestContract( const bbWorkingDirectory = await fs.mkdtemp(path.join(tmpdir(), 'bb-')); // Then we prove. - const proofRes = await generateAvmProof(bbPath, bbWorkingDirectory, avmCircuitInputs, internalLogger); + const proofRes = await generateAvmProof( + bbPath, + bbWorkingDirectory, + avmCircuitInputs, + internalLogger, + checkCircuitOnly, + ); if (proofRes.status === BB_RESULT.FAILURE) { internalLogger.error(`Proof generation failed: ${proofRes.reason}`); } expect(proofRes.status).toEqual(BB_RESULT.SUCCESS); - // Then we test VK extraction and serialization. - const succeededRes = proofRes as BBSuccess; - const vkData = await extractAvmVkData(succeededRes.vkPath!); - VerificationKeyData.fromBuffer(vkData.toBuffer()); + if (!checkCircuitOnly) { + // Then we test VK extraction and serialization. + const succeededRes = proofRes as BBSuccess; + const vkData = await extractAvmVkData(succeededRes.vkPath!); + VerificationKeyData.fromBuffer(vkData.toBuffer()); - // Then we verify. - const rawVkPath = path.join(succeededRes.vkPath!, 'vk'); - const verificationRes = await verifyAvmProof(bbPath, succeededRes.proofPath!, rawVkPath, logger); - expect(verificationRes.status).toBe(BB_RESULT.SUCCESS); + // Then we verify. + const rawVkPath = path.join(succeededRes.vkPath!, 'vk'); + const verificationRes = await verifyAvmProof(bbPath, succeededRes.proofPath!, rawVkPath, logger); + expect(verificationRes.status).toBe(BB_RESULT.SUCCESS); + } } diff --git a/yarn-project/bb-prover/src/bb/execute.ts b/yarn-project/bb-prover/src/bb/execute.ts index 48a689831266..4eec6e000756 100644 --- a/yarn-project/bb-prover/src/bb/execute.ts +++ b/yarn-project/bb-prover/src/bb/execute.ts @@ -506,6 +506,7 @@ export async function generateAvmProof( workingDirectory: string, input: AvmCircuitInputs, logger: Logger, + checkCircuitOnly: boolean = false, ): Promise { // Check that the working directory exists try { @@ -553,6 +554,7 @@ export async function generateAvmProof( '-o', outputPath, logger.level === 'debug' || logger.level === 'trace' ? '-d' : logger.level === 'verbose' ? '-v' : '', + checkCircuitOnly ? '--check-circuit-only' : '', ]; const timer = new Timer(); const logFunction = (message: string) => { diff --git a/yarn-project/simulator/src/avm/avm_simulator.ts b/yarn-project/simulator/src/avm/avm_simulator.ts index a69aa0893774..3549706283e5 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.ts @@ -137,6 +137,7 @@ export class AvmSimulator { this.bytecode = bytecode; const { machineState } = this.context; + const callStartGas = machineState.gasLeft; // Save gas before executing instruction (for profiling) try { // Execute instruction pointed to by the current program counter // continuing until the machine state signifies a halt @@ -180,7 +181,11 @@ export class AvmSimulator { const revertReason = reverted ? await revertReasonFromExplicitRevert(output, this.context) : undefined; const results = new AvmContractCallResult(reverted, output, machineState.gasLeft, revertReason); this.log.debug(`Context execution results: ${results.toString()}`); - this.log.debug(`Executed ${instrCounter} instructions`); + const totalGasUsed: Gas = { + l2Gas: callStartGas.l2Gas - machineState.l2GasLeft, + daGas: callStartGas.daGas - machineState.daGasLeft, + }; + this.log.debug(`Executed ${instrCounter} instructions and consumed ${totalGasUsed.l2Gas} L2 Gas`); this.tallyPrintFunction(); // Return results for processing by calling context diff --git a/yarn-project/simulator/src/public/fixtures/index.ts b/yarn-project/simulator/src/public/fixtures/index.ts index 17cca0600ce9..94767a78db88 100644 --- a/yarn-project/simulator/src/public/fixtures/index.ts +++ b/yarn-project/simulator/src/public/fixtures/index.ts @@ -54,6 +54,26 @@ export async function simulateAvmTestContractGenerateCircuitInputs( expectRevert: boolean = false, contractDataSource = new MockedAvmTestContractDataSource(), assertionErrString?: string, +): Promise { + return await simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs( + [functionName], + [args], + expectRevert, + contractDataSource, + assertionErrString, + ); +} + +export async function simulateAvmTestContractMultiplePhasesGenerateCircuitInputs( + setupFunctionNames: string[], + setupArgs: Fr[][] = [], + appFunctionNames: string[], + appArgs: Fr[][] = [], + teardownFunctionName?: string, + teardownArgs: Fr[] = [], + expectRevert: boolean = false, + contractDataSource = new MockedAvmTestContractDataSource(), + assertionErrString?: string, ): Promise { const globals = GlobalVariables.empty(); globals.timestamp = TIMESTAMP; @@ -71,17 +91,103 @@ export async function simulateAvmTestContractGenerateCircuitInputs( ); const sender = AztecAddress.random(); - const functionSelector = getAvmTestContractFunctionSelector(functionName); - args = [functionSelector.toField(), ...args]; - const callContext = new CallContext( - sender, - contractDataSource.firstContractInstance.address, - contractDataSource.fnSelector, - /*isStaticCall=*/ false, + const setupExecutionRequests: PublicExecutionRequest[] = []; + for (let i = 0; i < setupFunctionNames.length; i++) { + const functionSelector = getAvmTestContractFunctionSelector(setupFunctionNames[i]); + const fnArgs = [functionSelector.toField(), ...setupArgs[i]]; + const callContext = new CallContext( + sender, + contractDataSource.firstContractInstance.address, + contractDataSource.fnSelector, + /*isStaticCall=*/ false, + ); + const executionRequest = new PublicExecutionRequest(callContext, fnArgs); + setupExecutionRequests.push(executionRequest); + } + const appExecutionRequests: PublicExecutionRequest[] = []; + for (let i = 0; i < appFunctionNames.length; i++) { + const functionSelector = getAvmTestContractFunctionSelector(appFunctionNames[i]); + const fnArgs = [functionSelector.toField(), ...appArgs[i]]; + const callContext = new CallContext( + sender, + contractDataSource.firstContractInstance.address, + contractDataSource.fnSelector, + /*isStaticCall=*/ false, + ); + const executionRequest = new PublicExecutionRequest(callContext, fnArgs); + appExecutionRequests.push(executionRequest); + } + + let teardownExecutionRequest: PublicExecutionRequest | undefined = undefined; + if (teardownFunctionName) { + const functionSelector = getAvmTestContractFunctionSelector(teardownFunctionName); + const fnArgs = [functionSelector.toField(), ...teardownArgs]; + const callContext = new CallContext( + sender, + contractDataSource.firstContractInstance.address, + contractDataSource.fnSelector, + /*isStaticCall=*/ false, + ); + teardownExecutionRequest = new PublicExecutionRequest(callContext, fnArgs); + } + + const tx: Tx = createTxForMultiplePublicCalls(setupExecutionRequests, appExecutionRequests, teardownExecutionRequest); + + const avmResult = await simulator.simulate(tx); + + if (!expectRevert) { + expect(avmResult.revertCode.isOK()).toBe(true); + } else { + // Explicit revert when an assertion failed. + expect(avmResult.revertCode.isOK()).toBe(false); + expect(avmResult.revertReason).toBeDefined(); + if (assertionErrString !== undefined) { + expect(avmResult.revertReason?.getMessage()).toContain(assertionErrString); + } + } + + const avmCircuitInputs: AvmCircuitInputs = avmResult.avmProvingRequest.inputs; + return avmCircuitInputs; +} + +export async function simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs( + functionNames: string[], + args: Fr[][] = [], + expectRevert: boolean = false, + contractDataSource = new MockedAvmTestContractDataSource(), + assertionErrString?: string, +): Promise { + const globals = GlobalVariables.empty(); + globals.timestamp = TIMESTAMP; + + const merkleTrees = await (await MerkleTrees.new(openTmpStore(), new NoopTelemetryClient())).fork(); + await contractDataSource.deployContracts(merkleTrees); + const worldStateDB = new WorldStateDB(merkleTrees, contractDataSource); + + const simulator = new PublicTxSimulator( + merkleTrees, + worldStateDB, + new NoopTelemetryClient(), + globals, + /*doMerkleOperations=*/ true, ); - const executionRequest = new PublicExecutionRequest(callContext, args); - const tx: Tx = createTxForPublicCall(executionRequest); + const sender = AztecAddress.random(); + const appExecutionRequests: PublicExecutionRequest[] = []; + for (let i = 0; i < functionNames.length; i++) { + const functionSelector = getAvmTestContractFunctionSelector(functionNames[i]); + const fnArgs = [functionSelector.toField(), ...args[i]]; + const callContext = new CallContext( + sender, + contractDataSource.firstContractInstance.address, + contractDataSource.fnSelector, + /*isStaticCall=*/ false, + ); + const executionRequest = new PublicExecutionRequest(callContext, fnArgs); + appExecutionRequests.push(executionRequest); + } + + const tx: Tx = createTxForMultiplePublicCalls(/*setupExecutionRequests=*/ [], appExecutionRequests); const avmResult = await simulator.simulate(tx); @@ -148,20 +254,47 @@ export function createTxForPublicCall( gasUsedByPrivate: Gas = Gas.empty(), isTeardown: boolean = false, ): Tx { - const callRequest = executionRequest.toCallRequest(); + const setupExecutionRequests: PublicExecutionRequest[] = []; + const appExecutionRequests = isTeardown ? [] : [executionRequest]; + const teardownExecutionRequest = isTeardown ? executionRequest : undefined; + return createTxForMultiplePublicCalls( + setupExecutionRequests, + appExecutionRequests, + teardownExecutionRequest, + gasUsedByPrivate, + ); +} + +export function createTxForMultiplePublicCalls( + setupExecutionRequests: PublicExecutionRequest[], + appExecutionRequests: PublicExecutionRequest[], + teardownExecutionRequest?: PublicExecutionRequest, + gasUsedByPrivate: Gas = Gas.empty(), +): Tx { + assert( + setupExecutionRequests.length > 0 || appExecutionRequests.length > 0 || teardownExecutionRequest !== undefined, + "Can't create public tx with no enqueued calls", + ); + const setupCallRequests = setupExecutionRequests.map(er => er.toCallRequest()); + const appCallRequests = appExecutionRequests.map(er => er.toCallRequest()); // use max limits const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION); const forPublic = PartialPrivateTailPublicInputsForPublic.empty(); // TODO(#9269): Remove this fake nullifier method as we move away from 1st nullifier as hash. forPublic.nonRevertibleAccumulatedData.nullifiers[0] = Fr.random(); // fake tx nullifier - if (isTeardown) { - forPublic.publicTeardownCallRequest = callRequest; - } else { - forPublic.revertibleAccumulatedData.publicCallRequests[0] = callRequest; + + for (let i = 0; i < setupExecutionRequests.length; i++) { + forPublic.nonRevertibleAccumulatedData.publicCallRequests[i] = setupCallRequests[i]; + } + for (let i = 0; i < appCallRequests.length; i++) { + forPublic.revertibleAccumulatedData.publicCallRequests[i] = appCallRequests[i]; + } + if (teardownExecutionRequest) { + forPublic.publicTeardownCallRequest = teardownExecutionRequest.toCallRequest(); } - const teardownGasLimits = isTeardown ? gasLimits : Gas.empty(); + const teardownGasLimits = teardownExecutionRequest ? gasLimits : Gas.empty(); const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty()); const txContext = new TxContext(Fr.zero(), Fr.zero(), gasSettings); const constantData = new TxConstantData(BlockHeader.empty(), txContext, Fr.zero(), Fr.zero()); @@ -173,9 +306,13 @@ export function createTxForPublicCall( AztecAddress.zero(), forPublic, ); - const tx = isTeardown ? Tx.newWithTxData(txData, executionRequest) : Tx.newWithTxData(txData); - if (!isTeardown) { - tx.enqueuedPublicFunctionCalls[0] = executionRequest; + const tx = Tx.newWithTxData(txData, teardownExecutionRequest); + + for (let i = 0; i < setupExecutionRequests.length; i++) { + tx.enqueuedPublicFunctionCalls.push(setupExecutionRequests[i]); + } + for (let i = 0; i < appExecutionRequests.length; i++) { + tx.enqueuedPublicFunctionCalls.push(appExecutionRequests[i]); } return tx; diff --git a/yarn-project/simulator/src/public/public_tx_simulator.ts b/yarn-project/simulator/src/public/public_tx_simulator.ts index b4c91484e275..577f544483cd 100644 --- a/yarn-project/simulator/src/public/public_tx_simulator.ts +++ b/yarn-project/simulator/src/public/public_tx_simulator.ts @@ -294,7 +294,7 @@ export class PublicTxSimulator { const gasUsed = allocatedGas.sub(result.gasLeft); // by enqueued call context.consumeGas(phase, gasUsed); this.log.debug( - `Simulated enqueued public call consumed ${gasUsed.l2Gas} L2 gas ending with ${result.gasLeft.l2Gas} L2 gas left.`, + `Simulated enqueued public call (${fnName}) consumed ${gasUsed.l2Gas} L2 gas ending with ${result.gasLeft.l2Gas} L2 gas left.`, ); stateManager.traceEnqueuedCall(callRequest, executionRequest.args, result.reverted); From 65a11532fcf187ae7fcc637ca87721c544d1201a Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sat, 11 Jan 2025 20:13:28 +0000 Subject: [PATCH 02/11] cleanup --- .../contracts/avm_test_contract/src/main.nr | 5 + .../bb-prover/src/avm_proving.test.ts | 131 ++++++++++-------- .../simulator/src/public/fixtures/index.ts | 94 +------------ 3 files changed, 82 insertions(+), 148 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index fbf8816d8b24..39a79d0e8658 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -71,6 +71,11 @@ contract AvmTest { storage.single.read() } + #[public] + fn read_assert_storage_single(a: Field) { + assert(a == storage.single.read(), "Storage value does not match input"); + } + // should still be able to use ` -> pub *` for return type even though macro forces `pub` #[public] fn set_read_storage_single(a: Field) -> pub Field { diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 3f9d5847b36e..70bdae28da1e 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -11,7 +11,7 @@ import { Fr } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; import { MockedAvmTestContractDataSource, - simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs, + simulateAvmTestContractGenerateCircuitInputs, } from '@aztec/simulator/public/fixtures'; import fs from 'node:fs/promises'; @@ -23,11 +23,15 @@ import { extractAvmVkData } from './verification_key/verification_key_data.js'; const TIMEOUT = 300_000; +// This makes `avm_prove` only "check circuit", and skips `avm_verify` +const AVM_CHECK_CIRCUIT_ONLY = + process.env.AVM_CHECK_CIRCUIT_ONLY == 'true' || process.env.AVM_CHECK_CIRCUIT_ONLY == '1' ? true : false; + describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify bulk_testing', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'bulk_testing', /*args=*/ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(x => new Fr(x)), ); @@ -37,7 +41,7 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify test that performs too many storage writes and reverts', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'n_storage_writes', /*args=*/ [new Fr(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + 1)], /*expectRevert=*/ true, @@ -48,7 +52,7 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify test that creates too many note hashes and reverts', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'n_new_note_hashes', /*args=*/ [new Fr(MAX_NOTE_HASHES_PER_TX + 1)], /*expectRevert=*/ true, @@ -59,7 +63,7 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify test that creates too many nullifiers and reverts', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'n_new_nullifiers', /*args=*/ [new Fr(MAX_NULLIFIERS_PER_TX + 1)], /*expectRevert=*/ true, @@ -70,7 +74,7 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify test that creates too many l2tol1 messages and reverts', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'n_new_l2_to_l1_msgs', /*args=*/ [new Fr(MAX_L2_TO_L1_MSGS_PER_TX + 1)], /*expectRevert=*/ true, @@ -81,7 +85,7 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify test that creates too many unencrypted logs and reverts', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'n_new_unencrypted_logs', /*args=*/ [new Fr(MAX_UNENCRYPTED_LOGS_PER_TX + 1)], /*expectRevert=*/ true, @@ -101,7 +105,7 @@ describe('AVM WitGen, proof generation and verification', () => { args.push(args[0]); // include another contract address that reuses a class ID to ensure that we can call it even after the limit is reached args.push(contractDataSource.instanceSameClassAsFirstContract.address.toField()); - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'nested_call_to_add_n_times_different_addresses', args, /*expectRevert=*/ false, @@ -122,7 +126,7 @@ describe('AVM WitGen, proof generation and verification', () => { ); // push an empty one (just padding to match function calldata size of MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS+2) args.push(new Fr(0)); - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'nested_call_to_add_n_times_different_addresses', args, /*expectRevert=*/ true, @@ -135,42 +139,54 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify a top-level exceptional halt', async () => { - await proveAndVerifyAvmTestContract('divide_by_zero', /*args=*/ [], /*expectRevert=*/ true); + await proveAndVerifyAvmTestContractSimple('divide_by_zero', /*args=*/ [], /*expectRevert=*/ true); }, TIMEOUT, ); it( 'Should prove and verify a nested exceptional halt that propagates to top-level', async () => { - await proveAndVerifyAvmTestContract('external_call_to_divide_by_zero', /*args=*/ [], /*expectRevert=*/ true); + await proveAndVerifyAvmTestContractSimple( + 'external_call_to_divide_by_zero', + /*args=*/ [], + /*expectRevert=*/ true, + ); }, TIMEOUT, ); it( 'Should prove and verify a nested exceptional halt that is recovered from in caller', async () => { - await proveAndVerifyAvmTestContract('external_call_to_divide_by_zero_recovers'); + await proveAndVerifyAvmTestContractSimple( + 'external_call_to_divide_by_zero_recovers', + /*args=*/ [], + /*expectRevert=*/ false, + ); }, TIMEOUT, ); it( 'Should prove and verify an exceptional halt due to a nested call to non-existent contract that is propagated to top-level', async () => { - await proveAndVerifyAvmTestContract('nested_call_to_nothing', /*args=*/ [], /*expectRevert=*/ true); + await proveAndVerifyAvmTestContractSimple('nested_call_to_nothing', /*args=*/ [], /*expectRevert=*/ true); }, TIMEOUT, ); it( 'Should prove and verify an exceptional halt due to a nested call to non-existent contract that is recovered from in caller', async () => { - await proveAndVerifyAvmTestContract('nested_call_to_nothing_recovers', /*args=*/ [], /*expectRevert=*/ false); + await proveAndVerifyAvmTestContractSimple( + 'nested_call_to_nothing_recovers', + /*args=*/ [], + /*expectRevert=*/ false, + ); }, TIMEOUT, ); it( 'Should prove and verify a top-level exceptional halt due to a non-existent contract', async () => { - await proveAndVerifyAvmTestContract( + await proveAndVerifyAvmTestContractSimple( 'add_args_return', /*args=*/ [new Fr(1), new Fr(2)], /*expectRevert=*/ true, @@ -179,72 +195,73 @@ describe('AVM WitGen, proof generation and verification', () => { }, TIMEOUT, ); - it( + it.skip( 'Should prove and verify multiple app logic enqueued calls (like `enqueue_public_from_private`)', async () => { - await checkCircuitAvmTestContractMultipleEnqueuedCalls( - ['set_opcode_u8', 'set_read_storage_single'], - /*args=*/ [[], [new Fr(5)]], + await proveAndVerifyAvmTestContract( + /*setupFunctionNames=*/ [], + /*setupArgs=*/ [], + /*appFunctionNames=*/ ['set_opcode_u8', 'set_read_storage_single'], + /*appArgs=*/ [[], [new Fr(5)]], + ); + }, + TIMEOUT, + ); + it.skip( + 'Should prove and verify enqueued calls in every phase, with enqueued calls that depend on each other', + async () => { + await proveAndVerifyAvmTestContract( + /*setupFunctionNames=*/ ['read_assert_storage_single', 'set_storage_single'], + /*setupArgs=*/ [[new Fr(0)], [new Fr(5)]], + /*appFunctionNames=*/ ['read_assert_storage_single', 'set_storage_single'], + /*appArgs=*/ [[new Fr(5)], [new Fr(10)]], + /*teardownFunctionName=*/ 'read_assert_storage_single', + /*teardownArgs=*/ [new Fr(10)], ); }, TIMEOUT, ); }); -async function proveAndVerifyAvmTestContract( +async function proveAndVerifyAvmTestContractSimple( functionName: string, args: Fr[] = [], expectRevert = false, skipContractDeployments = false, contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), ) { - await proveAndVerifyAvmTestContractMultipleEnqueuedCalls( - [functionName], - [args], - expectRevert, - skipContractDeployments, - contractDataSource, - ); -} - -//async function checkCircuitAvmTestContract( -// functionName: string, -// args: Fr[] = [], -// expectRevert = false, -// skipContractDeployments = false, -// contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), -//) { -// await proveAndVerifyAvmTestContractMultipleEnqueuedCalls([functionName], [args], expectRevert, skipContractDeployments, contractDataSource, /*checkCircuitOnly*/true); -//} - -async function checkCircuitAvmTestContractMultipleEnqueuedCalls( - functionNames: string[], - args: Fr[][] = [], - expectRevert = false, - skipContractDeployments = false, - contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), -) { - await proveAndVerifyAvmTestContractMultipleEnqueuedCalls( - functionNames, - args, + await proveAndVerifyAvmTestContract( + /*setupFunctionNames=*/ [], + /*setupArgs=*/ [], + /*appFunctionNames=*/ [functionName], + /*appArgs=*/ [args], + /*teardownFunctionName=*/ undefined, + /*teardownArgs=*/ [], expectRevert, skipContractDeployments, contractDataSource, - /*checkCircuitOnly*/ true, ); } -async function proveAndVerifyAvmTestContractMultipleEnqueuedCalls( - functionNames: string[], - args: Fr[][] = [], +async function proveAndVerifyAvmTestContract( + setupFunctionNames: string[], + setupArgs: Fr[][] = [], + appFunctionNames: string[], + appArgs: Fr[][] = [], + teardownFunctionName?: string, + teardownArgs: Fr[] = [], expectRevert = false, skipContractDeployments = false, contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), - checkCircuitOnly = false, + checkCircuitOnly = AVM_CHECK_CIRCUIT_ONLY, ) { - const avmCircuitInputs = await simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs( - functionNames, - args, + const avmCircuitInputs = await simulateAvmTestContractGenerateCircuitInputs( + setupFunctionNames, + setupArgs, + appFunctionNames, + appArgs, + teardownFunctionName, + teardownArgs, expectRevert, contractDataSource, ); diff --git a/yarn-project/simulator/src/public/fixtures/index.ts b/yarn-project/simulator/src/public/fixtures/index.ts index 94767a78db88..c0439531d8a1 100644 --- a/yarn-project/simulator/src/public/fixtures/index.ts +++ b/yarn-project/simulator/src/public/fixtures/index.ts @@ -49,22 +49,6 @@ import { initContext, initExecutionEnvironment, initPersistableStateManager } fr const TIMESTAMP = new Fr(99833); export async function simulateAvmTestContractGenerateCircuitInputs( - functionName: string, - args: Fr[] = [], - expectRevert: boolean = false, - contractDataSource = new MockedAvmTestContractDataSource(), - assertionErrString?: string, -): Promise { - return await simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs( - [functionName], - [args], - expectRevert, - contractDataSource, - assertionErrString, - ); -} - -export async function simulateAvmTestContractMultiplePhasesGenerateCircuitInputs( setupFunctionNames: string[], setupArgs: Fr[][] = [], appFunctionNames: string[], @@ -131,63 +115,7 @@ export async function simulateAvmTestContractMultiplePhasesGenerateCircuitInputs teardownExecutionRequest = new PublicExecutionRequest(callContext, fnArgs); } - const tx: Tx = createTxForMultiplePublicCalls(setupExecutionRequests, appExecutionRequests, teardownExecutionRequest); - - const avmResult = await simulator.simulate(tx); - - if (!expectRevert) { - expect(avmResult.revertCode.isOK()).toBe(true); - } else { - // Explicit revert when an assertion failed. - expect(avmResult.revertCode.isOK()).toBe(false); - expect(avmResult.revertReason).toBeDefined(); - if (assertionErrString !== undefined) { - expect(avmResult.revertReason?.getMessage()).toContain(assertionErrString); - } - } - - const avmCircuitInputs: AvmCircuitInputs = avmResult.avmProvingRequest.inputs; - return avmCircuitInputs; -} - -export async function simulateAvmTestContractMultipleEnqueuedCallsGenerateCircuitInputs( - functionNames: string[], - args: Fr[][] = [], - expectRevert: boolean = false, - contractDataSource = new MockedAvmTestContractDataSource(), - assertionErrString?: string, -): Promise { - const globals = GlobalVariables.empty(); - globals.timestamp = TIMESTAMP; - - const merkleTrees = await (await MerkleTrees.new(openTmpStore(), new NoopTelemetryClient())).fork(); - await contractDataSource.deployContracts(merkleTrees); - const worldStateDB = new WorldStateDB(merkleTrees, contractDataSource); - - const simulator = new PublicTxSimulator( - merkleTrees, - worldStateDB, - new NoopTelemetryClient(), - globals, - /*doMerkleOperations=*/ true, - ); - - const sender = AztecAddress.random(); - const appExecutionRequests: PublicExecutionRequest[] = []; - for (let i = 0; i < functionNames.length; i++) { - const functionSelector = getAvmTestContractFunctionSelector(functionNames[i]); - const fnArgs = [functionSelector.toField(), ...args[i]]; - const callContext = new CallContext( - sender, - contractDataSource.firstContractInstance.address, - contractDataSource.fnSelector, - /*isStaticCall=*/ false, - ); - const executionRequest = new PublicExecutionRequest(callContext, fnArgs); - appExecutionRequests.push(executionRequest); - } - - const tx: Tx = createTxForMultiplePublicCalls(/*setupExecutionRequests=*/ [], appExecutionRequests); + const tx: Tx = createTxForPublicCalls(setupExecutionRequests, appExecutionRequests, teardownExecutionRequest); const avmResult = await simulator.simulate(tx); @@ -247,25 +175,9 @@ export async function simulateAvmTestContractCall( } /** - * Craft a carrier transaction for a public call for simulation by PublicTxSimulator. + * Craft a carrier transaction for some public calls for simulation by PublicTxSimulator. */ -export function createTxForPublicCall( - executionRequest: PublicExecutionRequest, - gasUsedByPrivate: Gas = Gas.empty(), - isTeardown: boolean = false, -): Tx { - const setupExecutionRequests: PublicExecutionRequest[] = []; - const appExecutionRequests = isTeardown ? [] : [executionRequest]; - const teardownExecutionRequest = isTeardown ? executionRequest : undefined; - return createTxForMultiplePublicCalls( - setupExecutionRequests, - appExecutionRequests, - teardownExecutionRequest, - gasUsedByPrivate, - ); -} - -export function createTxForMultiplePublicCalls( +export function createTxForPublicCalls( setupExecutionRequests: PublicExecutionRequest[], appExecutionRequests: PublicExecutionRequest[], teardownExecutionRequest?: PublicExecutionRequest, From 47e7d3ebb6d9c902bdaeed6c39000831b05874b5 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sat, 11 Jan 2025 20:25:01 +0000 Subject: [PATCH 03/11] comments --- yarn-project/bb-prover/src/avm_proving.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 70bdae28da1e..594c0552db2c 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -223,6 +223,9 @@ describe('AVM WitGen, proof generation and verification', () => { ); }); +/** + * Simulate, prove and verify just a single App Logic enqueued call. + */ async function proveAndVerifyAvmTestContractSimple( functionName: string, args: Fr[] = [], @@ -243,6 +246,9 @@ async function proveAndVerifyAvmTestContractSimple( ); } +/** + * Simulate, prove and verify setup calls, app logic calls and optionally a teardown call in one TX. + */ async function proveAndVerifyAvmTestContract( setupFunctionNames: string[], setupArgs: Fr[][] = [], @@ -286,6 +292,7 @@ async function proveAndVerifyAvmTestContract( } expect(proofRes.status).toEqual(BB_RESULT.SUCCESS); + // There is no proof to verify if we only check circuit. if (!checkCircuitOnly) { // Then we test VK extraction and serialization. const succeededRes = proofRes as BBSuccess; From 4cecca9d533105c1629af609c6a22ea74381e569 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sun, 12 Jan 2025 00:22:52 +0000 Subject: [PATCH 04/11] missed txe stuff --- .../simulator/src/public/fixtures/index.ts | 24 +++++-------------- yarn-project/txe/src/oracle/txe_oracle.ts | 9 +++++-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/yarn-project/simulator/src/public/fixtures/index.ts b/yarn-project/simulator/src/public/fixtures/index.ts index c0439531d8a1..5b9dc663eb04 100644 --- a/yarn-project/simulator/src/public/fixtures/index.ts +++ b/yarn-project/simulator/src/public/fixtures/index.ts @@ -75,16 +75,16 @@ export async function simulateAvmTestContractGenerateCircuitInputs( ); const sender = AztecAddress.random(); + const callContext = new CallContext( + sender, + contractDataSource.firstContractInstance.address, + contractDataSource.fnSelector, + /*isStaticCall=*/ false, + ); const setupExecutionRequests: PublicExecutionRequest[] = []; for (let i = 0; i < setupFunctionNames.length; i++) { const functionSelector = getAvmTestContractFunctionSelector(setupFunctionNames[i]); const fnArgs = [functionSelector.toField(), ...setupArgs[i]]; - const callContext = new CallContext( - sender, - contractDataSource.firstContractInstance.address, - contractDataSource.fnSelector, - /*isStaticCall=*/ false, - ); const executionRequest = new PublicExecutionRequest(callContext, fnArgs); setupExecutionRequests.push(executionRequest); } @@ -92,12 +92,6 @@ export async function simulateAvmTestContractGenerateCircuitInputs( for (let i = 0; i < appFunctionNames.length; i++) { const functionSelector = getAvmTestContractFunctionSelector(appFunctionNames[i]); const fnArgs = [functionSelector.toField(), ...appArgs[i]]; - const callContext = new CallContext( - sender, - contractDataSource.firstContractInstance.address, - contractDataSource.fnSelector, - /*isStaticCall=*/ false, - ); const executionRequest = new PublicExecutionRequest(callContext, fnArgs); appExecutionRequests.push(executionRequest); } @@ -106,12 +100,6 @@ export async function simulateAvmTestContractGenerateCircuitInputs( if (teardownFunctionName) { const functionSelector = getAvmTestContractFunctionSelector(teardownFunctionName); const fnArgs = [functionSelector.toField(), ...teardownArgs]; - const callContext = new CallContext( - sender, - contractDataSource.firstContractInstance.address, - contractDataSource.fnSelector, - /*isStaticCall=*/ false, - ); teardownExecutionRequest = new PublicExecutionRequest(callContext, fnArgs); } diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 07965dbce20e..abddcf3c300b 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -81,7 +81,7 @@ import { toACVMWitness, witnessMapToFields, } from '@aztec/simulator'; -import { createTxForPublicCall } from '@aztec/simulator/public/fixtures'; +import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state'; @@ -840,7 +840,12 @@ export class TXE implements TypedOracle { // When setting up a teardown call, we tell it that // private execution used Gas(1, 1) so it can compute a tx fee. const gasUsedByPrivate = isTeardown ? new Gas(1, 1) : Gas.empty(); - const tx = createTxForPublicCall(executionRequest, gasUsedByPrivate, isTeardown); + const tx = createTxForPublicCalls( + /*setupExecutionRequests=*/ [], + /*appExecutionRequests=*/ isTeardown ? [] : [executionRequest], + /*teardownExecutionRequests=*/ isTeardown ? executionRequest : undefined, + gasUsedByPrivate, + ); const result = await simulator.simulate(tx); From f3dd5da4b2e4542b239e01dde451e47b606e7f37 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sun, 12 Jan 2025 00:44:25 +0000 Subject: [PATCH 05/11] fix integration --- .../ivc-integration/src/avm_integration.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/yarn-project/ivc-integration/src/avm_integration.test.ts b/yarn-project/ivc-integration/src/avm_integration.test.ts index 20f913b6a956..067ea935bca4 100644 --- a/yarn-project/ivc-integration/src/avm_integration.test.ts +++ b/yarn-project/ivc-integration/src/avm_integration.test.ts @@ -121,7 +121,15 @@ describe('AVM Integration', () => { }); async function proveAvmTestContract(functionName: string, calldata: Fr[] = []): Promise { - const avmCircuitInputs = await simulateAvmTestContractGenerateCircuitInputs(functionName, calldata); + const avmCircuitInputs = await simulateAvmTestContractGenerateCircuitInputs( + /*setupFunctionNames=*/ [], + /*setupArgs=*/ [], + /*appFunctionNames=*/ [functionName], + /*appArgs=*/ [calldata], + /*teardownFunctionName=*/ undefined, + /*teardownArgs=*/ [], + /*expectRevert=*/ false, + ); const internalLogger = createLogger('ivc-integration:test:avm-proving'); From 1bcba559e6111c9eddfb4c01028059a12ff3fa83 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sun, 12 Jan 2025 01:40:31 +0000 Subject: [PATCH 06/11] fix --- yarn-project/bb-prover/src/avm_proving.test.ts | 6 +++--- yarn-project/simulator/src/public/fixtures/index.ts | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 857ac5bf79a8..11470a32ca53 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -203,13 +203,13 @@ describe('AVM WitGen, proof generation and verification', () => { TIMEOUT, ); it.skip( - 'Should prove and verify multiple app logic enqueued calls (like `enqueue_public_from_private`)', + 'Should prove and verify multiple app logic enqueued calls (set storage in first call, read it in next)', async () => { await proveAndVerifyAvmTestContract( /*setupFunctionNames=*/ [], /*setupArgs=*/ [], - /*appFunctionNames=*/ ['set_opcode_u8', 'set_read_storage_single'], - /*appArgs=*/ [[], [new Fr(5)]], + /*appFunctionNames=*/ ['set_storage_single', 'read_assert_storage_single'], + /*appArgs=*/ [[new Fr(5)], [new Fr(5)]], ); }, TIMEOUT, diff --git a/yarn-project/simulator/src/public/fixtures/index.ts b/yarn-project/simulator/src/public/fixtures/index.ts index 3c801fa7b3d3..e47f37df6de3 100644 --- a/yarn-project/simulator/src/public/fixtures/index.ts +++ b/yarn-project/simulator/src/public/fixtures/index.ts @@ -79,14 +79,16 @@ export async function simulateAvmTestContractGenerateCircuitInputs( /*isStaticCall=*/ false, ); const setupExecutionRequests: PublicExecutionRequest[] = []; - for (let i = 0; i < setupFunctionNames.length; i++) { + // we reverse order because the simulator expects it to be like a "stack" of calls to pop from + for (let i = setupFunctionNames.length - 1; i >= 0; i--) { const functionSelector = getAvmTestContractFunctionSelector(setupFunctionNames[i]); const fnArgs = [functionSelector.toField(), ...setupArgs[i]]; const executionRequest = new PublicExecutionRequest(callContext, fnArgs); setupExecutionRequests.push(executionRequest); } const appExecutionRequests: PublicExecutionRequest[] = []; - for (let i = 0; i < appFunctionNames.length; i++) { + // we reverse order because the simulator expects it to be like a "stack" of calls to pop from + for (let i = appFunctionNames.length - 1; i >= 0; i--) { const functionSelector = getAvmTestContractFunctionSelector(appFunctionNames[i]); const fnArgs = [functionSelector.toField(), ...appArgs[i]]; const executionRequest = new PublicExecutionRequest(callContext, fnArgs); From 5377e60c7a31205526b392910e1e4fa20c3702ac Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Sun, 12 Jan 2025 01:47:02 +0000 Subject: [PATCH 07/11] another test --- yarn-project/bb-prover/src/avm_proving.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 11470a32ca53..61357344029e 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -214,6 +214,18 @@ describe('AVM WitGen, proof generation and verification', () => { }, TIMEOUT, ); + it.skip( + 'Should prove and verify multiple app logic enqueued calls (like `enqueue_public_from_private`)', + async () => { + await proveAndVerifyAvmTestContract( + /*setupFunctionNames=*/ [], + /*setupArgs=*/ [], + /*appFunctionNames=*/ ['set_opcode_u8', 'set_read_storage_single'], + /*appArgs=*/ [[], [new Fr(5)]], + ); + }, + TIMEOUT, + ); it.skip( 'Should prove and verify enqueued calls in every phase, with enqueued calls that depend on each other', async () => { From f61c10ca0657aed24ff02cacbdf30e74e3eca6be Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Mon, 13 Jan 2025 16:01:03 +0000 Subject: [PATCH 08/11] cleanup --- .../barretenberg/vm/avm/trace/execution.cpp | 7 +-- .../bb-prover/src/avm_proving.test.ts | 43 ++++++++++++++----- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp index 4d4eaa3a8a05..cbd6888107a8 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp @@ -275,9 +275,6 @@ void Execution::check_circuit(AvmPublicInputs const& public_inputs, ExecutionHin vinfo("------- CHECKING CIRCUIT -------"); AVM_TRACK_TIME("prove/check_circuit", circuit_builder.check_circuit()); - // Reclaim memory. Ideally this would be done as soon as the polynomials are created, but the above flow requires - // the trace both in creation of the prover and the verifier. - circuit_builder.clear_trace(); } /** @@ -389,8 +386,8 @@ std::vector Execution::gen_trace(AvmPublicInputs const& public_inputs, uint32_t start_side_effect_counter = 0; // Temporary until we get proper nested call handling std::vector calldata; - for (const auto& enqueued_call_hints : execution_hints.enqueued_call_hints) { - calldata.insert(calldata.end(), enqueued_call_hints.calldata.begin(), enqueued_call_hints.calldata.end()); + for (const auto& enqueued_call_hint : execution_hints.enqueued_call_hints) { + calldata.insert(calldata.end(), enqueued_call_hint.calldata.begin(), enqueued_call_hint.calldata.end()); } AvmTraceBuilder trace_builder = Execution::trace_builder_constructor(public_inputs, execution_hints, start_side_effect_counter); diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 61357344029e..3655feee81c7 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -30,15 +30,12 @@ import { extractAvmVkData } from './verification_key/verification_key_data.js'; const TIMEOUT = 300_000; -// This makes `avm_prove` only "check circuit", and skips `avm_verify` -const AVM_CHECK_CIRCUIT_ONLY = - process.env.AVM_CHECK_CIRCUIT_ONLY == 'true' || process.env.AVM_CHECK_CIRCUIT_ONLY == '1' ? true : false; - describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify bulk_testing v1', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ false, // full proving & verifying 'bulk_testing', /*args=*/ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(x => new Fr(x)), ); @@ -49,6 +46,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify test that performs too many storage writes and reverts', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'n_storage_writes', /*args=*/ [new Fr(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + 1)], /*expectRevert=*/ true, @@ -57,9 +55,10 @@ describe('AVM WitGen, proof generation and verification', () => { TIMEOUT, ); it( - 'Should prove and verify test that creates too many note hashes and reverts', + 'Should run check circuit for test that creates too many note hashes and reverts', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'n_new_note_hashes', /*args=*/ [new Fr(MAX_NOTE_HASHES_PER_TX + 1)], /*expectRevert=*/ true, @@ -71,6 +70,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify test that creates too many nullifiers and reverts', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'n_new_nullifiers', /*args=*/ [new Fr(MAX_NULLIFIERS_PER_TX + 1)], /*expectRevert=*/ true, @@ -82,6 +82,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify test that creates too many l2tol1 messages and reverts', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'n_new_l2_to_l1_msgs', /*args=*/ [new Fr(MAX_L2_TO_L1_MSGS_PER_TX + 1)], /*expectRevert=*/ true, @@ -93,6 +94,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify test that creates too many unencrypted logs and reverts', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'n_new_unencrypted_logs', /*args=*/ [new Fr(MAX_UNENCRYPTED_LOGS_PER_TX + 1)], /*expectRevert=*/ true, @@ -113,6 +115,7 @@ describe('AVM WitGen, proof generation and verification', () => { // include another contract address that reuses a class ID to ensure that we can call it even after the limit is reached args.push(contractDataSource.instanceSameClassAsFirstContract.address.toField()); await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'nested_call_to_add_n_times_different_addresses', args, /*expectRevert=*/ false, @@ -134,6 +137,7 @@ describe('AVM WitGen, proof generation and verification', () => { // push an empty one (just padding to match function calldata size of MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS+2) args.push(new Fr(0)); await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'nested_call_to_add_n_times_different_addresses', args, /*expectRevert=*/ true, @@ -146,7 +150,12 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify a top-level exceptional halt', async () => { - await proveAndVerifyAvmTestContractSimple('divide_by_zero', /*args=*/ [], /*expectRevert=*/ true); + await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick + 'divide_by_zero', + /*args=*/ [], + /*expectRevert=*/ true, + ); }, TIMEOUT, ); @@ -154,6 +163,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify a nested exceptional halt that propagates to top-level', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'external_call_to_divide_by_zero', /*args=*/ [], /*expectRevert=*/ true, @@ -165,6 +175,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify a nested exceptional halt that is recovered from in caller', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'external_call_to_divide_by_zero_recovers', /*args=*/ [], /*expectRevert=*/ false, @@ -175,7 +186,12 @@ describe('AVM WitGen, proof generation and verification', () => { it( 'Should prove and verify an exceptional halt due to a nested call to non-existent contract that is propagated to top-level', async () => { - await proveAndVerifyAvmTestContractSimple('nested_call_to_nothing', /*args=*/ [], /*expectRevert=*/ true); + await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick + 'nested_call_to_nothing', + /*args=*/ [], + /*expectRevert=*/ true, + ); }, TIMEOUT, ); @@ -183,6 +199,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify an exceptional halt due to a nested call to non-existent contract that is recovered from in caller', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'nested_call_to_nothing_recovers', /*args=*/ [], /*expectRevert=*/ false, @@ -194,6 +211,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify a top-level exceptional halt due to a non-existent contract', async () => { await proveAndVerifyAvmTestContractSimple( + /*checkCircuitOnly=*/ true, // quick 'add_args_return', /*args=*/ [new Fr(1), new Fr(2)], /*expectRevert=*/ true, @@ -206,6 +224,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify multiple app logic enqueued calls (set storage in first call, read it in next)', async () => { await proveAndVerifyAvmTestContract( + /*checkCircuitOnly=*/ true, /*setupFunctionNames=*/ [], /*setupArgs=*/ [], /*appFunctionNames=*/ ['set_storage_single', 'read_assert_storage_single'], @@ -214,10 +233,11 @@ describe('AVM WitGen, proof generation and verification', () => { }, TIMEOUT, ); - it.skip( + it( 'Should prove and verify multiple app logic enqueued calls (like `enqueue_public_from_private`)', async () => { await proveAndVerifyAvmTestContract( + /*checkCircuitOnly=*/ true, /*setupFunctionNames=*/ [], /*setupArgs=*/ [], /*appFunctionNames=*/ ['set_opcode_u8', 'set_read_storage_single'], @@ -230,6 +250,7 @@ describe('AVM WitGen, proof generation and verification', () => { 'Should prove and verify enqueued calls in every phase, with enqueued calls that depend on each other', async () => { await proveAndVerifyAvmTestContract( + /*checkCircuitOnly=*/ true, /*setupFunctionNames=*/ ['read_assert_storage_single', 'set_storage_single'], /*setupArgs=*/ [[new Fr(0)], [new Fr(5)]], /*appFunctionNames=*/ ['read_assert_storage_single', 'set_storage_single'], @@ -246,6 +267,7 @@ describe('AVM WitGen, proof generation and verification', () => { * Simulate, prove and verify just a single App Logic enqueued call. */ async function proveAndVerifyAvmTestContractSimple( + checkCircuitOnly: boolean, functionName: string, args: Fr[] = [], expectRevert = false, @@ -253,6 +275,7 @@ async function proveAndVerifyAvmTestContractSimple( contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), ) { await proveAndVerifyAvmTestContract( + checkCircuitOnly, /*setupFunctionNames=*/ [], /*setupArgs=*/ [], /*appFunctionNames=*/ [functionName], @@ -269,8 +292,9 @@ async function proveAndVerifyAvmTestContractSimple( * Simulate, prove and verify setup calls, app logic calls and optionally a teardown call in one TX. */ async function proveAndVerifyAvmTestContract( + checkCircuitOnly: boolean, setupFunctionNames: string[], - setupArgs: Fr[][] = [], + setupArgs: Fr[][], appFunctionNames: string[], appArgs: Fr[][] = [], teardownFunctionName?: string, @@ -278,7 +302,6 @@ async function proveAndVerifyAvmTestContract( expectRevert = false, skipContractDeployments = false, contractDataSource = new MockedAvmTestContractDataSource(skipContractDeployments), - checkCircuitOnly = AVM_CHECK_CIRCUIT_ONLY, ) { const avmCircuitInputs = await simulateAvmTestContractGenerateCircuitInputs( setupFunctionNames, From ae93be96b79049ce2284c49a6791a30a590192a0 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Mon, 13 Jan 2025 16:24:30 +0000 Subject: [PATCH 09/11] fix --- yarn-project/bb-prover/src/avm_proving.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 3655feee81c7..5119af27f2af 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -233,7 +233,7 @@ describe('AVM WitGen, proof generation and verification', () => { }, TIMEOUT, ); - it( + it.skip( 'Should prove and verify multiple app logic enqueued calls (like `enqueue_public_from_private`)', async () => { await proveAndVerifyAvmTestContract( From f3303dba052ab640a69a6360ced9ea0f6947e45c Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Mon, 13 Jan 2025 16:45:14 +0000 Subject: [PATCH 10/11] re-enable bb-prover tests in CI --- yarn-project/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/package.json b/yarn-project/package.json index 6028af4c8f1c..b2678f6457ad 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -10,7 +10,7 @@ "formatting:fix": "FORCE_COLOR=true yarn workspaces foreach -A -p -v run formatting:fix", "lint": "yarn eslint --cache --ignore-pattern l1-artifacts .", "format": "yarn prettier --cache -w .", - "test": "RAYON_NUM_THREADS=4 FORCE_COLOR=true yarn workspaces foreach -A --exclude @aztec/aztec3-packages --exclude @aztec/bb-prover --exclude @aztec/prover-client -p -v run test --config=../jest.root.config.js", + "test": "RAYON_NUM_THREADS=4 FORCE_COLOR=true yarn workspaces foreach -A --exclude @aztec/aztec3-packages --exclude @aztec/prover-client -p -v run test --config=../jest.root.config.js", "build": "FORCE_COLOR=true yarn workspaces foreach -A --parallel --topological-dev --verbose --exclude @aztec/aztec3-packages --exclude @aztec/docs run build", "build:fast": "cd foundation && yarn build && cd ../l1-artifacts && yarn build && cd ../circuits.js && yarn build && cd .. && yarn generate && tsc -b", "build:dev": "./watch.sh", From e96b195a00b75362a8370867698a0d4b26bbde54 Mon Sep 17 00:00:00 2001 From: dbanks12 Date: Mon, 13 Jan 2025 18:51:44 +0000 Subject: [PATCH 11/11] separate check-circuit cpp command --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 95 ++++++++++--------- .../vm/avm/trace/execution_hints.hpp | 18 ++++ yarn-project/bb-prover/src/bb/execute.ts | 7 +- 3 files changed, 74 insertions(+), 46 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 0186ee014933..4552e66deb58 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -683,6 +683,27 @@ void print_avm_stats() #endif } +/** + * @brief Performs "check circuit" on the AVM circuit for the given public inputs and hints. + * + * @param public_inputs_path Path to the file containing the serialised avm public inputs + * @param hints_path Path to the file containing the serialised avm circuit hints + */ +void avm_check_circuit(const std::filesystem::path& public_inputs_path, const std::filesystem::path& hints_path) +{ + + const auto avm_public_inputs = AvmPublicInputs::from(read_file(public_inputs_path)); + const auto avm_hints = bb::avm_trace::ExecutionHints::from(read_file(hints_path)); + avm_hints.print_sizes(); + + vinfo("initializing crs with size: ", avm_trace::Execution::SRS_SIZE); + init_bn254_crs(avm_trace::Execution::SRS_SIZE); + + avm_trace::Execution::check_circuit(avm_public_inputs, avm_hints); + + print_avm_stats(); +} + /** * @brief Writes an avm proof and corresponding (incomplete) verification key to files. * @@ -695,55 +716,37 @@ void print_avm_stats() */ void avm_prove(const std::filesystem::path& public_inputs_path, const std::filesystem::path& hints_path, - const std::filesystem::path& output_path, - const bool check_circuit_only) + const std::filesystem::path& output_path) { const auto avm_public_inputs = AvmPublicInputs::from(read_file(public_inputs_path)); const auto avm_hints = bb::avm_trace::ExecutionHints::from(read_file(hints_path)); - - if (avm_hints.all_contract_bytecode.size() > 0) { - // Using [0] is fine now for the top-level call, but we might need to index by address in future - vinfo("bytecode size: ", avm_hints.all_contract_bytecode[0].bytecode.size()); - } - vinfo("hints.storage_read_hints size: ", avm_hints.storage_read_hints.size()); - vinfo("hints.storage_write_hints size: ", avm_hints.storage_write_hints.size()); - vinfo("hints.nullifier_read_hints size: ", avm_hints.nullifier_read_hints.size()); - vinfo("hints.nullifier_write_hints size: ", avm_hints.nullifier_write_hints.size()); - vinfo("hints.note_hash_read_hints size: ", avm_hints.note_hash_read_hints.size()); - vinfo("hints.note_hash_write_hints size: ", avm_hints.note_hash_write_hints.size()); - vinfo("hints.l1_to_l2_message_read_hints size: ", avm_hints.l1_to_l2_message_read_hints.size()); - vinfo("hints.contract_instance_hints size: ", avm_hints.contract_instance_hints.size()); - vinfo("hints.contract_bytecode_hints size: ", avm_hints.all_contract_bytecode.size()); + avm_hints.print_sizes(); vinfo("initializing crs with size: ", avm_trace::Execution::SRS_SIZE); init_bn254_crs(avm_trace::Execution::SRS_SIZE); - if (check_circuit_only) { - avm_trace::Execution::check_circuit(avm_public_inputs, avm_hints); - } else { - // Prove execution and return vk - auto const [verification_key, proof] = - AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(avm_public_inputs, avm_hints)); - - std::vector vk_as_fields = verification_key.to_field_elements(); - - vinfo("vk fields size: ", vk_as_fields.size()); - vinfo("circuit size: ", static_cast(vk_as_fields[0])); - vinfo("num of pub inputs: ", static_cast(vk_as_fields[1])); - - std::string vk_json = to_json(vk_as_fields); - const auto proof_path = output_path / "proof"; - const auto vk_path = output_path / "vk"; - const auto vk_fields_path = output_path / "vk_fields.json"; - - write_file(proof_path, to_buffer(proof)); - vinfo("proof written to: ", proof_path); - write_file(vk_path, to_buffer(vk_as_fields)); - vinfo("vk written to: ", vk_path); - write_file(vk_fields_path, { vk_json.begin(), vk_json.end() }); - vinfo("vk as fields written to: ", vk_fields_path); - } + // Prove execution and return vk + auto const [verification_key, proof] = + AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(avm_public_inputs, avm_hints)); + + std::vector vk_as_fields = verification_key.to_field_elements(); + + vinfo("vk fields size: ", vk_as_fields.size()); + vinfo("circuit size: ", static_cast(vk_as_fields[0])); + vinfo("num of pub inputs: ", static_cast(vk_as_fields[1])); + + std::string vk_json = to_json(vk_as_fields); + const auto proof_path = output_path / "proof"; + const auto vk_path = output_path / "vk"; + const auto vk_fields_path = output_path / "vk_fields.json"; + + write_file(proof_path, to_buffer(proof)); + vinfo("proof written to: ", proof_path); + write_file(vk_path, to_buffer(vk_as_fields)); + vinfo("vk written to: ", vk_path); + write_file(vk_fields_path, { vk_json.begin(), vk_json.end() }); + vinfo("vk as fields written to: ", vk_fields_path); print_avm_stats(); } @@ -1455,6 +1458,13 @@ int main(int argc, char* argv[]) std::filesystem::path public_inputs_path = get_option(args, "--avm-public-inputs", "./target/avm_public_inputs.bin"); return avm2_verify(proof_path, public_inputs_path, vk_path) ? 0 : 1; + } else if (command == "avm_check_circuit") { + std::filesystem::path avm_public_inputs_path = + get_option(args, "--avm-public-inputs", "./target/avm_public_inputs.bin"); + std::filesystem::path avm_hints_path = get_option(args, "--avm-hints", "./target/avm_hints.bin"); + extern std::filesystem::path avm_dump_trace_path; + avm_dump_trace_path = get_option(args, "--avm-dump-trace", ""); + avm_check_circuit(avm_public_inputs_path, avm_hints_path); } else if (command == "avm_prove") { std::filesystem::path avm_public_inputs_path = get_option(args, "--avm-public-inputs", "./target/avm_public_inputs.bin"); @@ -1463,8 +1473,7 @@ int main(int argc, char* argv[]) std::filesystem::path output_path = get_option(args, "-o", "./proofs"); extern std::filesystem::path avm_dump_trace_path; avm_dump_trace_path = get_option(args, "--avm-dump-trace", ""); - const bool check_circuit_only = flag_present(args, "--check-circuit-only"); - avm_prove(avm_public_inputs_path, avm_hints_path, output_path, check_circuit_only); + avm_prove(avm_public_inputs_path, avm_hints_path, output_path); } else if (command == "avm_verify") { return avm_verify(proof_path, vk_path) ? 0 : 1; #endif diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp index dc554ebd2b5c..568af787cf02 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp @@ -257,6 +257,24 @@ struct ExecutionHints { return *this; } + void print_sizes() const + { + vinfo("hints.enqueued_call_hints size: ", enqueued_call_hints.size()); + vinfo("hints.contract_instance_hints size: ", contract_instance_hints.size()); + vinfo("hints.contract_bytecode_hints size: ", all_contract_bytecode.size()); + if (all_contract_bytecode.size() > 0) { + // Using [0] is fine now for the top-level call, but we might need to index by address in future + vinfo("0th bytecode size: ", all_contract_bytecode[0].bytecode.size()); + } + vinfo("hints.storage_read_hints size: ", storage_read_hints.size()); + vinfo("hints.storage_write_hints size: ", storage_write_hints.size()); + vinfo("hints.nullifier_read_hints size: ", nullifier_read_hints.size()); + vinfo("hints.nullifier_write_hints size: ", nullifier_write_hints.size()); + vinfo("hints.note_hash_read_hints size: ", note_hash_read_hints.size()); + vinfo("hints.note_hash_write_hints size: ", note_hash_write_hints.size()); + vinfo("hints.l1_to_l2_message_read_hints size: ", l1_to_l2_message_read_hints.size()); + } + static void push_vec_into_map(std::unordered_map& into_map, const std::vector>& from_pair_vec) { diff --git a/yarn-project/bb-prover/src/bb/execute.ts b/yarn-project/bb-prover/src/bb/execute.ts index 731d575e3a9b..7089f888e23a 100644 --- a/yarn-project/bb-prover/src/bb/execute.ts +++ b/yarn-project/bb-prover/src/bb/execute.ts @@ -573,7 +573,7 @@ export async function generateAvmProofV2( } /** - * Used for generating AVM proofs. + * Used for generating AVM proofs (or doing check-circuit). * It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof. * @param pathToBB - The full path to the bb binary * @param workingDirectory - A working directory for use by bb @@ -637,10 +637,11 @@ export async function generateAvmProof( checkCircuitOnly ? '--check-circuit-only' : '', ]; const timer = new Timer(); + const cmd = checkCircuitOnly ? 'check_circuit' : 'prove'; const logFunction = (message: string) => { - logger.verbose(`AvmCircuit (prove) BB out - ${message}`); + logger.verbose(`AvmCircuit (${cmd}) BB out - ${message}`); }; - const result = await executeBB(pathToBB, 'avm_prove', args, logFunction); + const result = await executeBB(pathToBB, `avm_${cmd}`, args, logFunction); const duration = timer.ms(); if (result.status == BB_RESULT.SUCCESS) {