@aztec/pxe 0.41.0 → 0.43.0

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 (85) hide show
  1. package/dest/config/index.d.ts.map +1 -1
  2. package/dest/config/index.js +5 -2
  3. package/dest/contract_data_oracle/index.d.ts +1 -0
  4. package/dest/contract_data_oracle/index.d.ts.map +1 -1
  5. package/dest/contract_data_oracle/index.js +7 -1
  6. package/dest/contract_data_oracle/private_functions_tree.d.ts.map +1 -1
  7. package/dest/contract_data_oracle/private_functions_tree.js +2 -2
  8. package/dest/database/deferred_note_dao.d.ts +2 -2
  9. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  10. package/dest/database/deferred_note_dao.js +2 -2
  11. package/dest/database/incoming_note_dao.d.ts +73 -0
  12. package/dest/database/incoming_note_dao.d.ts.map +1 -0
  13. package/dest/database/incoming_note_dao.js +92 -0
  14. package/dest/database/kv_pxe_database.d.ts +10 -7
  15. package/dest/database/kv_pxe_database.d.ts.map +1 -1
  16. package/dest/database/kv_pxe_database.js +149 -78
  17. package/dest/database/{note_dao.d.ts → outgoing_note_dao.d.ts} +7 -12
  18. package/dest/database/outgoing_note_dao.d.ts.map +1 -0
  19. package/dest/database/outgoing_note_dao.js +83 -0
  20. package/dest/database/pxe_database.d.ts +21 -9
  21. package/dest/database/pxe_database.d.ts.map +1 -1
  22. package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
  23. package/dest/database/pxe_database_test_suite.js +71 -24
  24. package/dest/kernel_oracle/index.d.ts +4 -4
  25. package/dest/kernel_oracle/index.d.ts.map +1 -1
  26. package/dest/kernel_oracle/index.js +6 -17
  27. package/dest/kernel_prover/kernel_prover.d.ts +3 -0
  28. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  29. package/dest/kernel_prover/kernel_prover.js +44 -8
  30. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts +2 -1
  31. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.d.ts.map +1 -1
  32. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.js +32 -12
  33. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.d.ts +1 -1
  34. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.d.ts.map +1 -1
  35. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.js +9 -7
  36. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.d.ts.map +1 -1
  37. package/dest/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.js +7 -3
  38. package/dest/kernel_prover/proving_data_oracle.d.ts +6 -6
  39. package/dest/kernel_prover/proving_data_oracle.d.ts.map +1 -1
  40. package/dest/note_processor/note_processor.d.ts +23 -20
  41. package/dest/note_processor/note_processor.d.ts.map +1 -1
  42. package/dest/note_processor/note_processor.js +123 -76
  43. package/dest/note_processor/produce_note_dao.d.ts +13 -4
  44. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  45. package/dest/note_processor/produce_note_dao.js +88 -31
  46. package/dest/pxe_http/pxe_http_server.js +3 -3
  47. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  48. package/dest/pxe_service/create_pxe_service.js +4 -2
  49. package/dest/pxe_service/pxe_service.d.ts +14 -6
  50. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  51. package/dest/pxe_service/pxe_service.js +139 -87
  52. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
  53. package/dest/pxe_service/test/pxe_test_suite.js +3 -16
  54. package/dest/simulator_oracle/index.d.ts +1 -0
  55. package/dest/simulator_oracle/index.d.ts.map +1 -1
  56. package/dest/simulator_oracle/index.js +5 -2
  57. package/dest/synchronizer/synchronizer.d.ts +9 -2
  58. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  59. package/dest/synchronizer/synchronizer.js +43 -34
  60. package/package.json +14 -14
  61. package/src/config/index.ts +11 -1
  62. package/src/contract_data_oracle/index.ts +7 -0
  63. package/src/contract_data_oracle/private_functions_tree.ts +3 -1
  64. package/src/database/deferred_note_dao.ts +1 -1
  65. package/src/database/{note_dao.ts → incoming_note_dao.ts} +10 -7
  66. package/src/database/kv_pxe_database.ts +127 -29
  67. package/src/database/outgoing_note_dao.ts +90 -0
  68. package/src/database/pxe_database.ts +23 -9
  69. package/src/database/pxe_database_test_suite.ts +93 -29
  70. package/src/kernel_oracle/index.ts +4 -17
  71. package/src/kernel_prover/kernel_prover.ts +76 -16
  72. package/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts +79 -8
  73. package/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_outputs.ts +9 -5
  74. package/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts +13 -1
  75. package/src/kernel_prover/proving_data_oracle.ts +5 -6
  76. package/src/note_processor/note_processor.ts +191 -121
  77. package/src/note_processor/produce_note_dao.ts +164 -50
  78. package/src/pxe_http/pxe_http_server.ts +2 -2
  79. package/src/pxe_service/create_pxe_service.ts +3 -1
  80. package/src/pxe_service/pxe_service.ts +210 -149
  81. package/src/pxe_service/test/pxe_test_suite.ts +0 -20
  82. package/src/simulator_oracle/index.ts +5 -1
  83. package/src/synchronizer/synchronizer.ts +55 -50
  84. package/dest/database/note_dao.d.ts.map +0 -1
  85. package/dest/database/note_dao.js +0 -89
@@ -1,4 +1,4 @@
1
- import { type NoteFilter, NoteStatus, randomTxHash } from '@aztec/circuit-types';
1
+ import { type IncomingNotesFilter, NoteStatus, type OutgoingNotesFilter, randomTxHash } from '@aztec/circuit-types';
2
2
  import { AztecAddress, CompleteAddress, INITIAL_L2_BLOCK_NUM, PublicKeys } from '@aztec/circuits.js';
3
3
  import { makeHeader } from '@aztec/circuits.js/testing';
4
4
  import { randomInt } from '@aztec/foundation/crypto';
@@ -6,8 +6,10 @@ import { Fr, Point } from '@aztec/foundation/fields';
6
6
  import { BenchmarkingContractArtifact } from '@aztec/noir-contracts.js/Benchmarking';
7
7
  import { SerializableContractInstance } from '@aztec/types/contracts';
8
8
 
9
- import { type NoteDao } from './note_dao.js';
10
- import { randomNoteDao } from './note_dao.test.js';
9
+ import { type IncomingNoteDao } from './incoming_note_dao.js';
10
+ import { randomIncomingNoteDao } from './incoming_note_dao.test.js';
11
+ import { type OutgoingNoteDao } from './outgoing_note_dao.js';
12
+ import { randomOutgoingNoteDao } from './outgoing_note_dao.test.js';
11
13
  import { type PxeDatabase } from './pxe_database.js';
12
14
 
13
15
  /**
@@ -68,13 +70,13 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
68
70
  });
69
71
  });
70
72
 
71
- describe('notes', () => {
73
+ describe('incoming notes', () => {
72
74
  let owners: CompleteAddress[];
73
75
  let contractAddresses: AztecAddress[];
74
76
  let storageSlots: Fr[];
75
- let notes: NoteDao[];
77
+ let notes: IncomingNoteDao[];
76
78
 
77
- const filteringTests: [() => NoteFilter, () => NoteDao[]][] = [
79
+ const filteringTests: [() => IncomingNotesFilter, () => IncomingNoteDao[]][] = [
78
80
  [() => ({}), () => notes],
79
81
 
80
82
  [
@@ -94,7 +96,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
94
96
 
95
97
  [
96
98
  () => ({ owner: owners[0].address }),
97
- () => notes.filter(note => note.publicKey.equals(owners[0].publicKeys.masterIncomingViewingPublicKey)),
99
+ () => notes.filter(note => note.ivpkM.equals(owners[0].publicKeys.masterIncomingViewingPublicKey)),
98
100
  ],
99
101
 
100
102
  [
@@ -107,46 +109,44 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
107
109
  [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []],
108
110
  ];
109
111
 
110
- beforeEach(() => {
112
+ beforeEach(async () => {
111
113
  owners = Array.from({ length: 2 }).map(() => CompleteAddress.random());
112
114
  contractAddresses = Array.from({ length: 2 }).map(() => AztecAddress.random());
113
115
  storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
114
116
 
115
117
  notes = Array.from({ length: 10 }).map((_, i) =>
116
- randomNoteDao({
118
+ randomIncomingNoteDao({
117
119
  contractAddress: contractAddresses[i % contractAddresses.length],
118
120
  storageSlot: storageSlots[i % storageSlots.length],
119
- publicKey: owners[i % owners.length].publicKeys.masterIncomingViewingPublicKey,
121
+ ivpkM: owners[i % owners.length].publicKeys.masterIncomingViewingPublicKey,
120
122
  index: BigInt(i),
121
123
  }),
122
124
  );
123
- });
124
125
 
125
- beforeEach(async () => {
126
126
  for (const owner of owners) {
127
127
  await database.addCompleteAddress(owner);
128
128
  }
129
129
  });
130
130
 
131
131
  it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
132
- await database.addNotes(notes);
133
- await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected());
132
+ await database.addNotes(notes, []);
133
+ await expect(database.getIncomingNotes(getFilter())).resolves.toEqual(getExpected());
134
134
  });
135
135
 
136
136
  it.each(filteringTests)('stores notes one by one and retrieves notes', async (getFilter, getExpected) => {
137
137
  for (const note of notes) {
138
138
  await database.addNote(note);
139
139
  }
140
- await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected());
140
+ await expect(database.getIncomingNotes(getFilter())).resolves.toEqual(getExpected());
141
141
  });
142
142
 
143
143
  it.each(filteringTests)('retrieves nullified notes', async (getFilter, getExpected) => {
144
- await database.addNotes(notes);
144
+ await database.addNotes(notes, []);
145
145
 
146
146
  // Nullify all notes and use the same filter as other test cases
147
147
  for (const owner of owners) {
148
148
  const notesToNullify = notes.filter(note =>
149
- note.publicKey.equals(owner.publicKeys.masterIncomingViewingPublicKey),
149
+ note.ivpkM.equals(owner.publicKeys.masterIncomingViewingPublicKey),
150
150
  );
151
151
  const nullifiers = notesToNullify.map(note => note.siloedNullifier);
152
152
  await expect(
@@ -154,41 +154,41 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
154
154
  ).resolves.toEqual(notesToNullify);
155
155
  }
156
156
 
157
- await expect(database.getNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED })).resolves.toEqual(
158
- getExpected(),
159
- );
157
+ await expect(
158
+ database.getIncomingNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED }),
159
+ ).resolves.toEqual(getExpected());
160
160
  });
161
161
 
162
162
  it('skips nullified notes by default or when requesting active', async () => {
163
- await database.addNotes(notes);
163
+ await database.addNotes(notes, []);
164
164
 
165
165
  const notesToNullify = notes.filter(note =>
166
- note.publicKey.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
166
+ note.ivpkM.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
167
167
  );
168
168
  const nullifiers = notesToNullify.map(note => note.siloedNullifier);
169
- await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual(
169
+ await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].ivpkM)).resolves.toEqual(
170
170
  notesToNullify,
171
171
  );
172
172
 
173
- const actualNotesWithDefault = await database.getNotes({});
174
- const actualNotesWithActive = await database.getNotes({ status: NoteStatus.ACTIVE });
173
+ const actualNotesWithDefault = await database.getIncomingNotes({});
174
+ const actualNotesWithActive = await database.getIncomingNotes({ status: NoteStatus.ACTIVE });
175
175
 
176
176
  expect(actualNotesWithDefault).toEqual(actualNotesWithActive);
177
177
  expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note)));
178
178
  });
179
179
 
180
180
  it('returns active and nullified notes when requesting either', async () => {
181
- await database.addNotes(notes);
181
+ await database.addNotes(notes, []);
182
182
 
183
183
  const notesToNullify = notes.filter(note =>
184
- note.publicKey.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
184
+ note.ivpkM.equals(owners[0].publicKeys.masterIncomingViewingPublicKey),
185
185
  );
186
186
  const nullifiers = notesToNullify.map(note => note.siloedNullifier);
187
- await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual(
187
+ await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].ivpkM)).resolves.toEqual(
188
188
  notesToNullify,
189
189
  );
190
190
 
191
- const result = await database.getNotes({
191
+ const result = await database.getIncomingNotes({
192
192
  status: NoteStatus.ACTIVE_OR_NULLIFIED,
193
193
  });
194
194
 
@@ -198,6 +198,70 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
198
198
  });
199
199
  });
200
200
 
201
+ describe('outgoing notes', () => {
202
+ let owners: CompleteAddress[];
203
+ let contractAddresses: AztecAddress[];
204
+ let storageSlots: Fr[];
205
+ let notes: OutgoingNoteDao[];
206
+
207
+ const filteringTests: [() => OutgoingNotesFilter, () => OutgoingNoteDao[]][] = [
208
+ [() => ({}), () => notes],
209
+
210
+ [
211
+ () => ({ contractAddress: contractAddresses[0] }),
212
+ () => notes.filter(note => note.contractAddress.equals(contractAddresses[0])),
213
+ ],
214
+ [() => ({ contractAddress: AztecAddress.random() }), () => []],
215
+
216
+ [
217
+ () => ({ storageSlot: storageSlots[0] }),
218
+ () => notes.filter(note => note.storageSlot.equals(storageSlots[0])),
219
+ ],
220
+ [() => ({ storageSlot: Fr.random() }), () => []],
221
+
222
+ [() => ({ txHash: notes[0].txHash }), () => [notes[0]]],
223
+ [() => ({ txHash: randomTxHash() }), () => []],
224
+
225
+ [
226
+ () => ({ owner: owners[0].address }),
227
+ () => notes.filter(note => note.ovpkM.equals(owners[0].publicKeys.masterOutgoingViewingPublicKey)),
228
+ ],
229
+
230
+ [
231
+ () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }),
232
+ () =>
233
+ notes.filter(
234
+ note => note.contractAddress.equals(contractAddresses[0]) && note.storageSlot.equals(storageSlots[0]),
235
+ ),
236
+ ],
237
+ [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []],
238
+ ];
239
+
240
+ beforeEach(async () => {
241
+ owners = Array.from({ length: 2 }).map(() => CompleteAddress.random());
242
+ contractAddresses = Array.from({ length: 2 }).map(() => AztecAddress.random());
243
+ storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
244
+
245
+ notes = Array.from({ length: 10 }).map((_, i) =>
246
+ randomOutgoingNoteDao({
247
+ contractAddress: contractAddresses[i % contractAddresses.length],
248
+ storageSlot: storageSlots[i % storageSlots.length],
249
+ ovpkM: owners[i % owners.length].publicKeys.masterOutgoingViewingPublicKey,
250
+ index: BigInt(i),
251
+ }),
252
+ );
253
+
254
+ for (const owner of owners) {
255
+ await database.addCompleteAddress(owner);
256
+ }
257
+ });
258
+
259
+ it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
260
+ await database.addNotes([], notes);
261
+ await expect(database.getOutgoingNotes(getFilter())).resolves.toEqual(getExpected());
262
+ });
263
+ });
264
+
201
265
  describe('block header', () => {
202
266
  it('stores and retrieves the block header', async () => {
203
267
  const header = makeHeader(randomInt(1000), INITIAL_L2_BLOCK_NUM);
@@ -4,7 +4,6 @@ import {
4
4
  type Fr,
5
5
  type FunctionSelector,
6
6
  type GrumpkinPrivateKey,
7
- type KeyGenerator,
8
7
  MembershipWitness,
9
8
  type NOTE_HASH_TREE_HEIGHT,
10
9
  type Point,
@@ -70,23 +69,11 @@ export class KernelOracle implements ProvingDataOracle {
70
69
  return header.state.partial.noteHashTree.root;
71
70
  }
72
71
 
73
- public getMasterSecretKeyAndAppKeyGenerator(masterPublicKey: Point): Promise<[GrumpkinPrivateKey, KeyGenerator]> {
74
- return this.keyStore.getMasterSecretKeyAndAppKeyGenerator(masterPublicKey);
72
+ public getMasterSecretKey(masterPublicKey: Point): Promise<GrumpkinPrivateKey> {
73
+ return this.keyStore.getMasterSecretKey(masterPublicKey);
75
74
  }
76
75
 
77
- public async getFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
78
- try {
79
- const contractInstance = await this.contractDataOracle.getContractInstance(contractAddress);
80
-
81
- const [contractArtifact, functionArtifact] = await Promise.all([
82
- this.contractDataOracle.getContractArtifact(contractInstance.contractClassId),
83
- this.contractDataOracle.getFunctionArtifact(contractAddress, selector),
84
- ]);
85
-
86
- return `${contractArtifact.name}:${functionArtifact.name}`;
87
- } catch (e) {
88
- this.log.error(`Failed to get function name for contract ${contractAddress} and selector ${selector}: ${e}`);
89
- return 'Unknown';
90
- }
76
+ public getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string> {
77
+ return this.contractDataOracle.getDebugFunctionName(contractAddress, selector);
91
78
  }
92
79
  }
@@ -2,6 +2,12 @@ import { type KernelProofOutput, type ProofCreator } from '@aztec/circuit-types'
2
2
  import {
3
3
  CallRequest,
4
4
  Fr,
5
+ MAX_KEY_VALIDATION_REQUESTS_PER_TX,
6
+ MAX_NEW_NOTE_HASHES_PER_TX,
7
+ MAX_NEW_NULLIFIERS_PER_TX,
8
+ MAX_NOTE_ENCRYPTED_LOGS_PER_TX,
9
+ MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
10
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX,
5
11
  MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
6
12
  NESTED_RECURSIVE_PROOF_LENGTH,
7
13
  PrivateCallData,
@@ -16,6 +22,7 @@ import {
16
22
  type TxRequest,
17
23
  VK_TREE_HEIGHT,
18
24
  VerificationKeyAsFields,
25
+ getNonEmptyItems,
19
26
  makeRecursiveProof,
20
27
  } from '@aztec/circuits.js';
21
28
  import { padArrayEnd } from '@aztec/foundation/collection';
@@ -70,6 +77,9 @@ export class KernelProver {
70
77
  const noteHashNullifierCounterMap = collectNullifiedNoteHashCounters(executionResult);
71
78
 
72
79
  while (executionStack.length) {
80
+ if (!firstIteration && this.needsReset(executionStack, output)) {
81
+ output = await this.runReset(executionStack, output, noteHashLeafIndexMap, noteHashNullifierCounterMap);
82
+ }
73
83
  const currentExecution = executionStack.pop()!;
74
84
  executionStack.push(...[...currentExecution.nestedExecutions].reverse());
75
85
 
@@ -78,7 +88,7 @@ export class KernelProver {
78
88
  ? CallRequest.empty()
79
89
  : currentExecution.publicTeardownFunctionCall.toCallRequest();
80
90
 
81
- const functionName = await this.oracle.getFunctionName(
91
+ const functionName = await this.oracle.getDebugFunctionName(
82
92
  currentExecution.callStackItem.contractAddress,
83
93
  currentExecution.callStackItem.functionData.selector,
84
94
  );
@@ -126,21 +136,11 @@ export class KernelProver {
126
136
  firstIteration = false;
127
137
  }
128
138
 
129
- let previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
130
- let previousKernelData = new PrivateKernelData(
131
- output.publicInputs,
132
- output.proof,
133
- output.verificationKey,
134
- Number(previousVkMembershipWitness.leafIndex),
135
- assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
136
- );
137
-
138
- output = await this.proofCreator.createProofReset(
139
- await buildPrivateKernelResetInputs(previousKernelData, noteHashLeafIndexMap, this.oracle),
140
- );
141
-
142
- previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
143
- previousKernelData = new PrivateKernelData(
139
+ if (this.somethingToReset(output)) {
140
+ output = await this.runReset(executionStack, output, noteHashLeafIndexMap, noteHashNullifierCounterMap);
141
+ }
142
+ const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
143
+ const previousKernelData = new PrivateKernelData(
144
144
  output.publicInputs,
145
145
  output.proof,
146
146
  output.verificationKey,
@@ -160,6 +160,66 @@ export class KernelProver {
160
160
  return await this.proofCreator.createProofTail(privateInputs);
161
161
  }
162
162
 
163
+ private needsReset(executionStack: ExecutionResult[], output: KernelProofOutput<PrivateKernelCircuitPublicInputs>) {
164
+ const nextIteration = executionStack[executionStack.length - 1];
165
+ return (
166
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.newNoteHashes).length +
167
+ getNonEmptyItems(output.publicInputs.end.newNoteHashes).length >
168
+ MAX_NEW_NOTE_HASHES_PER_TX ||
169
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.newNullifiers).length +
170
+ getNonEmptyItems(output.publicInputs.end.newNullifiers).length >
171
+ MAX_NEW_NULLIFIERS_PER_TX ||
172
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.noteEncryptedLogsHashes).length +
173
+ getNonEmptyItems(output.publicInputs.end.noteEncryptedLogsHashes).length >
174
+ MAX_NOTE_ENCRYPTED_LOGS_PER_TX ||
175
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.noteHashReadRequests).length +
176
+ getNonEmptyItems(output.publicInputs.validationRequests.noteHashReadRequests).length >
177
+ MAX_NOTE_HASH_READ_REQUESTS_PER_TX ||
178
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.nullifierReadRequests).length +
179
+ getNonEmptyItems(output.publicInputs.validationRequests.nullifierReadRequests).length >
180
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX ||
181
+ getNonEmptyItems(nextIteration.callStackItem.publicInputs.keyValidationRequestsAndGenerators).length +
182
+ getNonEmptyItems(output.publicInputs.validationRequests.scopedKeyValidationRequestsAndGenerators).length >
183
+ MAX_KEY_VALIDATION_REQUESTS_PER_TX
184
+ );
185
+ }
186
+
187
+ private somethingToReset(output: KernelProofOutput<PrivateKernelCircuitPublicInputs>) {
188
+ return (
189
+ getNonEmptyItems(output.publicInputs.validationRequests.noteHashReadRequests).length > 0 ||
190
+ getNonEmptyItems(output.publicInputs.validationRequests.nullifierReadRequests).length > 0 ||
191
+ getNonEmptyItems(output.publicInputs.validationRequests.scopedKeyValidationRequestsAndGenerators).length > 0 ||
192
+ output.publicInputs.end.newNoteHashes.find(noteHash => noteHash.nullifierCounter !== 0) ||
193
+ output.publicInputs.end.newNullifiers.find(nullifier => !nullifier.nullifiedNoteHash.equals(Fr.zero()))
194
+ );
195
+ }
196
+
197
+ private async runReset(
198
+ executionStack: ExecutionResult[],
199
+ output: KernelProofOutput<PrivateKernelCircuitPublicInputs>,
200
+ noteHashLeafIndexMap: Map<bigint, bigint>,
201
+ noteHashNullifierCounterMap: Map<number, number>,
202
+ ): Promise<KernelProofOutput<PrivateKernelCircuitPublicInputs>> {
203
+ const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
204
+ const previousKernelData = new PrivateKernelData(
205
+ output.publicInputs,
206
+ output.proof,
207
+ output.verificationKey,
208
+ Number(previousVkMembershipWitness.leafIndex),
209
+ assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
210
+ );
211
+
212
+ return this.proofCreator.createProofReset(
213
+ await buildPrivateKernelResetInputs(
214
+ executionStack,
215
+ previousKernelData,
216
+ noteHashLeafIndexMap,
217
+ noteHashNullifierCounterMap,
218
+ this.oracle,
219
+ ),
220
+ );
221
+ }
222
+
163
223
  private async createPrivateCallData(
164
224
  { callStackItem }: ExecutionResult,
165
225
  publicCallRequests: CallRequest[],
@@ -1,5 +1,5 @@
1
1
  import {
2
- Fr,
2
+ type Fr,
3
3
  KeyValidationHint,
4
4
  MAX_KEY_VALIDATION_REQUESTS_PER_TX,
5
5
  MAX_NEW_NOTE_HASHES_PER_TX,
@@ -14,15 +14,19 @@ import {
14
14
  PrivateKernelResetCircuitPrivateInputs,
15
15
  type PrivateKernelResetCircuitPrivateInputsVariants,
16
16
  PrivateKernelResetHints,
17
- type ScopedKeyValidationRequest,
18
- type ScopedNullifier,
19
- type ScopedReadRequest,
17
+ type ReadRequest,
18
+ type ScopedKeyValidationRequestAndGenerator,
19
+ ScopedNoteHash,
20
+ ScopedNullifier,
21
+ ScopedReadRequest,
20
22
  buildNoteHashReadRequestHints,
21
23
  buildNullifierReadRequestHints,
22
24
  buildTransientDataHints,
25
+ getNonEmptyItems,
23
26
  } from '@aztec/circuits.js';
24
27
  import { makeTuple } from '@aztec/foundation/array';
25
28
  import { type Tuple } from '@aztec/foundation/serialize';
29
+ import type { ExecutionResult } from '@aztec/simulator';
26
30
 
27
31
  import { type ProvingDataOracle } from '../proving_data_oracle.js';
28
32
  import { buildPrivateKernelResetOutputs } from './build_private_kernel_reset_outputs.js';
@@ -33,6 +37,7 @@ function getNullifierReadRequestHints<PENDING extends number, SETTLED extends nu
33
37
  oracle: ProvingDataOracle,
34
38
  sizePending: PENDING,
35
39
  sizeSettled: SETTLED,
40
+ futureNullifiers: ScopedNullifier[],
36
41
  ) {
37
42
  const getNullifierMembershipWitness = async (nullifier: Fr) => {
38
43
  const res = await oracle.getNullifierMembershipWitness(nullifier);
@@ -57,11 +62,12 @@ function getNullifierReadRequestHints<PENDING extends number, SETTLED extends nu
57
62
  nullifiers,
58
63
  sizePending,
59
64
  sizeSettled,
65
+ futureNullifiers,
60
66
  );
61
67
  }
62
68
 
63
69
  async function getMasterSecretKeysAndAppKeyGenerators(
64
- keyValidationRequests: Tuple<ScopedKeyValidationRequest, typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX>,
70
+ keyValidationRequests: Tuple<ScopedKeyValidationRequestAndGenerator, typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX>,
65
71
  oracle: ProvingDataOracle,
66
72
  ) {
67
73
  const keysHints = makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_TX, KeyValidationHint.empty);
@@ -72,8 +78,8 @@ async function getMasterSecretKeysAndAppKeyGenerators(
72
78
  if (request.isEmpty()) {
73
79
  break;
74
80
  }
75
- const [secretKeys, appKeyGenerator] = await oracle.getMasterSecretKeyAndAppKeyGenerator(request.masterPublicKey);
76
- keysHints[keyIndex] = new KeyValidationHint(secretKeys, new Fr(appKeyGenerator), i);
81
+ const secretKeys = await oracle.getMasterSecretKey(request.request.pkM);
82
+ keysHints[keyIndex] = new KeyValidationHint(secretKeys, i);
77
83
  keyIndex++;
78
84
  }
79
85
  return {
@@ -83,12 +89,27 @@ async function getMasterSecretKeysAndAppKeyGenerators(
83
89
  }
84
90
 
85
91
  export async function buildPrivateKernelResetInputs(
92
+ executionStack: ExecutionResult[],
86
93
  previousKernelData: PrivateKernelData,
87
94
  noteHashLeafIndexMap: Map<bigint, bigint>,
95
+ noteHashNullifierCounterMap: Map<number, number>,
88
96
  oracle: ProvingDataOracle,
89
97
  ) {
90
98
  const publicInputs = previousKernelData.publicInputs;
91
99
  // Use max sizes, they will be trimmed down later.
100
+
101
+ const futureNoteHashes = collectNested(executionStack, executionResult => {
102
+ const nonEmptyNoteHashes = getNonEmptyItems(executionResult.callStackItem.publicInputs.newNoteHashes);
103
+ return nonEmptyNoteHashes.map(
104
+ noteHash =>
105
+ new ScopedNoteHash(
106
+ noteHash,
107
+ noteHashNullifierCounterMap.get(noteHash.counter) ?? 0,
108
+ executionResult.callStackItem.publicInputs.callContext.storageContractAddress,
109
+ ),
110
+ );
111
+ });
112
+
92
113
  const {
93
114
  numPendingReadHints: noteHashPendingReadHints,
94
115
  numSettledReadHints: noteHashSettledReadHints,
@@ -100,8 +121,17 @@ export async function buildPrivateKernelResetInputs(
100
121
  noteHashLeafIndexMap,
101
122
  MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
102
123
  MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
124
+ futureNoteHashes,
103
125
  );
104
126
 
127
+ const futureNullifiers = collectNested(executionStack, executionResult => {
128
+ const nonEmptyNullifiers = getNonEmptyItems(executionResult.callStackItem.publicInputs.newNullifiers);
129
+ return nonEmptyNullifiers.map(
130
+ nullifier =>
131
+ new ScopedNullifier(nullifier, executionResult.callStackItem.publicInputs.callContext.storageContractAddress),
132
+ );
133
+ });
134
+
105
135
  const {
106
136
  numPendingReadHints: nullifierPendingReadHints,
107
137
  numSettledReadHints: nullifierSettledReadHints,
@@ -112,13 +142,23 @@ export async function buildPrivateKernelResetInputs(
112
142
  oracle,
113
143
  MAX_NULLIFIER_READ_REQUESTS_PER_TX,
114
144
  MAX_NULLIFIER_READ_REQUESTS_PER_TX,
145
+ futureNullifiers,
115
146
  );
116
147
 
117
148
  const { keysCount, keysHints } = await getMasterSecretKeysAndAppKeyGenerators(
118
- publicInputs.validationRequests.keyValidationRequests,
149
+ publicInputs.validationRequests.scopedKeyValidationRequestsAndGenerators,
119
150
  oracle,
120
151
  );
121
152
 
153
+ const futureNoteHashReads = collectNestedReadRequests(
154
+ executionStack,
155
+ executionResult => executionResult.callStackItem.publicInputs.noteHashReadRequests,
156
+ );
157
+ const futureNullifierReads = collectNestedReadRequests(
158
+ executionStack,
159
+ executionResult => executionResult.callStackItem.publicInputs.nullifierReadRequests,
160
+ );
161
+
122
162
  const [
123
163
  transientNullifierIndexesForNoteHashes,
124
164
  transientNoteHashIndexesForNullifiers,
@@ -127,6 +167,8 @@ export async function buildPrivateKernelResetInputs(
127
167
  publicInputs.end.newNoteHashes,
128
168
  publicInputs.end.newNullifiers,
129
169
  publicInputs.end.noteEncryptedLogsHashes,
170
+ futureNoteHashReads,
171
+ futureNullifierReads,
130
172
  MAX_NEW_NOTE_HASHES_PER_TX,
131
173
  MAX_NEW_NULLIFIERS_PER_TX,
132
174
  MAX_NOTE_ENCRYPTED_LOGS_PER_TX,
@@ -136,6 +178,8 @@ export async function buildPrivateKernelResetInputs(
136
178
  previousKernelData.publicInputs.end.newNoteHashes,
137
179
  previousKernelData.publicInputs.end.newNullifiers,
138
180
  previousKernelData.publicInputs.end.noteEncryptedLogsHashes,
181
+ transientNullifierIndexesForNoteHashes,
182
+ transientNoteHashIndexesForNullifiers,
139
183
  );
140
184
 
141
185
  let privateInputs;
@@ -177,3 +221,30 @@ export async function buildPrivateKernelResetInputs(
177
221
 
178
222
  return privateInputs as PrivateKernelResetCircuitPrivateInputsVariants;
179
223
  }
224
+
225
+ function collectNested<T>(
226
+ executionStack: ExecutionResult[],
227
+ extractExecutionItems: (execution: ExecutionResult) => T[],
228
+ ): T[] {
229
+ const thisExecutionReads = executionStack.flatMap(extractExecutionItems);
230
+
231
+ return thisExecutionReads.concat(
232
+ executionStack.flatMap(({ nestedExecutions }) => collectNested(nestedExecutions, extractExecutionItems)),
233
+ );
234
+ }
235
+
236
+ function collectNestedReadRequests(
237
+ executionStack: ExecutionResult[],
238
+ extractReadRequests: (execution: ExecutionResult) => ReadRequest[],
239
+ ): ScopedReadRequest[] {
240
+ return collectNested(executionStack, executionResult => {
241
+ const nonEmptyReadRequests = getNonEmptyItems(extractReadRequests(executionResult));
242
+ return nonEmptyReadRequests.map(
243
+ readRequest =>
244
+ new ScopedReadRequest(
245
+ readRequest,
246
+ executionResult.callStackItem.publicInputs.callContext.storageContractAddress,
247
+ ),
248
+ );
249
+ });
250
+ }
@@ -14,22 +14,26 @@ export function buildPrivateKernelResetOutputs(
14
14
  prevNoteHashes: Tuple<ScopedNoteHash, typeof MAX_NEW_NOTE_HASHES_PER_TX>,
15
15
  prevNullifiers: Tuple<ScopedNullifier, typeof MAX_NEW_NULLIFIERS_PER_TX>,
16
16
  prevLogs: Tuple<NoteLogHash, typeof MAX_NOTE_ENCRYPTED_LOGS_PER_TX>,
17
+ transientNullifierIndexesForNoteHashes: Tuple<number, typeof MAX_NEW_NOTE_HASHES_PER_TX>,
18
+ transientNoteHashIndexesForNullifiers: Tuple<number, typeof MAX_NEW_NULLIFIERS_PER_TX>,
17
19
  ) {
18
- // Propagate note hashes that are not linked to a nullifier.
19
- // Note that note hashes can't link to the first nullifier (counter == 0).
20
+ // Propagate note hashes that are not going to be squashed in the transient arrays.
21
+ // A value isn't going to be squashed if the symmetrical index in the corresponding array is the length of the array.
20
22
  const noteHashes = padArrayEnd(
21
- prevNoteHashes.filter(n => !n.nullifierCounter),
23
+ prevNoteHashes.filter((_, index) => transientNullifierIndexesForNoteHashes[index] === MAX_NEW_NULLIFIERS_PER_TX),
22
24
  ScopedNoteHash.empty(),
23
25
  MAX_NEW_NOTE_HASHES_PER_TX,
24
26
  );
25
27
 
26
28
  const nullifiers = padArrayEnd(
27
- prevNullifiers.filter(n => n.nullifiedNoteHash.isZero()),
29
+ prevNullifiers.filter((_, index) => transientNoteHashIndexesForNullifiers[index] === MAX_NEW_NOTE_HASHES_PER_TX),
28
30
  ScopedNullifier.empty(),
29
31
  MAX_NEW_NULLIFIERS_PER_TX,
30
32
  );
31
33
 
32
- const nullifiedNotes = prevNoteHashes.filter(n => !n.isEmpty() && n.nullifierCounter).map(n => n.counter);
34
+ const nullifiedNotes = prevNoteHashes
35
+ .filter((_, index) => transientNullifierIndexesForNoteHashes[index] < MAX_NEW_NULLIFIERS_PER_TX)
36
+ .map(n => n.counter);
33
37
 
34
38
  const logs = padArrayEnd(
35
39
  prevLogs.filter(l => !l.isEmpty() && !nullifiedNotes.includes(l.noteHashCounter)),
@@ -3,13 +3,14 @@ import {
3
3
  MAX_NEW_NOTE_HASHES_PER_TX,
4
4
  MAX_NEW_NULLIFIERS_PER_TX,
5
5
  MAX_NOTE_ENCRYPTED_LOGS_PER_TX,
6
+ MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
6
7
  MAX_UNENCRYPTED_LOGS_PER_TX,
7
8
  type PrivateKernelCircuitPublicInputs,
8
9
  PrivateKernelTailHints,
9
10
  sortByCounterGetSortedHints,
10
11
  } from '@aztec/circuits.js';
11
12
 
12
- export function buildPrivateKernelTailHints(publicInputs: PrivateKernelCircuitPublicInputs) {
13
+ export function buildPrivateKernelTailHints(publicInputs: PrivateKernelCircuitPublicInputs): PrivateKernelTailHints {
13
14
  const [sortedNoteHashes, sortedNoteHashesIndexes] = sortByCounterGetSortedHints(
14
15
  publicInputs.end.newNoteHashes,
15
16
  MAX_NEW_NOTE_HASHES_PER_TX,
@@ -35,6 +36,15 @@ export function buildPrivateKernelTailHints(publicInputs: PrivateKernelCircuitPu
35
36
  MAX_UNENCRYPTED_LOGS_PER_TX,
36
37
  );
37
38
 
39
+ const [sortedCallRequests, sortedCallRequestsIndexes] = sortByCounterGetSortedHints(
40
+ publicInputs.end.publicCallStack,
41
+ MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
42
+ {
43
+ ascending: false,
44
+ hintIndexesBy: 'sorted',
45
+ },
46
+ );
47
+
38
48
  return new PrivateKernelTailHints(
39
49
  sortedNoteHashes,
40
50
  sortedNoteHashesIndexes,
@@ -46,5 +56,7 @@ export function buildPrivateKernelTailHints(publicInputs: PrivateKernelCircuitPu
46
56
  sortedEncryptedLogHashesIndexes,
47
57
  sortedUnencryptedLogHashes,
48
58
  sortedUnencryptedLogHashesIndexes,
59
+ sortedCallRequests,
60
+ sortedCallRequestsIndexes,
49
61
  );
50
62
  }
@@ -4,7 +4,6 @@ import {
4
4
  type Fr,
5
5
  type FunctionSelector,
6
6
  type GrumpkinPrivateKey,
7
- type KeyGenerator,
8
7
  type MembershipWitness,
9
8
  type NOTE_HASH_TREE_HEIGHT,
10
9
  type Point,
@@ -71,13 +70,13 @@ export interface ProvingDataOracle {
71
70
  getNoteHashTreeRoot(): Promise<Fr>;
72
71
 
73
72
  /**
74
- * Retrieves the sk_m for the pk_m and a generator index of the key type.
73
+ * Retrieves the sk_m corresponding to the pk_m.
75
74
  * @throws If the provided public key is not associated with any of the registered accounts.
76
- * @param masterPublicKey - The master public key to get secret key for.
77
- * @returns A Promise that resolves to sk_m and the corresponding app key generator.
75
+ * @param pkM - The master public key to get secret key for.
76
+ * @returns A Promise that resolves to sk_m.
78
77
  * @dev Used when feeding the sk_m to the kernel circuit for keys verification.
79
78
  */
80
- getMasterSecretKeyAndAppKeyGenerator(masterPublicKey: Point): Promise<[GrumpkinPrivateKey, KeyGenerator]>;
79
+ getMasterSecretKey(masterPublicKey: Point): Promise<GrumpkinPrivateKey>;
81
80
 
82
- getFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
81
+ getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
83
82
  }