import type { KeyPolicy } from "./role.ts"; import type { PageOpts } from "./paginator.ts"; import type { KeyInfo, UpdateKeyRequest, SchemaKeyType, KeyInRoleInfo, EvmSignRequest, EvmSignResponse, Eip191SignRequest, Eip712SignRequest, Eth2SignRequest, Eth2UnstakeRequest, AvaTx, BlobSignRequest, BtcSignRequest, SolanaSignRequest, SolanaSignResponse, BtcMessageSignResponse, BtcSignResponse, BlobSignResponse, AvaSignResponse, Eth2UnstakeResponse, Eth2SignResponse, Eip191Or712SignResponse, PsbtSignRequest, PsbtSignResponse, DiffieHellmanRequest, DiffieHellmanResponse, KeyInfoJwt, KeyAttestationQuery, KeyPropertiesPatch, Eip7702SignRequest, SignResponse, Scope, } from "./schema_types.ts"; import type { Ace, ApiClient, AvaChain, BabylonRegistrationRequest, BabylonRegistrationResponse, BabylonStakingRequest, BabylonStakingResponse, BtcMessageSignRequest, CubeSignerResponse, EditPolicy, Empty, ErrResponse, HistoricalTx, JsonValue, MfaReceipts, SuiSignRequest, SuiSignResponse, } from "./index.ts"; import { CubeSignerClient, delay } from "./index.ts"; import { loadSubtleCrypto } from "./user_export.ts"; import { encodeToHex, encodeToBase64 } from "./util.ts"; // these types are used in doc comments only // eslint-disable-next-line @typescript-eslint/no-unused-vars import type { KeyAttestationClaims } from "./schema_types.ts"; /** * Key access-control entry. * * This type allows specifying any valid {@link Scope} as an action, but CubeSigner * denies setting invalid / unsupported actions. */ // eslint-disable-next-line @typescript-eslint/no-empty-object-type export type KeyAce = Ace; /** Key ACL type. */ export type KeyAcl = KeyAce[]; /** Secp256k1 key type */ export enum Secp256k1 { Evm = "SecpEthAddr", Btc = "SecpBtc", BtcTest = "SecpBtcTest", Ltc = "SecpLtc", LtcTest = "SecpLtcTest", Xrp = "SecpXrpAddr", Cosmos = "SecpCosmosAddr", Taproot = "TaprootBtc", TaprootTest = "TaprootBtcTest", BabylonEots = "BabylonEots", BabylonCov = "BabylonCov", Ava = "SecpAvaAddr", AvaTest = "SecpAvaTestAddr", Tron = "SecpTronAddr", BtcLegacy = "SecpBtcLegacy", BtcLegacyTest = "SecpBtcLegacyTest", Doge = "SecpDogeAddr", DogeTest = "SecpDogeTestAddr", Kaspa = "SecpKaspaAddr", KaspaTest = "SecpKaspaTestAddr", KaspaSchnorr = "SchnorrKaspaAddr", KaspaTestSchnorr = "SchnorrKaspaTestAddr", } /** BLS key type */ export enum Bls { Eth2Deposited = "BlsPub", Eth2Inactive = "BlsInactive", AvaIcm = "BlsAvaIcm", } /** Ed25519 key type */ export enum Ed25519 { Solana = "Ed25519SolanaAddr", Sui = "Ed25519SuiAddr", Aptos = "Ed25519AptosAddr", Canton = "Ed25519CantonAddr", Cardano = "Ed25519CardanoAddrVk", Stellar = "Ed25519StellarAddr", Substrate = "Ed25519SubstrateAddr", Tendermint = "Ed25519TendermintAddr", BinanceApi = "Ed25519BinanceApi", CoinbaseApi = "Ed25519CoinbaseApi", Ton = "Ed25519TonAddr", Xrp = "Ed25519XrpAddr", } /** P256 key type */ export enum P256 { Cosmos = "P256CosmosAddr", Ontology = "P256OntologyAddr", Neo3 = "P256Neo3Addr", } /** Mnemonic key type */ export const Mnemonic = "Mnemonic" as const; export type Mnemonic = typeof Mnemonic; /** HmacSha256 key types */ export enum HmacSha256 { Generic = "HmacSha256", Bybit = "HmacSha256Bybit", } /** Stark key type */ export const Stark = "Stark" as const; export type Stark = typeof Stark; /** Baby Jubjub key type */ export const BabyJubjub = "BabyJubjub" as const; export type BabyJubjub = typeof BabyJubjub; /** Key type */ export type KeyType = Secp256k1 | Bls | Ed25519 | Mnemonic | HmacSha256 | Stark | P256 | BabyJubjub; /** * A representation of a signing key. */ export class Key { /** The CubeSigner instance that this key is associated with */ readonly #apiClient: ApiClient; /** @returns The organization that this key is in */ get orgId() { return this.#apiClient.sessionMeta.org_id; } /** * The id of the key: "Key#" followed by a unique identifier specific to * the type of key (such as a public key for BLS or an ethereum address for Secp) * * @example Key#0x8e3484687e66cdd26cf04c3647633ab4f3570148 */ readonly id: string; /** * A unique identifier specific to the type of key, such as a public key or an ethereum address * * @example 0x8e3484687e66cdd26cf04c3647633ab4f3570148 */ readonly materialId!: string; /** * @description Hex-encoded, serialized public key. The format used depends on the key type: * - secp256k1 keys use 65-byte uncompressed SECG format * - BLS keys use 48-byte compressed BLS12-381 (ZCash) format * @example 0x04d2688b6bc2ce7f9879b9e745f3c4dc177908c5cef0c1b64cff19ae7ff27dee623c64fe9d9c325c7fbbc748bbd5f607ce14dd83e28ebbbb7d3e7f2ffb70a79431 */ readonly publicKey: string; /** * Get the cached properties of this key. The cached properties reflect the * state of the last fetch or update (e.g., after awaiting `Key.enabled()` * or `Key.disable()`). */ cached: KeyInfo; /** * Attest to key properties. * * @param query Query parameters: * @param query.include_roles If specified, include all the roles the key is in. * @returns A JWT whose claims are the properties of the key. The type of the returned JWT payload is {@link KeyAttestationClaims}. */ async attest(query?: KeyAttestationQuery): Promise { return await this.#apiClient.keyAttest(this.id, query); } /** @returns The type of key. */ async type(): Promise { const data = await this.fetch(); return fromSchemaKeyType(data.key_type); } /** @returns Whether the key is enabled */ async enabled(): Promise { const data = await this.fetch(); return data.enabled; } /** * Enable the key. * * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided */ async enable(mfaReceipt?: MfaReceipts) { await this.update({ enabled: true }, mfaReceipt); } /** * Disable the key. * * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided */ async disable(mfaReceipt?: MfaReceipts) { await this.update({ enabled: false }, mfaReceipt); } /** * List roles this key is in. * * @param page Optional pagination options; by default, retrieves all roles this key is in. * @returns Roles this key is in. */ async roles(page?: PageOpts): Promise { return await this.#apiClient.keyRolesList(this.id, page).fetch(); } /** * List historical transactions for this key. * * @param page Optional pagination options; by default, retrieves all historical transactions for this key. * @returns Historical key transactions. */ async history(page?: PageOpts): Promise { return await this.#apiClient.keyHistory(this.id, page).fetch(); } /** * Set new policy (overwriting any policies previously set for this key) * * @param policy The new policy to set * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided */ async setPolicy(policy: KeyPolicy, mfaReceipt?: MfaReceipts) { await this.update({ policy }, mfaReceipt); } /** * Set new ACL (overwriting any existing ACL previously set for this key) * * @param acl The new ACL to set, or `null` to clear the ACL. * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided */ async setAcl(acl: KeyAcl | null, mfaReceipt?: MfaReceipts) { await this.update({ acl }, mfaReceipt); } /** * Set new edit policy (overwriting any edit policies previously set for this key) * * @param editPolicy The new edit policy to set * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided */ async setEditPolicy(editPolicy: EditPolicy, mfaReceipt?: MfaReceipts) { await this.update({ edit_policy: editPolicy }, mfaReceipt); } /** * Set key metadata. The metadata must be at most 1024 characters * and must match the following regex: ^[A-Za-z0-9_=+/ \-\.\,]{0,1024}$. * * @param metadata The new metadata to set. * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided * @returns The updated key info */ async setMetadata(metadata: JsonValue, mfaReceipt?: MfaReceipts): Promise { return await this.update({ metadata }, mfaReceipt); } /** * Set key properties. Each field in the provided patch is independent: missing * means leave alone, `null` clears, a value sets. Sending `null` for the whole * field clears all properties on the key. * * @param patch Type-specific properties * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided * @returns The updated key info */ async setProperties( patch: KeyPropertiesPatch | null, mfaReceipt?: MfaReceipts, ): Promise { return await this.update({ properties: patch }, mfaReceipt); } /** * Retrieves the existing metadata, asserts that it is an object (throws if it is not), * then sets the value of the {@link name} property in that object to {@link value}, * and finally submits the request to update the metadata. * * This whole process is done atomically, meaning, that if the metadata changes between the * time this method first retrieves it and the time it submits a request to update it, the * request will be rejected. When that happens, this method will retry a few times, as per * {@link ApiClient.config}. * * @param name The name of the property to set * @param value The new value of the property * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided * @returns Updated key information */ async setMetadataProperty( name: string, value: JsonValue, mfaReceipt?: MfaReceipts, ): Promise { return await this.#setMetadataProperty( name, value, this.#apiClient.config.updateRetryDelaysMs, mfaReceipt, ); } /** * Retrieves the existing metadata, asserts that it is in object (throws if it is not), * then deletes the {@link name} property in that object, and finally submits the * request to update the metadata. * * This whole process is done atomically, meaning, that if the metadata changes between the * time this method first retrieves it and the time it submits a request to update it, the * request will be rejected. When that happens, this method will retry a few times, as per * {@link ApiClient.config}. * * @param name The name of the property to set * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided * @returns Updated key information */ async deleteMetadataProperty(name: string, mfaReceipt?: MfaReceipts): Promise { return await this.#setMetadataProperty( name, undefined, this.#apiClient.config.updateRetryDelaysMs, mfaReceipt, ); } /** * @param name The name of the property to set * @param value The new value of the property * @param delaysMs Delays in milliseconds between retries * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided * @returns Updated key information * @internal */ async #setMetadataProperty( name: string, value: JsonValue | undefined, delaysMs: number[], mfaReceipt?: MfaReceipts, ): Promise { const data = await this.fetch(); const current = data.metadata ?? {}; if (typeof current !== "object") { throw new Error("Current metadata is not a JSON object"); } const updated = { ...current, [name]: value, }; try { return await this.update( { metadata: updated, version: data.version, }, mfaReceipt, ); } catch (e) { if ((e as ErrResponse).errorCode === "InvalidUpdate" && delaysMs.length > 0) { await delay(delaysMs[0]); return await this.#setMetadataProperty(name, value, delaysMs.slice(1)); } else { throw e; } } } /** * Append to existing key policy. This append is not atomic -- it uses {@link policy} * to fetch the current policy and then {@link setPolicy} to set the policy -- and * should not be used across concurrent sessions. * * @param policy The policy to append to the existing one. * @param mfaReceipt Optional MFA receipt(s) * @throws If MFA is required and no MFA receipts are provided */ async appendPolicy(policy: KeyPolicy, mfaReceipt?: MfaReceipts) { const existing = await this.policy(); await this.setPolicy([...existing, ...policy], mfaReceipt); } /** * Get the policy for the key. * * @returns The policy for the key. */ async policy(): Promise { const data = await this.fetch(); return (data.policy ?? []) as unknown as KeyPolicy; } /** * Append to existing key ACL. This append is not atomic -- it uses {@link acl} * to fetch the current ACL and then {@link setAcl} to set the ACL -- and * should not be used across concurrent sessions. * * @param acl The ACL to append to the existing one. * @param mfaReceipt Optional MFA receipt(s) * @throws If MFA is required and no MFA receipts are provided */ async appendAcl(acl: KeyAcl, mfaReceipt?: MfaReceipts) { const existing = await this.acl(); const newAcl: KeyAcl = [...(existing ?? []), ...acl]; await this.update({ acl: newAcl, version: this.cached.version }, mfaReceipt); } /** * Get the key ACL. * * @returns The key ACL, or `undefined` if it is not set. */ async acl(): Promise { const data = await this.fetch(); return data.acl as unknown as KeyAcl | undefined; } /** * Get the edit policy for the key. * * @returns The edit policy for the key, undefined if there is no edit policy */ async editPolicy(): Promise { const data = await this.fetch(); return data.edit_policy; } /** * Fetch the metadata for the key. * * @returns The policy for the key. */ async metadata(): Promise { const data = await this.fetch(); return data.metadata as JsonValue; } /** * @returns The user id for the owner of the key * @example User#c3b9379c-4e8c-4216-bd0a-65ace53cf98f */ async owner(): Promise { const data = await this.fetch(); return data.owner; } /** * Set the owner of the key. Only the key (or org) owner can change the owner of the key. * * @param owner The user-id of the new owner of the key. * @param mfaReceipt Optional MFA receipt(s) * @throws if MFA is required and no receipts are provided */ async setOwner(owner: string, mfaReceipt?: MfaReceipts) { await this.update({ owner }, mfaReceipt); } /** * Delete this key. * * @param mfaReceipt Optional MFA receipt(s) * @returns A response which can be used to approve MFA if needed */ async delete(mfaReceipt?: MfaReceipts): Promise> { return await this.#apiClient.keyDelete(this.id, mfaReceipt); } // -------------------------------------------------------------------------- // -- INTERNAL -------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Create a new key. * * @param client The API client to use. * @param data The JSON response from the API server. * @internal */ constructor(client: ApiClient | CubeSignerClient, data: KeyInfo) { this.#apiClient = client instanceof CubeSignerClient ? client.apiClient : client; this.id = data.key_id; this.materialId = data.material_id; this.publicKey = data.public_key; this.cached = data; } /** * Sign an EVM transaction. * * @param req What to sign. * @param mfaReceipt Optional MFA receipt(s). * @returns Signature (or MFA approval request). */ async signEvm( req: EvmSignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signEvm(this, req, mfaReceipt); } /** * Sign a Babylon staking transaction. * * @param req The staking transaction to sign * @param mfaReceipt Optional MFA receipt(s). * @returns Signature (or MFA approval request). */ async signBabylonStakingTxn( req: BabylonStakingRequest, mfaReceipt?: MfaReceipts, ): Promise> { return this.#apiClient.signBabylonStakingTxn(this, req, mfaReceipt); } /** * Sign a Babylon registration. * * @param req The registration request to sign * @param mfaReceipt Optional MFA receipt(s). * @returns Babylon staking registration data (or MFA approval request). */ async signBabylonRegistration( req: BabylonRegistrationRequest, mfaReceipt?: MfaReceipts, ): Promise> { return this.#apiClient.signBabylonRegistration(this, req, mfaReceipt); } /** * Sign EIP-191 typed data. * * This requires the key to have a '"AllowEip191Signing"' {@link KeyPolicy}. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns Signature (or MFA approval request). */ async signEip191( req: Eip191SignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signEip191(this, req, mfaReceipt); } /** * Sign EIP-712 typed data. * * This requires the key to have a '"AllowEip712Signing"' {@link KeyPolicy}. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns Signature (or MFA approval request). */ async signEip712( req: Eip712SignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signEip712(this, req, mfaReceipt); } /** * Sign EIP-7702 authorization request. * * This requires the key to have a '"AllowEip7702Signing"' {@link KeyPolicy}. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns Signature (or MFA approval request). */ async signEip7702( req: Eip7702SignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signEip7702(this, req, mfaReceipt); } /** * Sign an Eth2/Beacon-chain validation message. * * @param req What to sign. * @param mfaReceipt Optional MFA receipt(s) * @returns Signature */ async signEth2( req: Eth2SignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signEth2(this, req, mfaReceipt); } /** * Sign an Eth2/Beacon-chain unstake/exit request. * * @param req The request to sign. * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async unstake( req: Eth2UnstakeRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signUnstake(this, req, mfaReceipt); } /** * Sign an Avalanche P- or X-chain message. * * @param tx Avalanche message (transaction) to sign * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async signAva(tx: AvaTx, mfaReceipt?: MfaReceipts): Promise> { return await this.#apiClient.signAva(this, tx, mfaReceipt); } /** * Sign a serialized Avalanche C-/X-/P-chain message. * * @param avaChain Avalanche chain * @param tx Hex encoded transaction * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async signSerializedAva( avaChain: AvaChain, tx: string, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signSerializedAva(this, avaChain, tx, mfaReceipt); } /** * Sign a raw blob. * * This requires the key to have a '"AllowRawBlobSigning"' {@link KeyPolicy}. This is because * signing arbitrary messages is, in general, dangerous (and you should instead * prefer typed end-points as used by, for example, {@link signEvm}). For Secp256k1 keys, * for example, you **must** call this function with a message that is 32 bytes long and * the output of a secure hash function. * * This function returns signatures serialized as; * * - ECDSA signatures are serialized as big-endian r and s plus recovery-id * byte v, which can in general take any of the values 0, 1, 2, or 3. * * - EdDSA signatures are serialized in the standard format. * * - BLS signatures are not supported on the blob-sign endpoint. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async signBlob( req: BlobSignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signBlob(this, req, mfaReceipt); } /** * Perform a Diffie-Hellman exchange with one or more public keys. * * This requires the key to have a '"AllowDiffieHellmanExchange"' {@link KeyPolicy}. * This is because performing arbitrary Diffie-Hellman exchanges using signing keys * is, in general, dangerous. You should only use this API if you are 100% sure that * you know what you're doing! * * @param points Up to 32 elliptic curve points with which to perform Diffie-Hellman exchanges. These points must be serialized in a key-type--specific format; see the CubeSigner documentation for more info. * @param publicKey The NIST P-256 public key with which the responses will be encrypted. This should be the `publicKey` property of a value returned by `userExportKeygen`. * @param mfaReceipt Optional MFA receipt(s). * @returns The response. On success, the result can be decrypted with `diffieHellmanDecrypt`. */ async diffieHellmanExchange( points: Uint8Array[], publicKey: CryptoKey, mfaReceipt?: MfaReceipts, ): Promise> { if (points.length > 32) { throw new Error("maximum 32 DH exchanges per request"); } // construct the request const subtle = await loadSubtleCrypto(); const req: DiffieHellmanRequest = { points: points.map((pt) => encodeToBase64(pt)), public_key: encodeToBase64(await subtle.exportKey("raw", publicKey)), }; // send return await this.#apiClient.diffieHellmanExchange(this, req, mfaReceipt); } /** * Sign a Bitcoin transaction. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async signBtc( req: BtcSignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signBtc(this, req, mfaReceipt); } /** * Sign a PSBT. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns The response */ async signPsbt( req: PsbtSignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signPsbt(this, req, mfaReceipt); } /** * Sign a Bitcoin message. * * @param req The message to sign * @param opts Options for this request * @param opts.p2sh If this is a segwit key and p2sh is true, sign as p2sh-p2wpkh instead of p2wpkh. Defaults to false if not specified. * @param opts.metadata Optional arbitrary JSON metadata * @param opts.mfaReceipt Optional MFA receipt(s) * @returns The response */ async signBtcMessage( req: Uint8Array | string, opts: { p2sh?: boolean; mfaReceipt?: MfaReceipts; metadata?: unknown }, ): Promise> { const request: BtcMessageSignRequest = { data: encodeToHex(req), is_p2sh: opts.p2sh ?? false, metadata: opts.metadata, }; return await this.#apiClient.signBtcMessage(this, request, opts.mfaReceipt); } /** * Sign a Solana message. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async signSolana( req: SolanaSignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signSolana(this, req, mfaReceipt); } /** * Sign a SUI transaction. * * @param req What to sign * @param mfaReceipt Optional MFA receipt(s) * @returns The response. */ async signSui( req: SuiSignRequest, mfaReceipt?: MfaReceipts, ): Promise> { return await this.#apiClient.signSui(this, req, mfaReceipt); } /** * Update the key. * * @param request The JSON request to send to the API server. * @param mfaReceipt Optional MFA receipt(s) * @returns The JSON response from the API server. * @throws if MFA is required and no MFA receipts are provided * @internal */ private async update(request: UpdateKeyRequest, mfaReceipt?: MfaReceipts): Promise { const resp = await this.#apiClient.keyUpdate(this.id, request, mfaReceipt); this.cached = resp.data(); return this.cached; } /** * Fetch the key information. * * @returns The key information. * @internal */ private async fetch(): Promise { this.cached = await this.#apiClient.keyGet(this.id); return this.cached; } } /** * Convert a schema key type to a key type. * * @param ty The schema key type. * @returns The key type. * @internal */ export function fromSchemaKeyType(ty: SchemaKeyType): KeyType { switch (ty) { case "SecpEthAddr": return Secp256k1.Evm; case "SecpCosmosAddr": return Secp256k1.Cosmos; case "SecpBtc": return Secp256k1.Btc; case "SecpBtcTest": return Secp256k1.BtcTest; case "SecpBtcLegacy": return Secp256k1.BtcLegacy; case "SecpBtcLegacyTest": return Secp256k1.BtcLegacyTest; case "SecpAvaAddr": return Secp256k1.Ava; case "SecpAvaTestAddr": return Secp256k1.AvaTest; case "BabylonEots": return Secp256k1.BabylonEots; case "BabylonCov": return Secp256k1.BabylonEots; case "TaprootBtc": return Secp256k1.Taproot; case "TaprootBtcTest": return Secp256k1.TaprootTest; case "SecpTronAddr": return Secp256k1.Tron; case "SecpDogeAddr": return Secp256k1.Doge; case "SecpDogeTestAddr": return Secp256k1.DogeTest; case "SecpKaspaAddr": return Secp256k1.Kaspa; case "SecpKaspaTestAddr": return Secp256k1.KaspaTest; case "SchnorrKaspaAddr": return Secp256k1.KaspaSchnorr; case "SchnorrKaspaTestAddr": return Secp256k1.KaspaTestSchnorr; case "BlsPub": return Bls.Eth2Deposited; case "BlsInactive": return Bls.Eth2Inactive; case "BlsAvaIcm": return Bls.AvaIcm; case "Ed25519SolanaAddr": return Ed25519.Solana; case "Ed25519SuiAddr": return Ed25519.Sui; case "Ed25519AptosAddr": return Ed25519.Aptos; case "Ed25519CantonAddr": return Ed25519.Canton; case "Ed25519CardanoAddrVk": return Ed25519.Cardano; case "Ed25519StellarAddr": return Ed25519.Stellar; case "Ed25519SubstrateAddr": return Ed25519.Substrate; case "Ed25519TendermintAddr": return Ed25519.Tendermint; case "Ed25519TonAddr": return Ed25519.Ton; case "Ed25519BinanceApi": return Ed25519.BinanceApi; case "Ed25519CoinbaseApi": return Ed25519.CoinbaseApi; case "Stark": return Stark; case "HmacSha256": return HmacSha256.Generic; case "HmacSha256Bybit": return HmacSha256.Bybit; case "Mnemonic": return Mnemonic; case "P256CosmosAddr": return P256.Cosmos; case "P256OntologyAddr": return P256.Ontology; case "P256Neo3Addr": return P256.Neo3; case "SecpLtc": return Secp256k1.Ltc; case "SecpLtcTest": return Secp256k1.LtcTest; case "SecpXrpAddr": return Secp256k1.Xrp; case "Ed25519XrpAddr": return Ed25519.Xrp; case "BabyJubjub": return BabyJubjub; // NOTE: if you are adding a new key type, update the `create ${keyType} key` test in key.test.ts } }