@aztec/pxe 0.22.0 → 0.24.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/database/deferred_note_dao.d.ts +4 -0
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +6 -3
- package/dest/database/note_dao.d.ts +4 -0
- package/dest/database/note_dao.d.ts.map +1 -1
- package/dest/database/note_dao.js +7 -2
- package/dest/database/pxe_database_test_suite.js +2 -2
- package/dest/kernel_prover/kernel_prover.js +9 -9
- package/dest/kernel_prover/proof_creator.d.ts +10 -10
- package/dest/kernel_prover/proof_creator.d.ts.map +1 -1
- package/dest/kernel_prover/proof_creator.js +4 -4
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +4 -4
- package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
- package/dest/note_processor/produce_note_dao.js +4 -4
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +8 -4
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +5 -5
- package/package.json +13 -12
- package/src/bin/index.ts +42 -0
- package/src/config/index.ts +40 -0
- package/src/contract_data_oracle/index.ts +185 -0
- package/src/contract_data_oracle/private_functions_tree.ts +127 -0
- package/src/contract_database/index.ts +1 -0
- package/src/contract_database/memory_contract_database.ts +58 -0
- package/src/database/contracts/contract_artifact_db.ts +19 -0
- package/src/database/contracts/contract_instance_db.ts +18 -0
- package/src/database/deferred_note_dao.ts +55 -0
- package/src/database/index.ts +1 -0
- package/src/database/kv_pxe_database.ts +409 -0
- package/src/database/note_dao.ts +97 -0
- package/src/database/pxe_database.ts +162 -0
- package/src/database/pxe_database_test_suite.ts +258 -0
- package/src/index.ts +11 -0
- package/src/kernel_oracle/index.ts +61 -0
- package/src/kernel_prover/index.ts +2 -0
- package/src/kernel_prover/kernel_prover.ts +388 -0
- package/src/kernel_prover/proof_creator.ts +157 -0
- package/src/kernel_prover/proving_data_oracle.ts +76 -0
- package/src/note_processor/index.ts +1 -0
- package/src/note_processor/note_processor.ts +282 -0
- package/src/note_processor/produce_note_dao.ts +132 -0
- package/src/pxe_http/index.ts +1 -0
- package/src/pxe_http/pxe_http_server.ts +73 -0
- package/src/pxe_service/create_pxe_service.ts +52 -0
- package/src/pxe_service/index.ts +3 -0
- package/src/pxe_service/pxe_service.ts +756 -0
- package/src/pxe_service/test/pxe_test_suite.ts +138 -0
- package/src/simulator/index.ts +24 -0
- package/src/simulator_oracle/index.ts +210 -0
- package/src/synchronizer/index.ts +1 -0
- package/src/synchronizer/synchronizer.ts +427 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AztecAddress,
|
|
3
|
+
CallRequest,
|
|
4
|
+
Fr,
|
|
5
|
+
GrumpkinScalar,
|
|
6
|
+
MAX_NEW_COMMITMENTS_PER_TX,
|
|
7
|
+
MAX_NEW_NULLIFIERS_PER_TX,
|
|
8
|
+
MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX,
|
|
9
|
+
MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,
|
|
10
|
+
MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
|
|
11
|
+
MAX_READ_REQUESTS_PER_CALL,
|
|
12
|
+
MAX_READ_REQUESTS_PER_TX,
|
|
13
|
+
NullifierKeyValidationRequestContext,
|
|
14
|
+
PrivateCallData,
|
|
15
|
+
PrivateKernelInitCircuitPrivateInputs,
|
|
16
|
+
PrivateKernelInnerCircuitPrivateInputs,
|
|
17
|
+
PrivateKernelInnerCircuitPublicInputs,
|
|
18
|
+
PrivateKernelInnerData,
|
|
19
|
+
PrivateKernelTailCircuitPrivateInputs,
|
|
20
|
+
ReadRequestMembershipWitness,
|
|
21
|
+
SideEffect,
|
|
22
|
+
SideEffectLinkedToNoteHash,
|
|
23
|
+
SideEffectType,
|
|
24
|
+
TxRequest,
|
|
25
|
+
VK_TREE_HEIGHT,
|
|
26
|
+
VerificationKey,
|
|
27
|
+
makeEmptyProof,
|
|
28
|
+
} from '@aztec/circuits.js';
|
|
29
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
30
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
31
|
+
import { Tuple, assertLength, mapTuple } from '@aztec/foundation/serialize';
|
|
32
|
+
import { pushTestData } from '@aztec/foundation/testing';
|
|
33
|
+
import { ExecutionResult, NoteAndSlot } from '@aztec/simulator';
|
|
34
|
+
|
|
35
|
+
import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js';
|
|
36
|
+
import { ProvingDataOracle } from './proving_data_oracle.js';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Represents an output note data object.
|
|
40
|
+
* Contains the contract address, new note data and commitment for the note,
|
|
41
|
+
* resulting from the execution of a transaction in the Aztec network.
|
|
42
|
+
*/
|
|
43
|
+
export interface OutputNoteData {
|
|
44
|
+
/**
|
|
45
|
+
* The address of the contract the note was created in.
|
|
46
|
+
*/
|
|
47
|
+
contractAddress: AztecAddress;
|
|
48
|
+
/**
|
|
49
|
+
* The encrypted note data for an output note.
|
|
50
|
+
*/
|
|
51
|
+
data: NoteAndSlot;
|
|
52
|
+
/**
|
|
53
|
+
* The unique value representing the note.
|
|
54
|
+
*/
|
|
55
|
+
commitment: Fr;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Represents the output data of the Kernel Prover.
|
|
60
|
+
* Provides information about the newly created notes, along with the public inputs and proof.
|
|
61
|
+
*/
|
|
62
|
+
export interface KernelProverOutput extends ProofOutputFinal {
|
|
63
|
+
/**
|
|
64
|
+
* An array of output notes containing the contract address, note data, and commitment for each new note.
|
|
65
|
+
*/
|
|
66
|
+
outputNotes: OutputNoteData[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The KernelProver class is responsible for generating kernel proofs.
|
|
71
|
+
* It takes a transaction request, its signature, and the simulation result as inputs, and outputs a proof
|
|
72
|
+
* along with output notes. The class interacts with a ProvingDataOracle to fetch membership witnesses and
|
|
73
|
+
* constructs private call data based on the execution results.
|
|
74
|
+
*/
|
|
75
|
+
export class KernelProver {
|
|
76
|
+
constructor(private oracle: ProvingDataOracle, private proofCreator: ProofCreator = new KernelProofCreator()) {}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Generate a proof for a given transaction request and execution result.
|
|
80
|
+
* The function iterates through the nested executions in the execution result, creates private call data,
|
|
81
|
+
* and generates a proof using the provided ProofCreator instance. It also maintains an index of new notes
|
|
82
|
+
* created during the execution and returns them as a part of the KernelProverOutput.
|
|
83
|
+
*
|
|
84
|
+
* @param txRequest - The authenticated transaction request object.
|
|
85
|
+
* @param executionResult - The execution result object containing nested executions and preimages.
|
|
86
|
+
* @returns A Promise that resolves to a KernelProverOutput object containing proof, public inputs, and output notes.
|
|
87
|
+
*/
|
|
88
|
+
async prove(txRequest: TxRequest, executionResult: ExecutionResult): Promise<KernelProverOutput> {
|
|
89
|
+
const executionStack = [executionResult];
|
|
90
|
+
const newNotes: { [commitmentStr: string]: OutputNoteData } = {};
|
|
91
|
+
let firstIteration = true;
|
|
92
|
+
let previousVerificationKey = VerificationKey.makeFake();
|
|
93
|
+
|
|
94
|
+
let output: ProofOutput = {
|
|
95
|
+
publicInputs: PrivateKernelInnerCircuitPublicInputs.empty(),
|
|
96
|
+
proof: makeEmptyProof(),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
while (executionStack.length) {
|
|
100
|
+
const currentExecution = executionStack.pop()!;
|
|
101
|
+
executionStack.push(...currentExecution.nestedExecutions);
|
|
102
|
+
|
|
103
|
+
const privateCallRequests = currentExecution.nestedExecutions.map(result => result.callStackItem.toCallRequest());
|
|
104
|
+
const publicCallRequests = currentExecution.enqueuedPublicFunctionCalls.map(result => result.toCallRequest());
|
|
105
|
+
|
|
106
|
+
// Start with the partially filled in read request witnesses from the simulator
|
|
107
|
+
// and fill the non-transient ones in with sibling paths via oracle.
|
|
108
|
+
const readRequestMembershipWitnesses = currentExecution.readRequestPartialWitnesses;
|
|
109
|
+
for (let rr = 0; rr < readRequestMembershipWitnesses.length; rr++) {
|
|
110
|
+
// Pretty sure this check was forever broken. I made some changes to Fr and this started triggering.
|
|
111
|
+
// The conditional makes no sense to me anyway.
|
|
112
|
+
// if (currentExecution.callStackItem.publicInputs.readRequests[rr] == Fr.ZERO) {
|
|
113
|
+
// throw new Error(
|
|
114
|
+
// 'Number of read requests output from Noir circuit does not match number of read request commitment indices output from simulator.',
|
|
115
|
+
// );
|
|
116
|
+
// }
|
|
117
|
+
const rrWitness = readRequestMembershipWitnesses[rr];
|
|
118
|
+
if (!rrWitness.isTransient) {
|
|
119
|
+
// Non-transient reads must contain full membership witness with sibling path from commitment to root.
|
|
120
|
+
// Get regular membership witness to fill in sibling path in the read request witness.
|
|
121
|
+
const membershipWitness = await this.oracle.getNoteMembershipWitness(rrWitness.leafIndex.toBigInt());
|
|
122
|
+
rrWitness.siblingPath = membershipWitness.siblingPath;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// fill in witnesses for remaining/empty read requests
|
|
127
|
+
readRequestMembershipWitnesses.push(
|
|
128
|
+
...Array(MAX_READ_REQUESTS_PER_CALL - readRequestMembershipWitnesses.length)
|
|
129
|
+
.fill(0)
|
|
130
|
+
.map(() => ReadRequestMembershipWitness.empty(BigInt(0))),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const privateCallData = await this.createPrivateCallData(
|
|
134
|
+
currentExecution,
|
|
135
|
+
privateCallRequests,
|
|
136
|
+
publicCallRequests,
|
|
137
|
+
readRequestMembershipWitnesses,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (firstIteration) {
|
|
141
|
+
const proofInput = new PrivateKernelInitCircuitPrivateInputs(txRequest, privateCallData);
|
|
142
|
+
pushTestData('private-kernel-inputs-init', proofInput);
|
|
143
|
+
output = await this.proofCreator.createProofInit(proofInput);
|
|
144
|
+
} else {
|
|
145
|
+
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey);
|
|
146
|
+
const previousKernelData = new PrivateKernelInnerData(
|
|
147
|
+
output.publicInputs,
|
|
148
|
+
output.proof,
|
|
149
|
+
previousVerificationKey,
|
|
150
|
+
Number(previousVkMembershipWitness.leafIndex),
|
|
151
|
+
assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
|
|
152
|
+
);
|
|
153
|
+
const proofInput = new PrivateKernelInnerCircuitPrivateInputs(previousKernelData, privateCallData);
|
|
154
|
+
pushTestData('private-kernel-inputs-inner', proofInput);
|
|
155
|
+
output = await this.proofCreator.createProofInner(proofInput);
|
|
156
|
+
}
|
|
157
|
+
(await this.getNewNotes(currentExecution)).forEach(n => {
|
|
158
|
+
newNotes[n.commitment.toString()] = n;
|
|
159
|
+
});
|
|
160
|
+
firstIteration = false;
|
|
161
|
+
previousVerificationKey = privateCallData.vk;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey);
|
|
165
|
+
const previousKernelData = new PrivateKernelInnerData(
|
|
166
|
+
output.publicInputs,
|
|
167
|
+
output.proof,
|
|
168
|
+
previousVerificationKey,
|
|
169
|
+
Number(previousVkMembershipWitness.leafIndex),
|
|
170
|
+
assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const [sortedCommitments, sortedCommitmentsIndexes] = this.sortSideEffects<
|
|
174
|
+
SideEffect,
|
|
175
|
+
typeof MAX_NEW_COMMITMENTS_PER_TX
|
|
176
|
+
>(output.publicInputs.end.newCommitments);
|
|
177
|
+
|
|
178
|
+
const [sortedNullifiers, sortedNullifiersIndexes] = this.sortSideEffects<
|
|
179
|
+
SideEffectLinkedToNoteHash,
|
|
180
|
+
typeof MAX_NEW_NULLIFIERS_PER_TX
|
|
181
|
+
>(output.publicInputs.end.newNullifiers);
|
|
182
|
+
|
|
183
|
+
const readCommitmentHints = this.getReadRequestHints(output.publicInputs.end.readRequests, sortedCommitments);
|
|
184
|
+
|
|
185
|
+
const nullifierCommitmentHints = this.getNullifierHints(
|
|
186
|
+
mapTuple(sortedNullifiers, n => n.noteHash),
|
|
187
|
+
sortedCommitments,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const masterNullifierSecretKeys = await this.getMasterNullifierSecretKeys(
|
|
191
|
+
output.publicInputs.end.nullifierKeyValidationRequests,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const privateInputs = new PrivateKernelTailCircuitPrivateInputs(
|
|
195
|
+
previousKernelData,
|
|
196
|
+
sortedCommitments,
|
|
197
|
+
sortedCommitmentsIndexes,
|
|
198
|
+
readCommitmentHints,
|
|
199
|
+
sortedNullifiers,
|
|
200
|
+
sortedNullifiersIndexes,
|
|
201
|
+
nullifierCommitmentHints,
|
|
202
|
+
masterNullifierSecretKeys,
|
|
203
|
+
);
|
|
204
|
+
pushTestData('private-kernel-inputs-ordering', privateInputs);
|
|
205
|
+
const outputFinal = await this.proofCreator.createProofTail(privateInputs);
|
|
206
|
+
|
|
207
|
+
// Only return the notes whose commitment is in the commitments of the final proof.
|
|
208
|
+
const finalNewCommitments = outputFinal.publicInputs.end.newCommitments;
|
|
209
|
+
const outputNotes = finalNewCommitments.map(c => newNotes[c.value.toString()]).filter(c => !!c);
|
|
210
|
+
|
|
211
|
+
return { ...outputFinal, outputNotes };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private sortSideEffects<T extends SideEffectType, K extends number>(
|
|
215
|
+
sideEffects: Tuple<T, K>,
|
|
216
|
+
): [Tuple<T, K>, Tuple<number, K>] {
|
|
217
|
+
const sorted = sideEffects
|
|
218
|
+
.map((sideEffect, index) => ({ sideEffect, index }))
|
|
219
|
+
.sort((a, b) => {
|
|
220
|
+
// Empty ones go to the right
|
|
221
|
+
if (a.sideEffect.isEmpty()) {
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
return Number(a.sideEffect.counter.toBigInt() - b.sideEffect.counter.toBigInt());
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const originalToSorted = sorted.map(() => 0);
|
|
228
|
+
sorted.forEach(({ index }, i) => {
|
|
229
|
+
originalToSorted[index] = i;
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
return [sorted.map(({ sideEffect }) => sideEffect) as Tuple<T, K>, originalToSorted as Tuple<number, K>];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private async createPrivateCallData(
|
|
236
|
+
{ callStackItem, vk }: ExecutionResult,
|
|
237
|
+
privateCallRequests: CallRequest[],
|
|
238
|
+
publicCallRequests: CallRequest[],
|
|
239
|
+
readRequestMembershipWitnesses: ReadRequestMembershipWitness[],
|
|
240
|
+
) {
|
|
241
|
+
const { contractAddress, functionData, publicInputs } = callStackItem;
|
|
242
|
+
const { portalContractAddress } = publicInputs.callContext;
|
|
243
|
+
|
|
244
|
+
// Pad with empty items to reach max/const length expected by circuit.
|
|
245
|
+
const privateCallStack = padArrayEnd(
|
|
246
|
+
privateCallRequests,
|
|
247
|
+
CallRequest.empty(),
|
|
248
|
+
MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,
|
|
249
|
+
);
|
|
250
|
+
const publicCallStack = padArrayEnd(publicCallRequests, CallRequest.empty(), MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL);
|
|
251
|
+
|
|
252
|
+
const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness(
|
|
253
|
+
contractAddress,
|
|
254
|
+
functionData.selector,
|
|
255
|
+
);
|
|
256
|
+
const { contractClassId, publicKeysHash, saltedInitializationHash } = await this.oracle.getContractAddressPreimage(
|
|
257
|
+
contractAddress,
|
|
258
|
+
);
|
|
259
|
+
const { artifactHash: contractClassArtifactHash, publicBytecodeCommitment: contractClassPublicBytecodeCommitment } =
|
|
260
|
+
await this.oracle.getContractClassIdPreimage(contractClassId);
|
|
261
|
+
|
|
262
|
+
// TODO(#262): Use real acir hash
|
|
263
|
+
// const acirHash = keccak(Buffer.from(bytecode, 'hex'));
|
|
264
|
+
const acirHash = Fr.fromBuffer(Buffer.alloc(32, 0));
|
|
265
|
+
|
|
266
|
+
// TODO
|
|
267
|
+
const proof = makeEmptyProof();
|
|
268
|
+
|
|
269
|
+
return PrivateCallData.from({
|
|
270
|
+
callStackItem,
|
|
271
|
+
privateCallStack,
|
|
272
|
+
publicCallStack,
|
|
273
|
+
proof,
|
|
274
|
+
vk: VerificationKey.fromBuffer(vk),
|
|
275
|
+
publicKeysHash,
|
|
276
|
+
contractClassArtifactHash,
|
|
277
|
+
contractClassPublicBytecodeCommitment,
|
|
278
|
+
saltedInitializationHash,
|
|
279
|
+
functionLeafMembershipWitness,
|
|
280
|
+
readRequestMembershipWitnesses: makeTuple(MAX_READ_REQUESTS_PER_CALL, i => readRequestMembershipWitnesses[i], 0),
|
|
281
|
+
portalContractAddress: portalContractAddress.toField(),
|
|
282
|
+
acirHash,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Retrieves the new output notes for a given execution result.
|
|
288
|
+
* The function maps over the new notes and associates them with their corresponding
|
|
289
|
+
* commitments in the public inputs of the execution result. It also includes the contract address
|
|
290
|
+
* from the call context of the public inputs.
|
|
291
|
+
*
|
|
292
|
+
* @param executionResult - The execution result object containing notes and public inputs.
|
|
293
|
+
* @returns An array of OutputNoteData objects, each representing an output note with its associated data.
|
|
294
|
+
*/
|
|
295
|
+
private async getNewNotes(executionResult: ExecutionResult): Promise<OutputNoteData[]> {
|
|
296
|
+
const {
|
|
297
|
+
callStackItem: { publicInputs },
|
|
298
|
+
newNotes,
|
|
299
|
+
} = executionResult;
|
|
300
|
+
const contractAddress = publicInputs.callContext.storageContractAddress;
|
|
301
|
+
// Assuming that for each new commitment there's an output note added to the execution result.
|
|
302
|
+
const newCommitments = await this.proofCreator.getSiloedCommitments(publicInputs);
|
|
303
|
+
return newNotes.map((data, i) => ({
|
|
304
|
+
contractAddress,
|
|
305
|
+
data,
|
|
306
|
+
commitment: newCommitments[i],
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Performs the matching between an array of read request and an array of commitments. This produces
|
|
312
|
+
* hints for the private kernel ordering circuit to efficiently match a read request with the corresponding
|
|
313
|
+
* commitment.
|
|
314
|
+
*
|
|
315
|
+
* @param readRequests - The array of read requests.
|
|
316
|
+
* @param commitments - The array of commitments.
|
|
317
|
+
* @returns An array of hints where each element is the index of the commitment in commitments array
|
|
318
|
+
* corresponding to the read request. In other words we have readRequests[i] == commitments[hints[i]].
|
|
319
|
+
*/
|
|
320
|
+
private getReadRequestHints(
|
|
321
|
+
readRequests: Tuple<SideEffect, typeof MAX_READ_REQUESTS_PER_TX>,
|
|
322
|
+
commitments: Tuple<SideEffect, typeof MAX_NEW_COMMITMENTS_PER_TX>,
|
|
323
|
+
): Tuple<Fr, typeof MAX_READ_REQUESTS_PER_TX> {
|
|
324
|
+
const hints = makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero);
|
|
325
|
+
for (let i = 0; i < MAX_READ_REQUESTS_PER_TX && !readRequests[i].isEmpty(); i++) {
|
|
326
|
+
const equalToRR = (cmt: SideEffect) => cmt.value.equals(readRequests[i].value);
|
|
327
|
+
const result = commitments.findIndex(equalToRR);
|
|
328
|
+
if (result == -1) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
`The read request at index ${i} with value ${readRequests[i].toString()} does not match to any commitment.`,
|
|
331
|
+
);
|
|
332
|
+
} else {
|
|
333
|
+
hints[i] = new Fr(result);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return hints;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Performs the matching between an array of nullified commitments and an array of commitments. This produces
|
|
341
|
+
* hints for the private kernel ordering circuit to efficiently match a nullifier with the corresponding
|
|
342
|
+
* commitment.
|
|
343
|
+
*
|
|
344
|
+
* @param nullifiedCommitments - The array of nullified commitments.
|
|
345
|
+
* @param commitments - The array of commitments.
|
|
346
|
+
* @returns An array of hints where each element is the index of the commitment in commitments array
|
|
347
|
+
* corresponding to the nullified commitments. In other words we have nullifiedCommitments[i] == commitments[hints[i]].
|
|
348
|
+
*/
|
|
349
|
+
private getNullifierHints(
|
|
350
|
+
nullifiedCommitments: Tuple<Fr, typeof MAX_NEW_NULLIFIERS_PER_TX>,
|
|
351
|
+
commitments: Tuple<SideEffect, typeof MAX_NEW_COMMITMENTS_PER_TX>,
|
|
352
|
+
): Tuple<Fr, typeof MAX_NEW_NULLIFIERS_PER_TX> {
|
|
353
|
+
const hints = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero);
|
|
354
|
+
for (let i = 0; i < MAX_NEW_NULLIFIERS_PER_TX; i++) {
|
|
355
|
+
if (!nullifiedCommitments[i].isZero()) {
|
|
356
|
+
const equalToCommitment = (cmt: SideEffect) => cmt.value.equals(nullifiedCommitments[i]);
|
|
357
|
+
const result = commitments.findIndex(equalToCommitment);
|
|
358
|
+
if (result == -1) {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`The nullified commitment at index ${i} with value ${nullifiedCommitments[
|
|
361
|
+
i
|
|
362
|
+
].toString()} does not match to any commitment.`,
|
|
363
|
+
);
|
|
364
|
+
} else {
|
|
365
|
+
hints[i] = new Fr(result);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return hints;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private async getMasterNullifierSecretKeys(
|
|
373
|
+
nullifierKeyValidationRequests: Tuple<
|
|
374
|
+
NullifierKeyValidationRequestContext,
|
|
375
|
+
typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX
|
|
376
|
+
>,
|
|
377
|
+
) {
|
|
378
|
+
const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar.zero);
|
|
379
|
+
for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) {
|
|
380
|
+
const request = nullifierKeyValidationRequests[i];
|
|
381
|
+
if (request.isEmpty()) {
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
keys[i] = await this.oracle.getMasterNullifierSecretKey(request.publicKey);
|
|
385
|
+
}
|
|
386
|
+
return keys;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { CircuitSimulationStats } from '@aztec/circuit-types/stats';
|
|
2
|
+
import {
|
|
3
|
+
PrivateCircuitPublicInputs,
|
|
4
|
+
PrivateKernelInitCircuitPrivateInputs,
|
|
5
|
+
PrivateKernelInnerCircuitPrivateInputs,
|
|
6
|
+
PrivateKernelInnerCircuitPublicInputs,
|
|
7
|
+
PrivateKernelTailCircuitPrivateInputs,
|
|
8
|
+
PrivateKernelTailCircuitPublicInputs,
|
|
9
|
+
Proof,
|
|
10
|
+
makeEmptyProof,
|
|
11
|
+
} from '@aztec/circuits.js';
|
|
12
|
+
import { siloCommitment } from '@aztec/circuits.js/abis';
|
|
13
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
14
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
15
|
+
import { elapsed } from '@aztec/foundation/timer';
|
|
16
|
+
import { executeInit, executeInner, executeTail } from '@aztec/noir-protocol-circuits-types';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Represents the output of the proof creation process for init and inner private kernel circuit.
|
|
20
|
+
* Contains the public inputs required for the init and inner private kernel circuit and the generated proof.
|
|
21
|
+
*/
|
|
22
|
+
export interface ProofOutput {
|
|
23
|
+
/**
|
|
24
|
+
* The public inputs required for the proof generation process.
|
|
25
|
+
*/
|
|
26
|
+
publicInputs: PrivateKernelInnerCircuitPublicInputs;
|
|
27
|
+
/**
|
|
28
|
+
* The zk-SNARK proof for the kernel execution.
|
|
29
|
+
*/
|
|
30
|
+
proof: Proof;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Represents the output of the proof creation process for final ordering private kernel circuit.
|
|
35
|
+
* Contains the public inputs required for the final ordering private kernel circuit and the generated proof.
|
|
36
|
+
*/
|
|
37
|
+
export interface ProofOutputFinal {
|
|
38
|
+
/**
|
|
39
|
+
* The public inputs required for the proof generation process.
|
|
40
|
+
*/
|
|
41
|
+
publicInputs: PrivateKernelTailCircuitPublicInputs;
|
|
42
|
+
/**
|
|
43
|
+
* The zk-SNARK proof for the kernel execution.
|
|
44
|
+
*/
|
|
45
|
+
proof: Proof;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ProofCreator provides functionality to create and validate proofs, and retrieve
|
|
50
|
+
* siloed commitments necessary for maintaining transaction privacy and security on the network.
|
|
51
|
+
*/
|
|
52
|
+
export interface ProofCreator {
|
|
53
|
+
/**
|
|
54
|
+
* Computes the siloed commitments for a given set of public inputs.
|
|
55
|
+
*
|
|
56
|
+
* @param publicInputs - The public inputs containing the contract address and new commitments to be used in generating siloed commitments.
|
|
57
|
+
* @returns An array of Fr (finite field) elements representing the siloed commitments.
|
|
58
|
+
*/
|
|
59
|
+
getSiloedCommitments(publicInputs: PrivateCircuitPublicInputs): Promise<Fr[]>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Creates a proof output for a given signed transaction request and private call data for the first iteration.
|
|
63
|
+
*
|
|
64
|
+
* @param privateKernelInputsInit - The private data structure for the initial iteration.
|
|
65
|
+
* @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof.
|
|
66
|
+
*/
|
|
67
|
+
createProofInit(privateKernelInputsInit: PrivateKernelInitCircuitPrivateInputs): Promise<ProofOutput>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Creates a proof output for a given previous kernel data and private call data for an inner iteration.
|
|
71
|
+
*
|
|
72
|
+
* @param privateKernelInputsInner - The private input data structure for the inner iteration.
|
|
73
|
+
* @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof.
|
|
74
|
+
*/
|
|
75
|
+
createProofInner(privateKernelInputsInner: PrivateKernelInnerCircuitPrivateInputs): Promise<ProofOutput>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Creates a proof output based on the last inner kernel iteration kernel data for the final ordering iteration.
|
|
79
|
+
*
|
|
80
|
+
* @param privateKernelInputsTail - The private input data structure for the final ordering iteration.
|
|
81
|
+
* @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof.
|
|
82
|
+
*/
|
|
83
|
+
createProofTail(privateKernelInputsTail: PrivateKernelTailCircuitPrivateInputs): Promise<ProofOutputFinal>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The KernelProofCreator class is responsible for generating siloed commitments and zero-knowledge proofs
|
|
88
|
+
* for private kernel circuit. It leverages Barretenberg to perform cryptographic operations and proof creation.
|
|
89
|
+
* The class provides methods to compute commitments based on the given public inputs and to generate proofs based on
|
|
90
|
+
* signed transaction requests, previous kernel data, private call data, and a flag indicating whether it's the first
|
|
91
|
+
* iteration or not.
|
|
92
|
+
*/
|
|
93
|
+
export class KernelProofCreator implements ProofCreator {
|
|
94
|
+
constructor(private log = createDebugLogger('aztec:kernel_proof_creator')) {}
|
|
95
|
+
|
|
96
|
+
public getSiloedCommitments(publicInputs: PrivateCircuitPublicInputs) {
|
|
97
|
+
const contractAddress = publicInputs.callContext.storageContractAddress;
|
|
98
|
+
|
|
99
|
+
return Promise.resolve(
|
|
100
|
+
publicInputs.newCommitments.map(commitment => siloCommitment(contractAddress, commitment.value)),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public async createProofInit(privateInputs: PrivateKernelInitCircuitPrivateInputs): Promise<ProofOutput> {
|
|
105
|
+
const [duration, result] = await elapsed(() => executeInit(privateInputs));
|
|
106
|
+
this.log(`Simulated private kernel init`, {
|
|
107
|
+
eventName: 'circuit-simulation',
|
|
108
|
+
circuitName: 'private-kernel-init',
|
|
109
|
+
duration,
|
|
110
|
+
inputSize: privateInputs.toBuffer().length,
|
|
111
|
+
outputSize: result.toBuffer().length,
|
|
112
|
+
} satisfies CircuitSimulationStats);
|
|
113
|
+
this.log('Skipping private kernel init proving...');
|
|
114
|
+
const proof = makeEmptyProof();
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
publicInputs: result,
|
|
118
|
+
proof: proof,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async createProofInner(privateInputs: PrivateKernelInnerCircuitPrivateInputs): Promise<ProofOutput> {
|
|
123
|
+
const [duration, result] = await elapsed(() => executeInner(privateInputs));
|
|
124
|
+
this.log(`Simulated private kernel inner`, {
|
|
125
|
+
eventName: 'circuit-simulation',
|
|
126
|
+
circuitName: 'private-kernel-inner',
|
|
127
|
+
duration,
|
|
128
|
+
inputSize: privateInputs.toBuffer().length,
|
|
129
|
+
outputSize: result.toBuffer().length,
|
|
130
|
+
} satisfies CircuitSimulationStats);
|
|
131
|
+
this.log('Skipping private kernel inner proving...');
|
|
132
|
+
const proof = makeEmptyProof();
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
publicInputs: result,
|
|
136
|
+
proof: proof,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public async createProofTail(privateInputs: PrivateKernelTailCircuitPrivateInputs): Promise<ProofOutputFinal> {
|
|
141
|
+
const [duration, result] = await elapsed(() => executeTail(privateInputs));
|
|
142
|
+
this.log(`Simulated private kernel ordering`, {
|
|
143
|
+
eventName: 'circuit-simulation',
|
|
144
|
+
circuitName: 'private-kernel-ordering',
|
|
145
|
+
duration,
|
|
146
|
+
inputSize: privateInputs.toBuffer().length,
|
|
147
|
+
outputSize: result.toBuffer().length,
|
|
148
|
+
} satisfies CircuitSimulationStats);
|
|
149
|
+
this.log('Skipping private kernel ordering proving...');
|
|
150
|
+
const proof = makeEmptyProof();
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
publicInputs: result,
|
|
154
|
+
proof: proof,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FUNCTION_TREE_HEIGHT,
|
|
3
|
+
Fr,
|
|
4
|
+
FunctionSelector,
|
|
5
|
+
GrumpkinPrivateKey,
|
|
6
|
+
MembershipWitness,
|
|
7
|
+
NOTE_HASH_TREE_HEIGHT,
|
|
8
|
+
Point,
|
|
9
|
+
VK_TREE_HEIGHT,
|
|
10
|
+
VerificationKey,
|
|
11
|
+
} from '@aztec/circuits.js';
|
|
12
|
+
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Provides functionality to fetch membership witnesses for verification keys,
|
|
16
|
+
* contract addresses, and function selectors in their respective merkle trees.
|
|
17
|
+
*/
|
|
18
|
+
export interface ProvingDataOracle {
|
|
19
|
+
/** Retrieves the preimage of a contract address from the registered contract instances db. */
|
|
20
|
+
getContractAddressPreimage(
|
|
21
|
+
address: AztecAddress,
|
|
22
|
+
): Promise<{ saltedInitializationHash: Fr; publicKeysHash: Fr; contractClassId: Fr }>;
|
|
23
|
+
|
|
24
|
+
/** Retrieves the preimage of a contract class id from the contract classes db. */
|
|
25
|
+
getContractClassIdPreimage(
|
|
26
|
+
contractClassId: Fr,
|
|
27
|
+
): Promise<{ artifactHash: Fr; publicBytecodeCommitment: Fr; privateFunctionsRoot: Fr }>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Retrieve the function membership witness for the given contract address and function selector.
|
|
31
|
+
* The function membership witness represents a proof that the function belongs to the specified contract.
|
|
32
|
+
* Throws an error if the contract address or function selector is unknown.
|
|
33
|
+
*
|
|
34
|
+
* @param contractAddress - The contract address.
|
|
35
|
+
* @param selector - The function selector.
|
|
36
|
+
* @returns A promise that resolves with the MembershipWitness instance for the specified contract's function.
|
|
37
|
+
*/
|
|
38
|
+
getFunctionMembershipWitness(
|
|
39
|
+
contractAddress: AztecAddress,
|
|
40
|
+
selector: FunctionSelector,
|
|
41
|
+
): Promise<MembershipWitness<typeof FUNCTION_TREE_HEIGHT>>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Retrieve the membership witness corresponding to a verification key.
|
|
45
|
+
* This function currently returns a random membership witness of the specified height,
|
|
46
|
+
* which is a placeholder implementation until a concrete membership witness calculation
|
|
47
|
+
* is implemented.
|
|
48
|
+
*
|
|
49
|
+
* @param vk - The VerificationKey for which the membership witness is needed.
|
|
50
|
+
* @returns A Promise that resolves to the MembershipWitness instance.
|
|
51
|
+
*/
|
|
52
|
+
getVkMembershipWitness(vk: VerificationKey): Promise<MembershipWitness<typeof VK_TREE_HEIGHT>>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the note membership witness for a note in the note hash tree at the given leaf index.
|
|
56
|
+
*
|
|
57
|
+
* @param leafIndex - The leaf index of the note in the note hash tree.
|
|
58
|
+
* @returns the MembershipWitness for the note.
|
|
59
|
+
*/
|
|
60
|
+
getNoteMembershipWitness(leafIndex: bigint): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT>>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the root of the note hash tree.
|
|
64
|
+
*
|
|
65
|
+
* @returns the root of the note hash tree.
|
|
66
|
+
*/
|
|
67
|
+
getNoteHashTreeRoot(): Promise<Fr>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get the master secret key of the nullifier public key.
|
|
71
|
+
*
|
|
72
|
+
* @param nullifierPublicKey - The nullifier public key.
|
|
73
|
+
* @returns the master nullifier secret key.
|
|
74
|
+
*/
|
|
75
|
+
getMasterNullifierSecretKey(nullifierPublicKey: Point): Promise<GrumpkinPrivateKey>;
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './note_processor.js';
|