@aztec/pxe 0.56.0 → 0.57.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.
- package/dest/bin/index.js +0 -0
- package/dest/database/deferred_note_dao.d.ts +6 -2
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +8 -5
- package/dest/database/incoming_note_dao.d.ts +3 -1
- package/dest/database/incoming_note_dao.d.ts.map +1 -1
- package/dest/database/incoming_note_dao.js +5 -1
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +3 -2
- package/dest/database/outgoing_note_dao.d.ts +3 -1
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/outgoing_note_dao.js +5 -1
- package/dest/kernel_oracle/index.d.ts +1 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +28 -0
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -0
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +260 -0
- package/dest/kernel_prover/hints/index.d.ts +1 -2
- package/dest/kernel_prover/hints/index.d.ts.map +1 -1
- package/dest/kernel_prover/hints/index.js +2 -3
- package/dest/kernel_prover/kernel_prover.d.ts +2 -4
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +26 -25
- package/dest/kernel_prover/test/test_circuit_prover.d.ts +2 -3
- package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +1 -1
- package/dest/kernel_prover/test/test_circuit_prover.js +8 -11
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +13 -15
- package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts +12 -0
- package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts.map +1 -0
- package/dest/note_processor/utils/add_nullable_field_to_payload.js +46 -0
- package/dest/note_processor/utils/brute_force_note_info.d.ts +26 -0
- package/dest/note_processor/utils/brute_force_note_info.d.ts.map +1 -0
- package/dest/note_processor/utils/brute_force_note_info.js +52 -0
- package/dest/note_processor/utils/index.d.ts +3 -0
- package/dest/note_processor/utils/index.d.ts.map +1 -0
- package/dest/note_processor/utils/index.js +2 -0
- package/dest/note_processor/{produce_note_dao.d.ts → utils/produce_note_daos.d.ts} +12 -8
- package/dest/note_processor/utils/produce_note_daos.d.ts.map +1 -0
- package/dest/note_processor/utils/produce_note_daos.js +53 -0
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts +9 -0
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts.map +1 -0
- package/dest/note_processor/utils/produce_note_daos_for_key.js +80 -0
- package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
- package/dest/pxe_http/pxe_http_server.js +12 -4
- package/dest/pxe_service/pxe_service.d.ts +3 -3
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +36 -38
- package/package.json +17 -14
- package/src/database/deferred_note_dao.ts +5 -1
- package/src/database/incoming_note_dao.ts +24 -1
- package/src/database/kv_pxe_database.ts +3 -1
- package/src/database/outgoing_note_dao.ts +23 -1
- package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +467 -0
- package/src/kernel_prover/hints/index.ts +1 -2
- package/src/kernel_prover/kernel_prover.ts +53 -76
- package/src/kernel_prover/test/test_circuit_prover.ts +11 -15
- package/src/note_processor/note_processor.ts +30 -21
- package/src/note_processor/utils/add_nullable_field_to_payload.ts +67 -0
- package/src/note_processor/utils/brute_force_note_info.ts +82 -0
- package/src/note_processor/utils/index.ts +2 -0
- package/src/note_processor/utils/produce_note_daos.ts +114 -0
- package/src/note_processor/utils/produce_note_daos_for_key.ts +157 -0
- package/src/pxe_http/pxe_http_server.ts +18 -3
- package/src/pxe_service/pxe_service.ts +53 -71
- package/dest/kernel_prover/hints/build_private_kernel_reset_hints.d.ts +0 -5
- package/dest/kernel_prover/hints/build_private_kernel_reset_hints.d.ts.map +0 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_hints.js +0 -90
- package/dest/kernel_prover/hints/needs_reset.d.ts +0 -5
- package/dest/kernel_prover/hints/needs_reset.d.ts.map +0 -1
- package/dest/kernel_prover/hints/needs_reset.js +0 -38
- package/dest/note_processor/produce_note_dao.d.ts.map +0 -1
- package/dest/note_processor/produce_note_dao.js +0 -131
- package/src/kernel_prover/hints/build_private_kernel_reset_hints.ts +0 -249
- package/src/kernel_prover/hints/needs_reset.ts +0 -54
- package/src/note_processor/produce_note_dao.ts +0 -235
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { type PrivateExecutionResult, type PrivateKernelSimulateOutput, collectNested } from '@aztec/circuit-types';
|
|
2
|
+
import {
|
|
3
|
+
type Fr,
|
|
4
|
+
KeyValidationHint,
|
|
5
|
+
MAX_KEY_VALIDATION_REQUESTS_PER_TX,
|
|
6
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
7
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
|
|
8
|
+
MAX_NULLIFIERS_PER_TX,
|
|
9
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
10
|
+
MembershipWitness,
|
|
11
|
+
NULLIFIER_TREE_HEIGHT,
|
|
12
|
+
type PrivateCircuitPublicInputs,
|
|
13
|
+
type PrivateKernelCircuitPublicInputs,
|
|
14
|
+
PrivateKernelData,
|
|
15
|
+
PrivateKernelResetCircuitPrivateInputs,
|
|
16
|
+
PrivateKernelResetDimensions,
|
|
17
|
+
PrivateKernelResetHints,
|
|
18
|
+
type ReadRequest,
|
|
19
|
+
ReadRequestResetStates,
|
|
20
|
+
ReadRequestState,
|
|
21
|
+
type ScopedKeyValidationRequestAndGenerator,
|
|
22
|
+
ScopedNoteHash,
|
|
23
|
+
ScopedNullifier,
|
|
24
|
+
ScopedReadRequest,
|
|
25
|
+
TransientDataIndexHint,
|
|
26
|
+
VK_TREE_HEIGHT,
|
|
27
|
+
buildNoteHashReadRequestHintsFromResetStates,
|
|
28
|
+
buildNullifierReadRequestHintsFromResetStates,
|
|
29
|
+
buildTransientDataHints,
|
|
30
|
+
countAccumulatedItems,
|
|
31
|
+
findPrivateKernelResetDimensions,
|
|
32
|
+
getNonEmptyItems,
|
|
33
|
+
getNoteHashReadRequestResetStates,
|
|
34
|
+
getNullifierReadRequestResetStates,
|
|
35
|
+
privateKernelResetDimensionNames,
|
|
36
|
+
} from '@aztec/circuits.js';
|
|
37
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
38
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
39
|
+
import { type Tuple, assertLength } from '@aztec/foundation/serialize';
|
|
40
|
+
import { privateKernelResetDimensionsConfig } from '@aztec/noir-protocol-circuits-types';
|
|
41
|
+
|
|
42
|
+
import { type ProvingDataOracle } from '../proving_data_oracle.js';
|
|
43
|
+
|
|
44
|
+
function collectNestedReadRequests(
|
|
45
|
+
executionStack: PrivateExecutionResult[],
|
|
46
|
+
extractReadRequests: (execution: PrivateExecutionResult) => ReadRequest[],
|
|
47
|
+
): ScopedReadRequest[] {
|
|
48
|
+
return collectNested(executionStack, executionResult => {
|
|
49
|
+
const nonEmptyReadRequests = getNonEmptyItems(extractReadRequests(executionResult));
|
|
50
|
+
return nonEmptyReadRequests.map(
|
|
51
|
+
readRequest =>
|
|
52
|
+
new ScopedReadRequest(
|
|
53
|
+
readRequest,
|
|
54
|
+
executionResult.callStackItem.publicInputs.callContext.storageContractAddress,
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getNullifierMembershipWitnessResolver(oracle: ProvingDataOracle) {
|
|
61
|
+
return async (nullifier: Fr) => {
|
|
62
|
+
const res = await oracle.getNullifierMembershipWitness(nullifier);
|
|
63
|
+
if (!res) {
|
|
64
|
+
throw new Error(`Cannot find the leaf for nullifier ${nullifier.toBigInt()}.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { index, siblingPath, leafPreimage } = res;
|
|
68
|
+
return {
|
|
69
|
+
membershipWitness: new MembershipWitness(NULLIFIER_TREE_HEIGHT, index, siblingPath.toTuple()),
|
|
70
|
+
leafPreimage,
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function getMasterSecretKeysAndAppKeyGenerators(
|
|
76
|
+
keyValidationRequests: Tuple<ScopedKeyValidationRequestAndGenerator, typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX>,
|
|
77
|
+
oracle: ProvingDataOracle,
|
|
78
|
+
) {
|
|
79
|
+
const keysHints = [];
|
|
80
|
+
for (let i = 0; i < keyValidationRequests.length; ++i) {
|
|
81
|
+
const request = keyValidationRequests[i].request;
|
|
82
|
+
if (request.isEmpty()) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
const secretKeys = await oracle.getMasterSecretKey(request.request.pkM);
|
|
86
|
+
keysHints.push(new KeyValidationHint(secretKeys, i));
|
|
87
|
+
}
|
|
88
|
+
return padArrayEnd(
|
|
89
|
+
keysHints,
|
|
90
|
+
KeyValidationHint.nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX),
|
|
91
|
+
MAX_KEY_VALIDATION_REQUESTS_PER_TX,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class PrivateKernelResetPrivateInputsBuilder {
|
|
96
|
+
private previousKernel: PrivateKernelCircuitPublicInputs;
|
|
97
|
+
// If there's no next iteration, it's the final reset.
|
|
98
|
+
private nextIteration?: PrivateCircuitPublicInputs;
|
|
99
|
+
|
|
100
|
+
private noteHashResetStates: ReadRequestResetStates<typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX>;
|
|
101
|
+
private nullifierResetStates: ReadRequestResetStates<typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>;
|
|
102
|
+
private numTransientData?: number;
|
|
103
|
+
private transientDataIndexHints: Tuple<TransientDataIndexHint, typeof MAX_NULLIFIERS_PER_TX>;
|
|
104
|
+
private requestedDimensions: PrivateKernelResetDimensions;
|
|
105
|
+
|
|
106
|
+
constructor(
|
|
107
|
+
private previousKernelOutput: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>,
|
|
108
|
+
private executionStack: PrivateExecutionResult[],
|
|
109
|
+
private noteHashNullifierCounterMap: Map<number, number>,
|
|
110
|
+
private validationRequestsSplitCounter: number,
|
|
111
|
+
) {
|
|
112
|
+
this.previousKernel = previousKernelOutput.publicInputs;
|
|
113
|
+
this.requestedDimensions = PrivateKernelResetDimensions.empty();
|
|
114
|
+
this.noteHashResetStates = ReadRequestResetStates.empty(MAX_NOTE_HASH_READ_REQUESTS_PER_TX);
|
|
115
|
+
this.nullifierResetStates = ReadRequestResetStates.empty(MAX_NULLIFIER_READ_REQUESTS_PER_TX);
|
|
116
|
+
this.transientDataIndexHints = makeTuple(
|
|
117
|
+
MAX_NULLIFIERS_PER_TX,
|
|
118
|
+
() => new TransientDataIndexHint(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX),
|
|
119
|
+
);
|
|
120
|
+
this.nextIteration = executionStack[this.executionStack.length - 1]?.callStackItem.publicInputs;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
needsReset(): boolean {
|
|
124
|
+
const fns: (() => boolean)[] = [
|
|
125
|
+
() => this.needsResetNoteHashReadRequests(),
|
|
126
|
+
() => this.needsResetNullifierReadRequests(),
|
|
127
|
+
() => this.needsResetNullifierKeys(),
|
|
128
|
+
() => this.needsResetTransientData(),
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
if (this.nextIteration) {
|
|
132
|
+
// If there's a next iteration, reset is needed only when data of a dimension is about to overflow.
|
|
133
|
+
// fns are executed until a dimension that needs reset is found.
|
|
134
|
+
return fns.some(fn => fn());
|
|
135
|
+
} else {
|
|
136
|
+
// Siloing is only needed after processing all iterations.
|
|
137
|
+
fns.push(
|
|
138
|
+
...[() => this.needsSiloNoteHashes(), () => this.needsSiloNullifiers(), () => this.needsSiloLogHashes()],
|
|
139
|
+
);
|
|
140
|
+
// If there's no next iteration, reset is needed when any of the dimension has non empty data.
|
|
141
|
+
// All the fns should to be executed so that data in all dimensions will be reset.
|
|
142
|
+
const result = fns.map(fn => fn());
|
|
143
|
+
return result.some(r => r);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async build(oracle: ProvingDataOracle, noteHashLeafIndexMap: Map<bigint, bigint>) {
|
|
148
|
+
if (privateKernelResetDimensionNames.every(name => !this.requestedDimensions[name])) {
|
|
149
|
+
throw new Error('Reset is not required.');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const isInner = !!this.nextIteration;
|
|
153
|
+
|
|
154
|
+
// "final" reset must be done at most once.
|
|
155
|
+
// Because the code that silo note hashes can't be run repeatedly.
|
|
156
|
+
// The dimensions found must be big enough to reset all values, i.e. empty remainder.
|
|
157
|
+
const allowRemainder = isInner;
|
|
158
|
+
|
|
159
|
+
const dimensions = findPrivateKernelResetDimensions(
|
|
160
|
+
this.requestedDimensions,
|
|
161
|
+
privateKernelResetDimensionsConfig,
|
|
162
|
+
isInner,
|
|
163
|
+
allowRemainder,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const previousVkMembershipWitness = await oracle.getVkMembershipWitness(this.previousKernelOutput.verificationKey);
|
|
167
|
+
const previousKernelData = new PrivateKernelData(
|
|
168
|
+
this.previousKernelOutput.publicInputs,
|
|
169
|
+
this.previousKernelOutput.verificationKey,
|
|
170
|
+
Number(previousVkMembershipWitness.leafIndex),
|
|
171
|
+
assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
this.reduceReadRequestStates(
|
|
175
|
+
this.noteHashResetStates,
|
|
176
|
+
dimensions.NOTE_HASH_PENDING_AMOUNT,
|
|
177
|
+
dimensions.NOTE_HASH_SETTLED_AMOUNT,
|
|
178
|
+
);
|
|
179
|
+
this.reduceReadRequestStates(
|
|
180
|
+
this.nullifierResetStates,
|
|
181
|
+
dimensions.NULLIFIER_PENDING_AMOUNT,
|
|
182
|
+
dimensions.NULLIFIER_SETTLED_AMOUNT,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
return new PrivateKernelResetCircuitPrivateInputs(
|
|
186
|
+
previousKernelData,
|
|
187
|
+
new PrivateKernelResetHints(
|
|
188
|
+
await buildNoteHashReadRequestHintsFromResetStates(
|
|
189
|
+
oracle,
|
|
190
|
+
this.previousKernel.validationRequests.noteHashReadRequests,
|
|
191
|
+
this.previousKernel.end.noteHashes,
|
|
192
|
+
this.noteHashResetStates,
|
|
193
|
+
noteHashLeafIndexMap,
|
|
194
|
+
),
|
|
195
|
+
await buildNullifierReadRequestHintsFromResetStates(
|
|
196
|
+
{ getNullifierMembershipWitness: getNullifierMembershipWitnessResolver(oracle) },
|
|
197
|
+
this.previousKernel.validationRequests.nullifierReadRequests,
|
|
198
|
+
this.nullifierResetStates,
|
|
199
|
+
),
|
|
200
|
+
await getMasterSecretKeysAndAppKeyGenerators(
|
|
201
|
+
this.previousKernel.validationRequests.scopedKeyValidationRequestsAndGenerators,
|
|
202
|
+
oracle,
|
|
203
|
+
),
|
|
204
|
+
this.transientDataIndexHints,
|
|
205
|
+
this.validationRequestsSplitCounter,
|
|
206
|
+
),
|
|
207
|
+
dimensions,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private reduceReadRequestStates<NUM_READS extends number>(
|
|
212
|
+
resetStates: ReadRequestResetStates<NUM_READS>,
|
|
213
|
+
maxPending: number,
|
|
214
|
+
maxSettled: number,
|
|
215
|
+
) {
|
|
216
|
+
let numPending = 0;
|
|
217
|
+
let numSettled = 0;
|
|
218
|
+
for (let i = 0; i < resetStates.states.length; i++) {
|
|
219
|
+
const state = resetStates.states[i];
|
|
220
|
+
if (state === ReadRequestState.PENDING) {
|
|
221
|
+
if (numPending < maxPending) {
|
|
222
|
+
numPending++;
|
|
223
|
+
} else {
|
|
224
|
+
resetStates.states[i] = ReadRequestState.NADA;
|
|
225
|
+
}
|
|
226
|
+
} else if (state === ReadRequestState.SETTLED) {
|
|
227
|
+
if (numSettled < maxSettled) {
|
|
228
|
+
numSettled++;
|
|
229
|
+
} else {
|
|
230
|
+
resetStates.states[i] = ReadRequestState.NADA;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
resetStates.pendingReadHints = resetStates.pendingReadHints.slice(0, maxPending);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private needsResetNoteHashReadRequests(forceResetAll = false) {
|
|
239
|
+
const numCurr = countAccumulatedItems(this.previousKernel.validationRequests.noteHashReadRequests);
|
|
240
|
+
const numNext = this.nextIteration ? countAccumulatedItems(this.nextIteration.noteHashReadRequests) : 0;
|
|
241
|
+
const maxAmountToKeep = !this.nextIteration || forceResetAll ? 0 : MAX_NOTE_HASH_READ_REQUESTS_PER_TX;
|
|
242
|
+
if (numCurr + numNext <= maxAmountToKeep) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const futureNoteHashes = collectNested(this.executionStack, executionResult => {
|
|
247
|
+
const nonEmptyNoteHashes = getNonEmptyItems(executionResult.callStackItem.publicInputs.noteHashes);
|
|
248
|
+
return nonEmptyNoteHashes.map(
|
|
249
|
+
noteHash =>
|
|
250
|
+
new ScopedNoteHash(noteHash, executionResult.callStackItem.publicInputs.callContext.storageContractAddress),
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const resetStates = getNoteHashReadRequestResetStates(
|
|
255
|
+
this.previousKernel.validationRequests.noteHashReadRequests,
|
|
256
|
+
this.previousKernel.end.noteHashes,
|
|
257
|
+
futureNoteHashes,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const numPendingReads = resetStates.pendingReadHints.length;
|
|
261
|
+
const numSettledReads = resetStates.states.reduce(
|
|
262
|
+
(accum, state) => accum + (state === ReadRequestState.SETTLED ? 1 : 0),
|
|
263
|
+
0,
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
if (!this.nextIteration) {
|
|
267
|
+
this.noteHashResetStates = resetStates;
|
|
268
|
+
this.requestedDimensions.NOTE_HASH_PENDING_AMOUNT = numPendingReads;
|
|
269
|
+
this.requestedDimensions.NOTE_HASH_SETTLED_AMOUNT = numSettledReads;
|
|
270
|
+
} else {
|
|
271
|
+
// Pick only one dimension to reset if next iteration is not empty.
|
|
272
|
+
if (numPendingReads > numSettledReads) {
|
|
273
|
+
this.requestedDimensions.NOTE_HASH_PENDING_AMOUNT = numPendingReads;
|
|
274
|
+
this.noteHashResetStates.states = assertLength(
|
|
275
|
+
resetStates.states.map(state => (state === ReadRequestState.PENDING ? state : ReadRequestState.NADA)),
|
|
276
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
|
|
277
|
+
);
|
|
278
|
+
this.noteHashResetStates.pendingReadHints = resetStates.pendingReadHints;
|
|
279
|
+
} else {
|
|
280
|
+
this.requestedDimensions.NOTE_HASH_SETTLED_AMOUNT = numSettledReads;
|
|
281
|
+
this.noteHashResetStates.states = assertLength(
|
|
282
|
+
resetStates.states.map(state => (state === ReadRequestState.SETTLED ? state : ReadRequestState.NADA)),
|
|
283
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private needsResetNullifierReadRequests(forceResetAll = false) {
|
|
292
|
+
const numCurr = countAccumulatedItems(this.previousKernel.validationRequests.nullifierReadRequests);
|
|
293
|
+
const numNext = this.nextIteration ? countAccumulatedItems(this.nextIteration.nullifierReadRequests) : 0;
|
|
294
|
+
const maxAmountToKeep = !this.nextIteration || forceResetAll ? 0 : MAX_NULLIFIER_READ_REQUESTS_PER_TX;
|
|
295
|
+
if (numCurr + numNext <= maxAmountToKeep) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const futureNullifiers = collectNested(this.executionStack, executionResult => {
|
|
300
|
+
const nonEmptyNullifiers = getNonEmptyItems(executionResult.callStackItem.publicInputs.nullifiers);
|
|
301
|
+
return nonEmptyNullifiers.map(
|
|
302
|
+
nullifier =>
|
|
303
|
+
new ScopedNullifier(nullifier, executionResult.callStackItem.publicInputs.callContext.storageContractAddress),
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const resetStates = getNullifierReadRequestResetStates(
|
|
308
|
+
this.previousKernel.validationRequests.nullifierReadRequests,
|
|
309
|
+
this.previousKernel.end.nullifiers,
|
|
310
|
+
futureNullifiers,
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
const numPendingReads = resetStates.pendingReadHints.length;
|
|
314
|
+
const numSettledReads = resetStates.states.reduce(
|
|
315
|
+
(accum, state) => accum + (state === ReadRequestState.SETTLED ? 1 : 0),
|
|
316
|
+
0,
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
if (!this.nextIteration) {
|
|
320
|
+
this.nullifierResetStates = resetStates;
|
|
321
|
+
this.requestedDimensions.NULLIFIER_PENDING_AMOUNT = numPendingReads;
|
|
322
|
+
this.requestedDimensions.NULLIFIER_SETTLED_AMOUNT = numSettledReads;
|
|
323
|
+
} else {
|
|
324
|
+
// Pick only one dimension to reset if next iteration is not empty.
|
|
325
|
+
if (numPendingReads > numSettledReads) {
|
|
326
|
+
this.requestedDimensions.NULLIFIER_PENDING_AMOUNT = numPendingReads;
|
|
327
|
+
this.nullifierResetStates.states = assertLength(
|
|
328
|
+
resetStates.states.map(state => (state === ReadRequestState.PENDING ? state : ReadRequestState.NADA)),
|
|
329
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
330
|
+
);
|
|
331
|
+
this.nullifierResetStates.pendingReadHints = resetStates.pendingReadHints;
|
|
332
|
+
} else {
|
|
333
|
+
this.requestedDimensions.NULLIFIER_SETTLED_AMOUNT = numSettledReads;
|
|
334
|
+
this.nullifierResetStates.states = assertLength(
|
|
335
|
+
resetStates.states.map(state => (state === ReadRequestState.SETTLED ? state : ReadRequestState.NADA)),
|
|
336
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private needsResetNullifierKeys() {
|
|
345
|
+
const numCurr = countAccumulatedItems(
|
|
346
|
+
this.previousKernel.validationRequests.scopedKeyValidationRequestsAndGenerators,
|
|
347
|
+
);
|
|
348
|
+
const numNext = this.nextIteration
|
|
349
|
+
? countAccumulatedItems(this.nextIteration.keyValidationRequestsAndGenerators)
|
|
350
|
+
: 0;
|
|
351
|
+
const maxAmountToKeep = !this.nextIteration ? 0 : MAX_KEY_VALIDATION_REQUESTS_PER_TX;
|
|
352
|
+
if (numCurr + numNext <= maxAmountToKeep) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
this.requestedDimensions.NULLIFIER_KEYS = numCurr;
|
|
357
|
+
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
private needsResetTransientData() {
|
|
362
|
+
// Initialize this to 0 so that needsSilo can be run.
|
|
363
|
+
this.numTransientData = 0;
|
|
364
|
+
|
|
365
|
+
const nextAccumNoteHashes =
|
|
366
|
+
countAccumulatedItems(this.previousKernel.end.noteHashes) +
|
|
367
|
+
countAccumulatedItems(this.nextIteration?.noteHashes ?? []);
|
|
368
|
+
const noteHashWillOverflow = nextAccumNoteHashes > MAX_NOTE_HASHES_PER_TX;
|
|
369
|
+
const nextAccumNullifiers =
|
|
370
|
+
countAccumulatedItems(this.previousKernel.end.nullifiers) +
|
|
371
|
+
countAccumulatedItems(this.nextIteration?.nullifiers ?? []);
|
|
372
|
+
const nullifierWillOverflow = nextAccumNullifiers > MAX_NULLIFIERS_PER_TX;
|
|
373
|
+
if (this.nextIteration && !noteHashWillOverflow && !nullifierWillOverflow) {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const futureNoteHashReads = collectNestedReadRequests(
|
|
378
|
+
this.executionStack,
|
|
379
|
+
executionResult => executionResult.callStackItem.publicInputs.noteHashReadRequests,
|
|
380
|
+
);
|
|
381
|
+
const futureNullifierReads = collectNestedReadRequests(
|
|
382
|
+
this.executionStack,
|
|
383
|
+
executionResult => executionResult.callStackItem.publicInputs.nullifierReadRequests,
|
|
384
|
+
);
|
|
385
|
+
if (this.nextIteration) {
|
|
386
|
+
// If it's not the final reset, only one dimension will be reset at a time.
|
|
387
|
+
// The note hashes and nullifiers for the remaining read requests can't be squashed.
|
|
388
|
+
futureNoteHashReads.push(
|
|
389
|
+
...this.previousKernel.validationRequests.noteHashReadRequests.filter(r => !r.isEmpty()),
|
|
390
|
+
);
|
|
391
|
+
futureNullifierReads.push(
|
|
392
|
+
...this.previousKernel.validationRequests.nullifierReadRequests.filter(r => !r.isEmpty()),
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const { numTransientData, hints: transientDataIndexHints } = buildTransientDataHints(
|
|
397
|
+
this.previousKernel.end.noteHashes,
|
|
398
|
+
this.previousKernel.end.nullifiers,
|
|
399
|
+
futureNoteHashReads,
|
|
400
|
+
futureNullifierReads,
|
|
401
|
+
this.noteHashNullifierCounterMap,
|
|
402
|
+
this.validationRequestsSplitCounter,
|
|
403
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
404
|
+
MAX_NULLIFIERS_PER_TX,
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
if (this.nextIteration && !numTransientData) {
|
|
408
|
+
const forceResetAll = true;
|
|
409
|
+
const canClearReadRequests =
|
|
410
|
+
(noteHashWillOverflow && this.needsResetNoteHashReadRequests(forceResetAll)) ||
|
|
411
|
+
(nullifierWillOverflow && this.needsResetNullifierReadRequests(forceResetAll));
|
|
412
|
+
if (!canClearReadRequests) {
|
|
413
|
+
const overflownData = noteHashWillOverflow ? 'note hashes' : 'nullifiers';
|
|
414
|
+
throw new Error(`Number of ${overflownData} exceeds the limit.`);
|
|
415
|
+
}
|
|
416
|
+
// Clearing the read requests might not be enough to squash the overflown data.
|
|
417
|
+
// In this case, the next iteration will fail at the above check.
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
this.numTransientData = numTransientData;
|
|
422
|
+
this.transientDataIndexHints = transientDataIndexHints;
|
|
423
|
+
this.requestedDimensions.TRANSIENT_DATA_AMOUNT = numTransientData;
|
|
424
|
+
|
|
425
|
+
return numTransientData > 0;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private needsSiloNoteHashes() {
|
|
429
|
+
if (this.numTransientData === undefined) {
|
|
430
|
+
throw new Error('`needsResetTransientData` must be run before `needsSiloNoteHashes`.');
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const numNoteHashes = this.previousKernel.end.noteHashes.filter(n => !n.contractAddress.isEmpty()).length;
|
|
434
|
+
const numToSilo = Math.max(0, numNoteHashes - this.numTransientData);
|
|
435
|
+
this.requestedDimensions.NOTE_HASH_SILOING_AMOUNT = numToSilo;
|
|
436
|
+
|
|
437
|
+
return numToSilo > 0;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private needsSiloNullifiers() {
|
|
441
|
+
if (this.numTransientData === undefined) {
|
|
442
|
+
throw new Error('`needsResetTransientData` must be run before `needsSiloNullifiers`.');
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const numNullifiers = this.previousKernel.end.nullifiers.filter(n => !n.contractAddress.isEmpty()).length;
|
|
446
|
+
const numToSilo = Math.max(0, numNullifiers - this.numTransientData);
|
|
447
|
+
// Include the first nullifier if there's something to silo.
|
|
448
|
+
// The reset circuit checks that capped_size must be greater than or equal to all non-empty nullifiers.
|
|
449
|
+
// Which includes the first nullifier, even though its contract address is always zero and doesn't need siloing.
|
|
450
|
+
const cappedSize = numToSilo ? numToSilo + 1 : 0;
|
|
451
|
+
this.requestedDimensions.NULLIFIER_SILOING_AMOUNT = cappedSize;
|
|
452
|
+
|
|
453
|
+
return numToSilo > 0;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private needsSiloLogHashes() {
|
|
457
|
+
if (this.numTransientData === undefined) {
|
|
458
|
+
throw new Error('`needsResetTransientData` must be run before `needsSiloLogHashes`.');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const numLogs = this.previousKernel.end.encryptedLogsHashes.filter(l => !l.logHash.randomness.isZero()).length;
|
|
462
|
+
const numToSilo = Math.max(0, numLogs - this.numTransientData);
|
|
463
|
+
this.requestedDimensions.ENCRYPTED_LOG_SILOING_AMOUNT = numToSilo;
|
|
464
|
+
|
|
465
|
+
return numToSilo > 0;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './needs_reset.js';
|
|
1
|
+
export * from './build_private_kernel_reset_private_inputs.js';
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type PrivateExecutionResult,
|
|
3
|
+
type PrivateKernelProver,
|
|
4
|
+
type PrivateKernelSimulateOutput,
|
|
5
|
+
collectEnqueuedPublicFunctionCalls,
|
|
6
|
+
collectNoteHashLeafIndexMap,
|
|
7
|
+
collectNoteHashNullifierCounterMap,
|
|
8
|
+
collectPublicTeardownFunctionCall,
|
|
9
|
+
getFinalMinRevertibleSideEffectCounter,
|
|
10
|
+
} from '@aztec/circuit-types';
|
|
2
11
|
import {
|
|
3
12
|
Fr,
|
|
4
13
|
PrivateCallData,
|
|
@@ -15,29 +24,18 @@ import {
|
|
|
15
24
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
16
25
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
17
26
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
18
|
-
import {
|
|
19
|
-
ClientCircuitArtifacts,
|
|
20
|
-
PrivateResetTagToArtifactName,
|
|
21
|
-
getVKTreeRoot,
|
|
22
|
-
} from '@aztec/noir-protocol-circuits-types';
|
|
23
|
-
import {
|
|
24
|
-
type ExecutionResult,
|
|
25
|
-
collectEnqueuedPublicFunctionCalls,
|
|
26
|
-
collectNoteHashLeafIndexMap,
|
|
27
|
-
collectNoteHashNullifierCounterMap,
|
|
28
|
-
collectPublicTeardownFunctionCall,
|
|
29
|
-
getFinalMinRevertibleSideEffectCounter,
|
|
30
|
-
} from '@aztec/simulator';
|
|
27
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
|
|
31
28
|
|
|
32
29
|
import { type WitnessMap } from '@noir-lang/types';
|
|
33
30
|
|
|
34
|
-
import {
|
|
31
|
+
import { PrivateKernelResetPrivateInputsBuilder } from './hints/build_private_kernel_reset_private_inputs.js';
|
|
35
32
|
import { type ProvingDataOracle } from './proving_data_oracle.js';
|
|
36
33
|
|
|
37
34
|
const NULL_PROVE_OUTPUT: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs> = {
|
|
38
35
|
publicInputs: PrivateKernelCircuitPublicInputs.empty(),
|
|
39
36
|
verificationKey: VerificationKeyAsFields.makeEmpty(),
|
|
40
37
|
outputWitness: new Map(),
|
|
38
|
+
bytecode: Buffer.from([]),
|
|
41
39
|
};
|
|
42
40
|
/**
|
|
43
41
|
* The KernelProver class is responsible for generating kernel proofs.
|
|
@@ -63,7 +61,7 @@ export class KernelProver {
|
|
|
63
61
|
*/
|
|
64
62
|
async prove(
|
|
65
63
|
txRequest: TxRequest,
|
|
66
|
-
executionResult:
|
|
64
|
+
executionResult: PrivateExecutionResult,
|
|
67
65
|
): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>> {
|
|
68
66
|
const executionStack = [executionResult];
|
|
69
67
|
let firstIteration = true;
|
|
@@ -81,22 +79,29 @@ export class KernelProver {
|
|
|
81
79
|
const witnessStack: WitnessMap[] = [];
|
|
82
80
|
|
|
83
81
|
while (executionStack.length) {
|
|
84
|
-
if (!firstIteration
|
|
85
|
-
|
|
86
|
-
executionStack,
|
|
82
|
+
if (!firstIteration) {
|
|
83
|
+
let resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
87
84
|
output,
|
|
88
|
-
|
|
85
|
+
executionStack,
|
|
89
86
|
noteHashNullifierCounterMap,
|
|
90
87
|
validationRequestsSplitCounter,
|
|
91
|
-
false,
|
|
92
88
|
);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
while (resetBuilder.needsReset()) {
|
|
90
|
+
const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
|
|
91
|
+
output = await this.proofCreator.simulateProofReset(privateInputs);
|
|
92
|
+
// TODO(#7368) consider refactoring this redundant bytecode pushing
|
|
93
|
+
acirs.push(output.bytecode);
|
|
94
|
+
witnessStack.push(output.outputWitness);
|
|
95
|
+
|
|
96
|
+
resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
97
|
+
output,
|
|
98
|
+
executionStack,
|
|
99
|
+
noteHashNullifierCounterMap,
|
|
100
|
+
validationRequestsSplitCounter,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
99
103
|
}
|
|
104
|
+
|
|
100
105
|
const currentExecution = executionStack.pop()!;
|
|
101
106
|
executionStack.push(...[...currentExecution.nestedExecutions].reverse());
|
|
102
107
|
|
|
@@ -117,7 +122,7 @@ export class KernelProver {
|
|
|
117
122
|
const proofInput = new PrivateKernelInitCircuitPrivateInputs(txRequest, getVKTreeRoot(), privateCallData);
|
|
118
123
|
pushTestData('private-kernel-inputs-init', proofInput);
|
|
119
124
|
output = await this.proofCreator.simulateProofInit(proofInput);
|
|
120
|
-
acirs.push(
|
|
125
|
+
acirs.push(output.bytecode);
|
|
121
126
|
witnessStack.push(output.outputWitness);
|
|
122
127
|
} else {
|
|
123
128
|
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
|
|
@@ -130,28 +135,34 @@ export class KernelProver {
|
|
|
130
135
|
const proofInput = new PrivateKernelInnerCircuitPrivateInputs(previousKernelData, privateCallData);
|
|
131
136
|
pushTestData('private-kernel-inputs-inner', proofInput);
|
|
132
137
|
output = await this.proofCreator.simulateProofInner(proofInput);
|
|
133
|
-
acirs.push(
|
|
138
|
+
acirs.push(output.bytecode);
|
|
134
139
|
witnessStack.push(output.outputWitness);
|
|
135
140
|
}
|
|
136
141
|
firstIteration = false;
|
|
137
142
|
}
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
// Reset.
|
|
145
|
+
let resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
146
|
+
output,
|
|
147
|
+
[],
|
|
148
|
+
noteHashNullifierCounterMap,
|
|
149
|
+
validationRequestsSplitCounter,
|
|
150
|
+
);
|
|
151
|
+
while (resetBuilder.needsReset()) {
|
|
152
|
+
const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
|
|
153
|
+
output = await this.proofCreator.simulateProofReset(privateInputs);
|
|
154
|
+
acirs.push(output.bytecode);
|
|
155
|
+
witnessStack.push(output.outputWitness);
|
|
156
|
+
|
|
157
|
+
resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
142
158
|
output,
|
|
143
|
-
|
|
159
|
+
[],
|
|
144
160
|
noteHashNullifierCounterMap,
|
|
145
161
|
validationRequestsSplitCounter,
|
|
146
|
-
true,
|
|
147
162
|
);
|
|
148
|
-
output = await this.proofCreator.simulateProofReset(resetInputs);
|
|
149
|
-
// TODO(#7368) consider refactoring this redundant bytecode pushing
|
|
150
|
-
acirs.push(
|
|
151
|
-
Buffer.from(ClientCircuitArtifacts[PrivateResetTagToArtifactName[resetInputs.sizeTag]].bytecode, 'base64'),
|
|
152
|
-
);
|
|
153
|
-
witnessStack.push(output.outputWitness);
|
|
154
163
|
}
|
|
164
|
+
|
|
165
|
+
// Private tail.
|
|
155
166
|
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
|
|
156
167
|
const previousKernelData = new PrivateKernelData(
|
|
157
168
|
output.publicInputs,
|
|
@@ -168,14 +179,7 @@ export class KernelProver {
|
|
|
168
179
|
|
|
169
180
|
pushTestData('private-kernel-inputs-ordering', privateInputs);
|
|
170
181
|
const tailOutput = await this.proofCreator.simulateProofTail(privateInputs);
|
|
171
|
-
acirs.push(
|
|
172
|
-
Buffer.from(
|
|
173
|
-
privateInputs.isForPublic()
|
|
174
|
-
? ClientCircuitArtifacts.PrivateKernelTailToPublicArtifact.bytecode
|
|
175
|
-
: ClientCircuitArtifacts.PrivateKernelTailArtifact.bytecode,
|
|
176
|
-
'base64',
|
|
177
|
-
),
|
|
178
|
-
);
|
|
182
|
+
acirs.push(tailOutput.bytecode);
|
|
179
183
|
witnessStack.push(tailOutput.outputWitness);
|
|
180
184
|
|
|
181
185
|
// TODO(#7368) how do we 'bincode' encode these inputs?
|
|
@@ -184,34 +188,7 @@ export class KernelProver {
|
|
|
184
188
|
return tailOutput;
|
|
185
189
|
}
|
|
186
190
|
|
|
187
|
-
private async
|
|
188
|
-
executionStack: ExecutionResult[],
|
|
189
|
-
output: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>,
|
|
190
|
-
noteHashLeafIndexMap: Map<bigint, bigint>,
|
|
191
|
-
noteHashNullifierCounterMap: Map<number, number>,
|
|
192
|
-
validationRequestsSplitCounter: number,
|
|
193
|
-
shouldSilo: boolean,
|
|
194
|
-
) {
|
|
195
|
-
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
|
|
196
|
-
const previousKernelData = new PrivateKernelData(
|
|
197
|
-
output.publicInputs,
|
|
198
|
-
output.verificationKey,
|
|
199
|
-
Number(previousVkMembershipWitness.leafIndex),
|
|
200
|
-
assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
return await buildPrivateKernelResetInputs(
|
|
204
|
-
executionStack,
|
|
205
|
-
previousKernelData,
|
|
206
|
-
noteHashLeafIndexMap,
|
|
207
|
-
noteHashNullifierCounterMap,
|
|
208
|
-
validationRequestsSplitCounter,
|
|
209
|
-
shouldSilo,
|
|
210
|
-
this.oracle,
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
private async createPrivateCallData({ callStackItem }: ExecutionResult, vk: VerificationKeyAsFields) {
|
|
191
|
+
private async createPrivateCallData({ callStackItem }: PrivateExecutionResult, vk: VerificationKeyAsFields) {
|
|
215
192
|
const { contractAddress, functionData } = callStackItem;
|
|
216
193
|
|
|
217
194
|
const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness(
|