diff --git a/.changeset/keystores-drop-ethereumjs-wallet.md b/.changeset/keystores-drop-ethereumjs-wallet.md new file mode 100644 index 0000000000..3423238556 --- /dev/null +++ b/.changeset/keystores-drop-ethereumjs-wallet.md @@ -0,0 +1,17 @@ +--- +'@celo/keystores': patch +--- + +Replace the deprecated `ethereumjs-wallet` dependency with an in-package V3 +keystore implementation built on `@noble/hashes` and `@noble/ciphers`. + +`ethereumjs-wallet` pulled in the unmaintained browserify crypto stack +(`ethereum-cryptography@0.1.3`, `pbkdf2`, `sha.js`, `cipher-base`, `secp256k1@4`, +`elliptic`), which carried several critical advisories — among them `pbkdf2` +silently returning static keys for `Uint8Array` input, and hash-rewind flaws in +`sha.js` and `cipher-base`. Those packages are no longer in the dependency tree. + +The keystore format is unchanged: encryption still uses geth's defaults (scrypt +n=262144, r=8, p=1, AES-128-CTR, keccak256 MAC), and geth-generated keystores +still decrypt. Decryption now accepts only the `aes-128-ctr` cipher rather than +passing the file's `cipher` field to an arbitrary cipher constructor. diff --git a/packages/sdk/keystores/package.json b/packages/sdk/keystores/package.json index 04ceefe34e..184e32dea4 100644 --- a/packages/sdk/keystores/package.json +++ b/packages/sdk/keystores/package.json @@ -27,7 +27,8 @@ "dependencies": { "@celo/utils": "^8.0.3", "@celo/wallet-local": "^8.0.1", - "ethereumjs-wallet": "^1.0.1", + "@noble/ciphers": "1.1.3", + "@noble/hashes": "1.3.3", "rimraf": "^4.4.1" }, "devDependencies": { diff --git a/packages/sdk/keystores/src/keystore-base.ts b/packages/sdk/keystores/src/keystore-base.ts index 358cf6056a..a232114079 100644 --- a/packages/sdk/keystores/src/keystore-base.ts +++ b/packages/sdk/keystores/src/keystore-base.ts @@ -3,7 +3,7 @@ import { normalizeAddressWith0x, privateKeyToAddress, } from '@celo/utils/lib/address' -import Wallet from 'ethereumjs-wallet' +import { decryptV3, encryptV3, v3Filename } from './v3-keystore' export enum ErrorMessages { KEYSTORE_ENTRY_EXISTS = 'Existing encrypted keystore for address', @@ -90,12 +90,10 @@ export abstract class KeystoreBase { throw new Error(ErrorMessages.KEYSTORE_ENTRY_EXISTS) } - const key = Buffer.from(privateKey, 'hex') - const wallet = Wallet.fromPrivateKey(key) - const keystore = await wallet.toV3String(passphrase) - const keystoreName = wallet.getV3Filename(Date.now()) + const keystore = await encryptV3(privateKey, passphrase) + const keystoreName = v3Filename(address, Date.now()) - this.persistKeystore(keystoreName, keystore) + this.persistKeystore(keystoreName, JSON.stringify(keystore)) } /** @@ -120,7 +118,7 @@ export abstract class KeystoreBase { async getPrivateKey(address: string, passphrase: string): Promise { const rawKeystore = this.getRawKeystore(await this.getKeystoreName(address)) // TODO do we want to trim leading 0x here? what is the best practice here? - return (await Wallet.fromV3(rawKeystore, passphrase)).getPrivateKeyString() + return decryptV3(rawKeystore, passphrase) } /** @@ -132,10 +130,9 @@ export abstract class KeystoreBase { async changeKeystorePassphrase(address: string, oldPassphrase: string, newPassphrase: string) { const keystoreName = await this.getKeystoreName(address) const rawKeystore = this.getRawKeystore(keystoreName) - const newKeystore = await (await Wallet.fromV3(rawKeystore, oldPassphrase)).toV3String( - newPassphrase - ) - this.persistKeystore(keystoreName, newKeystore) + const privateKey = await decryptV3(rawKeystore, oldPassphrase) + const newKeystore = await encryptV3(privateKey, newPassphrase) + this.persistKeystore(keystoreName, JSON.stringify(newKeystore)) } /** diff --git a/packages/sdk/keystores/src/test-constants.ts b/packages/sdk/keystores/src/test-constants.ts index 677769d575..df86288155 100644 --- a/packages/sdk/keystores/src/test-constants.ts +++ b/packages/sdk/keystores/src/test-constants.ts @@ -11,3 +11,9 @@ export const PK2 = 'bb6f3fa4a83b7b06e72e580a3b09df5dd6fb4fa745ee2b0d865413ad6299 export const KEYSTORE_NAME2 = 'PK2 keystore name' export const GETH_GEN_KEYSTORE2 = `{"address":"b81a82696018fd9d8b43431966b60c31bdcdc2e8","blspublickey":"b9f862e2ced58bb2eef8ffde7020189ab2bb050603630eceec9b80c1636d98f8c3b9bd517d673937a0551c3a0698a00086bda4db1f0d859912a91988775ae388886013e7eb254d195871f9ced6643e288755da0b483ebe6dda448fea2eb75481","crypto":{"cipher":"aes-128-ctr","ciphertext":"6f3cd02b2d3d81b2bbf76743396c9c3c1685ddc6cfafbba34195ab03476831d3","cipherparams":{"iv":"af1f9853e0ff20ee5d495cf7d9461e1c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"cf0446914e5d214f2a312c08ef24e7e3dd15e948d2ca67d59b3bb97903a96147"},"mac":"58348f6d843d28b3ac8cf40542d10da198016f28f132c32389ab56a945c858e1"},"id":"b224dac6-c089-4b47-8557-e04ae60b3506","version":3}` export const ADDRESS2 = normalizeAddressWith0x(privateKeyToAddress(PK2)) + +// The pbkdf2 test vector from the Web3 Secret Storage Definition. Keystores in +// the wild almost always use scrypt, so this pins the pbkdf2 derivation path. +export const PBKDF2_PASSPHRASE = 'testpassword' +export const PBKDF2_PK = '7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d' +export const PBKDF2_KEYSTORE = `{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"6087dab2f9fdbbfaddc31a909735c1e6"},"ciphertext":"5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46","kdf":"pbkdf2","kdfparams":{"c":262144,"dklen":32,"prf":"hmac-sha256","salt":"ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"},"mac":"517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2"},"id":"3198bc9c-6672-5ab3-d995-4942343ae5b6","version":3}` diff --git a/packages/sdk/keystores/src/v3-keystore.test.ts b/packages/sdk/keystores/src/v3-keystore.test.ts new file mode 100644 index 0000000000..7d6804728e --- /dev/null +++ b/packages/sdk/keystores/src/v3-keystore.test.ts @@ -0,0 +1,130 @@ +import { trimLeading0x } from '@celo/utils/lib/address' +import { + ADDRESS1, + GETH_GEN_KEYSTORE1, + GETH_GEN_KEYSTORE2, + PASSPHRASE1, + PASSPHRASE2, + PBKDF2_KEYSTORE, + PBKDF2_PASSPHRASE, + PBKDF2_PK, + PK1, + PK2, +} from './test-constants' +import { decryptV3, encryptV3, V3ErrorMessages, v3Filename } from './v3-keystore' + +jest.setTimeout(30000) + +describe('decryptV3', () => { + it('decrypts a geth-generated keystore', async () => { + expect(trimLeading0x(await decryptV3(GETH_GEN_KEYSTORE1, PASSPHRASE1))).toBe(PK1) + expect(trimLeading0x(await decryptV3(GETH_GEN_KEYSTORE2, PASSPHRASE2))).toBe(PK2) + }) + + it('returns the private key 0x-prefixed', async () => { + expect(await decryptV3(GETH_GEN_KEYSTORE1, PASSPHRASE1)).toBe(`0x${PK1}`) + }) + + it('decrypts a pbkdf2 keystore', async () => { + expect(trimLeading0x(await decryptV3(PBKDF2_KEYSTORE, PBKDF2_PASSPHRASE))).toBe(PBKDF2_PK) + }) + + it('rejects a wrong passphrase for a pbkdf2 keystore', async () => { + await expect(decryptV3(PBKDF2_KEYSTORE, `${PBKDF2_PASSPHRASE}!`)).rejects.toThrow( + V3ErrorMessages.WRONG_PASSPHRASE + ) + }) + + it('rejects a wrong passphrase', async () => { + await expect(decryptV3(GETH_GEN_KEYSTORE1, `${PASSPHRASE1}!`)).rejects.toThrow( + V3ErrorMessages.WRONG_PASSPHRASE + ) + }) + + it('rejects a non-V3 keystore', async () => { + const v1 = JSON.stringify({ ...JSON.parse(GETH_GEN_KEYSTORE1), version: 1 }) + await expect(decryptV3(v1, PASSPHRASE1)).rejects.toThrow(V3ErrorMessages.NOT_V3) + }) + + it('rejects an unsupported cipher', async () => { + const parsed = JSON.parse(GETH_GEN_KEYSTORE1) + parsed.crypto.cipher = 'aes-128-cbc' + await expect(decryptV3(JSON.stringify(parsed), PASSPHRASE1)).rejects.toThrow( + V3ErrorMessages.UNSUPPORTED_CIPHER + ) + }) + + it('rejects an unsupported key derivation scheme', async () => { + const parsed = JSON.parse(GETH_GEN_KEYSTORE1) + parsed.crypto.kdf = 'bcrypt' + await expect(decryptV3(JSON.stringify(parsed), PASSPHRASE1)).rejects.toThrow( + V3ErrorMessages.UNSUPPORTED_KDF + ) + }) + + it('rejects pbkdf2 with a pseudorandom function other than hmac-sha256', async () => { + const parsed = JSON.parse(GETH_GEN_KEYSTORE1) + parsed.crypto.kdf = 'pbkdf2' + parsed.crypto.kdfparams = { dklen: 32, salt: '00'.repeat(32), c: 1, prf: 'hmac-sha512' } + await expect(decryptV3(JSON.stringify(parsed), PASSPHRASE1)).rejects.toThrow( + V3ErrorMessages.UNSUPPORTED_PBKDF2_PARAMS + ) + }) + + it('detects a tampered ciphertext via the mac', async () => { + const parsed = JSON.parse(GETH_GEN_KEYSTORE1) + parsed.crypto.ciphertext = `${parsed.crypto.ciphertext.slice(0, -2)}00` + await expect(decryptV3(JSON.stringify(parsed), PASSPHRASE1)).rejects.toThrow( + V3ErrorMessages.WRONG_PASSPHRASE + ) + }) +}) + +describe('encryptV3', () => { + it('round-trips a private key', async () => { + const keystore = await encryptV3(PK1, PASSPHRASE1) + expect(trimLeading0x(await decryptV3(JSON.stringify(keystore), PASSPHRASE1))).toBe(PK1) + }) + + it('round-trips a 0x-prefixed private key', async () => { + const keystore = await encryptV3(`0x${PK1}`, PASSPHRASE1) + expect(trimLeading0x(await decryptV3(JSON.stringify(keystore), PASSPHRASE1))).toBe(PK1) + }) + + it('writes geth-compatible parameters', async () => { + const { version, crypto } = await encryptV3(PK1, PASSPHRASE1) + expect(version).toBe(3) + expect(crypto.cipher).toBe('aes-128-ctr') + expect(crypto.kdf).toBe('scrypt') + expect(crypto.kdfparams).toMatchObject({ dklen: 32, n: 262144, r: 8, p: 1 }) + expect(crypto.cipherparams.iv).toHaveLength(32) + expect(crypto.kdfparams.salt).toHaveLength(64) + expect(crypto.mac).toHaveLength(64) + }) + + it('stores the address unprefixed and lowercased', async () => { + const { address } = await encryptV3(PK1, PASSPHRASE1) + expect(address).toBe(trimLeading0x(ADDRESS1).toLowerCase()) + }) + + it('uses a fresh salt and iv for each keystore', async () => { + const [a, b] = await Promise.all([encryptV3(PK1, PASSPHRASE1), encryptV3(PK1, PASSPHRASE1)]) + expect(a.crypto.kdfparams.salt).not.toBe(b.crypto.kdfparams.salt) + expect(a.crypto.cipherparams.iv).not.toBe(b.crypto.cipherparams.iv) + expect(a.crypto.ciphertext).not.toBe(b.crypto.ciphertext) + expect(a.id).not.toBe(b.id) + }) +}) + +describe('v3Filename', () => { + it('builds the geth filename convention', () => { + expect(v3Filename(ADDRESS1, Date.parse('2016-03-15T17:11:33.007Z'))).toBe( + `UTC--2016-03-15T17-11-33.007Z--${trimLeading0x(ADDRESS1).toLowerCase()}` + ) + }) + + it('accepts an address with or without a 0x prefix', () => { + const timestamp = Date.parse('2016-03-15T17:11:33.007Z') + expect(v3Filename(ADDRESS1, timestamp)).toBe(v3Filename(trimLeading0x(ADDRESS1), timestamp)) + }) +}) diff --git a/packages/sdk/keystores/src/v3-keystore.ts b/packages/sdk/keystores/src/v3-keystore.ts new file mode 100644 index 0000000000..3493d3b751 --- /dev/null +++ b/packages/sdk/keystores/src/v3-keystore.ts @@ -0,0 +1,176 @@ +/** + * Encryption and decryption of Web3 Secret Storage V3 keystores. + * See https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition + * + * Parameter defaults and error messages match those of geth-generated keystores. + */ + +import { randomUUID } from 'node:crypto' +import { + ensureLeading0x, + hexToBuffer, + privateKeyToAddress, + trimLeading0x, +} from '@celo/utils/lib/address' +import { ctr } from '@noble/ciphers/aes' +import { pbkdf2Async } from '@noble/hashes/pbkdf2' +import { scryptAsync } from '@noble/hashes/scrypt' +import { keccak_256 } from '@noble/hashes/sha3' +import { sha256 } from '@noble/hashes/sha256' +import { randomBytes } from '@noble/hashes/utils' + +/** The only cipher used by geth and by the wider V3 ecosystem. */ +const CIPHER = 'aes-128-ctr' +const SCRYPT_N = 262144 +const SCRYPT_R = 8 +const SCRYPT_P = 1 +const DERIVED_KEY_LENGTH = 32 +const SALT_LENGTH = 32 +const IV_LENGTH = 16 + +export enum V3ErrorMessages { + NOT_V3 = 'Not a V3 wallet', + UNSUPPORTED_CIPHER = 'Unsupported cipher', + UNSUPPORTED_KDF = 'Unsupported key derivation scheme', + UNSUPPORTED_PBKDF2_PARAMS = 'Unsupported parameters to PBKDF2', + WRONG_PASSPHRASE = 'Key derivation failed - possibly wrong passphrase', +} + +interface ScryptParams { + dklen: number + salt: string + n: number + r: number + p: number +} + +interface Pbkdf2Params { + dklen: number + salt: string + c: number + prf: string +} + +export interface V3Keystore { + version: number + id: string + address: string + crypto: { + ciphertext: string + cipherparams: { iv: string } + cipher: string + kdf: string + kdfparams: ScryptParams | Pbkdf2Params + mac: string + } +} + +/** + * Derives the symmetric key that protects a keystore's ciphertext. + * The first half encrypts the private key, the second half authenticates it. + */ +async function deriveKey( + kdf: string, + kdfparams: ScryptParams | Pbkdf2Params, + passphrase: string +): Promise { + const password = Buffer.from(passphrase, 'utf8') + const salt = hexToBuffer(kdfparams.salt) + + if (kdf === 'scrypt') { + const { n, r, p } = kdfparams as ScryptParams + return scryptAsync(password, salt, { N: n, r, p, dkLen: kdfparams.dklen }) + } + if (kdf === 'pbkdf2') { + const { c, prf } = kdfparams as Pbkdf2Params + if (prf !== 'hmac-sha256') { + throw new Error(V3ErrorMessages.UNSUPPORTED_PBKDF2_PARAMS) + } + return pbkdf2Async(sha256, password, salt, { c, dkLen: kdfparams.dklen }) + } + throw new Error(V3ErrorMessages.UNSUPPORTED_KDF) +} + +/** + * The V3 message authentication code, over the second half of the derived key + * and the ciphertext. + */ +function macOf(derivedKey: Uint8Array, ciphertext: Uint8Array): string { + return Buffer.from( + keccak_256(Buffer.concat([Buffer.from(derivedKey.subarray(16, 32)), Buffer.from(ciphertext)])) + ).toString('hex') +} + +/** + * Decrypts a V3 keystore + * @param keystore Serialized V3 keystore + * @param passphrase Secret phrase the private key was encrypted with + * @returns Private key as a 0x-prefixed hex string + */ +export async function decryptV3(keystore: string, passphrase: string): Promise { + const json: V3Keystore = JSON.parse(keystore) + if (json.version !== 3) { + throw new Error(V3ErrorMessages.NOT_V3) + } + if (json.crypto.cipher !== CIPHER) { + throw new Error(`${V3ErrorMessages.UNSUPPORTED_CIPHER}: ${json.crypto.cipher}`) + } + + const derivedKey = await deriveKey(json.crypto.kdf, json.crypto.kdfparams, passphrase) + const ciphertext = hexToBuffer(json.crypto.ciphertext) + if (macOf(derivedKey, ciphertext) !== json.crypto.mac) { + throw new Error(V3ErrorMessages.WRONG_PASSPHRASE) + } + + const privateKey = ctr( + derivedKey.subarray(0, 16), + hexToBuffer(json.crypto.cipherparams.iv) + ).decrypt(ciphertext) + return ensureLeading0x(Buffer.from(privateKey).toString('hex')) +} + +/** + * Encrypts a private key into a V3 keystore, using geth's default parameters + * @param privateKey Private key to encrypt, with or without a 0x prefix + * @param passphrase Secret phrase to encrypt the private key with + */ +export async function encryptV3(privateKey: string, passphrase: string): Promise { + const salt = randomBytes(SALT_LENGTH) + const iv = randomBytes(IV_LENGTH) + const kdfparams: ScryptParams = { + dklen: DERIVED_KEY_LENGTH, + salt: Buffer.from(salt).toString('hex'), + n: SCRYPT_N, + r: SCRYPT_R, + p: SCRYPT_P, + } + + const derivedKey = await deriveKey('scrypt', kdfparams, passphrase) + const ciphertext = ctr(derivedKey.subarray(0, 16), iv).encrypt(hexToBuffer(privateKey)) + + return { + version: 3, + id: randomUUID(), + // The V3 spec omits the address, but geth and its ecosystem always write it. + address: trimLeading0x(privateKeyToAddress(privateKey)).toLowerCase(), + crypto: { + ciphertext: Buffer.from(ciphertext).toString('hex'), + cipherparams: { iv: Buffer.from(iv).toString('hex') }, + cipher: CIPHER, + kdf: 'scrypt', + kdfparams, + mac: macOf(derivedKey, ciphertext), + }, + } +} + +/** + * Builds the conventional geth filename for a V3 keystore entry, + * e.g. UTC--2016-03-15T17-11-33.007Z--
+ * @param address Account address of the keystore entry + * @param timestamp Creation time in milliseconds since the epoch + */ +export function v3Filename(address: string, timestamp: number): string { + const isoTime = new Date(timestamp).toJSON().replace(/:/g, '-') + return `UTC--${isoTime}--${trimLeading0x(address).toLowerCase()}` +} diff --git a/yarn.lock b/yarn.lock index 56f60be457..b81d6bbe5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2002,8 +2002,9 @@ __metadata: "@celo/typescript": "workspace:^" "@celo/utils": "npm:^8.0.3" "@celo/wallet-local": "npm:^8.0.1" + "@noble/ciphers": "npm:1.1.3" + "@noble/hashes": "npm:1.3.3" "@types/rimraf": "npm:3.0.2" - ethereumjs-wallet: "npm:^1.0.1" rimraf: "npm:^4.4.1" languageName: unknown linkType: soft @@ -6568,15 +6569,6 @@ __metadata: languageName: node linkType: hard -"@types/pbkdf2@npm:^3.0.0": - version: 3.1.0 - resolution: "@types/pbkdf2@npm:3.1.0" - dependencies: - "@types/node": "npm:*" - checksum: d15024b1957c21cf3b8887329d9bd8dfde754cf13a09d76ae25f1391cfc62bb8b8d7b760773c5dbaa748172fba8b3e0c3dbe962af6ccbd69b76df12a48dfba40 - languageName: node - linkType: hard - "@types/prompts@npm:^1.1.1": version: 1.2.0 resolution: "@types/prompts@npm:1.2.0" @@ -6620,7 +6612,7 @@ __metadata: languageName: node linkType: hard -"@types/secp256k1@npm:^4.0.0, @types/secp256k1@npm:^4.0.1": +"@types/secp256k1@npm:^4.0.0": version: 4.0.3 resolution: "@types/secp256k1@npm:4.0.3" dependencies: @@ -6981,13 +6973,6 @@ __metadata: languageName: node linkType: hard -"aes-js@npm:^3.1.2": - version: 3.1.2 - resolution: "aes-js@npm:3.1.2" - checksum: b65916767034a51375a3ac5aad62af452d89a386c1ae7b607bb9145d0bb8b8823bf2f3eba85bdfa52d61c65d5aed90ba90f677b8c826bfa1a8b7ae2fa3b54d91 - languageName: node - linkType: hard - "agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -7391,15 +7376,6 @@ __metadata: languageName: node linkType: hard -"base-x@npm:^3.0.2": - version: 3.0.9 - resolution: "base-x@npm:3.0.9" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 957101d6fd09e1903e846fd8f69fd7e5e3e50254383e61ab667c725866bec54e5ece5ba49ce385128ae48f9ec93a26567d1d5ebb91f4d56ef4a9cc0d5a5481e8 - languageName: node - linkType: hard - "base64-js@npm:^1.0.2, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -7487,13 +7463,6 @@ __metadata: languageName: node linkType: hard -"blakejs@npm:^1.1.0": - version: 1.2.1 - resolution: "blakejs@npm:1.2.1" - checksum: 0638b1bd058b21892633929c43005aa6a4cc4b2ac5b338a146c3c076622f1b360795bd7a4d1f077c9b01863ed2df0c1504a81c5b520d164179120434847e6cd7 - languageName: node - linkType: hard - "bn.js@npm:^4.11.9": version: 4.12.0 resolution: "bn.js@npm:4.12.0" @@ -7501,7 +7470,7 @@ __metadata: languageName: node linkType: hard -"bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": +"bn.js@npm:^5.2.1": version: 5.2.1 resolution: "bn.js@npm:5.2.1" checksum: 7a7e8764d7a6e9708b8b9841b2b3d6019cc154d2fc23716d0efecfe1e16921b7533c6f7361fb05471eab47986c4aa310c270f88e3507172104632ac8df2cfd84 @@ -7559,20 +7528,6 @@ __metadata: languageName: node linkType: hard -"browserify-aes@npm:^1.2.0": - version: 1.2.0 - resolution: "browserify-aes@npm:1.2.0" - dependencies: - buffer-xor: "npm:^1.0.3" - cipher-base: "npm:^1.0.0" - create-hash: "npm:^1.1.0" - evp_bytestokey: "npm:^1.0.3" - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - checksum: 2813058f74e083a00450b11ea9d5d1f072de7bf0133f5d122d4ff7b849bece56d52b9c51ad0db0fad21c0bc4e8272fd5196114bbe7b94a9b7feb0f9fbb33a3bf - languageName: node - linkType: hard - "browserslist@npm:^4.21.3": version: 4.21.5 resolution: "browserslist@npm:4.21.5" @@ -7596,26 +7551,6 @@ __metadata: languageName: node linkType: hard -"bs58@npm:^4.0.0": - version: 4.0.1 - resolution: "bs58@npm:4.0.1" - dependencies: - base-x: "npm:^3.0.2" - checksum: b3c5365bb9e0c561e1a82f1a2d809a1a692059fae016be233a6127ad2f50a6b986467c3a50669ce4c18929dcccb297c5909314dd347a25a68c21b68eb3e95ac2 - languageName: node - linkType: hard - -"bs58check@npm:^2.1.2": - version: 2.1.2 - resolution: "bs58check@npm:2.1.2" - dependencies: - bs58: "npm:^4.0.0" - create-hash: "npm:^1.1.0" - safe-buffer: "npm:^5.1.2" - checksum: 43bdf08a5dd04581b78f040bc4169480e17008da482ffe2a6507327bbc4fc5c28de0501f7faf22901cfe57fbca79cbb202ca529003fedb4cb8dccd265b38e54d - languageName: node - linkType: hard - "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -7670,13 +7605,6 @@ __metadata: languageName: node linkType: hard -"buffer-xor@npm:^1.0.3": - version: 1.0.3 - resolution: "buffer-xor@npm:1.0.3" - checksum: 4a63d48b5117c7eda896d81cd3582d9707329b07c97a14b0ece2edc6e64220ea7ea17c94b295e8c2cb7b9f8291e2b079f9096be8ac14be238420a43e06ec66e2 - languageName: node - linkType: hard - "buffer@npm:4.9.2": version: 4.9.2 resolution: "buffer@npm:4.9.2" @@ -8067,16 +7995,6 @@ __metadata: languageName: node linkType: hard -"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": - version: 1.0.4 - resolution: "cipher-base@npm:1.0.4" - dependencies: - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - checksum: 3d5d6652ca499c3f7c5d7fdc2932a357ec1e5aa84f2ad766d850efd42e89753c97b795c3a104a8e7ae35b4e293f5363926913de3bf8181af37067d9d541ca0db - languageName: node - linkType: hard - "cjs-module-lexer@npm:^1.0.0": version: 1.2.3 resolution: "cjs-module-lexer@npm:1.2.3" @@ -8407,33 +8325,6 @@ __metadata: languageName: node linkType: hard -"create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": - version: 1.2.0 - resolution: "create-hash@npm:1.2.0" - dependencies: - cipher-base: "npm:^1.0.1" - inherits: "npm:^2.0.1" - md5.js: "npm:^1.3.4" - ripemd160: "npm:^2.0.1" - sha.js: "npm:^2.4.0" - checksum: 3cfef32043b47a8999602af9bcd74966db6971dd3eb828d1a479f3a44d7f58e38c1caf34aa21a01941cc8d9e1a841738a732f200f00ea155f8a8835133d2e7bc - languageName: node - linkType: hard - -"create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": - version: 1.1.7 - resolution: "create-hmac@npm:1.1.7" - dependencies: - cipher-base: "npm:^1.0.3" - create-hash: "npm:^1.1.0" - inherits: "npm:^2.0.1" - ripemd160: "npm:^2.0.0" - safe-buffer: "npm:^5.0.1" - sha.js: "npm:^2.4.8" - checksum: 2b26769f87e99ef72150bf99d1439d69272b2e510e23a2b8daf4e93e2412f4842504237d726044fa797cb20ee0ec8bee78d414b11f2d7ca93299185c93df0dae - languageName: node - linkType: hard - "create-jest@npm:^29.7.0": version: 29.7.0 resolution: "create-jest@npm:29.7.0" @@ -9080,58 +8971,6 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^0.1.3": - version: 0.1.3 - resolution: "ethereum-cryptography@npm:0.1.3" - dependencies: - "@types/pbkdf2": "npm:^3.0.0" - "@types/secp256k1": "npm:^4.0.1" - blakejs: "npm:^1.1.0" - browserify-aes: "npm:^1.2.0" - bs58check: "npm:^2.1.2" - create-hash: "npm:^1.2.0" - create-hmac: "npm:^1.1.7" - hash.js: "npm:^1.1.7" - keccak: "npm:^3.0.0" - pbkdf2: "npm:^3.0.17" - randombytes: "npm:^2.1.0" - safe-buffer: "npm:^5.1.2" - scrypt-js: "npm:^3.0.0" - secp256k1: "npm:^4.0.1" - setimmediate: "npm:^1.0.5" - checksum: 975e476782746acd97d5b37366801ae622a52fb31e5d83f600804be230a61ef7b9d289dcecd9c308fb441967caf3a6e3768dd7c8add6441fcc60c398175d5a96 - languageName: node - linkType: hard - -"ethereumjs-util@npm:^7.1.2": - version: 7.1.5 - resolution: "ethereumjs-util@npm:7.1.5" - dependencies: - "@types/bn.js": "npm:^5.1.0" - bn.js: "npm:^5.1.2" - create-hash: "npm:^1.1.2" - ethereum-cryptography: "npm:^0.1.3" - rlp: "npm:^2.2.4" - checksum: f28fc1ebb8f35bf9e418f76f51be737d94d603b912c3e014c4e87cd45ccd1b10bdfef764c8f152574b57e9faa260a18773cbc110f9e0a754d6b3730699e54dc9 - languageName: node - linkType: hard - -"ethereumjs-wallet@npm:^1.0.1": - version: 1.0.2 - resolution: "ethereumjs-wallet@npm:1.0.2" - dependencies: - aes-js: "npm:^3.1.2" - bs58check: "npm:^2.1.2" - ethereum-cryptography: "npm:^0.1.3" - ethereumjs-util: "npm:^7.1.2" - randombytes: "npm:^2.1.0" - scrypt-js: "npm:^3.0.1" - utf8: "npm:^3.0.0" - uuid: "npm:^8.3.2" - checksum: 0a9ad0ac0930627c15e6fa6115dde8d1dd81160e57fbdf81ef0bcd1e0edd750fe9e8b00992651e694cabefee29eef2ad651dce8b24ae5253861927d0e19b6c90 - languageName: node - linkType: hard - "ethers@npm:5.7.2": version: 5.7.2 resolution: "ethers@npm:5.7.2" @@ -9205,17 +9044,6 @@ __metadata: languageName: node linkType: hard -"evp_bytestokey@npm:^1.0.3": - version: 1.0.3 - resolution: "evp_bytestokey@npm:1.0.3" - dependencies: - md5.js: "npm:^1.3.4" - node-gyp: "npm:latest" - safe-buffer: "npm:^5.1.1" - checksum: ad4e1577f1a6b721c7800dcc7c733fe01f6c310732bb5bf2240245c2a5b45a38518b91d8be2c610611623160b9d1c0e91f1ce96d639f8b53e8894625cf20fa45 - languageName: node - linkType: hard - "execa@npm:^5.0.0": version: 5.1.1 resolution: "execa@npm:5.1.1" @@ -10077,18 +9905,7 @@ __metadata: languageName: node linkType: hard -"hash-base@npm:^3.0.0": - version: 3.1.0 - resolution: "hash-base@npm:3.1.0" - dependencies: - inherits: "npm:^2.0.4" - readable-stream: "npm:^3.6.0" - safe-buffer: "npm:^5.2.0" - checksum: 26b7e97ac3de13cb23fc3145e7e3450b0530274a9562144fc2bf5c1e2983afd0e09ed7cc3b20974ba66039fad316db463da80eb452e7373e780cbee9a0d2f2dc - languageName: node - linkType: hard - -"hash.js@npm:1.1.7, hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7": +"hash.js@npm:1.1.7, hash.js@npm:^1.0.0, hash.js@npm:^1.0.3": version: 1.1.7 resolution: "hash.js@npm:1.1.7" dependencies: @@ -10373,7 +10190,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": +"inherits@npm:2, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 @@ -11677,18 +11494,6 @@ __metadata: languageName: node linkType: hard -"keccak@npm:^3.0.0": - version: 3.0.3 - resolution: "keccak@npm:3.0.3" - dependencies: - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - readable-stream: "npm:^3.6.0" - checksum: 30c652c39e935132eb92300eca974fad1f4ec4aed4c6e2f21d774b06001d07e24117dd46ef1494272f5674f7f11d5e7a8ee50c7bf8d87bb3895aa60607c4aabc - languageName: node - linkType: hard - "keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -12227,17 +12032,6 @@ __metadata: languageName: node linkType: hard -"md5.js@npm:^1.3.4": - version: 1.3.5 - resolution: "md5.js@npm:1.3.5" - dependencies: - hash-base: "npm:^3.0.0" - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.1.2" - checksum: 098494d885684bcc4f92294b18ba61b7bd353c23147fbc4688c75b45cb8590f5a95fd4584d742415dcc52487f7a1ef6ea611cfa1543b0dc4492fe026357f3f0c - languageName: node - linkType: hard - "mdurl@npm:^2.0.0": version: 2.0.0 resolution: "mdurl@npm:2.0.0" @@ -13598,19 +13392,6 @@ __metadata: languageName: node linkType: hard -"pbkdf2@npm:^3.0.17": - version: 3.1.2 - resolution: "pbkdf2@npm:3.1.2" - dependencies: - create-hash: "npm:^1.1.2" - create-hmac: "npm:^1.1.4" - ripemd160: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - sha.js: "npm:^2.4.8" - checksum: 40bdf30df1c9bb1ae41ec50c11e480cf0d36484b7c7933bf55e4451d1d0e3f09589df70935c56e7fccc5702779a0d7b842d012be8c08a187b44eb24d55bb9460 - languageName: node - linkType: hard - "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -14028,15 +13809,6 @@ __metadata: languageName: node linkType: hard -"randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: "npm:^5.1.0" - checksum: 4efd1ad3d88db77c2d16588dc54c2b52fd2461e70fe5724611f38d283857094fe09040fa2c9776366803c3152cf133171b452ef717592b65631ce5dc3a2bdafc - languageName: node - linkType: hard - "rc@npm:^1.2.7": version: 1.2.8 resolution: "rc@npm:1.2.8" @@ -14373,27 +14145,6 @@ __metadata: languageName: node linkType: hard -"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": - version: 2.0.2 - resolution: "ripemd160@npm:2.0.2" - dependencies: - hash-base: "npm:^3.0.0" - inherits: "npm:^2.0.1" - checksum: 006accc40578ee2beae382757c4ce2908a826b27e2b079efdcd2959ee544ddf210b7b5d7d5e80467807604244e7388427330f5c6d4cd61e6edaddc5773ccc393 - languageName: node - linkType: hard - -"rlp@npm:^2.2.4": - version: 2.2.7 - resolution: "rlp@npm:2.2.7" - dependencies: - bn.js: "npm:^5.2.0" - bin: - rlp: bin/rlp - checksum: cf1919a2dc99f336191b3363b76299db567c192b7ee3c6f5c722728c34f65577883c9c88eeb7a1bfcbc26693c8a4f1fb0662e79ee86f0c98dd258d6987303498 - languageName: node - linkType: hard - "rollup@npm:^4.34.9": version: 4.62.0 resolution: "rollup@npm:4.62.0" @@ -14518,7 +14269,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -14571,7 +14322,7 @@ __metadata: languageName: node linkType: hard -"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": +"scrypt-js@npm:3.0.1": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" checksum: 2f8aa72b7f76a6f9c446bbec5670f80d47497bccce98474203d89b5667717223eeb04a50492ae685ed7adc5a060fc2d8f9fd988f8f7ebdaf3341967f3aeff116 @@ -14590,18 +14341,6 @@ __metadata: languageName: node linkType: hard -"secp256k1@npm:^4.0.1": - version: 4.0.3 - resolution: "secp256k1@npm:4.0.3" - dependencies: - elliptic: "npm:^6.5.4" - node-addon-api: "npm:^2.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.2.0" - checksum: 8b45820cd90fd2f95cc8fdb9bf8a71e572de09f2311911ae461a951ffa9e30c99186a129d0f1afeb380dd67eca0c10493f8a7513c39063fda015e99995088e3b - languageName: node - linkType: hard - "semver@npm:^6.0.0, semver@npm:^6.3.0": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -14690,25 +14429,6 @@ __metadata: languageName: node linkType: hard -"setimmediate@npm:^1.0.5": - version: 1.0.5 - resolution: "setimmediate@npm:1.0.5" - checksum: 76e3f5d7f4b581b6100ff819761f04a984fa3f3990e72a6554b57188ded53efce2d3d6c0932c10f810b7c59414f85e2ab3c11521877d1dea1ce0b56dc906f485 - languageName: node - linkType: hard - -"sha.js@npm:^2.4.0, sha.js@npm:^2.4.8": - version: 2.4.11 - resolution: "sha.js@npm:2.4.11" - dependencies: - inherits: "npm:^2.0.1" - safe-buffer: "npm:^5.0.1" - bin: - sha.js: ./bin.js - checksum: d833bfa3e0a67579a6ce6e1bc95571f05246e0a441dd8c76e3057972f2a3e098465687a4369b07e83a0375a88703577f71b5b2e966809e67ebc340dbedb478c7 - languageName: node - linkType: hard - "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -15932,7 +15652,7 @@ __metadata: languageName: node linkType: hard -"utf8@npm:3.0.0, utf8@npm:^3.0.0": +"utf8@npm:3.0.0": version: 3.0.0 resolution: "utf8@npm:3.0.0" checksum: 31d19c4faacbb65b09ebc1c21c32b20bdb0919c6f6773cee5001b99bb83f8e503e7233c08fc71ebb34f7cfebd95cec3243b81d90176097aa2f286cccb4ce866e @@ -15975,7 +15695,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.3.0, uuid@npm:^8.3.2": +"uuid@npm:^8.3.0": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: