From 6428ab707cad20ead26a0cdb948b7c4633b5e923 Mon Sep 17 00:00:00 2001 From: Gregor Date: Wed, 8 May 2024 10:28:06 +0200 Subject: [PATCH 1/5] add better-named wrappers for vk permissions --- src/lib/mina/account-update.ts | 97 +++++++++++++++++++++++++++------- src/lib/mina/precondition.ts | 3 ++ 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/lib/mina/account-update.ts b/src/lib/mina/account-update.ts index cfb21532d..cae627548 100644 --- a/src/lib/mina/account-update.ts +++ b/src/lib/mina/account-update.ts @@ -152,6 +152,18 @@ const False = () => Bool(false); * documentation on those methods to learn more. */ type Permission = Types.AuthRequired; + +class VerificationKeyPermission { + constructor(public auth: Permission, public txnVersion: UInt32) {} + + // TODO this class could be made incompatible with a plain object (breaking change) + // private _ = undefined; + + static withCurrentTxnVersion(perm: Permission) { + return new VerificationKeyPermission(perm, TransactionVersion.current()); + } +} + let Permission = { /** * Modification is impossible. @@ -197,6 +209,65 @@ let Permission = { signatureNecessary: False(), signatureSufficient: True(), }), + + /** + * Special Verification key permissions. + * + * The difference to normal permissions is that `Permission.proof` and `Permission.impossible` are replaced by less restrictive permissions: + * - `impossible` is replaced by `impossibleUntilHardfork` + * - `proof` is replaced by `proofUntilHardfork` + * + * The issue is that a future hardfork which changes the proof system could mean that old verification keys can no longer + * be used to verify proofs in the new proof system, and the zkApp would have to be redeployed to adapt the verification key to the new proof system. + * + * Having either `impossible` or `proof` would mean that these zkApps can't be upgraded after this hypothetical hardfork, and would become unusable. + * + * A future hardfork would manifest as an increment in the "transaction version" of zkApps, which you can check with {@link TransactionVersion.current()}. + * + * The `impossibleUntilHardfork` and `proofUntilHardfork` have an additional `txnVersion` field. + * These permissions follow the same semantics of not upgradable, or only upgradable with proofs, + * _as long as_ the current transaction version is the same as the one one the permission. + * + * If the current transaction version is higher than the one on the permission, the permission is treated as `signature`, + * and the zkApp can be redeployed with a signature of the original account owner. + */ + VerificationKey: { + /** + * Modification is impossible, until the next hardfork. + * + * After a hardfork which changes the {@link TransactionVersion}, the permission is treated as `signature`. + */ + impossibleUntilHardfork: () => + VerificationKeyPermission.withCurrentTxnVersion(Permission.impossible()), + + /** + * Modification is always permitted + */ + none: () => + VerificationKeyPermission.withCurrentTxnVersion(Permission.none()), + + /** + * Modification is permitted by zkapp proofs only; but only until the next hardfork. + * + * After a hardfork which changes the {@link TransactionVersion}, the permission is treated as `signature`. + */ + proofUntilHardfork: () => + VerificationKeyPermission.withCurrentTxnVersion(Permission.proof()), + + /** + * Modification is permitted by signatures only, using the private key of the zkapp account + */ + signature: () => + VerificationKeyPermission.withCurrentTxnVersion(Permission.signature()), + + /** + * Modification is permitted by zkapp proofs or signatures + */ + proofOrSignature: () => + VerificationKeyPermission.withCurrentTxnVersion( + Permission.proofOrSignature() + ), + }, }; // TODO: we could replace the interface below if we could bridge annotations from OCaml @@ -242,10 +313,7 @@ interface Permissions extends Permissions_ { * key associated with the circuit tied to this account. Effectively * "upgradeability" of the smart contract. */ - setVerificationKey: { - auth: Permission; - txnVersion: UInt32; - }; + setVerificationKey: VerificationKeyPermission; /** * The {@link Permission} corresponding to the ability to set the zkapp uri @@ -283,6 +351,7 @@ interface Permissions extends Permissions_ { } let Permissions = { ...Permission, + /** * Default permissions are: * @@ -311,10 +380,7 @@ let Permissions = { receive: Permission.none(), setDelegate: Permission.signature(), setPermissions: Permission.signature(), - setVerificationKey: { - auth: Permission.signature(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permission.VerificationKey.signature(), setZkappUri: Permission.signature(), editActionState: Permission.proof(), setTokenSymbol: Permission.signature(), @@ -330,10 +396,7 @@ let Permissions = { receive: Permission.none(), setDelegate: Permission.signature(), setPermissions: Permission.signature(), - setVerificationKey: { - auth: Permission.signature(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permission.VerificationKey.signature(), setZkappUri: Permission.signature(), editActionState: Permission.signature(), setTokenSymbol: Permission.signature(), @@ -350,10 +413,7 @@ let Permissions = { access: Permission.none(), setDelegate: Permission.none(), setPermissions: Permission.none(), - setVerificationKey: { - auth: Permission.signature(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permission.VerificationKey.none(), setZkappUri: Permission.none(), editActionState: Permission.none(), setTokenSymbol: Permission.none(), @@ -369,10 +429,7 @@ let Permissions = { access: Permission.impossible(), setDelegate: Permission.impossible(), setPermissions: Permission.impossible(), - setVerificationKey: { - auth: Permission.signature(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permission.VerificationKey.impossibleUntilHardfork(), setZkappUri: Permission.impossible(), editActionState: Permission.impossible(), setTokenSymbol: Permission.impossible(), diff --git a/src/lib/mina/precondition.ts b/src/lib/mina/precondition.ts index 87cf5e0df..f27674849 100644 --- a/src/lib/mina/precondition.ts +++ b/src/lib/mina/precondition.ts @@ -19,6 +19,7 @@ import { ZkappUri, } from '../../bindings/mina-transaction/transaction-leaves.js'; import type { Types } from '../../bindings/mina-transaction/types.js'; +import type { Permissions } from './account-update.js'; import { ZkappStateLength } from './mina-instance.js'; export { @@ -615,6 +616,8 @@ type UpdateValueOriginal = { type UpdateValue = { [K in keyof Update_]: K extends 'zkappUri' | 'tokenSymbol' ? string + : K extends 'permissions' + ? Permissions : Update_[K]['value']; }; From 228168aefd4dc47179d54fcc6fb7b3b3aef2603f Mon Sep 17 00:00:00 2001 From: Gregor Date: Wed, 8 May 2024 10:28:12 +0200 Subject: [PATCH 2/5] adapt all examples --- src/examples/zkapps/dex/erc20.ts | 6 +----- src/examples/zkapps/dex/upgradability.ts | 14 ++------------ src/examples/zkapps/voting/dummy-contract.ts | 5 ----- src/examples/zkapps/voting/membership.ts | 6 +----- src/examples/zkapps/voting/voting.ts | 6 +----- src/examples/zkapps/zkapp-self-update.ts | 6 +----- 6 files changed, 6 insertions(+), 37 deletions(-) diff --git a/src/examples/zkapps/dex/erc20.ts b/src/examples/zkapps/dex/erc20.ts index 586b301fa..a5f6e290e 100644 --- a/src/examples/zkapps/dex/erc20.ts +++ b/src/examples/zkapps/dex/erc20.ts @@ -13,7 +13,6 @@ import { TokenContract, AccountUpdateForest, Struct, - TransactionVersion, } from 'o1js'; export { Erc20Like, TrivialCoin }; @@ -79,10 +78,7 @@ class TrivialCoin extends TokenContract implements Erc20Like { // make account non-upgradable forever this.account.permissions.set({ ...Permissions.default(), - setVerificationKey: { - auth: Permissions.impossible(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permissions.VerificationKey.impossibleUntilHardfork(), setPermissions: Permissions.impossible(), access: Permissions.proofOrSignature(), }); diff --git a/src/examples/zkapps/dex/upgradability.ts b/src/examples/zkapps/dex/upgradability.ts index 4034f2e4a..52e0debec 100644 --- a/src/examples/zkapps/dex/upgradability.ts +++ b/src/examples/zkapps/dex/upgradability.ts @@ -1,12 +1,5 @@ import { expect } from 'expect'; -import { - AccountUpdate, - Mina, - Permissions, - PrivateKey, - UInt64, - TransactionVersion, -} from 'o1js'; +import { AccountUpdate, Mina, Permissions, PrivateKey, UInt64 } from 'o1js'; import { getProfiler } from '../../utils/profiler.js'; import { TokenContract, addresses, createDex, keys, tokenIds } from './dex.js'; @@ -446,10 +439,7 @@ async function upgradeabilityTests({ withVesting }: { withVesting: boolean }) { let update = AccountUpdate.createSigned(addresses.dex); update.account.permissions.set({ ...Permissions.initial(), - setVerificationKey: { - auth: Permissions.impossible(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permissions.VerificationKey.impossibleUntilHardfork(), }); }); await tx.prove(); diff --git a/src/examples/zkapps/voting/dummy-contract.ts b/src/examples/zkapps/voting/dummy-contract.ts index 006cacc15..87aaf9e05 100644 --- a/src/examples/zkapps/voting/dummy-contract.ts +++ b/src/examples/zkapps/voting/dummy-contract.ts @@ -6,7 +6,6 @@ import { method, DeployArgs, Permissions, - TransactionVersion, } from 'o1js'; export class DummyContract extends SmartContract { @@ -19,10 +18,6 @@ export class DummyContract extends SmartContract { editState: Permissions.proofOrSignature(), editActionState: Permissions.proofOrSignature(), setPermissions: Permissions.proofOrSignature(), - setVerificationKey: { - auth: Permissions.signature(), - txnVersion: TransactionVersion.current(), - }, incrementNonce: Permissions.proofOrSignature(), }); this.sum.set(Field(0)); diff --git a/src/examples/zkapps/voting/membership.ts b/src/examples/zkapps/voting/membership.ts index 178d91182..3210fb39c 100644 --- a/src/examples/zkapps/voting/membership.ts +++ b/src/examples/zkapps/voting/membership.ts @@ -11,7 +11,6 @@ import { provablePure, AccountUpdate, Provable, - TransactionVersion, } from 'o1js'; import { Member } from './member.js'; import { ParticipantPreconditions } from './preconditions.js'; @@ -76,10 +75,7 @@ export class Membership_ extends SmartContract { editState: Permissions.proofOrSignature(), editActionState: Permissions.proofOrSignature(), setPermissions: Permissions.proofOrSignature(), - setVerificationKey: { - auth: Permissions.proofOrSignature(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permissions.VerificationKey.proofOrSignature(), incrementNonce: Permissions.proofOrSignature(), }); } diff --git a/src/examples/zkapps/voting/voting.ts b/src/examples/zkapps/voting/voting.ts index 3a90071bf..f68157cdf 100644 --- a/src/examples/zkapps/voting/voting.ts +++ b/src/examples/zkapps/voting/voting.ts @@ -11,7 +11,6 @@ import { provablePure, AccountUpdate, Provable, - TransactionVersion, } from 'o1js'; import { Member } from './member.js'; @@ -103,10 +102,7 @@ export class Voting_ extends SmartContract { editState: Permissions.proofOrSignature(), editActionState: Permissions.proofOrSignature(), incrementNonce: Permissions.proofOrSignature(), - setVerificationKey: { - auth: Permissions.none(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permissions.VerificationKey.none(), setPermissions: Permissions.proofOrSignature(), }); this.accumulatedVotes.set(Reducer.initialActionState); diff --git a/src/examples/zkapps/zkapp-self-update.ts b/src/examples/zkapps/zkapp-self-update.ts index 53c27eb7b..38e2cc369 100644 --- a/src/examples/zkapps/zkapp-self-update.ts +++ b/src/examples/zkapps/zkapp-self-update.ts @@ -9,7 +9,6 @@ import { Mina, AccountUpdate, Provable, - TransactionVersion, } from 'o1js'; class SelfUpdater extends SmartContract { @@ -17,10 +16,7 @@ class SelfUpdater extends SmartContract { super.init(); this.account.permissions.set({ ...Permissions.default(), - setVerificationKey: { - auth: Permissions.proof(), - txnVersion: TransactionVersion.current(), - }, + setVerificationKey: Permissions.VerificationKey.proofUntilHardfork(), }); } From b85dc0cbf1c41bd062e8a453e0ca132c0f330d6e Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 9 May 2024 08:18:05 +0200 Subject: [PATCH 3/5] change naming to "during current version" --- src/examples/zkapps/dex/erc20.ts | 3 ++- src/examples/zkapps/dex/upgradability.ts | 3 ++- src/examples/zkapps/zkapp-self-update.ts | 3 ++- src/lib/mina/account-update.ts | 30 ++++++++++++------------ 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/examples/zkapps/dex/erc20.ts b/src/examples/zkapps/dex/erc20.ts index a5f6e290e..9438bb09b 100644 --- a/src/examples/zkapps/dex/erc20.ts +++ b/src/examples/zkapps/dex/erc20.ts @@ -78,7 +78,8 @@ class TrivialCoin extends TokenContract implements Erc20Like { // make account non-upgradable forever this.account.permissions.set({ ...Permissions.default(), - setVerificationKey: Permissions.VerificationKey.impossibleUntilHardfork(), + setVerificationKey: + Permissions.VerificationKey.impossibleDuringCurrentVersion(), setPermissions: Permissions.impossible(), access: Permissions.proofOrSignature(), }); diff --git a/src/examples/zkapps/dex/upgradability.ts b/src/examples/zkapps/dex/upgradability.ts index 52e0debec..1e1f8e856 100644 --- a/src/examples/zkapps/dex/upgradability.ts +++ b/src/examples/zkapps/dex/upgradability.ts @@ -439,7 +439,8 @@ async function upgradeabilityTests({ withVesting }: { withVesting: boolean }) { let update = AccountUpdate.createSigned(addresses.dex); update.account.permissions.set({ ...Permissions.initial(), - setVerificationKey: Permissions.VerificationKey.impossibleUntilHardfork(), + setVerificationKey: + Permissions.VerificationKey.impossibleDuringCurrentVersion(), }); }); await tx.prove(); diff --git a/src/examples/zkapps/zkapp-self-update.ts b/src/examples/zkapps/zkapp-self-update.ts index 38e2cc369..e0ef735e8 100644 --- a/src/examples/zkapps/zkapp-self-update.ts +++ b/src/examples/zkapps/zkapp-self-update.ts @@ -16,7 +16,8 @@ class SelfUpdater extends SmartContract { super.init(); this.account.permissions.set({ ...Permissions.default(), - setVerificationKey: Permissions.VerificationKey.proofUntilHardfork(), + setVerificationKey: + Permissions.VerificationKey.proofDuringCurrentVersion(), }); } diff --git a/src/lib/mina/account-update.ts b/src/lib/mina/account-update.ts index cae627548..6a38942e7 100644 --- a/src/lib/mina/account-update.ts +++ b/src/lib/mina/account-update.ts @@ -159,7 +159,7 @@ class VerificationKeyPermission { // TODO this class could be made incompatible with a plain object (breaking change) // private _ = undefined; - static withCurrentTxnVersion(perm: Permission) { + static withCurrentVersion(perm: Permission) { return new VerificationKeyPermission(perm, TransactionVersion.current()); } } @@ -214,21 +214,21 @@ let Permission = { * Special Verification key permissions. * * The difference to normal permissions is that `Permission.proof` and `Permission.impossible` are replaced by less restrictive permissions: - * - `impossible` is replaced by `impossibleUntilHardfork` - * - `proof` is replaced by `proofUntilHardfork` + * - `impossible` is replaced by `impossibleDuringCurrentVersion` + * - `proof` is replaced by `proofDuringCurrentVersion` * * The issue is that a future hardfork which changes the proof system could mean that old verification keys can no longer * be used to verify proofs in the new proof system, and the zkApp would have to be redeployed to adapt the verification key to the new proof system. * * Having either `impossible` or `proof` would mean that these zkApps can't be upgraded after this hypothetical hardfork, and would become unusable. * - * A future hardfork would manifest as an increment in the "transaction version" of zkApps, which you can check with {@link TransactionVersion.current()}. + * Such a future hardfork would manifest as an increment in the "transaction version" of zkApps, which you can check with {@link TransactionVersion.current()}. * - * The `impossibleUntilHardfork` and `proofUntilHardfork` have an additional `txnVersion` field. + * The `impossibleDuringCurrentVersion` and `proofDuringCurrentVersion` have an additional `txnVersion` field. * These permissions follow the same semantics of not upgradable, or only upgradable with proofs, * _as long as_ the current transaction version is the same as the one one the permission. * - * If the current transaction version is higher than the one on the permission, the permission is treated as `signature`, + * Once the current transaction version is higher than the one on the permission, the permission is treated as `signature`, * and the zkApp can be redeployed with a signature of the original account owner. */ VerificationKey: { @@ -237,34 +237,33 @@ let Permission = { * * After a hardfork which changes the {@link TransactionVersion}, the permission is treated as `signature`. */ - impossibleUntilHardfork: () => - VerificationKeyPermission.withCurrentTxnVersion(Permission.impossible()), + impossibleDuringCurrentVersion: () => + VerificationKeyPermission.withCurrentVersion(Permission.impossible()), /** * Modification is always permitted */ - none: () => - VerificationKeyPermission.withCurrentTxnVersion(Permission.none()), + none: () => VerificationKeyPermission.withCurrentVersion(Permission.none()), /** * Modification is permitted by zkapp proofs only; but only until the next hardfork. * * After a hardfork which changes the {@link TransactionVersion}, the permission is treated as `signature`. */ - proofUntilHardfork: () => - VerificationKeyPermission.withCurrentTxnVersion(Permission.proof()), + proofDuringCurrentVersion: () => + VerificationKeyPermission.withCurrentVersion(Permission.proof()), /** * Modification is permitted by signatures only, using the private key of the zkapp account */ signature: () => - VerificationKeyPermission.withCurrentTxnVersion(Permission.signature()), + VerificationKeyPermission.withCurrentVersion(Permission.signature()), /** * Modification is permitted by zkapp proofs or signatures */ proofOrSignature: () => - VerificationKeyPermission.withCurrentTxnVersion( + VerificationKeyPermission.withCurrentVersion( Permission.proofOrSignature() ), }, @@ -429,7 +428,8 @@ let Permissions = { access: Permission.impossible(), setDelegate: Permission.impossible(), setPermissions: Permission.impossible(), - setVerificationKey: Permission.VerificationKey.impossibleUntilHardfork(), + setVerificationKey: + Permission.VerificationKey.impossibleDuringCurrentVersion(), setZkappUri: Permission.impossible(), editActionState: Permission.impossible(), setTokenSymbol: Permission.impossible(), From d664b6bd15f46af9b3f5684da7dc901db316c349 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 9 May 2024 08:23:51 +0200 Subject: [PATCH 4/5] comment tweaks --- src/lib/mina/account-update.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/mina/account-update.ts b/src/lib/mina/account-update.ts index 6a38942e7..79a92a758 100644 --- a/src/lib/mina/account-update.ts +++ b/src/lib/mina/account-update.ts @@ -218,7 +218,7 @@ let Permission = { * - `proof` is replaced by `proofDuringCurrentVersion` * * The issue is that a future hardfork which changes the proof system could mean that old verification keys can no longer - * be used to verify proofs in the new proof system, and the zkApp would have to be redeployed to adapt the verification key to the new proof system. + * be used to verify proofs in the new proof system, and the zkApp would have to be redeployed to adapt the verification key. * * Having either `impossible` or `proof` would mean that these zkApps can't be upgraded after this hypothetical hardfork, and would become unusable. * @@ -226,16 +226,16 @@ let Permission = { * * The `impossibleDuringCurrentVersion` and `proofDuringCurrentVersion` have an additional `txnVersion` field. * These permissions follow the same semantics of not upgradable, or only upgradable with proofs, - * _as long as_ the current transaction version is the same as the one one the permission. + * _as long as_ the current transaction version is the same as the one on the permission. * * Once the current transaction version is higher than the one on the permission, the permission is treated as `signature`, * and the zkApp can be redeployed with a signature of the original account owner. */ VerificationKey: { /** - * Modification is impossible, until the next hardfork. + * Modification is impossible, as long as the network accepts the current {@link TransactionVersion}. * - * After a hardfork which changes the {@link TransactionVersion}, the permission is treated as `signature`. + * After a hardfork that increments the transaction version, the permission is treated as `signature`. */ impossibleDuringCurrentVersion: () => VerificationKeyPermission.withCurrentVersion(Permission.impossible()), @@ -246,9 +246,9 @@ let Permission = { none: () => VerificationKeyPermission.withCurrentVersion(Permission.none()), /** - * Modification is permitted by zkapp proofs only; but only until the next hardfork. + * Modification is permitted by zkapp proofs only; as long as the network accepts the current {@link TransactionVersion}. * - * After a hardfork which changes the {@link TransactionVersion}, the permission is treated as `signature`. + * After a hardfork that increments the transaction version, the permission is treated as `signature`. */ proofDuringCurrentVersion: () => VerificationKeyPermission.withCurrentVersion(Permission.proof()), From 045c90b87c75238f2adc4fd2c8763202f9beb05f Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 9 May 2024 08:29:34 +0200 Subject: [PATCH 5/5] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b99530dc..7847fcdb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased](https://github.com/o1-labs/o1js/compare/4a17de857...HEAD) +### Added + +- `Permissions.VerificationKey`, a namespace for verification key permissions https://github.com/o1-labs/o1js/pull/1639 + - Includes more accurate names for the `impossible` and `proof` permissions for verification keys, which are now called `impossibleDuringCurrentVersion` and `proofDuringCurrentVersion` respectively. + ### Fixes - Fix absolute imports which prevented compilation in some TS projects that used o1js https://github.com/o1-labs/o1js/pull/1628