diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp index 9b525d2e6aa4..de01c08e2793 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp @@ -2,7 +2,6 @@ #include "function_data.hpp" #include "tx_context.hpp" -#include "aztec3/utils/array.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 73800bc8f415..080a28f80726 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -8,7 +8,7 @@ import { AztecAddress, CompleteAddress, FunctionData, - KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PartialAddress, PrivateKey, @@ -418,7 +418,7 @@ export class AztecRPCServer implements AztecRPC { // See https://github.com/AztecProtocol/aztec-packages/issues/1615 // TODO(#757): Enforce proper ordering of enqueued public calls private async patchPublicCallStackOrdering( - publicInputs: KernelCircuitPublicInputs, + publicInputs: KernelCircuitPublicInputsFinal, enqueuedPublicCalls: PublicCallRequest[], ) { const callToHash = (call: PublicCallRequest) => call.toPublicCallStackItem().then(item => item.hash()); diff --git a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts index 94afeca021d8..8791f403328d 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts @@ -18,7 +18,7 @@ import { } from '@aztec/circuits.js'; import { assertLength } from '@aztec/foundation/serialize'; -import { KernelProofCreator, ProofCreator, ProofOutput } from './proof_creator.js'; +import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js'; import { ProvingDataOracle } from './proving_data_oracle.js'; /** @@ -45,7 +45,7 @@ export interface OutputNoteData { * Represents the output data of the Kernel Prover. * Provides information about the newly created notes, along with the public inputs and proof. */ -export interface KernelProverOutput extends ProofOutput { +export interface KernelProverOutput extends ProofOutputFinal { /** * An array of output notes containing the contract address, note data, and commitment for each new note. */ @@ -163,13 +163,13 @@ export class KernelProver { assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); - output = await this.proofCreator.createProofOrdering(previousKernelData); + const outputFinal = await this.proofCreator.createProofOrdering(previousKernelData); // Only return the notes whose commitment is in the commitments of the final proof. - const finalNewCommitments = output.publicInputs.end.newCommitments; + const finalNewCommitments = outputFinal.publicInputs.end.newCommitments; const outputNotes = finalNewCommitments.map(c => newNotes[c.toString()]).filter(c => !!c); - return { ...output, outputNotes }; + return { ...outputFinal, outputNotes }; } private async createPrivateCallData( diff --git a/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts b/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts index fe6ce191bd8b..1fc7712f33d6 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts @@ -2,6 +2,7 @@ import { CircuitError, CircuitsWasm, KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, PreviousKernelData, PrivateCallData, PrivateCircuitPublicInputs, @@ -17,8 +18,8 @@ import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; /** - * Represents the output of the proof creation process. - * Contains the public inputs required for the kernel circuit and the generated proof. + * Represents the output of the proof creation process for init and inner private kernel circuit. + * Contains the public inputs required for the init and inner private kernel circuit and the generated proof. */ export interface ProofOutput { /** @@ -31,6 +32,21 @@ export interface ProofOutput { proof: Proof; } +/** + * Represents the output of the proof creation process for final ordering private kernel circuit. + * Contains the public inputs required for the final ordering private kernel circuit and the generated proof. + */ +export interface ProofOutputFinal { + /** + * The public inputs required for the proof generation process. + */ + publicInputs: KernelCircuitPublicInputsFinal; + /** + * The zk-SNARK proof for the kernel execution. + */ + proof: Proof; +} + /** * ProofCreator provides functionality to create and validate proofs, and retrieve * siloed commitments necessary for maintaining transaction privacy and security on the network. @@ -68,7 +84,7 @@ export interface ProofCreator { * @param previousKernelData - The previous kernel data object. * @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof. */ - createProofOrdering(previousKernelData: PreviousKernelData): Promise; + createProofOrdering(previousKernelData: PreviousKernelData): Promise; } /** @@ -121,7 +137,7 @@ export class KernelProofCreator implements ProofCreator { }; } - public async createProofOrdering(previousKernelData: PreviousKernelData): Promise { + public async createProofOrdering(previousKernelData: PreviousKernelData): Promise { const wasm = await CircuitsWasm.get(); this.log('Executing private kernel simulation ordering...'); const result = privateKernelSimOrdering(wasm, previousKernelData); @@ -133,7 +149,7 @@ export class KernelProofCreator implements ProofCreator { const proof = makeEmptyProof(); this.log('Ordering Kernel Prover Ordering Completed!'); - const publicInputs = result as KernelCircuitPublicInputs; + const publicInputs = result as KernelCircuitPublicInputsFinal; return { publicInputs, diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index 39dff6c141ec..a20febec7143 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -22,8 +22,6 @@ export { AggregationObject as NativeAggregationState, AztecAddress as Address, VerificationKey as VerificationKeyData, - PrivateKernelPublicInputs as PublicInputs, - PrivateKernelPublicInputsFinal as PublicInputsFinal, Fr, Fq, G1AffineElement, diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index d3dedcd7db7e..798b59cdf356 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -15,6 +15,7 @@ import { NUM_FIELDS_PER_SHA256, } from '../../cbind/constants.gen.js'; import { assertMemberLength, makeTuple } from '../../index.js'; +import { makeEmptyReadRequestMembershipWitness } from '../../tests/factories.js'; import { serializeToBuffer } from '../../utils/serialize.js'; import { AggregationObject, @@ -428,6 +429,28 @@ export class CombinedAccumulatedData { ); } + static fromFinalAccumulatedData(finalData: FinalAccumulatedData): CombinedAccumulatedData { + return new CombinedAccumulatedData( + finalData.aggregationObject, + makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero), + makeTuple(MAX_READ_REQUESTS_PER_TX, makeEmptyReadRequestMembershipWitness), + finalData.newCommitments, + finalData.newNullifiers, + finalData.nullifiedCommitments, + finalData.privateCallStack, + finalData.publicCallStack, + finalData.newL2ToL1Msgs, + finalData.encryptedLogsHash, + finalData.unencryptedLogsHash, + finalData.encryptedLogPreimagesLength, + finalData.unencryptedLogPreimagesLength, + finalData.newContracts, + finalData.optionallyRevealedData, + makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), + ); + } + /** * Deserializes from a string, corresponding to a write in cpp. * @param str - String to read from. diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 835210bccf52..dadab826aa27 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -466,6 +466,15 @@ export function makeReadRequestMembershipWitness(start: number): ReadRequestMemb ); } +/** + * Creates empty membership witness where the sibling paths is an array of fields filled with zeros. + * @param start - The start of the membership witness. + * @returns Non-transient empty read request membership witness. + */ +export function makeEmptyReadRequestMembershipWitness(): ReadRequestMembershipWitness { + return new ReadRequestMembershipWitness(new Fr(0), makeTuple(PRIVATE_DATA_TREE_HEIGHT, Fr.zero), false, new Fr(0)); +} + /** * Creates arbitrary/mocked verification key. * @returns A verification key. diff --git a/yarn-project/p2p/src/service/tx_messages.test.ts b/yarn-project/p2p/src/service/tx_messages.test.ts index 21cc5c51efef..da6c9f79be5e 100644 --- a/yarn-project/p2p/src/service/tx_messages.test.ts +++ b/yarn-project/p2p/src/service/tx_messages.test.ts @@ -1,5 +1,5 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof } from '@aztec/circuits.js'; -import { makeKernelPublicInputs, makePublicCallRequest } from '@aztec/circuits.js/factories'; +import { makeKernelPublicInputsFinal, makePublicCallRequest } from '@aztec/circuits.js/factories'; import { EncodedContractFunction, Tx, TxHash, TxL2Logs } from '@aztec/types'; import { expect } from '@jest/globals'; @@ -24,7 +24,7 @@ const makeTx = () => { const encodedPublicFunctions = [EncodedContractFunction.random(), EncodedContractFunction.random()]; const enqueuedPublicFunctionCalls = times(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, i => makePublicCallRequest(i)); return new Tx( - makeKernelPublicInputs(), + makeKernelPublicInputsFinal(), Proof.fromBuffer(Buffer.alloc(10, 9)), TxL2Logs.random(8, 2), TxL2Logs.random(8, 3), diff --git a/yarn-project/p2p/src/service/tx_messages.ts b/yarn-project/p2p/src/service/tx_messages.ts index 170ea6f63aab..fe0bc6f72bd0 100644 --- a/yarn-project/p2p/src/service/tx_messages.ts +++ b/yarn-project/p2p/src/service/tx_messages.ts @@ -1,4 +1,4 @@ -import { KernelCircuitPublicInputs, Proof, PublicCallRequest } from '@aztec/circuits.js'; +import { KernelCircuitPublicInputsFinal, Proof, PublicCallRequest } from '@aztec/circuits.js'; import { numToUInt32BE } from '@aztec/foundation/serialize'; import { EncodedContractFunction, Tx, TxHash, TxL2Logs } from '@aztec/types'; @@ -186,7 +186,7 @@ export function fromTxMessage(buffer: Buffer): Tx { }; // this is the opposite of the 'toMessage' function // so the first 4 bytes is the complete length, skip it - const publicInputs = toObject(buffer.subarray(4), KernelCircuitPublicInputs); + const publicInputs = toObject(buffer.subarray(4), KernelCircuitPublicInputsFinal); const proof = toObject(publicInputs.remainingData, Proof); const encryptedLogs = toObject(proof.remainingData, TxL2Logs); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 099b240f9c8e..5473d199a91a 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -22,7 +22,7 @@ import { computeBlockHashWithGlobals, computeContractLeaf } from '@aztec/circuit import { fr, makeBaseOrMergeRollupPublicInputs, - makeKernelPublicInputs, + makeKernelPublicInputsFinal, makeNewContractData, makeProof, makePublicCallRequest, @@ -168,7 +168,7 @@ describe('sequencer/solo_block_builder', () => { }; const buildMockSimulatorInputs = async () => { - const kernelOutput = makeKernelPublicInputs(); + const kernelOutput = makeKernelPublicInputsFinal(); kernelOutput.constants.blockData = await getHistoricBlockData(expectsDb); const tx = await makeProcessedTx( diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index fbf80ff5f039..ce25a8d3dead 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -1,11 +1,22 @@ -import { Fr, HistoricBlockData, KernelCircuitPublicInputs, Proof, makeEmptyProof } from '@aztec/circuits.js'; +import { + CombinedAccumulatedData, + Fr, + HistoricBlockData, + KernelCircuitPublicInputs, + Proof, + makeEmptyProof, +} from '@aztec/circuits.js'; import { Tx, TxHash, TxL2Logs } from '@aztec/types'; /** * Represents a tx that has been processed by the sequencer public processor, * so its kernel circuit public inputs are filled in. */ -export type ProcessedTx = Pick & { +export type ProcessedTx = Pick & { + /** + * Output of the public kernel circuit for this tx. + */ + data: KernelCircuitPublicInputs; /** * Hash of the transaction. */ @@ -47,7 +58,13 @@ export async function makeProcessedTx( ): Promise { return { hash: await tx.getTxHash(), - data: kernelOutput ?? tx.data, + data: + kernelOutput ?? + new KernelCircuitPublicInputs( + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + tx.data.isPrivate, + ), proof: proof ?? tx.proof, encryptedLogs: tx.encryptedLogs, unencryptedLogs: tx.unencryptedLogs, diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 2f2fa204759e..ae21e1a5b830 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -4,11 +4,13 @@ import { AztecAddress, CallContext, CircuitsWasm, + CombinedAccumulatedData, EthAddress, Fr, FunctionData, GlobalVariables, HistoricBlockData, + KernelCircuitPublicInputs, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PUBLIC_DATA_TREE_HEIGHT, @@ -20,7 +22,7 @@ import { import { computeCallStackItemHash } from '@aztec/circuits.js/abis'; import { makeAztecAddress, - makeKernelPublicInputs, + makeKernelPublicInputsFinal, makePublicCallRequest, makeSelector, } from '@aztec/circuits.js/factories'; @@ -39,7 +41,6 @@ import { import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state'; import { MockProxy, mock } from 'jest-mock-extended'; -import pick from 'lodash.pick'; import times from 'lodash.times'; import { PublicProver } from '../prover/index.js'; @@ -101,7 +102,18 @@ describe('public_processor', () => { const [processed, failed] = await processor.process([tx]); expect(processed).toEqual([ - { isEmpty: false, hash, ...pick(tx, 'data', 'proof', 'encryptedLogs', 'unencryptedLogs') }, + { + isEmpty: false, + hash, + data: new KernelCircuitPublicInputs( + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + tx.data.isPrivate, + ), + proof: tx.proof, + encryptedLogs: tx.encryptedLogs, + unencryptedLogs: tx.unencryptedLogs, + }, ]); expect(failed).toEqual([]); }); @@ -151,7 +163,7 @@ describe('public_processor', () => { const callStackItems = await Promise.all(callRequests.map(call => call.toPublicCallStackItem())); const callStackHashes = callStackItems.map(call => computeCallStackItemHash(wasm, call)); - const kernelOutput = makeKernelPublicInputs(0x10); + const kernelOutput = makeKernelPublicInputsFinal(0x10); kernelOutput.end.publicCallStack = padArrayEnd(callStackHashes, Fr.ZERO, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); kernelOutput.end.privateCallStack = padArrayEnd([], Fr.ZERO, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); @@ -179,7 +191,7 @@ describe('public_processor', () => { const callStackItem = await callRequest.toPublicCallStackItem(); const callStackHash = computeCallStackItemHash(wasm, callStackItem); - const kernelOutput = makeKernelPublicInputs(0x10); + const kernelOutput = makeKernelPublicInputsFinal(0x10); kernelOutput.end.publicCallStack = padArrayEnd([callStackHash], Fr.ZERO, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); kernelOutput.end.privateCallStack = padArrayEnd([], Fr.ZERO, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 8ff1a223ca0b..839a4b9869f8 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -9,6 +9,7 @@ import { import { AztecAddress, CircuitsWasm, + CombinedAccumulatedData, ContractStorageRead, ContractStorageUpdateRequest, Fr, @@ -149,7 +150,11 @@ export class PublicProcessor { this.log(`Executing enqueued public calls for tx ${await tx.getTxHash()}`); if (!tx.enqueuedPublicFunctionCalls) throw new Error(`Missing preimages for enqueued public calls`); - let kernelOutput = tx.data; + let kernelOutput = new KernelCircuitPublicInputs( + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + tx.data.isPrivate, + ); let kernelProof = tx.proof; const newUnencryptedFunctionLogs: FunctionL2Logs[] = []; diff --git a/yarn-project/types/src/mocks.ts b/yarn-project/types/src/mocks.ts index 9136d6adb8f2..552a8e7dee8d 100644 --- a/yarn-project/types/src/mocks.ts +++ b/yarn-project/types/src/mocks.ts @@ -1,5 +1,5 @@ import { AztecAddress, EthAddress, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof } from '@aztec/circuits.js'; -import { makeKernelPublicInputs, makePublicCallRequest } from '@aztec/circuits.js/factories'; +import { makeKernelPublicInputsFinal, makePublicCallRequest } from '@aztec/circuits.js/factories'; import { ContractAbi } from '@aztec/foundation/abi'; import { randomBytes } from '@aztec/foundation/crypto'; @@ -18,7 +18,7 @@ export function makeEmptyLogs(): TxL2Logs { export const mockTx = (seed = 1) => { return new Tx( - makeKernelPublicInputs(seed), + makeKernelPublicInputsFinal(seed), new Proof(Buffer.alloc(0)), TxL2Logs.random(8, 3), // 8 priv function invocations creating 3 encrypted logs each TxL2Logs.random(11, 2), // 8 priv + 3 pub function invocations creating 2 unencrypted logs each diff --git a/yarn-project/types/src/tx/tx.ts b/yarn-project/types/src/tx/tx.ts index 4ba5c6d83cd6..cfe3046bf197 100644 --- a/yarn-project/types/src/tx/tx.ts +++ b/yarn-project/types/src/tx/tx.ts @@ -1,7 +1,7 @@ import { AztecAddress, Fr, - KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PartialAddress, Proof, @@ -23,7 +23,7 @@ export class Tx { /** * Output of the private kernel circuit for this tx. */ - public readonly data: KernelCircuitPublicInputs, + public readonly data: KernelCircuitPublicInputsFinal, /** * Proof from the private kernel circuit. */ @@ -74,7 +74,7 @@ export class Tx { static fromBuffer(buffer: Buffer | BufferReader): Tx { const reader = BufferReader.asReader(buffer); return new Tx( - reader.readObject(KernelCircuitPublicInputs), + reader.readObject(KernelCircuitPublicInputsFinal), reader.readObject(Proof), reader.readObject(TxL2Logs), reader.readObject(TxL2Logs), @@ -121,7 +121,7 @@ export class Tx { * @returns A Tx class object. */ public static fromJSON(obj: any) { - const publicInputs = KernelCircuitPublicInputs.fromBuffer(Buffer.from(obj.data, 'hex')); + const publicInputs = KernelCircuitPublicInputsFinal.fromBuffer(Buffer.from(obj.data, 'hex')); const encryptedLogs = TxL2Logs.fromBuffer(Buffer.from(obj.encryptedLogs, 'hex')); const unencryptedLogs = TxL2Logs.fromBuffer(Buffer.from(obj.unencryptedLogs, 'hex')); const proof = Buffer.from(obj.proof, 'hex'); @@ -167,7 +167,7 @@ export class Tx { * @returns The cloned transaction. */ static clone(tx: Tx): Tx { - const publicInputs = KernelCircuitPublicInputs.fromBuffer(tx.data.toBuffer()); + const publicInputs = KernelCircuitPublicInputsFinal.fromBuffer(tx.data.toBuffer()); const proof = Proof.fromBuffer(tx.proof.toBuffer()); const encryptedLogs = TxL2Logs.fromBuffer(tx.encryptedLogs.toBuffer()); const unencryptedLogs = TxL2Logs.fromBuffer(tx.unencryptedLogs.toBuffer());