o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
415 lines (348 loc) • 11.5 kB
text/typescript
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>;
}