Skip to content

Commit 3756ff5

Browse files
Merge pull request #2458 from o1-labs/shigoto/performance-regression-migrate-tests
Update ZkProgram tests to utilize the new performance (compilation, proving, verification) regression framework
2 parents 2c99041 + 7ccf316 commit 3756ff5

File tree

9 files changed

+163
-50
lines changed

9 files changed

+163
-50
lines changed

src/examples/zkprogram/gadgets.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Field, Provable, Gadgets, ZkProgram } from 'o1js';
1+
import { Field, Gadgets, Provable, ZkProgram } from 'o1js';
2+
import { Performance } from '../../lib/testing/perf-regression.js';
23

34
let cs = await Provable.constraintSystem(() => {
45
let f = Provable.witness(Field, () => 12);
@@ -54,25 +55,40 @@ const BitwiseProver = ZkProgram({
5455
},
5556
});
5657

57-
console.log('compiling..');
58+
const csBitwise = await BitwiseProver.analyzeMethods();
59+
const perfBitwise = Performance.create(BitwiseProver.name, csBitwise);
5860

59-
console.time('compile');
61+
console.log('\ncompiling..');
62+
63+
perfBitwise.start('compile');
6064
await BitwiseProver.compile();
61-
console.timeEnd('compile');
65+
perfBitwise.end();
6266

63-
console.log('proving..');
67+
console.log('\nproving..');
6468

65-
console.time('rotation prove');
69+
perfBitwise.start('prove', 'rot');
6670
let { proof: rotProof } = await BitwiseProver.rot();
67-
console.timeEnd('rotation prove');
68-
if (!(await BitwiseProver.verify(rotProof))) throw Error('rot: Invalid proof');
71+
perfBitwise.end();
72+
73+
perfBitwise.start('verify', 'rot');
74+
const isValidRot = await BitwiseProver.verify(rotProof);
75+
perfBitwise.end();
76+
if (!isValidRot) throw Error('rot: Invalid proof');
6977

70-
console.time('xor prove');
78+
perfBitwise.start('prove', 'xor');
7179
let { proof: xorProof } = await BitwiseProver.xor();
72-
console.timeEnd('xor prove');
73-
if (!(await BitwiseProver.verify(xorProof))) throw Error('xor: Invalid proof');
80+
perfBitwise.end();
7481

75-
console.time('and prove');
82+
perfBitwise.start('verify', 'xor');
83+
const isValidXor = await BitwiseProver.verify(xorProof);
84+
perfBitwise.end();
85+
if (!isValidXor) throw Error('xor: Invalid proof');
86+
87+
perfBitwise.start('prove', 'and');
7688
let { proof: andProof } = await BitwiseProver.and();
77-
console.timeEnd('and prove');
78-
if (!(await BitwiseProver.verify(andProof))) throw Error('and: Invalid proof');
89+
perfBitwise.end();
90+
91+
perfBitwise.start('verify', 'and');
92+
const isValidAnd = await BitwiseProver.verify(andProof);
93+
perfBitwise.end();
94+
if (!isValidAnd) throw Error('and: Invalid proof');

src/examples/zkprogram/hash-chain.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* We implement this as a self-recursive ZkProgram, using `proveRecursivelyIf()`
66
*/
77
import { assert, Bool, Experimental, Field, Poseidon, Provable, Struct, ZkProgram } from 'o1js';
8+
import { Performance } from '../../lib/testing/perf-regression.js';
89

910
const HASHES_PER_PROOF = 30;
1011

@@ -47,14 +48,24 @@ const hashChain = ZkProgram({
4748
});
4849
let hashChainRecursive = Experimental.Recursive(hashChain);
4950

51+
const cs = await hashChain.analyzeMethods();
52+
const perfHashChain = Performance.create(hashChain.name, cs);
53+
54+
perfHashChain.start('compile');
5055
await hashChain.compile();
56+
perfHashChain.end();
5157

5258
let n = 100;
5359
let x = Field.random();
5460

61+
perfHashChain.start('prove', 'chain');
5562
let { proof } = await hashChain.chain({ x, n });
63+
perfHashChain.end();
5664

57-
assert(await hashChain.verify(proof), 'Proof invalid');
65+
perfHashChain.start('verify', 'chain');
66+
const isValid = await hashChain.verify(proof);
67+
perfHashChain.end();
68+
assert(isValid, 'Proof invalid');
5869

5970
// check that the output is correct
6071
let z = Array.from({ length: n }, () => 0).reduce((y) => Poseidon.hash([y]), x);

src/examples/zkprogram/mutual-recursion.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { ZkProgram, Field, DynamicProof, Proof, VerificationKey, Undefined, verify } from 'o1js';
1+
import { DynamicProof, Field, Proof, Undefined, VerificationKey, ZkProgram, verify } from 'o1js';
2+
import { Performance } from '../../lib/testing/perf-regression.js';
23

34
/**
45
* This example showcases mutual recursion (A -> B -> A) through two circuits that respectively
@@ -51,21 +52,38 @@ const multiply = ZkProgram({
5152
},
5253
});
5354

54-
console.log('Compiling circuits...');
55+
const csAdd = await add.analyzeMethods();
56+
const csMultiply = await multiply.analyzeMethods();
57+
58+
const perfAdd = Performance.create(add.name, csAdd);
59+
const perfMultiply = Performance.create(multiply.name, csMultiply);
60+
61+
perfAdd.start('compile');
5562
const addVk = (await add.compile()).verificationKey;
63+
perfAdd.end();
64+
65+
perfMultiply.start('compile');
5666
const multiplyVk = (await multiply.compile()).verificationKey;
67+
perfMultiply.end();
5768

58-
console.log('Proving basecase');
5969
const dummyProof = await DynamicMultiplyProof.dummy(undefined, Field(0), 1);
70+
71+
perfAdd.start('prove', 'performAddition');
6072
const { proof: baseCase } = await add.performAddition(Field(5), dummyProof, multiplyVk);
73+
perfAdd.end();
6174

75+
perfAdd.start('verify', 'performAddition');
6276
const validBaseCase = await verify(baseCase, addVk);
77+
perfAdd.end();
6378
console.log('ok?', validBaseCase);
6479

65-
console.log('Proving first multiplication');
80+
perfMultiply.start('prove', 'performMultiplication');
6681
const { proof: multiply1 } = await multiply.performMultiplication(Field(3), baseCase);
82+
perfMultiply.end();
6783

84+
perfMultiply.start('verify', 'performMultiplication');
6885
const validMultiplication = await verify(multiply1, multiplyVk);
86+
perfMultiply.end();
6987
console.log('ok?', validMultiplication);
7088

7189
console.log('Proving second (recursive) addition');

src/examples/zkprogram/program-small-big.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Bytes, Field, Hash, Poseidon, UInt8, ZkProgram, verify } from 'o1js';
2+
import { Performance } from '../../lib/testing/perf-regression.js';
23

34
const SmallProgram = ZkProgram({
45
name: 'small-program',
@@ -52,24 +53,27 @@ console.log('small program rows: ', csSmall.poseidonHash.rows);
5253
const csBig = await BigProgram.analyzeMethods();
5354
console.log('big program rows: ', csBig.combinedHash.rows, '\n');
5455

55-
console.time('compile small');
56+
const perfSmall = Performance.create(SmallProgram.name, csSmall);
57+
const perfBig = Performance.create(BigProgram.name, csBig);
58+
59+
perfSmall.start('compile');
5660
await SmallProgram.compile();
57-
console.timeEnd('compile small');
61+
perfSmall.end();
5862

59-
console.time('compile big');
63+
perfBig.start('compile');
6064
const { verificationKey: verificationKeyBig } = await BigProgram.compile();
61-
console.timeEnd('compile big');
65+
perfBig.end();
6266

63-
console.time('prove small');
67+
perfSmall.start('prove', 'poseidonHash');
6468
const proofSmall = await SmallProgram.poseidonHash(Field.random());
65-
console.timeEnd('prove small');
69+
perfSmall.end();
6670

67-
console.time('prove big');
71+
perfBig.start('prove', 'combinedHash');
6872
const { proof: proofBig } = await BigProgram.combinedHash(proofSmall.proof);
69-
console.timeEnd('prove big');
73+
perfBig.end();
7074

71-
console.time('verify big');
75+
perfBig.start('verify', 'combinedHash');
7276
await verify(proofBig, verificationKeyBig);
73-
console.timeEnd('verify big');
77+
perfBig.end();
7478

7579
console.log('Final Digest: ', proofBig.publicOutput.toHex());

src/examples/zkprogram/program-with-chunking.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Field, Cache, Gadgets, ZkProgram } from 'o1js';
1+
import { Cache, Field, Gadgets, ZkProgram } from 'o1js';
2+
import { Performance } from '../../lib/testing/perf-regression.js';
23

34
let MyProgram = ZkProgram({
45
chunks: 1,
@@ -22,14 +23,21 @@ let MyProgram = ZkProgram({
2223
},
2324
});
2425

25-
console.log(await MyProgram.analyzeMethods());
26+
const cs = await MyProgram.analyzeMethods();
27+
const perf = Performance.create(MyProgram.name, cs);
2628

27-
console.log('compiling MyProgram...');
29+
console.log('MyProgram baseCase method rows: ', cs.baseCase.rows);
30+
31+
perf.start('compile');
2832
await MyProgram.compile({ cache: Cache.None });
33+
perf.end();
2934

30-
console.log('proving base case...');
35+
perf.start('prove', 'baseCase');
3136
let { proof } = await MyProgram.baseCase(Field(0));
37+
perf.end();
3238

33-
console.log('verify...');
39+
perf.start('verify', 'baseCase');
3440
let ok = await MyProgram.verify(proof);
41+
perf.end();
42+
3543
console.log('ok?', ok);

src/examples/zkprogram/runtime-table/run.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { Field, verify } from 'o1js';
2+
import { Performance } from '../../../lib/testing/perf-regression.js';
23
import { PayrollRuntimeTableZkProgram } from './payroll.js';
34

5+
const cs = await PayrollRuntimeTableZkProgram.analyzeMethods();
6+
const perfPayroll = Performance.create(PayrollRuntimeTableZkProgram.name, cs);
7+
8+
perfPayroll.start('compile');
49
let { verificationKey } = await PayrollRuntimeTableZkProgram.compile({ withRuntimeTables: true });
10+
perfPayroll.end();
511

612
export const examplePayrollPublicInput = Field(1600_00); // total withheld (cents)
713
export const examplePayrollPrivateInputs = [
@@ -13,9 +19,13 @@ export const examplePayrollPrivateInputs = [
1319
Field(3_000), // Charlie rate
1420
] as const;
1521

22+
perfPayroll.start('prove', 'verifyPayroll');
1623
let { proof } = await PayrollRuntimeTableZkProgram.verifyPayroll(
1724
examplePayrollPublicInput,
1825
...examplePayrollPrivateInputs
1926
);
27+
perfPayroll.end();
2028

21-
verify(proof, verificationKey);
29+
perfPayroll.start('verify', 'verifyPayroll');
30+
await verify(proof, verificationKey);
31+
perfPayroll.end();

src/examples/zkprogram/side-loading/run.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
11
import { Field, MerkleTree, verify } from 'o1js';
2+
import { Performance } from '../../../lib/testing/perf-regression.js';
23
import {
3-
sideloadedProgram,
4-
mainProgram,
5-
SideloadedProgramProof,
6-
MerkleTreeWitness,
74
MainProgramState,
5+
MerkleTreeWitness,
6+
SideloadedProgramProof,
7+
mainProgram,
8+
sideloadedProgram,
89
} from './dynamic-keys-merkletree.js';
910

10-
console.log('Compiling circuits...');
11+
const csSide = await sideloadedProgram.analyzeMethods();
12+
const csMain = await mainProgram.analyzeMethods();
13+
14+
const perfSide = Performance.create(sideloadedProgram.name, csSide);
15+
const perfMain = Performance.create(mainProgram.name, csMain);
16+
17+
perfSide.start('compile');
1118
const sideVk = (await sideloadedProgram.compile()).verificationKey;
19+
perfSide.end();
20+
21+
perfMain.start('compile');
1222
const mainVk = (await mainProgram.compile()).verificationKey;
23+
perfMain.end();
1324

1425
const tree = new MerkleTree(64);
1526

16-
console.log('Proving deployment of side-loaded key');
27+
console.log('\nProving deployment of side-loaded key');
1728
const rootBefore = tree.getRoot();
1829
tree.setLeaf(1n, sideVk.hash);
1930
const witness = new MerkleTreeWitness(tree.getWitness(1n));
2031

32+
perfMain.start('prove', 'addSideloadedProgram');
2133
const { proof: proof1 } = await mainProgram.addSideloadedProgram(
2234
new MainProgramState({
2335
treeRoot: rootBefore,
@@ -26,26 +38,35 @@ const { proof: proof1 } = await mainProgram.addSideloadedProgram(
2638
sideVk,
2739
witness
2840
);
41+
perfMain.end();
2942

30-
console.log('Proving child program execution');
43+
console.log('\nProving child program execution');
44+
perfSide.start('prove', 'compute');
3145
const { proof: childProof1 } = await sideloadedProgram.compute(Field(0), Field(10));
46+
perfSide.end();
3247

33-
console.log('Proving verification inside main program');
48+
console.log('\nProving verification inside main program');
49+
perfMain.start('prove', 'validateUsingTree');
3450
const { proof: proof2 } = await mainProgram.validateUsingTree(
3551
proof1.publicOutput,
3652
proof1,
3753
sideVk,
3854
witness,
3955
SideloadedProgramProof.fromProof(childProof1)
4056
);
57+
perfMain.end();
4158

59+
perfMain.start('verify', 'validateUsingTree');
4260
const validProof2 = await verify(proof2, mainVk);
61+
perfMain.end();
4362
console.log('ok?', validProof2);
4463

45-
console.log('Proving different method of child program');
64+
console.log('\nProving different method of child program');
65+
perfSide.start('prove', 'assertAndAdd');
4666
const { proof: childProof2 } = await sideloadedProgram.assertAndAdd(Field(0), Field(10));
67+
perfSide.end();
4768

48-
console.log('Proving verification inside main program');
69+
console.log('\nProving verification inside main program');
4970
const { proof: proof3 } = await mainProgram.validateUsingTree(
5071
proof1.publicOutput,
5172
proof1,

tests/perf-regression/perf-regression.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,12 @@ MODE=$1
1515
./run src/examples/crypto/blake2b/run.ts --bundle "$MODE"
1616
./run src/examples/crypto/rsa/run.ts --bundle "$MODE"
1717

18+
./run src/examples/zkprogram/mutual-recursion.ts --bundle "$MODE"
19+
./run src/examples/zkprogram/hash-chain.ts --bundle "$MODE"
20+
./run src/examples/zkprogram/gadgets.ts --bundle "$MODE"
21+
./run src/examples/zkprogram/side-loading/run.ts --bundle "$MODE"
22+
./run src/examples/zkprogram/runtime-table/run.ts --bundle "$MODE"
23+
./run src/examples/zkprogram/program-small-big.ts --bundle "$MODE"
24+
1825
# Run CS + zkApps performance regression tests
1926
./run tests/perf-regression/perf-regression.ts --bundle "$MODE"
Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
import assert from 'node:assert';
2-
import { diverse, Bytes128 } from './diverse-zk-program.js';
2+
import { verify } from 'o1js';
3+
import { Performance } from '../../src/lib/testing/perf-regression.js';
4+
import { Bytes128, diverse } from './diverse-zk-program.js';
35

4-
console.log('testing proof generation for diverse program');
5-
await diverse.compile();
6+
const cs = await diverse.analyzeMethods();
7+
const perfDiverse = Performance.create(diverse.name, cs);
68

9+
perfDiverse.start('compile');
10+
const { verificationKey } = await diverse.compile();
11+
perfDiverse.end();
12+
13+
perfDiverse.start('prove', 'sha3');
714
let { proof: proof1 } = await diverse.sha3(Bytes128.fromString('hello'));
8-
assert(await diverse.verify(proof1), 'verifies');
15+
perfDiverse.end();
16+
17+
perfDiverse.start('verify', 'sha3');
18+
const isValid1 = await verify(proof1, verificationKey);
19+
perfDiverse.end();
20+
assert(isValid1, 'proof1 verification failed!');
921

22+
perfDiverse.start('prove', 'recursive');
1023
let { proof: proof2 } = await diverse.recursive(proof1);
11-
assert(await diverse.verify(proof2), 'verifies');
24+
perfDiverse.end();
25+
26+
perfDiverse.start('verify', 'recursive');
27+
const isValid2 = await verify(proof2, verificationKey);
28+
perfDiverse.end();
29+
assert(isValid2, 'proof2 verification failed!');

0 commit comments

Comments
 (0)