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