Skip to content

Commit 1ad9249

Browse files
Thunkarmaramihaliledwards2225ludamad
authored
test: wasm proof verifying with native bb (#13499)
Main feature - New test for testing wasm proof output verifying with native CLI, adapting the wasm ivc test in yarn-project Also - dont hide test info by default - allow passing BB_WORKING_DIRECTORY env var and keeping outputs around like in e2e - use new-style logger in wasm test, dedupe some setup code --------- Co-authored-by: maramihali <[email protected]> Co-authored-by: ledwards2225 <[email protected]> Co-authored-by: ludamad <[email protected]> Co-authored-by: ludamad <[email protected]>
1 parent 0ebb29e commit 1ad9249

File tree

7 files changed

+77
-52
lines changed

7 files changed

+77
-52
lines changed

yarn-project/ivc-integration/src/avm_integration.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
88
import type { ProofAndVerificationKey } from '@aztec/stdlib/interfaces/server';
99

1010
import { jest } from '@jest/globals';
11-
import { promises as fs } from 'fs';
12-
import os from 'os';
1311
import path from 'path';
1412
import { fileURLToPath } from 'url';
1513

14+
import { getWorkingDirectory } from './bb_working_directory.js';
1615
import {
1716
MockRollupBasePublicCircuit,
1817
generate3FunctionTestingIVCStack,
@@ -45,7 +44,7 @@ describe('AVM Integration', () => {
4544
let simTester: PublicTxSimulationTester;
4645

4746
beforeAll(async () => {
48-
const clientIVCProofPath = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-avm-integration-client-ivc-'));
47+
const clientIVCProofPath = await getWorkingDirectory('bb-avm-integration-client-ivc-');
4948
bbBinaryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../barretenberg/cpp/build/bin', 'bb');
5049
const [bytecodes, witnessStack, tailPublicInputs] = await generate3FunctionTestingIVCStack();
5150
clientIVCPublicInputs = tailPublicInputs;
@@ -63,7 +62,7 @@ describe('AVM Integration', () => {
6362

6463
beforeEach(async () => {
6564
//Create a temp working dir
66-
bbWorkingDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-avm-integration-'));
65+
bbWorkingDirectory = await getWorkingDirectory('bb-avm-integration-');
6766

6867
simTester = await PublicTxSimulationTester.create();
6968
avmTestContractInstance = await simTester.registerAndDeployContract(
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import fs from 'fs/promises';
2+
import os from 'os';
3+
import path from 'path';
4+
5+
export async function getWorkingDirectory(prefix: string): Promise<string> {
6+
const baseFolder = process.env.BB_WORKING_DIRECTORY || os.tmpdir();
7+
await fs.mkdir(baseFolder, { recursive: true });
8+
return await fs.mkdtemp(path.join(baseFolder, prefix));
9+
}

yarn-project/ivc-integration/src/native_client_ivc_integration.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import { BB_RESULT, verifyClientIvcProof, writeClientIVCProofToOutputDirectory }
22
import { createLogger } from '@aztec/foundation/log';
33

44
import { jest } from '@jest/globals';
5-
import { promises as fs } from 'fs';
6-
import os from 'os';
75
import path from 'path';
86
import { fileURLToPath } from 'url';
97

8+
import { getWorkingDirectory } from './bb_working_directory.js';
109
import { generate3FunctionTestingIVCStack, generate6FunctionTestingIVCStack } from './index.js';
1110
import { proveClientIVC } from './prove_native.js';
1211

@@ -22,7 +21,7 @@ describe('Client IVC Integration', () => {
2221

2322
beforeEach(async () => {
2423
// Create a temp working dir
25-
bbWorkingDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-client-ivc-integration-'));
24+
bbWorkingDirectory = await getWorkingDirectory('bb-client-ivc-integration-');
2625
bbBinaryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../barretenberg/cpp/build/bin', 'bb');
2726
});
2827

yarn-project/ivc-integration/src/prove_wasm.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1+
import { ClientIvcProof } from '@aztec/stdlib/proofs';
2+
3+
import os from 'os';
14
import { ungzip } from 'pako';
25

36
function base64ToUint8Array(base64: string): Uint8Array {
47
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
58
}
69

10+
export async function proveClientIVC(
11+
bytecodes: string[],
12+
witnessStack: Uint8Array[],
13+
threads?: number,
14+
): Promise<ClientIvcProof> {
15+
const { AztecClientBackend } = await import('@aztec/bb.js');
16+
const backend = new AztecClientBackend(
17+
bytecodes.map(base64ToUint8Array).map((arr: Uint8Array) => ungzip(arr)),
18+
{ threads: threads || Math.min(os.cpus().length, 16) },
19+
);
20+
try {
21+
const [proof] = await backend.prove(witnessStack.map((arr: Uint8Array) => ungzip(arr)));
22+
return new ClientIvcProof(Buffer.from(proof));
23+
} finally {
24+
await backend.destroy();
25+
}
26+
}
27+
728
export async function proveThenVerifyAztecClient(
829
bytecodes: string[],
930
witnessStack: Uint8Array[],
@@ -12,7 +33,7 @@ export async function proveThenVerifyAztecClient(
1233
const { AztecClientBackend } = await import('@aztec/bb.js');
1334
const backend = new AztecClientBackend(
1435
bytecodes.map(base64ToUint8Array).map((arr: Uint8Array) => ungzip(arr)),
15-
{ threads },
36+
{ threads: threads || Math.min(os.cpus().length, 16) },
1637
);
1738
try {
1839
const [proof, vk] = await backend.prove(witnessStack.map((arr: Uint8Array) => ungzip(arr)));

yarn-project/ivc-integration/src/rollup_ivc_integration.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
99
import type { ProofAndVerificationKey } from '@aztec/stdlib/interfaces/server';
1010

1111
import { jest } from '@jest/globals';
12-
import { promises as fs } from 'fs';
13-
import os from 'os';
1412
import path from 'path';
1513
import { fileURLToPath } from 'url';
1614

15+
import { getWorkingDirectory } from './bb_working_directory.js';
1716
import {
1817
MockRollupBasePrivateCircuit,
1918
MockRollupBasePublicCircuit,
@@ -54,7 +53,7 @@ describe('Rollup IVC Integration', () => {
5453
bbBinaryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '../../../barretenberg/cpp/build/bin', 'bb');
5554

5655
// Create a client IVC proof
57-
const clientIVCWorkingDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-rollup-ivc-integration-client-ivc-'));
56+
const clientIVCWorkingDirectory = await getWorkingDirectory('bb-rollup-ivc-integration-client-ivc-');
5857

5958
const [bytecodes, witnessStack, tailPublicInputs] = await generate3FunctionTestingIVCStack();
6059
clientIVCPublicInputs = tailPublicInputs;
@@ -71,7 +70,7 @@ describe('Rollup IVC Integration', () => {
7170
tubeProof = await proveTube(bbBinaryPath, clientIVCWorkingDirectory, logger);
7271

7372
// Create an AVM proof
74-
const avmWorkingDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-rollup-ivc-integration-avm-'));
73+
const avmWorkingDirectory = await getWorkingDirectory('bb-rollup-ivc-integration-avm-');
7574

7675
const simTester = await PublicTxSimulationTester.create();
7776
const avmTestContractInstance = await simTester.registerAndDeployContract(
@@ -90,7 +89,7 @@ describe('Rollup IVC Integration', () => {
9089
});
9190

9291
beforeEach(async () => {
93-
workingDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'bb-rollup-ivc-integration-'));
92+
workingDirectory = await getWorkingDirectory('bb-rollup-ivc-integration-');
9493
});
9594

9695
it('Should be able to generate a proof of a 3 transaction rollup', async () => {

yarn-project/ivc-integration/src/wasm_client_ivc_integration.test.ts

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import { BB_RESULT, verifyClientIvcProof, writeClientIVCProofToOutputDirectory } from '@aztec/bb-prover';
12
import { AztecClientBackend } from '@aztec/bb.js';
3+
import { createLogger } from '@aztec/foundation/log';
24

35
import { jest } from '@jest/globals';
46

57
/* eslint-disable camelcase */
68
import createDebug from 'debug';
79
import { ungzip } from 'pako';
10+
import path from 'path';
11+
import { fileURLToPath } from 'url';
812

13+
import { getWorkingDirectory } from './bb_working_directory.js';
914
import {
1015
MOCK_MAX_COMMITMENTS_PER_TX,
1116
MockAppCreatorCircuit,
@@ -19,6 +24,7 @@ import {
1924
MockPrivateKernelResetCircuit,
2025
MockPrivateKernelResetVk,
2126
MockPrivateKernelTailCircuit,
27+
generate3FunctionTestingIVCStack,
2228
getVkAsFields,
2329
witnessGenCreatorAppMockCircuit,
2430
witnessGenMockPrivateKernelInitCircuit,
@@ -27,9 +33,11 @@ import {
2733
witnessGenMockPrivateKernelTailCircuit,
2834
witnessGenReaderAppMockCircuit,
2935
} from './index.js';
30-
import { proveThenVerifyAztecClient } from './prove_wasm.js';
36+
import { proveClientIVC as proveClientIVCNative } from './prove_native.js';
37+
import { proveClientIVC as proveClientIVCWasm, proveThenVerifyAztecClient } from './prove_wasm.js';
38+
39+
const logger = createLogger('ivc-integration:test:wasm');
3140

32-
const logger = createDebug('ivc-integration:test:wasm');
3341
createDebug.enable('*');
3442

3543
jest.setTimeout(120_000);
@@ -41,42 +49,31 @@ describe('Client IVC Integration', () => {
4149
// 1. Run a mock app that creates two commitments
4250
// 2. Run the init kernel to process the app run
4351
// 3. Run the tail kernel to finish the client IVC chain.
44-
it('Should generate a verifiable client IVC proof from a simple mock tx via bb.js', async () => {
45-
const tx = {
46-
number_of_calls: '0x1',
47-
};
48-
// Witness gen app and kernels
49-
const appWitnessGenResult = await witnessGenCreatorAppMockCircuit({ commitments_to_create: ['0x1', '0x2'] });
50-
logger('generated app mock circuit witness');
51-
52-
const initWitnessGenResult = await witnessGenMockPrivateKernelInitCircuit({
53-
app_inputs: appWitnessGenResult.publicInputs,
54-
tx,
55-
app_vk: getVkAsFields(MockAppCreatorVk),
56-
});
57-
logger('generated mock private kernel init witness');
58-
59-
const tailWitnessGenResult = await witnessGenMockPrivateKernelTailCircuit({
60-
prev_kernel_public_inputs: initWitnessGenResult.publicInputs,
61-
kernel_vk: getVkAsFields(MockPrivateKernelInitVk),
62-
});
63-
logger('generated mock private kernel tail witness');
64-
65-
// Create client IVC proof
66-
const bytecodes = [
67-
MockAppCreatorCircuit.bytecode,
68-
MockPrivateKernelInitCircuit.bytecode,
69-
MockPrivateKernelTailCircuit.bytecode,
52+
it('Should generate a verifiable client IVC proof from a simple mock tx via bb.js, verified by bb', async () => {
53+
const [bytecodes, witnessStack] = await generate3FunctionTestingIVCStack();
54+
55+
// We use the bb binary for verification / writing out the VK
56+
const bbBinaryPath = path.join(
57+
path.dirname(fileURLToPath(import.meta.url)),
58+
'../../../barretenberg/cpp/build/bin',
59+
'bb',
60+
);
61+
const clientIVCWorkingDirectory = await getWorkingDirectory('bb-client-ivc-integration-');
62+
const tasks = [
63+
proveClientIVCNative(bbBinaryPath, clientIVCWorkingDirectory, witnessStack, bytecodes, logger),
64+
proveClientIVCWasm(bytecodes, witnessStack),
7065
];
71-
72-
logger('built bytecode array');
73-
const witnessStack = [appWitnessGenResult.witness, initWitnessGenResult.witness, tailWitnessGenResult.witness];
74-
logger('built witness stack');
75-
76-
const verifyResult = await proveThenVerifyAztecClient(bytecodes, witnessStack);
77-
logger(`generated then verified proof. result: ${verifyResult}`);
78-
79-
expect(verifyResult).toEqual(true);
66+
const [_, wasmProof] = await Promise.all(tasks);
67+
68+
// Write the WASM proof over the output directory (the bb cli will have output to this folder, we need the vk to be in place).
69+
await writeClientIVCProofToOutputDirectory(wasmProof, clientIVCWorkingDirectory);
70+
const verifyWasmResultInNative = await verifyClientIvcProof(
71+
bbBinaryPath,
72+
clientIVCWorkingDirectory.concat('/proof'),
73+
clientIVCWorkingDirectory.concat('/vk'),
74+
logger.info,
75+
);
76+
expect(verifyWasmResultInNative.status).toEqual(BB_RESULT.SUCCESS);
8077
});
8178

8279
it('Should generate an array of gate numbers for the stack of programs being proved by ClientIVC', async () => {
@@ -93,7 +90,7 @@ describe('Client IVC Integration', () => {
9390
// Compute the numbers of gates in each circuit
9491
const gateNumbers = await backend.gates();
9592
await backend.destroy();
96-
logger('Gate numbers for each circuit:', gateNumbers);
93+
logger.info('Gate numbers for each circuit:', gateNumbers);
9794
// STARTER: add a test here instantiate an AztecClientBackend with the above bytecodes, call gates, and check they're correct (maybe just
9895
// eyeball against logs to start... better is to make another test that actually pins the sizes since the mock protocol circuits are
9996
// intended not to change, though for sure there will be some friction, and such test should actually just be located in barretenberg/ts)
@@ -160,7 +157,7 @@ describe('Client IVC Integration', () => {
160157
];
161158

162159
const verifyResult = await proveThenVerifyAztecClient(bytecodes, witnessStack);
163-
logger(`generated then verified proof. result: ${verifyResult}`);
160+
logger.info(`generated then verified proof. result: ${verifyResult}`);
164161

165162
expect(verifyResult).toEqual(true);
166163
});

yarn-project/scripts/run_test.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ if [ "${ISOLATE:-0}" -eq 1 ]; then
3434
wait $!
3535
else
3636
export NODE_OPTIONS="--no-warnings --experimental-vm-modules --loader @swc-node/register"
37+
export LOG_LEVEL=${LOG_LEVEL:-info}
3738
cd ../$dir
3839
node ../node_modules/.bin/jest --forceExit --runInBand $test
3940
fi

0 commit comments

Comments
 (0)