diff --git a/README.md b/README.md index a02be8117158..6d127df72c7d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The Aztec 3 system consists of the following sub projects. - `aztec-rpc` - `aztec.js` - `ethereum.js` -- `kernel-simulator` +- `kernel-prover` - `key-store` - `l1-contracts` - `p2p` diff --git a/build_manifest.json b/build_manifest.json index e0d49269ab08..c6817fce918c 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -101,11 +101,11 @@ "rebuildPatterns": ["^yarn-project/foundation/"], "dependencies": [] }, - "kernel-simulator": { + "kernel-prover": { "buildDir": "yarn-project", - "projectDir": "yarn-project/kernel-simulator", - "dockerfile": "kernel-simulator/Dockerfile", - "rebuildPatterns": ["^yarn-project/kernel-simulator/"], + "projectDir": "yarn-project/kernel-prover", + "dockerfile": "kernel-prover/Dockerfile", + "rebuildPatterns": ["^yarn-project/kernel-prover/"], "dependencies": ["yarn-project-base"] }, "key-store": { diff --git a/build_manifest.sh b/build_manifest.sh index 6cd66ec2600f..7857d7653f38 100755 --- a/build_manifest.sh +++ b/build_manifest.sh @@ -18,7 +18,7 @@ PROJECTS=( # aztec.js:yarn-project # end-to-end:yarn-project # ethereum.js:yarn-project - # kernel-simulator:yarn-project + # kernel-prover:yarn-project # key-store:yarn-project # merkle-tree:yarn-project # p2p:yarn-project diff --git a/yarn-project/acir-simulator/src/acvm.ts b/yarn-project/acir-simulator/src/acvm.ts new file mode 100644 index 000000000000..2c2f5daabe24 --- /dev/null +++ b/yarn-project/acir-simulator/src/acvm.ts @@ -0,0 +1,31 @@ +import { AztecAddress, CallContext, ContractDeploymentData } from './circuits.js'; +import { NoteLoadOracleInputs } from './db_oracle.js'; + +export interface ACIRCallback { + getSecretKey(keyId: Buffer): Promise; + getNotes(storageSlot: Buffer): Promise; + getRandomField(): Promise; + privateFunctionCall( + contractAddress: AztecAddress, + functionSelector: string, + args: Array, + ): Promise>; +} + +export interface ExecutionPreimages { + newNotes: Buffer[]; + nullifiedNotes: Buffer[]; +} + +export interface ACIRExecutionResult { + preimages: ExecutionPreimages; + partialWitness: Buffer; +} + +export type execute = ( + acir: Buffer, + args: Array, + callContext: CallContext, + contractDeploymentData: ContractDeploymentData, + oracle: ACIRCallback, +) => Promise; diff --git a/yarn-project/acir-simulator/src/circuits.ts b/yarn-project/acir-simulator/src/circuits.ts new file mode 100644 index 000000000000..917b55cc08a2 --- /dev/null +++ b/yarn-project/acir-simulator/src/circuits.ts @@ -0,0 +1,229 @@ +// See aztec3/constants.hpp +// Copied here for prototyping purposes +// In future: structured serialization? +export const ARGS_LENGTH = 8; +export const RETURN_VALUES_LENGTH = 4; +export const EMITTED_EVENTS_LENGTH = 4; + +export const NEW_COMMITMENTS_LENGTH = 4; +export const NEW_NULLIFIERS_LENGTH = 4; + +export const STATE_TRANSITIONS_LENGTH = 4; +export const STATE_READS_LENGTH = 4; + +export const PRIVATE_CALL_STACK_LENGTH = 4; +export const PUBLIC_CALL_STACK_LENGTH = 4; +export const L1_MSG_STACK_LENGTH = 2; + +export const KERNEL_NEW_COMMITMENTS_LENGTH = 16; +export const KERNEL_NEW_NULLIFIERS_LENGTH = 16; +export const KERNEL_NEW_CONTRACTS_LENGTH = 8; +export const KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; +export const KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; +export const KERNEL_L1_MSG_STACK_LENGTH = 4; +export const KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; + +export const VK_TREE_HEIGHT = 3; +export const CONTRACT_TREE_HEIGHT = 4; +export const PRIVATE_DATA_TREE_HEIGHT = 8; +export const NULLIFIER_TREE_HEIGHT = 8; + +export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; +export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; + +export const FUNCTION_SELECTOR_NUM_BYTES = 31; + +/** + * Assert a member is a certain length. + * @param obj - An object. + * @param member - A member string. + * @param length - The length. + */ +export function assertLength( + obj: T, + member: F, + length: number, +) { + if (obj[member].length !== length) { + throw new Error(`Expected ${member} to have length ${length}! Was: ${obj[member].length}`); + } +} + +export class Fr { + public static ZERO = new Fr(Buffer.alloc(32)); + + constructor(public readonly buffer: Buffer) {} +} + +export class AztecAddress { + public static SIZE = 64; + + public static ZERO = new AztecAddress(Buffer.alloc(AztecAddress.SIZE)); + + constructor(public readonly buffer: Buffer) {} + + public equals(rhs: AztecAddress) { + return this.buffer.equals(rhs.buffer); + } +} + +export class EthAddress { + public static ZERO = new EthAddress(Buffer.alloc(20)); + + constructor(public readonly buffer: Buffer) {} +} + +/** + * Call context. + * @see abis/call_context.hpp + */ +export class CallContext { + constructor( + public msgSender: AztecAddress, + public storageContractAddress: AztecAddress, + public portalContractAddress: EthAddress, + public isDelegateCall: boolean, + public isStaticCall: boolean, + public isContractDeployment: boolean, + ) {} +} + +/** + * Contract deployment data in a @TxContext. + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ +export class ContractDeploymentData { + constructor( + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress, + ) {} +} + +/** + * Public inputs to a private circuit. + * @see abis/private_circuit_public_inputs.hpp. + */ +export class PrivateCircuitPublicInputs { + constructor( + // NOTE: Must have same order as CPP. + public callContext: CallContext, + public args: Fr[], + public returnValues: Fr[], + public emittedEvents: Fr[], + public newCommitments: Fr[], + public newNullifiers: Fr[], + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + public historicPrivateDataTreeRoot: Fr, + public historicPrivateNullifierTreeRoot: Fr, + public historicContractTreeRoot: Fr, + public contractDeploymentData: ContractDeploymentData, + ) { + assertLength(this, 'args', ARGS_LENGTH); + assertLength(this, 'returnValues', RETURN_VALUES_LENGTH); + assertLength(this, 'emittedEvents', EMITTED_EVENTS_LENGTH); + assertLength(this, 'newCommitments', NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', L1_MSG_STACK_LENGTH); + } +} + +export class TxContext { + constructor( + public readonly isFeePaymentTx: boolean, + public readonly isRebatePaymentTx: boolean, + public readonly isContractDeploymentTx: boolean, + public readonly contractDeploymentData: ContractDeploymentData, + ) {} +} + +export interface FunctionData { + functionSelector: Buffer; + isSecret: boolean; + isContructor: boolean; +} + +export class TxRequest { + constructor( + public readonly from: AztecAddress, + public readonly to: AztecAddress, + public readonly functionData: FunctionData, + public readonly args: Fr[], + public readonly txContext: TxContext, + public readonly nonce: Fr, + public readonly chainId: Fr, + ) {} + + toBuffer() { + return Buffer.alloc(0); + } +} + +export class PrivateCallStackItem { + constructor( + public readonly contractAddress: AztecAddress, + public readonly functionSelector: Buffer, + public readonly publicInputs: PrivateCircuitPublicInputs, + ) {} +} + +export class OldTreeRoots { + constructor( + public privateDataTreeRoot: Fr, + public nullifierTreeRoot: Fr, + public contractTreeRoot: Fr, + public privateKernelVkTreeRoot: Fr, // future enhancement + ) {} +} + +export class ConstantData { + constructor(public oldTreeRoots: OldTreeRoots, public txContext: TxContext) {} +} + +export class AggregationObject {} + +export class NewContractData { + constructor( + public readonly contractAddress: AztecAddress, + public readonly portalContractAddress: EthAddress, + public readonly functionTreeRoot: Fr, + ) {} +} + +export class OptionallyRevealedData {} + +export class AccumulatedTxData { + constructor( + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + + public privateCallCount: Fr, + + public newCommitments: Fr[], + public newNullifiers: Fr[], + + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + + public newContracts: NewContractData[], + + public optionallyRevealedData: OptionallyRevealedData[], + ) { + assertLength(this, 'newCommitments', KERNEL_NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', KERNEL_NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', KERNEL_PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', KERNEL_PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', KERNEL_L1_MSG_STACK_LENGTH); + assertLength(this, 'newContracts', KERNEL_NEW_CONTRACTS_LENGTH); + assertLength(this, 'optionallyRevealedData', KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH); + } +} + +export class PrivateKernelPublicInputs { + constructor(public end: AccumulatedTxData, public constants: ConstantData, public isPrivateKernel: true) {} +} diff --git a/yarn-project/acir-simulator/src/db_oracle.ts b/yarn-project/acir-simulator/src/db_oracle.ts new file mode 100644 index 000000000000..ae006a01f950 --- /dev/null +++ b/yarn-project/acir-simulator/src/db_oracle.ts @@ -0,0 +1,16 @@ +import { AztecAddress, EthAddress } from './circuits.js'; + +export interface NoteLoadOracleInputs { + note: Buffer; + siblingPath: Buffer; + leafIndex: number; + root: Buffer; +} + +export interface DBOracle { + getSecretKey(contractAddress: AztecAddress, keyId: Buffer): Promise; + getNotes(contractAddress: AztecAddress, storageSlot: Buffer): Promise; + getBytecode(contractAddress: AztecAddress, functionSelector: string): Promise; + getProvingKey(contractAddress: AztecAddress, functionSelector: string): Promise; + getPortalContractAddress(contractAddress: AztecAddress): Promise; +} diff --git a/yarn-project/acir-simulator/src/index.ts b/yarn-project/acir-simulator/src/index.ts index e517e3e3ac0a..330c9900b134 100644 --- a/yarn-project/acir-simulator/src/index.ts +++ b/yarn-project/acir-simulator/src/index.ts @@ -1,4 +1,3 @@ -/** - * A placeholder for the Acir Simulator. - */ -export class AcirSimulator {} +export * from './simulator.js'; +export * from './db_oracle.js'; +export * from './acvm.js'; diff --git a/yarn-project/acir-simulator/src/simulator.ts b/yarn-project/acir-simulator/src/simulator.ts new file mode 100644 index 000000000000..0716d462c694 --- /dev/null +++ b/yarn-project/acir-simulator/src/simulator.ts @@ -0,0 +1,69 @@ +import { ExecutionPreimages } from './acvm.js'; +import { + CallContext, + PrivateCircuitPublicInputs, + TxRequest, + EthAddress, + PrivateCallStackItem, + OldTreeRoots, +} from './circuits.js'; + +export interface ExecutionResult { + // Needed for prover + acir: Buffer; + partialWitness: Buffer; + // Needed for the verifier (kernel) + callStackItem: PrivateCallStackItem; + // Needed for the user + preimages: ExecutionPreimages; + // Nested executions + nestedExecutions: this[]; +} + +/** + * A placeholder for the Acir Simulator. + */ +export class AcirSimulator { + run( + request: TxRequest, + entryPointACIR: Buffer, + portalContractAddress: EthAddress, + oldRoots: OldTreeRoots, + ): Promise { + const callContext = new CallContext( + request.from, + request.to, + portalContractAddress, + false, + false, + request.functionData.isContructor, + ); + + const publicInputs = new PrivateCircuitPublicInputs( + callContext, + request.args, + [], // returnValues, + [], // emittedEvents, + [], // newCommitments, + [], // newNullifiers, + [], // privateCallStack, + [], // publicCallStack, + [], // l1MsgStack, + oldRoots.privateDataTreeRoot, + oldRoots.nullifierTreeRoot, + oldRoots.contractTreeRoot, + request.txContext.contractDeploymentData, + ); + + return Promise.resolve({ + acir: entryPointACIR, + partialWitness: Buffer.alloc(0), + callStackItem: new PrivateCallStackItem(request.to, request.functionData.functionSelector, publicInputs), + preimages: { + newNotes: [], + nullifiedNotes: [], + }, + nestedExecutions: [], + }); + } +} diff --git a/yarn-project/aztec-rpc/package.json b/yarn-project/aztec-rpc/package.json index fbf0ae595f68..ae0c49b467c5 100644 --- a/yarn-project/aztec-rpc/package.json +++ b/yarn-project/aztec-rpc/package.json @@ -29,7 +29,9 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/acir-simulator": "workspace:^", "@aztec/aztec-node": "workspace:^", + "@aztec/kernel-prover": "workspace:^", "sha3": "^2.1.4", "tslib": "^2.4.0" }, diff --git a/yarn-project/aztec-rpc/src/acir_simulator.ts b/yarn-project/aztec-rpc/src/acir_simulator.ts deleted file mode 100644 index c5c5c78fa50d..000000000000 --- a/yarn-project/aztec-rpc/src/acir_simulator.ts +++ /dev/null @@ -1,9 +0,0 @@ -// TODO use @aztce/acir-simulator - -import { PreviousKernelData, PrivateCallData, TxRequest } from './circuits.js'; - -export class AcirSimulator { - public simulate(txRequest: TxRequest) { - return Promise.resolve({ kernelData: new PreviousKernelData(), callData: new PrivateCallData() }); - } -} 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 e7f4d8a8845d..690debda9ad4 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 @@ -1,6 +1,7 @@ import { AztecNode, Tx } from '@aztec/aztec-node'; +import { AcirSimulator } from '@aztec/acir-simulator'; +import { KernelProver } from '@aztec/kernel-prover'; import { generateFunctionSelector } from '../abi_coder/index.js'; -import { AcirSimulator } from '../acir_simulator.js'; import { AztecRPCClient } from '../aztec_rpc_client/index.js'; import { AztecAddress, @@ -8,7 +9,8 @@ import { EthAddress, Fr, generateContractAddress, - KernelPrivateInputs, + OldTreeRoots, + PrivateKernelPublicInputs, Signature, TxContext, TxRequest, @@ -16,16 +18,17 @@ import { import { Database } from '../database/index.js'; import { KeyStore } from '../key_store/index.js'; import { ContractAbi } from '../noir.js'; -import { ProofGenerator } from '../proof_generator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; import { TxHash } from '../tx/index.js'; +import { AccumulatedTxData } from '@aztec/p2p'; +import { ContractDao } from '../contract_data_source/contract_dao.js'; export class AztecRPCServer implements AztecRPCClient { constructor( private keyStore: KeyStore, private synchroniser: Synchroniser, - private simulator: AcirSimulator, - private proofGenerator: ProofGenerator, + private acirSimulator: AcirSimulator, + private kernelProver: KernelProver, private node: AztecNode, private db: Database, ) {} @@ -60,20 +63,18 @@ export class AztecRPCServer implements AztecRPCClient { isContructor: true, }; - const contractDataHash = Fr.ZERO; + const constructorVkHash = Fr.ZERO; const functionTreeRoot = Fr.ZERO; - const constructorHash = Fr.ZERO; const contractDeploymentData = new ContractDeploymentData( - contractDataHash, + constructorVkHash, functionTreeRoot, - constructorHash, contractAddressSalt, portalContract, ); const txContext = new TxContext(false, false, false, contractDeploymentData); const contractAddress = generateContractAddress(from, contractAddressSalt, args); - await this.db.addContract(contractAddress, abi, false); + await this.db.addContract(contractAddress, portalContract, abi, false); return new TxRequest( from, @@ -87,19 +88,16 @@ export class AztecRPCServer implements AztecRPCClient { } public async createTxRequest(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress) { - const abi = await this.db.getContract(to); - if (!abi) { + const contract = await this.db.getContract(to); + if (!contract) { throw new Error('Unknown contract.'); } - const functionAbi = abi.functions.find(f => f.selector.equals(functionSelector)); - if (!functionAbi) { - throw new Error('Unknown function.'); - } + const functionDao = this.findFunction(contract, functionSelector); const functionData = { functionSelector, - isSecret: functionAbi.isSecret, + isSecret: functionDao.isSecret, isContructor: false, }; @@ -121,10 +119,54 @@ export class AztecRPCServer implements AztecRPCClient { } public async createTx(txRequest: TxRequest, signature: Signature) { - const { kernelData, callData } = await this.simulator.simulate(txRequest); - const privateInputs = new KernelPrivateInputs(txRequest, signature, kernelData, callData); - const { accumulatedTxData } = await this.proofGenerator.createProof(privateInputs); - return new Tx(accumulatedTxData); + let contractAddress; + + if (txRequest.to === AztecAddress.ZERO) { + contractAddress = generateContractAddress( + txRequest.from, + txRequest.txContext.contractDeploymentData.contractAddressSalt, + txRequest.args, + ); + } else { + contractAddress = txRequest.to; + } + + const contract = await this.db.getContract(contractAddress); + + if (!contract) { + throw new Error('Unknown contract.'); + } + + const functionDao = this.findFunction(contract, txRequest.functionData.functionSelector); + + const oldRoots = new OldTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); // TODO - get old roots from the database/node + const executionResult = await this.acirSimulator.run( + txRequest, + Buffer.from(functionDao.bytecode, 'base64'), + contract.portalAddress, + oldRoots, + ); + const { publicInputs, proof } = await this.kernelProver.prove(txRequest, signature, executionResult, oldRoots); + return this.buildTx(publicInputs, proof); + } + + private buildTx(publicInputs: PrivateKernelPublicInputs, proof: Buffer) { + const accumulatedData = publicInputs.end; + + // TODO I think the TX should include all the data from the publicInputs + proof + return new Tx( + new AccumulatedTxData( + accumulatedData.newCommitments.map(fr => fr.buffer), + accumulatedData.newNullifiers.map(fr => fr.buffer), + accumulatedData.privateCallStack.map(fr => fr.buffer), + accumulatedData.publicCallStack.map(fr => fr.buffer), + accumulatedData.l1MsgStack.map(fr => fr.buffer), + accumulatedData.newContracts.map(() => Buffer.alloc(0)), // TODO: use toBuffer from circuits/ts + accumulatedData.newCommitments.map(fr => fr.buffer), + {}, // TODO aggregationObject from circuits/ts + accumulatedData.privateCallCount.buffer.readUInt32BE(), // TODO: check if correct + ), + ); } public async sendTx(tx: Tx) { @@ -154,4 +196,12 @@ export class AztecRPCServer implements AztecRPCClient { status: !tx.error, }; } + + private findFunction(contract: ContractDao, functionSelector: Buffer) { + const functionDao = contract.functions.find(f => f.selector.equals(functionSelector)); + if (!functionDao) { + throw new Error('Unknown function.'); + } + return functionDao; + } } diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts index 3e0879770ac2..23dd610e2127 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts @@ -1,9 +1,9 @@ +import { AcirSimulator } from '@aztec/acir-simulator'; import { AztecNode } from '@aztec/aztec-node'; -import { AcirSimulator } from '../acir_simulator.js'; -import { EthAddress, KernelCircuitProver } from '../circuits.js'; +import { KernelProver } from '@aztec/kernel-prover'; +import { EthAddress } from '../circuits.js'; import { MemoryDB } from '../database/index.js'; import { KeyStore, TestKeyStore } from '../key_store/index.js'; -import { ProofGenerator } from '../proof_generator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; import { AztecRPCServer } from './aztec_rpc_server.js'; @@ -12,8 +12,8 @@ export async function createAztecRPCServer({ node, db, synchroniser, - simulator, - proofGenerator, + acirSimulator, + kernelProver, ethRpcUrl, rollupAddress, yeeterAddress, @@ -22,8 +22,8 @@ export async function createAztecRPCServer({ node?: AztecNode; db?: MemoryDB; synchroniser?: Synchroniser; - simulator?: AcirSimulator; - proofGenerator?: ProofGenerator; + acirSimulator?: AcirSimulator; + kernelProver?: KernelProver; ethRpcUrl?: string; rollupAddress?: EthAddress; yeeterAddress?: EthAddress; @@ -44,8 +44,8 @@ export async function createAztecRPCServer({ } db = db || new MemoryDB(); synchroniser = synchroniser || new Synchroniser(node, db); - simulator = simulator || new AcirSimulator(); - proofGenerator = proofGenerator || new ProofGenerator(new KernelCircuitProver()); + acirSimulator = acirSimulator || new AcirSimulator(); + kernelProver = kernelProver || new KernelProver(); - return new AztecRPCServer(keyStore, synchroniser, simulator, proofGenerator, node, db); + return new AztecRPCServer(keyStore, synchroniser, acirSimulator, kernelProver, node, db); } diff --git a/yarn-project/aztec-rpc/src/circuits.ts b/yarn-project/aztec-rpc/src/circuits.ts index 4611a8f863bd..7360897095fc 100644 --- a/yarn-project/aztec-rpc/src/circuits.ts +++ b/yarn-project/aztec-rpc/src/circuits.ts @@ -56,15 +56,18 @@ export interface FunctionData { isContructor: boolean; } +/** + * Contract deployment data in a TxContext + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ export class ContractDeploymentData { - public static EMPTY = new ContractDeploymentData(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); + public static EMPTY = new ContractDeploymentData(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); constructor( - public readonly contractDataHash: Fr, - public readonly functionTreeRoot: Fr, - public readonly constructorHash: Fr, - public readonly contractAddressSalt: Fr, - public readonly portalContractAddress: Fr, + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress, ) {} } @@ -97,8 +100,6 @@ export class PreviousKernelData {} export class PrivateCallData {} -export class AccumulatedTxData {} - export class KernelPrivateInputs { constructor( public readonly txRequest: TxRequest, @@ -108,20 +109,6 @@ export class KernelPrivateInputs { ) {} } -export class KernelProofData { - public readonly accumulatedTxData: AccumulatedTxData; - - constructor(public readonly proofData: Buffer) { - this.accumulatedTxData = new AccumulatedTxData(); - } -} - -export class KernelCircuitProver { - public createProof(inputs: KernelPrivateInputs) { - return Promise.resolve(new KernelProofData(Buffer.alloc(100))); - } -} - export function generateContractAddress( deployerAddress: AztecAddress, salt: Fr, @@ -130,3 +117,51 @@ export function generateContractAddress( ) { return AztecAddress.random(); } + +export class OldTreeRoots { + constructor( + public privateDataTreeRoot: Fr, + public nullifierTreeRoot: Fr, + public contractTreeRoot: Fr, + public privateKernelVkTreeRoot: Fr, // future enhancement + ) {} +} + +export class ConstantData { + constructor(public oldTreeRoots: OldTreeRoots, public txContext: TxContext) {} +} + +export class AggregationObject {} + +export class NewContractData { + constructor( + public readonly contractAddress: AztecAddress, + public readonly portalContractAddress: EthAddress, + public readonly functionTreeRoot: Fr, + ) {} +} + +export class OptionallyRevealedData {} + +export class AccumulatedTxData { + constructor( + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + + public privateCallCount: Fr, + + public newCommitments: Fr[], + public newNullifiers: Fr[], + + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + + public newContracts: NewContractData[], + + public optionallyRevealedData: OptionallyRevealedData[], + ) {} +} + +export class PrivateKernelPublicInputs { + constructor(public end: AccumulatedTxData, public constants: ConstantData, public isPrivateKernel: true) {} +} diff --git a/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts b/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts index d15712687ae2..ae3f167c3985 100644 --- a/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts +++ b/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts @@ -1,5 +1,5 @@ import { generateFunctionSelector } from '../abi_coder/index.js'; -import { AztecAddress } from '../circuits.js'; +import { AztecAddress, EthAddress } from '../circuits.js'; import { ContractAbi, FunctionAbi } from '../noir.js'; export interface ContractFunctionDao extends FunctionAbi { @@ -8,6 +8,7 @@ export interface ContractFunctionDao extends FunctionAbi { export interface ContractDao extends ContractAbi { address: AztecAddress; + portalAddress: EthAddress; functions: ContractFunctionDao[]; deployed: boolean; } @@ -20,9 +21,15 @@ export function functionAbiToFunctionDao(abi: FunctionAbi) { }; } -export function contractAbiToContractDao(address: AztecAddress, abi: ContractAbi, deployed: boolean): ContractDao { +export function contractAbiToContractDao( + address: AztecAddress, + portalAddress: EthAddress, + abi: ContractAbi, + deployed: boolean, +): ContractDao { return { address, + portalAddress, functions: abi.functions.map(functionAbiToFunctionDao), deployed, }; diff --git a/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts b/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts index f086dc05cc7b..f22699ee79a9 100644 --- a/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts +++ b/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts @@ -1,9 +1,9 @@ -import { AztecAddress } from '../circuits.js'; +import { AztecAddress, EthAddress } from '../circuits.js'; import { ContractAbi } from '../noir.js'; import { ContractDao } from './contract_dao.js'; export interface ContractDataSource { - addContract(address: AztecAddress, abi: ContractAbi, deployed?: boolean): Promise; + addContract(address: AztecAddress, portalAddress: EthAddress, abi: ContractAbi, deployed?: boolean): Promise; getContract(address: AztecAddress): Promise; getCode(contractAddress: AztecAddress, functionSelector: Buffer): Promise; } diff --git a/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts b/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts index 3f40eb39b771..ba377e5a1b50 100644 --- a/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts +++ b/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts @@ -1,4 +1,4 @@ -import { AztecAddress } from '../circuits.js'; +import { AztecAddress, EthAddress } from '../circuits.js'; import { ContractAbi } from '../noir.js'; import { contractAbiToContractDao, ContractDao } from './contract_dao.js'; import { ContractDataSource } from './contract_data_source.js'; @@ -6,8 +6,8 @@ import { ContractDataSource } from './contract_data_source.js'; export class MemoryContractDataSource implements ContractDataSource { private contracts: ContractDao[] = []; - public addContract(address: AztecAddress, abi: ContractAbi, deployed = false) { - this.contracts.push(contractAbiToContractDao(address, abi, deployed)); + public addContract(address: AztecAddress, portalAddress: EthAddress, abi: ContractAbi, deployed = false) { + this.contracts.push(contractAbiToContractDao(address, portalAddress, abi, deployed)); return Promise.resolve(); } diff --git a/yarn-project/aztec-rpc/src/proof_generator/index.ts b/yarn-project/aztec-rpc/src/proof_generator/index.ts deleted file mode 100644 index 0907f3cd0065..000000000000 --- a/yarn-project/aztec-rpc/src/proof_generator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './proof_generator.js'; diff --git a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts b/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts deleted file mode 100644 index 383ef462f490..000000000000 --- a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { KernelCircuitProver, KernelPrivateInputs } from '../circuits.js'; - -export class ProofGenerator { - constructor(private prover: KernelCircuitProver) {} - - public async createProof(inputs: KernelPrivateInputs) { - // TODO - iterate - const { accumulatedTxData } = await this.prover.createProof(inputs); - return { accumulatedTxData: accumulatedTxData as any }; - } -} diff --git a/yarn-project/aztec.js/Dockerfile b/yarn-project/aztec.js/Dockerfile index 0257381620c2..f09e9a608b00 100644 --- a/yarn-project/aztec.js/Dockerfile +++ b/yarn-project/aztec.js/Dockerfile @@ -6,6 +6,8 @@ COPY archiver archiver COPY world-state world-state COPY p2p p2p COPY aztec-node aztec-node +COPY acir-simulator acir-simulator +COPY kernel-prover kernel-prover COPY aztec-rpc aztec-rpc COPY aztec.js aztec.js RUN cd ethereum.js && yarn build @@ -14,6 +16,8 @@ RUN cd merkle-tree && yarn build RUN cd world-state && yarn build RUN cd p2p && yarn build RUN cd aztec-node && yarn build +RUN cd acir-simulator && yarn build +RUN cd kernel-prover && yarn build RUN cd aztec-rpc && yarn build WORKDIR /usr/src/yarn-project/aztec.js RUN yarn build && yarn formatting && yarn test diff --git a/yarn-project/kernel-simulator/.eslintrc.cjs b/yarn-project/kernel-prover/.eslintrc.cjs similarity index 100% rename from yarn-project/kernel-simulator/.eslintrc.cjs rename to yarn-project/kernel-prover/.eslintrc.cjs diff --git a/yarn-project/kernel-simulator/Dockerfile b/yarn-project/kernel-prover/Dockerfile similarity index 55% rename from yarn-project/kernel-simulator/Dockerfile rename to yarn-project/kernel-prover/Dockerfile index 60c31d5c269c..0738898f4433 100644 --- a/yarn-project/kernel-simulator/Dockerfile +++ b/yarn-project/kernel-prover/Dockerfile @@ -1,7 +1,7 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder -COPY kernel-simulator kernel-simulator -WORKDIR /usr/src/yarn-project/kernel-simulator +COPY kernel-prover kernel-prover +WORKDIR /usr/src/yarn-project/kernel-prover RUN yarn build && yarn formatting && yarn test # Prune dev dependencies. See comment in base image. @@ -9,6 +9,6 @@ RUN yarn cache clean RUN yarn workspaces focus --production > /dev/null FROM node:18-alpine -COPY --from=builder /usr/src/yarn-project/kernel-simulator /usr/src/yarn-project/kernel-simulator -WORKDIR /usr/src/yarn-project/kernel-simulator +COPY --from=builder /usr/src/yarn-project/kernel-prover /usr/src/yarn-project/kernel-prover +WORKDIR /usr/src/yarn-project/kernel-prover ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/kernel-simulator/README.md b/yarn-project/kernel-prover/README.md similarity index 100% rename from yarn-project/kernel-simulator/README.md rename to yarn-project/kernel-prover/README.md diff --git a/yarn-project/kernel-simulator/package.json b/yarn-project/kernel-prover/package.json similarity index 93% rename from yarn-project/kernel-simulator/package.json rename to yarn-project/kernel-prover/package.json index d102f8977478..bd8398e1f775 100644 --- a/yarn-project/kernel-simulator/package.json +++ b/yarn-project/kernel-prover/package.json @@ -1,5 +1,5 @@ { - "name": "@aztec/kernel-simulator", + "name": "@aztec/kernel-prover", "version": "0.0.0", "type": "module", "exports": "./dest/index.js", @@ -29,6 +29,7 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/acir-simulator": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/kernel-prover/src/circuits.ts b/yarn-project/kernel-prover/src/circuits.ts new file mode 100644 index 000000000000..6c9c25ab6c9a --- /dev/null +++ b/yarn-project/kernel-prover/src/circuits.ts @@ -0,0 +1,235 @@ +// See aztec3/constants.hpp +// Copied here for prototyping purposes +// In future: structured serialization? +export const ARGS_LENGTH = 8; +export const RETURN_VALUES_LENGTH = 4; +export const EMITTED_EVENTS_LENGTH = 4; + +export const NEW_COMMITMENTS_LENGTH = 4; +export const NEW_NULLIFIERS_LENGTH = 4; + +export const STATE_TRANSITIONS_LENGTH = 4; +export const STATE_READS_LENGTH = 4; + +export const PRIVATE_CALL_STACK_LENGTH = 4; +export const PUBLIC_CALL_STACK_LENGTH = 4; +export const L1_MSG_STACK_LENGTH = 2; + +export const KERNEL_NEW_COMMITMENTS_LENGTH = 16; +export const KERNEL_NEW_NULLIFIERS_LENGTH = 16; +export const KERNEL_NEW_CONTRACTS_LENGTH = 8; +export const KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; +export const KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; +export const KERNEL_L1_MSG_STACK_LENGTH = 4; +export const KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; + +export const VK_TREE_HEIGHT = 3; +export const CONTRACT_TREE_HEIGHT = 4; +export const PRIVATE_DATA_TREE_HEIGHT = 8; +export const NULLIFIER_TREE_HEIGHT = 8; + +export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; +export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; + +export const FUNCTION_SELECTOR_NUM_BYTES = 31; + +/** + * Assert a member is a certain length. + * @param obj - An object. + * @param member - A member string. + * @param length - The length. + */ +export function assertLength( + obj: T, + member: F, + length: number, +) { + if (obj[member].length !== length) { + throw new Error(`Expected ${member} to have length ${length}! Was: ${obj[member].length}`); + } +} + +export class Fr { + public static ZERO = new Fr(Buffer.alloc(32)); + + constructor(public readonly buffer: Buffer) {} +} + +export class AztecAddress { + public static SIZE = 64; + + public static ZERO = new AztecAddress(Buffer.alloc(AztecAddress.SIZE)); + + constructor(public readonly buffer: Buffer) {} + + public equals(rhs: AztecAddress) { + return this.buffer.equals(rhs.buffer); + } +} + +export class EthAddress { + public static ZERO = new EthAddress(Buffer.alloc(20)); + + constructor(public readonly buffer: Buffer) {} +} + +/** + * Call context. + * @see abis/call_context.hpp + */ +export class CallContext { + constructor( + public msgSender: AztecAddress, + public storageContractAddress: AztecAddress, + public portalContractAddress: EthAddress, + public isDelegateCall: boolean, + public isStaticCall: boolean, + public isContractDeployment: boolean, + ) {} +} + +/** + * Contract deployment data in a @TxContext. + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ +export class ContractDeploymentData { + constructor( + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress, + ) {} +} + +/** + * Public inputs to a private circuit. + * @see abis/private_circuit_public_inputs.hpp. + */ +export class PrivateCircuitPublicInputs { + constructor( + // NOTE: Must have same order as CPP. + public callContext: CallContext, + public args: Fr[], + public returnValues: Fr[], + public emittedEvents: Fr[], + public newCommitments: Fr[], + public newNullifiers: Fr[], + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + public historicPrivateDataTreeRoot: Fr, + public historicPrivateNullifierTreeRoot: Fr, + public historicContractTreeRoot: Fr, + public contractDeploymentData: ContractDeploymentData, + ) { + assertLength(this, 'args', ARGS_LENGTH); + assertLength(this, 'returnValues', RETURN_VALUES_LENGTH); + assertLength(this, 'emittedEvents', EMITTED_EVENTS_LENGTH); + assertLength(this, 'newCommitments', NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', L1_MSG_STACK_LENGTH); + } +} + +export class TxContext { + constructor( + public readonly isFeePaymentTx: boolean, + public readonly isRebatePaymentTx: boolean, + public readonly isContractDeploymentTx: boolean, + public readonly contractDeploymentData: ContractDeploymentData, + ) {} +} + +export interface FunctionData { + functionSelector: Buffer; + isSecret: boolean; + isContructor: boolean; +} + +export class TxRequest { + constructor( + public readonly from: AztecAddress, + public readonly to: AztecAddress, + public readonly functionData: FunctionData, + public readonly args: Fr[], + public readonly txContext: TxContext, + public readonly nonce: Fr, + public readonly chainId: Fr, + ) {} + + toBuffer() { + return Buffer.alloc(0); + } +} + +export class PrivateCallStackItem { + constructor( + public readonly contractAddress: AztecAddress, + public readonly functionSelector: Buffer, + public readonly publicInputs: PrivateCircuitPublicInputs, + ) {} +} + +export class OldTreeRoots { + constructor( + public privateDataTreeRoot: Fr, + public nullifierTreeRoot: Fr, + public contractTreeRoot: Fr, + public privateKernelVkTreeRoot: Fr, // future enhancement + ) {} +} + +export class ConstantData { + constructor(public oldTreeRoots: OldTreeRoots, public txContext: TxContext) {} +} + +export class AggregationObject {} + +export class NewContractData { + constructor( + public readonly contractAddress: AztecAddress, + public readonly portalContractAddress: EthAddress, + public readonly functionTreeRoot: Fr, + ) {} +} + +export class OptionallyRevealedData {} + +export class AccumulatedTxData { + constructor( + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + + public privateCallCount: Fr, + + public newCommitments: Fr[], + public newNullifiers: Fr[], + + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + + public newContracts: NewContractData[], + + public optionallyRevealedData: OptionallyRevealedData[], + ) { + assertLength(this, 'newCommitments', KERNEL_NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', KERNEL_NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', KERNEL_PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', KERNEL_PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', KERNEL_L1_MSG_STACK_LENGTH); + assertLength(this, 'newContracts', KERNEL_NEW_CONTRACTS_LENGTH); + assertLength(this, 'optionallyRevealedData', KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH); + } +} + +export class PrivateKernelPublicInputs { + constructor(public end: AccumulatedTxData, public constants: ConstantData, public isPrivateKernel: true) {} +} + +export class Signature { + public static SIZE = 64; + + constructor(public readonly buffer: Buffer) {} +} diff --git a/yarn-project/kernel-prover/src/index.ts b/yarn-project/kernel-prover/src/index.ts new file mode 100644 index 000000000000..173a83b2bb77 --- /dev/null +++ b/yarn-project/kernel-prover/src/index.ts @@ -0,0 +1,54 @@ +import { ExecutionResult } from '@aztec/acir-simulator'; +import { + AccumulatedTxData, + AggregationObject, + ConstantData, + Fr, + NewContractData, + OldTreeRoots, + PrivateKernelPublicInputs, + Signature, + TxRequest, +} from './circuits.js'; +export class KernelProver { + prove( + txRequest: TxRequest, + txSignature: Signature, + executionResult: ExecutionResult, + oldRoots: OldTreeRoots, + ): Promise<{ publicInputs: PrivateKernelPublicInputs; proof: Buffer }> { + // TODO: implement this + const newContracts = []; + if (txRequest.functionData.isContructor) { + newContracts.push( + new NewContractData( + txRequest.to, + txRequest.txContext.contractDeploymentData.portalContractAddress, + txRequest.txContext.contractDeploymentData.functionTreeRoot, + ), + ); + } + const accumulatedTxData = new AccumulatedTxData( + new AggregationObject(), + new Fr(Buffer.from([1])), + [], // newCommitments + [], // newNullifiers + [], // privateCallStack + [], // publicCallStack + [], // l1MsgStack + newContracts, + [], // optionallyRevealedData + ); + + const publicInputs = new PrivateKernelPublicInputs( + accumulatedTxData, + new ConstantData(oldRoots, txRequest.txContext), + true, + ); + + return Promise.resolve({ + publicInputs, + proof: Buffer.alloc(0), + }); + } +} diff --git a/yarn-project/kernel-simulator/tsconfig.dest.json b/yarn-project/kernel-prover/tsconfig.dest.json similarity index 100% rename from yarn-project/kernel-simulator/tsconfig.dest.json rename to yarn-project/kernel-prover/tsconfig.dest.json diff --git a/yarn-project/kernel-simulator/tsconfig.json b/yarn-project/kernel-prover/tsconfig.json similarity index 100% rename from yarn-project/kernel-simulator/tsconfig.json rename to yarn-project/kernel-prover/tsconfig.json diff --git a/yarn-project/kernel-simulator/src/index.ts b/yarn-project/kernel-simulator/src/index.ts deleted file mode 100644 index d63aa680f381..000000000000 --- a/yarn-project/kernel-simulator/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A placeholder for the Kernel Simulator. - */ -export class KernelSimulator {} diff --git a/yarn-project/package.json b/yarn-project/package.json index 3253b261fe58..ecc6350ba1ec 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -17,7 +17,7 @@ "ethereum.js", "ethereum.js/example", "foundation", - "kernel-simulator", + "kernel-prover", "key-store", "merkle-tree", "noir-contracts", diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index e405ee04264e..475584d6a5de 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -8,7 +8,7 @@ "aztec-rpc", "aztec.js", "ethereum.js", - "kernel-simulator", + "kernel-prover", "key-store", "noir-contracts", "p2p", diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 83e87ef2e5cc..329795a5982b 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -24,7 +24,7 @@ COPY ethereum.js/package.json ethereum.js/package.json # Note: foundation has its own lock file, we need to copy it and build COPY foundation/package.json foundation/package.json COPY foundation/yarn.lock foundation/yarn.lock -COPY kernel-simulator/package.json kernel-simulator/package.json +COPY kernel-prover/package.json kernel-prover/package.json COPY key-store/package.json key-store/package.json COPY merkle-tree/package.json merkle-tree/package.json COPY noir-contracts/package.json noir-contracts/package.json diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 2eb3ad32ba79..b3fc4b684f8a 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -15,7 +15,7 @@ __metadata: languageName: node linkType: hard -"@aztec/acir-simulator@workspace:acir-simulator": +"@aztec/acir-simulator@workspace:^, @aztec/acir-simulator@workspace:acir-simulator": version: 0.0.0-use.local resolution: "@aztec/acir-simulator@workspace:acir-simulator" dependencies: @@ -101,7 +101,9 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/aztec-rpc@workspace:aztec-rpc" dependencies: + "@aztec/acir-simulator": "workspace:^" "@aztec/aztec-node": "workspace:^" + "@aztec/kernel-prover": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -242,10 +244,11 @@ __metadata: languageName: unknown linkType: soft -"@aztec/kernel-simulator@workspace:kernel-simulator": +"@aztec/kernel-prover@workspace:^, @aztec/kernel-prover@workspace:kernel-prover": version: 0.0.0-use.local - resolution: "@aztec/kernel-simulator@workspace:kernel-simulator" + resolution: "@aztec/kernel-prover@workspace:kernel-prover" dependencies: + "@aztec/acir-simulator": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0