@aztec/bb-prover 0.41.0 → 0.43.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.
- package/dest/bb/cli.d.ts.map +1 -1
- package/dest/bb/cli.js +24 -2
- package/dest/bb/execute.d.ts +30 -1
- package/dest/bb/execute.d.ts.map +1 -1
- package/dest/bb/execute.js +252 -60
- package/dest/config.d.ts +9 -0
- package/dest/config.d.ts.map +1 -0
- package/dest/config.js +2 -0
- package/dest/index.d.ts +2 -0
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +3 -1
- package/dest/mappings/mappings.d.ts +1 -0
- package/dest/mappings/mappings.d.ts.map +1 -1
- package/dest/mappings/mappings.js +27 -8
- package/dest/prover/bb_native_proof_creator.d.ts +2 -8
- package/dest/prover/bb_native_proof_creator.d.ts.map +1 -1
- package/dest/prover/bb_native_proof_creator.js +37 -79
- package/dest/prover/bb_prover.d.ts +33 -32
- package/dest/prover/bb_prover.d.ts.map +1 -1
- package/dest/prover/bb_prover.js +231 -162
- package/dest/stats.d.ts.map +1 -1
- package/dest/stats.js +8 -2
- package/dest/test/index.d.ts +1 -0
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +2 -1
- package/dest/test/test_circuit_prover.d.ts +9 -7
- package/dest/test/test_circuit_prover.d.ts.map +1 -1
- package/dest/test/test_circuit_prover.js +32 -16
- package/dest/test/test_verifier.d.ts +7 -0
- package/dest/test/test_verifier.d.ts.map +1 -0
- package/dest/test/test_verifier.js +10 -0
- package/dest/verification_key/verification_key_data.d.ts +8 -0
- package/dest/verification_key/verification_key_data.d.ts.map +1 -0
- package/dest/verification_key/verification_key_data.js +24 -0
- package/dest/verifier/bb_verifier.d.ts +18 -0
- package/dest/verifier/bb_verifier.d.ts.map +1 -0
- package/dest/verifier/bb_verifier.js +90 -0
- package/dest/verifier/index.d.ts +2 -0
- package/dest/verifier/index.d.ts.map +1 -0
- package/dest/verifier/index.js +2 -0
- package/package.json +6 -6
- package/src/bb/cli.ts +36 -1
- package/src/bb/execute.ts +340 -67
- package/src/config.ts +9 -0
- package/src/index.ts +2 -0
- package/src/mappings/mappings.ts +38 -12
- package/src/prover/bb_native_proof_creator.ts +49 -91
- package/src/prover/bb_prover.ts +396 -221
- package/src/stats.ts +7 -1
- package/src/test/index.ts +1 -0
- package/src/test/test_circuit_prover.ts +85 -23
- package/src/test/test_verifier.ts +12 -0
- package/src/verification_key/verification_key_data.ts +35 -0
- package/src/verifier/bb_verifier.ts +156 -0
- package/src/verifier/index.ts +1 -0
- package/dest/prover/verification_key_data.d.ts +0 -16
- package/dest/prover/verification_key_data.d.ts.map +0 -1
- package/dest/prover/verification_key_data.js +0 -5
- package/src/prover/verification_key_data.ts +0 -16
package/src/bb/execute.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AvmCircuitInputs } from '@aztec/circuits.js';
|
|
1
2
|
import { sha256 } from '@aztec/foundation/crypto';
|
|
2
3
|
import { type LogFn } from '@aztec/foundation/log';
|
|
3
4
|
import { Timer } from '@aztec/foundation/timer';
|
|
@@ -5,6 +6,7 @@ import { type NoirCompiledCircuit } from '@aztec/types/noir';
|
|
|
5
6
|
|
|
6
7
|
import * as proc from 'child_process';
|
|
7
8
|
import * as fs from 'fs/promises';
|
|
9
|
+
import { basename, dirname, join } from 'path';
|
|
8
10
|
|
|
9
11
|
export const VK_FILENAME = 'vk';
|
|
10
12
|
export const VK_FIELDS_FILENAME = 'vk_fields.json';
|
|
@@ -20,9 +22,14 @@ export enum BB_RESULT {
|
|
|
20
22
|
export type BBSuccess = {
|
|
21
23
|
status: BB_RESULT.SUCCESS | BB_RESULT.ALREADY_PRESENT;
|
|
22
24
|
duration: number;
|
|
25
|
+
/** Full path of the public key. */
|
|
23
26
|
pkPath?: string;
|
|
27
|
+
/** Base directory for the VKs (raw, fields). */
|
|
24
28
|
vkPath?: string;
|
|
29
|
+
/** Full path of the proof. */
|
|
25
30
|
proofPath?: string;
|
|
31
|
+
/** Full path of the contract. */
|
|
32
|
+
contractPath?: string;
|
|
26
33
|
};
|
|
27
34
|
|
|
28
35
|
export type BBFailure = {
|
|
@@ -32,6 +39,8 @@ export type BBFailure = {
|
|
|
32
39
|
|
|
33
40
|
export type BBResult = BBSuccess | BBFailure;
|
|
34
41
|
|
|
42
|
+
export type VerificationFunction = typeof verifyProof | typeof verifyAvmProof;
|
|
43
|
+
|
|
35
44
|
type BBExecResult = {
|
|
36
45
|
status: BB_RESULT;
|
|
37
46
|
exitCode: number;
|
|
@@ -56,8 +65,19 @@ export function executeBB(
|
|
|
56
65
|
): Promise<BBExecResult> {
|
|
57
66
|
return new Promise<BBExecResult>(resolve => {
|
|
58
67
|
// spawn the bb process
|
|
68
|
+
const { HARDWARE_CONCURRENCY: _, ...envWithoutConcurrency } = process.env;
|
|
69
|
+
const env = process.env.HARDWARE_CONCURRENCY ? process.env : envWithoutConcurrency;
|
|
70
|
+
logger(`Executing BB with: ${command} ${args.join(' ')}`);
|
|
59
71
|
const bb = proc.spawn(pathToBB, [command, ...args], {
|
|
60
|
-
|
|
72
|
+
env,
|
|
73
|
+
});
|
|
74
|
+
bb.stdout.on('data', data => {
|
|
75
|
+
const message = data.toString('utf-8').replace(/\n$/, '');
|
|
76
|
+
logger(message);
|
|
77
|
+
});
|
|
78
|
+
bb.stderr.on('data', data => {
|
|
79
|
+
const message = data.toString('utf-8').replace(/\n$/, '');
|
|
80
|
+
logger(message);
|
|
61
81
|
});
|
|
62
82
|
bb.on('close', (exitCode: number, signal?: string) => {
|
|
63
83
|
if (resultParser(exitCode)) {
|
|
@@ -69,7 +89,6 @@ export function executeBB(
|
|
|
69
89
|
}).catch(_ => ({ status: BB_RESULT.FAILURE, exitCode: -1, signal: undefined }));
|
|
70
90
|
}
|
|
71
91
|
|
|
72
|
-
const bytecodeHashFilename = 'bytecode_hash';
|
|
73
92
|
const bytecodeFilename = 'bytecode';
|
|
74
93
|
|
|
75
94
|
/**
|
|
@@ -101,41 +120,101 @@ export async function generateKeyForNoirCircuit(
|
|
|
101
120
|
// The bytecode is written to e.g. /workingDirectory/pk/BaseParityArtifact/bytecode
|
|
102
121
|
// The bytecode is removed after the key is generated, leaving just the hash file
|
|
103
122
|
const circuitOutputDirectory = `${workingDirectory}/${key}/${circuitName}`;
|
|
104
|
-
const bytecodeHashPath = `${circuitOutputDirectory}/${bytecodeHashFilename}`;
|
|
105
|
-
const bytecodePath = `${circuitOutputDirectory}/${bytecodeFilename}`;
|
|
106
|
-
const bytecodeHash = sha256(bytecode);
|
|
107
|
-
|
|
108
123
|
const outputPath = `${circuitOutputDirectory}`;
|
|
124
|
+
const bytecodeHash = sha256(bytecode);
|
|
109
125
|
|
|
110
126
|
// ensure the directory exists
|
|
111
127
|
await fs.mkdir(circuitOutputDirectory, { recursive: true });
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
.
|
|
118
|
-
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
const res = await fsCache<BBSuccess | BBFailure>(circuitOutputDirectory, bytecodeHash, log, force, async () => {
|
|
130
|
+
const binaryPresent = await fs
|
|
131
|
+
.access(pathToBB, fs.constants.R_OK)
|
|
132
|
+
.then(_ => true)
|
|
133
|
+
.catch(_ => false);
|
|
134
|
+
if (!binaryPresent) {
|
|
135
|
+
return { status: BB_RESULT.FAILURE, reason: `Failed to find bb binary at ${pathToBB}` };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// We are now going to generate the key
|
|
139
|
+
try {
|
|
140
|
+
const bytecodePath = `${circuitOutputDirectory}/${bytecodeFilename}`;
|
|
141
|
+
// Write the bytecode to the working directory
|
|
142
|
+
await fs.writeFile(bytecodePath, bytecode);
|
|
143
|
+
|
|
144
|
+
// args are the output path and the input bytecode path
|
|
145
|
+
const args = ['-o', `${outputPath}/${VK_FILENAME}`, '-b', bytecodePath];
|
|
146
|
+
const timer = new Timer();
|
|
147
|
+
let result = await executeBB(pathToBB, `write_${key}`, args, log);
|
|
148
|
+
// If we succeeded and the type of key if verification, have bb write the 'fields' version too
|
|
149
|
+
if (result.status == BB_RESULT.SUCCESS && key === 'vk') {
|
|
150
|
+
const asFieldsArgs = ['-k', `${outputPath}/${VK_FILENAME}`, '-o', `${outputPath}/${VK_FIELDS_FILENAME}`, '-v'];
|
|
151
|
+
result = await executeBB(pathToBB, `vk_as_fields`, asFieldsArgs, log);
|
|
152
|
+
}
|
|
153
|
+
const duration = timer.ms();
|
|
126
154
|
|
|
127
|
-
|
|
128
|
-
|
|
155
|
+
if (result.status == BB_RESULT.SUCCESS) {
|
|
156
|
+
return {
|
|
157
|
+
status: BB_RESULT.SUCCESS,
|
|
158
|
+
duration,
|
|
159
|
+
pkPath: key === 'pk' ? outputPath : undefined,
|
|
160
|
+
vkPath: key === 'vk' ? outputPath : undefined,
|
|
161
|
+
proofPath: undefined,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// Not a great error message here but it is difficult to decipher what comes from bb
|
|
165
|
+
return {
|
|
166
|
+
status: BB_RESULT.FAILURE,
|
|
167
|
+
reason: `Failed to generate key. Exit code: ${result.exitCode}. Signal ${result.signal}.`,
|
|
168
|
+
};
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return { status: BB_RESULT.FAILURE, reason: `${error}` };
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (!res) {
|
|
129
175
|
return {
|
|
130
176
|
status: BB_RESULT.ALREADY_PRESENT,
|
|
131
177
|
duration: 0,
|
|
132
178
|
pkPath: key === 'pk' ? outputPath : undefined,
|
|
133
179
|
vkPath: key === 'vk' ? outputPath : undefined,
|
|
134
|
-
proofPath: undefined,
|
|
135
180
|
};
|
|
136
181
|
}
|
|
137
182
|
|
|
138
|
-
|
|
183
|
+
return res;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Used for generating proofs of noir circuits.
|
|
188
|
+
* It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof.
|
|
189
|
+
* @param pathToBB - The full path to the bb binary
|
|
190
|
+
* @param workingDirectory - A working directory for use by bb
|
|
191
|
+
* @param circuitName - An identifier for the circuit
|
|
192
|
+
* @param bytecode - The compiled circuit bytecode
|
|
193
|
+
* @param inputWitnessFile - The circuit input witness
|
|
194
|
+
* @param log - A logging function
|
|
195
|
+
* @returns An object containing a result indication, the location of the proof and the duration taken
|
|
196
|
+
*/
|
|
197
|
+
export async function generateProof(
|
|
198
|
+
pathToBB: string,
|
|
199
|
+
workingDirectory: string,
|
|
200
|
+
circuitName: string,
|
|
201
|
+
bytecode: Buffer,
|
|
202
|
+
inputWitnessFile: string,
|
|
203
|
+
log: LogFn,
|
|
204
|
+
): Promise<BBFailure | BBSuccess> {
|
|
205
|
+
// Check that the working directory exists
|
|
206
|
+
try {
|
|
207
|
+
await fs.access(workingDirectory);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return { status: BB_RESULT.FAILURE, reason: `Working directory ${workingDirectory} does not exist` };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// The bytecode is written to e.g. /workingDirectory/BaseParityArtifact-bytecode
|
|
213
|
+
const bytecodePath = `${workingDirectory}/${circuitName}-bytecode`;
|
|
214
|
+
|
|
215
|
+
// The proof is written to e.g. /workingDirectory/proof
|
|
216
|
+
const outputPath = `${workingDirectory}`;
|
|
217
|
+
|
|
139
218
|
const binaryPresent = await fs
|
|
140
219
|
.access(pathToBB, fs.constants.R_OK)
|
|
141
220
|
.then(_ => true)
|
|
@@ -144,38 +223,30 @@ export async function generateKeyForNoirCircuit(
|
|
|
144
223
|
return { status: BB_RESULT.FAILURE, reason: `Failed to find bb binary at ${pathToBB}` };
|
|
145
224
|
}
|
|
146
225
|
|
|
147
|
-
// We are now going to generate the key
|
|
148
226
|
try {
|
|
149
227
|
// Write the bytecode to the working directory
|
|
150
228
|
await fs.writeFile(bytecodePath, bytecode);
|
|
151
|
-
|
|
152
|
-
// args are the output path and the input bytecode path
|
|
153
|
-
const args = ['-o', outputPath, '-b', bytecodePath];
|
|
229
|
+
const args = ['-o', outputPath, '-b', bytecodePath, '-w', inputWitnessFile, '-v'];
|
|
154
230
|
const timer = new Timer();
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
result = await executeBB(pathToBB, `vk_as_fields`, asFieldsArgs, log);
|
|
160
|
-
}
|
|
231
|
+
const logFunction = (message: string) => {
|
|
232
|
+
log(`${circuitName} BB out - ${message}`);
|
|
233
|
+
};
|
|
234
|
+
const result = await executeBB(pathToBB, 'prove_output_all', args, logFunction);
|
|
161
235
|
const duration = timer.ms();
|
|
162
|
-
|
|
163
|
-
await fs.rm(bytecodePath, { force: true });
|
|
236
|
+
|
|
164
237
|
if (result.status == BB_RESULT.SUCCESS) {
|
|
165
|
-
// Store the bytecode hash so we don't need to regenerate at a later time
|
|
166
|
-
await fs.writeFile(bytecodeHashPath, bytecodeHash);
|
|
167
238
|
return {
|
|
168
239
|
status: BB_RESULT.SUCCESS,
|
|
169
240
|
duration,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
241
|
+
proofPath: `${outputPath}`,
|
|
242
|
+
pkPath: undefined,
|
|
243
|
+
vkPath: `${outputPath}`,
|
|
173
244
|
};
|
|
174
245
|
}
|
|
175
246
|
// Not a great error message here but it is difficult to decipher what comes from bb
|
|
176
247
|
return {
|
|
177
248
|
status: BB_RESULT.FAILURE,
|
|
178
|
-
reason: `Failed to generate
|
|
249
|
+
reason: `Failed to generate proof. Exit code ${result.exitCode}. Signal ${result.signal}.`,
|
|
179
250
|
};
|
|
180
251
|
} catch (error) {
|
|
181
252
|
return { status: BB_RESULT.FAILURE, reason: `${error}` };
|
|
@@ -183,22 +254,18 @@ export async function generateKeyForNoirCircuit(
|
|
|
183
254
|
}
|
|
184
255
|
|
|
185
256
|
/**
|
|
186
|
-
* Used for generating proofs
|
|
257
|
+
* Used for generating AVM proofs.
|
|
187
258
|
* It is assumed that the working directory is a temporary and/or random directory used solely for generating this proof.
|
|
188
259
|
* @param pathToBB - The full path to the bb binary
|
|
189
260
|
* @param workingDirectory - A working directory for use by bb
|
|
190
|
-
* @param
|
|
191
|
-
* @param bytecode - The compiled circuit bytecode
|
|
192
|
-
* @param inputWitnessFile - The circuit input witness
|
|
261
|
+
* @param bytecode - The AVM bytecode for the public function to be proven (expected to be decompressed)
|
|
193
262
|
* @param log - A logging function
|
|
194
263
|
* @returns An object containing a result indication, the location of the proof and the duration taken
|
|
195
264
|
*/
|
|
196
|
-
export async function
|
|
265
|
+
export async function generateAvmProof(
|
|
197
266
|
pathToBB: string,
|
|
198
267
|
workingDirectory: string,
|
|
199
|
-
|
|
200
|
-
bytecode: Buffer,
|
|
201
|
-
inputWitnessFile: string,
|
|
268
|
+
input: AvmCircuitInputs,
|
|
202
269
|
log: LogFn,
|
|
203
270
|
): Promise<BBFailure | BBSuccess> {
|
|
204
271
|
// Check that the working directory exists
|
|
@@ -208,39 +275,81 @@ export async function generateProof(
|
|
|
208
275
|
return { status: BB_RESULT.FAILURE, reason: `Working directory ${workingDirectory} does not exist` };
|
|
209
276
|
}
|
|
210
277
|
|
|
211
|
-
//
|
|
212
|
-
const bytecodePath =
|
|
278
|
+
// Paths for the inputs
|
|
279
|
+
const bytecodePath = join(workingDirectory, 'avm_bytecode.bin');
|
|
280
|
+
const calldataPath = join(workingDirectory, 'avm_calldata.bin');
|
|
281
|
+
const publicInputsPath = join(workingDirectory, 'avm_public_inputs.bin');
|
|
282
|
+
const avmHintsPath = join(workingDirectory, 'avm_hints.bin');
|
|
213
283
|
|
|
214
284
|
// The proof is written to e.g. /workingDirectory/proof
|
|
215
|
-
const outputPath =
|
|
285
|
+
const outputPath = workingDirectory;
|
|
216
286
|
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
287
|
+
const filePresent = async (file: string) =>
|
|
288
|
+
await fs
|
|
289
|
+
.access(file, fs.constants.R_OK)
|
|
290
|
+
.then(_ => true)
|
|
291
|
+
.catch(_ => false);
|
|
292
|
+
|
|
293
|
+
const binaryPresent = await filePresent(pathToBB);
|
|
221
294
|
if (!binaryPresent) {
|
|
222
295
|
return { status: BB_RESULT.FAILURE, reason: `Failed to find bb binary at ${pathToBB}` };
|
|
223
296
|
}
|
|
224
297
|
|
|
225
298
|
try {
|
|
226
|
-
// Write the
|
|
227
|
-
await fs.writeFile(bytecodePath, bytecode);
|
|
228
|
-
|
|
299
|
+
// Write the inputs to the working directory.
|
|
300
|
+
await fs.writeFile(bytecodePath, input.bytecode);
|
|
301
|
+
if (!filePresent(bytecodePath)) {
|
|
302
|
+
return { status: BB_RESULT.FAILURE, reason: `Could not write bytecode at ${bytecodePath}` };
|
|
303
|
+
}
|
|
304
|
+
await fs.writeFile(
|
|
305
|
+
calldataPath,
|
|
306
|
+
input.calldata.map(fr => fr.toBuffer()),
|
|
307
|
+
);
|
|
308
|
+
if (!filePresent(calldataPath)) {
|
|
309
|
+
return { status: BB_RESULT.FAILURE, reason: `Could not write calldata at ${calldataPath}` };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// public inputs are used directly as a vector of fields in C++,
|
|
313
|
+
// so we serialize them as such here instead of just using toBuffer
|
|
314
|
+
await fs.writeFile(
|
|
315
|
+
publicInputsPath,
|
|
316
|
+
input.publicInputs.toFields().map(fr => fr.toBuffer()),
|
|
317
|
+
);
|
|
318
|
+
if (!filePresent(publicInputsPath)) {
|
|
319
|
+
return { status: BB_RESULT.FAILURE, reason: `Could not write publicInputs at ${publicInputsPath}` };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
await fs.writeFile(avmHintsPath, input.avmHints.toBuffer());
|
|
323
|
+
if (!filePresent(avmHintsPath)) {
|
|
324
|
+
return { status: BB_RESULT.FAILURE, reason: `Could not write avmHints at ${avmHintsPath}` };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const args = [
|
|
328
|
+
'--avm-bytecode',
|
|
329
|
+
bytecodePath,
|
|
330
|
+
'--avm-calldata',
|
|
331
|
+
calldataPath,
|
|
332
|
+
'--avm-public-inputs',
|
|
333
|
+
publicInputsPath,
|
|
334
|
+
'--avm-hints',
|
|
335
|
+
avmHintsPath,
|
|
336
|
+
'-o',
|
|
337
|
+
outputPath,
|
|
338
|
+
];
|
|
229
339
|
const timer = new Timer();
|
|
230
340
|
const logFunction = (message: string) => {
|
|
231
|
-
log(
|
|
341
|
+
log(`AvmCircuit (prove) BB out - ${message}`);
|
|
232
342
|
};
|
|
233
|
-
const result = await executeBB(pathToBB, '
|
|
343
|
+
const result = await executeBB(pathToBB, 'avm_prove', args, logFunction);
|
|
234
344
|
const duration = timer.ms();
|
|
235
|
-
|
|
236
|
-
await fs.rm(bytecodePath, { force: true });
|
|
345
|
+
|
|
237
346
|
if (result.status == BB_RESULT.SUCCESS) {
|
|
238
347
|
return {
|
|
239
348
|
status: BB_RESULT.SUCCESS,
|
|
240
349
|
duration,
|
|
241
|
-
proofPath:
|
|
350
|
+
proofPath: join(outputPath, PROOF_FILENAME),
|
|
242
351
|
pkPath: undefined,
|
|
243
|
-
vkPath:
|
|
352
|
+
vkPath: outputPath,
|
|
244
353
|
};
|
|
245
354
|
}
|
|
246
355
|
// Not a great error message here but it is difficult to decipher what comes from bb
|
|
@@ -266,6 +375,42 @@ export async function verifyProof(
|
|
|
266
375
|
proofFullPath: string,
|
|
267
376
|
verificationKeyPath: string,
|
|
268
377
|
log: LogFn,
|
|
378
|
+
): Promise<BBFailure | BBSuccess> {
|
|
379
|
+
return await verifyProofInternal(pathToBB, proofFullPath, verificationKeyPath, 'verify', log);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Used for verifying proofs of the AVM
|
|
384
|
+
* @param pathToBB - The full path to the bb binary
|
|
385
|
+
* @param proofFullPath - The full path to the proof to be verified
|
|
386
|
+
* @param verificationKeyPath - The full path to the circuit verification key
|
|
387
|
+
* @param log - A logging function
|
|
388
|
+
* @returns An object containing a result indication and duration taken
|
|
389
|
+
*/
|
|
390
|
+
export async function verifyAvmProof(
|
|
391
|
+
pathToBB: string,
|
|
392
|
+
proofFullPath: string,
|
|
393
|
+
verificationKeyPath: string,
|
|
394
|
+
log: LogFn,
|
|
395
|
+
): Promise<BBFailure | BBSuccess> {
|
|
396
|
+
return await verifyProofInternal(pathToBB, proofFullPath, verificationKeyPath, 'avm_verify', log);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Used for verifying proofs with BB
|
|
401
|
+
* @param pathToBB - The full path to the bb binary
|
|
402
|
+
* @param proofFullPath - The full path to the proof to be verified
|
|
403
|
+
* @param verificationKeyPath - The full path to the circuit verification key
|
|
404
|
+
* @param command - The BB command to execute (verify/avm_verify)
|
|
405
|
+
* @param log - A logging function
|
|
406
|
+
* @returns An object containing a result indication and duration taken
|
|
407
|
+
*/
|
|
408
|
+
async function verifyProofInternal(
|
|
409
|
+
pathToBB: string,
|
|
410
|
+
proofFullPath: string,
|
|
411
|
+
verificationKeyPath: string,
|
|
412
|
+
command: 'verify' | 'avm_verify',
|
|
413
|
+
log: LogFn,
|
|
269
414
|
): Promise<BBFailure | BBSuccess> {
|
|
270
415
|
const binaryPresent = await fs
|
|
271
416
|
.access(pathToBB, fs.constants.R_OK)
|
|
@@ -278,7 +423,7 @@ export async function verifyProof(
|
|
|
278
423
|
try {
|
|
279
424
|
const args = ['-p', proofFullPath, '-k', verificationKeyPath];
|
|
280
425
|
const timer = new Timer();
|
|
281
|
-
const result = await executeBB(pathToBB,
|
|
426
|
+
const result = await executeBB(pathToBB, command, args, log);
|
|
282
427
|
const duration = timer.ms();
|
|
283
428
|
if (result.status == BB_RESULT.SUCCESS) {
|
|
284
429
|
return { status: BB_RESULT.SUCCESS, duration };
|
|
@@ -338,6 +483,7 @@ export async function writeVkAsFields(
|
|
|
338
483
|
* @param pathToBB - The full path to the bb binary
|
|
339
484
|
* @param proofPath - The directory containing the binary proof
|
|
340
485
|
* @param proofFileName - The filename of the proof
|
|
486
|
+
* @param vkFileName - The filename of the verification key
|
|
341
487
|
* @param log - A logging function
|
|
342
488
|
* @returns An object containing a result indication and duration taken
|
|
343
489
|
*/
|
|
@@ -345,6 +491,7 @@ export async function writeProofAsFields(
|
|
|
345
491
|
pathToBB: string,
|
|
346
492
|
proofPath: string,
|
|
347
493
|
proofFileName: string,
|
|
494
|
+
vkFilePath: string,
|
|
348
495
|
log: LogFn,
|
|
349
496
|
): Promise<BBFailure | BBSuccess> {
|
|
350
497
|
const binaryPresent = await fs
|
|
@@ -356,7 +503,7 @@ export async function writeProofAsFields(
|
|
|
356
503
|
}
|
|
357
504
|
|
|
358
505
|
try {
|
|
359
|
-
const args = ['-p', `${proofPath}/${proofFileName}`, '-v'];
|
|
506
|
+
const args = ['-p', `${proofPath}/${proofFileName}`, '-k', vkFilePath, '-v'];
|
|
360
507
|
const timer = new Timer();
|
|
361
508
|
const result = await executeBB(pathToBB, 'proof_as_fields', args, log);
|
|
362
509
|
const duration = timer.ms();
|
|
@@ -372,3 +519,129 @@ export async function writeProofAsFields(
|
|
|
372
519
|
return { status: BB_RESULT.FAILURE, reason: `${error}` };
|
|
373
520
|
}
|
|
374
521
|
}
|
|
522
|
+
|
|
523
|
+
export async function generateContractForVerificationKey(
|
|
524
|
+
pathToBB: string,
|
|
525
|
+
vkFilePath: string,
|
|
526
|
+
contractPath: string,
|
|
527
|
+
log: LogFn,
|
|
528
|
+
): Promise<BBFailure | BBSuccess> {
|
|
529
|
+
const binaryPresent = await fs
|
|
530
|
+
.access(pathToBB, fs.constants.R_OK)
|
|
531
|
+
.then(_ => true)
|
|
532
|
+
.catch(_ => false);
|
|
533
|
+
|
|
534
|
+
if (!binaryPresent) {
|
|
535
|
+
return { status: BB_RESULT.FAILURE, reason: `Failed to find bb binary at ${pathToBB}` };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const outputDir = dirname(contractPath);
|
|
539
|
+
const contractName = basename(contractPath);
|
|
540
|
+
// cache contract generation based on vk file and contract name
|
|
541
|
+
const cacheKey = sha256(Buffer.concat([Buffer.from(contractName), await fs.readFile(vkFilePath)]));
|
|
542
|
+
|
|
543
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
544
|
+
|
|
545
|
+
const res = await fsCache<BBSuccess | BBFailure>(outputDir, cacheKey, log, false, async () => {
|
|
546
|
+
try {
|
|
547
|
+
const args = ['-k', vkFilePath, '-o', contractPath, '-v'];
|
|
548
|
+
const timer = new Timer();
|
|
549
|
+
const result = await executeBB(pathToBB, 'contract', args, log);
|
|
550
|
+
const duration = timer.ms();
|
|
551
|
+
if (result.status == BB_RESULT.SUCCESS) {
|
|
552
|
+
return { status: BB_RESULT.SUCCESS, duration, contractPath };
|
|
553
|
+
}
|
|
554
|
+
// Not a great error message here but it is difficult to decipher what comes from bb
|
|
555
|
+
return {
|
|
556
|
+
status: BB_RESULT.FAILURE,
|
|
557
|
+
reason: `Failed to write verifier contract. Exit code ${result.exitCode}. Signal ${result.signal}.`,
|
|
558
|
+
};
|
|
559
|
+
} catch (error) {
|
|
560
|
+
return { status: BB_RESULT.FAILURE, reason: `${error}` };
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
if (!res) {
|
|
565
|
+
return {
|
|
566
|
+
status: BB_RESULT.ALREADY_PRESENT,
|
|
567
|
+
duration: 0,
|
|
568
|
+
contractPath,
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return res;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export async function generateContractForCircuit(
|
|
576
|
+
pathToBB: string,
|
|
577
|
+
workingDirectory: string,
|
|
578
|
+
circuitName: string,
|
|
579
|
+
compiledCircuit: NoirCompiledCircuit,
|
|
580
|
+
contractName: string,
|
|
581
|
+
log: LogFn,
|
|
582
|
+
force = false,
|
|
583
|
+
) {
|
|
584
|
+
const vkResult = await generateKeyForNoirCircuit(
|
|
585
|
+
pathToBB,
|
|
586
|
+
workingDirectory,
|
|
587
|
+
circuitName,
|
|
588
|
+
compiledCircuit,
|
|
589
|
+
'vk',
|
|
590
|
+
log,
|
|
591
|
+
force,
|
|
592
|
+
);
|
|
593
|
+
if (vkResult.status === BB_RESULT.FAILURE) {
|
|
594
|
+
return vkResult;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return generateContractForVerificationKey(
|
|
598
|
+
pathToBB,
|
|
599
|
+
join(vkResult.vkPath!, VK_FILENAME),
|
|
600
|
+
join(workingDirectory, 'contract', circuitName, contractName),
|
|
601
|
+
log,
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const CACHE_FILENAME = '.cache';
|
|
606
|
+
async function fsCache<T>(
|
|
607
|
+
dir: string,
|
|
608
|
+
expectedCacheKey: Buffer,
|
|
609
|
+
logger: LogFn,
|
|
610
|
+
force: boolean,
|
|
611
|
+
action: () => Promise<T>,
|
|
612
|
+
): Promise<T | undefined> {
|
|
613
|
+
const cacheFilePath = join(dir, CACHE_FILENAME);
|
|
614
|
+
|
|
615
|
+
let run: boolean;
|
|
616
|
+
if (force) {
|
|
617
|
+
run = true;
|
|
618
|
+
} else {
|
|
619
|
+
try {
|
|
620
|
+
run = !expectedCacheKey.equals(await fs.readFile(cacheFilePath));
|
|
621
|
+
} catch (err: any) {
|
|
622
|
+
if (err && 'code' in err && err.code === 'ENOENT') {
|
|
623
|
+
// cache file doesn't exist, swallow error and run
|
|
624
|
+
run = true;
|
|
625
|
+
} else {
|
|
626
|
+
throw err;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
let res: T | undefined;
|
|
632
|
+
if (run) {
|
|
633
|
+
logger(`Cache miss or forced run. Running operation in ${dir}...`);
|
|
634
|
+
res = await action();
|
|
635
|
+
} else {
|
|
636
|
+
logger(`Cache hit. Skipping operation in ${dir}...`);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
try {
|
|
640
|
+
await fs.writeFile(cacheFilePath, expectedCacheKey);
|
|
641
|
+
} catch (err) {
|
|
642
|
+
logger(`Couldn't write cache data to ${cacheFilePath}. Skipping cache...`);
|
|
643
|
+
// ignore
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return res;
|
|
647
|
+
}
|
package/src/config.ts
ADDED
package/src/index.ts
CHANGED
package/src/mappings/mappings.ts
CHANGED
|
@@ -2,12 +2,18 @@ import { PublicKernelType } from '@aztec/circuit-types';
|
|
|
2
2
|
import { type PublicKernelCircuitPrivateInputs, type PublicKernelCircuitPublicInputs } from '@aztec/circuits.js';
|
|
3
3
|
import {
|
|
4
4
|
type ServerProtocolArtifact,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
convertPublicInnerInputsToWitnessMap,
|
|
6
|
+
convertPublicInnerOutputFromWitnessMap,
|
|
7
|
+
convertPublicSetupInputsToWitnessMap,
|
|
8
|
+
convertPublicSetupOutputFromWitnessMap,
|
|
9
|
+
convertPublicTeardownInputsToWitnessMap,
|
|
10
|
+
convertPublicTeardownOutputFromWitnessMap,
|
|
11
|
+
convertSimulatedPublicInnerInputsToWitnessMap,
|
|
12
|
+
convertSimulatedPublicInnerOutputFromWitnessMap,
|
|
13
|
+
convertSimulatedPublicSetupInputsToWitnessMap,
|
|
14
|
+
convertSimulatedPublicSetupOutputFromWitnessMap,
|
|
15
|
+
convertSimulatedPublicTeardownInputsToWitnessMap,
|
|
16
|
+
convertSimulatedPublicTeardownOutputFromWitnessMap,
|
|
11
17
|
} from '@aztec/noir-protocol-circuits-types';
|
|
12
18
|
|
|
13
19
|
import { type WitnessMap } from '@noir-lang/types';
|
|
@@ -20,22 +26,42 @@ export type PublicKernelProvingOps = {
|
|
|
20
26
|
|
|
21
27
|
export type KernelTypeToArtifact = Record<PublicKernelType, PublicKernelProvingOps | undefined>;
|
|
22
28
|
|
|
29
|
+
export const SimulatedPublicKernelArtifactMapping: KernelTypeToArtifact = {
|
|
30
|
+
[PublicKernelType.NON_PUBLIC]: undefined,
|
|
31
|
+
[PublicKernelType.APP_LOGIC]: {
|
|
32
|
+
artifact: 'PublicKernelAppLogicArtifact',
|
|
33
|
+
convertInputs: convertSimulatedPublicInnerInputsToWitnessMap,
|
|
34
|
+
convertOutputs: convertSimulatedPublicInnerOutputFromWitnessMap,
|
|
35
|
+
},
|
|
36
|
+
[PublicKernelType.SETUP]: {
|
|
37
|
+
artifact: 'PublicKernelSetupArtifact',
|
|
38
|
+
convertInputs: convertSimulatedPublicSetupInputsToWitnessMap,
|
|
39
|
+
convertOutputs: convertSimulatedPublicSetupOutputFromWitnessMap,
|
|
40
|
+
},
|
|
41
|
+
[PublicKernelType.TEARDOWN]: {
|
|
42
|
+
artifact: 'PublicKernelTeardownArtifact',
|
|
43
|
+
convertInputs: convertSimulatedPublicTeardownInputsToWitnessMap,
|
|
44
|
+
convertOutputs: convertSimulatedPublicTeardownOutputFromWitnessMap,
|
|
45
|
+
},
|
|
46
|
+
[PublicKernelType.TAIL]: undefined,
|
|
47
|
+
};
|
|
48
|
+
|
|
23
49
|
export const PublicKernelArtifactMapping: KernelTypeToArtifact = {
|
|
24
50
|
[PublicKernelType.NON_PUBLIC]: undefined,
|
|
25
51
|
[PublicKernelType.APP_LOGIC]: {
|
|
26
52
|
artifact: 'PublicKernelAppLogicArtifact',
|
|
27
|
-
convertInputs:
|
|
28
|
-
convertOutputs:
|
|
53
|
+
convertInputs: convertPublicInnerInputsToWitnessMap,
|
|
54
|
+
convertOutputs: convertPublicInnerOutputFromWitnessMap,
|
|
29
55
|
},
|
|
30
56
|
[PublicKernelType.SETUP]: {
|
|
31
57
|
artifact: 'PublicKernelSetupArtifact',
|
|
32
|
-
convertInputs:
|
|
33
|
-
convertOutputs:
|
|
58
|
+
convertInputs: convertPublicSetupInputsToWitnessMap,
|
|
59
|
+
convertOutputs: convertPublicSetupOutputFromWitnessMap,
|
|
34
60
|
},
|
|
35
61
|
[PublicKernelType.TEARDOWN]: {
|
|
36
62
|
artifact: 'PublicKernelTeardownArtifact',
|
|
37
|
-
convertInputs:
|
|
38
|
-
convertOutputs:
|
|
63
|
+
convertInputs: convertPublicTeardownInputsToWitnessMap,
|
|
64
|
+
convertOutputs: convertPublicTeardownOutputFromWitnessMap,
|
|
39
65
|
},
|
|
40
66
|
[PublicKernelType.TAIL]: undefined,
|
|
41
67
|
};
|