Skip to content

Commit 932189d

Browse files
authored
Merge pull request #2171 from o1-labs/boray/vk-validation
Add Verification Key Validation To Localblockchain
2 parents 3322c49 + e889c30 commit 932189d

File tree

6 files changed

+74
-3
lines changed

6 files changed

+74
-3
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
4242

4343
### Added
4444

45-
- Added bitwise operation methods (xor, not, and, or) to `UInt8` class. https://github.com/o1-labs/o1js/pull/2144$0
45+
- Added bitwise operation methods (xor, not, and, or) to `UInt8` class. https://github.com/o1-labs/o1js/pull/2144
46+
47+
### Changed
48+
49+
- Added verification key validity checks to `LocalBlockchain`. https://github.com/o1-labs/o1js/pull/2171
4650

4751
## [2.4.0](https://github.com/o1-labs/o1js/compare/fb625f...6ff7f8470a) - 2025-04-01
4852

src/examples/zkapps/zkapp-self-update.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,30 @@ Provable.log('original verification key', fooVerificationKey);
5959

6060
const { verificationKey: barVerificationKey } = await Bar.compile();
6161

62+
try {
63+
const invalidVerificationKey = new VerificationKey({
64+
data: fooVerificationKey!.data,
65+
hash: barVerificationKey.hash,
66+
});
67+
68+
const tx2x = await Mina.transaction(deployer, async () => {
69+
// VK with mismatched hash and data should throw
70+
await contract.replaceVerificationKey(invalidVerificationKey);
71+
});
72+
await tx2x.prove();
73+
await tx2x.sign([deployer.key]).send();
74+
} catch (error: any) {
75+
if (
76+
error.message.includes('The verification key hash is not consistent with the provided data')
77+
) {
78+
console.log('correctly threw on invalid verification key');
79+
} else {
80+
throw error;
81+
}
82+
}
83+
6284
const tx2 = await Mina.transaction(deployer, async () => {
85+
// This call will work because the vk is valid
6386
await contract.replaceVerificationKey(barVerificationKey);
6487
});
6588
await tx2.prove();

src/lib/mina/v1/transaction-validation.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { Types, TypesBigint } from '../../../bindings/mina-transaction/v1/types.
2121
import type { NetworkId } from '../../../mina-signer/src/types.js';
2222
import type { Account } from './account.js';
2323
import type { NetworkValue } from './precondition.js';
24+
import { VerificationKey } from '../../proof-system/verification-key.js';
2425

2526
export {
2627
reportGetAccountError,
@@ -242,8 +243,13 @@ async function verifyAccountUpdate(
242243
publicOutput: [],
243244
};
244245

245-
let verificationKey = account.zkapp?.verificationKey?.data;
246-
assert(verificationKey !== undefined, 'Account does not have a verification key');
246+
let verificationKeyRaw = account.zkapp?.verificationKey;
247+
assert(verificationKeyRaw !== undefined, 'Account does not have a verification key');
248+
let verificationKey = verificationKeyRaw.data;
249+
250+
const isVkValid = await VerificationKey.checkValidity(verificationKeyRaw);
251+
if (!isVkValid)
252+
throw Error(`The verification key hash is not consistent with the provided data`);
247253

248254
isValidProof = await verify(proof, verificationKey);
249255
if (!isValidProof) {
@@ -305,6 +311,13 @@ async function verifyAccountUpdate(
305311
}
306312
});
307313

314+
if (accountUpdate.update.verificationKey.isSome.toBoolean()) {
315+
const isVkValid = await VerificationKey.checkValidity(
316+
accountUpdate.update.verificationKey.value
317+
);
318+
if (!isVkValid)
319+
throw Error(`The verification key hash is not consistent with the provided data`);
320+
}
308321
// checks the sequence events (which result in an updated sequence state)
309322
if (accountUpdate.body.actions.data.length > 0) {
310323
let p = permissionForUpdate('actions');

src/lib/proof-system/verification-key.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { initializeBindings, Pickles } from '../../snarky.js';
2+
import { synchronousRunners } from '../provable/core/provable-context.js';
23
import { provable } from '../provable/types/provable-derivers.js';
34
import { Struct } from '../provable/types/struct.js';
45
import { Field } from '../provable/wrapped.js';
6+
import { inCircuitVkHash } from './zkprogram.js';
57

68
export { VerificationKey };
79

@@ -26,6 +28,21 @@ class VerificationKey extends Struct({
2628
hash: Field(RAW_VERIFICATION_KEY.hash),
2729
});
2830
}
31+
32+
static async checkValidity(key: VerificationKey): Promise<boolean> {
33+
try {
34+
let { runAndCheckSync } = await synchronousRunners();
35+
36+
runAndCheckSync(() => {
37+
let vk = Pickles.sideLoaded.vkToCircuit(() => key.data);
38+
let inCircuitHash = inCircuitVkHash(vk);
39+
inCircuitHash.assertEquals(key.hash);
40+
});
41+
return true;
42+
} catch {
43+
return false;
44+
}
45+
}
2946
}
3047

3148
const RAW_VERIFICATION_KEY = {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
import { assert } from 'console';
22
import { VerificationKey } from './verification-key.js';
3+
import { Field } from '../provable/wrapped.js';
34

45
console.log('verification key consistency check (generated and cached)');
56
let generated = await VerificationKey.dummy();
67
let cached = VerificationKey.dummySync();
78

89
assert(generated.data === cached.data, 'data equals');
910
assert(generated.hash.equals(cached.hash).toBoolean(), 'hash equals');
11+
12+
let vkIsValid = await VerificationKey.checkValidity(generated);
13+
assert(vkIsValid, 'valid verification key is being rejected as invalid');
14+
15+
const invalidVerificationKey = new VerificationKey({
16+
data: generated.data,
17+
hash: Field.random(),
18+
});
19+
20+
21+
let vkIsNotValid = await VerificationKey.checkValidity(invalidVerificationKey);
22+
assert(vkIsNotValid === false, 'invalid verification key is being accepted as valid');

src/lib/proof-system/zkprogram.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export {
6060
TupleToInstances,
6161
PrivateInput,
6262
Proof,
63+
inCircuitVkHash,
6364
};
6465

6566
type Undefined = undefined;

0 commit comments

Comments
 (0)