@aztec/bb-prover 0.76.4 → 0.77.0-testnet-ignition.21

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