From 785591e0527beef7adf0f7a791618afff9df3705 Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:40:29 +0100 Subject: [PATCH] fix: Take a deep copy of circuit inputs for proving (#5777) This PR ensures we take a copy of the circuit inputs during simulation for use in proving. --- .circleci/config.yml | 94 +++++++++---------- .../structs/kernel/public_call_data.test.ts | 10 ++ .../src/structs/kernel/public_call_data.ts | 26 +++-- ...blic_kernel_circuit_private_inputs.test.ts | 17 ++++ .../public_kernel_circuit_private_inputs.ts | 17 +++- ...kernel_tail_circuit_private_inputs.test.ts | 17 ++++ ...blic_kernel_tail_circuit_private_inputs.ts | 24 ++++- .../non_existent_read_request_hints.ts | 7 +- .../src/public/abstract_phase_manager.ts | 7 +- .../src/public/tail_phase_manager.ts | 4 +- 10 files changed, 158 insertions(+), 65 deletions(-) create mode 100644 yarn-project/circuits.js/src/structs/kernel/public_call_data.test.ts create mode 100644 yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.test.ts create mode 100644 yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.test.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 5b7245c3e60..6b4c8af64ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -531,35 +531,35 @@ jobs: # Semantics are similar to Dockerfile # NOTE: Unlike other e2e, these will be re-enabled here as currently the logs functionality is not in the new earthfile setup - # bench-publish-rollup: - # steps: - # - *checkout - # - *setup_env - # - run: - # name: "Benchmark" - # command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_publish_rollup.test.ts DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees - # aztec_manifest_key: end-to-end - # <<: *defaults_e2e_test - - # bench-process-history: - # steps: - # - *checkout - # - *setup_env - # - run: - # name: "Benchmark" - # command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_process_history.test.ts DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees - # aztec_manifest_key: end-to-end - # <<: *defaults_e2e_test - - # bench-tx-size: - # steps: - # - *checkout - # - *setup_env - # - run: - # name: "Benchmark" - # command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_tx_size_fees.test.ts ENABLE_GAS=1 DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees - # aztec_manifest_key: end-to-end - # <<: *defaults_e2e_test + bench-publish-rollup: + steps: + - *checkout + - *setup_env + - run: + name: "Benchmark" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_publish_rollup.test.ts DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees + aztec_manifest_key: end-to-end + <<: *defaults_e2e_test + + bench-process-history: + steps: + - *checkout + - *setup_env + - run: + name: "Benchmark" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_process_history.test.ts DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees + aztec_manifest_key: end-to-end + <<: *defaults_e2e_test + + bench-tx-size: + steps: + - *checkout + - *setup_env + - run: + name: "Benchmark" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_tx_size_fees.test.ts ENABLE_GAS=1 DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees + aztec_manifest_key: end-to-end + <<: *defaults_e2e_test build-docs: machine: @@ -597,15 +597,15 @@ jobs: name: "Noop" command: echo Noop - # bench-summary: - # machine: - # image: default - # steps: - # - *checkout - # - *setup_env - # - run: - # name: "Assemble benchmark summary from uploaded logs" - # command: ./scripts/ci/assemble_e2e_benchmark.sh + bench-summary: + machine: + image: default + steps: + - *checkout + - *setup_env + - run: + name: "Assemble benchmark summary from uploaded logs" + command: ./scripts/ci/assemble_e2e_benchmark.sh # Deploy & release jobs. deploy-and-release: @@ -898,15 +898,15 @@ workflows: <<: *defaults # Benchmark jobs. - # - bench-publish-rollup: *e2e_test - # - bench-process-history: *e2e_test - # - bench-tx-size: *e2e_test - # - bench-summary: - # requires: - # - bench-publish-rollup - # - bench-process-history - # - bench-tx-size - # <<: *defaults + - bench-publish-rollup: *e2e_test + - bench-process-history: *e2e_test + - bench-tx-size: *e2e_test + - bench-summary: + requires: + - bench-publish-rollup + - bench-process-history + - bench-tx-size + <<: *defaults # Production releases. - deploy-and-release: *defaults_deploy diff --git a/yarn-project/circuits.js/src/structs/kernel/public_call_data.test.ts b/yarn-project/circuits.js/src/structs/kernel/public_call_data.test.ts new file mode 100644 index 00000000000..cafa167f31e --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/public_call_data.test.ts @@ -0,0 +1,10 @@ +import { makePublicCallData } from '../../tests/factories.js'; +import { PublicCallData } from './public_call_data.js'; + +describe('PublicCallData', () => { + it('PublicCallData after serialization and deserialization is equal to the original', () => { + const original = makePublicCallData(123, true); + const serialized = PublicCallData.fromBuffer(original.toBuffer()); + expect(original).toEqual(serialized); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/kernel/public_call_data.ts b/yarn-project/circuits.js/src/structs/kernel/public_call_data.ts index 5d53b9a49a7..249bd3fa1a8 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_call_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_call_data.ts @@ -1,10 +1,10 @@ -import { type Fr } from '@aztec/foundation/fields'; -import { type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; -import { type MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL } from '../../constants.gen.js'; -import { type CallRequest } from '../call_request.js'; -import { type Proof } from '../proof.js'; -import { type PublicCallStackItem } from '../public_call_stack_item.js'; +import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL } from '../../constants.gen.js'; +import { CallRequest } from '../call_request.js'; +import { Proof } from '../proof.js'; +import { PublicCallStackItem } from '../public_call_stack_item.js'; /** * Public calldata assembled from the kernel execution result and proof. @@ -42,4 +42,18 @@ export class PublicCallData { this.bytecodeHash, ); } + + static fromBuffer(buffer: BufferReader | Buffer) { + const reader = BufferReader.asReader(buffer); + return new PublicCallData( + reader.readObject(PublicCallStackItem), + reader.readArray( + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + CallRequest, + ), + reader.readObject(Proof), + reader.readObject(Fr), + reader.readObject(Fr), + ); + } } diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.test.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.test.ts new file mode 100644 index 00000000000..0240c1b081c --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.test.ts @@ -0,0 +1,17 @@ +import { makePublicKernelCircuitPrivateInputs } from '../../tests/factories.js'; +import { PublicKernelCircuitPrivateInputs } from './public_kernel_circuit_private_inputs.js'; + +describe('PublicKernelCircuitPrivateInputs', () => { + it('PublicKernelCircuitPrivateInputs after serialization and deserialization is equal to the original', () => { + const original = makePublicKernelCircuitPrivateInputs(123); + const serialized = PublicKernelCircuitPrivateInputs.fromBuffer(original.toBuffer()); + expect(original).toEqual(serialized); + }); + + it('PublicKernelCircuitPrivateInputs after clone is equal to the original', () => { + const original = makePublicKernelCircuitPrivateInputs(123); + const serialized = original.clone(); + expect(original).toEqual(serialized); + expect(original).not.toBe(serialized); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.ts index 86530dc0f4d..63f377cd63c 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_private_inputs.ts @@ -1,7 +1,7 @@ -import { serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { type PublicCallData } from './public_call_data.js'; -import { type PublicKernelData } from './public_kernel_data.js'; +import { PublicCallData } from './public_call_data.js'; +import { PublicKernelData } from './public_kernel_data.js'; /** * Inputs to the public kernel circuit. @@ -21,4 +21,15 @@ export class PublicKernelCircuitPrivateInputs { toBuffer() { return serializeToBuffer(this.previousKernel, this.publicCall); } + + static fromBuffer(buffer: BufferReader | Buffer) { + const reader = BufferReader.asReader(buffer); + const previousKernel = reader.readObject(PublicKernelData); + const publicCall = reader.readObject(PublicCallData); + return new PublicKernelCircuitPrivateInputs(previousKernel, publicCall); + } + + clone() { + return PublicKernelCircuitPrivateInputs.fromBuffer(this.toBuffer()); + } } diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.test.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.test.ts new file mode 100644 index 00000000000..e53f3f2df21 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.test.ts @@ -0,0 +1,17 @@ +import { makePublicKernelTailCircuitPrivateInputs } from '../../tests/factories.js'; +import { PublicKernelTailCircuitPrivateInputs } from './public_kernel_tail_circuit_private_inputs.js'; + +describe('PublicKernelTailCircuitPrivateInputs', () => { + it('PublicKernelTailCircuitPrivateInputs after serialization and deserialization is equal to the original', () => { + const original = makePublicKernelTailCircuitPrivateInputs(123); + const serialized = PublicKernelTailCircuitPrivateInputs.fromBuffer(original.toBuffer()); + expect(original).toEqual(serialized); + }); + + it('PublicKernelTailCircuitPrivateInputs after clone is equal to the original', () => { + const original = makePublicKernelTailCircuitPrivateInputs(123); + const serialized = original.clone(); + expect(original).toEqual(serialized); + expect(original).not.toBe(serialized); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts index 073c0598861..be3037d4565 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts @@ -1,8 +1,11 @@ -import { serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { type NullifierNonExistentReadRequestHints } from '../non_existent_read_request_hints.js'; -import { type NullifierReadRequestHints } from '../read_request_hints.js'; -import { type PublicKernelData } from './public_kernel_data.js'; +import { + type NullifierNonExistentReadRequestHints, + nullifierNonExistentReadRequestHintsFromBuffer, +} from '../non_existent_read_request_hints.js'; +import { type NullifierReadRequestHints, nullifierReadRequestHintsFromBuffer } from '../read_request_hints.js'; +import { PublicKernelData } from './public_kernel_data.js'; /** * Inputs to the public kernel circuit. @@ -30,4 +33,17 @@ export class PublicKernelTailCircuitPrivateInputs { this.nullifierNonExistentReadRequestHints, ); } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PublicKernelTailCircuitPrivateInputs( + reader.readObject(PublicKernelData), + nullifierReadRequestHintsFromBuffer(reader), + nullifierNonExistentReadRequestHintsFromBuffer(reader), + ); + } + + clone() { + return PublicKernelTailCircuitPrivateInputs.fromBuffer(this.toBuffer()); + } } diff --git a/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts b/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts index a459be8be34..9659c63d0c3 100644 --- a/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts @@ -84,7 +84,12 @@ export class NonExistentReadRequestHints< } toBuffer() { - return serializeToBuffer(this.nonMembershipHints, this.nextPendingValueIndices); + return serializeToBuffer( + this.nonMembershipHints, + this.nextPendingValueIndices, + this.sortedPendingValues, + this.sortedPendingValueHints, + ); } } diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index 1ccbf3669cc..cb56906ea2a 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -339,14 +339,15 @@ export abstract class AbstractPhaseManager { ): Promise<[PublicKernelCircuitPrivateInputs, PublicKernelCircuitPublicInputs]> { const previousKernel = this.getPreviousKernelData(previousOutput, previousProof); + // We take a deep copy (clone) of these inputs to be passed to the prover const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, callData); switch (this.phase) { case PublicKernelPhase.SETUP: - return [inputs, await this.publicKernel.publicKernelCircuitSetup(inputs)]; + return [inputs.clone(), await this.publicKernel.publicKernelCircuitSetup(inputs)]; case PublicKernelPhase.APP_LOGIC: - return [inputs, await this.publicKernel.publicKernelCircuitAppLogic(inputs)]; + return [inputs.clone(), await this.publicKernel.publicKernelCircuitAppLogic(inputs)]; case PublicKernelPhase.TEARDOWN: - return [inputs, await this.publicKernel.publicKernelCircuitTeardown(inputs)]; + return [inputs.clone(), await this.publicKernel.publicKernelCircuitTeardown(inputs)]; default: throw new Error(`No public kernel circuit for inputs`); } diff --git a/yarn-project/simulator/src/public/tail_phase_manager.ts b/yarn-project/simulator/src/public/tail_phase_manager.ts index 0cc78be521f..44ebe1dd2d3 100644 --- a/yarn-project/simulator/src/public/tail_phase_manager.ts +++ b/yarn-project/simulator/src/public/tail_phase_manager.ts @@ -101,12 +101,14 @@ export class TailPhaseManager extends AbstractPhaseManager { endNonRevertibleData.newNullifiers, end.newNullifiers, ); + + // We take a deep copy (clone) of these to pass to the prover const inputs = new PublicKernelTailCircuitPrivateInputs( previousKernel, nullifierReadRequestHints, nullifierNonExistentReadRequestHints, ); - return [inputs, await this.publicKernel.publicKernelCircuitTail(inputs)]; + return [inputs.clone(), await this.publicKernel.publicKernelCircuitTail(inputs)]; } private sortNoteHashes(noteHashes: Tuple): Tuple {