@aztec/pxe 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +13 -0
  2. package/dest/bin/index.d.ts +3 -0
  3. package/dest/bin/index.d.ts.map +1 -0
  4. package/dest/bin/index.js +31 -0
  5. package/dest/config/index.d.ts +21 -0
  6. package/dest/config/index.d.ts.map +1 -0
  7. package/dest/config/index.js +21 -0
  8. package/dest/contract_data_oracle/index.d.ts +99 -0
  9. package/dest/contract_data_oracle/index.d.ts.map +1 -0
  10. package/dest/contract_data_oracle/index.js +137 -0
  11. package/dest/contract_database/index.d.ts +2 -0
  12. package/dest/contract_database/index.d.ts.map +1 -0
  13. package/dest/contract_database/index.js +2 -0
  14. package/dest/contract_database/memory_contract_database.d.ts +43 -0
  15. package/dest/contract_database/memory_contract_database.d.ts.map +1 -0
  16. package/dest/contract_database/memory_contract_database.js +51 -0
  17. package/dest/contract_tree/index.d.ts +107 -0
  18. package/dest/contract_tree/index.d.ts.map +1 -0
  19. package/dest/contract_tree/index.js +181 -0
  20. package/dest/database/database.d.ts +118 -0
  21. package/dest/database/database.d.ts.map +1 -0
  22. package/dest/database/database.js +2 -0
  23. package/dest/database/index.d.ts +4 -0
  24. package/dest/database/index.d.ts.map +1 -0
  25. package/dest/database/index.js +4 -0
  26. package/dest/database/memory_db.d.ts +45 -0
  27. package/dest/database/memory_db.d.ts.map +1 -0
  28. package/dest/database/memory_db.js +111 -0
  29. package/dest/database/note_spending_info_dao.d.ts +44 -0
  30. package/dest/database/note_spending_info_dao.d.ts.map +1 -0
  31. package/dest/database/note_spending_info_dao.js +14 -0
  32. package/dest/index.d.ts +10 -0
  33. package/dest/index.d.ts.map +1 -0
  34. package/dest/index.js +10 -0
  35. package/dest/kernel_oracle/index.d.ts +18 -0
  36. package/dest/kernel_oracle/index.d.ts.map +1 -0
  37. package/dest/kernel_oracle/index.js +29 -0
  38. package/dest/kernel_prover/index.d.ts +3 -0
  39. package/dest/kernel_prover/index.d.ts.map +1 -0
  40. package/dest/kernel_prover/index.js +3 -0
  41. package/dest/kernel_prover/kernel_prover.d.ts +89 -0
  42. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -0
  43. package/dest/kernel_prover/kernel_prover.js +175 -0
  44. package/dest/kernel_prover/proof_creator.d.ts +84 -0
  45. package/dest/kernel_prover/proof_creator.d.ts.map +1 -0
  46. package/dest/kernel_prover/proof_creator.js +83 -0
  47. package/dest/kernel_prover/proving_data_oracle.d.ts +53 -0
  48. package/dest/kernel_prover/proving_data_oracle.d.ts.map +1 -0
  49. package/dest/kernel_prover/proving_data_oracle.js +2 -0
  50. package/dest/note_processor/index.d.ts +2 -0
  51. package/dest/note_processor/index.d.ts.map +1 -0
  52. package/dest/note_processor/index.js +2 -0
  53. package/dest/note_processor/note_processor.d.ts +78 -0
  54. package/dest/note_processor/note_processor.d.ts.map +1 -0
  55. package/dest/note_processor/note_processor.js +206 -0
  56. package/dest/pxe_http/index.d.ts +2 -0
  57. package/dest/pxe_http/index.d.ts.map +1 -0
  58. package/dest/pxe_http/index.js +2 -0
  59. package/dest/pxe_http/pxe_http_server.d.ts +40 -0
  60. package/dest/pxe_http/pxe_http_server.d.ts.map +1 -0
  61. package/dest/pxe_http/pxe_http_server.js +44 -0
  62. package/dest/pxe_service/create_pxe_service.d.ts +30 -0
  63. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -0
  64. package/dest/pxe_service/create_pxe_service.js +27 -0
  65. package/dest/pxe_service/index.d.ts +4 -0
  66. package/dest/pxe_service/index.d.ts.map +1 -0
  67. package/dest/pxe_service/index.js +4 -0
  68. package/dest/pxe_service/pxe_service.d.ts +70 -0
  69. package/dest/pxe_service/pxe_service.d.ts.map +1 -0
  70. package/dest/pxe_service/pxe_service.js +470 -0
  71. package/dest/pxe_service/test/pxe_test_suite.d.ts +3 -0
  72. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -0
  73. package/dest/pxe_service/test/pxe_test_suite.js +100 -0
  74. package/dest/simulator/index.d.ts +9 -0
  75. package/dest/simulator/index.d.ts.map +1 -0
  76. package/dest/simulator/index.js +11 -0
  77. package/dest/simulator_oracle/index.d.ts +53 -0
  78. package/dest/simulator_oracle/index.d.ts.map +1 -0
  79. package/dest/simulator_oracle/index.js +91 -0
  80. package/dest/synchronizer/index.d.ts +2 -0
  81. package/dest/synchronizer/index.d.ts.map +1 -0
  82. package/dest/synchronizer/index.js +2 -0
  83. package/dest/synchronizer/synchronizer.d.ts +82 -0
  84. package/dest/synchronizer/synchronizer.d.ts.map +1 -0
  85. package/dest/synchronizer/synchronizer.js +241 -0
  86. package/package.json +74 -0
  87. package/src/bin/index.ts +39 -0
  88. package/src/config/index.ts +34 -0
  89. package/src/contract_data_oracle/index.ts +151 -0
  90. package/src/contract_database/index.ts +1 -0
  91. package/src/contract_database/memory_contract_database.ts +58 -0
  92. package/src/contract_tree/index.ts +245 -0
  93. package/src/database/database.ts +131 -0
  94. package/src/database/index.ts +3 -0
  95. package/src/database/memory_db.ts +147 -0
  96. package/src/database/note_spending_info_dao.ts +64 -0
  97. package/src/index.ts +11 -0
  98. package/src/kernel_oracle/index.ts +39 -0
  99. package/src/kernel_prover/index.ts +2 -0
  100. package/src/kernel_prover/kernel_prover.ts +317 -0
  101. package/src/kernel_prover/proof_creator.ts +176 -0
  102. package/src/kernel_prover/proving_data_oracle.ts +69 -0
  103. package/src/note_processor/index.ts +1 -0
  104. package/src/note_processor/note_processor.ts +267 -0
  105. package/src/pxe_http/index.ts +1 -0
  106. package/src/pxe_http/pxe_http_server.ts +70 -0
  107. package/src/pxe_service/create_pxe_service.ts +52 -0
  108. package/src/pxe_service/index.ts +3 -0
  109. package/src/pxe_service/pxe_service.ts +650 -0
  110. package/src/pxe_service/test/pxe_test_suite.ts +138 -0
  111. package/src/simulator/index.ts +24 -0
  112. package/src/simulator_oracle/index.ts +121 -0
  113. package/src/synchronizer/index.ts +1 -0
  114. package/src/synchronizer/synchronizer.ts +285 -0
@@ -0,0 +1,147 @@
1
+ import { CompleteAddress, HistoricBlockData } from '@aztec/circuits.js';
2
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
3
+ import { Fr } from '@aztec/foundation/fields';
4
+ import { createDebugLogger } from '@aztec/foundation/log';
5
+ import { MerkleTreeId, PublicKey } from '@aztec/types';
6
+
7
+ import { MemoryContractDatabase } from '../contract_database/index.js';
8
+ import { Database } from './database.js';
9
+ import { NoteSpendingInfoDao } from './note_spending_info_dao.js';
10
+
11
+ /**
12
+ * The MemoryDB class provides an in-memory implementation of a database to manage transactions and auxiliary data.
13
+ * It extends the MemoryContractDatabase, allowing it to store contract-related data as well.
14
+ * The class offers methods to add, fetch, and remove transaction records and auxiliary data based on various filters such as transaction hash, address, and storage slot.
15
+ * As an in-memory database, the stored data will not persist beyond the life of the application instance.
16
+ */
17
+ export class MemoryDB extends MemoryContractDatabase implements Database {
18
+ private noteSpendingInfoTable: NoteSpendingInfoDao[] = [];
19
+ private treeRoots: Record<MerkleTreeId, Fr> | undefined;
20
+ private globalVariablesHash: Fr | undefined;
21
+ private addresses: CompleteAddress[] = [];
22
+ private authWitnesses: Record<string, Fr[]> = {};
23
+
24
+ constructor(logSuffix?: string) {
25
+ super(createDebugLogger(logSuffix ? 'aztec:memory_db_' + logSuffix : 'aztec:memory_db'));
26
+ }
27
+
28
+ /**
29
+ * Add a auth witness to the database.
30
+ * @param messageHash - The message hash.
31
+ * @param witness - An array of field elements representing the auth witness.
32
+ */
33
+ public addAuthWitness(messageHash: Fr, witness: Fr[]): Promise<void> {
34
+ this.authWitnesses[messageHash.toString()] = witness;
35
+ return Promise.resolve();
36
+ }
37
+
38
+ /**
39
+ * Fetching the auth witness for a given message hash.
40
+ * @param messageHash - The message hash.
41
+ * @returns A Promise that resolves to an array of field elements representing the auth witness.
42
+ */
43
+ public getAuthWitness(messageHash: Fr): Promise<Fr[]> {
44
+ return Promise.resolve(this.authWitnesses[messageHash.toString()]);
45
+ }
46
+
47
+ public addNoteSpendingInfo(noteSpendingInfoDao: NoteSpendingInfoDao) {
48
+ this.noteSpendingInfoTable.push(noteSpendingInfoDao);
49
+ return Promise.resolve();
50
+ }
51
+
52
+ public addNoteSpendingInfoBatch(noteSpendingInfoDaos: NoteSpendingInfoDao[]) {
53
+ this.noteSpendingInfoTable.push(...noteSpendingInfoDaos);
54
+ return Promise.resolve();
55
+ }
56
+
57
+ public getNoteSpendingInfo(contract: AztecAddress, storageSlot: Fr) {
58
+ const res = this.noteSpendingInfoTable.filter(
59
+ noteSpendingInfo =>
60
+ noteSpendingInfo.contractAddress.equals(contract) &&
61
+ noteSpendingInfo.storageSlot.toBuffer().equals(storageSlot.toBuffer()),
62
+ );
63
+ return Promise.resolve(res);
64
+ }
65
+
66
+ public removeNullifiedNoteSpendingInfo(nullifiers: Fr[], account: PublicKey) {
67
+ const nullifierSet = new Set(nullifiers.map(nullifier => nullifier.toString()));
68
+ const [remaining, removed] = this.noteSpendingInfoTable.reduce(
69
+ (acc: [NoteSpendingInfoDao[], NoteSpendingInfoDao[]], noteSpendingInfo) => {
70
+ const nullifier = noteSpendingInfo.siloedNullifier.toString();
71
+ if (noteSpendingInfo.publicKey.equals(account) && nullifierSet.has(nullifier)) {
72
+ acc[1].push(noteSpendingInfo);
73
+ } else {
74
+ acc[0].push(noteSpendingInfo);
75
+ }
76
+ return acc;
77
+ },
78
+ [[], []],
79
+ );
80
+
81
+ this.noteSpendingInfoTable = remaining;
82
+
83
+ return Promise.resolve(removed);
84
+ }
85
+
86
+ public getTreeRoots(): Record<MerkleTreeId, Fr> {
87
+ const roots = this.treeRoots;
88
+ if (!roots) throw new Error(`Tree roots not set in memory database`);
89
+ return roots;
90
+ }
91
+
92
+ public setTreeRoots(roots: Record<MerkleTreeId, Fr>) {
93
+ this.treeRoots = roots;
94
+ return Promise.resolve();
95
+ }
96
+
97
+ public getHistoricBlockData(): HistoricBlockData {
98
+ const roots = this.getTreeRoots();
99
+ if (!this.globalVariablesHash) throw new Error(`Global variables hash not set in memory database`);
100
+ return new HistoricBlockData(
101
+ roots[MerkleTreeId.PRIVATE_DATA_TREE],
102
+ roots[MerkleTreeId.NULLIFIER_TREE],
103
+ roots[MerkleTreeId.CONTRACT_TREE],
104
+ roots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE],
105
+ roots[MerkleTreeId.BLOCKS_TREE],
106
+ Fr.ZERO, // todo: private kernel vk tree root
107
+ roots[MerkleTreeId.PUBLIC_DATA_TREE],
108
+ this.globalVariablesHash,
109
+ );
110
+ }
111
+
112
+ public async setHistoricBlockData(historicBlockData: HistoricBlockData): Promise<void> {
113
+ this.globalVariablesHash = historicBlockData.globalVariablesHash;
114
+ await this.setTreeRoots({
115
+ [MerkleTreeId.PRIVATE_DATA_TREE]: historicBlockData.privateDataTreeRoot,
116
+ [MerkleTreeId.NULLIFIER_TREE]: historicBlockData.nullifierTreeRoot,
117
+ [MerkleTreeId.CONTRACT_TREE]: historicBlockData.contractTreeRoot,
118
+ [MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: historicBlockData.l1ToL2MessagesTreeRoot,
119
+ [MerkleTreeId.BLOCKS_TREE]: historicBlockData.blocksTreeRoot,
120
+ [MerkleTreeId.PUBLIC_DATA_TREE]: historicBlockData.publicDataTreeRoot,
121
+ });
122
+ }
123
+
124
+ public addCompleteAddress(completeAddress: CompleteAddress): Promise<boolean> {
125
+ const accountIndex = this.addresses.findIndex(r => r.address.equals(completeAddress.address));
126
+ if (accountIndex !== -1) {
127
+ if (this.addresses[accountIndex].equals(completeAddress)) {
128
+ return Promise.resolve(false);
129
+ }
130
+
131
+ throw new Error(
132
+ `Complete address with aztec address ${completeAddress.address.toString()} but different public key or partial key already exists in memory database`,
133
+ );
134
+ }
135
+ this.addresses.push(completeAddress);
136
+ return Promise.resolve(true);
137
+ }
138
+
139
+ public getCompleteAddress(address: AztecAddress): Promise<CompleteAddress | undefined> {
140
+ const recipient = this.addresses.find(r => r.address.equals(address));
141
+ return Promise.resolve(recipient);
142
+ }
143
+
144
+ public getCompleteAddresses(): Promise<CompleteAddress[]> {
145
+ return Promise.resolve(this.addresses);
146
+ }
147
+ }
@@ -0,0 +1,64 @@
1
+ import { AztecAddress, Fr, PublicKey } from '@aztec/circuits.js';
2
+ import { Point } from '@aztec/foundation/fields';
3
+ import { NotePreimage } from '@aztec/types';
4
+
5
+ /**
6
+ * Represents the data access object for auxiliary transaction data.
7
+ * Contains properties from the decrypted note, computed properties, and information about
8
+ * the public key used for encryption, as well as the location of the data in the tree.
9
+ */
10
+ export interface NoteSpendingInfoDao {
11
+ /**
12
+ * The contract address this note is created in.
13
+ */
14
+ contractAddress: AztecAddress;
15
+ /**
16
+ * The nonce of the note.
17
+ */
18
+ nonce: Fr;
19
+ /**
20
+ * The specific storage location of the note on the contract.
21
+ */
22
+ storageSlot: Fr;
23
+ /**
24
+ * The preimage of the note, containing essential information about the note.
25
+ */
26
+ notePreimage: NotePreimage;
27
+ /**
28
+ * Inner note hash of the note. This is customisable by the app circuit.
29
+ * We can use this value to compute siloedNoteHash and uniqueSiloedNoteHash.
30
+ */
31
+ innerNoteHash: Fr;
32
+ /**
33
+ * The nullifier of the note (siloed by contract address).
34
+ */
35
+ siloedNullifier: Fr;
36
+ /**
37
+ * The location of the relevant note in the private data tree.
38
+ */
39
+ index: bigint;
40
+ /**
41
+ * The public key that was used to encrypt the data.
42
+ */
43
+ publicKey: PublicKey;
44
+ }
45
+
46
+ export const createRandomNoteSpendingInfoDao = ({
47
+ contractAddress = AztecAddress.random(),
48
+ nonce = Fr.random(),
49
+ storageSlot = Fr.random(),
50
+ notePreimage = NotePreimage.random(),
51
+ innerNoteHash = Fr.random(),
52
+ siloedNullifier = Fr.random(),
53
+ index = Fr.random().value,
54
+ publicKey = Point.random(),
55
+ }: Partial<NoteSpendingInfoDao> = {}): NoteSpendingInfoDao => ({
56
+ contractAddress,
57
+ nonce,
58
+ storageSlot,
59
+ notePreimage,
60
+ innerNoteHash,
61
+ siloedNullifier,
62
+ index,
63
+ publicKey,
64
+ });
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export * from './pxe_service/index.js';
2
+ export * from './pxe_http/index.js';
3
+ export * from './config/index.js';
4
+
5
+ export { Tx, TxHash } from '@aztec/types';
6
+
7
+ export { TxRequest, CircuitsWasm, PartialAddress } from '@aztec/circuits.js';
8
+ export * from '@aztec/foundation/fields';
9
+ export * from '@aztec/foundation/eth-address';
10
+ export * from '@aztec/foundation/aztec-address';
11
+ export * from '@aztec/key-store';
@@ -0,0 +1,39 @@
1
+ import { AztecAddress, Fr, FunctionSelector, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT } from '@aztec/circuits.js';
2
+ import { Tuple } from '@aztec/foundation/serialize';
3
+ import { AztecNode, MerkleTreeId } from '@aztec/types';
4
+
5
+ import { ContractDataOracle } from '../contract_data_oracle/index.js';
6
+ import { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js';
7
+
8
+ /**
9
+ * A data oracle that provides information needed for simulating a transaction.
10
+ */
11
+ export class KernelOracle implements ProvingDataOracle {
12
+ constructor(private contractDataOracle: ContractDataOracle, private node: AztecNode) {}
13
+
14
+ public async getContractMembershipWitness(contractAddress: AztecAddress) {
15
+ return await this.contractDataOracle.getContractMembershipWitness(contractAddress);
16
+ }
17
+
18
+ public async getFunctionMembershipWitness(contractAddress: AztecAddress, selector: FunctionSelector) {
19
+ return await this.contractDataOracle.getFunctionMembershipWitness(contractAddress, selector);
20
+ }
21
+
22
+ public async getVkMembershipWitness() {
23
+ return await this.contractDataOracle.getVkMembershipWitness();
24
+ }
25
+
26
+ async getNoteMembershipWitness(leafIndex: bigint): Promise<MembershipWitness<typeof PRIVATE_DATA_TREE_HEIGHT>> {
27
+ const path = await this.node.getDataTreePath(leafIndex);
28
+ return new MembershipWitness<typeof PRIVATE_DATA_TREE_HEIGHT>(
29
+ path.pathSize,
30
+ leafIndex,
31
+ path.toFieldArray() as Tuple<Fr, typeof PRIVATE_DATA_TREE_HEIGHT>,
32
+ );
33
+ }
34
+
35
+ async getPrivateDataRoot(): Promise<Fr> {
36
+ const roots = await this.node.getTreeRoots();
37
+ return roots[MerkleTreeId.PRIVATE_DATA_TREE];
38
+ }
39
+ }
@@ -0,0 +1,2 @@
1
+ export * from './kernel_prover.js';
2
+ export * from './proving_data_oracle.js';
@@ -0,0 +1,317 @@
1
+ import { ExecutionResult, NewNoteData } from '@aztec/acir-simulator';
2
+ import {
3
+ AztecAddress,
4
+ CONTRACT_TREE_HEIGHT,
5
+ EMPTY_NULLIFIED_COMMITMENT,
6
+ Fr,
7
+ MAX_NEW_COMMITMENTS_PER_TX,
8
+ MAX_NEW_NULLIFIERS_PER_TX,
9
+ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,
10
+ MAX_READ_REQUESTS_PER_CALL,
11
+ MAX_READ_REQUESTS_PER_TX,
12
+ MembershipWitness,
13
+ PreviousKernelData,
14
+ PrivateCallData,
15
+ PrivateCallStackItem,
16
+ PrivateKernelInputsInit,
17
+ PrivateKernelInputsInner,
18
+ PrivateKernelInputsOrdering,
19
+ PrivateKernelPublicInputs,
20
+ ReadRequestMembershipWitness,
21
+ TxRequest,
22
+ VK_TREE_HEIGHT,
23
+ VerificationKey,
24
+ makeEmptyProof,
25
+ makeTuple,
26
+ } from '@aztec/circuits.js';
27
+ import { Tuple, assertLength } from '@aztec/foundation/serialize';
28
+
29
+ import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js';
30
+ import { ProvingDataOracle } from './proving_data_oracle.js';
31
+
32
+ /**
33
+ * Represents an output note data object.
34
+ * Contains the contract address, new note data and commitment for the note,
35
+ * resulting from the execution of a transaction in the Aztec network.
36
+ */
37
+ export interface OutputNoteData {
38
+ /**
39
+ * The address of the contract the note was created in.
40
+ */
41
+ contractAddress: AztecAddress;
42
+ /**
43
+ * The encrypted note data for an output note.
44
+ */
45
+ data: NewNoteData;
46
+ /**
47
+ * The unique value representing the note.
48
+ */
49
+ commitment: Fr;
50
+ }
51
+
52
+ /**
53
+ * Represents the output data of the Kernel Prover.
54
+ * Provides information about the newly created notes, along with the public inputs and proof.
55
+ */
56
+ export interface KernelProverOutput extends ProofOutputFinal {
57
+ /**
58
+ * An array of output notes containing the contract address, note data, and commitment for each new note.
59
+ */
60
+ outputNotes: OutputNoteData[];
61
+ }
62
+
63
+ /**
64
+ * The KernelProver class is responsible for generating kernel proofs.
65
+ * It takes a transaction request, its signature, and the simulation result as inputs, and outputs a proof
66
+ * along with output notes. The class interacts with a ProvingDataOracle to fetch membership witnesses and
67
+ * constructs private call data based on the execution results.
68
+ */
69
+ export class KernelProver {
70
+ constructor(private oracle: ProvingDataOracle, private proofCreator: ProofCreator = new KernelProofCreator()) {}
71
+
72
+ /**
73
+ * Generate a proof for a given transaction request and execution result.
74
+ * The function iterates through the nested executions in the execution result, creates private call data,
75
+ * and generates a proof using the provided ProofCreator instance. It also maintains an index of new notes
76
+ * created during the execution and returns them as a part of the KernelProverOutput.
77
+ *
78
+ * @param txRequest - The authenticated transaction request object.
79
+ * @param executionResult - The execution result object containing nested executions and preimages.
80
+ * @returns A Promise that resolves to a KernelProverOutput object containing proof, public inputs, and output notes.
81
+ */
82
+ async prove(txRequest: TxRequest, executionResult: ExecutionResult): Promise<KernelProverOutput> {
83
+ const executionStack = [executionResult];
84
+ const newNotes: { [commitmentStr: string]: OutputNoteData } = {};
85
+ let firstIteration = true;
86
+ let previousVerificationKey = VerificationKey.makeFake();
87
+
88
+ let output: ProofOutput = {
89
+ publicInputs: PrivateKernelPublicInputs.empty(),
90
+ proof: makeEmptyProof(),
91
+ };
92
+
93
+ while (executionStack.length) {
94
+ const currentExecution = executionStack.pop()!;
95
+ executionStack.push(...currentExecution.nestedExecutions);
96
+ const privateCallStackPreimages = currentExecution.nestedExecutions.map(result => result.callStackItem);
97
+ if (privateCallStackPreimages.length > MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) {
98
+ throw new Error(
99
+ `Too many items in the call stack. Maximum amount is ${MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL}. Got ${privateCallStackPreimages.length}.`,
100
+ );
101
+ }
102
+ // Pad with empty items to reach max/const length expected by circuit.
103
+ privateCallStackPreimages.push(
104
+ ...Array(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL - privateCallStackPreimages.length)
105
+ .fill(0)
106
+ .map(() => PrivateCallStackItem.empty()),
107
+ );
108
+
109
+ // Start with the partially filled in read request witnesses from the simulator
110
+ // and fill the non-transient ones in with sibling paths via oracle.
111
+ const readRequestMembershipWitnesses = currentExecution.readRequestPartialWitnesses;
112
+ for (let rr = 0; rr < readRequestMembershipWitnesses.length; rr++) {
113
+ if (currentExecution.callStackItem.publicInputs.readRequests[rr] == Fr.zero()) {
114
+ throw new Error(
115
+ 'Number of read requests output from Noir circuit does not match number of read request commitment indices output from simulator.',
116
+ );
117
+ }
118
+ const rrWitness = readRequestMembershipWitnesses[rr];
119
+ if (!rrWitness.isTransient) {
120
+ // Non-transient reads must contain full membership witness with sibling path from commitment to root.
121
+ // Get regular membership witness to fill in sibling path in the read request witness.
122
+ const membershipWitness = await this.oracle.getNoteMembershipWitness(rrWitness.leafIndex.toBigInt());
123
+ rrWitness.siblingPath = membershipWitness.siblingPath;
124
+ }
125
+ }
126
+
127
+ // fill in witnesses for remaining/empty read requests
128
+ readRequestMembershipWitnesses.push(
129
+ ...Array(MAX_READ_REQUESTS_PER_CALL - readRequestMembershipWitnesses.length)
130
+ .fill(0)
131
+ .map(() => ReadRequestMembershipWitness.empty(BigInt(0))),
132
+ );
133
+
134
+ const privateCallData = await this.createPrivateCallData(
135
+ currentExecution,
136
+ readRequestMembershipWitnesses,
137
+ makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, i => privateCallStackPreimages[i], 0),
138
+ );
139
+
140
+ if (firstIteration) {
141
+ output = await this.proofCreator.createProofInit(new PrivateKernelInputsInit(txRequest, privateCallData));
142
+ } else {
143
+ const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey);
144
+ const previousKernelData = new PreviousKernelData(
145
+ output.publicInputs,
146
+ output.proof,
147
+ previousVerificationKey,
148
+ Number(previousVkMembershipWitness.leafIndex),
149
+ assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
150
+ );
151
+ output = await this.proofCreator.createProofInner(
152
+ new PrivateKernelInputsInner(previousKernelData, privateCallData),
153
+ );
154
+ }
155
+ (await this.getNewNotes(currentExecution)).forEach(n => {
156
+ newNotes[n.commitment.toString()] = n;
157
+ });
158
+ firstIteration = false;
159
+ previousVerificationKey = privateCallData.vk;
160
+ }
161
+
162
+ const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey);
163
+ const previousKernelData = new PreviousKernelData(
164
+ output.publicInputs,
165
+ output.proof,
166
+ previousVerificationKey,
167
+ Number(previousVkMembershipWitness.leafIndex),
168
+ assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
169
+ );
170
+
171
+ const readCommitmentHints = this.getReadRequestHints(
172
+ output.publicInputs.end.readRequests,
173
+ output.publicInputs.end.newCommitments,
174
+ );
175
+
176
+ const nullifierCommitmentHints = this.getNullifierHints(
177
+ output.publicInputs.end.nullifiedCommitments,
178
+ output.publicInputs.end.newCommitments,
179
+ );
180
+
181
+ const privateInputs = new PrivateKernelInputsOrdering(
182
+ previousKernelData,
183
+ readCommitmentHints,
184
+ nullifierCommitmentHints,
185
+ );
186
+ const outputFinal = await this.proofCreator.createProofOrdering(privateInputs);
187
+
188
+ // Only return the notes whose commitment is in the commitments of the final proof.
189
+ const finalNewCommitments = outputFinal.publicInputs.end.newCommitments;
190
+ const outputNotes = finalNewCommitments.map(c => newNotes[c.toString()]).filter(c => !!c);
191
+
192
+ return { ...outputFinal, outputNotes };
193
+ }
194
+
195
+ private async createPrivateCallData(
196
+ { callStackItem, vk }: ExecutionResult,
197
+ readRequestMembershipWitnesses: ReadRequestMembershipWitness[],
198
+ privateCallStackPreimages: Tuple<PrivateCallStackItem, typeof MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL>,
199
+ ) {
200
+ const { contractAddress, functionData, publicInputs } = callStackItem;
201
+ const { portalContractAddress } = publicInputs.callContext;
202
+
203
+ const contractLeafMembershipWitness = functionData.isConstructor
204
+ ? MembershipWitness.random(CONTRACT_TREE_HEIGHT)
205
+ : await this.oracle.getContractMembershipWitness(contractAddress);
206
+
207
+ const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness(
208
+ contractAddress,
209
+ functionData.selector,
210
+ );
211
+
212
+ // TODO(#262): Use real acir hash
213
+ // const acirHash = keccak(Buffer.from(bytecode, 'hex'));
214
+ const acirHash = Fr.fromBuffer(Buffer.alloc(32, 0));
215
+
216
+ // TODO
217
+ const proof = makeEmptyProof();
218
+
219
+ return new PrivateCallData(
220
+ callStackItem,
221
+ privateCallStackPreimages,
222
+ proof,
223
+ VerificationKey.fromBuffer(vk),
224
+ functionLeafMembershipWitness,
225
+ contractLeafMembershipWitness,
226
+ makeTuple(MAX_READ_REQUESTS_PER_CALL, i => readRequestMembershipWitnesses[i], 0),
227
+ portalContractAddress.toField(),
228
+ acirHash,
229
+ );
230
+ }
231
+
232
+ /**
233
+ * Retrieves the new output notes for a given execution result.
234
+ * The function maps over the new note preimages and associates them with their corresponding
235
+ * commitments in the public inputs of the execution result. It also includes the contract address
236
+ * from the call context of the public inputs.
237
+ *
238
+ * @param executionResult - The execution result object containing note preimages and public inputs.
239
+ * @returns An array of OutputNoteData objects, each representing an output note with its associated data.
240
+ */
241
+ private async getNewNotes(executionResult: ExecutionResult): Promise<OutputNoteData[]> {
242
+ const {
243
+ callStackItem: { publicInputs },
244
+ newNotes,
245
+ } = executionResult;
246
+ const contractAddress = publicInputs.callContext.storageContractAddress;
247
+ // Assuming that for each new commitment there's an output note added to the execution result.
248
+ const newCommitments = await this.proofCreator.getSiloedCommitments(publicInputs);
249
+ return newNotes.map((data, i) => ({
250
+ contractAddress,
251
+ data,
252
+ commitment: newCommitments[i],
253
+ }));
254
+ }
255
+
256
+ /**
257
+ * Performs the matching between an array of read request and an array of commitments. This produces
258
+ * hints for the private kernel ordering circuit to efficiently match a read request with the corresponding
259
+ * commitment.
260
+ *
261
+ * @param readRequests - The array of read requests.
262
+ * @param commitments - The array of commitments.
263
+ * @returns An array of hints where each element is the index of the commitment in commitments array
264
+ * corresponding to the read request. In other words we have readRequests[i] == commitments[hints[i]].
265
+ */
266
+ private getReadRequestHints(
267
+ readRequests: Tuple<Fr, typeof MAX_READ_REQUESTS_PER_TX>,
268
+ commitments: Tuple<Fr, typeof MAX_NEW_COMMITMENTS_PER_TX>,
269
+ ): Tuple<Fr, typeof MAX_READ_REQUESTS_PER_TX> {
270
+ const hints = makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero);
271
+ for (let i = 0; i < MAX_READ_REQUESTS_PER_TX && !readRequests[i].isZero(); i++) {
272
+ const equalToRR = (cmt: Fr) => cmt.equals(readRequests[i]);
273
+ const result = commitments.findIndex(equalToRR);
274
+ if (result == -1) {
275
+ throw new Error(
276
+ `The read request at index ${i} with value ${readRequests[i].toString()} does not match to any commitment.`,
277
+ );
278
+ } else {
279
+ hints[i] = new Fr(result);
280
+ }
281
+ }
282
+ return hints;
283
+ }
284
+
285
+ /**
286
+ * Performs the matching between an array of nullified commitments and an array of commitments. This produces
287
+ * hints for the private kernel ordering circuit to efficiently match a nullifier with the corresponding
288
+ * commitment.
289
+ *
290
+ * @param nullifiedCommitments - The array of nullified commitments.
291
+ * @param commitments - The array of commitments.
292
+ * @returns An array of hints where each element is the index of the commitment in commitments array
293
+ * corresponding to the nullified commitments. In other words we have nullifiedCommitments[i] == commitments[hints[i]].
294
+ */
295
+ private getNullifierHints(
296
+ nullifiedCommitments: Tuple<Fr, typeof MAX_NEW_NULLIFIERS_PER_TX>,
297
+ commitments: Tuple<Fr, typeof MAX_NEW_COMMITMENTS_PER_TX>,
298
+ ): Tuple<Fr, typeof MAX_NEW_NULLIFIERS_PER_TX> {
299
+ const hints = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero);
300
+ for (let i = 0; i < MAX_NEW_NULLIFIERS_PER_TX; i++) {
301
+ if (!nullifiedCommitments[i].isZero() && !nullifiedCommitments[i].equals(new Fr(EMPTY_NULLIFIED_COMMITMENT))) {
302
+ const equalToCommitment = (cmt: Fr) => cmt.equals(nullifiedCommitments[i]);
303
+ const result = commitments.findIndex(equalToCommitment);
304
+ if (result == -1) {
305
+ throw new Error(
306
+ `The nullified commitment at index ${i} with value ${nullifiedCommitments[
307
+ i
308
+ ].toString()} does not match to any commitment.`,
309
+ );
310
+ } else {
311
+ hints[i] = new Fr(result);
312
+ }
313
+ }
314
+ }
315
+ return hints;
316
+ }
317
+ }