diff --git a/package.json b/package.json index baaa50f1801d..a1cb364fc492 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "postinstall": "patch-package && gulp fix-lockfile", "prepare": "husky install", "test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js", + "test:debug": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand", "test:update": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js -u", "spellcheck": "cspell lint --no-must-find-files" }, diff --git a/packages/backup-format/src/normalize/index.ts b/packages/backup-format/src/normalize/index.ts index 677e4ced8822..01242f699ee7 100644 --- a/packages/backup-format/src/normalize/index.ts +++ b/packages/backup-format/src/normalize/index.ts @@ -6,15 +6,15 @@ import { generateBackupVersion2, isBackupVersion2, normalizeBackupVersion2 } fro import type { NormalizedBackup } from './type' export * from './type' -function __normalizeBackup(data: unknown): NormalizedBackup.Data { +async function __normalizeBackup(data: unknown): Promise { if (isBackupVersion2(data)) return normalizeBackupVersion2(data) if (isBackupVersion1(data)) return normalizeBackupVersion1(data) if (isBackupVersion0(data)) return normalizeBackupVersion0(data) throw new TypeError(BackupErrors.UnknownFormat) } -export function normalizeBackup(data: unknown): NormalizedBackup.Data { - const normalized = __normalizeBackup(data) +export async function normalizeBackup(data: unknown): Promise { + const normalized = await __normalizeBackup(data) // fix invalid URL normalized.settings.grantedHostPermissions = normalized.settings.grantedHostPermissions.filter((url) => diff --git a/packages/backup-format/src/version-0/index.ts b/packages/backup-format/src/version-0/index.ts index fb50e2335871..24b66e529441 100644 --- a/packages/backup-format/src/version-0/index.ts +++ b/packages/backup-format/src/version-0/index.ts @@ -24,7 +24,7 @@ export function isBackupVersion0(obj: unknown): obj is BackupJSONFileVersion0 { return false } } -export function normalizeBackupVersion0(file: BackupJSONFileVersion0): NormalizedBackup.Data { +export async function normalizeBackupVersion0(file: BackupJSONFileVersion0): Promise { const backup = createEmptyNormalizedBackup() backup.meta.version = 0 backup.meta.maskVersion = Some('<=1.3.2') @@ -36,7 +36,7 @@ export function normalizeBackupVersion0(file: BackupJSONFileVersion0): Normalize if (!isEC_Public_JsonWebKey(publicKey)) return backup const persona: NormalizedBackup.PersonaBackup = { - identifier: ECKeyIdentifierFromJsonWebKey(publicKey), + identifier: await ECKeyIdentifierFromJsonWebKey(publicKey), publicKey, linkedProfiles: new Map(), localKey: isAESJsonWebKey(local) ? Some(local) : None, diff --git a/packages/backup-format/src/version-1/index.ts b/packages/backup-format/src/version-1/index.ts index c21a843b3bb4..4f001c0dc895 100644 --- a/packages/backup-format/src/version-1/index.ts +++ b/packages/backup-format/src/version-1/index.ts @@ -25,7 +25,7 @@ export function isBackupVersion1(obj: unknown): obj is BackupJSONFileVersion1 { return false } } -export function normalizeBackupVersion1(file: BackupJSONFileVersion1): NormalizedBackup.Data { +export async function normalizeBackupVersion1(file: BackupJSONFileVersion1): Promise { const backup = createEmptyNormalizedBackup() backup.meta.version = 1 @@ -49,7 +49,7 @@ export function normalizeBackupVersion1(file: BackupJSONFileVersion1): Normalize } if (isEC_Public_JsonWebKey(publicKey)) { - const personaID = ECKeyIdentifierFromJsonWebKey(publicKey) + const personaID = await ECKeyIdentifierFromJsonWebKey(publicKey) const persona: NormalizedBackup.PersonaBackup = backup.personas.get(personaID) || { identifier: personaID, nickname: None, diff --git a/packages/backup-format/src/version-2/index.ts b/packages/backup-format/src/version-2/index.ts index 752e64b71b89..7a9da8856975 100644 --- a/packages/backup-format/src/version-2/index.ts +++ b/packages/backup-format/src/version-2/index.ts @@ -25,7 +25,7 @@ export function isBackupVersion2(item: unknown): item is BackupJSONFileVersion2 return false } -export function normalizeBackupVersion2(item: BackupJSONFileVersion2): NormalizedBackup.Data { +export async function normalizeBackupVersion2(item: BackupJSONFileVersion2): Promise { const backup = createEmptyNormalizedBackup() backup.meta.version = 2 @@ -38,7 +38,7 @@ export function normalizeBackupVersion2(item: BackupJSONFileVersion2): Normalize for (const persona of personas) { const { publicKey } = persona if (!isEC_Public_JsonWebKey(publicKey)) continue - const identifier = ECKeyIdentifierFromJsonWebKey(publicKey) + const identifier = await ECKeyIdentifierFromJsonWebKey(publicKey) const normalizedPersona: NormalizedBackup.PersonaBackup = { identifier, linkedProfiles: new Map(), diff --git a/packages/encryption/src/payload_internal/version-37.encoder.ts b/packages/encryption/src/payload_internal/version-37.encoder.ts index f0a05180633e..f9e49786f050 100644 --- a/packages/encryption/src/payload_internal/version-37.encoder.ts +++ b/packages/encryption/src/payload_internal/version-37.encoder.ts @@ -14,7 +14,10 @@ const enum Index { data = 6, } export async function encode37(payload: PayloadWellFormed.Payload) { - const payload_arr: any[] = [0] + type KeyMaterials = Partial> + type AcceptableArray = Array> + + const payload_arr: AcceptableArray = [0] if (payload.author.some) { const { network, userId } = payload.author.val @@ -27,7 +30,7 @@ export async function encode37(payload: PayloadWellFormed.Payload) { const raw = await exportCryptoKeyToRaw(key) if (raw.ok) { if (algr === EC_KeyCurveEnum.secp256k1) - payload_arr[Index.authorPublicKey] = compressSecp256k1KeyRaw(raw.val) + payload_arr[Index.authorPublicKey] = await compressSecp256k1KeyRaw(raw.val) else payload_arr[Index.authorPublicKey] = raw.val } else { payload_arr[Index.authorPublicKey] = null @@ -36,13 +39,13 @@ export async function encode37(payload: PayloadWellFormed.Payload) { } if (payload.encryption.type === 'E2E') { const { ephemeralPublicKey, iv, ownersAESKeyEncrypted } = payload.encryption - const keyMaterials: any = {} - const subArr: any[] = [1, ownersAESKeyEncrypted, iv, keyMaterials] + const keyMaterials: Partial> = {} + const subArr: Array = [1, ownersAESKeyEncrypted, iv, keyMaterials] for (const [alg, key] of ephemeralPublicKey.entries()) { const k = await exportCryptoKeyToRaw(key) if (k.err) warn(key, k.err) else { - if (alg === EC_KeyCurveEnum.secp256k1) keyMaterials[alg] = compressSecp256k1KeyRaw(k.val) + if (alg === EC_KeyCurveEnum.secp256k1) keyMaterials[alg] = await compressSecp256k1KeyRaw(k.val) else keyMaterials[alg] = k.val } } diff --git a/packages/encryption/src/payload_internal/version-37.parser.ts b/packages/encryption/src/payload_internal/version-37.parser.ts index a00eb26fc6d0..ab58af790b62 100644 --- a/packages/encryption/src/payload_internal/version-37.parser.ts +++ b/packages/encryption/src/payload_internal/version-37.parser.ts @@ -95,7 +95,7 @@ function importAsymmetryKey(algr: unknown, key: unknown, name: string) { if (typeof algr === 'number') { if (algr in EC_KeyCurveEnum) { if (algr === EC_KeyCurveEnum.secp256k1) { - pubKey = decompressSecp256k1KeyRaw(pubKey) + pubKey = await decompressSecp256k1KeyRaw(pubKey) } const key = await importEC(pubKey, algr) if (key.err) return key diff --git a/packages/encryption/src/payload_internal/version-38.encoder.ts b/packages/encryption/src/payload_internal/version-38.encoder.ts index b58fe2bc478a..3a21cb69e690 100644 --- a/packages/encryption/src/payload_internal/version-38.encoder.ts +++ b/packages/encryption/src/payload_internal/version-38.encoder.ts @@ -77,7 +77,7 @@ function encodeSignature(sig: Option) { async function compressSecp256k1Key(key: CryptoKey) { const jwk = await exportCryptoKeyToJWK(key) if (jwk.err) return jwk.mapErr((e) => new CheckedError(CryptoException.InvalidCryptoKey, e)) - const arr = Result.wrap(() => compressSecp256k1Point(jwk.val.x!, jwk.val.y!)).mapErr( + const arr = (await Result.wrapAsync(() => compressSecp256k1Point(jwk.val.x!, jwk.val.y!))).mapErr( (e) => new CheckedError(CryptoException.InvalidCryptoKey, e), ) if (arr.err) return arr diff --git a/packages/encryption/src/payload_internal/version-38.parser.ts b/packages/encryption/src/payload_internal/version-38.parser.ts index ddf0a1e5a492..143774f0fc71 100644 --- a/packages/encryption/src/payload_internal/version-38.parser.ts +++ b/packages/encryption/src/payload_internal/version-38.parser.ts @@ -126,10 +126,10 @@ async function decodePublicSharedAESKey( } async function decodeECDHPublicKey(compressedPublic: string): Promise> { - const key = decodeUint8ArrayCrypto(compressedPublic).andThen((val) => - Result.wrap(() => decompressSecp256k1Point(val)).mapErr( - (e) => new CheckedError(CryptoException.InvalidCryptoKey, e), - ), + const key = await andThenAsync(decodeUint8ArrayCrypto(compressedPublic), async (val) => + ( + await Result.wrapAsync(() => decompressSecp256k1Point(val)) + ).mapErr((e) => new CheckedError(CryptoException.InvalidCryptoKey, e)), ) if (key.err) return key diff --git a/packages/encryption/tests/setup.ts b/packages/encryption/tests/setup.ts index 26c67f53e009..de7d5f3df8aa 100644 --- a/packages/encryption/tests/setup.ts +++ b/packages/encryption/tests/setup.ts @@ -1,6 +1,7 @@ import { test } from '@jest/globals' import { atob, btoa } from 'buffer' import { polyfill } from '@dimensiondev/secp256k1-webcrypto/node' +import '../../shared-base/node_modules/tiny-secp256k1' test('Setup env', () => {}) diff --git a/packages/mask/background/database/persona/helper.ts b/packages/mask/background/database/persona/helper.ts index d681968619ab..4ba446e7ac70 100644 --- a/packages/mask/background/database/persona/helper.ts +++ b/packages/mask/background/database/persona/helper.ts @@ -155,7 +155,7 @@ export async function createPersonaByJsonWebKey(options: { mnemonic?: PersonaRecord['mnemonic'] uninitialized?: boolean }): Promise { - const identifier = ECKeyIdentifierFromJsonWebKey(options.publicKey) + const identifier = await ECKeyIdentifierFromJsonWebKey(options.publicKey) const record: PersonaRecord = { createdAt: new Date(), updatedAt: new Date(), @@ -184,7 +184,7 @@ export async function createProfileWithPersona( mnemonic?: PersonaRecord['mnemonic'] }, ): Promise { - const ec_id = ECKeyIdentifierFromJsonWebKey(keys.publicKey) + const ec_id = await ECKeyIdentifierFromJsonWebKey(keys.publicKey) const rec: PersonaRecord = { createdAt: new Date(), updatedAt: new Date(), diff --git a/packages/mask/background/services/backup/restore.ts b/packages/mask/background/services/backup/restore.ts index 67e270e2c264..4471113809e9 100644 --- a/packages/mask/background/services/backup/restore.ts +++ b/packages/mask/background/services/backup/restore.ts @@ -34,7 +34,7 @@ export async function restoreUnconfirmedBackup({ id, action }: RestoreUnconfirme export async function addUnconfirmedBackup(raw: string): Promise> { return Result.wrapAsync(async () => { const backupObj: unknown = JSON.parse(raw) - const backup = normalizeBackup(backupObj) + const backup = await normalizeBackup(backupObj) const preview = getBackupPreviewInfo(backup) const id = uuid() unconfirmedBackup.set(id, backup) diff --git a/packages/mask/background/services/crypto/decryption.ts b/packages/mask/background/services/crypto/decryption.ts index 22d2640a2238..c3a1964f0dac 100644 --- a/packages/mask/background/services/crypto/decryption.ts +++ b/packages/mask/background/services/crypto/decryption.ts @@ -226,7 +226,7 @@ async function storeAuthorPublicKey( if (persona?.privateKey) return const key = (await crypto.subtle.exportKey('jwk', pub.key)) as EC_JsonWebKey - const otherPersona = await queryPersonaDB(ECKeyIdentifierFromJsonWebKey(key)) + const otherPersona = await queryPersonaDB(await ECKeyIdentifierFromJsonWebKey(key)) if (otherPersona?.privateKey) return return createProfileWithPersona( diff --git a/packages/mask/background/services/identity/persona/update.ts b/packages/mask/background/services/identity/persona/update.ts index 5bcaaf14ecdb..0f136c2662a6 100644 --- a/packages/mask/background/services/identity/persona/update.ts +++ b/packages/mask/background/services/identity/persona/update.ts @@ -71,7 +71,7 @@ export async function setupPersona(id: PersonaIdentifier) { export async function loginExistPersonaByPrivateKey(privateKeyString: string): Promise { const privateKey = decode(decodeArrayBuffer(privateKeyString)) if (!isEC_Private_JsonWebKey(privateKey)) throw new TypeError('Invalid private key') - const identifier = ECKeyIdentifierFromJsonWebKey(privateKey) + const identifier = await ECKeyIdentifierFromJsonWebKey(privateKey) const persona = await queryPersonaDB(identifier, undefined, true) if (persona) { @@ -86,7 +86,7 @@ export async function loginExistPersonaByPrivateKey(privateKeyString: string): P export async function mobile_queryPersonaByPrivateKey(privateKeyString: string): Promise { if (process.env.architecture !== 'app') throw new Error('This function is only available in app') const privateKey = decode(decodeArrayBuffer(privateKeyString)) as EC_JsonWebKey - const identifier = ECKeyIdentifierFromJsonWebKey(privateKey) + const identifier = await ECKeyIdentifierFromJsonWebKey(privateKey) const persona = await queryPersonaDB(identifier, undefined, true) if (persona) { @@ -112,7 +112,7 @@ export async function queryPersonaByMnemonic(mnemonic: string, password: ''): Pr } const { key } = await recover_ECDH_256k1_KeyPair_ByMnemonicWord(mnemonic, password) - const identifier = ECKeyIdentifierFromJsonWebKey(key.privateKey) + const identifier = await ECKeyIdentifierFromJsonWebKey(key.privateKey) const persona = await queryPersonaDB(identifier, undefined, true) if (persona) { await loginPersona(persona.identifier) diff --git a/packages/mask/background/services/identity/persona/utils.ts b/packages/mask/background/services/identity/persona/utils.ts index 2fde21125488..668c8e22440d 100644 --- a/packages/mask/background/services/identity/persona/utils.ts +++ b/packages/mask/background/services/identity/persona/utils.ts @@ -54,7 +54,7 @@ export async function generate_ECDH_256k1_KeyPair_ByMnemonicWord( const seed = await bip39.mnemonicToSeed(mnemonicWord, password) const masterKey = wallet.HDKey.parseMasterSeed(seed) const derivedKey = masterKey.derive(path) - const key = await split_ec_k256_keypair_into_pub_priv(HDKeyToJwk(derivedKey)) + const key = await split_ec_k256_keypair_into_pub_priv(await HDKeyToJwk(derivedKey)) return { key, password, @@ -76,7 +76,7 @@ export async function recover_ECDH_256k1_KeyPair_ByMnemonicWord( const seed = await bip39.mnemonicToSeed(mnemonicWord, password) const masterKey = wallet.HDKey.parseMasterSeed(seed) const derivedKey = masterKey.derive(path) - const key = await split_ec_k256_keypair_into_pub_priv(HDKeyToJwk(derivedKey)) + const key = await split_ec_k256_keypair_into_pub_priv(await HDKeyToJwk(derivedKey)) return { key, password, @@ -89,8 +89,8 @@ export async function recover_ECDH_256k1_KeyPair_ByMnemonicWord( export const validateMnemonic = bip39.validateMnemonic -function HDKeyToJwk(hdk: wallet.HDKey): JsonWebKey { - const jwk = decompressSecp256k1Key(encodeArrayBuffer(hdk.publicKey)) +async function HDKeyToJwk(hdk: wallet.HDKey): Promise { + const jwk = await decompressSecp256k1Key(encodeArrayBuffer(hdk.publicKey)) jwk.d = hdk.privateKey ? toBase64URL(hdk.privateKey) : undefined return jwk } diff --git a/packages/mask/src/extension/background-script/BackupService.ts b/packages/mask/src/extension/background-script/BackupService.ts index 70a94e6d558e..6c97ebfeb4a1 100644 --- a/packages/mask/src/extension/background-script/BackupService.ts +++ b/packages/mask/src/extension/background-script/BackupService.ts @@ -76,7 +76,7 @@ delegateWalletRestore(async function (backup) { const name = wallet.name if (wallet.privateKey.some) - await recoverWalletFromPrivateKey(name, JWKToKey(wallet.privateKey.val, 'private')) + await recoverWalletFromPrivateKey(name, await JWKToKey(wallet.privateKey.val, 'private')) else if (wallet.mnemonic.some) { // fix a backup bug of pre-v2.2.2 versions const accounts = await getDerivableAccounts(wallet.mnemonic.val.words, 1, 5) @@ -223,17 +223,17 @@ function keyToJWK(key: string, type: 'public' | 'private'): JsonWebKey { } } -function JWKToKey(jwk: EC_JsonWebKey, type: 'public' | 'private'): string { +async function JWKToKey(jwk: EC_JsonWebKey, type: 'public' | 'private'): Promise { const ec = new EC('secp256k1') if (type === 'public' && jwk.x && jwk.y) { const xb = fromBase64URL(jwk.x) const yb = fromBase64URL(jwk.y) const point = new Uint8Array(concatArrayBuffer(new Uint8Array([0x04]), xb, yb)) - if (isSecp256k1Point(point)) return `0x${ec.keyFromPublic(point).getPublic(false, 'hex')}` + if (await isSecp256k1Point(point)) return `0x${ec.keyFromPublic(point).getPublic(false, 'hex')}` } if (type === 'private' && jwk.d) { const db = fromBase64URL(jwk.d) - if (isSecp256k1PrivateKey(db)) return `0x${ec.keyFromPrivate(db).getPrivate('hex')}` + if (await isSecp256k1PrivateKey(db)) return `0x${ec.keyFromPrivate(db).getPrivate('hex')}` } throw new Error('invalid private key') } diff --git a/packages/shared-base/src/crypto/secp256k1.ts b/packages/shared-base/src/crypto/secp256k1.ts index 26b45a6b2bdc..e7dbcc2193bf 100644 --- a/packages/shared-base/src/crypto/secp256k1.ts +++ b/packages/shared-base/src/crypto/secp256k1.ts @@ -2,37 +2,31 @@ import { encodeArrayBuffer, decodeArrayBuffer, concatArrayBuffer } from '@dimens import type { EC_JsonWebKey, EC_Public_JsonWebKey } from './JWKType' import { fromBase64URL, toBase64URL } from '../convert' import { ECKeyIdentifier } from '../Identifier' -import type { EC_CryptoKey } from '.' // This module is only used in background. // Loading tiny-secp256k1 will instantiate a WebAssembly module which is not allowed in the content script for unknown reason and fail the whole module graph. -// TODO: switch to holoflows-kit -let secp256k1!: typeof import('tiny-secp256k1') -const isContentScript = (() => { - try { - if (location.protocol.startsWith('http')) return true - } catch {} - return false -})() -if (!isContentScript) { +async function loadLib(): Promise { if (process.env.architecture === 'app') { // Note: mobile (Android and iOS does not return a correct MINE type, therefore we can not use streaming to initialize the WASM module). WebAssembly.instantiateStreaming = undefined! WebAssembly.compileStreaming = undefined! } - import('tiny-secp256k1').then((mod) => (secp256k1 = mod)) + // You should not load this module in the content script. If you find you're stuck here, please check your code why it is loading this lib. + const mod = await import('tiny-secp256k1') + return mod } /** * Compress x & y into a single x */ -export function compressSecp256k1Point(x: string, y: string): Uint8Array { +export async function compressSecp256k1Point(x: string, y: string): Promise { + const { isPoint, pointCompress } = await loadLib() const xb = fromBase64URL(x) const yb = fromBase64URL(y) const point = new Uint8Array(concatArrayBuffer(new Uint8Array([0x04]), xb, yb)) - if (secp256k1.isPoint(point)) { - return secp256k1.pointCompress(point, true) + if (isPoint(point)) { + return pointCompress(point, true) } else { throw new TypeError('Not a point on secp256k1!') } @@ -40,33 +34,36 @@ export function compressSecp256k1Point(x: string, y: string): Uint8Array { /** * Decompress x into x & y */ -export function decompressSecp256k1Point(point: Uint8Array): { x: string; y: string } { - if (!secp256k1.isPoint(point)) throw new TypeError('Not a point on secp256k1!') - const uncompressed = secp256k1.isPointCompressed(point) ? secp256k1.pointCompress(point, false) : point +export async function decompressSecp256k1Point(point: Uint8Array): Promise<{ x: string; y: string }> { + const { isPoint, isPointCompressed, pointCompress } = await loadLib() + if (!isPoint(point)) throw new TypeError('Not a point on secp256k1!') + const uncompressed = isPointCompressed(point) ? pointCompress(point, false) : point const len = (uncompressed.length - 1) / 2 const x = uncompressed.slice(1, len + 1) const y = uncompressed.slice(len + 1) return { x: toBase64URL(x), y: toBase64URL(y) } } -export function compressSecp256k1KeyRaw(point: Uint8Array) { - if (!secp256k1.isPoint(point)) throw new TypeError('Not a point on secp256k1!') - if (secp256k1.isPointCompressed(point)) return point - return secp256k1.pointCompress(point, true) +export async function compressSecp256k1KeyRaw(point: Uint8Array) { + const { isPoint, isPointCompressed, pointCompress } = await loadLib() + if (!isPoint(point)) throw new TypeError('Not a point on secp256k1!') + if (isPointCompressed(point)) return point + return pointCompress(point, true) } -export function decompressSecp256k1KeyRaw(point: Uint8Array) { - if (!secp256k1.isPoint(point)) throw new TypeError('Not a point on secp256k1!') - if (!secp256k1.isPointCompressed(point)) return point - return secp256k1.pointCompress(point, false) +export async function decompressSecp256k1KeyRaw(point: Uint8Array) { + const { isPoint, isPointCompressed, pointCompress } = await loadLib() + if (!isPoint(point)) throw new TypeError('Not a point on secp256k1!') + if (!isPointCompressed(point)) return point + return pointCompress(point, false) } -export function compressSecp256k1Key(key: EC_JsonWebKey): string { - const arr = compressSecp256k1Point(key.x!, key.y!) +async function compressSecp256k1Key(key: EC_JsonWebKey): Promise { + const arr = await compressSecp256k1Point(key.x!, key.y!) return encodeArrayBuffer(arr) } -export function decompressSecp256k1Key(compressedPublic: string): EC_Public_JsonWebKey { +export async function decompressSecp256k1Key(compressedPublic: string): Promise { const arr = decodeArrayBuffer(compressedPublic) - const key = decompressSecp256k1Point(new Uint8Array(arr)) + const key = await decompressSecp256k1Point(new Uint8Array(arr)) const jwk: JsonWebKey = { crv: 'K-256', ext: true, @@ -78,20 +75,17 @@ export function decompressSecp256k1Key(compressedPublic: string): EC_Public_Json return jwk as EC_Public_JsonWebKey } -export function isSecp256k1Point(x: Uint8Array) { - return secp256k1.isPoint(x) +export async function isSecp256k1Point(x: Uint8Array) { + const { isPoint } = await loadLib() + return isPoint(x) } -export function isSecp256k1PrivateKey(d: Uint8Array) { - return secp256k1.isPrivate(d) +export async function isSecp256k1PrivateKey(d: Uint8Array) { + const { isPrivate } = await loadLib() + return isPrivate(d) } -export function ECKeyIdentifierFromJsonWebKey(key: EC_JsonWebKey) { - const x = compressSecp256k1Key(key) +export async function ECKeyIdentifierFromJsonWebKey(key: EC_JsonWebKey) { + const x = await compressSecp256k1Key(key) return new ECKeyIdentifier('secp256k1', x) } - -export async function ECKeyIdentifierFromCryptoKey(key: EC_CryptoKey) { - const k = (await crypto.subtle.exportKey('jwk', key)) as EC_JsonWebKey - return ECKeyIdentifierFromJsonWebKey(k) -}