@aztec/bb-prover 0.43.0 → 0.44.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.
@@ -1,3 +1,4 @@
1
+ import { __esDecorate, __runInitializers } from "tslib";
1
2
  /* eslint-disable require-await */
2
3
  import { makePublicInputsAndRecursiveProof, } from '@aztec/circuit-types';
3
4
  import { AGGREGATION_OBJECT_LENGTH, EmptyNestedCircuitInputs, EmptyNestedData, Fr, NESTED_RECURSIVE_PROOF_LENGTH, PrivateKernelEmptyInputs, Proof, RECURSIVE_PROOF_LENGTH, RecursiveProof, RootParityInput, makeRecursiveProofFromBinary, } from '@aztec/circuits.js';
@@ -6,10 +7,12 @@ import { createDebugLogger } from '@aztec/foundation/log';
6
7
  import { Timer } from '@aztec/foundation/timer';
7
8
  import { EmptyNestedArtifact, ServerCircuitArtifacts, convertBaseParityInputsToWitnessMap, convertBaseParityOutputsFromWitnessMap, convertBaseRollupInputsToWitnessMap, convertBaseRollupOutputsFromWitnessMap, convertMergeRollupInputsToWitnessMap, convertMergeRollupOutputsFromWitnessMap, convertPrivateKernelEmptyInputsToWitnessMap, convertPrivateKernelEmptyOutputsFromWitnessMap, convertPublicTailInputsToWitnessMap, convertPublicTailOutputFromWitnessMap, convertRootParityInputsToWitnessMap, convertRootParityOutputsFromWitnessMap, convertRootRollupInputsToWitnessMap, convertRootRollupOutputsFromWitnessMap, } from '@aztec/noir-protocol-circuits-types';
8
9
  import { NativeACVMSimulator } from '@aztec/simulator';
10
+ import { Attributes, trackSpan } from '@aztec/telemetry-client';
9
11
  import { abiEncode } from '@noir-lang/noirc_abi';
10
12
  import * as fs from 'fs/promises';
11
13
  import * as path from 'path';
12
14
  import { BB_RESULT, PROOF_FIELDS_FILENAME, PROOF_FILENAME, VK_FILENAME, generateAvmProof, generateKeyForNoirCircuit, generateProof, verifyAvmProof, verifyProof, writeProofAsFields, } from '../bb/execute.js';
15
+ import { ProverInstrumentation } from '../instrumentation.js';
13
16
  import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
14
17
  import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
15
18
  import { extractVkData } from '../verification_key/verification_key_data.js';
@@ -21,397 +24,446 @@ const CIRCUITS_WITHOUT_AGGREGATION = new Set([
21
24
  /**
22
25
  * Prover implementation that uses barretenberg native proving
23
26
  */
24
- export class BBNativeRollupProver {
25
- constructor(config) {
26
- this.config = config;
27
- this.verificationKeys = new Map();
28
- }
29
- static async new(config) {
30
- await fs.access(config.acvmBinaryPath, fs.constants.R_OK);
31
- await fs.mkdir(config.acvmWorkingDirectory, { recursive: true });
32
- await fs.access(config.bbBinaryPath, fs.constants.R_OK);
33
- await fs.mkdir(config.bbWorkingDirectory, { recursive: true });
34
- logger.info(`Using native BB at ${config.bbBinaryPath} and working directory ${config.bbWorkingDirectory}`);
35
- logger.info(`Using native ACVM at ${config.acvmBinaryPath} and working directory ${config.acvmWorkingDirectory}`);
36
- return new BBNativeRollupProver(config);
37
- }
38
- /**
39
- * Simulates the base parity circuit from its inputs.
40
- * @param inputs - Inputs to the circuit.
41
- * @returns The public inputs of the parity circuit.
42
- */
43
- async getBaseParityProof(inputs) {
44
- const { circuitOutput, proof } = await this.createRecursiveProof(inputs, 'BaseParityArtifact', RECURSIVE_PROOF_LENGTH, convertBaseParityInputsToWitnessMap, convertBaseParityOutputsFromWitnessMap);
45
- const verificationKey = await this.getVerificationKeyDataForCircuit('BaseParityArtifact');
46
- await this.verifyProof('BaseParityArtifact', proof.binaryProof);
47
- return new RootParityInput(proof, verificationKey.keyAsFields, circuitOutput);
48
- }
49
- /**
50
- * Simulates the root parity circuit from its inputs.
51
- * @param inputs - Inputs to the circuit.
52
- * @returns The public inputs of the parity circuit.
53
- */
54
- async getRootParityProof(inputs) {
55
- const { circuitOutput, proof } = await this.createRecursiveProof(inputs, 'RootParityArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertRootParityInputsToWitnessMap, convertRootParityOutputsFromWitnessMap);
56
- const verificationKey = await this.getVerificationKeyDataForCircuit('RootParityArtifact');
57
- await this.verifyProof('RootParityArtifact', proof.binaryProof);
58
- return new RootParityInput(proof, verificationKey.keyAsFields, circuitOutput);
59
- }
60
- /**
61
- * Creates an AVM proof and verifies it.
62
- * @param inputs - The inputs to the AVM circuit.
63
- * @returns The proof.
64
- */
65
- async getAvmProof(inputs) {
66
- const proofAndVk = await this.createAvmProof(inputs);
67
- await this.verifyAvmProof(proofAndVk.proof, proofAndVk.verificationKey);
68
- return proofAndVk;
69
- }
70
- /**
71
- * Requests that a public kernel circuit be executed and the proof generated
72
- * @param kernelRequest - The object encapsulating the request for a proof
73
- * @returns The requested circuit's public inputs and proof
74
- */
75
- async getPublicKernelProof(kernelRequest) {
76
- const kernelOps = PublicKernelArtifactMapping[kernelRequest.type];
77
- if (kernelOps === undefined) {
78
- throw new Error(`Unable to prove kernel type ${kernelRequest.type}`);
79
- }
80
- // We may need to convert the recursive proof into fields format
81
- kernelRequest.inputs.previousKernel.proof = await this.ensureValidProof(kernelRequest.inputs.previousKernel.proof, kernelOps.artifact, kernelRequest.inputs.previousKernel.vk);
82
- await this.verifyWithKey(kernelRequest.inputs.previousKernel.vk, kernelRequest.inputs.previousKernel.proof.binaryProof);
83
- const { circuitOutput, proof } = await this.createRecursiveProof(kernelRequest.inputs, kernelOps.artifact, NESTED_RECURSIVE_PROOF_LENGTH, kernelOps.convertInputs, kernelOps.convertOutputs);
84
- const verificationKey = await this.getVerificationKeyDataForCircuit(kernelOps.artifact);
85
- await this.verifyProof(kernelOps.artifact, proof.binaryProof);
86
- return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
87
- }
88
- /**
89
- * Requests that the public kernel tail circuit be executed and the proof generated
90
- * @param kernelRequest - The object encapsulating the request for a proof
91
- * @returns The requested circuit's public inputs and proof
92
- */
93
- async getPublicTailProof(kernelRequest) {
94
- const { circuitOutput, proof } = await this.createRecursiveProof(kernelRequest.inputs, 'PublicKernelTailArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertPublicTailInputsToWitnessMap, convertPublicTailOutputFromWitnessMap);
95
- const verificationKey = await this.getVerificationKeyDataForCircuit('PublicKernelTailArtifact');
96
- await this.verifyProof('PublicKernelTailArtifact', proof.binaryProof);
97
- return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
98
- }
99
- /**
100
- * Simulates the base rollup circuit from its inputs.
101
- * @param input - Inputs to the circuit.
102
- * @returns The public inputs as outputs of the simulation.
103
- */
104
- async getBaseRollupProof(input) {
105
- // We may need to convert the recursive proof into fields format
106
- input.kernelData.proof = await this.ensureValidProof(input.kernelData.proof, 'BaseRollupArtifact', input.kernelData.vk);
107
- const { circuitOutput, proof } = await this.createRecursiveProof(input, 'BaseRollupArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertBaseRollupInputsToWitnessMap, convertBaseRollupOutputsFromWitnessMap);
108
- const verificationKey = await this.getVerificationKeyDataForCircuit('BaseRollupArtifact');
109
- await this.verifyProof('BaseRollupArtifact', proof.binaryProof);
110
- return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
111
- }
112
- /**
113
- * Simulates the merge rollup circuit from its inputs.
114
- * @param input - Inputs to the circuit.
115
- * @returns The public inputs as outputs of the simulation.
116
- */
117
- async getMergeRollupProof(input) {
118
- const { circuitOutput, proof } = await this.createRecursiveProof(input, 'MergeRollupArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertMergeRollupInputsToWitnessMap, convertMergeRollupOutputsFromWitnessMap);
119
- const verificationKey = await this.getVerificationKeyDataForCircuit('MergeRollupArtifact');
120
- await this.verifyProof('MergeRollupArtifact', proof.binaryProof);
121
- return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
122
- }
123
- /**
124
- * Simulates the root rollup circuit from its inputs.
125
- * @param input - Inputs to the circuit.
126
- * @returns The public inputs as outputs of the simulation.
127
- */
128
- async getRootRollupProof(input) {
129
- const { circuitOutput, proof } = await this.createProof(input, 'RootRollupArtifact', convertRootRollupInputsToWitnessMap, convertRootRollupOutputsFromWitnessMap);
130
- const recursiveProof = makeRecursiveProofFromBinary(proof, NESTED_RECURSIVE_PROOF_LENGTH);
131
- const verificationKey = await this.getVerificationKeyDataForCircuit('RootRollupArtifact');
132
- await this.verifyProof('RootRollupArtifact', proof);
133
- return makePublicInputsAndRecursiveProof(circuitOutput, recursiveProof, verificationKey);
134
- }
135
- async getEmptyPrivateKernelProof(inputs) {
136
- const emptyNested = await this.getEmptyNestedProof();
137
- const emptyPrivateKernelProof = await this.getEmptyPrivateKernelProofFromEmptyNested(PrivateKernelEmptyInputs.from({
138
- ...inputs,
139
- emptyNested,
140
- }));
141
- return emptyPrivateKernelProof;
142
- }
143
- async getEmptyNestedProof() {
144
- const inputs = new EmptyNestedCircuitInputs();
145
- const { proof } = await this.createRecursiveProof(inputs, 'EmptyNestedArtifact', RECURSIVE_PROOF_LENGTH, (nothing) => abiEncode(EmptyNestedArtifact.abi, { _inputs: nothing }), () => new EmptyNestedCircuitInputs());
146
- const verificationKey = await this.getVerificationKeyDataForCircuit('EmptyNestedArtifact');
147
- await this.verifyProof('EmptyNestedArtifact', proof.binaryProof);
148
- return new EmptyNestedData(proof, verificationKey.keyAsFields);
149
- }
150
- async getEmptyPrivateKernelProofFromEmptyNested(inputs) {
151
- const { circuitOutput, proof } = await this.createRecursiveProof(inputs, 'PrivateKernelEmptyArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertPrivateKernelEmptyInputsToWitnessMap, convertPrivateKernelEmptyOutputsFromWitnessMap);
152
- const verificationKey = await this.getVerificationKeyDataForCircuit('PrivateKernelEmptyArtifact');
153
- await this.verifyProof('PrivateKernelEmptyArtifact', proof.binaryProof);
154
- return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
155
- }
156
- async generateProofWithBB(input, circuitType, convertInput, convertOutput, workingDirectory) {
157
- // Have the ACVM write the partial witness here
158
- const outputWitnessFile = path.join(workingDirectory, 'partial-witness.gz');
159
- // Generate the partial witness using the ACVM
160
- // A further temp directory will be created beneath ours and then cleaned up after the partial witness has been copied to our specified location
161
- const simulator = new NativeACVMSimulator(this.config.acvmWorkingDirectory, this.config.acvmBinaryPath, outputWitnessFile);
162
- const artifact = ServerCircuitArtifacts[circuitType];
163
- logger.debug(`Generating witness data for ${circuitType}`);
164
- const inputWitness = convertInput(input);
165
- const timer = new Timer();
166
- const outputWitness = await simulator.simulateCircuit(inputWitness, artifact);
167
- const witnessGenerationDuration = timer.ms();
168
- const output = convertOutput(outputWitness);
169
- logger.debug(`Generated witness`, {
170
- circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
171
- duration: witnessGenerationDuration,
172
- inputSize: input.toBuffer().length,
173
- outputSize: output.toBuffer().length,
174
- eventName: 'circuit-witness-generation',
175
- });
176
- // Now prove the circuit from the generated witness
177
- logger.debug(`Proving ${circuitType}...`);
178
- const provingResult = await generateProof(this.config.bbBinaryPath, workingDirectory, circuitType, Buffer.from(artifact.bytecode, 'base64'), outputWitnessFile, logger.debug);
179
- if (provingResult.status === BB_RESULT.FAILURE) {
180
- logger.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`);
181
- throw new Error(provingResult.reason);
182
- }
183
- // Ensure our vk cache is up to date
184
- const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath, circuitType);
185
- return {
186
- circuitOutput: output,
187
- vkData,
188
- provingResult,
189
- };
190
- }
191
- async createProof(input, circuitType, convertInput, convertOutput) {
192
- const operation = async (bbWorkingDirectory) => {
193
- const { provingResult, vkData, circuitOutput: output, } = await this.generateProofWithBB(input, circuitType, convertInput, convertOutput, bbWorkingDirectory);
194
- // Read the binary proof
195
- const rawProof = await fs.readFile(`${provingResult.proofPath}/${PROOF_FILENAME}`);
196
- const proof = new Proof(rawProof, vkData.numPublicInputs);
197
- logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${proof.buffer.length} bytes`, {
198
- circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
199
- // does not include reading the proof from disk
200
- duration: provingResult.duration,
201
- proofSize: proof.buffer.length,
202
- eventName: 'circuit-proving',
203
- // circuitOutput is the partial witness that became the input to the proof
204
- inputSize: output.toBuffer().length,
205
- circuitSize: vkData.circuitSize,
206
- numPublicInputs: vkData.numPublicInputs,
207
- });
208
- return { circuitOutput: output, proof };
209
- };
210
- return await runInDirectory(this.config.bbWorkingDirectory, operation);
211
- }
212
- async generateAvmProofWithBB(input, workingDirectory) {
213
- logger.debug(`Proving avm-circuit...`);
214
- const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.verbose);
215
- if (provingResult.status === BB_RESULT.FAILURE) {
216
- logger.error(`Failed to generate proof for avm-circuit: ${provingResult.reason}`);
217
- throw new Error(provingResult.reason);
218
- }
219
- return provingResult;
220
- }
221
- async createAvmProof(input) {
222
- const cleanupDir = !process.env.AVM_PROVING_PRESERVE_WORKING_DIR;
223
- const operation = async (bbWorkingDirectory) => {
224
- if (!cleanupDir) {
225
- logger.info(`Preserving working directory ${bbWorkingDirectory}`);
27
+ let BBNativeRollupProver = (() => {
28
+ var _a;
29
+ let _instanceExtraInitializers = [];
30
+ let _getBaseParityProof_decorators;
31
+ let _getRootParityProof_decorators;
32
+ let _getAvmProof_decorators;
33
+ let _getPublicKernelProof_decorators;
34
+ return _a = class BBNativeRollupProver {
35
+ constructor(config, telemetry) {
36
+ this.config = (__runInitializers(this, _instanceExtraInitializers), config);
37
+ this.verificationKeys = new Map();
38
+ this.instrumentation = new ProverInstrumentation(telemetry, 'BBNativeRollupProver');
226
39
  }
227
- const provingResult = await this.generateAvmProofWithBB(input, bbWorkingDirectory);
228
- const rawProof = await fs.readFile(provingResult.proofPath);
229
- // TODO(https://github.com/AztecProtocol/aztec-packages/issues/6773): this VK data format is wrong.
230
- // In particular, the number of public inputs, etc will be wrong.
231
- const verificationKey = await extractVkData(provingResult.vkPath);
232
- const proof = new Proof(rawProof, verificationKey.numPublicInputs);
233
- const circuitType = 'avm-circuit';
234
- logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${proof.buffer.length} bytes`, {
235
- circuitName: circuitType,
236
- // does not include reading the proof from disk
237
- duration: provingResult.duration,
238
- proofSize: proof.buffer.length,
239
- eventName: 'circuit-proving',
240
- inputSize: input.toBuffer().length,
241
- circuitSize: verificationKey.circuitSize,
242
- numPublicInputs: verificationKey.numPublicInputs,
243
- });
244
- return { proof, verificationKey };
245
- };
246
- return await runInDirectory(this.config.bbWorkingDirectory, operation, cleanupDir);
247
- }
248
- /**
249
- * Executes a circuit and returns it's outputs and corresponding proof with embedded aggregation object
250
- * @param witnessMap - The input witness
251
- * @param circuitType - The type of circuit to be executed
252
- * @param proofLength - The length of the proof to be generated. This is a dummy parameter to aid in type checking
253
- * @param convertInput - Function for mapping the input object to a witness map.
254
- * @param convertOutput - Function for parsing the output witness to it's corresponding object
255
- * @returns The circuits output object and it's proof
256
- */
257
- async createRecursiveProof(input, circuitType, proofLength, convertInput, convertOutput) {
258
- const operation = async (bbWorkingDirectory) => {
259
- const { provingResult, vkData, circuitOutput: output, } = await this.generateProofWithBB(input, circuitType, convertInput, convertOutput, bbWorkingDirectory);
260
- // Read the proof as fields
261
- const proof = await this.readProofAsFields(provingResult.proofPath, circuitType, proofLength);
262
- logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${proof.proof.length} fields`, {
263
- circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
264
- circuitSize: vkData.circuitSize,
265
- duration: provingResult.duration,
266
- inputSize: output.toBuffer().length,
267
- proofSize: proof.binaryProof.buffer.length,
268
- eventName: 'circuit-proving',
269
- numPublicInputs: vkData.numPublicInputs,
270
- });
271
- return {
272
- circuitOutput: output,
273
- proof,
274
- };
275
- };
276
- return await runInDirectory(this.config.bbWorkingDirectory, operation);
277
- }
278
- /**
279
- * Verifies a proof, will generate the verification key if one is not cached internally
280
- * @param circuitType - The type of circuit whose proof is to be verified
281
- * @param proof - The proof to be verified
282
- */
283
- async verifyProof(circuitType, proof) {
284
- const verificationKey = await this.getVerificationKeyDataForCircuit(circuitType);
285
- return await this.verifyWithKey(verificationKey, proof);
286
- }
287
- async verifyAvmProof(proof, verificationKey) {
288
- return await this.verifyWithKeyInternal(proof, verificationKey, verifyAvmProof);
289
- }
290
- async verifyWithKey(verificationKey, proof) {
291
- return await this.verifyWithKeyInternal(proof, verificationKey, verifyProof);
292
- }
293
- async verifyWithKeyInternal(proof, verificationKey, verificationFunction) {
294
- const operation = async (bbWorkingDirectory) => {
295
- const proofFileName = path.join(bbWorkingDirectory, PROOF_FILENAME);
296
- const verificationKeyPath = path.join(bbWorkingDirectory, VK_FILENAME);
297
- await fs.writeFile(proofFileName, proof.buffer);
298
- await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes);
299
- const logFunction = (message) => {
300
- logger.debug(`BB out - ${message}`);
301
- };
302
- const result = await verificationFunction(this.config.bbBinaryPath, proofFileName, verificationKeyPath, logFunction);
303
- if (result.status === BB_RESULT.FAILURE) {
304
- const errorMessage = `Failed to verify proof from key!`;
305
- throw new Error(errorMessage);
40
+ get tracer() {
41
+ return this.instrumentation.tracer;
306
42
  }
307
- logger.debug(`Successfully verified proof from key in ${result.duration} ms`);
308
- };
309
- await runInDirectory(this.config.bbWorkingDirectory, operation);
310
- }
311
- /**
312
- * Returns the verification key for a circuit, will generate it if not cached internally
313
- * @param circuitType - The type of circuit for which the verification key is required
314
- * @returns The verification key
315
- */
316
- async getVerificationKeyForCircuit(circuitType) {
317
- const vkData = await this.getVerificationKeyDataForCircuit(circuitType);
318
- return vkData.clone().keyAsFields;
319
- }
320
- /**
321
- * Will check a recursive proof argument for validity of it's 'fields' format of proof and convert if required
322
- * @param proof - The input proof that may need converting
323
- * @returns - The valid proof
324
- */
325
- async ensureValidProof(proof, circuit, vk) {
326
- // If the 'fields' proof is already valid then simply return
327
- // This will be false for proofs coming from clients
328
- if (proof.fieldsValid) {
329
- return proof;
330
- }
331
- const operation = async (bbWorkingDirectory) => {
332
- const numPublicInputs = vk.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
333
- const proofFullFilename = path.join(bbWorkingDirectory, PROOF_FILENAME);
334
- const vkFullFilename = path.join(bbWorkingDirectory, VK_FILENAME);
335
- logger.debug(`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}`);
336
- await fs.writeFile(proofFullFilename, proof.binaryProof.buffer);
337
- await fs.writeFile(vkFullFilename, vk.keyAsBytes);
338
- const logFunction = (message) => {
339
- logger.debug(`${circuit} BB out - ${message}`);
340
- };
341
- const result = await writeProofAsFields(this.config.bbBinaryPath, bbWorkingDirectory, PROOF_FILENAME, vkFullFilename, logFunction);
342
- if (result.status === BB_RESULT.FAILURE) {
343
- const errorMessage = `Failed to convert ${circuit} proof to fields, ${result.reason}`;
344
- throw new Error(errorMessage);
43
+ static async new(config, telemetry) {
44
+ await fs.access(config.acvmBinaryPath, fs.constants.R_OK);
45
+ await fs.mkdir(config.acvmWorkingDirectory, { recursive: true });
46
+ await fs.access(config.bbBinaryPath, fs.constants.R_OK);
47
+ await fs.mkdir(config.bbWorkingDirectory, { recursive: true });
48
+ logger.info(`Using native BB at ${config.bbBinaryPath} and working directory ${config.bbWorkingDirectory}`);
49
+ logger.info(`Using native ACVM at ${config.acvmBinaryPath} and working directory ${config.acvmWorkingDirectory}`);
50
+ return new _a(config, telemetry);
345
51
  }
346
- const proofString = await fs.readFile(path.join(bbWorkingDirectory, PROOF_FIELDS_FILENAME), {
347
- encoding: 'utf-8',
348
- });
349
- const json = JSON.parse(proofString);
350
- const fields = json.slice(numPublicInputs).map(Fr.fromString);
351
- return new RecursiveProof(fields, new Proof(proof.binaryProof.buffer, vk.numPublicInputs), true);
352
- };
353
- return await runInDirectory(this.config.bbWorkingDirectory, operation);
354
- }
355
- /**
356
- * Returns the verification key data for a circuit, will generate and cache it if not cached internally
357
- * @param circuitType - The type of circuit for which the verification key is required
358
- * @returns The verification key data
359
- */
360
- async getVerificationKeyDataForCircuit(circuitType) {
361
- let promise = this.verificationKeys.get(circuitType);
362
- if (!promise) {
363
- promise = generateKeyForNoirCircuit(this.config.bbBinaryPath, this.config.bbWorkingDirectory, circuitType, ServerCircuitArtifacts[circuitType], 'vk', logger.debug).then(result => {
364
- if (result.status === BB_RESULT.FAILURE) {
365
- throw new Error(`Failed to generate verification key for ${circuitType}, ${result.reason}`);
52
+ /**
53
+ * Simulates the base parity circuit from its inputs.
54
+ * @param inputs - Inputs to the circuit.
55
+ * @returns The public inputs of the parity circuit.
56
+ */
57
+ async getBaseParityProof(inputs) {
58
+ const { circuitOutput, proof } = await this.createRecursiveProof(inputs, 'BaseParityArtifact', RECURSIVE_PROOF_LENGTH, convertBaseParityInputsToWitnessMap, convertBaseParityOutputsFromWitnessMap);
59
+ const verificationKey = await this.getVerificationKeyDataForCircuit('BaseParityArtifact');
60
+ await this.verifyProof('BaseParityArtifact', proof.binaryProof);
61
+ return new RootParityInput(proof, verificationKey.keyAsFields, circuitOutput);
62
+ }
63
+ /**
64
+ * Simulates the root parity circuit from its inputs.
65
+ * @param inputs - Inputs to the circuit.
66
+ * @returns The public inputs of the parity circuit.
67
+ */
68
+ async getRootParityProof(inputs) {
69
+ const { circuitOutput, proof } = await this.createRecursiveProof(inputs, 'RootParityArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertRootParityInputsToWitnessMap, convertRootParityOutputsFromWitnessMap);
70
+ const verificationKey = await this.getVerificationKeyDataForCircuit('RootParityArtifact');
71
+ await this.verifyProof('RootParityArtifact', proof.binaryProof);
72
+ return new RootParityInput(proof, verificationKey.keyAsFields, circuitOutput);
73
+ }
74
+ /**
75
+ * Creates an AVM proof and verifies it.
76
+ * @param inputs - The inputs to the AVM circuit.
77
+ * @returns The proof.
78
+ */
79
+ async getAvmProof(inputs) {
80
+ const proofAndVk = await this.createAvmProof(inputs);
81
+ await this.verifyAvmProof(proofAndVk.proof, proofAndVk.verificationKey);
82
+ return proofAndVk;
83
+ }
84
+ /**
85
+ * Requests that a public kernel circuit be executed and the proof generated
86
+ * @param kernelRequest - The object encapsulating the request for a proof
87
+ * @returns The requested circuit's public inputs and proof
88
+ */
89
+ async getPublicKernelProof(kernelRequest) {
90
+ const kernelOps = PublicKernelArtifactMapping[kernelRequest.type];
91
+ if (kernelOps === undefined) {
92
+ throw new Error(`Unable to prove kernel type ${kernelRequest.type}`);
93
+ }
94
+ // We may need to convert the recursive proof into fields format
95
+ kernelRequest.inputs.previousKernel.proof = await this.ensureValidProof(kernelRequest.inputs.previousKernel.proof, kernelOps.artifact, kernelRequest.inputs.previousKernel.vk);
96
+ await this.verifyWithKey(kernelRequest.inputs.previousKernel.vk, kernelRequest.inputs.previousKernel.proof.binaryProof);
97
+ const { circuitOutput, proof } = await this.createRecursiveProof(kernelRequest.inputs, kernelOps.artifact, NESTED_RECURSIVE_PROOF_LENGTH, kernelOps.convertInputs, kernelOps.convertOutputs);
98
+ const verificationKey = await this.getVerificationKeyDataForCircuit(kernelOps.artifact);
99
+ await this.verifyProof(kernelOps.artifact, proof.binaryProof);
100
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
101
+ }
102
+ /**
103
+ * Requests that the public kernel tail circuit be executed and the proof generated
104
+ * @param kernelRequest - The object encapsulating the request for a proof
105
+ * @returns The requested circuit's public inputs and proof
106
+ */
107
+ async getPublicTailProof(kernelRequest) {
108
+ const { circuitOutput, proof } = await this.createRecursiveProof(kernelRequest.inputs, 'PublicKernelTailArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertPublicTailInputsToWitnessMap, convertPublicTailOutputFromWitnessMap);
109
+ const verificationKey = await this.getVerificationKeyDataForCircuit('PublicKernelTailArtifact');
110
+ await this.verifyProof('PublicKernelTailArtifact', proof.binaryProof);
111
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
112
+ }
113
+ /**
114
+ * Simulates the base rollup circuit from its inputs.
115
+ * @param input - Inputs to the circuit.
116
+ * @returns The public inputs as outputs of the simulation.
117
+ */
118
+ async getBaseRollupProof(input) {
119
+ // We may need to convert the recursive proof into fields format
120
+ input.kernelData.proof = await this.ensureValidProof(input.kernelData.proof, 'BaseRollupArtifact', input.kernelData.vk);
121
+ const { circuitOutput, proof } = await this.createRecursiveProof(input, 'BaseRollupArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertBaseRollupInputsToWitnessMap, convertBaseRollupOutputsFromWitnessMap);
122
+ const verificationKey = await this.getVerificationKeyDataForCircuit('BaseRollupArtifact');
123
+ await this.verifyProof('BaseRollupArtifact', proof.binaryProof);
124
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
125
+ }
126
+ /**
127
+ * Simulates the merge rollup circuit from its inputs.
128
+ * @param input - Inputs to the circuit.
129
+ * @returns The public inputs as outputs of the simulation.
130
+ */
131
+ async getMergeRollupProof(input) {
132
+ const { circuitOutput, proof } = await this.createRecursiveProof(input, 'MergeRollupArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertMergeRollupInputsToWitnessMap, convertMergeRollupOutputsFromWitnessMap);
133
+ const verificationKey = await this.getVerificationKeyDataForCircuit('MergeRollupArtifact');
134
+ await this.verifyProof('MergeRollupArtifact', proof.binaryProof);
135
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
136
+ }
137
+ /**
138
+ * Simulates the root rollup circuit from its inputs.
139
+ * @param input - Inputs to the circuit.
140
+ * @returns The public inputs as outputs of the simulation.
141
+ */
142
+ async getRootRollupProof(input) {
143
+ const { circuitOutput, proof } = await this.createProof(input, 'RootRollupArtifact', convertRootRollupInputsToWitnessMap, convertRootRollupOutputsFromWitnessMap);
144
+ const recursiveProof = makeRecursiveProofFromBinary(proof, NESTED_RECURSIVE_PROOF_LENGTH);
145
+ const verificationKey = await this.getVerificationKeyDataForCircuit('RootRollupArtifact');
146
+ await this.verifyProof('RootRollupArtifact', proof);
147
+ return makePublicInputsAndRecursiveProof(circuitOutput, recursiveProof, verificationKey);
148
+ }
149
+ async getEmptyPrivateKernelProof(inputs) {
150
+ const emptyNested = await this.getEmptyNestedProof();
151
+ const emptyPrivateKernelProof = await this.getEmptyPrivateKernelProofFromEmptyNested(PrivateKernelEmptyInputs.from({
152
+ ...inputs,
153
+ emptyNested,
154
+ }));
155
+ return emptyPrivateKernelProof;
156
+ }
157
+ async getEmptyNestedProof() {
158
+ const inputs = new EmptyNestedCircuitInputs();
159
+ const { proof } = await this.createRecursiveProof(inputs, 'EmptyNestedArtifact', RECURSIVE_PROOF_LENGTH, (nothing) => abiEncode(EmptyNestedArtifact.abi, { _inputs: nothing }), () => new EmptyNestedCircuitInputs());
160
+ const verificationKey = await this.getVerificationKeyDataForCircuit('EmptyNestedArtifact');
161
+ await this.verifyProof('EmptyNestedArtifact', proof.binaryProof);
162
+ return new EmptyNestedData(proof, verificationKey.keyAsFields);
163
+ }
164
+ async getEmptyPrivateKernelProofFromEmptyNested(inputs) {
165
+ const { circuitOutput, proof } = await this.createRecursiveProof(inputs, 'PrivateKernelEmptyArtifact', NESTED_RECURSIVE_PROOF_LENGTH, convertPrivateKernelEmptyInputsToWitnessMap, convertPrivateKernelEmptyOutputsFromWitnessMap);
166
+ const verificationKey = await this.getVerificationKeyDataForCircuit('PrivateKernelEmptyArtifact');
167
+ await this.verifyProof('PrivateKernelEmptyArtifact', proof.binaryProof);
168
+ return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
169
+ }
170
+ async generateProofWithBB(input, circuitType, convertInput, convertOutput, workingDirectory) {
171
+ // Have the ACVM write the partial witness here
172
+ const outputWitnessFile = path.join(workingDirectory, 'partial-witness.gz');
173
+ // Generate the partial witness using the ACVM
174
+ // A further temp directory will be created beneath ours and then cleaned up after the partial witness has been copied to our specified location
175
+ const simulator = new NativeACVMSimulator(this.config.acvmWorkingDirectory, this.config.acvmBinaryPath, outputWitnessFile);
176
+ const artifact = ServerCircuitArtifacts[circuitType];
177
+ logger.debug(`Generating witness data for ${circuitType}`);
178
+ const inputWitness = convertInput(input);
179
+ const timer = new Timer();
180
+ const outputWitness = await simulator.simulateCircuit(inputWitness, artifact);
181
+ const output = convertOutput(outputWitness);
182
+ const circuitName = mapProtocolArtifactNameToCircuitName(circuitType);
183
+ this.instrumentation.recordDuration('witGenDuration', circuitName, timer);
184
+ this.instrumentation.recordSize('witGenInputSize', circuitName, input.toBuffer().length);
185
+ this.instrumentation.recordSize('witGenOutputSize', circuitName, output.toBuffer().length);
186
+ logger.debug(`Generated witness`, {
187
+ circuitName,
188
+ duration: timer.ms(),
189
+ inputSize: input.toBuffer().length,
190
+ outputSize: output.toBuffer().length,
191
+ eventName: 'circuit-witness-generation',
192
+ });
193
+ // Now prove the circuit from the generated witness
194
+ logger.debug(`Proving ${circuitType}...`);
195
+ const provingResult = await generateProof(this.config.bbBinaryPath, workingDirectory, circuitType, Buffer.from(artifact.bytecode, 'base64'), outputWitnessFile, logger.debug);
196
+ if (provingResult.status === BB_RESULT.FAILURE) {
197
+ logger.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`);
198
+ throw new Error(provingResult.reason);
199
+ }
200
+ // Ensure our vk cache is up to date
201
+ const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath, circuitType);
202
+ return {
203
+ circuitOutput: output,
204
+ vkData,
205
+ provingResult,
206
+ };
207
+ }
208
+ async createProof(input, circuitType, convertInput, convertOutput) {
209
+ const operation = async (bbWorkingDirectory) => {
210
+ const { provingResult, vkData, circuitOutput: output, } = await this.generateProofWithBB(input, circuitType, convertInput, convertOutput, bbWorkingDirectory);
211
+ // Read the binary proof
212
+ const rawProof = await fs.readFile(`${provingResult.proofPath}/${PROOF_FILENAME}`);
213
+ const proof = new Proof(rawProof, vkData.numPublicInputs);
214
+ const circuitName = mapProtocolArtifactNameToCircuitName(circuitType);
215
+ this.instrumentation.recordDuration('provingDuration', circuitName, provingResult.durationMs / 1000);
216
+ this.instrumentation.recordSize('proofSize', circuitName, proof.buffer.length);
217
+ this.instrumentation.recordSize('circuitPublicInputCount', circuitName, vkData.numPublicInputs);
218
+ this.instrumentation.recordSize('circuitSize', circuitName, vkData.circuitSize);
219
+ logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.durationMs)} ms`, {
220
+ circuitName,
221
+ // does not include reading the proof from disk
222
+ duration: provingResult.durationMs,
223
+ proofSize: proof.buffer.length,
224
+ eventName: 'circuit-proving',
225
+ // circuitOutput is the partial witness that became the input to the proof
226
+ inputSize: output.toBuffer().length,
227
+ circuitSize: vkData.circuitSize,
228
+ numPublicInputs: vkData.numPublicInputs,
229
+ });
230
+ return { circuitOutput: output, proof };
231
+ };
232
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
233
+ }
234
+ async generateAvmProofWithBB(input, workingDirectory) {
235
+ logger.info(`Proving avm-circuit for ${input.functionName}...`);
236
+ const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.verbose);
237
+ if (provingResult.status === BB_RESULT.FAILURE) {
238
+ logger.error(`Failed to generate AVM proof for ${input.functionName}: ${provingResult.reason}`);
239
+ throw new Error(provingResult.reason);
240
+ }
241
+ return provingResult;
242
+ }
243
+ async createAvmProof(input) {
244
+ const cleanupDir = !process.env.AVM_PROVING_PRESERVE_WORKING_DIR;
245
+ const operation = async (bbWorkingDirectory) => {
246
+ if (!cleanupDir) {
247
+ logger.info(`Preserving working directory ${bbWorkingDirectory}`);
248
+ }
249
+ const provingResult = await this.generateAvmProofWithBB(input, bbWorkingDirectory);
250
+ const rawProof = await fs.readFile(provingResult.proofPath);
251
+ // TODO(https://github.com/AztecProtocol/aztec-packages/issues/6773): this VK data format is wrong.
252
+ // In particular, the number of public inputs, etc will be wrong.
253
+ const verificationKey = await extractVkData(provingResult.vkPath);
254
+ const proof = new Proof(rawProof, verificationKey.numPublicInputs);
255
+ const circuitType = 'avm-circuit';
256
+ const appCircuitName = 'unknown';
257
+ this.instrumentation.recordAvmDuration('provingDuration', appCircuitName, provingResult.durationMs);
258
+ this.instrumentation.recordAvmSize('proofSize', appCircuitName, proof.buffer.length);
259
+ this.instrumentation.recordAvmSize('circuitPublicInputCount', appCircuitName, verificationKey.numPublicInputs);
260
+ this.instrumentation.recordAvmSize('circuitSize', appCircuitName, verificationKey.circuitSize);
261
+ logger.info(`Generated proof for ${circuitType}(${input.functionName}) in ${Math.ceil(provingResult.durationMs)} ms`, {
262
+ circuitName: circuitType,
263
+ appCircuitName: input.functionName,
264
+ // does not include reading the proof from disk
265
+ duration: provingResult.durationMs,
266
+ proofSize: proof.buffer.length,
267
+ eventName: 'circuit-proving',
268
+ inputSize: input.toBuffer().length,
269
+ circuitSize: verificationKey.circuitSize, // FIX: wrong in VK
270
+ numPublicInputs: verificationKey.numPublicInputs, // FIX: wrong in VK
271
+ });
272
+ return { proof, verificationKey };
273
+ };
274
+ return await runInDirectory(this.config.bbWorkingDirectory, operation, cleanupDir);
275
+ }
276
+ /**
277
+ * Executes a circuit and returns it's outputs and corresponding proof with embedded aggregation object
278
+ * @param witnessMap - The input witness
279
+ * @param circuitType - The type of circuit to be executed
280
+ * @param proofLength - The length of the proof to be generated. This is a dummy parameter to aid in type checking
281
+ * @param convertInput - Function for mapping the input object to a witness map.
282
+ * @param convertOutput - Function for parsing the output witness to it's corresponding object
283
+ * @returns The circuits output object and it's proof
284
+ */
285
+ async createRecursiveProof(input, circuitType, proofLength, convertInput, convertOutput) {
286
+ const operation = async (bbWorkingDirectory) => {
287
+ const { provingResult, vkData, circuitOutput: output, } = await this.generateProofWithBB(input, circuitType, convertInput, convertOutput, bbWorkingDirectory);
288
+ // Read the proof as fields
289
+ const proof = await this.readProofAsFields(provingResult.proofPath, circuitType, proofLength);
290
+ const circuitName = mapProtocolArtifactNameToCircuitName(circuitType);
291
+ this.instrumentation.recordDuration('provingDuration', circuitName, provingResult.durationMs / 1000);
292
+ this.instrumentation.recordSize('proofSize', circuitName, proof.binaryProof.buffer.length);
293
+ this.instrumentation.recordSize('circuitPublicInputCount', circuitName, vkData.numPublicInputs);
294
+ this.instrumentation.recordSize('circuitSize', circuitName, vkData.circuitSize);
295
+ logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.durationMs)} ms, size: ${proof.proof.length} fields`, {
296
+ circuitName,
297
+ circuitSize: vkData.circuitSize,
298
+ duration: provingResult.durationMs,
299
+ inputSize: output.toBuffer().length,
300
+ proofSize: proof.binaryProof.buffer.length,
301
+ eventName: 'circuit-proving',
302
+ numPublicInputs: vkData.numPublicInputs,
303
+ });
304
+ return {
305
+ circuitOutput: output,
306
+ proof,
307
+ };
308
+ };
309
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
310
+ }
311
+ /**
312
+ * Verifies a proof, will generate the verification key if one is not cached internally
313
+ * @param circuitType - The type of circuit whose proof is to be verified
314
+ * @param proof - The proof to be verified
315
+ */
316
+ async verifyProof(circuitType, proof) {
317
+ const verificationKey = await this.getVerificationKeyDataForCircuit(circuitType);
318
+ return await this.verifyWithKey(verificationKey, proof);
319
+ }
320
+ async verifyAvmProof(proof, verificationKey) {
321
+ return await this.verifyWithKeyInternal(proof, verificationKey, verifyAvmProof);
322
+ }
323
+ async verifyWithKey(verificationKey, proof) {
324
+ return await this.verifyWithKeyInternal(proof, verificationKey, verifyProof);
325
+ }
326
+ async verifyWithKeyInternal(proof, verificationKey, verificationFunction) {
327
+ const operation = async (bbWorkingDirectory) => {
328
+ const proofFileName = path.join(bbWorkingDirectory, PROOF_FILENAME);
329
+ const verificationKeyPath = path.join(bbWorkingDirectory, VK_FILENAME);
330
+ await fs.writeFile(proofFileName, proof.buffer);
331
+ await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes);
332
+ const logFunction = (message) => {
333
+ logger.debug(`BB out - ${message}`);
334
+ };
335
+ const result = await verificationFunction(this.config.bbBinaryPath, proofFileName, verificationKeyPath, logFunction);
336
+ if (result.status === BB_RESULT.FAILURE) {
337
+ const errorMessage = `Failed to verify proof from key!`;
338
+ throw new Error(errorMessage);
339
+ }
340
+ logger.debug(`Successfully verified proof from key in ${result.durationMs} ms`);
341
+ };
342
+ await runInDirectory(this.config.bbWorkingDirectory, operation);
343
+ }
344
+ /**
345
+ * Returns the verification key for a circuit, will generate it if not cached internally
346
+ * @param circuitType - The type of circuit for which the verification key is required
347
+ * @returns The verification key
348
+ */
349
+ async getVerificationKeyForCircuit(circuitType) {
350
+ const vkData = await this.getVerificationKeyDataForCircuit(circuitType);
351
+ return vkData.clone().keyAsFields;
352
+ }
353
+ /**
354
+ * Will check a recursive proof argument for validity of it's 'fields' format of proof and convert if required
355
+ * @param proof - The input proof that may need converting
356
+ * @returns - The valid proof
357
+ */
358
+ async ensureValidProof(proof, circuit, vk) {
359
+ // If the 'fields' proof is already valid then simply return
360
+ // This will be false for proofs coming from clients
361
+ if (proof.fieldsValid) {
362
+ return proof;
366
363
  }
367
- return extractVkData(result.vkPath);
368
- });
369
- this.verificationKeys.set(circuitType, promise);
370
- }
371
- const vk = await promise;
372
- return vk.clone();
373
- }
374
- /**
375
- * Ensures our verification key cache includes the key data located at the specified directory
376
- * @param filePath - The directory containing the verification key data files
377
- * @param circuitType - The type of circuit to which the verification key corresponds
378
- */
379
- async updateVerificationKeyAfterProof(filePath, circuitType) {
380
- let promise = this.verificationKeys.get(circuitType);
381
- if (!promise) {
382
- promise = extractVkData(filePath);
383
- this.verificationKeys.set(circuitType, promise);
384
- }
385
- return promise;
386
- }
387
- /**
388
- * Parses and returns the proof data stored at the specified directory
389
- * @param filePath - The directory containing the proof data
390
- * @param circuitType - The type of circuit proven
391
- * @returns The proof
392
- */
393
- async readProofAsFields(filePath, circuitType, proofLength) {
394
- const proofFilename = path.join(filePath, PROOF_FILENAME);
395
- const proofFieldsFilename = path.join(filePath, PROOF_FIELDS_FILENAME);
396
- const [binaryProof, proofString] = await Promise.all([
397
- fs.readFile(proofFilename),
398
- fs.readFile(proofFieldsFilename, { encoding: 'utf-8' }),
399
- ]);
400
- const json = JSON.parse(proofString);
401
- const vkData = await this.verificationKeys.get(circuitType);
402
- if (!vkData) {
403
- throw new Error(`Invalid verification key for ${circuitType}`);
404
- }
405
- const numPublicInputs = CIRCUITS_WITHOUT_AGGREGATION.has(circuitType)
406
- ? vkData.numPublicInputs
407
- : vkData.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
408
- const fieldsWithoutPublicInputs = json.slice(numPublicInputs).map(Fr.fromString);
409
- logger.debug(`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}`);
410
- const proof = new RecursiveProof(fieldsWithoutPublicInputs, new Proof(binaryProof, numPublicInputs), true);
411
- if (proof.proof.length !== proofLength) {
412
- throw new Error(`Proof length doesn't match expected length (${proof.proof.length} != ${proofLength})`);
413
- }
414
- return proof;
415
- }
416
- }
417
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmJfcHJvdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb3Zlci9iYl9wcm92ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsa0NBQWtDO0FBQ2xDLE9BQU8sRUFNTCxpQ0FBaUMsR0FDbEMsTUFBTSxzQkFBc0IsQ0FBQztBQUU5QixPQUFPLEVBQ0wseUJBQXlCLEVBS3pCLHdCQUF3QixFQUN4QixlQUFlLEVBQ2YsRUFBRSxFQUdGLDZCQUE2QixFQUU3Qix3QkFBd0IsRUFDeEIsS0FBSyxFQUVMLHNCQUFzQixFQUN0QixjQUFjLEVBQ2QsZUFBZSxFQU1mLDRCQUE0QixHQUM3QixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDaEQsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixzQkFBc0IsRUFFdEIsbUNBQW1DLEVBQ25DLHNDQUFzQyxFQUN0QyxtQ0FBbUMsRUFDbkMsc0NBQXNDLEVBQ3RDLG9DQUFvQyxFQUNwQyx1Q0FBdUMsRUFDdkMsMkNBQTJDLEVBQzNDLDhDQUE4QyxFQUM5QyxtQ0FBbUMsRUFDbkMscUNBQXFDLEVBQ3JDLG1DQUFtQyxFQUNuQyxzQ0FBc0MsRUFDdEMsbUNBQW1DLEVBQ25DLHNDQUFzQyxHQUN2QyxNQUFNLHFDQUFxQyxDQUFDO0FBQzdDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXZELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVqRCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUU3QixPQUFPLEVBRUwsU0FBUyxFQUNULHFCQUFx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
364
+ const operation = async (bbWorkingDirectory) => {
365
+ const numPublicInputs = vk.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
366
+ const proofFullFilename = path.join(bbWorkingDirectory, PROOF_FILENAME);
367
+ const vkFullFilename = path.join(bbWorkingDirectory, VK_FILENAME);
368
+ logger.debug(`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}`);
369
+ await fs.writeFile(proofFullFilename, proof.binaryProof.buffer);
370
+ await fs.writeFile(vkFullFilename, vk.keyAsBytes);
371
+ const logFunction = (message) => {
372
+ logger.debug(`${circuit} BB out - ${message}`);
373
+ };
374
+ const result = await writeProofAsFields(this.config.bbBinaryPath, bbWorkingDirectory, PROOF_FILENAME, vkFullFilename, logFunction);
375
+ if (result.status === BB_RESULT.FAILURE) {
376
+ const errorMessage = `Failed to convert ${circuit} proof to fields, ${result.reason}`;
377
+ throw new Error(errorMessage);
378
+ }
379
+ const proofString = await fs.readFile(path.join(bbWorkingDirectory, PROOF_FIELDS_FILENAME), {
380
+ encoding: 'utf-8',
381
+ });
382
+ const json = JSON.parse(proofString);
383
+ const fields = json.slice(numPublicInputs).map(Fr.fromString);
384
+ return new RecursiveProof(fields, new Proof(proof.binaryProof.buffer, vk.numPublicInputs), true);
385
+ };
386
+ return await runInDirectory(this.config.bbWorkingDirectory, operation);
387
+ }
388
+ /**
389
+ * Returns the verification key data for a circuit, will generate and cache it if not cached internally
390
+ * @param circuitType - The type of circuit for which the verification key is required
391
+ * @returns The verification key data
392
+ */
393
+ async getVerificationKeyDataForCircuit(circuitType) {
394
+ let promise = this.verificationKeys.get(circuitType);
395
+ if (!promise) {
396
+ promise = generateKeyForNoirCircuit(this.config.bbBinaryPath, this.config.bbWorkingDirectory, circuitType, ServerCircuitArtifacts[circuitType], 'vk', logger.debug).then(result => {
397
+ if (result.status === BB_RESULT.FAILURE) {
398
+ throw new Error(`Failed to generate verification key for ${circuitType}, ${result.reason}`);
399
+ }
400
+ return extractVkData(result.vkPath);
401
+ });
402
+ this.verificationKeys.set(circuitType, promise);
403
+ }
404
+ const vk = await promise;
405
+ return vk.clone();
406
+ }
407
+ /**
408
+ * Ensures our verification key cache includes the key data located at the specified directory
409
+ * @param filePath - The directory containing the verification key data files
410
+ * @param circuitType - The type of circuit to which the verification key corresponds
411
+ */
412
+ async updateVerificationKeyAfterProof(filePath, circuitType) {
413
+ let promise = this.verificationKeys.get(circuitType);
414
+ if (!promise) {
415
+ promise = extractVkData(filePath);
416
+ this.verificationKeys.set(circuitType, promise);
417
+ }
418
+ return promise;
419
+ }
420
+ /**
421
+ * Parses and returns the proof data stored at the specified directory
422
+ * @param filePath - The directory containing the proof data
423
+ * @param circuitType - The type of circuit proven
424
+ * @returns The proof
425
+ */
426
+ async readProofAsFields(filePath, circuitType, proofLength) {
427
+ const proofFilename = path.join(filePath, PROOF_FILENAME);
428
+ const proofFieldsFilename = path.join(filePath, PROOF_FIELDS_FILENAME);
429
+ const [binaryProof, proofString] = await Promise.all([
430
+ fs.readFile(proofFilename),
431
+ fs.readFile(proofFieldsFilename, { encoding: 'utf-8' }),
432
+ ]);
433
+ const json = JSON.parse(proofString);
434
+ const vkData = await this.verificationKeys.get(circuitType);
435
+ if (!vkData) {
436
+ throw new Error(`Invalid verification key for ${circuitType}`);
437
+ }
438
+ const numPublicInputs = CIRCUITS_WITHOUT_AGGREGATION.has(circuitType)
439
+ ? vkData.numPublicInputs
440
+ : vkData.numPublicInputs - AGGREGATION_OBJECT_LENGTH;
441
+ const fieldsWithoutPublicInputs = json.slice(numPublicInputs).map(Fr.fromString);
442
+ logger.debug(`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}`);
443
+ const proof = new RecursiveProof(fieldsWithoutPublicInputs, new Proof(binaryProof, numPublicInputs), true);
444
+ if (proof.proof.length !== proofLength) {
445
+ throw new Error(`Proof length doesn't match expected length (${proof.proof.length} != ${proofLength})`);
446
+ }
447
+ return proof;
448
+ }
449
+ },
450
+ (() => {
451
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
452
+ _getBaseParityProof_decorators = [trackSpan('BBNativeRollupProver.getBaseParityProof', { [Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-parity' })];
453
+ _getRootParityProof_decorators = [trackSpan('BBNativeRollupProver.getRootParityProof', { [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-parity' })];
454
+ _getAvmProof_decorators = [trackSpan('BBNativeRollupProver.getAvmProof', inputs => ({
455
+ [Attributes.APP_CIRCUIT_NAME]: inputs.functionName,
456
+ }))];
457
+ _getPublicKernelProof_decorators = [trackSpan('BBNativeRollupProver.getPublicKernelProof', kernelReq => ({
458
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: mapProtocolArtifactNameToCircuitName(PublicKernelArtifactMapping[kernelReq.type].artifact),
459
+ }))];
460
+ __esDecorate(_a, null, _getBaseParityProof_decorators, { kind: "method", name: "getBaseParityProof", static: false, private: false, access: { has: obj => "getBaseParityProof" in obj, get: obj => obj.getBaseParityProof }, metadata: _metadata }, null, _instanceExtraInitializers);
461
+ __esDecorate(_a, null, _getRootParityProof_decorators, { kind: "method", name: "getRootParityProof", static: false, private: false, access: { has: obj => "getRootParityProof" in obj, get: obj => obj.getRootParityProof }, metadata: _metadata }, null, _instanceExtraInitializers);
462
+ __esDecorate(_a, null, _getAvmProof_decorators, { kind: "method", name: "getAvmProof", static: false, private: false, access: { has: obj => "getAvmProof" in obj, get: obj => obj.getAvmProof }, metadata: _metadata }, null, _instanceExtraInitializers);
463
+ __esDecorate(_a, null, _getPublicKernelProof_decorators, { kind: "method", name: "getPublicKernelProof", static: false, private: false, access: { has: obj => "getPublicKernelProof" in obj, get: obj => obj.getPublicKernelProof }, metadata: _metadata }, null, _instanceExtraInitializers);
464
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
465
+ })(),
466
+ _a;
467
+ })();
468
+ export { BBNativeRollupProver };
469
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmJfcHJvdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb3Zlci9iYl9wcm92ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLGtDQUFrQztBQUNsQyxPQUFPLEVBTUwsaUNBQWlDLEdBQ2xDLE1BQU0sc0JBQXNCLENBQUM7QUFFOUIsT0FBTyxFQUNMLHlCQUF5QixFQUt6Qix3QkFBd0IsRUFDeEIsZUFBZSxFQUNmLEVBQUUsRUFHRiw2QkFBNkIsRUFFN0Isd0JBQXdCLEVBQ3hCLEtBQUssRUFFTCxzQkFBc0IsRUFDdEIsY0FBYyxFQUNkLGVBQWUsRUFNZiw0QkFBNEIsR0FDN0IsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDMUQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ2hELE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsc0JBQXNCLEVBRXRCLG1DQUFtQyxFQUNuQyxzQ0FBc0MsRUFDdEMsbUNBQW1DLEVBQ25DLHNDQUFzQyxFQUN0QyxvQ0FBb0MsRUFDcEMsdUNBQXVDLEVBQ3ZDLDJDQUEyQyxFQUMzQyw4Q0FBOEMsRUFDOUMsbUNBQW1DLEVBQ25DLHFDQUFxQyxFQUNyQyxtQ0FBbUMsRUFDbkMsc0NBQXNDLEVBQ3RDLG1DQUFtQyxFQUNuQyxzQ0FBc0MsR0FDdkMsTUFBTSxxQ0FBcUMsQ0FBQztBQUM3QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsVUFBVSxFQUF3QixTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUV0RixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFakQsT0FBTyxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEMsT0FBTyxL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