@aztec/bb-prover 0.0.0-test.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 (97) hide show
  1. package/dest/avm_proving_tests/avm_proving_tester.d.ts +25 -0
  2. package/dest/avm_proving_tests/avm_proving_tester.d.ts.map +1 -0
  3. package/dest/avm_proving_tests/avm_proving_tester.js +105 -0
  4. package/dest/bb/cli.d.ts +12 -0
  5. package/dest/bb/cli.d.ts.map +1 -0
  6. package/dest/bb/cli.js +19 -0
  7. package/dest/bb/execute.d.ts +140 -0
  8. package/dest/bb/execute.d.ts.map +1 -0
  9. package/dest/bb/execute.js +780 -0
  10. package/dest/bb/index.d.ts +3 -0
  11. package/dest/bb/index.d.ts.map +1 -0
  12. package/dest/bb/index.js +16 -0
  13. package/dest/config.d.ts +13 -0
  14. package/dest/config.d.ts.map +1 -0
  15. package/dest/config.js +1 -0
  16. package/dest/honk.d.ts +13 -0
  17. package/dest/honk.d.ts.map +1 -0
  18. package/dest/honk.js +18 -0
  19. package/dest/index.d.ts +8 -0
  20. package/dest/index.d.ts.map +1 -0
  21. package/dest/index.js +6 -0
  22. package/dest/instrumentation.d.ts +47 -0
  23. package/dest/instrumentation.d.ts.map +1 -0
  24. package/dest/instrumentation.js +100 -0
  25. package/dest/prover/bb_native_private_kernel_prover.d.ts +25 -0
  26. package/dest/prover/bb_native_private_kernel_prover.d.ts.map +1 -0
  27. package/dest/prover/bb_native_private_kernel_prover.js +69 -0
  28. package/dest/prover/bb_private_kernel_prover.d.ts +32 -0
  29. package/dest/prover/bb_private_kernel_prover.d.ts.map +1 -0
  30. package/dest/prover/bb_private_kernel_prover.js +109 -0
  31. package/dest/prover/bb_prover.d.ts +120 -0
  32. package/dest/prover/bb_prover.d.ts.map +1 -0
  33. package/dest/prover/bb_prover.js +423 -0
  34. package/dest/prover/client_ivc_proof_utils.d.ts +25 -0
  35. package/dest/prover/client_ivc_proof_utils.d.ts.map +1 -0
  36. package/dest/prover/client_ivc_proof_utils.js +43 -0
  37. package/dest/prover/index.d.ts +4 -0
  38. package/dest/prover/index.d.ts.map +1 -0
  39. package/dest/prover/index.js +3 -0
  40. package/dest/stats.d.ts +5 -0
  41. package/dest/stats.d.ts.map +1 -0
  42. package/dest/stats.js +62 -0
  43. package/dest/test/delay_values.d.ts +4 -0
  44. package/dest/test/delay_values.d.ts.map +1 -0
  45. package/dest/test/delay_values.js +29 -0
  46. package/dest/test/index.d.ts +3 -0
  47. package/dest/test/index.d.ts.map +1 -0
  48. package/dest/test/index.js +2 -0
  49. package/dest/test/test_circuit_prover.d.ts +81 -0
  50. package/dest/test/test_circuit_prover.d.ts.map +1 -0
  51. package/dest/test/test_circuit_prover.js +175 -0
  52. package/dest/test/test_verifier.d.ts +6 -0
  53. package/dest/test/test_verifier.d.ts.map +1 -0
  54. package/dest/test/test_verifier.js +5 -0
  55. package/dest/verification_key/verification_key_data.d.ts +9 -0
  56. package/dest/verification_key/verification_key_data.d.ts.map +1 -0
  57. package/dest/verification_key/verification_key_data.js +44 -0
  58. package/dest/verifier/bb_verifier.d.ts +17 -0
  59. package/dest/verifier/bb_verifier.d.ts.map +1 -0
  60. package/dest/verifier/bb_verifier.js +86 -0
  61. package/dest/verifier/index.d.ts +2 -0
  62. package/dest/verifier/index.d.ts.map +1 -0
  63. package/dest/verifier/index.js +1 -0
  64. package/dest/wasm/bb_wasm_private_kernel_prover.d.ts +17 -0
  65. package/dest/wasm/bb_wasm_private_kernel_prover.d.ts.map +1 -0
  66. package/dest/wasm/bb_wasm_private_kernel_prover.js +46 -0
  67. package/dest/wasm/bundle.d.ts +6 -0
  68. package/dest/wasm/bundle.d.ts.map +1 -0
  69. package/dest/wasm/bundle.js +8 -0
  70. package/dest/wasm/lazy.d.ts +6 -0
  71. package/dest/wasm/lazy.d.ts.map +1 -0
  72. package/dest/wasm/lazy.js +8 -0
  73. package/package.json +111 -0
  74. package/src/avm_proving_tests/avm_proving_tester.ts +170 -0
  75. package/src/bb/cli.ts +32 -0
  76. package/src/bb/execute.ts +853 -0
  77. package/src/bb/index.ts +23 -0
  78. package/src/config.ts +13 -0
  79. package/src/honk.ts +30 -0
  80. package/src/index.ts +8 -0
  81. package/src/instrumentation.ts +144 -0
  82. package/src/prover/bb_native_private_kernel_prover.ts +119 -0
  83. package/src/prover/bb_private_kernel_prover.ts +249 -0
  84. package/src/prover/bb_prover.ts +781 -0
  85. package/src/prover/client_ivc_proof_utils.ts +42 -0
  86. package/src/prover/index.ts +3 -0
  87. package/src/stats.ts +64 -0
  88. package/src/test/delay_values.ts +31 -0
  89. package/src/test/index.ts +2 -0
  90. package/src/test/test_circuit_prover.ts +368 -0
  91. package/src/test/test_verifier.ts +8 -0
  92. package/src/verification_key/verification_key_data.ts +45 -0
  93. package/src/verifier/bb_verifier.ts +114 -0
  94. package/src/verifier/index.ts +1 -0
  95. package/src/wasm/bb_wasm_private_kernel_prover.ts +55 -0
  96. package/src/wasm/bundle.ts +11 -0
  97. package/src/wasm/lazy.ts +11 -0
@@ -0,0 +1,780 @@
1
+ import { sha256 } from '@aztec/foundation/crypto';
2
+ import { Timer } from '@aztec/foundation/timer';
3
+ import * as proc from 'child_process';
4
+ import { promises as fs } from 'fs';
5
+ import { basename, dirname, join } from 'path';
6
+ import { CLIENT_IVC_PROOF_FILE_NAME, CLIENT_IVC_VK_FILE_NAME } from '../prover/client_ivc_proof_utils.js';
7
+ export const VK_FILENAME = 'vk';
8
+ export const VK_FIELDS_FILENAME = 'vk_fields.json';
9
+ export const PROOF_FILENAME = 'proof';
10
+ export const PROOF_FIELDS_FILENAME = 'proof_fields.json';
11
+ export const AVM_INPUTS_FILENAME = 'avm_inputs.bin';
12
+ export const AVM_BYTECODE_FILENAME = 'avm_bytecode.bin';
13
+ export const AVM_PUBLIC_INPUTS_FILENAME = 'avm_public_inputs.bin';
14
+ export const AVM_HINTS_FILENAME = 'avm_hints.bin';
15
+ export var BB_RESULT = /*#__PURE__*/ function(BB_RESULT) {
16
+ BB_RESULT[BB_RESULT["SUCCESS"] = 0] = "SUCCESS";
17
+ BB_RESULT[BB_RESULT["FAILURE"] = 1] = "FAILURE";
18
+ BB_RESULT[BB_RESULT["ALREADY_PRESENT"] = 2] = "ALREADY_PRESENT";
19
+ return BB_RESULT;
20
+ }({});
21
+ /**
22
+ * Invokes the Barretenberg binary with the provided command and args
23
+ * @param pathToBB - The path to the BB binary
24
+ * @param command - The command to execute
25
+ * @param args - The arguments to pass
26
+ * @param logger - A log function
27
+ * @param resultParser - An optional handler for detecting success or failure
28
+ * @returns The completed partial witness outputted from the circuit
29
+ */ export function executeBB(pathToBB, command, args, logger, resultParser = (code)=>code === 0) {
30
+ return new Promise((resolve)=>{
31
+ // spawn the bb process
32
+ const { HARDWARE_CONCURRENCY: _, ...envWithoutConcurrency } = process.env;
33
+ const env = process.env.HARDWARE_CONCURRENCY ? process.env : envWithoutConcurrency;
34
+ logger(`Executing BB with: ${pathToBB} ${command} ${args.join(' ')}`);
35
+ const bb = proc.spawn(pathToBB, [
36
+ command,
37
+ ...args
38
+ ], {
39
+ env
40
+ });
41
+ bb.stdout.on('data', (data)=>{
42
+ const message = data.toString('utf-8').replace(/\n$/, '');
43
+ logger(message);
44
+ });
45
+ bb.stderr.on('data', (data)=>{
46
+ const message = data.toString('utf-8').replace(/\n$/, '');
47
+ logger(message);
48
+ });
49
+ bb.on('close', (exitCode, signal)=>{
50
+ if (resultParser(exitCode)) {
51
+ resolve({
52
+ status: 0,
53
+ exitCode,
54
+ signal
55
+ });
56
+ } else {
57
+ resolve({
58
+ status: 1,
59
+ exitCode,
60
+ signal
61
+ });
62
+ }
63
+ });
64
+ }).catch((_)=>({
65
+ status: 1,
66
+ exitCode: -1,
67
+ signal: undefined
68
+ }));
69
+ }
70
+ // TODO(#7369) comment this etc (really just take inspiration from this and rewrite it all O:))
71
+ export async function executeBbClientIvcProof(pathToBB, workingDirectory, bytecodeStackPath, witnessStackPath, log) {
72
+ // Check that the working directory exists
73
+ try {
74
+ await fs.access(workingDirectory);
75
+ } catch (error) {
76
+ return {
77
+ status: 1,
78
+ reason: `Working directory ${workingDirectory} does not exist`
79
+ };
80
+ }
81
+ // The proof is written to e.g. /workingDirectory/proof
82
+ const outputPath = `${workingDirectory}`;
83
+ const binaryPresent = await fs.access(pathToBB, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
84
+ if (!binaryPresent) {
85
+ return {
86
+ status: 1,
87
+ reason: `Failed to find bb binary at ${pathToBB}`
88
+ };
89
+ }
90
+ try {
91
+ // Write the bytecode to the working directory
92
+ log(`bytecodePath ${bytecodeStackPath}`);
93
+ log(`outputPath ${outputPath}`);
94
+ const args = [
95
+ '-o',
96
+ outputPath,
97
+ '-b',
98
+ bytecodeStackPath,
99
+ '-w',
100
+ witnessStackPath,
101
+ '-v',
102
+ '--scheme',
103
+ 'client_ivc',
104
+ '--input_type',
105
+ 'runtime_stack',
106
+ '--write_vk'
107
+ ];
108
+ const timer = new Timer();
109
+ const logFunction = (message)=>{
110
+ log(`bb - ${message}`);
111
+ };
112
+ const result = await executeBB(pathToBB, 'prove', args, logFunction);
113
+ const durationMs = timer.ms();
114
+ if (result.status == 0) {
115
+ return {
116
+ status: 0,
117
+ durationMs,
118
+ proofPath: `${outputPath}`,
119
+ pkPath: undefined,
120
+ vkPath: `${outputPath}`
121
+ };
122
+ }
123
+ // Not a great error message here but it is difficult to decipher what comes from bb
124
+ return {
125
+ status: 1,
126
+ reason: `Failed to generate proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
127
+ retry: !!result.signal
128
+ };
129
+ } catch (error) {
130
+ return {
131
+ status: 1,
132
+ reason: `${error}`
133
+ };
134
+ }
135
+ }
136
+ function getArgs(flavor) {
137
+ switch(flavor){
138
+ case 'ultra_honk':
139
+ {
140
+ return [
141
+ '--scheme',
142
+ 'ultra_honk',
143
+ '--oracle_hash',
144
+ 'poseidon2'
145
+ ];
146
+ }
147
+ case 'ultra_keccak_honk':
148
+ {
149
+ return [
150
+ '--scheme',
151
+ 'ultra_honk',
152
+ '--oracle_hash',
153
+ 'keccak'
154
+ ];
155
+ }
156
+ case 'ultra_rollup_honk':
157
+ {
158
+ return [
159
+ '--scheme',
160
+ 'ultra_honk',
161
+ '--oracle_hash',
162
+ 'poseidon2',
163
+ '--ipa_accumulation'
164
+ ];
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Used for generating proofs of noir circuits.
170
+ * It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof.
171
+ * @param pathToBB - The full path to the bb binary
172
+ * @param workingDirectory - A working directory for use by bb
173
+ * @param circuitName - An identifier for the circuit
174
+ * @param bytecode - The compiled circuit bytecode
175
+ * @param inputWitnessFile - The circuit input witness
176
+ * @param log - A logging function
177
+ * @returns An object containing a result indication, the location of the proof and the duration taken
178
+ */ export async function generateProof(pathToBB, workingDirectory, circuitName, bytecode, recursive, inputWitnessFile, flavor, log) {
179
+ // Check that the working directory exists
180
+ try {
181
+ await fs.access(workingDirectory);
182
+ } catch (error) {
183
+ return {
184
+ status: 1,
185
+ reason: `Working directory ${workingDirectory} does not exist`
186
+ };
187
+ }
188
+ // The bytecode is written to e.g. /workingDirectory/BaseParityArtifact-bytecode
189
+ const bytecodePath = `${workingDirectory}/${circuitName}-bytecode`;
190
+ // The proof is written to e.g. /workingDirectory/ultra_honk/proof
191
+ const outputPath = `${workingDirectory}`;
192
+ const binaryPresent = await fs.access(pathToBB, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
193
+ if (!binaryPresent) {
194
+ return {
195
+ status: 1,
196
+ reason: `Failed to find bb binary at ${pathToBB}`
197
+ };
198
+ }
199
+ try {
200
+ // Write the bytecode to the working directory
201
+ await fs.writeFile(bytecodePath, bytecode);
202
+ const args = getArgs(flavor).concat([
203
+ '--output_format',
204
+ 'bytes_and_fields',
205
+ '--write_vk',
206
+ '-o',
207
+ outputPath,
208
+ '-b',
209
+ bytecodePath,
210
+ '-w',
211
+ inputWitnessFile,
212
+ '-v'
213
+ ]);
214
+ if (recursive) {
215
+ args.push('--init_kzg_accumulator');
216
+ }
217
+ const timer = new Timer();
218
+ const logFunction = (message)=>{
219
+ log(`${circuitName} BB out - ${message}`);
220
+ };
221
+ const result = await executeBB(pathToBB, `prove`, args, logFunction);
222
+ const duration = timer.ms();
223
+ if (result.status == 0) {
224
+ return {
225
+ status: 0,
226
+ durationMs: duration,
227
+ proofPath: `${outputPath}`,
228
+ pkPath: undefined,
229
+ vkPath: `${outputPath}`
230
+ };
231
+ }
232
+ // Not a great error message here but it is difficult to decipher what comes from bb
233
+ return {
234
+ status: 1,
235
+ reason: `Failed to generate proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
236
+ retry: !!result.signal
237
+ };
238
+ } catch (error) {
239
+ return {
240
+ status: 1,
241
+ reason: `${error}`
242
+ };
243
+ }
244
+ }
245
+ /**
246
+ * Used for generating proofs of the tube circuit
247
+ * It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof.
248
+ * @param pathToBB - The full path to the bb binary
249
+ * @param workingDirectory - A working directory for use by bb
250
+ * @param circuitName - An identifier for the circuit
251
+ * @param bytecode - The compiled circuit bytecode
252
+ * @param inputWitnessFile - The circuit input witness
253
+ * @param log - A logging function
254
+ * @returns An object containing a result indication, the location of the proof and the duration taken
255
+ */ export async function generateTubeProof(pathToBB, workingDirectory, log) {
256
+ // Check that the working directory exists
257
+ try {
258
+ await fs.access(workingDirectory);
259
+ } catch (error) {
260
+ return {
261
+ status: 1,
262
+ reason: `Working directory ${workingDirectory} does not exist`
263
+ };
264
+ }
265
+ // // Paths for the inputs
266
+ const vkPath = join(workingDirectory, CLIENT_IVC_VK_FILE_NAME);
267
+ const proofPath = join(workingDirectory, CLIENT_IVC_PROOF_FILE_NAME);
268
+ // The proof is written to e.g. /workingDirectory/proof
269
+ const outputPath = workingDirectory;
270
+ const filePresent = async (file)=>await fs.access(file, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
271
+ const binaryPresent = await filePresent(pathToBB);
272
+ if (!binaryPresent) {
273
+ return {
274
+ status: 1,
275
+ reason: `Failed to find bb binary at ${pathToBB}`
276
+ };
277
+ }
278
+ try {
279
+ if (!await filePresent(vkPath) || !await filePresent(proofPath)) {
280
+ return {
281
+ status: 1,
282
+ reason: `Client IVC input files not present in ${workingDirectory}`
283
+ };
284
+ }
285
+ const args = [
286
+ '-o',
287
+ outputPath,
288
+ '-v'
289
+ ];
290
+ const timer = new Timer();
291
+ const logFunction = (message)=>{
292
+ log(`TubeCircuit (prove) BB out - ${message}`);
293
+ };
294
+ const result = await executeBB(pathToBB, 'prove_tube', args, logFunction);
295
+ const durationMs = timer.ms();
296
+ if (result.status == 0) {
297
+ return {
298
+ status: 0,
299
+ durationMs,
300
+ proofPath: outputPath,
301
+ pkPath: undefined,
302
+ vkPath: outputPath
303
+ };
304
+ }
305
+ // Not a great error message here but it is difficult to decipher what comes from bb
306
+ return {
307
+ status: 1,
308
+ reason: `Failed to generate proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
309
+ retry: !!result.signal
310
+ };
311
+ } catch (error) {
312
+ return {
313
+ status: 1,
314
+ reason: `${error}`
315
+ };
316
+ }
317
+ }
318
+ /**
319
+ * Used for generating AVM proofs.
320
+ * It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof.
321
+ * @param pathToBB - The full path to the bb binary
322
+ * @param workingDirectory - A working directory for use by bb
323
+ * @param input - The inputs for the public function to be proven
324
+ * @param log - A logging function
325
+ * @returns An object containing a result indication, the location of the proof and the duration taken
326
+ */ export async function generateAvmProofV2(pathToBB, workingDirectory, input, logger) {
327
+ // Check that the working directory exists
328
+ try {
329
+ await fs.access(workingDirectory);
330
+ } catch (error) {
331
+ return {
332
+ status: 1,
333
+ reason: `Working directory ${workingDirectory} does not exist`
334
+ };
335
+ }
336
+ // The proof is written to e.g. /workingDirectory/proof
337
+ const outputPath = workingDirectory;
338
+ const filePresent = async (file)=>await fs.access(file, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
339
+ const binaryPresent = await filePresent(pathToBB);
340
+ if (!binaryPresent) {
341
+ return {
342
+ status: 1,
343
+ reason: `Failed to find bb binary at ${pathToBB}`
344
+ };
345
+ }
346
+ const inputsBuffer = input.serializeWithMessagePack();
347
+ try {
348
+ // Write the inputs to the working directory.
349
+ const avmInputsPath = join(workingDirectory, AVM_INPUTS_FILENAME);
350
+ await fs.writeFile(avmInputsPath, inputsBuffer);
351
+ if (!await filePresent(avmInputsPath)) {
352
+ return {
353
+ status: 1,
354
+ reason: `Could not write avm inputs to ${avmInputsPath}`
355
+ };
356
+ }
357
+ const args = [
358
+ '--avm-inputs',
359
+ avmInputsPath,
360
+ '-o',
361
+ outputPath
362
+ ];
363
+ const loggingArg = logger.level === 'debug' || logger.level === 'trace' ? '-d' : logger.level === 'verbose' ? '-v' : '';
364
+ if (loggingArg !== '') {
365
+ args.push(loggingArg);
366
+ }
367
+ const timer = new Timer();
368
+ const logFunction = (message)=>{
369
+ logger.verbose(`AvmCircuit (prove) BB out - ${message}`);
370
+ };
371
+ const result = await executeBB(pathToBB, 'avm2_prove', args, logFunction);
372
+ const duration = timer.ms();
373
+ if (result.status == 0) {
374
+ return {
375
+ status: 0,
376
+ durationMs: duration,
377
+ proofPath: join(outputPath, PROOF_FILENAME),
378
+ pkPath: undefined,
379
+ vkPath: outputPath
380
+ };
381
+ }
382
+ // Not a great error message here but it is difficult to decipher what comes from bb
383
+ return {
384
+ status: 1,
385
+ reason: `Failed to generate proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
386
+ retry: !!result.signal
387
+ };
388
+ } catch (error) {
389
+ return {
390
+ status: 1,
391
+ reason: `${error}`
392
+ };
393
+ }
394
+ }
395
+ /**
396
+ * Used for generating AVM proofs (or doing check-circuit).
397
+ * It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof.
398
+ * @param pathToBB - The full path to the bb binary
399
+ * @param workingDirectory - A working directory for use by bb
400
+ * @param bytecode - The AVM bytecode for the public function to be proven (expected to be decompressed)
401
+ * @param log - A logging function
402
+ * @returns An object containing a result indication, the location of the proof and the duration taken
403
+ */ export async function generateAvmProof(pathToBB, workingDirectory, _input, logger, checkCircuitOnly = false) {
404
+ // Check that the working directory exists
405
+ try {
406
+ await fs.access(workingDirectory);
407
+ } catch (error) {
408
+ return {
409
+ status: 1,
410
+ reason: `Working directory ${workingDirectory} does not exist`
411
+ };
412
+ }
413
+ // Paths for the inputs
414
+ const publicInputsPath = join(workingDirectory, AVM_PUBLIC_INPUTS_FILENAME);
415
+ const avmHintsPath = join(workingDirectory, AVM_HINTS_FILENAME);
416
+ // The proof is written to e.g. /workingDirectory/proof
417
+ const outputPath = workingDirectory;
418
+ const filePresent = async (file)=>await fs.access(file, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
419
+ const binaryPresent = await filePresent(pathToBB);
420
+ if (!binaryPresent) {
421
+ return {
422
+ status: 1,
423
+ reason: `Failed to find bb binary at ${pathToBB}`
424
+ };
425
+ }
426
+ try {
427
+ // Write the inputs to the working directory.
428
+ // WARNING: Not writing the inputs since VM1 is disabled!
429
+ // await fs.writeFile(publicInputsPath, input.publicInputs.toBuffer());
430
+ // if (!(await filePresent(publicInputsPath))) {
431
+ // return { status: BB_RESULT.FAILURE, reason: `Could not write publicInputs at ${publicInputsPath}` };
432
+ // }
433
+ // await fs.writeFile(avmHintsPath, input.avmHints.toBuffer());
434
+ // if (!(await filePresent(avmHintsPath))) {
435
+ // return { status: BB_RESULT.FAILURE, reason: `Could not write avmHints at ${avmHintsPath}` };
436
+ // }
437
+ const args = [
438
+ '--avm-public-inputs',
439
+ publicInputsPath,
440
+ '--avm-hints',
441
+ avmHintsPath,
442
+ '-o',
443
+ outputPath
444
+ ];
445
+ const loggingArg = logger.level === 'debug' || logger.level === 'trace' ? '-d' : logger.level === 'verbose' ? '-v' : '';
446
+ if (loggingArg !== '') {
447
+ args.push(loggingArg);
448
+ }
449
+ const timer = new Timer();
450
+ const cmd = checkCircuitOnly ? 'check_circuit' : 'prove';
451
+ const logFunction = (message)=>{
452
+ logger.verbose(`AvmCircuit (${cmd}) BB out - ${message}`);
453
+ };
454
+ const result = await executeBB(pathToBB, `avm_${cmd}`, args, logFunction);
455
+ const duration = timer.ms();
456
+ if (result.status == 0) {
457
+ return {
458
+ status: 0,
459
+ durationMs: duration,
460
+ proofPath: join(outputPath, PROOF_FILENAME),
461
+ pkPath: undefined,
462
+ vkPath: outputPath
463
+ };
464
+ }
465
+ // Not a great error message here but it is difficult to decipher what comes from bb
466
+ return {
467
+ status: 1,
468
+ reason: `Failed to generate proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
469
+ retry: !!result.signal
470
+ };
471
+ } catch (error) {
472
+ return {
473
+ status: 1,
474
+ reason: `${error}`
475
+ };
476
+ }
477
+ }
478
+ /**
479
+ * Used for verifying proofs of noir circuits
480
+ * @param pathToBB - The full path to the bb binary
481
+ * @param proofFullPath - The full path to the proof to be verified
482
+ * @param verificationKeyPath - The full path to the circuit verification key
483
+ * @param log - A logging function
484
+ * @returns An object containing a result indication and duration taken
485
+ */ export async function verifyProof(pathToBB, proofFullPath, verificationKeyPath, ultraHonkFlavor, log) {
486
+ return await verifyProofInternal(pathToBB, proofFullPath, verificationKeyPath, `verify`, log, getArgs(ultraHonkFlavor));
487
+ }
488
+ /**
489
+ * Used for verifying proofs of the AVM
490
+ * @param pathToBB - The full path to the bb binary
491
+ * @param proofFullPath - The full path to the proof to be verified
492
+ * @param verificationKeyPath - The full path to the circuit verification key
493
+ * @param log - A logging function
494
+ * @returns An object containing a result indication and duration taken
495
+ */ export async function verifyAvmProof(pathToBB, proofFullPath, verificationKeyPath, logger) {
496
+ return await verifyProofInternal(pathToBB, proofFullPath, verificationKeyPath, 'avm_verify', logger);
497
+ }
498
+ export async function verifyAvmProofV2(pathToBB, workingDirectory, proofFullPath, publicInputs, verificationKeyPath, logger) {
499
+ const inputsBuffer = publicInputs.serializeWithMessagePack();
500
+ // Write the inputs to the working directory.
501
+ const filePresent = async (file)=>await fs.access(file, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
502
+ const avmInputsPath = join(workingDirectory, 'avm_public_inputs.bin');
503
+ await fs.writeFile(avmInputsPath, inputsBuffer);
504
+ if (!await filePresent(avmInputsPath)) {
505
+ return {
506
+ status: 1,
507
+ reason: `Could not write avm inputs to ${avmInputsPath}`
508
+ };
509
+ }
510
+ return await verifyProofInternal(pathToBB, proofFullPath, verificationKeyPath, 'avm2_verify', logger, [
511
+ '--avm-public-inputs',
512
+ avmInputsPath
513
+ ]);
514
+ }
515
+ /**
516
+ * Verifies a ClientIvcProof
517
+ * TODO(#7370) The verification keys should be supplied separately
518
+ * @param pathToBB - The full path to the bb binary
519
+ * @param targetPath - The path to the folder with the proof, accumulator, and verification keys
520
+ * @param log - A logging function
521
+ * @returns An object containing a result indication and duration taken
522
+ */ export async function verifyClientIvcProof(pathToBB, proofPath, keyPath, log) {
523
+ const binaryPresent = await fs.access(pathToBB, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
524
+ if (!binaryPresent) {
525
+ return {
526
+ status: 1,
527
+ reason: `Failed to find bb binary at ${pathToBB}`
528
+ };
529
+ }
530
+ try {
531
+ const args = [
532
+ '--scheme',
533
+ 'client_ivc',
534
+ '-p',
535
+ proofPath,
536
+ '-k',
537
+ keyPath
538
+ ];
539
+ const timer = new Timer();
540
+ const command = 'verify';
541
+ const result = await executeBB(pathToBB, command, args, log);
542
+ const duration = timer.ms();
543
+ if (result.status == 0) {
544
+ return {
545
+ status: 0,
546
+ durationMs: duration
547
+ };
548
+ }
549
+ // Not a great error message here but it is difficult to decipher what comes from bb
550
+ return {
551
+ status: 1,
552
+ reason: `Failed to verify proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
553
+ retry: !!result.signal
554
+ };
555
+ } catch (error) {
556
+ return {
557
+ status: 1,
558
+ reason: `${error}`
559
+ };
560
+ }
561
+ }
562
+ /**
563
+ * Used for verifying proofs with BB
564
+ * @param pathToBB - The full path to the bb binary
565
+ * @param proofFullPath - The full path to the proof to be verified
566
+ * @param verificationKeyPath - The full path to the circuit verification key
567
+ * @param command - The BB command to execute (verify/avm_verify)
568
+ * @param log - A logging function
569
+ * @returns An object containing a result indication and duration taken
570
+ */ async function verifyProofInternal(pathToBB, proofFullPath, verificationKeyPath, command, logger, extraArgs = []) {
571
+ const binaryPresent = await fs.access(pathToBB, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
572
+ if (!binaryPresent) {
573
+ return {
574
+ status: 1,
575
+ reason: `Failed to find bb binary at ${pathToBB}`
576
+ };
577
+ }
578
+ const logFunction = (message)=>{
579
+ logger.verbose(`bb-prover (verify) BB out - ${message}`);
580
+ };
581
+ try {
582
+ const args = [
583
+ '-p',
584
+ proofFullPath,
585
+ '-k',
586
+ verificationKeyPath,
587
+ ...extraArgs
588
+ ];
589
+ const loggingArg = logger.level === 'debug' || logger.level === 'trace' ? '-d' : logger.level === 'verbose' ? '-v' : '';
590
+ if (loggingArg !== '') {
591
+ args.push(loggingArg);
592
+ }
593
+ const timer = new Timer();
594
+ const result = await executeBB(pathToBB, command, args, logFunction);
595
+ const duration = timer.ms();
596
+ if (result.status == 0) {
597
+ return {
598
+ status: 0,
599
+ durationMs: duration
600
+ };
601
+ }
602
+ // Not a great error message here but it is difficult to decipher what comes from bb
603
+ return {
604
+ status: 1,
605
+ reason: `Failed to verify proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
606
+ retry: !!result.signal
607
+ };
608
+ } catch (error) {
609
+ return {
610
+ status: 1,
611
+ reason: `${error}`
612
+ };
613
+ }
614
+ }
615
+ export async function generateContractForVerificationKey(pathToBB, vkFilePath, contractPath, log) {
616
+ const binaryPresent = await fs.access(pathToBB, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
617
+ if (!binaryPresent) {
618
+ return {
619
+ status: 1,
620
+ reason: `Failed to find bb binary at ${pathToBB}`
621
+ };
622
+ }
623
+ const outputDir = dirname(contractPath);
624
+ const contractName = basename(contractPath);
625
+ // cache contract generation based on vk file and contract name
626
+ const cacheKey = sha256(Buffer.concat([
627
+ Buffer.from(contractName),
628
+ await fs.readFile(vkFilePath)
629
+ ]));
630
+ await fs.mkdir(outputDir, {
631
+ recursive: true
632
+ });
633
+ const res = await fsCache(outputDir, cacheKey, log, false, async ()=>{
634
+ try {
635
+ const args = [
636
+ '--scheme',
637
+ 'ultra_honk',
638
+ '-k',
639
+ vkFilePath,
640
+ '-o',
641
+ contractPath,
642
+ '-v'
643
+ ];
644
+ const timer = new Timer();
645
+ const result = await executeBB(pathToBB, 'contract', args, log);
646
+ const duration = timer.ms();
647
+ if (result.status == 0) {
648
+ return {
649
+ status: 0,
650
+ durationMs: duration,
651
+ contractPath
652
+ };
653
+ }
654
+ // Not a great error message here but it is difficult to decipher what comes from bb
655
+ return {
656
+ status: 1,
657
+ reason: `Failed to write verifier contract. Exit code ${result.exitCode}. Signal ${result.signal}.`,
658
+ retry: !!result.signal
659
+ };
660
+ } catch (error) {
661
+ return {
662
+ status: 1,
663
+ reason: `${error}`
664
+ };
665
+ }
666
+ });
667
+ if (!res) {
668
+ return {
669
+ status: 2,
670
+ durationMs: 0,
671
+ contractPath
672
+ };
673
+ }
674
+ return res;
675
+ }
676
+ /**
677
+ * Compute bb gate count for a given circuit
678
+ * @param pathToBB - The full path to the bb binary
679
+ * @param workingDirectory - A temporary directory for writing the bytecode
680
+ * @param circuitName - The name of the circuit
681
+ * @param bytecode - The bytecode of the circuit
682
+ * @param flavor - The flavor of the backend - mega_honk or ultra_honk variants
683
+ * @returns An object containing the status, gate count, and time taken
684
+ */ export async function computeGateCountForCircuit(pathToBB, workingDirectory, circuitName, bytecode, flavor, log) {
685
+ // Check that the working directory exists
686
+ try {
687
+ await fs.access(workingDirectory);
688
+ } catch (error) {
689
+ return {
690
+ status: 1,
691
+ reason: `Working directory ${workingDirectory} does not exist`
692
+ };
693
+ }
694
+ // The bytecode is written to e.g. /workingDirectory/BaseParityArtifact-bytecode
695
+ const bytecodePath = `${workingDirectory}/${circuitName}-bytecode`;
696
+ const binaryPresent = await fs.access(pathToBB, fs.constants.R_OK).then((_)=>true).catch((_)=>false);
697
+ if (!binaryPresent) {
698
+ return {
699
+ status: 1,
700
+ reason: `Failed to find bb binary at ${pathToBB}`
701
+ };
702
+ }
703
+ // Accumulate the stdout from bb
704
+ let stdout = '';
705
+ const logHandler = (message)=>{
706
+ stdout += message;
707
+ log(message);
708
+ };
709
+ try {
710
+ // Write the bytecode to the working directory
711
+ await fs.writeFile(bytecodePath, bytecode);
712
+ const timer = new Timer();
713
+ const result = await executeBB(pathToBB, 'gates', [
714
+ '--scheme',
715
+ flavor === 'mega_honk' ? 'client_ivc' : 'ultra_honk',
716
+ '-b',
717
+ bytecodePath,
718
+ '-v'
719
+ ], logHandler);
720
+ const duration = timer.ms();
721
+ if (result.status == 0) {
722
+ // Look for "circuit_size" in the stdout and parse the number
723
+ const circuitSizeMatch = stdout.match(/circuit_size": (\d+)/);
724
+ if (!circuitSizeMatch) {
725
+ return {
726
+ status: 1,
727
+ reason: 'Failed to parse circuit_size from bb gates stdout.'
728
+ };
729
+ }
730
+ const circuitSize = parseInt(circuitSizeMatch[1]);
731
+ return {
732
+ status: 0,
733
+ durationMs: duration,
734
+ circuitSize: circuitSize
735
+ };
736
+ }
737
+ return {
738
+ status: 1,
739
+ reason: 'Failed getting the gate count.'
740
+ };
741
+ } catch (error) {
742
+ return {
743
+ status: 1,
744
+ reason: `${error}`
745
+ };
746
+ }
747
+ }
748
+ const CACHE_FILENAME = '.cache';
749
+ async function fsCache(dir, expectedCacheKey, logger, force, action) {
750
+ const cacheFilePath = join(dir, CACHE_FILENAME);
751
+ let run;
752
+ if (force) {
753
+ run = true;
754
+ } else {
755
+ try {
756
+ run = !expectedCacheKey.equals(await fs.readFile(cacheFilePath));
757
+ } catch (err) {
758
+ if (err && 'code' in err && err.code === 'ENOENT') {
759
+ // cache file doesn't exist, swallow error and run
760
+ run = true;
761
+ } else {
762
+ throw err;
763
+ }
764
+ }
765
+ }
766
+ let res;
767
+ if (run) {
768
+ logger(`Cache miss or forced run. Running operation in ${dir}...`);
769
+ res = await action();
770
+ } else {
771
+ logger(`Cache hit. Skipping operation in ${dir}...`);
772
+ }
773
+ try {
774
+ await fs.writeFile(cacheFilePath, expectedCacheKey);
775
+ } catch (err) {
776
+ logger(`Couldn't write cache data to ${cacheFilePath}. Skipping cache...`);
777
+ // ignore
778
+ }
779
+ return res;
780
+ }