@aztec/bb-prover 0.40.1 → 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 (60) 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 +37 -2
  4. package/dest/bb/execute.d.ts.map +1 -1
  5. package/dest/bb/execute.js +276 -75
  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 +4 -9
  16. package/dest/prover/bb_native_proof_creator.d.ts.map +1 -1
  17. package/dest/prover/bb_native_proof_creator.js +77 -101
  18. package/dest/prover/bb_prover.d.ts +35 -23
  19. package/dest/prover/bb_prover.d.ts.map +1 -1
  20. package/dest/prover/bb_prover.js +247 -155
  21. package/dest/stats.d.ts +2 -5
  22. package/dest/stats.d.ts.map +1 -1
  23. package/dest/stats.js +27 -26
  24. package/dest/test/index.d.ts +1 -0
  25. package/dest/test/index.d.ts.map +1 -1
  26. package/dest/test/index.js +2 -1
  27. package/dest/test/test_circuit_prover.d.ts +9 -7
  28. package/dest/test/test_circuit_prover.d.ts.map +1 -1
  29. package/dest/test/test_circuit_prover.js +31 -15
  30. package/dest/test/test_verifier.d.ts +7 -0
  31. package/dest/test/test_verifier.d.ts.map +1 -0
  32. package/dest/test/test_verifier.js +10 -0
  33. package/dest/verification_key/verification_key_data.d.ts +8 -0
  34. package/dest/verification_key/verification_key_data.d.ts.map +1 -0
  35. package/dest/verification_key/verification_key_data.js +24 -0
  36. package/dest/verifier/bb_verifier.d.ts +18 -0
  37. package/dest/verifier/bb_verifier.d.ts.map +1 -0
  38. package/dest/verifier/bb_verifier.js +90 -0
  39. package/dest/verifier/index.d.ts +2 -0
  40. package/dest/verifier/index.d.ts.map +1 -0
  41. package/dest/verifier/index.js +2 -0
  42. package/package.json +6 -6
  43. package/src/bb/cli.ts +36 -1
  44. package/src/bb/execute.ts +371 -83
  45. package/src/config.ts +9 -0
  46. package/src/index.ts +2 -0
  47. package/src/mappings/mappings.ts +38 -12
  48. package/src/prover/bb_native_proof_creator.ts +139 -119
  49. package/src/prover/bb_prover.ts +454 -242
  50. package/src/stats.ts +30 -45
  51. package/src/test/index.ts +1 -0
  52. package/src/test/test_circuit_prover.ts +84 -21
  53. package/src/test/test_verifier.ts +12 -0
  54. package/src/verification_key/verification_key_data.ts +35 -0
  55. package/src/verifier/bb_verifier.ts +156 -0
  56. package/src/verifier/index.ts +1 -0
  57. package/dest/prover/verification_key_data.d.ts +0 -16
  58. package/dest/prover/verification_key_data.d.ts.map +0 -1
  59. package/dest/prover/verification_key_data.js +0 -5
  60. 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';
11
+ import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
10
12
  import {
13
+ AGGREGATION_OBJECT_LENGTH,
14
+ type AvmCircuitInputs,
11
15
  type BaseOrMergeRollupPublicInputs,
12
16
  type BaseParityInputs,
13
17
  type BaseRollupInputs,
18
+ EmptyNestedCircuitInputs,
19
+ EmptyNestedData,
14
20
  Fr,
15
21
  type KernelCircuitPublicInputs,
16
22
  type MergeRollupInputs,
17
- type NESTED_RECURSIVE_PROOF_LENGTH,
18
- type ParityPublicInputs,
19
- type PreviousRollupData,
23
+ NESTED_RECURSIVE_PROOF_LENGTH,
24
+ type PrivateKernelEmptyInputData,
25
+ PrivateKernelEmptyInputs,
20
26
  Proof,
21
27
  type PublicKernelCircuitPublicInputs,
22
- type RECURSIVE_PROOF_LENGTH,
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
- import { circuitTypeToCircuitName, emitCircuitProvingStats, emitCircuitWitnessGenerationStats } 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 { mapProtocolArtifactNameToCircuitName } from '../stats.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,19 +122,19 @@ 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 witnessMap = convertBaseParityInputsToWitnessMap(inputs);
118
-
119
- const [circuitOutput, proof] = await this.createRecursiveProof<typeof RECURSIVE_PROOF_LENGTH, ParityPublicInputs>(
120
- witnessMap,
125
+ const { circuitOutput, proof } = await this.createRecursiveProof(
126
+ inputs,
121
127
  'BaseParityArtifact',
128
+ RECURSIVE_PROOF_LENGTH,
129
+ convertBaseParityInputsToWitnessMap,
122
130
  convertBaseParityOutputsFromWitnessMap,
123
131
  );
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,18 +145,30 @@ 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 witnessMap = convertRootParityInputsToWitnessMap(inputs);
141
-
142
- const [circuitOutput, proof] = await this.createRecursiveProof<
143
- typeof NESTED_RECURSIVE_PROOF_LENGTH,
144
- ParityPublicInputs
145
- >(witnessMap, 'RootParityArtifact', convertRootParityOutputsFromWitnessMap);
148
+ const { circuitOutput, proof } = await this.createRecursiveProof(
149
+ inputs,
150
+ 'RootParityArtifact',
151
+ NESTED_RECURSIVE_PROOF_LENGTH,
152
+ convertRootParityInputsToWitnessMap,
153
+ convertRootParityOutputsFromWitnessMap,
154
+ );
146
155
 
147
156
  const verificationKey = await this.getVerificationKeyDataForCircuit('RootParityArtifact');
148
157
 
149
- 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
+ }
150
162
 
151
- 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;
152
172
  }
153
173
 
154
174
  /**
@@ -158,17 +178,37 @@ export class BBNativeRollupProver implements ServerCircuitProver {
158
178
  */
159
179
  public async getPublicKernelProof(
160
180
  kernelRequest: PublicKernelNonTailRequest,
161
- ): Promise<PublicInputsAndProof<PublicKernelCircuitPublicInputs>> {
181
+ ): Promise<PublicInputsAndRecursiveProof<PublicKernelCircuitPublicInputs>> {
162
182
  const kernelOps = PublicKernelArtifactMapping[kernelRequest.type];
163
183
  if (kernelOps === undefined) {
164
184
  throw new Error(`Unable to prove kernel type ${PublicKernelType[kernelRequest.type]}`);
165
185
  }
166
- const witnessMap = kernelOps.convertInputs(kernelRequest.inputs);
167
186
 
168
- const [outputWitness, proof] = await this.createProof(witnessMap, kernelOps.artifact);
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(
200
+ kernelRequest.inputs,
201
+ kernelOps.artifact,
202
+ NESTED_RECURSIVE_PROOF_LENGTH,
203
+ kernelOps.convertInputs,
204
+ kernelOps.convertOutputs,
205
+ );
206
+
207
+ const verificationKey = await this.getVerificationKeyDataForCircuit(kernelOps.artifact);
208
+
209
+ await this.verifyProof(kernelOps.artifact, proof.binaryProof);
169
210
 
170
- const result = kernelOps.convertOutputs(outputWitness);
171
- return makePublicInputsAndProof(result, proof);
211
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
172
212
  }
173
213
 
174
214
  /**
@@ -178,13 +218,20 @@ export class BBNativeRollupProver implements ServerCircuitProver {
178
218
  */
179
219
  public async getPublicTailProof(
180
220
  kernelRequest: PublicKernelTailRequest,
181
- ): Promise<PublicInputsAndProof<KernelCircuitPublicInputs>> {
182
- const witnessMap = convertPublicTailInputsToWitnessMap(kernelRequest.inputs);
221
+ ): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>> {
222
+ const { circuitOutput, proof } = await this.createRecursiveProof(
223
+ kernelRequest.inputs,
224
+ 'PublicKernelTailArtifact',
225
+ NESTED_RECURSIVE_PROOF_LENGTH,
226
+ convertPublicTailInputsToWitnessMap,
227
+ convertPublicTailOutputFromWitnessMap,
228
+ );
229
+
230
+ const verificationKey = await this.getVerificationKeyDataForCircuit('PublicKernelTailArtifact');
183
231
 
184
- const [outputWitness, proof] = await this.createProof(witnessMap, 'PublicKernelTailArtifact');
232
+ await this.verifyProof('PublicKernelTailArtifact', proof.binaryProof);
185
233
 
186
- const result = convertPublicTailOutputFromWitnessMap(outputWitness);
187
- return makePublicInputsAndProof(result, proof);
234
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
188
235
  }
189
236
 
190
237
  /**
@@ -194,15 +241,29 @@ export class BBNativeRollupProver implements ServerCircuitProver {
194
241
  */
195
242
  public async getBaseRollupProof(
196
243
  input: BaseRollupInputs,
197
- ): Promise<PublicInputsAndProof<BaseOrMergeRollupPublicInputs>> {
198
- const witnessMap = convertBaseRollupInputsToWitnessMap(input);
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(
253
+ input,
254
+ 'BaseRollupArtifact',
255
+ NESTED_RECURSIVE_PROOF_LENGTH,
256
+ convertBaseRollupInputsToWitnessMap,
257
+ convertBaseRollupOutputsFromWitnessMap,
258
+ );
199
259
 
200
- const [outputWitness, proof] = await this.createProof(witnessMap, 'BaseRollupArtifact');
260
+ const verificationKey = await this.getVerificationKeyDataForCircuit('BaseRollupArtifact');
201
261
 
202
- const result = convertBaseRollupOutputsFromWitnessMap(outputWitness);
262
+ await this.verifyProof('BaseRollupArtifact', proof.binaryProof);
203
263
 
204
- return makePublicInputsAndProof(result, proof);
264
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
205
265
  }
266
+
206
267
  /**
207
268
  * Simulates the merge rollup circuit from its inputs.
208
269
  * @param input - Inputs to the circuit.
@@ -210,17 +271,20 @@ export class BBNativeRollupProver implements ServerCircuitProver {
210
271
  */
211
272
  public async getMergeRollupProof(
212
273
  input: MergeRollupInputs,
213
- ): Promise<PublicInputsAndProof<BaseOrMergeRollupPublicInputs>> {
214
- // verify both inputs
215
- await Promise.all(input.previousRollupData.map(prev => this.verifyPreviousRollupProof(prev)));
216
-
217
- const witnessMap = convertMergeRollupInputsToWitnessMap(input);
274
+ ): Promise<PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>> {
275
+ const { circuitOutput, proof } = await this.createRecursiveProof(
276
+ input,
277
+ 'MergeRollupArtifact',
278
+ NESTED_RECURSIVE_PROOF_LENGTH,
279
+ convertMergeRollupInputsToWitnessMap,
280
+ convertMergeRollupOutputsFromWitnessMap,
281
+ );
218
282
 
219
- const [outputWitness, proof] = await this.createProof(witnessMap, 'MergeRollupArtifact');
283
+ const verificationKey = await this.getVerificationKeyDataForCircuit('MergeRollupArtifact');
220
284
 
221
- const result = convertMergeRollupOutputsFromWitnessMap(outputWitness);
285
+ await this.verifyProof('MergeRollupArtifact', proof.binaryProof);
222
286
 
223
- return makePublicInputsAndProof(result, proof);
287
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
224
288
  }
225
289
 
226
290
  /**
@@ -228,30 +292,84 @@ export class BBNativeRollupProver implements ServerCircuitProver {
228
292
  * @param input - Inputs to the circuit.
229
293
  * @returns The public inputs as outputs of the simulation.
230
294
  */
231
- public async getRootRollupProof(input: RootRollupInputs): Promise<PublicInputsAndProof<RootRollupPublicInputs>> {
232
- // verify the inputs
233
- await Promise.all(input.previousRollupData.map(prev => this.verifyPreviousRollupProof(prev)));
295
+ public async getRootRollupProof(
296
+ input: RootRollupInputs,
297
+ ): Promise<PublicInputsAndRecursiveProof<RootRollupPublicInputs>> {
298
+ const { circuitOutput, proof } = await this.createProof(
299
+ input,
300
+ 'RootRollupArtifact',
301
+ convertRootRollupInputsToWitnessMap,
302
+ convertRootRollupOutputsFromWitnessMap,
303
+ );
234
304
 
235
- const witnessMap = convertRootRollupInputsToWitnessMap(input);
305
+ const recursiveProof = makeRecursiveProofFromBinary(proof, NESTED_RECURSIVE_PROOF_LENGTH);
236
306
 
237
- const [outputWitness, proof] = await this.createProof(witnessMap, 'RootRollupArtifact');
307
+ const verificationKey = await this.getVerificationKeyDataForCircuit('RootRollupArtifact');
238
308
 
239
309
  await this.verifyProof('RootRollupArtifact', proof);
240
310
 
241
- const result = convertRootRollupOutputsFromWitnessMap(outputWitness);
242
- 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;
326
+ }
327
+
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);
243
342
  }
244
343
 
245
- // TODO(@PhilWindle): Delete when no longer required
246
- public async createProof(witnessMap: WitnessMap, circuitType: ServerProtocolArtifact): Promise<[WitnessMap, Proof]> {
247
- // Create random directory to be used for temp files
248
- const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
249
- await fs.mkdir(bbWorkingDirectory, { recursive: true });
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);
250
357
 
251
- await fs.access(bbWorkingDirectory);
358
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
359
+ }
252
360
 
361
+ private async generateProofWithBB<
362
+ Input extends { toBuffer: () => Buffer },
363
+ Output extends { toBuffer: () => Buffer },
364
+ >(
365
+ input: Input,
366
+ circuitType: ServerProtocolArtifact,
367
+ convertInput: (input: Input) => WitnessMap,
368
+ convertOutput: (outputWitness: WitnessMap) => Output,
369
+ workingDirectory: string,
370
+ ): Promise<{ circuitOutput: Output; vkData: VerificationKeyData; provingResult: BBSuccess }> {
253
371
  // Have the ACVM write the partial witness here
254
- const outputWitnessFile = `${bbWorkingDirectory}/partial-witness.gz`;
372
+ const outputWitnessFile = path.join(workingDirectory, 'partial-witness.gz');
255
373
 
256
374
  // Generate the partial witness using the ACVM
257
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
@@ -265,22 +383,25 @@ export class BBNativeRollupProver implements ServerCircuitProver {
265
383
 
266
384
  logger.debug(`Generating witness data for ${circuitType}`);
267
385
 
386
+ const inputWitness = convertInput(input);
268
387
  const timer = new Timer();
269
- const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
270
- emitCircuitWitnessGenerationStats(
271
- circuitTypeToCircuitName(circuitType),
272
- timer.ms(),
273
- witnessMap.size * Fr.SIZE_IN_BYTES,
274
- outputWitness.size * Fr.SIZE_IN_BYTES,
275
- logger,
276
- );
388
+ const outputWitness = await simulator.simulateCircuit(inputWitness, artifact);
389
+ const witnessGenerationDuration = timer.ms();
390
+ const output = convertOutput(outputWitness);
391
+ logger.debug(`Generated witness`, {
392
+ circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
393
+ duration: witnessGenerationDuration,
394
+ inputSize: input.toBuffer().length,
395
+ outputSize: output.toBuffer().length,
396
+ eventName: 'circuit-witness-generation',
397
+ } satisfies CircuitWitnessGenerationStats);
277
398
 
278
399
  // Now prove the circuit from the generated witness
279
400
  logger.debug(`Proving ${circuitType}...`);
280
401
 
281
402
  const provingResult = await generateProof(
282
403
  this.config.bbBinaryPath,
283
- bbWorkingDirectory,
404
+ workingDirectory,
284
405
  circuitType,
285
406
  Buffer.from(artifact.bytecode, 'base64'),
286
407
  outputWitnessFile,
@@ -293,115 +414,150 @@ export class BBNativeRollupProver implements ServerCircuitProver {
293
414
  }
294
415
 
295
416
  // Ensure our vk cache is up to date
296
- await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
297
-
298
- // Read the proof and then cleanup up our temporary directory
299
- const proof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);
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
- );
310
-
311
- await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
312
-
313
- logger.info(`Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.length} fields`);
417
+ const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
314
418
 
315
- return [outputWitness, new Proof(proof)];
419
+ return {
420
+ circuitOutput: output,
421
+ vkData,
422
+ provingResult,
423
+ };
316
424
  }
317
425
 
318
- /**
319
- * Executes a circuit and returns it's outputs and corresponding proof with embedded aggregation object
320
- * @param witnessMap - The input witness
321
- * @param circuitType - The type of circuit to be executed
322
- * @param convertOutput - Function for parsing the output witness to it's corresponding object
323
- * @returns The circuits output object and it's proof
324
- */
325
- public async createRecursiveProof<PROOF_LENGTH extends number, CircuitOutputType>(
326
- witnessMap: WitnessMap,
426
+ private async createProof<Input extends { toBuffer: () => Buffer }, Output extends { toBuffer: () => Buffer }>(
427
+ input: Input,
327
428
  circuitType: ServerProtocolArtifact,
328
- convertOutput: (outputWitness: WitnessMap) => CircuitOutputType,
329
- ): Promise<[CircuitOutputType, RecursiveProof<PROOF_LENGTH>]> {
330
- // Create random directory to be used for temp files
331
- const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
332
- await fs.mkdir(bbWorkingDirectory, { recursive: true });
333
-
334
- await fs.access(bbWorkingDirectory);
335
-
336
- try {
337
- // Have the ACVM write the partial witness here
338
- const outputWitnessFile = `${bbWorkingDirectory}/partial-witness.gz`;
339
-
340
- // Generate the partial witness using the ACVM
341
- // A further temp directory will be created beneath ours and then cleaned up after the partial witness has been copied to our specified location
342
- const simulator = new NativeACVMSimulator(
343
- this.config.acvmWorkingDirectory,
344
- this.config.acvmBinaryPath,
345
- outputWitnessFile,
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,
346
458
  );
347
459
 
348
- const artifact = ServerCircuitArtifacts[circuitType];
460
+ return { circuitOutput: output, proof };
461
+ };
462
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
463
+ }
349
464
 
350
- logger.debug(`Generating witness data for ${circuitType}`);
465
+ private async generateAvmProofWithBB(input: AvmCircuitInputs, workingDirectory: string): Promise<BBSuccess> {
466
+ logger.debug(`Proving avm-circuit...`);
351
467
 
352
- const timer = new Timer();
353
- const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
468
+ const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.debug);
354
469
 
355
- emitCircuitWitnessGenerationStats(
356
- circuitTypeToCircuitName(circuitType),
357
- timer.ms(),
358
- witnessMap.size * Fr.SIZE_IN_BYTES,
359
- outputWitness.size * Fr.SIZE_IN_BYTES,
360
- logger,
361
- );
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
+ }
362
474
 
363
- const outputType = convertOutput(outputWitness);
475
+ return provingResult;
476
+ }
364
477
 
365
- // Now prove the circuit from the generated witness
366
- logger.debug(`Proving ${circuitType}...`);
478
+ private async createAvmProof(input: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
479
+ const operation = async (bbWorkingDirectory: string): Promise<ProofAndVerificationKey> => {
480
+ const provingResult = await this.generateAvmProofWithBB(input, bbWorkingDirectory);
367
481
 
368
- const provingResult = await generateProof(
369
- this.config.bbBinaryPath,
370
- bbWorkingDirectory,
371
- circuitType,
372
- Buffer.from(artifact.bytecode, 'base64'),
373
- outputWitnessFile,
374
- logger.debug,
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,
375
503
  );
376
504
 
377
- if (provingResult.status === BB_RESULT.FAILURE) {
378
- logger.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`);
379
- throw new Error(provingResult.reason);
380
- }
505
+ return { proof, verificationKey };
506
+ };
507
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
508
+ }
381
509
 
382
- // Ensure our vk cache is up to date
383
- await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
510
+ /**
511
+ * Executes a circuit and returns it's outputs and corresponding proof with embedded aggregation object
512
+ * @param witnessMap - The input witness
513
+ * @param circuitType - The type of circuit to be executed
514
+ * @param proofLength - The length of the proof to be generated. This is a dummy parameter to aid in type checking
515
+ * @param convertInput - Function for mapping the input object to a witness map.
516
+ * @param convertOutput - Function for parsing the output witness to it's corresponding object
517
+ * @returns The circuits output object and it's proof
518
+ */
519
+ private async createRecursiveProof<
520
+ PROOF_LENGTH extends number,
521
+ CircuitInputType extends { toBuffer: () => Buffer },
522
+ CircuitOutputType extends { toBuffer: () => Buffer },
523
+ >(
524
+ input: CircuitInputType,
525
+ circuitType: ServerProtocolArtifact,
526
+ proofLength: PROOF_LENGTH,
527
+ convertInput: (input: CircuitInputType) => WitnessMap,
528
+ convertOutput: (outputWitness: WitnessMap) => CircuitOutputType,
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);
384
536
 
385
- // Read the proof and then cleanup up our temporary directory
386
- const proof = await this.readProofAsFields<PROOF_LENGTH>(provingResult.proofPath!, circuitType);
537
+ // Read the proof as fields
538
+ const proof = await this.readProofAsFields(provingResult.proofPath!, circuitType, proofLength);
387
539
 
388
540
  logger.info(
389
- `Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.proof.length} fields`,
390
- );
391
-
392
- emitCircuitProvingStats(
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,
541
+ `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
542
+ proof.proof.length
543
+ } fields`,
544
+ {
545
+ circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
546
+ circuitSize: vkData.circuitSize,
547
+ duration: provingResult.duration,
548
+ inputSize: output.toBuffer().length,
549
+ proofSize: proof.binaryProof.buffer.length,
550
+ eventName: 'circuit-proving',
551
+ numPublicInputs: vkData.numPublicInputs,
552
+ } satisfies CircuitProvingStats,
399
553
  );
400
554
 
401
- return [outputType, proof];
402
- } finally {
403
- await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
404
- }
555
+ return {
556
+ circuitOutput: output,
557
+ proof,
558
+ };
559
+ };
560
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
405
561
  }
406
562
 
407
563
  /**
@@ -410,33 +566,50 @@ export class BBNativeRollupProver implements ServerCircuitProver {
410
566
  * @param proof - The proof to be verified
411
567
  */
412
568
  public async verifyProof(circuitType: ServerProtocolArtifact, proof: Proof) {
413
- // Create random directory to be used for temp files
414
- const bbWorkingDirectory = `${this.config.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`;
415
- await fs.mkdir(bbWorkingDirectory, { recursive: true });
416
-
417
- const proofFileName = `${bbWorkingDirectory}/proof`;
418
- const verificationKeyPath = `${bbWorkingDirectory}/vk`;
419
569
  const verificationKey = await this.getVerificationKeyDataForCircuit(circuitType);
570
+ return await this.verifyWithKey(verificationKey, proof);
571
+ }
420
572
 
421
- 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
+ }
422
576
 
423
- await fs.writeFile(proofFileName, proof.buffer);
424
- await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes);
577
+ public async verifyWithKey(verificationKey: VerificationKeyData, proof: Proof) {
578
+ return await this.verifyWithKeyInternal(proof, verificationKey, verifyProof);
579
+ }
425
580
 
426
- const logFunction = (message: string) => {
427
- logger.debug(`${circuitType} BB out - ${message}`);
428
- };
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);
429
589
 
430
- const result = await verifyProof(this.config.bbBinaryPath, proofFileName, verificationKeyPath!, logFunction);
590
+ await fs.writeFile(proofFileName, proof.buffer);
591
+ await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes);
431
592
 
432
- await fs.rm(bbWorkingDirectory, { recursive: true, force: true });
593
+ const logFunction = (message: string) => {
594
+ logger.debug(`BB out - ${message}`);
595
+ };
433
596
 
434
- if (result.status === BB_RESULT.FAILURE) {
435
- const errorMessage = `Failed to verify ${circuitType} proof!`;
436
- throw new Error(errorMessage);
437
- }
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
+ };
438
611
 
439
- logger.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`);
612
+ await runInDirectory(this.config.bbWorkingDirectory, operation);
440
613
  }
441
614
 
442
615
  /**
@@ -446,16 +619,66 @@ export class BBNativeRollupProver implements ServerCircuitProver {
446
619
  */
447
620
  public async getVerificationKeyForCircuit(circuitType: ServerProtocolArtifact): Promise<VerificationKeyAsFields> {
448
621
  const vkData = await this.getVerificationKeyDataForCircuit(circuitType);
449
- return new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash);
622
+ return vkData.clone().keyAsFields;
450
623
  }
451
624
 
452
- private async verifyPreviousRollupProof(previousRollupData: PreviousRollupData) {
453
- const proof = previousRollupData.proof;
454
- const circuitType =
455
- previousRollupData.baseOrMergeRollupPublicInputs.rollupType === RollupTypes.Base
456
- ? 'BaseRollupArtifact'
457
- : 'MergeRollupArtifact';
458
- 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);
459
682
  }
460
683
 
461
684
  /**
@@ -477,37 +700,12 @@ export class BBNativeRollupProver implements ServerCircuitProver {
477
700
  if (result.status === BB_RESULT.FAILURE) {
478
701
  throw new Error(`Failed to generate verification key for ${circuitType}, ${result.reason}`);
479
702
  }
480
- return this.convertVk(result.vkPath!);
703
+ return extractVkData(result.vkPath!);
481
704
  });
482
705
  this.verificationKeys.set(circuitType, promise);
483
706
  }
484
- return await promise;
485
- }
486
-
487
- /**
488
- * Reads the verification key data stored at the specified location and parses into a VerificationKeyData
489
- * @param filePath - The directory containing the verification key data files
490
- * @returns The verification key data
491
- */
492
- private async convertVk(filePath: string): Promise<VerificationKeyData> {
493
- const [rawFields, rawBinary] = await Promise.all([
494
- fs.readFile(`${filePath}/${VK_FIELDS_FILENAME}`, { encoding: 'utf-8' }),
495
- fs.readFile(`${filePath}/${VK_FILENAME}`),
496
- ]);
497
- const fieldsJson = JSON.parse(rawFields);
498
- const fields = fieldsJson.map(Fr.fromString);
499
- // The first item is the hash, this is not part of the actual VK
500
- const vkHash = fields[0];
501
- const actualVk = fields.slice(1);
502
- const vk: VerificationKeyData = {
503
- hash: vkHash,
504
- keyAsFields: actualVk as Tuple<Fr, typeof VERIFICATION_KEY_LENGTH_IN_FIELDS>,
505
- keyAsBytes: rawBinary,
506
- numPublicInputs: Number(actualVk[CIRCUIT_PUBLIC_INPUTS_INDEX]),
507
- circuitSize: Number(actualVk[CIRCUIT_SIZE_INDEX]),
508
- isRecursive: actualVk[CIRCUIT_RECURSIVE_INDEX] == Fr.ONE,
509
- };
510
- return vk;
707
+ const vk = await promise;
708
+ return vk.clone();
511
709
  }
512
710
 
513
711
  /**
@@ -515,13 +713,16 @@ export class BBNativeRollupProver implements ServerCircuitProver {
515
713
  * @param filePath - The directory containing the verification key data files
516
714
  * @param circuitType - The type of circuit to which the verification key corresponds
517
715
  */
518
- private async updateVerificationKeyAfterProof(filePath: string, circuitType: ServerProtocolArtifact) {
716
+ private async updateVerificationKeyAfterProof(
717
+ filePath: string,
718
+ circuitType: ServerProtocolArtifact,
719
+ ): Promise<VerificationKeyData> {
519
720
  let promise = this.verificationKeys.get(circuitType);
520
721
  if (!promise) {
521
- promise = this.convertVk(filePath);
722
+ promise = extractVkData(filePath);
522
723
  this.verificationKeys.set(circuitType, promise);
523
724
  }
524
- await promise;
725
+ return promise;
525
726
  }
526
727
 
527
728
  /**
@@ -533,25 +734,36 @@ export class BBNativeRollupProver implements ServerCircuitProver {
533
734
  private async readProofAsFields<PROOF_LENGTH extends number>(
534
735
  filePath: string,
535
736
  circuitType: ServerProtocolArtifact,
737
+ proofLength: PROOF_LENGTH,
536
738
  ): Promise<RecursiveProof<PROOF_LENGTH>> {
739
+ const proofFilename = path.join(filePath, PROOF_FILENAME);
740
+ const proofFieldsFilename = path.join(filePath, PROOF_FIELDS_FILENAME);
741
+
537
742
  const [binaryProof, proofString] = await Promise.all([
538
- fs.readFile(`${filePath}/${PROOF_FILENAME}`),
539
- fs.readFile(`${filePath}/${PROOF_FIELDS_FILENAME}`, { encoding: 'utf-8' }),
743
+ fs.readFile(proofFilename),
744
+ fs.readFile(proofFieldsFilename, { encoding: 'utf-8' }),
540
745
  ]);
541
746
  const json = JSON.parse(proofString);
542
- const fields = json.map(Fr.fromString);
543
747
  const vkData = await this.verificationKeys.get(circuitType);
544
748
  if (!vkData) {
545
749
  throw new Error(`Invalid verification key for ${circuitType}`);
546
750
  }
547
751
  const numPublicInputs = CIRCUITS_WITHOUT_AGGREGATION.has(circuitType)
548
752
  ? vkData.numPublicInputs
549
- : vkData.numPublicInputs - AGGREGATION_OBJECT_SIZE;
550
- const fieldsWithoutPublicInputs = fields.slice(numPublicInputs);
753
+ : vkData.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
754
+ const fieldsWithoutPublicInputs = json.slice(numPublicInputs).map(Fr.fromString);
551
755
  logger.debug(
552
- `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}`,
553
757
  );
554
- const proof = new RecursiveProof<PROOF_LENGTH>(fieldsWithoutPublicInputs, new Proof(binaryProof));
758
+ const proof = new RecursiveProof<PROOF_LENGTH>(
759
+ fieldsWithoutPublicInputs,
760
+ new Proof(binaryProof, numPublicInputs),
761
+ true,
762
+ );
763
+ if (proof.proof.length !== proofLength) {
764
+ throw new Error(`Proof length doesn't match expected length (${proof.proof.length} != ${proofLength})`);
765
+ }
766
+
555
767
  return proof;
556
768
  }
557
769
  }