@aztec/bb-prover 0.40.0 → 0.41.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/bb/execute.d.ts +7 -1
- package/dest/bb/execute.d.ts.map +1 -1
- package/dest/bb/execute.js +35 -26
- package/dest/prover/bb_native_proof_creator.d.ts +3 -2
- package/dest/prover/bb_native_proof_creator.d.ts.map +1 -1
- package/dest/prover/bb_native_proof_creator.js +53 -35
- package/dest/prover/bb_prover.d.ts +14 -3
- package/dest/prover/bb_prover.d.ts.map +1 -1
- package/dest/prover/bb_prover.js +67 -40
- package/dest/stats.d.ts +2 -5
- package/dest/stats.d.ts.map +1 -1
- package/dest/stats.js +20 -25
- package/package.json +6 -6
- package/src/bb/execute.ts +41 -26
- package/src/prover/bb_native_proof_creator.ts +104 -42
- package/src/prover/bb_prover.ts +122 -82
- package/src/stats.ts +23 -44
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '@aztec/circuit-types';
|
|
2
|
+
import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
|
|
2
3
|
import {
|
|
3
4
|
Fr,
|
|
4
5
|
NESTED_RECURSIVE_PROOF_LENGTH,
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
type PrivateKernelCircuitPublicInputs,
|
|
7
8
|
type PrivateKernelInitCircuitPrivateInputs,
|
|
8
9
|
type PrivateKernelInnerCircuitPrivateInputs,
|
|
10
|
+
type PrivateKernelResetCircuitPrivateInputsVariants,
|
|
9
11
|
type PrivateKernelTailCircuitPrivateInputs,
|
|
10
12
|
type PrivateKernelTailCircuitPublicInputs,
|
|
11
13
|
Proof,
|
|
@@ -18,13 +20,17 @@ import { siloNoteHash } from '@aztec/circuits.js/hash';
|
|
|
18
20
|
import { randomBytes } from '@aztec/foundation/crypto';
|
|
19
21
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
20
22
|
import { type Tuple } from '@aztec/foundation/serialize';
|
|
23
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
21
24
|
import {
|
|
22
25
|
ClientCircuitArtifacts,
|
|
23
26
|
type ClientProtocolArtifact,
|
|
27
|
+
PrivateResetTagToArtifactName,
|
|
24
28
|
convertPrivateKernelInitInputsToWitnessMap,
|
|
25
29
|
convertPrivateKernelInitOutputsFromWitnessMap,
|
|
26
30
|
convertPrivateKernelInnerInputsToWitnessMap,
|
|
27
31
|
convertPrivateKernelInnerOutputsFromWitnessMap,
|
|
32
|
+
convertPrivateKernelResetInputsToWitnessMap,
|
|
33
|
+
convertPrivateKernelResetOutputsFromWitnessMap,
|
|
28
34
|
convertPrivateKernelTailForPublicOutputsFromWitnessMap,
|
|
29
35
|
convertPrivateKernelTailInputsToWitnessMap,
|
|
30
36
|
convertPrivateKernelTailOutputsFromWitnessMap,
|
|
@@ -47,6 +53,7 @@ import {
|
|
|
47
53
|
generateProof,
|
|
48
54
|
verifyProof,
|
|
49
55
|
} from '../bb/execute.js';
|
|
56
|
+
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
|
|
50
57
|
import {
|
|
51
58
|
AGGREGATION_OBJECT_SIZE,
|
|
52
59
|
CIRCUIT_PUBLIC_INPUTS_INDEX,
|
|
@@ -55,25 +62,6 @@ import {
|
|
|
55
62
|
type VerificationKeyData,
|
|
56
63
|
} from './verification_key_data.js';
|
|
57
64
|
|
|
58
|
-
type PrivateKernelProvingOps = {
|
|
59
|
-
convertOutputs: (outputs: WitnessMap) => PrivateKernelCircuitPublicInputs | PrivateKernelTailCircuitPublicInputs;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const PrivateKernelArtifactMapping: Record<ClientProtocolArtifact, PrivateKernelProvingOps> = {
|
|
63
|
-
PrivateKernelInitArtifact: {
|
|
64
|
-
convertOutputs: convertPrivateKernelInitOutputsFromWitnessMap,
|
|
65
|
-
},
|
|
66
|
-
PrivateKernelInnerArtifact: {
|
|
67
|
-
convertOutputs: convertPrivateKernelInnerOutputsFromWitnessMap,
|
|
68
|
-
},
|
|
69
|
-
PrivateKernelTailArtifact: {
|
|
70
|
-
convertOutputs: convertPrivateKernelTailOutputsFromWitnessMap,
|
|
71
|
-
},
|
|
72
|
-
PrivateKernelTailToPublicArtifact: {
|
|
73
|
-
convertOutputs: convertPrivateKernelTailForPublicOutputsFromWitnessMap,
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
|
|
77
65
|
/**
|
|
78
66
|
* This proof creator implementation uses the native bb binary.
|
|
79
67
|
* This is a temporary implementation until we make the WASM version work.
|
|
@@ -103,38 +91,66 @@ export class BBNativeProofCreator implements ProofCreator {
|
|
|
103
91
|
public async createProofInit(
|
|
104
92
|
inputs: PrivateKernelInitCircuitPrivateInputs,
|
|
105
93
|
): Promise<KernelProofOutput<PrivateKernelCircuitPublicInputs>> {
|
|
106
|
-
|
|
107
|
-
|
|
94
|
+
return await this.createSafeProof(
|
|
95
|
+
inputs,
|
|
96
|
+
'PrivateKernelInitArtifact',
|
|
97
|
+
convertPrivateKernelInitInputsToWitnessMap,
|
|
98
|
+
convertPrivateKernelInitOutputsFromWitnessMap,
|
|
99
|
+
);
|
|
108
100
|
}
|
|
109
101
|
|
|
110
102
|
public async createProofInner(
|
|
111
103
|
inputs: PrivateKernelInnerCircuitPrivateInputs,
|
|
112
104
|
): Promise<KernelProofOutput<PrivateKernelCircuitPublicInputs>> {
|
|
113
|
-
|
|
114
|
-
|
|
105
|
+
return await this.createSafeProof(
|
|
106
|
+
inputs,
|
|
107
|
+
'PrivateKernelInnerArtifact',
|
|
108
|
+
convertPrivateKernelInnerInputsToWitnessMap,
|
|
109
|
+
convertPrivateKernelInnerOutputsFromWitnessMap,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public async createProofReset(
|
|
114
|
+
inputs: PrivateKernelResetCircuitPrivateInputsVariants,
|
|
115
|
+
): Promise<KernelProofOutput<PrivateKernelCircuitPublicInputs>> {
|
|
116
|
+
return await this.createSafeProof(
|
|
117
|
+
inputs,
|
|
118
|
+
PrivateResetTagToArtifactName[inputs.sizeTag],
|
|
119
|
+
convertPrivateKernelResetInputsToWitnessMap,
|
|
120
|
+
output => convertPrivateKernelResetOutputsFromWitnessMap(output, inputs.sizeTag),
|
|
121
|
+
);
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
public async createProofTail(
|
|
118
125
|
inputs: PrivateKernelTailCircuitPrivateInputs,
|
|
119
126
|
): Promise<KernelProofOutput<PrivateKernelTailCircuitPublicInputs>> {
|
|
120
127
|
if (!inputs.isForPublic()) {
|
|
121
|
-
|
|
122
|
-
|
|
128
|
+
return await this.createSafeProof(
|
|
129
|
+
inputs,
|
|
130
|
+
'PrivateKernelTailArtifact',
|
|
131
|
+
convertPrivateKernelTailInputsToWitnessMap,
|
|
132
|
+
convertPrivateKernelTailOutputsFromWitnessMap,
|
|
133
|
+
);
|
|
123
134
|
}
|
|
124
|
-
|
|
125
|
-
|
|
135
|
+
return await this.createSafeProof(
|
|
136
|
+
inputs,
|
|
137
|
+
'PrivateKernelTailToPublicArtifact',
|
|
138
|
+
convertPrivateKernelTailToPublicInputsToWitnessMap,
|
|
139
|
+
convertPrivateKernelTailForPublicOutputsFromWitnessMap,
|
|
140
|
+
);
|
|
126
141
|
}
|
|
127
142
|
|
|
128
143
|
public async createAppCircuitProof(
|
|
129
144
|
partialWitness: Map<number, ACVMField>,
|
|
130
145
|
bytecode: Buffer,
|
|
146
|
+
appCircuitName?: string,
|
|
131
147
|
): Promise<AppCircuitProofOutput> {
|
|
132
148
|
const directory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
|
|
133
149
|
await fs.mkdir(directory, { recursive: true });
|
|
134
150
|
this.log.debug(`Created directory: ${directory}`);
|
|
135
151
|
try {
|
|
136
152
|
this.log.debug(`Proving app circuit`);
|
|
137
|
-
const proofOutput = await this.createProof(directory, partialWitness, bytecode, 'App');
|
|
153
|
+
const proofOutput = await this.createProof(directory, partialWitness, bytecode, 'App', 0, 0, appCircuitName);
|
|
138
154
|
if (proofOutput.proof.proof.length != RECURSIVE_PROOF_LENGTH) {
|
|
139
155
|
throw new Error(`Incorrect proof length`);
|
|
140
156
|
}
|
|
@@ -263,48 +279,66 @@ export class BBNativeProofCreator implements ProofCreator {
|
|
|
263
279
|
return await promise;
|
|
264
280
|
}
|
|
265
281
|
|
|
266
|
-
private async createSafeProof<
|
|
267
|
-
inputs:
|
|
282
|
+
private async createSafeProof<I extends { toBuffer: () => Buffer }, O extends { toBuffer: () => Buffer }>(
|
|
283
|
+
inputs: I,
|
|
268
284
|
circuitType: ClientProtocolArtifact,
|
|
269
|
-
|
|
285
|
+
convertInputs: (inputs: I) => WitnessMap,
|
|
286
|
+
convertOutputs: (outputs: WitnessMap) => O,
|
|
287
|
+
): Promise<KernelProofOutput<O>> {
|
|
270
288
|
const directory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
|
|
271
289
|
await fs.mkdir(directory, { recursive: true });
|
|
272
290
|
this.log.debug(`Created directory: ${directory}`);
|
|
273
291
|
try {
|
|
274
|
-
return await this.generateWitnessAndCreateProof(inputs, circuitType, directory);
|
|
292
|
+
return await this.generateWitnessAndCreateProof(inputs, circuitType, directory, convertInputs, convertOutputs);
|
|
275
293
|
} finally {
|
|
276
294
|
await fs.rm(directory, { recursive: true, force: true });
|
|
277
295
|
this.log.debug(`Deleted directory: ${directory}`);
|
|
278
296
|
}
|
|
279
297
|
}
|
|
280
298
|
|
|
281
|
-
private async generateWitnessAndCreateProof<
|
|
282
|
-
|
|
299
|
+
private async generateWitnessAndCreateProof<
|
|
300
|
+
I extends { toBuffer: () => Buffer },
|
|
301
|
+
O extends { toBuffer: () => Buffer },
|
|
302
|
+
>(
|
|
303
|
+
inputs: I,
|
|
283
304
|
circuitType: ClientProtocolArtifact,
|
|
284
305
|
directory: string,
|
|
285
|
-
|
|
306
|
+
convertInputs: (inputs: I) => WitnessMap,
|
|
307
|
+
convertOutputs: (outputs: WitnessMap) => O,
|
|
308
|
+
): Promise<KernelProofOutput<O>> {
|
|
286
309
|
this.log.debug(`Generating witness for ${circuitType}`);
|
|
287
310
|
const compiledCircuit: NoirCompiledCircuit = ClientCircuitArtifacts[circuitType];
|
|
288
311
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
this.
|
|
292
|
-
|
|
293
|
-
|
|
312
|
+
const witnessMap = convertInputs(inputs);
|
|
313
|
+
const timer = new Timer();
|
|
314
|
+
const outputWitness = await this.simulator.simulateCircuit(witnessMap, compiledCircuit);
|
|
315
|
+
const output = convertOutputs(outputWitness);
|
|
316
|
+
|
|
317
|
+
const inputSize = inputs.toBuffer().length;
|
|
318
|
+
const outputSize = output.toBuffer().length;
|
|
319
|
+
this.log.debug(`Generated witness for ${circuitType}`, {
|
|
320
|
+
eventName: 'circuit-witness-generation',
|
|
321
|
+
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
|
|
322
|
+
duration: timer.ms(),
|
|
323
|
+
inputSize,
|
|
324
|
+
outputSize,
|
|
325
|
+
} satisfies CircuitWitnessGenerationStats);
|
|
294
326
|
|
|
295
327
|
const proofOutput = await this.createProof(
|
|
296
328
|
directory,
|
|
297
329
|
outputWitness,
|
|
298
330
|
Buffer.from(compiledCircuit.bytecode, 'base64'),
|
|
299
331
|
circuitType,
|
|
332
|
+
inputSize,
|
|
333
|
+
outputSize,
|
|
300
334
|
);
|
|
301
335
|
if (proofOutput.proof.proof.length != NESTED_RECURSIVE_PROOF_LENGTH) {
|
|
302
336
|
throw new Error(`Incorrect proof length`);
|
|
303
337
|
}
|
|
304
338
|
const nestedProof = proofOutput.proof as RecursiveProof<typeof NESTED_RECURSIVE_PROOF_LENGTH>;
|
|
305
339
|
|
|
306
|
-
const kernelOutput: KernelProofOutput<
|
|
307
|
-
publicInputs,
|
|
340
|
+
const kernelOutput: KernelProofOutput<O> = {
|
|
341
|
+
publicInputs: output,
|
|
308
342
|
proof: nestedProof,
|
|
309
343
|
verificationKey: proofOutput.verificationKey,
|
|
310
344
|
};
|
|
@@ -316,6 +350,9 @@ export class BBNativeProofCreator implements ProofCreator {
|
|
|
316
350
|
partialWitness: WitnessMap,
|
|
317
351
|
bytecode: Buffer,
|
|
318
352
|
circuitType: ClientProtocolArtifact | 'App',
|
|
353
|
+
inputSize: number,
|
|
354
|
+
outputSize: number,
|
|
355
|
+
appCircuitName?: string,
|
|
319
356
|
): Promise<{
|
|
320
357
|
proof: RecursiveProof<typeof RECURSIVE_PROOF_LENGTH> | RecursiveProof<typeof NESTED_RECURSIVE_PROOF_LENGTH>;
|
|
321
358
|
verificationKey: VerificationKeyAsFields;
|
|
@@ -345,11 +382,36 @@ export class BBNativeProofCreator implements ProofCreator {
|
|
|
345
382
|
if (circuitType === 'App') {
|
|
346
383
|
const vkData = await this.convertVk(directory);
|
|
347
384
|
const proof = await this.readProofAsFields<typeof RECURSIVE_PROOF_LENGTH>(directory, circuitType, vkData);
|
|
385
|
+
|
|
386
|
+
this.log.debug(`Generated proof`, {
|
|
387
|
+
eventName: 'circuit-proving',
|
|
388
|
+
circuitName: 'app-circuit',
|
|
389
|
+
duration: provingResult.duration,
|
|
390
|
+
inputSize,
|
|
391
|
+
outputSize,
|
|
392
|
+
proofSize: proof.binaryProof.buffer.length,
|
|
393
|
+
appCircuitName,
|
|
394
|
+
circuitSize: vkData.circuitSize,
|
|
395
|
+
numPublicInputs: vkData.numPublicInputs,
|
|
396
|
+
} as CircuitProvingStats);
|
|
397
|
+
|
|
348
398
|
return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) };
|
|
349
399
|
}
|
|
350
400
|
|
|
351
401
|
const vkData = await this.updateVerificationKeyAfterProof(directory, circuitType);
|
|
352
402
|
const proof = await this.readProofAsFields<typeof NESTED_RECURSIVE_PROOF_LENGTH>(directory, circuitType, vkData);
|
|
403
|
+
|
|
404
|
+
this.log.debug(`Generated proof`, {
|
|
405
|
+
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
|
|
406
|
+
duration: provingResult.duration,
|
|
407
|
+
eventName: 'circuit-proving',
|
|
408
|
+
inputSize,
|
|
409
|
+
outputSize,
|
|
410
|
+
proofSize: proof.binaryProof.buffer.length,
|
|
411
|
+
circuitSize: vkData.circuitSize,
|
|
412
|
+
numPublicInputs: vkData.numPublicInputs,
|
|
413
|
+
} as CircuitProvingStats);
|
|
414
|
+
|
|
353
415
|
return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) };
|
|
354
416
|
}
|
|
355
417
|
|
package/src/prover/bb_prover.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type ServerCircuitProver,
|
|
8
8
|
makePublicInputsAndProof,
|
|
9
9
|
} from '@aztec/circuit-types';
|
|
10
|
+
import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
|
|
10
11
|
import {
|
|
11
12
|
type BaseOrMergeRollupPublicInputs,
|
|
12
13
|
type BaseParityInputs,
|
|
@@ -14,12 +15,11 @@ import {
|
|
|
14
15
|
Fr,
|
|
15
16
|
type KernelCircuitPublicInputs,
|
|
16
17
|
type MergeRollupInputs,
|
|
17
|
-
|
|
18
|
-
type ParityPublicInputs,
|
|
18
|
+
NESTED_RECURSIVE_PROOF_LENGTH,
|
|
19
19
|
type PreviousRollupData,
|
|
20
20
|
Proof,
|
|
21
21
|
type PublicKernelCircuitPublicInputs,
|
|
22
|
-
|
|
22
|
+
RECURSIVE_PROOF_LENGTH,
|
|
23
23
|
RecursiveProof,
|
|
24
24
|
RollupTypes,
|
|
25
25
|
RootParityInput,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
verifyProof,
|
|
66
66
|
} from '../bb/execute.js';
|
|
67
67
|
import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
|
|
68
|
-
import {
|
|
68
|
+
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
|
|
69
69
|
import {
|
|
70
70
|
AGGREGATION_OBJECT_SIZE,
|
|
71
71
|
CIRCUIT_PUBLIC_INPUTS_INDEX,
|
|
@@ -114,11 +114,11 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
114
114
|
* @returns The public inputs of the parity circuit.
|
|
115
115
|
*/
|
|
116
116
|
public async getBaseParityProof(inputs: BaseParityInputs): Promise<RootParityInput<typeof RECURSIVE_PROOF_LENGTH>> {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
const [circuitOutput, proof] = await this.createRecursiveProof<typeof RECURSIVE_PROOF_LENGTH, ParityPublicInputs>(
|
|
120
|
-
witnessMap,
|
|
117
|
+
const [circuitOutput, proof] = await this.createRecursiveProof(
|
|
118
|
+
inputs,
|
|
121
119
|
'BaseParityArtifact',
|
|
120
|
+
RECURSIVE_PROOF_LENGTH,
|
|
121
|
+
convertBaseParityInputsToWitnessMap,
|
|
122
122
|
convertBaseParityOutputsFromWitnessMap,
|
|
123
123
|
);
|
|
124
124
|
|
|
@@ -137,12 +137,13 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
137
137
|
public async getRootParityProof(
|
|
138
138
|
inputs: RootParityInputs,
|
|
139
139
|
): Promise<RootParityInput<typeof NESTED_RECURSIVE_PROOF_LENGTH>> {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
const [circuitOutput, proof] = await this.createRecursiveProof(
|
|
141
|
+
inputs,
|
|
142
|
+
'RootParityArtifact',
|
|
143
|
+
NESTED_RECURSIVE_PROOF_LENGTH,
|
|
144
|
+
convertRootParityInputsToWitnessMap,
|
|
145
|
+
convertRootParityOutputsFromWitnessMap,
|
|
146
|
+
);
|
|
146
147
|
|
|
147
148
|
const verificationKey = await this.getVerificationKeyDataForCircuit('RootParityArtifact');
|
|
148
149
|
|
|
@@ -163,11 +164,13 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
163
164
|
if (kernelOps === undefined) {
|
|
164
165
|
throw new Error(`Unable to prove kernel type ${PublicKernelType[kernelRequest.type]}`);
|
|
165
166
|
}
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
const [result, proof] = await this.createProof(
|
|
168
|
+
kernelRequest.inputs,
|
|
169
|
+
kernelOps.artifact,
|
|
170
|
+
kernelOps.convertInputs,
|
|
171
|
+
kernelOps.convertOutputs,
|
|
172
|
+
);
|
|
169
173
|
|
|
170
|
-
const result = kernelOps.convertOutputs(outputWitness);
|
|
171
174
|
return makePublicInputsAndProof(result, proof);
|
|
172
175
|
}
|
|
173
176
|
|
|
@@ -179,11 +182,13 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
179
182
|
public async getPublicTailProof(
|
|
180
183
|
kernelRequest: PublicKernelTailRequest,
|
|
181
184
|
): Promise<PublicInputsAndProof<KernelCircuitPublicInputs>> {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
const [result, proof] = await this.createProof(
|
|
186
|
+
kernelRequest.inputs,
|
|
187
|
+
'PublicKernelTailArtifact',
|
|
188
|
+
convertPublicTailInputsToWitnessMap,
|
|
189
|
+
convertPublicTailOutputFromWitnessMap,
|
|
190
|
+
);
|
|
185
191
|
|
|
186
|
-
const result = convertPublicTailOutputFromWitnessMap(outputWitness);
|
|
187
192
|
return makePublicInputsAndProof(result, proof);
|
|
188
193
|
}
|
|
189
194
|
|
|
@@ -195,11 +200,12 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
195
200
|
public async getBaseRollupProof(
|
|
196
201
|
input: BaseRollupInputs,
|
|
197
202
|
): Promise<PublicInputsAndProof<BaseOrMergeRollupPublicInputs>> {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
const [result, proof] = await this.createProof(
|
|
204
|
+
input,
|
|
205
|
+
'BaseRollupArtifact',
|
|
206
|
+
convertBaseRollupInputsToWitnessMap,
|
|
207
|
+
convertBaseRollupOutputsFromWitnessMap,
|
|
208
|
+
);
|
|
203
209
|
|
|
204
210
|
return makePublicInputsAndProof(result, proof);
|
|
205
211
|
}
|
|
@@ -214,11 +220,12 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
214
220
|
// verify both inputs
|
|
215
221
|
await Promise.all(input.previousRollupData.map(prev => this.verifyPreviousRollupProof(prev)));
|
|
216
222
|
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
223
|
+
const [result, proof] = await this.createProof(
|
|
224
|
+
input,
|
|
225
|
+
'MergeRollupArtifact',
|
|
226
|
+
convertMergeRollupInputsToWitnessMap,
|
|
227
|
+
convertMergeRollupOutputsFromWitnessMap,
|
|
228
|
+
);
|
|
222
229
|
|
|
223
230
|
return makePublicInputsAndProof(result, proof);
|
|
224
231
|
}
|
|
@@ -232,18 +239,25 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
232
239
|
// verify the inputs
|
|
233
240
|
await Promise.all(input.previousRollupData.map(prev => this.verifyPreviousRollupProof(prev)));
|
|
234
241
|
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
242
|
+
const [result, proof] = await this.createProof(
|
|
243
|
+
input,
|
|
244
|
+
'RootRollupArtifact',
|
|
245
|
+
convertRootRollupInputsToWitnessMap,
|
|
246
|
+
convertRootRollupOutputsFromWitnessMap,
|
|
247
|
+
);
|
|
238
248
|
|
|
239
249
|
await this.verifyProof('RootRollupArtifact', proof);
|
|
240
250
|
|
|
241
|
-
const result = convertRootRollupOutputsFromWitnessMap(outputWitness);
|
|
242
251
|
return makePublicInputsAndProof(result, proof);
|
|
243
252
|
}
|
|
244
253
|
|
|
245
254
|
// TODO(@PhilWindle): Delete when no longer required
|
|
246
|
-
public async createProof
|
|
255
|
+
public async createProof<Input extends { toBuffer: () => Buffer }, Output extends { toBuffer: () => Buffer }>(
|
|
256
|
+
input: Input,
|
|
257
|
+
circuitType: ServerProtocolArtifact,
|
|
258
|
+
convertInput: (input: Input) => WitnessMap,
|
|
259
|
+
convertOutput: (outputWitness: WitnessMap) => Output,
|
|
260
|
+
): Promise<[Output, Proof]> {
|
|
247
261
|
// Create random directory to be used for temp files
|
|
248
262
|
const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
|
|
249
263
|
await fs.mkdir(bbWorkingDirectory, { recursive: true });
|
|
@@ -265,15 +279,16 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
265
279
|
|
|
266
280
|
logger.debug(`Generating witness data for ${circuitType}`);
|
|
267
281
|
|
|
282
|
+
const witnessMap = convertInput(input);
|
|
268
283
|
const timer = new Timer();
|
|
269
284
|
const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
timer.ms(),
|
|
273
|
-
witnessMap.size * Fr.SIZE_IN_BYTES,
|
|
274
|
-
outputWitness.size * Fr.SIZE_IN_BYTES,
|
|
275
|
-
|
|
276
|
-
);
|
|
285
|
+
logger.debug(`Generated witness`, {
|
|
286
|
+
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
|
|
287
|
+
duration: timer.ms(),
|
|
288
|
+
inputSize: witnessMap.size * Fr.SIZE_IN_BYTES,
|
|
289
|
+
outputSize: outputWitness.size * Fr.SIZE_IN_BYTES,
|
|
290
|
+
eventName: 'circuit-witness-generation',
|
|
291
|
+
} satisfies CircuitWitnessGenerationStats);
|
|
277
292
|
|
|
278
293
|
// Now prove the circuit from the generated witness
|
|
279
294
|
logger.debug(`Proving ${circuitType}...`);
|
|
@@ -293,38 +308,51 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
293
308
|
}
|
|
294
309
|
|
|
295
310
|
// Ensure our vk cache is up to date
|
|
296
|
-
await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
|
|
311
|
+
const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
|
|
297
312
|
|
|
298
313
|
// Read the proof and then cleanup up our temporary directory
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
// does not include reading the proof from disk above because duration comes from the bb wrapper
|
|
302
|
-
emitCircuitProvingStats(
|
|
303
|
-
circuitTypeToCircuitName(circuitType),
|
|
304
|
-
provingResult.duration,
|
|
305
|
-
witnessMap.size * Fr.SIZE_IN_BYTES,
|
|
306
|
-
outputWitness.size * Fr.SIZE_IN_BYTES,
|
|
307
|
-
proof.length,
|
|
308
|
-
logger,
|
|
309
|
-
);
|
|
314
|
+
const rawProof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);
|
|
310
315
|
|
|
311
316
|
await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
|
|
312
317
|
|
|
313
|
-
|
|
318
|
+
const output = convertOutput(outputWitness);
|
|
319
|
+
const proof = new Proof(rawProof);
|
|
320
|
+
logger.info(
|
|
321
|
+
`Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.buffer.length} fields`,
|
|
322
|
+
{
|
|
323
|
+
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
|
|
324
|
+
// does not include reading the proof from disk
|
|
325
|
+
duration: provingResult.duration,
|
|
326
|
+
proofSize: proof.buffer.length,
|
|
327
|
+
eventName: 'circuit-proving',
|
|
328
|
+
inputSize: input.toBuffer().length,
|
|
329
|
+
outputSize: output.toBuffer().length,
|
|
330
|
+
circuitSize: vkData.circuitSize,
|
|
331
|
+
numPublicInputs: vkData.numPublicInputs,
|
|
332
|
+
} satisfies CircuitProvingStats,
|
|
333
|
+
);
|
|
314
334
|
|
|
315
|
-
return [
|
|
335
|
+
return [output, proof];
|
|
316
336
|
}
|
|
317
337
|
|
|
318
338
|
/**
|
|
319
339
|
* Executes a circuit and returns it's outputs and corresponding proof with embedded aggregation object
|
|
320
340
|
* @param witnessMap - The input witness
|
|
321
341
|
* @param circuitType - The type of circuit to be executed
|
|
342
|
+
* @param proofLength - The length of the proof to be generated. This is a dummy parameter to aid in type checking
|
|
343
|
+
* @param convertInput - Function for mapping the input object to a witness map.
|
|
322
344
|
* @param convertOutput - Function for parsing the output witness to it's corresponding object
|
|
323
345
|
* @returns The circuits output object and it's proof
|
|
324
346
|
*/
|
|
325
|
-
public async createRecursiveProof<
|
|
326
|
-
|
|
347
|
+
public async createRecursiveProof<
|
|
348
|
+
PROOF_LENGTH extends number,
|
|
349
|
+
CircuitInputType extends { toBuffer: () => Buffer },
|
|
350
|
+
CircuitOutputType extends { toBuffer: () => Buffer },
|
|
351
|
+
>(
|
|
352
|
+
input: CircuitInputType,
|
|
327
353
|
circuitType: ServerProtocolArtifact,
|
|
354
|
+
proofLength: PROOF_LENGTH,
|
|
355
|
+
convertInput: (input: CircuitInputType) => WitnessMap,
|
|
328
356
|
convertOutput: (outputWitness: WitnessMap) => CircuitOutputType,
|
|
329
357
|
): Promise<[CircuitOutputType, RecursiveProof<PROOF_LENGTH>]> {
|
|
330
358
|
// Create random directory to be used for temp files
|
|
@@ -350,17 +378,20 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
350
378
|
logger.debug(`Generating witness data for ${circuitType}`);
|
|
351
379
|
|
|
352
380
|
const timer = new Timer();
|
|
381
|
+
const witnessMap = convertInput(input);
|
|
353
382
|
const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
|
|
354
383
|
|
|
355
|
-
|
|
356
|
-
circuitTypeToCircuitName(circuitType),
|
|
357
|
-
timer.ms(),
|
|
358
|
-
witnessMap.size * Fr.SIZE_IN_BYTES,
|
|
359
|
-
outputWitness.size * Fr.SIZE_IN_BYTES,
|
|
360
|
-
logger,
|
|
361
|
-
);
|
|
384
|
+
const output = convertOutput(outputWitness);
|
|
362
385
|
|
|
363
|
-
const
|
|
386
|
+
const inputSize = input.toBuffer().length;
|
|
387
|
+
const outputSize = output.toBuffer().length;
|
|
388
|
+
logger.debug(`Generated witness`, {
|
|
389
|
+
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
|
|
390
|
+
duration: timer.ms(),
|
|
391
|
+
inputSize,
|
|
392
|
+
outputSize,
|
|
393
|
+
eventName: 'circuit-witness-generation',
|
|
394
|
+
} satisfies CircuitWitnessGenerationStats);
|
|
364
395
|
|
|
365
396
|
// Now prove the circuit from the generated witness
|
|
366
397
|
logger.debug(`Proving ${circuitType}...`);
|
|
@@ -380,25 +411,26 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
380
411
|
}
|
|
381
412
|
|
|
382
413
|
// Ensure our vk cache is up to date
|
|
383
|
-
await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
|
|
414
|
+
const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
|
|
384
415
|
|
|
385
416
|
// Read the proof and then cleanup up our temporary directory
|
|
386
|
-
const proof = await this.readProofAsFields
|
|
417
|
+
const proof = await this.readProofAsFields(provingResult.proofPath!, circuitType, proofLength);
|
|
387
418
|
|
|
388
419
|
logger.info(
|
|
389
420
|
`Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.proof.length} fields`,
|
|
421
|
+
{
|
|
422
|
+
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
|
|
423
|
+
circuitSize: vkData.circuitSize,
|
|
424
|
+
duration: provingResult.duration,
|
|
425
|
+
inputSize,
|
|
426
|
+
outputSize,
|
|
427
|
+
proofSize: proof.binaryProof.buffer.length,
|
|
428
|
+
eventName: 'circuit-proving',
|
|
429
|
+
numPublicInputs: vkData.numPublicInputs,
|
|
430
|
+
} satisfies CircuitProvingStats,
|
|
390
431
|
);
|
|
391
432
|
|
|
392
|
-
|
|
393
|
-
circuitTypeToCircuitName(circuitType),
|
|
394
|
-
provingResult.duration,
|
|
395
|
-
witnessMap.size * Fr.SIZE_IN_BYTES,
|
|
396
|
-
outputWitness.size * Fr.SIZE_IN_BYTES,
|
|
397
|
-
proof.binaryProof.buffer.length,
|
|
398
|
-
logger,
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
return [outputType, proof];
|
|
433
|
+
return [output, proof];
|
|
402
434
|
} finally {
|
|
403
435
|
await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
|
|
404
436
|
}
|
|
@@ -515,13 +547,16 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
515
547
|
* @param filePath - The directory containing the verification key data files
|
|
516
548
|
* @param circuitType - The type of circuit to which the verification key corresponds
|
|
517
549
|
*/
|
|
518
|
-
private async updateVerificationKeyAfterProof(
|
|
550
|
+
private async updateVerificationKeyAfterProof(
|
|
551
|
+
filePath: string,
|
|
552
|
+
circuitType: ServerProtocolArtifact,
|
|
553
|
+
): Promise<VerificationKeyData> {
|
|
519
554
|
let promise = this.verificationKeys.get(circuitType);
|
|
520
555
|
if (!promise) {
|
|
521
556
|
promise = this.convertVk(filePath);
|
|
522
557
|
this.verificationKeys.set(circuitType, promise);
|
|
523
558
|
}
|
|
524
|
-
|
|
559
|
+
return promise;
|
|
525
560
|
}
|
|
526
561
|
|
|
527
562
|
/**
|
|
@@ -533,6 +568,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
533
568
|
private async readProofAsFields<PROOF_LENGTH extends number>(
|
|
534
569
|
filePath: string,
|
|
535
570
|
circuitType: ServerProtocolArtifact,
|
|
571
|
+
proofLength: PROOF_LENGTH,
|
|
536
572
|
): Promise<RecursiveProof<PROOF_LENGTH>> {
|
|
537
573
|
const [binaryProof, proofString] = await Promise.all([
|
|
538
574
|
fs.readFile(`${filePath}/${PROOF_FILENAME}`),
|
|
@@ -552,6 +588,10 @@ export class BBNativeRollupProver implements ServerCircuitProver {
|
|
|
552
588
|
`Circuit type: ${circuitType}, complete proof length: ${fields.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`,
|
|
553
589
|
);
|
|
554
590
|
const proof = new RecursiveProof<PROOF_LENGTH>(fieldsWithoutPublicInputs, new Proof(binaryProof));
|
|
591
|
+
if (proof.proof.length !== proofLength) {
|
|
592
|
+
throw new Error("Proof length doesn't match expected length");
|
|
593
|
+
}
|
|
594
|
+
|
|
555
595
|
return proof;
|
|
556
596
|
}
|
|
557
597
|
}
|