From 26e1c25de5af47fb97f8f7bd58662ce4594879ce Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Mon, 13 Nov 2023 16:57:31 +0100 Subject: [PATCH 1/2] chore: migrate to ecies/js --- packages/utils/package.json | 1 + packages/utils/src/crypto/ec-utils.ts | 107 ++++++++++++-------- packages/utils/test/crypto/ec-utils.test.ts | 32 +++--- yarn.lock | 26 +++++ 4 files changed, 107 insertions(+), 59 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index f08b2a03dd..da510336b7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -42,6 +42,7 @@ "dependencies": { "@requestnetwork/types": "0.37.0", "@toruslabs/eccrypto": "4.0.0", + "eciesjs": "^0.4.5", "ethers": "5.5.1", "secp256k1": "4.0.2", "tslib": "2.5.0" diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 03c3419260..7b1cec3fd3 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,6 +1,8 @@ import { publicKeyConvert, ecdsaRecover } from 'secp256k1'; import { ethers } from 'ethers'; -import { Ecies, decrypt, encrypt } from '@toruslabs/eccrypto'; +// import { Ecies, decrypt, encrypt } from '@toruslabs/eccrypto'; + +import { decrypt, encrypt, ECIES_CONFIG } from 'eciesjs'; /** * Function to manage Elliptic-curve cryptography @@ -14,6 +16,11 @@ export { ecSign, }; +ECIES_CONFIG.ellipticCurve = 'secp256k1'; +ECIES_CONFIG.isEphemeralKeyCompressed = false; +ECIES_CONFIG.symmetricAlgorithm = 'aes-256-gcm'; +ECIES_CONFIG.symmetricNonceLength = 16; + /** * Function to derive the address from an EC private key * @@ -132,29 +139,51 @@ function ecRecover(signature: string, data: string): string { * * @returns the encrypted data */ -async function ecEncrypt(publicKey: string, data: string): Promise { +function ecEncrypt(publicKey: string, data: string): string { try { // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) - const compressed = compressPublicKey(publicKey); - const encrypted = await encrypt(Buffer.from(compressed), Buffer.from(data)); + // const compressed = compressPublicKey(publicKey); + // const encrypted = await encrypt(Buffer.from(compressed), Buffer.from(data)); + + return encrypt(publicKey, Buffer.from(data)).toString('hex').slice(2); // Transforms the object with the encrypted data into a smaller string-representation. - return Buffer.concat([ - encrypted.iv, - publicKeyConvert(encrypted.ephemPublicKey), - encrypted.mac, - encrypted.ciphertext, - ]).toString('hex'); + // return Buffer.concat([ + // encrypted.iv, + // publicKeyConvert(encrypted.ephemPublicKey), + // encrypted.mac, + // encrypted.ciphertext, + // ]).toString('hex'); } catch (e) { - if ( - e.message === 'public key length is invalid' || - e.message === 'Expected public key to be an Uint8Array with length [33, 65]' - ) { + if (e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); } throw e; } } +// +// /** +// * Function to encrypt data with a public key +// * +// * @param publicKey the public key to encrypt with +// * @param data the data to encrypt +// * +// * @returns the encrypted data +// */ +// function ecEncrypt(publicKey: string, data: string): string { +// try { +// // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) +// return encrypt(publicKey, Buffer.from(data)).toString('hex'); +// } catch (e) { +// if ( +// e.message === 'public key length is invalid' || +// e.message === 'Expected public key to be an Uint8Array with length [33, 65]' +// ) { +// throw new Error('The public key must be a string representing 64 bytes'); +// } +// throw e; +// } +// } /** * Function to decrypt data with a public key @@ -164,25 +193,17 @@ async function ecEncrypt(publicKey: string, data: string): Promise { * * @returns the decrypted data */ -async function ecDecrypt(privateKey: string, data: string): Promise { +function ecDecrypt(privateKey: string, data: string): string { try { - const buf = await decrypt(Buffer.from(privateKey.replace(/^0x/, ''), 'hex'), eciesSplit(data)); - return buf.toString(); + if (!data.startsWith('04')) { + data = `04${data}`; + } + return decrypt(privateKey, Buffer.from(data, 'hex')).toString(); } catch (e) { - if ( - e.message === 'Bad private key' || - e.message === 'Expected private key to be an Uint8Array with length 32' - ) { + if (e.message === 'Invalid private key') { throw new Error('The private key must be a string representing 32 bytes'); } - if ( - e.message === 'public key length is invalid' || - e.message === 'Expected public key to be an Uint8Array with length [33, 65]' || - e.message === 'Bad MAC' || - e.message === 'bad MAC after trying padded' || - e.message === 'the public key could not be parsed or is invalid' || - e.message === 'Public Key could not be parsed' - ) { + if (e.message === 'second arg must be public key') { throw new Error('The encrypted data is not well formatted'); } throw e; @@ -205,17 +226,17 @@ function compressPublicKey(publicKey: string): Uint8Array { * Split an encrypted string to ECIES params * inspired from https://github.com/pubkey/eth-crypto/blob/master/src/ecDecrypt-with-private-key.js */ -const eciesSplit = (str: string): Ecies => { - const buf = Buffer.from(str, 'hex'); - - const ephemPublicKeyStr = buf.toString('hex', 16, 49); - - return { - iv: Buffer.from(buf.toString('hex', 0, 16), 'hex'), - mac: Buffer.from(buf.toString('hex', 49, 81), 'hex'), - ciphertext: Buffer.from(buf.toString('hex', 81, buf.length), 'hex'), - ephemPublicKey: Buffer.from( - publicKeyConvert(new Uint8Array(Buffer.from(ephemPublicKeyStr, 'hex')), false), - ), - }; -}; +// const eciesSplit = (str: string): Ecies => { +// const buf = Buffer.from(str, 'hex'); +// +// const ephemPublicKeyStr = buf.toString('hex', 16, 49); +// +// return { +// iv: Buffer.from(buf.toString('hex', 0, 16), 'hex'), +// mac: Buffer.from(buf.toString('hex', 49, 81), 'hex'), +// ciphertext: Buffer.from(buf.toString('hex', 81, buf.length), 'hex'), +// ephemPublicKey: Buffer.from( +// publicKeyConvert(new Uint8Array(Buffer.from(ephemPublicKeyStr, 'hex')), false), +// ), +// }; +// }; diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index 668708c2ab..b803c9ed9a 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -97,15 +97,15 @@ describe('Utils/EcUtils', () => { describe('encrypt', () => { it('can encrypt', async () => { - const encryptedData = await ecEncrypt(rawId.publicKey, anyData); + const encryptedData = ecEncrypt(rawId.publicKey, anyData); // 'encrypt() error' expect(encryptedData.length).toBe(226); // 'decrypt() error' - expect(await ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); + expect(ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); }); it('can encrypt with other public key formats', async () => { - const encryptedData = await ecEncrypt( + const encryptedData = ecEncrypt( '0396212fc129c2f78771218b2e93da7a5aac63490a42bb41b97848c39c14fe65cd', anyData, ); @@ -113,7 +113,7 @@ describe('Utils/EcUtils', () => { }); it('cannot encrypt data with a wrong public key', async () => { - await expect(ecEncrypt('cf4a', anyData)).rejects.toThrowError( + expect(() => ecEncrypt('cf4a', anyData)).toThrow( 'The public key must be a string representing 64 bytes', ); }); @@ -121,7 +121,7 @@ describe('Utils/EcUtils', () => { describe('decrypt', () => { it('can decrypt', async () => { - const data = await ecDecrypt( + const data = ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ); @@ -130,36 +130,36 @@ describe('Utils/EcUtils', () => { }); it('cannot decrypt data with a wrong private key', async () => { - await expect( + expect(() => ecDecrypt( '0xaa', '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ), - ).rejects.toThrowError('The private key must be a string representing 32 bytes'); + ).toThrow('The private key must be a string representing 32 bytes'); }); it('cannot decrypt data with a wrong encrypted data: public key too short', async () => { - await expect(ecDecrypt(rawId.privateKey, 'aa')).rejects.toThrowError( + expect(() => ecDecrypt(rawId.privateKey, 'aa')).toThrow( 'The encrypted data is not well formatted', ); }); it('cannot decrypt data with a wrong encrypted data: public key not parsable', async () => { - await expect( + expect(() => ecDecrypt( rawId.privateKey, 'e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', ), - ).rejects.toThrowError('The encrypted data is not well formatted'); + ).toThrow('The encrypted data is not well formatted'); }); it('cannot decrypt data with a wrong encrypted data: bad MAC', async () => { - await expect( + expect(() => ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', ), - ).rejects.toThrowError('The encrypted data is not well formatted'); + ).toThrow('The encrypted data is not well formatted'); }); it.each([ @@ -168,22 +168,22 @@ describe('Utils/EcUtils', () => { ])('should be compatible with legacy $type implementation of eccrypto', async ({ array }) => { for (const row of array) { const { data, key, encrypted } = row; - const decrypted = await ecDecrypt(key, encrypted); + const decrypted = ecDecrypt(key, encrypted); expect(decrypted).toBe(data); } }); }); it('can encrypt()', async () => { - const encryptedData = await ecEncrypt(rawId.publicKey, anyData); + const encryptedData = ecEncrypt(rawId.publicKey, anyData); // 'encrypt() error' expect(encryptedData.length).toBe(226); // 'decrypt() error' - expect(await ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); + expect(ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); }); it('can decrypt()', async () => { - const data = await ecDecrypt( + const data = ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ); diff --git a/yarn.lock b/yarn.lock index 3f7056f0ff..3d1d30097f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3871,11 +3871,28 @@ bn.js "5.2.1" borsh "^0.7.0" +"@noble/ciphers@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.3.0.tgz#6ba3090afdc7a7051393486f6af210e62e0f04ec" + integrity sha512-ldbrnOjmNRwFdXcTM6uXDcxpMIFrbzAWNnpBPp4oTJTFF0XByGD6vf45WrehZGXRQTRVV+Zm8YP+EgEf+e4cWA== + +"@noble/curves@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.3.2", "@noble/hashes@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz" @@ -9492,6 +9509,15 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +eciesjs@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.4.5.tgz#35c48963e6942687da2bc93eb5b612ebf6a0bbfb" + integrity sha512-2zSRIygO48LpdS95Rwt9ryIkJNO37IdbkjRsnYyAn7gx7e4WPBNimnk6jGNdx2QQYr/VJRPnSVdwQpO5bycYZw== + dependencies: + "@noble/ciphers" "^0.3.0" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.2" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" From c48a00a3d017408e73f8f5d6dfb9e82a54396dfa Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Mon, 13 Nov 2023 17:56:37 +0100 Subject: [PATCH 2/2] handle sign and recover --- packages/utils/package.json | 5 +- packages/utils/src/crypto/ec-utils.ts | 130 +++++--------------------- yarn.lock | 11 +-- 3 files changed, 29 insertions(+), 117 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index da510336b7..196a3185e3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -40,11 +40,10 @@ "test:watch": "yarn test --watch" }, "dependencies": { + "@noble/curves": "1.2.0", "@requestnetwork/types": "0.37.0", - "@toruslabs/eccrypto": "4.0.0", - "eciesjs": "^0.4.5", + "eciesjs": "0.4.5", "ethers": "5.5.1", - "secp256k1": "4.0.2", "tslib": "2.5.0" }, "devDependencies": { diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 7b1cec3fd3..60a7948cdf 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,8 +1,8 @@ -import { publicKeyConvert, ecdsaRecover } from 'secp256k1'; import { ethers } from 'ethers'; -// import { Ecies, decrypt, encrypt } from '@toruslabs/eccrypto'; -import { decrypt, encrypt, ECIES_CONFIG } from 'eciesjs'; +import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; +import { secp256k1 } from '@noble/curves/secp256k1'; +import { computeAddress } from 'ethers/lib/utils'; /** * Function to manage Elliptic-curve cryptography @@ -49,13 +49,13 @@ function getAddressFromPrivateKey(privateKey: string): string { /** * Function to derive the address from an EC public key * - * @param publicKey the public key to derive + * @param publicKeyHex the public key to derive * * @returns the address */ -function getAddressFromPublicKey(publicKey: string): string { +function getAddressFromPublicKey(publicKeyHex: string): string { try { - return ethers.utils.computeAddress(compressPublicKey(publicKey)); + return ethers.utils.computeAddress(PublicKey.fromHex(publicKeyHex).toHex(true)); } catch (e) { if ( e.message === 'public key length is invalid' || @@ -69,22 +69,20 @@ function getAddressFromPublicKey(publicKey: string): string { } /** - * Function ecSigndata with ECDSA + * Function ecSign data with ECDSA * - * @param data the data to sign + * @param privateKey the private key used to sign the message + * @param dataHash the data to sign * * @returns the signature */ -function ecSign(privateKey: string, data: string): string { +function ecSign(privateKey: string, dataHash: string): string { try { - const signingKey = new ethers.utils.SigningKey(privateKey); - return ethers.utils.joinSignature(signingKey.signDigest(data)); + privateKey = privateKey.replace(/^0x/, ''); + dataHash = dataHash.replace(/^0x/, ''); + return `0x${secp256k1.sign(dataHash, privateKey).toCompactHex()}1b`; } catch (e) { - if ( - e.message === 'private key length is invalid' || - e.message === 'Expected private key to be an Uint8Array with length 32' || - e.code === 'INVALID_ARGUMENT' - ) { + if (e.message === 'private key must be 32 bytes, hex or bigint, not string') { throw new Error('The private key must be a string representing 32 bytes'); } throw e; @@ -94,37 +92,25 @@ function ecSign(privateKey: string, data: string): string { /** * Function to recover address from a signature * - * @param signature the signature - * @param data the data signed + * @param signatureHex the signature + * @param dataHash the data signed * * @returns the address */ -function ecRecover(signature: string, data: string): string { +function ecRecover(signatureHex: string, dataHash: string): string { try { - signature = signature.replace(/^0x/, ''); - data = data.replace(/^0x/, ''); - // split into v-value and sig - const sigOnly = signature.substring(0, signature.length - 2); // all but last 2 chars - const vValue = signature.slice(-2); // last 2 chars + signatureHex = signatureHex.replace(/^0x/, ''); + dataHash = dataHash.replace(/^0x/, ''); + const sigOnly = signatureHex.substring(0, signatureHex.length - 2); // all but last 2 chars + const vValue = signatureHex.slice(-2); // last 2 chars const recoveryNumber = vValue === '1c' ? 1 : 0; - return ethers.utils.computeAddress( - Buffer.from( - ecdsaRecover( - new Uint8Array(Buffer.from(sigOnly, 'hex')), - recoveryNumber, - new Uint8Array(Buffer.from(data, 'hex')), - false, - ), - ), - ); + const signature = secp256k1.Signature.fromCompact(sigOnly); + const signatureRecover = signature.addRecoveryBit(recoveryNumber); + return computeAddress(`0x${signatureRecover.recoverPublicKey(dataHash).toHex()}`); } catch (e) { - if ( - e.message === 'signature length is invalid' || - e.message === 'Expected signature to be an Uint8Array with length 64' || - e.code === 'INVALID_ARGUMENT' - ) { + if (e.message === 'compactSignature expected 64 bytes, got 0') { throw new Error('The signature must be a string representing 66 bytes'); } throw e; @@ -141,19 +127,7 @@ function ecRecover(signature: string, data: string): string { */ function ecEncrypt(publicKey: string, data: string): string { try { - // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) - // const compressed = compressPublicKey(publicKey); - // const encrypted = await encrypt(Buffer.from(compressed), Buffer.from(data)); - return encrypt(publicKey, Buffer.from(data)).toString('hex').slice(2); - - // Transforms the object with the encrypted data into a smaller string-representation. - // return Buffer.concat([ - // encrypted.iv, - // publicKeyConvert(encrypted.ephemPublicKey), - // encrypted.mac, - // encrypted.ciphertext, - // ]).toString('hex'); } catch (e) { if (e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); @@ -161,29 +135,6 @@ function ecEncrypt(publicKey: string, data: string): string { throw e; } } -// -// /** -// * Function to encrypt data with a public key -// * -// * @param publicKey the public key to encrypt with -// * @param data the data to encrypt -// * -// * @returns the encrypted data -// */ -// function ecEncrypt(publicKey: string, data: string): string { -// try { -// // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) -// return encrypt(publicKey, Buffer.from(data)).toString('hex'); -// } catch (e) { -// if ( -// e.message === 'public key length is invalid' || -// e.message === 'Expected public key to be an Uint8Array with length [33, 65]' -// ) { -// throw new Error('The public key must be a string representing 64 bytes'); -// } -// throw e; -// } -// } /** * Function to decrypt data with a public key @@ -209,34 +160,3 @@ function ecDecrypt(privateKey: string, data: string): string { throw e; } } - -/** - * Converts a public key to its compressed form. - */ -function compressPublicKey(publicKey: string): Uint8Array { - publicKey = publicKey.replace(/^0x/, ''); - // if there are more bytes than the key itself, it means there is already a prefix - if (publicKey.length % 32 === 0) { - publicKey = `04${publicKey}`; - } - return publicKeyConvert(Buffer.from(publicKey, 'hex')); -} - -/** - * Split an encrypted string to ECIES params - * inspired from https://github.com/pubkey/eth-crypto/blob/master/src/ecDecrypt-with-private-key.js - */ -// const eciesSplit = (str: string): Ecies => { -// const buf = Buffer.from(str, 'hex'); -// -// const ephemPublicKeyStr = buf.toString('hex', 16, 49); -// -// return { -// iv: Buffer.from(buf.toString('hex', 0, 16), 'hex'), -// mac: Buffer.from(buf.toString('hex', 49, 81), 'hex'), -// ciphertext: Buffer.from(buf.toString('hex', 81, buf.length), 'hex'), -// ephemPublicKey: Buffer.from( -// publicKeyConvert(new Uint8Array(Buffer.from(ephemPublicKeyStr, 'hex')), false), -// ), -// }; -// }; diff --git a/yarn.lock b/yarn.lock index 3d1d30097f..f400e69a98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4590,13 +4590,6 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== -"@toruslabs/eccrypto@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@toruslabs/eccrypto/-/eccrypto-4.0.0.tgz#0b27ed2d1e9483e77f42a7619a2c3c19cb802f44" - integrity sha512-Z3EINkbsgJx1t6jCDVIJjLSUEGUtNIeDjhMWmeDGOWcP/+v/yQ1hEvd1wfxEz4q5WqIHhevacmPiVxiJ4DljGQ== - dependencies: - elliptic "^6.5.4" - "@truffle/abi-utils@^0.2.11": version "0.2.11" resolved "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.2.11.tgz" @@ -9509,7 +9502,7 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -eciesjs@^0.4.5: +eciesjs@0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.4.5.tgz#35c48963e6942687da2bc93eb5b612ebf6a0bbfb" integrity sha512-2zSRIygO48LpdS95Rwt9ryIkJNO37IdbkjRsnYyAn7gx7e4WPBNimnk6jGNdx2QQYr/VJRPnSVdwQpO5bycYZw== @@ -18776,7 +18769,7 @@ scuid@^1.1.0: resolved "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz" integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg== -secp256k1@4.0.2, secp256k1@^4.0.1: +secp256k1@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz" integrity sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==