UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

415 lines (348 loc) 11.5 kB
import { Bool } from '../../provable/bool.js'; import { Field } from '../../provable/field.js'; import { UInt32 } from '../../provable/int.js'; import { PrivateKey, PublicKey } from '../../provable/crypto/signature.js'; import { HashInput } from '../../provable/types/provable-derivers.js'; import * as Bindings from '../../../bindings/mina-transaction/v2/index.js'; import { NetworkId } from '../../../mina-signer/src/types.js'; import { protocolVersions } from '../../../bindings/crypto/constants.js'; export { AccountUpdateAuthorization, AccountUpdateAuthorizationEnvironment, AccountUpdateAuthorizationKind, AccountUpdateAuthorizationKindIdentifier, AccountUpdateAuthorizationKindWithZkappContext, AuthorizationLevelIdentifier, VerificationKeyAuthorizationLevel, ZkappFeePaymentAuthorizationEnvironment, ZkappCommandAuthorizationEnvironment, }; type AuthorizationLevelIdentifier = Bindings.Leaves.AuthRequiredIdentifier; export class AuthorizationLevel { // TODO: it would be nice if these could be private, but then the subtyping doesn't work... maybe we can do a trick here with object splats? constant: Bool; signatureNecessary: Bool; signatureSufficient: Bool; constructor({ constant, signatureNecessary, signatureSufficient, }: { constant: Bool; signatureNecessary: Bool; signatureSufficient: Bool; }) { this.constant = constant; this.signatureNecessary = signatureNecessary; this.signatureSufficient = signatureSufficient; } toInternalRepr(): Bindings.Leaves.AuthRequired { return this; } static fromInternalRepr(x: Bindings.Leaves.AuthRequired): AuthorizationLevel { return new AuthorizationLevel(x); } toJSON(): any { return AuthorizationLevel.toJSON(this); } toInput(): HashInput { return AuthorizationLevel.toInput(this); } toFields(): Field[] { return AuthorizationLevel.toFields(this); } isImpossible(): Bool { return Bindings.Leaves.AuthRequired.isImpossible(this); } isNone(): Bool { return Bindings.Leaves.AuthRequired.isNone(this); } isProof(): Bool { return Bindings.Leaves.AuthRequired.isProof(this); } isSignature(): Bool { return Bindings.Leaves.AuthRequired.isSignature(this); } isProofOrSignature(): Bool { return Bindings.Leaves.AuthRequired.isEither(this); } requiresProof(): Bool { return this.isProof().or(this.isProofOrSignature()); } requiresSignature(): Bool { return this.isSignature().or(this.isProofOrSignature()); } isSatisfied(authKind: AccountUpdateAuthorizationKind): Bool { return Bool.allTrue([ this.requiresProof().implies(authKind.isProved), this.requiresSignature().implies(authKind.isSigned), ]); } // TODO: property test that this is the inverse of `from` identifier identifier(): AuthorizationLevelIdentifier { if (this.isImpossible().toBoolean()) { return 'Impossible'; } else if (this.isNone().toBoolean()) { return 'None'; } else if (this.isProof().toBoolean()) { return 'Proof'; } else if (this.isSignature().toBoolean()) { return 'Signature'; } else if (this.isProofOrSignature().toBoolean()) { return 'Either'; } else { throw new Error('internal error: invalid authorization level'); } } static Impossible(): AuthorizationLevel { return new AuthorizationLevel({ constant: new Bool(true), signatureNecessary: new Bool(true), signatureSufficient: new Bool(false), }); } static None(): AuthorizationLevel { return new AuthorizationLevel({ constant: new Bool(true), signatureNecessary: new Bool(false), signatureSufficient: new Bool(true), }); } static Proof(): AuthorizationLevel { return new AuthorizationLevel({ constant: new Bool(false), signatureNecessary: new Bool(false), signatureSufficient: new Bool(false), }); } static Signature(): AuthorizationLevel { return new AuthorizationLevel({ constant: new Bool(false), signatureNecessary: new Bool(true), signatureSufficient: new Bool(true), }); } static ProofOrSignature(): AuthorizationLevel { return new AuthorizationLevel({ constant: new Bool(false), signatureNecessary: new Bool(false), signatureSufficient: new Bool(true), }); } // TODO: ProofAndSignature static sizeInFields(): number { return Bindings.Leaves.AuthRequired.sizeInFields(); } static empty(): AuthorizationLevel { return new AuthorizationLevel(Bindings.Leaves.AuthRequired.empty()); } static toJSON(x: AuthorizationLevel): any { return Bindings.Leaves.AuthRequired.toJSON(x); } static toInput(x: AuthorizationLevel): HashInput { return Bindings.Leaves.AuthRequired.toInput(x); } static toFields(x: AuthorizationLevel): Field[] { return Bindings.Leaves.AuthRequired.toFields(x); } static toAuxiliary(x?: AuthorizationLevel): any[] { return Bindings.Leaves.AuthRequired.toAuxiliary(x); } static fromFields(fields: Field[], aux: any[]): AuthorizationLevel { return new AuthorizationLevel(Bindings.Leaves.AuthRequired.fromFields(fields, aux)); } static check(x: AuthorizationLevel) { Bindings.Leaves.AuthRequired.check(x); } static toValue(x: AuthorizationLevel): AuthorizationLevel { return x; } static fromValue(x: AuthorizationLevel): AuthorizationLevel { return x; } static from(x: AuthorizationLevelIdentifier | AuthorizationLevel): AuthorizationLevel { switch (x) { case 'Signature': return AuthorizationLevel.Signature(); case 'Proof': return AuthorizationLevel.Proof(); // TODO: rename this case 'Either': return AuthorizationLevel.ProofOrSignature(); case 'None': return AuthorizationLevel.None(); case 'Impossible': return AuthorizationLevel.Impossible(); default: return x; } } } class VerificationKeyAuthorizationLevel { auth: AuthorizationLevel; txnVersion: UInt32; constructor( auth: AuthorizationLevel, txnVersion: UInt32 = UInt32.from(protocolVersions.txnVersion) ) { this.auth = auth; this.txnVersion = txnVersion; } toJSON(): { auth: AuthorizationLevelIdentifier; txnVersion: string } { return { auth: this.auth.toJSON(), txnVersion: this.txnVersion.toString(), }; } // private static get layout(): BindingsLayout { // return bindingsLayout.AccountUpdate // .get('body', 'update', 'permissions') // .unwrapOption() // .inner // .get('setVerificationKey') // .unwrapObject(); // } static sizeInFields(): number { return Bindings.Leaves.AuthRequired.sizeInFields(); } static empty(): VerificationKeyAuthorizationLevel { return new VerificationKeyAuthorizationLevel(AuthorizationLevel.empty(), UInt32.zero); } static toFields(_x: VerificationKeyAuthorizationLevel): Field[] { throw new Error('TODO'); // return Bindings.AuthRequired.toFields(x); } static toAuxiliary(_x?: VerificationKeyAuthorizationLevel): any[] { throw new Error('TODO'); // return Bindings.AuthRequired.toAuxiliary(x); } static fromFields(_fields: Field[], _aux: any[]): VerificationKeyAuthorizationLevel { throw new Error('TODO'); /* BindingsLayout.Object.fromFields(fields, aux) const schema = { auth: AuthorizationLevel.fromFields, txnVersion: UInt32.fromFields, }; return new VerificationKeyAuthorizationLevel(BindingsLayout.fromFields(VerificationKeyAuthorizationLevel.bindingsLayout, this, )); */ } static check(_x: VerificationKeyAuthorizationLevel) { throw new Error('TODO'); // Bindings.AuthRequired.check(x); } static toValue(x: VerificationKeyAuthorizationLevel): VerificationKeyAuthorizationLevel { return x; } static fromValue(x: VerificationKeyAuthorizationLevel): VerificationKeyAuthorizationLevel { return x; } static from( x: AuthorizationLevelIdentifier | AuthorizationLevel | VerificationKeyAuthorizationLevel ): VerificationKeyAuthorizationLevel { if (x instanceof VerificationKeyAuthorizationLevel) { return x; } else { return new VerificationKeyAuthorizationLevel(AuthorizationLevel.from(x)); } } } interface AccountUpdateAuthorization { proof: string | null; signature: string | null; } type AccountUpdateAuthorizationKindIdentifier = | 'None' | 'Signature' | 'Proof' | 'SignatureAndProof'; class AccountUpdateAuthorizationKind { isSigned: Bool; isProved: Bool; constructor({ isSigned, isProved }: { isSigned: Bool; isProved: Bool }) { this.isSigned = isSigned; this.isProved = isProved; } // NB: only safe to call in prover contexts // TODO: we should replace this with a circuit-safe representation using ZkEnum identifier(): AccountUpdateAuthorizationKindIdentifier { if (this.isSigned.toBoolean()) { if (this.isProved.toBoolean()) { return 'SignatureAndProof'; } else { return 'Signature'; } } else { if (this.isProved.toBoolean()) { return 'Proof'; } else { return 'None'; } } } static from( x: AccountUpdateAuthorizationKindIdentifier | AccountUpdateAuthorizationKind ): AccountUpdateAuthorizationKind { if (x instanceof AccountUpdateAuthorizationKind) return x; switch (x) { case 'None': return AccountUpdateAuthorizationKind.None(); case 'Signature': return AccountUpdateAuthorizationKind.Signature(); case 'Proof': return AccountUpdateAuthorizationKind.Proof(); case 'SignatureAndProof': return AccountUpdateAuthorizationKind.SignatureAndProof(); } } static None(): AccountUpdateAuthorizationKind { return new AccountUpdateAuthorizationKind({ isSigned: new Bool(false), isProved: new Bool(false), }); } static Signature(): AccountUpdateAuthorizationKind { return new AccountUpdateAuthorizationKind({ isSigned: new Bool(true), isProved: new Bool(false), }); } static Proof(): AccountUpdateAuthorizationKind { return new AccountUpdateAuthorizationKind({ isSigned: new Bool(false), isProved: new Bool(true), }); } static SignatureAndProof(): AccountUpdateAuthorizationKind { return new AccountUpdateAuthorizationKind({ isSigned: new Bool(true), isProved: new Bool(true), }); } } class AccountUpdateAuthorizationKindWithZkappContext { isSigned: Bool; isProved: Bool; verificationKeyHash: Field; constructor(kind: AccountUpdateAuthorizationKind, verificationKeyHash: Field) { this.isSigned = kind.isSigned; this.isProved = kind.isProved; this.verificationKeyHash = verificationKeyHash; } toJSON(): any { Bindings.Layout.AuthorizationKindStructured.toJSON(this); } } type AccountUpdateAuthorizationEnvironment = ZkappCommandAuthorizationEnvironment & { accountUpdateForestCommitment: bigint; // TODO: Field; fullTransactionCommitment?: bigint; // TODO: Field; }; interface ZkappFeePaymentAuthorizationEnvironment { networkId: NetworkId; privateKey: PrivateKey; fullTransactionCommitment: bigint; // TODO: Field } interface ZkappCommandAuthorizationEnvironment { networkId: NetworkId; getPrivateKey(publicKey: PublicKey): Promise<PrivateKey>; }