@aztec/bb-prover 0.41.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dest/bb/cli.d.ts.map +1 -1
  2. package/dest/bb/cli.js +24 -2
  3. package/dest/bb/execute.d.ts +30 -1
  4. package/dest/bb/execute.d.ts.map +1 -1
  5. package/dest/bb/execute.js +252 -60
  6. package/dest/config.d.ts +9 -0
  7. package/dest/config.d.ts.map +1 -0
  8. package/dest/config.js +2 -0
  9. package/dest/index.d.ts +2 -0
  10. package/dest/index.d.ts.map +1 -1
  11. package/dest/index.js +3 -1
  12. package/dest/mappings/mappings.d.ts +1 -0
  13. package/dest/mappings/mappings.d.ts.map +1 -1
  14. package/dest/mappings/mappings.js +27 -8
  15. package/dest/prover/bb_native_proof_creator.d.ts +2 -8
  16. package/dest/prover/bb_native_proof_creator.d.ts.map +1 -1
  17. package/dest/prover/bb_native_proof_creator.js +37 -79
  18. package/dest/prover/bb_prover.d.ts +33 -32
  19. package/dest/prover/bb_prover.d.ts.map +1 -1
  20. package/dest/prover/bb_prover.js +231 -162
  21. package/dest/stats.d.ts.map +1 -1
  22. package/dest/stats.js +8 -2
  23. package/dest/test/index.d.ts +1 -0
  24. package/dest/test/index.d.ts.map +1 -1
  25. package/dest/test/index.js +2 -1
  26. package/dest/test/test_circuit_prover.d.ts +9 -7
  27. package/dest/test/test_circuit_prover.d.ts.map +1 -1
  28. package/dest/test/test_circuit_prover.js +32 -16
  29. package/dest/test/test_verifier.d.ts +7 -0
  30. package/dest/test/test_verifier.d.ts.map +1 -0
  31. package/dest/test/test_verifier.js +10 -0
  32. package/dest/verification_key/verification_key_data.d.ts +8 -0
  33. package/dest/verification_key/verification_key_data.d.ts.map +1 -0
  34. package/dest/verification_key/verification_key_data.js +24 -0
  35. package/dest/verifier/bb_verifier.d.ts +18 -0
  36. package/dest/verifier/bb_verifier.d.ts.map +1 -0
  37. package/dest/verifier/bb_verifier.js +90 -0
  38. package/dest/verifier/index.d.ts +2 -0
  39. package/dest/verifier/index.d.ts.map +1 -0
  40. package/dest/verifier/index.js +2 -0
  41. package/package.json +6 -6
  42. package/src/bb/cli.ts +36 -1
  43. package/src/bb/execute.ts +340 -67
  44. package/src/config.ts +9 -0
  45. package/src/index.ts +2 -0
  46. package/src/mappings/mappings.ts +38 -12
  47. package/src/prover/bb_native_proof_creator.ts +49 -91
  48. package/src/prover/bb_prover.ts +396 -221
  49. package/src/stats.ts +7 -1
  50. package/src/test/index.ts +1 -0
  51. package/src/test/test_circuit_prover.ts +85 -23
  52. package/src/test/test_verifier.ts +12 -0
  53. package/src/verification_key/verification_key_data.ts +35 -0
  54. package/src/verifier/bb_verifier.ts +156 -0
  55. package/src/verifier/index.ts +1 -0
  56. package/dest/prover/verification_key_data.d.ts +0 -16
  57. package/dest/prover/verification_key_data.d.ts.map +0 -1
  58. package/dest/prover/verification_key_data.js +0 -5
  59. package/src/prover/verification_key_data.ts +0 -16
@@ -1,39 +1,44 @@
1
1
  /* eslint-disable require-await */
2
2
  import {
3
- type PublicInputsAndProof,
3
+ type ProofAndVerificationKey,
4
+ type PublicInputsAndRecursiveProof,
4
5
  type PublicKernelNonTailRequest,
5
6
  type PublicKernelTailRequest,
6
- PublicKernelType,
7
7
  type ServerCircuitProver,
8
- makePublicInputsAndProof,
8
+ makePublicInputsAndRecursiveProof,
9
9
  } from '@aztec/circuit-types';
10
10
  import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
11
11
  import {
12
+ AGGREGATION_OBJECT_LENGTH,
13
+ type AvmCircuitInputs,
12
14
  type BaseOrMergeRollupPublicInputs,
13
15
  type BaseParityInputs,
14
16
  type BaseRollupInputs,
17
+ EmptyNestedCircuitInputs,
18
+ EmptyNestedData,
15
19
  Fr,
16
20
  type KernelCircuitPublicInputs,
17
21
  type MergeRollupInputs,
18
22
  NESTED_RECURSIVE_PROOF_LENGTH,
19
- type PreviousRollupData,
23
+ type PrivateKernelEmptyInputData,
24
+ PrivateKernelEmptyInputs,
20
25
  Proof,
21
26
  type PublicKernelCircuitPublicInputs,
22
27
  RECURSIVE_PROOF_LENGTH,
23
28
  RecursiveProof,
24
- RollupTypes,
25
29
  RootParityInput,
26
30
  type RootParityInputs,
27
31
  type RootRollupInputs,
28
32
  type RootRollupPublicInputs,
29
- type VERIFICATION_KEY_LENGTH_IN_FIELDS,
30
- VerificationKeyAsFields,
33
+ type VerificationKeyAsFields,
34
+ type VerificationKeyData,
35
+ makeRecursiveProofFromBinary,
31
36
  } from '@aztec/circuits.js';
32
- import { randomBytes } from '@aztec/foundation/crypto';
37
+ import { runInDirectory } from '@aztec/foundation/fs';
33
38
  import { createDebugLogger } from '@aztec/foundation/log';
34
- import { type Tuple } from '@aztec/foundation/serialize';
35
39
  import { Timer } from '@aztec/foundation/timer';
36
40
  import {
41
+ EmptyNestedArtifact,
37
42
  ServerCircuitArtifacts,
38
43
  type ServerProtocolArtifact,
39
44
  convertBaseParityInputsToWitnessMap,
@@ -42,6 +47,8 @@ import {
42
47
  convertBaseRollupOutputsFromWitnessMap,
43
48
  convertMergeRollupInputsToWitnessMap,
44
49
  convertMergeRollupOutputsFromWitnessMap,
50
+ convertPrivateKernelEmptyInputsToWitnessMap,
51
+ convertPrivateKernelEmptyOutputsFromWitnessMap,
45
52
  convertPublicTailInputsToWitnessMap,
46
53
  convertPublicTailOutputFromWitnessMap,
47
54
  convertRootParityInputsToWitnessMap,
@@ -51,41 +58,41 @@ import {
51
58
  } from '@aztec/noir-protocol-circuits-types';
52
59
  import { NativeACVMSimulator } from '@aztec/simulator';
53
60
 
54
- import { type WitnessMap } from '@noir-lang/types';
61
+ import { abiEncode } from '@noir-lang/noirc_abi';
62
+ import { type Abi, type WitnessMap } from '@noir-lang/types';
55
63
  import * as fs from 'fs/promises';
64
+ import * as path from 'path';
56
65
 
57
66
  import {
67
+ type BBSuccess,
58
68
  BB_RESULT,
59
69
  PROOF_FIELDS_FILENAME,
60
70
  PROOF_FILENAME,
61
- VK_FIELDS_FILENAME,
62
71
  VK_FILENAME,
72
+ type VerificationFunction,
73
+ generateAvmProof,
63
74
  generateKeyForNoirCircuit,
64
75
  generateProof,
76
+ verifyAvmProof,
65
77
  verifyProof,
78
+ writeProofAsFields,
66
79
  } from '../bb/execute.js';
80
+ import type { ACVMConfig, BBConfig } from '../config.js';
67
81
  import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
68
82
  import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
69
- import {
70
- AGGREGATION_OBJECT_SIZE,
71
- CIRCUIT_PUBLIC_INPUTS_INDEX,
72
- CIRCUIT_RECURSIVE_INDEX,
73
- CIRCUIT_SIZE_INDEX,
74
- type VerificationKeyData,
75
- } from './verification_key_data.js';
83
+ import { extractVkData } from '../verification_key/verification_key_data.js';
76
84
 
77
85
  const logger = createDebugLogger('aztec:bb-prover');
78
86
 
79
- const CIRCUITS_WITHOUT_AGGREGATION: Set<ServerProtocolArtifact> = new Set(['BaseParityArtifact']);
87
+ const CIRCUITS_WITHOUT_AGGREGATION: Set<ServerProtocolArtifact> = new Set([
88
+ 'BaseParityArtifact',
89
+ 'EmptyNestedArtifact',
90
+ ]);
80
91
 
81
- export type BBProverConfig = {
82
- bbBinaryPath: string;
83
- bbWorkingDirectory: string;
84
- acvmBinaryPath: string;
85
- acvmWorkingDirectory: string;
92
+ export interface BBProverConfig extends BBConfig, ACVMConfig {
86
93
  // list of circuits supported by this prover. defaults to all circuits if empty
87
94
  circuitFilter?: ServerProtocolArtifact[];
88
- };
95
+ }
89
96
 
90
97
  /**
91
98
  * Prover implementation that uses barretenberg native proving
@@ -114,7 +121,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
114
121
  * @returns The public inputs of the parity circuit.
115
122
  */
116
123
  public async getBaseParityProof(inputs: BaseParityInputs): Promise<RootParityInput<typeof RECURSIVE_PROOF_LENGTH>> {
117
- const [circuitOutput, proof] = await this.createRecursiveProof(
124
+ const { circuitOutput, proof } = await this.createRecursiveProof(
118
125
  inputs,
119
126
  'BaseParityArtifact',
120
127
  RECURSIVE_PROOF_LENGTH,
@@ -124,9 +131,9 @@ export class BBNativeRollupProver implements ServerCircuitProver {
124
131
 
125
132
  const verificationKey = await this.getVerificationKeyDataForCircuit('BaseParityArtifact');
126
133
 
127
- const vk = new VerificationKeyAsFields(verificationKey.keyAsFields, verificationKey.hash);
134
+ await this.verifyProof('BaseParityArtifact', proof.binaryProof);
128
135
 
129
- return new RootParityInput(proof, vk, circuitOutput);
136
+ return new RootParityInput(proof, verificationKey.keyAsFields, circuitOutput);
130
137
  }
131
138
 
132
139
  /**
@@ -137,7 +144,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
137
144
  public async getRootParityProof(
138
145
  inputs: RootParityInputs,
139
146
  ): Promise<RootParityInput<typeof NESTED_RECURSIVE_PROOF_LENGTH>> {
140
- const [circuitOutput, proof] = await this.createRecursiveProof(
147
+ const { circuitOutput, proof } = await this.createRecursiveProof(
141
148
  inputs,
142
149
  'RootParityArtifact',
143
150
  NESTED_RECURSIVE_PROOF_LENGTH,
@@ -147,9 +154,20 @@ export class BBNativeRollupProver implements ServerCircuitProver {
147
154
 
148
155
  const verificationKey = await this.getVerificationKeyDataForCircuit('RootParityArtifact');
149
156
 
150
- const vk = new VerificationKeyAsFields(verificationKey.keyAsFields, verificationKey.hash);
157
+ await this.verifyProof('RootParityArtifact', proof.binaryProof);
158
+
159
+ return new RootParityInput(proof, verificationKey.keyAsFields, circuitOutput);
160
+ }
151
161
 
152
- return new RootParityInput(proof, vk, circuitOutput);
162
+ /**
163
+ * Creates an AVM proof and verifies it.
164
+ * @param inputs - The inputs to the AVM circuit.
165
+ * @returns The proof.
166
+ */
167
+ public async getAvmProof(inputs: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
168
+ const proofAndVk = await this.createAvmProof(inputs);
169
+ await this.verifyAvmProof(proofAndVk.proof, proofAndVk.verificationKey);
170
+ return proofAndVk;
153
171
  }
154
172
 
155
173
  /**
@@ -159,19 +177,37 @@ export class BBNativeRollupProver implements ServerCircuitProver {
159
177
  */
160
178
  public async getPublicKernelProof(
161
179
  kernelRequest: PublicKernelNonTailRequest,
162
- ): Promise<PublicInputsAndProof<PublicKernelCircuitPublicInputs>> {
180
+ ): Promise<PublicInputsAndRecursiveProof<PublicKernelCircuitPublicInputs>> {
163
181
  const kernelOps = PublicKernelArtifactMapping[kernelRequest.type];
164
182
  if (kernelOps === undefined) {
165
- throw new Error(`Unable to prove kernel type ${PublicKernelType[kernelRequest.type]}`);
183
+ throw new Error(`Unable to prove kernel type ${kernelRequest.type}`);
166
184
  }
167
- const [result, proof] = await this.createProof(
185
+
186
+ // We may need to convert the recursive proof into fields format
187
+ kernelRequest.inputs.previousKernel.proof = await this.ensureValidProof(
188
+ kernelRequest.inputs.previousKernel.proof,
189
+ kernelOps.artifact,
190
+ kernelRequest.inputs.previousKernel.vk,
191
+ );
192
+
193
+ await this.verifyWithKey(
194
+ kernelRequest.inputs.previousKernel.vk,
195
+ kernelRequest.inputs.previousKernel.proof.binaryProof,
196
+ );
197
+
198
+ const { circuitOutput, proof } = await this.createRecursiveProof(
168
199
  kernelRequest.inputs,
169
200
  kernelOps.artifact,
201
+ NESTED_RECURSIVE_PROOF_LENGTH,
170
202
  kernelOps.convertInputs,
171
203
  kernelOps.convertOutputs,
172
204
  );
173
205
 
174
- return makePublicInputsAndProof(result, proof);
206
+ const verificationKey = await this.getVerificationKeyDataForCircuit(kernelOps.artifact);
207
+
208
+ await this.verifyProof(kernelOps.artifact, proof.binaryProof);
209
+
210
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
175
211
  }
176
212
 
177
213
  /**
@@ -181,15 +217,20 @@ export class BBNativeRollupProver implements ServerCircuitProver {
181
217
  */
182
218
  public async getPublicTailProof(
183
219
  kernelRequest: PublicKernelTailRequest,
184
- ): Promise<PublicInputsAndProof<KernelCircuitPublicInputs>> {
185
- const [result, proof] = await this.createProof(
220
+ ): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>> {
221
+ const { circuitOutput, proof } = await this.createRecursiveProof(
186
222
  kernelRequest.inputs,
187
223
  'PublicKernelTailArtifact',
224
+ NESTED_RECURSIVE_PROOF_LENGTH,
188
225
  convertPublicTailInputsToWitnessMap,
189
226
  convertPublicTailOutputFromWitnessMap,
190
227
  );
191
228
 
192
- return makePublicInputsAndProof(result, proof);
229
+ const verificationKey = await this.getVerificationKeyDataForCircuit('PublicKernelTailArtifact');
230
+
231
+ await this.verifyProof('PublicKernelTailArtifact', proof.binaryProof);
232
+
233
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
193
234
  }
194
235
 
195
236
  /**
@@ -199,16 +240,29 @@ export class BBNativeRollupProver implements ServerCircuitProver {
199
240
  */
200
241
  public async getBaseRollupProof(
201
242
  input: BaseRollupInputs,
202
- ): Promise<PublicInputsAndProof<BaseOrMergeRollupPublicInputs>> {
203
- const [result, proof] = await this.createProof(
243
+ ): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>> {
244
+ // We may need to convert the recursive proof into fields format
245
+ input.kernelData.proof = await this.ensureValidProof(
246
+ input.kernelData.proof,
247
+ 'BaseRollupArtifact',
248
+ input.kernelData.vk,
249
+ );
250
+
251
+ const { circuitOutput, proof } = await this.createRecursiveProof(
204
252
  input,
205
253
  'BaseRollupArtifact',
254
+ NESTED_RECURSIVE_PROOF_LENGTH,
206
255
  convertBaseRollupInputsToWitnessMap,
207
256
  convertBaseRollupOutputsFromWitnessMap,
208
257
  );
209
258
 
210
- return makePublicInputsAndProof(result, proof);
259
+ const verificationKey = await this.getVerificationKeyDataForCircuit('BaseRollupArtifact');
260
+
261
+ await this.verifyProof('BaseRollupArtifact', proof.binaryProof);
262
+
263
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
211
264
  }
265
+
212
266
  /**
213
267
  * Simulates the merge rollup circuit from its inputs.
214
268
  * @param input - Inputs to the circuit.
@@ -216,18 +270,20 @@ export class BBNativeRollupProver implements ServerCircuitProver {
216
270
  */
217
271
  public async getMergeRollupProof(
218
272
  input: MergeRollupInputs,
219
- ): Promise<PublicInputsAndProof<BaseOrMergeRollupPublicInputs>> {
220
- // verify both inputs
221
- await Promise.all(input.previousRollupData.map(prev => this.verifyPreviousRollupProof(prev)));
222
-
223
- const [result, proof] = await this.createProof(
273
+ ): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>> {
274
+ const { circuitOutput, proof } = await this.createRecursiveProof(
224
275
  input,
225
276
  'MergeRollupArtifact',
277
+ NESTED_RECURSIVE_PROOF_LENGTH,
226
278
  convertMergeRollupInputsToWitnessMap,
227
279
  convertMergeRollupOutputsFromWitnessMap,
228
280
  );
229
281
 
230
- return makePublicInputsAndProof(result, proof);
282
+ const verificationKey = await this.getVerificationKeyDataForCircuit('MergeRollupArtifact');
283
+
284
+ await this.verifyProof('MergeRollupArtifact', proof.binaryProof);
285
+
286
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
231
287
  }
232
288
 
233
289
  /**
@@ -235,37 +291,84 @@ export class BBNativeRollupProver implements ServerCircuitProver {
235
291
  * @param input - Inputs to the circuit.
236
292
  * @returns The public inputs as outputs of the simulation.
237
293
  */
238
- public async getRootRollupProof(input: RootRollupInputs): Promise<PublicInputsAndProof<RootRollupPublicInputs>> {
239
- // verify the inputs
240
- await Promise.all(input.previousRollupData.map(prev => this.verifyPreviousRollupProof(prev)));
241
-
242
- const [result, proof] = await this.createProof(
294
+ public async getRootRollupProof(
295
+ input: RootRollupInputs,
296
+ ): Promise<PublicInputsAndRecursiveProof<RootRollupPublicInputs>> {
297
+ const { circuitOutput, proof } = await this.createProof(
243
298
  input,
244
299
  'RootRollupArtifact',
245
300
  convertRootRollupInputsToWitnessMap,
246
301
  convertRootRollupOutputsFromWitnessMap,
247
302
  );
248
303
 
304
+ const recursiveProof = makeRecursiveProofFromBinary(proof, NESTED_RECURSIVE_PROOF_LENGTH);
305
+
306
+ const verificationKey = await this.getVerificationKeyDataForCircuit('RootRollupArtifact');
307
+
249
308
  await this.verifyProof('RootRollupArtifact', proof);
250
309
 
251
- return makePublicInputsAndProof(result, proof);
310
+ return makePublicInputsAndRecursiveProof(circuitOutput, recursiveProof, verificationKey);
252
311
  }
253
312
 
254
- // TODO(@PhilWindle): Delete when no longer required
255
- public async createProof<Input extends { toBuffer: () => Buffer }, Output extends { toBuffer: () => Buffer }>(
313
+ public async getEmptyPrivateKernelProof(
314
+ inputs: PrivateKernelEmptyInputData,
315
+ ): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>> {
316
+ const emptyNested = await this.getEmptyNestedProof();
317
+ const emptyPrivateKernelProof = await this.getEmptyPrivateKernelProofFromEmptyNested(
318
+ PrivateKernelEmptyInputs.from({
319
+ ...inputs,
320
+ emptyNested,
321
+ }),
322
+ );
323
+
324
+ return emptyPrivateKernelProof;
325
+ }
326
+
327
+ private async getEmptyNestedProof(): Promise<EmptyNestedData> {
328
+ const inputs = new EmptyNestedCircuitInputs();
329
+ const { proof } = await this.createRecursiveProof(
330
+ inputs,
331
+ 'EmptyNestedArtifact',
332
+ RECURSIVE_PROOF_LENGTH,
333
+ (nothing: any) => abiEncode(EmptyNestedArtifact.abi as Abi, { _inputs: nothing as any }),
334
+ () => new EmptyNestedCircuitInputs(),
335
+ );
336
+
337
+ const verificationKey = await this.getVerificationKeyDataForCircuit('EmptyNestedArtifact');
338
+ await this.verifyProof('EmptyNestedArtifact', proof.binaryProof);
339
+
340
+ return new EmptyNestedData(proof, verificationKey.keyAsFields);
341
+ }
342
+
343
+ private async getEmptyPrivateKernelProofFromEmptyNested(
344
+ inputs: PrivateKernelEmptyInputs,
345
+ ): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>> {
346
+ const { circuitOutput, proof } = await this.createRecursiveProof(
347
+ inputs,
348
+ 'PrivateKernelEmptyArtifact',
349
+ NESTED_RECURSIVE_PROOF_LENGTH,
350
+ convertPrivateKernelEmptyInputsToWitnessMap,
351
+ convertPrivateKernelEmptyOutputsFromWitnessMap,
352
+ );
353
+
354
+ const verificationKey = await this.getVerificationKeyDataForCircuit('PrivateKernelEmptyArtifact');
355
+ await this.verifyProof('PrivateKernelEmptyArtifact', proof.binaryProof);
356
+
357
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
358
+ }
359
+
360
+ private async generateProofWithBB<
361
+ Input extends { toBuffer: () => Buffer },
362
+ Output extends { toBuffer: () => Buffer },
363
+ >(
256
364
  input: Input,
257
365
  circuitType: ServerProtocolArtifact,
258
366
  convertInput: (input: Input) => WitnessMap,
259
367
  convertOutput: (outputWitness: WitnessMap) => Output,
260
- ): Promise<[Output, Proof]> {
261
- // Create random directory to be used for temp files
262
- const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
263
- await fs.mkdir(bbWorkingDirectory, { recursive: true });
264
-
265
- await fs.access(bbWorkingDirectory);
266
-
368
+ workingDirectory: string,
369
+ ): Promise<{ circuitOutput: Output; vkData: VerificationKeyData; provingResult: BBSuccess }> {
267
370
  // Have the ACVM write the partial witness here
268
- const outputWitnessFile = `${bbWorkingDirectory}/partial-witness.gz`;
371
+ const outputWitnessFile = path.join(workingDirectory, 'partial-witness.gz');
269
372
 
270
373
  // Generate the partial witness using the ACVM
271
374
  // A further temp directory will be created beneath ours and then cleaned up after the partial witness has been copied to our specified location
@@ -279,14 +382,16 @@ export class BBNativeRollupProver implements ServerCircuitProver {
279
382
 
280
383
  logger.debug(`Generating witness data for ${circuitType}`);
281
384
 
282
- const witnessMap = convertInput(input);
385
+ const inputWitness = convertInput(input);
283
386
  const timer = new Timer();
284
- const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
387
+ const outputWitness = await simulator.simulateCircuit(inputWitness, artifact);
388
+ const witnessGenerationDuration = timer.ms();
389
+ const output = convertOutput(outputWitness);
285
390
  logger.debug(`Generated witness`, {
286
391
  circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
287
- duration: timer.ms(),
288
- inputSize: witnessMap.size * Fr.SIZE_IN_BYTES,
289
- outputSize: outputWitness.size * Fr.SIZE_IN_BYTES,
392
+ duration: witnessGenerationDuration,
393
+ inputSize: input.toBuffer().length,
394
+ outputSize: output.toBuffer().length,
290
395
  eventName: 'circuit-witness-generation',
291
396
  } satisfies CircuitWitnessGenerationStats);
292
397
 
@@ -295,7 +400,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
295
400
 
296
401
  const provingResult = await generateProof(
297
402
  this.config.bbBinaryPath,
298
- bbWorkingDirectory,
403
+ workingDirectory,
299
404
  circuitType,
300
405
  Buffer.from(artifact.bytecode, 'base64'),
301
406
  outputWitnessFile,
@@ -310,29 +415,99 @@ export class BBNativeRollupProver implements ServerCircuitProver {
310
415
  // Ensure our vk cache is up to date
311
416
  const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
312
417
 
313
- // Read the proof and then cleanup up our temporary directory
314
- const rawProof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);
418
+ return {
419
+ circuitOutput: output,
420
+ vkData,
421
+ provingResult,
422
+ };
423
+ }
424
+
425
+ private async createProof<Input extends { toBuffer: () => Buffer }, Output extends { toBuffer: () => Buffer }>(
426
+ input: Input,
427
+ circuitType: ServerProtocolArtifact,
428
+ convertInput: (input: Input) => WitnessMap,
429
+ convertOutput: (outputWitness: WitnessMap) => Output,
430
+ ): Promise<{ circuitOutput: Output; proof: Proof }> {
431
+ const operation = async (bbWorkingDirectory: string) => {
432
+ const {
433
+ provingResult,
434
+ vkData,
435
+ circuitOutput: output,
436
+ } = await this.generateProofWithBB(input, circuitType, convertInput, convertOutput, bbWorkingDirectory);
437
+
438
+ // Read the binary proof
439
+ const rawProof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);
440
+
441
+ const proof = new Proof(rawProof, vkData.numPublicInputs);
442
+ logger.info(
443
+ `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
444
+ proof.buffer.length
445
+ } bytes`,
446
+ {
447
+ circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
448
+ // does not include reading the proof from disk
449
+ duration: provingResult.duration,
450
+ proofSize: proof.buffer.length,
451
+ eventName: 'circuit-proving',
452
+ // circuitOutput is the partial witness that became the input to the proof
453
+ inputSize: output.toBuffer().length,
454
+ circuitSize: vkData.circuitSize,
455
+ numPublicInputs: vkData.numPublicInputs,
456
+ } satisfies CircuitProvingStats,
457
+ );
315
458
 
316
- await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
459
+ return { circuitOutput: output, proof };
460
+ };
461
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
462
+ }
317
463
 
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
- );
464
+ private async generateAvmProofWithBB(input: AvmCircuitInputs, workingDirectory: string): Promise<BBSuccess> {
465
+ logger.debug(`Proving avm-circuit...`);
466
+
467
+ const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.verbose);
334
468
 
335
- return [output, proof];
469
+ if (provingResult.status === BB_RESULT.FAILURE) {
470
+ logger.error(`Failed to generate proof for avm-circuit: ${provingResult.reason}`);
471
+ throw new Error(provingResult.reason);
472
+ }
473
+
474
+ return provingResult;
475
+ }
476
+
477
+ private async createAvmProof(input: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
478
+ const cleanupDir: boolean = !process.env.AVM_PROVING_PRESERVE_WORKING_DIR;
479
+ const operation = async (bbWorkingDirectory: string): Promise<ProofAndVerificationKey> => {
480
+ if (!cleanupDir) {
481
+ logger.info(`Preserving working directory ${bbWorkingDirectory}`);
482
+ }
483
+ const provingResult = await this.generateAvmProofWithBB(input, bbWorkingDirectory);
484
+
485
+ const rawProof = await fs.readFile(provingResult.proofPath!);
486
+ // TODO(https://github.com/AztecProtocol/aztec-packages/issues/6773): this VK data format is wrong.
487
+ // In particular, the number of public inputs, etc will be wrong.
488
+ const verificationKey = await extractVkData(provingResult.vkPath!);
489
+ const proof = new Proof(rawProof, verificationKey.numPublicInputs);
490
+
491
+ const circuitType = 'avm-circuit' as const;
492
+ logger.info(
493
+ `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
494
+ proof.buffer.length
495
+ } bytes`,
496
+ {
497
+ circuitName: circuitType,
498
+ // does not include reading the proof from disk
499
+ duration: provingResult.duration,
500
+ proofSize: proof.buffer.length,
501
+ eventName: 'circuit-proving',
502
+ inputSize: input.toBuffer().length,
503
+ circuitSize: verificationKey.circuitSize,
504
+ numPublicInputs: verificationKey.numPublicInputs,
505
+ } satisfies CircuitProvingStats,
506
+ );
507
+
508
+ return { proof, verificationKey };
509
+ };
510
+ return await runInDirectory(this.config.bbWorkingDirectory, operation, cleanupDir);
336
511
  }
337
512
 
338
513
  /**
@@ -344,7 +519,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
344
519
  * @param convertOutput - Function for parsing the output witness to it's corresponding object
345
520
  * @returns The circuits output object and it's proof
346
521
  */
347
- public async createRecursiveProof<
522
+ private async createRecursiveProof<
348
523
  PROOF_LENGTH extends number,
349
524
  CircuitInputType extends { toBuffer: () => Buffer },
350
525
  CircuitOutputType extends { toBuffer: () => Buffer },
@@ -354,86 +529,38 @@ export class BBNativeRollupProver implements ServerCircuitProver {
354
529
  proofLength: PROOF_LENGTH,
355
530
  convertInput: (input: CircuitInputType) => WitnessMap,
356
531
  convertOutput: (outputWitness: WitnessMap) => CircuitOutputType,
357
- ): Promise<[CircuitOutputType, RecursiveProof<PROOF_LENGTH>]> {
358
- // Create random directory to be used for temp files
359
- const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
360
- await fs.mkdir(bbWorkingDirectory, { recursive: true });
361
-
362
- await fs.access(bbWorkingDirectory);
363
-
364
- try {
365
- // Have the ACVM write the partial witness here
366
- const outputWitnessFile = `${bbWorkingDirectory}/partial-witness.gz`;
367
-
368
- // Generate the partial witness using the ACVM
369
- // A further temp directory will be created beneath ours and then cleaned up after the partial witness has been copied to our specified location
370
- const simulator = new NativeACVMSimulator(
371
- this.config.acvmWorkingDirectory,
372
- this.config.acvmBinaryPath,
373
- outputWitnessFile,
374
- );
375
-
376
- const artifact = ServerCircuitArtifacts[circuitType];
377
-
378
- logger.debug(`Generating witness data for ${circuitType}`);
379
-
380
- const timer = new Timer();
381
- const witnessMap = convertInput(input);
382
- const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
383
-
384
- const output = convertOutput(outputWitness);
385
-
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);
395
-
396
- // Now prove the circuit from the generated witness
397
- logger.debug(`Proving ${circuitType}...`);
398
-
399
- const provingResult = await generateProof(
400
- this.config.bbBinaryPath,
401
- bbWorkingDirectory,
402
- circuitType,
403
- Buffer.from(artifact.bytecode, 'base64'),
404
- outputWitnessFile,
405
- logger.debug,
406
- );
407
-
408
- if (provingResult.status === BB_RESULT.FAILURE) {
409
- logger.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`);
410
- throw new Error(provingResult.reason);
411
- }
412
-
413
- // Ensure our vk cache is up to date
414
- const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
415
-
416
- // Read the proof and then cleanup up our temporary directory
532
+ ): Promise<{ circuitOutput: CircuitOutputType; proof: RecursiveProof<PROOF_LENGTH> }> {
533
+ const operation = async (bbWorkingDirectory: string) => {
534
+ const {
535
+ provingResult,
536
+ vkData,
537
+ circuitOutput: output,
538
+ } = await this.generateProofWithBB(input, circuitType, convertInput, convertOutput, bbWorkingDirectory);
539
+
540
+ // Read the proof as fields
417
541
  const proof = await this.readProofAsFields(provingResult.proofPath!, circuitType, proofLength);
418
542
 
419
543
  logger.info(
420
- `Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.proof.length} fields`,
544
+ `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
545
+ proof.proof.length
546
+ } fields`,
421
547
  {
422
548
  circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
423
549
  circuitSize: vkData.circuitSize,
424
550
  duration: provingResult.duration,
425
- inputSize,
426
- outputSize,
551
+ inputSize: output.toBuffer().length,
427
552
  proofSize: proof.binaryProof.buffer.length,
428
553
  eventName: 'circuit-proving',
429
554
  numPublicInputs: vkData.numPublicInputs,
430
555
  } satisfies CircuitProvingStats,
431
556
  );
432
557
 
433
- return [output, proof];
434
- } finally {
435
- await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
436
- }
558
+ return {
559
+ circuitOutput: output,
560
+ proof,
561
+ };
562
+ };
563
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
437
564
  }
438
565
 
439
566
  /**
@@ -442,33 +569,50 @@ export class BBNativeRollupProver implements ServerCircuitProver {
442
569
  * @param proof - The proof to be verified
443
570
  */
444
571
  public async verifyProof(circuitType: ServerProtocolArtifact, proof: Proof) {
445
- // Create random directory to be used for temp files
446
- const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
447
- await fs.mkdir(bbWorkingDirectory, { recursive: true });
448
-
449
- const proofFileName = `${bbWorkingDirectory}/proof`;
450
- const verificationKeyPath = `${bbWorkingDirectory}/vk`;
451
572
  const verificationKey = await this.getVerificationKeyDataForCircuit(circuitType);
573
+ return await this.verifyWithKey(verificationKey, proof);
574
+ }
452
575
 
453
- logger.debug(`Verifying with key: ${verificationKey.hash.toString()}`);
576
+ public async verifyAvmProof(proof: Proof, verificationKey: VerificationKeyData) {
577
+ return await this.verifyWithKeyInternal(proof, verificationKey, verifyAvmProof);
578
+ }
454
579
 
455
- await fs.writeFile(proofFileName, proof.buffer);
456
- await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes);
580
+ public async verifyWithKey(verificationKey: VerificationKeyData, proof: Proof) {
581
+ return await this.verifyWithKeyInternal(proof, verificationKey, verifyProof);
582
+ }
457
583
 
458
- const logFunction = (message: string) => {
459
- logger.debug(`${circuitType} BB out - ${message}`);
460
- };
584
+ private async verifyWithKeyInternal(
585
+ proof: Proof,
586
+ verificationKey: VerificationKeyData,
587
+ verificationFunction: VerificationFunction,
588
+ ) {
589
+ const operation = async (bbWorkingDirectory: string) => {
590
+ const proofFileName = path.join(bbWorkingDirectory, PROOF_FILENAME);
591
+ const verificationKeyPath = path.join(bbWorkingDirectory, VK_FILENAME);
461
592
 
462
- const result = await verifyProof(this.config.bbBinaryPath, proofFileName, verificationKeyPath!, logFunction);
593
+ await fs.writeFile(proofFileName, proof.buffer);
594
+ await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes);
463
595
 
464
- await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
596
+ const logFunction = (message: string) => {
597
+ logger.debug(`BB out - ${message}`);
598
+ };
465
599
 
466
- if (result.status === BB_RESULT.FAILURE) {
467
- const errorMessage = `Failed to verify ${circuitType} proof!`;
468
- throw new Error(errorMessage);
469
- }
600
+ const result = await verificationFunction(
601
+ this.config.bbBinaryPath,
602
+ proofFileName,
603
+ verificationKeyPath!,
604
+ logFunction,
605
+ );
606
+
607
+ if (result.status === BB_RESULT.FAILURE) {
608
+ const errorMessage = `Failed to verify proof from key!`;
609
+ throw new Error(errorMessage);
610
+ }
611
+
612
+ logger.debug(`Successfully verified proof from key in ${result.duration} ms`);
613
+ };
470
614
 
471
- logger.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`);
615
+ await runInDirectory(this.config.bbWorkingDirectory, operation);
472
616
  }
473
617
 
474
618
  /**
@@ -478,16 +622,66 @@ export class BBNativeRollupProver implements ServerCircuitProver {
478
622
  */
479
623
  public async getVerificationKeyForCircuit(circuitType: ServerProtocolArtifact): Promise<VerificationKeyAsFields> {
480
624
  const vkData = await this.getVerificationKeyDataForCircuit(circuitType);
481
- return new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash);
625
+ return vkData.clone().keyAsFields;
482
626
  }
483
627
 
484
- private async verifyPreviousRollupProof(previousRollupData: PreviousRollupData) {
485
- const proof = previousRollupData.proof;
486
- const circuitType =
487
- previousRollupData.baseOrMergeRollupPublicInputs.rollupType === RollupTypes.Base
488
- ? 'BaseRollupArtifact'
489
- : 'MergeRollupArtifact';
490
- await this.verifyProof(circuitType, proof);
628
+ /**
629
+ * Will check a recursive proof argument for validity of it's 'fields' format of proof and convert if required
630
+ * @param proof - The input proof that may need converting
631
+ * @returns - The valid proof
632
+ */
633
+ public async ensureValidProof(
634
+ proof: RecursiveProof<typeof NESTED_RECURSIVE_PROOF_LENGTH>,
635
+ circuit: ServerProtocolArtifact,
636
+ vk: VerificationKeyData,
637
+ ) {
638
+ // If the 'fields' proof is already valid then simply return
639
+ // This will be false for proofs coming from clients
640
+ if (proof.fieldsValid) {
641
+ return proof;
642
+ }
643
+
644
+ const operation = async (bbWorkingDirectory: string) => {
645
+ const numPublicInputs = vk.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
646
+ const proofFullFilename = path.join(bbWorkingDirectory, PROOF_FILENAME);
647
+ const vkFullFilename = path.join(bbWorkingDirectory, VK_FILENAME);
648
+
649
+ logger.debug(
650
+ `Converting proof to fields format for circuit ${circuit}, directory ${bbWorkingDirectory}, num public inputs: ${vk.numPublicInputs}, proof length ${proof.binaryProof.buffer.length}, vk length ${vk.keyAsBytes.length}`,
651
+ );
652
+
653
+ await fs.writeFile(proofFullFilename, proof.binaryProof.buffer);
654
+ await fs.writeFile(vkFullFilename, vk.keyAsBytes);
655
+
656
+ const logFunction = (message: string) => {
657
+ logger.debug(`${circuit} BB out - ${message}`);
658
+ };
659
+
660
+ const result = await writeProofAsFields(
661
+ this.config.bbBinaryPath,
662
+ bbWorkingDirectory,
663
+ PROOF_FILENAME,
664
+ vkFullFilename,
665
+ logFunction,
666
+ );
667
+
668
+ if (result.status === BB_RESULT.FAILURE) {
669
+ const errorMessage = `Failed to convert ${circuit} proof to fields, ${result.reason}`;
670
+ throw new Error(errorMessage);
671
+ }
672
+
673
+ const proofString = await fs.readFile(path.join(bbWorkingDirectory, PROOF_FIELDS_FILENAME), {
674
+ encoding: 'utf-8',
675
+ });
676
+ const json = JSON.parse(proofString);
677
+ const fields = json.slice(numPublicInputs).map(Fr.fromString);
678
+ return new RecursiveProof<typeof NESTED_RECURSIVE_PROOF_LENGTH>(
679
+ fields,
680
+ new Proof(proof.binaryProof.buffer, vk.numPublicInputs),
681
+ true,
682
+ );
683
+ };
684
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
491
685
  }
492
686
 
493
687
  /**
@@ -509,37 +703,12 @@ export class BBNativeRollupProver implements ServerCircuitProver {
509
703
  if (result.status === BB_RESULT.FAILURE) {
510
704
  throw new Error(`Failed to generate verification key for ${circuitType}, ${result.reason}`);
511
705
  }
512
- return this.convertVk(result.vkPath!);
706
+ return extractVkData(result.vkPath!);
513
707
  });
514
708
  this.verificationKeys.set(circuitType, promise);
515
709
  }
516
- return await promise;
517
- }
518
-
519
- /**
520
- * Reads the verification key data stored at the specified location and parses into a VerificationKeyData
521
- * @param filePath - The directory containing the verification key data files
522
- * @returns The verification key data
523
- */
524
- private async convertVk(filePath: string): Promise<VerificationKeyData> {
525
- const [rawFields, rawBinary] = await Promise.all([
526
- fs.readFile(`${filePath}/${VK_FIELDS_FILENAME}`, { encoding: 'utf-8' }),
527
- fs.readFile(`${filePath}/${VK_FILENAME}`),
528
- ]);
529
- const fieldsJson = JSON.parse(rawFields);
530
- const fields = fieldsJson.map(Fr.fromString);
531
- // The first item is the hash, this is not part of the actual VK
532
- const vkHash = fields[0];
533
- const actualVk = fields.slice(1);
534
- const vk: VerificationKeyData = {
535
- hash: vkHash,
536
- keyAsFields: actualVk as Tuple<Fr, typeof VERIFICATION_KEY_LENGTH_IN_FIELDS>,
537
- keyAsBytes: rawBinary,
538
- numPublicInputs: Number(actualVk[CIRCUIT_PUBLIC_INPUTS_INDEX]),
539
- circuitSize: Number(actualVk[CIRCUIT_SIZE_INDEX]),
540
- isRecursive: actualVk[CIRCUIT_RECURSIVE_INDEX] == Fr.ONE,
541
- };
542
- return vk;
710
+ const vk = await promise;
711
+ return vk.clone();
543
712
  }
544
713
 
545
714
  /**
@@ -553,7 +722,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
553
722
  ): Promise<VerificationKeyData> {
554
723
  let promise = this.verificationKeys.get(circuitType);
555
724
  if (!promise) {
556
- promise = this.convertVk(filePath);
725
+ promise = extractVkData(filePath);
557
726
  this.verificationKeys.set(circuitType, promise);
558
727
  }
559
728
  return promise;
@@ -570,26 +739,32 @@ export class BBNativeRollupProver implements ServerCircuitProver {
570
739
  circuitType: ServerProtocolArtifact,
571
740
  proofLength: PROOF_LENGTH,
572
741
  ): Promise<RecursiveProof<PROOF_LENGTH>> {
742
+ const proofFilename = path.join(filePath, PROOF_FILENAME);
743
+ const proofFieldsFilename = path.join(filePath, PROOF_FIELDS_FILENAME);
744
+
573
745
  const [binaryProof, proofString] = await Promise.all([
574
- fs.readFile(`${filePath}/${PROOF_FILENAME}`),
575
- fs.readFile(`${filePath}/${PROOF_FIELDS_FILENAME}`, { encoding: 'utf-8' }),
746
+ fs.readFile(proofFilename),
747
+ fs.readFile(proofFieldsFilename, { encoding: 'utf-8' }),
576
748
  ]);
577
749
  const json = JSON.parse(proofString);
578
- const fields = json.map(Fr.fromString);
579
750
  const vkData = await this.verificationKeys.get(circuitType);
580
751
  if (!vkData) {
581
752
  throw new Error(`Invalid verification key for ${circuitType}`);
582
753
  }
583
754
  const numPublicInputs = CIRCUITS_WITHOUT_AGGREGATION.has(circuitType)
584
755
  ? vkData.numPublicInputs
585
- : vkData.numPublicInputs - AGGREGATION_OBJECT_SIZE;
586
- const fieldsWithoutPublicInputs = fields.slice(numPublicInputs);
756
+ : vkData.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
757
+ const fieldsWithoutPublicInputs = json.slice(numPublicInputs).map(Fr.fromString);
587
758
  logger.debug(
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}`,
759
+ `Circuit type: ${circuitType}, complete proof length: ${json.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`,
760
+ );
761
+ const proof = new RecursiveProof<PROOF_LENGTH>(
762
+ fieldsWithoutPublicInputs,
763
+ new Proof(binaryProof, numPublicInputs),
764
+ true,
589
765
  );
590
- const proof = new RecursiveProof<PROOF_LENGTH>(fieldsWithoutPublicInputs, new Proof(binaryProof));
591
766
  if (proof.proof.length !== proofLength) {
592
- throw new Error("Proof length doesn't match expected length");
767
+ throw new Error(`Proof length doesn't match expected length (${proof.proof.length} != ${proofLength})`);
593
768
  }
594
769
 
595
770
  return proof;