diff --git a/apps/sdk-vite-integration/package.json b/apps/sdk-vite-integration/package.json index f62ca44f1..206d44175 100644 --- a/apps/sdk-vite-integration/package.json +++ b/apps/sdk-vite-integration/package.json @@ -35,4 +35,4 @@ "vitest": "^2.1.4", "vitest-browser-react": "^0.0.4" } -} \ No newline at end of file +} diff --git a/packages/core/src/secp256k1/Secp256k1.ts b/packages/core/src/secp256k1/Secp256k1.ts index 2d8416404..c083e8ad5 100644 --- a/packages/core/src/secp256k1/Secp256k1.ts +++ b/packages/core/src/secp256k1/Secp256k1.ts @@ -107,7 +107,7 @@ class Secp256k1 { * * {@link global.crypto.subtle.generateKey}; * * [nc_secp256k1.utils.randomPrivateKey](https://github.com/paulmillr/noble-secp256k1). */ - public static async generatePrivateKey(): Promise { + public static async _generatePrivateKey(): Promise { try { return nc_secp256k1.utils.randomPrivateKey(); } catch (e) { @@ -132,6 +132,32 @@ class Secp256k1 { } } + /** + * Generates a new Secp256k1 private key using a secure random number generator. + * + * @return {Promise} A promise that resolves to a Uint8Array representing the generated private key. + * This encoded private key is suitable for cryptographic operations. + * @throws {InvalidSecp256k1PrivateKey} Throws an error if private key generation fails if a secure random number + * generator is not provided by the hosting operating system. + * + * @remarks Security auditable method, depends on + * * [nc_secp256k1.utils.randomPrivateKey](https://github.com/paulmillr/noble-secp256k1). + */ + public static async generatePrivateKey(): Promise { + return await new Promise((resolve) => { + try { + resolve(nc_secp256k1.utils.randomPrivateKey()); + } catch (e) { + throw new InvalidSecp256k1PrivateKey( + 'Secp256k1.generatePrivateKey', + 'Private key generation failed: ensure you have a secure random number generator available at runtime.', + undefined, + e + ); + } + }); + } + /** * Inflate a compressed public key to its uncompressed form. * @@ -192,20 +218,18 @@ class Secp256k1 { * {@link {@link global.crypto} is used as fall back togenerate * the random sequence. * - * @param {number} [bytesLength=32] - Optional. The number of random bytes to generate. + * @param {number} [bytesLength=32] - Optional. The number of random bytes to generate, 32 by default. * @return {Uint8Array} - A Uint8Array containing the random bytes. * * @remarks Security auditable method, depends on - * * {@link global.crypto.getRandomValues}; + * * {@link global.crypto.getRandomValues}; * * [nh_randomBytes](https://github.com/paulmillr/noble-hashes). */ - public static randomBytes(bytesLength?: number): Uint8Array { + public static randomBytes(bytesLength: number = 32): Uint8Array { try { return nh_randomBytes(bytesLength); } catch (e) { - return global.crypto.getRandomValues( - new Uint8Array(bytesLength ?? 32) - ); + return global.crypto.getRandomValues(new Uint8Array(bytesLength)); } } diff --git a/packages/core/src/vcdm/Address.ts b/packages/core/src/vcdm/Address.ts index 6ba492a41..aedc9829a 100644 --- a/packages/core/src/vcdm/Address.ts +++ b/packages/core/src/vcdm/Address.ts @@ -1,14 +1,10 @@ -import { Keccak256 } from './hash/Keccak256'; import { HDKey } from '../hdkey/HDKey'; import { Hex } from './Hex'; import { HexUInt } from './HexUInt'; +import { InvalidDataType, InvalidHDKey } from '@vechain/sdk-errors'; +import { Keccak256 } from './hash/Keccak256'; import { Secp256k1 } from '../secp256k1/Secp256k1'; import { Txt } from './Txt'; -import { - InvalidDataType, - InvalidHDKey, - InvalidSecp256k1PrivateKey -} from '@vechain/sdk-errors'; /** * Represents a VeChain Address as unsigned integer. @@ -89,29 +85,18 @@ class Address extends HexUInt { } /** - * Create an Address instance from the given private key. - * - * @param {Uint8Array} privateKey - The private key to convert. - * - * @param {boolean} [isCompressed=true] - The flag to indicate if the derived public key should be compressed. + * Generates an Address object from the given private key. * - * @returns {Address} The converted address. - * - * @remarks Security auditable method, depends on - * * {@link Secp256k1.derivePublicKey}. + * @param {Uint8Array} privateKey - The private key used to derive the corresponding address. + * @return {Address} The derived Address object. + * @throws {InvalidDataType} If the provided private key is invalid or cannot derive an address. */ - public static ofPrivateKey( - privateKey: Uint8Array, - isCompressed: boolean = true - ): Address { + public static ofPrivateKey(privateKey: Uint8Array): Address { try { return Address.ofPublicKey( - Secp256k1.derivePublicKey(privateKey, isCompressed) + Secp256k1.derivePublicKey(privateKey, true) ); } catch (error) { - if (error instanceof InvalidSecp256k1PrivateKey) { - throw error; - } throw new InvalidDataType( 'Address.ofPrivateKey', 'not a valid private key', diff --git a/packages/core/src/vcdm/hash/Keccak256.ts b/packages/core/src/vcdm/hash/Keccak256.ts index 62af9ecbf..7be2ab498 100644 --- a/packages/core/src/vcdm/hash/Keccak256.ts +++ b/packages/core/src/vcdm/hash/Keccak256.ts @@ -4,13 +4,13 @@ import { Hex } from '../Hex'; import { HexUInt } from '../HexUInt'; /** - * Represents the result of an [SHA-3](https://en.wikipedia.org/wiki/SHA-3) [KECCAK 256](https://keccak.team/keccak.html) hash operation. + * Represents the result of an [KECCAK 256](https://keccak.team/keccak.html) hash operation. * * @extends HexUInt */ class Keccak256 extends HexUInt { /** - * Generates the [KECCAK 256](https://eth-hash.readthedocs.io/en/stable/) hash of the given input. + * Generates the [KECCAK 256](https://keccak.team/keccak.html) hash of the given input. * * @param {bigint | number | string | Uint8Array | Hex} exp - The input value to hash. * diff --git a/packages/core/tests/keystore/keystore.unit.test.ts b/packages/core/tests/keystore/keystore.unit.test.ts index 10afec487..729157315 100644 --- a/packages/core/tests/keystore/keystore.unit.test.ts +++ b/packages/core/tests/keystore/keystore.unit.test.ts @@ -1,5 +1,6 @@ import { beforeEach, describe, expect, test } from '@jest/globals'; import { + InvalidDataType, InvalidKeystore, InvalidKeystoreParams, InvalidSecp256k1PrivateKey, @@ -60,7 +61,11 @@ import { encryptionPassword } from './fixture'; new TextEncoder().encode('wrong private key'), encryptionPassword ) - ).rejects.toThrowError(InvalidSecp256k1PrivateKey); + ).rejects.toThrowError( + experimentalCryptography + ? InvalidDataType + : InvalidSecp256k1PrivateKey + ); }); /** diff --git a/packages/core/tests/secp256k1/Secp256k1.unit.test.ts b/packages/core/tests/secp256k1/Secp256k1.unit.test.ts index 9bd0b29f5..210b0dd14 100644 --- a/packages/core/tests/secp256k1/Secp256k1.unit.test.ts +++ b/packages/core/tests/secp256k1/Secp256k1.unit.test.ts @@ -4,177 +4,191 @@ import { InvalidSecp256k1PrivateKey, InvalidSecp256k1Signature } from '@vechain/sdk-errors'; -import { HexUInt, Secp256k1, ZERO_BYTES } from '../../src'; -import { - invalidMessageHashes, - messageHashBuffer, - privateKey, - publicKeyCompressed, - publicKeyUncompressed, - signature, - validMessageHashes, - validPrivateKeys -} from './fixture'; +import { Keccak256, Secp256k1, Txt, ZERO_BYTES } from '../../src'; +import * as n_utils from '@noble/curves/abstract/utils'; + +const HASHES = { + invalid: Txt.of('some_invalid_stuff').bytes, + valid: Keccak256.of(Txt.of('hello world').bytes).bytes +}; + +const KEYS = { + private: { + invalid: n_utils.hexToBytes( + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + ), + valid: n_utils.hexToBytes( + '7582be841ca040aa940fff6c05773129e135623e41acce3e0b8ba520dc1ae26a' + ) + }, + public: { + compressed: n_utils.hexToBytes( + '03b90e9bb2617387eba4502c730de65a33878ef384a46f1096d86f2da19043304a' + ), + uncompressed: n_utils.hexToBytes( + '04b90e9bb2617387eba4502c730de65a33878ef384a46f1096d86f2da19043304afa67d0ad09cf2bea0c6f2d1767a9e62a7a7ecc41facf18f2fa505d92243a658f' + ) + } +}; + +const SIGNATURES = { + valid: n_utils.hexToBytes( + 'f8fe82c74f9e1f5bf443f8a7f8eb968140f554968fdcab0a6ffe904e451c8b9244be44bccb1feb34dd20d9d8943f8c131227e55861736907b02d32c06b934d7200' + ) +}; /** * Test Secp256k1 class. * @group unit/Secp256k1 */ describe('Secp256k1 class tests', () => { - const invalid = new TextEncoder().encode('some_invalid_stuff'); - describe('Secp256k1 - compressPublicKey', () => { - test('Secp256k1 - compressPublicKey - from compressed', () => { + describe('compressPublicKey', () => { + test('ok <- compressed', () => { expect( - Secp256k1.compressPublicKey(publicKeyCompressed) - ).toStrictEqual(publicKeyCompressed); + Secp256k1.compressPublicKey(KEYS.public.compressed) + ).toStrictEqual(KEYS.public.compressed); }); - test('Secp256k1 - compressPublicKey - from uncompressed', () => { + test('ok <- uncompressed', () => { expect( - Secp256k1.compressPublicKey(publicKeyUncompressed) - ).toStrictEqual(publicKeyCompressed); + Secp256k1.compressPublicKey(KEYS.public.uncompressed) + ).toStrictEqual(KEYS.public.compressed); }); }); - describe('Secp256k1 - derivePublicKey', () => { - test('Secp256k1 - derivePublicKey - compressed', () => { - expect(Secp256k1.derivePublicKey(privateKey)).toStrictEqual( - Secp256k1.compressPublicKey(publicKeyUncompressed) + describe('derivePublicKey', () => { + test('ok <- compressed', () => { + expect(Secp256k1.derivePublicKey(KEYS.private.valid)).toStrictEqual( + Secp256k1.compressPublicKey(KEYS.public.compressed) ); }); - test('Secp256k1 - derivePublicKey - uncompressed', () => { - expect(Secp256k1.derivePublicKey(privateKey, false)).toStrictEqual( - publicKeyUncompressed - ); + test('ok <- uncompressed', () => { + expect( + Secp256k1.derivePublicKey(KEYS.private.valid, false) + ).toStrictEqual(KEYS.public.uncompressed); }); - test('Secp256k1 - derivePublicKey - error', () => { + test('error <- invalid key', () => { expect(() => Secp256k1.derivePublicKey(ZERO_BYTES(32)) ).toThrowError(InvalidSecp256k1PrivateKey); }); }); - describe('Secp256k1 - generatePublicKey', () => { - test('Secp256k1 - generatePrivateKey', async () => { - const randomPrivateKey = await Secp256k1.generatePrivateKey(); + describe('generatePrivateKey', () => { + test('ok <- noble library', async () => { + const privateKey = await Secp256k1.generatePrivateKey(); // Length of private key should be 32 bytes - expect(randomPrivateKey.length).toBe(32); + expect(privateKey.length).toBe(32); // Private key should be valid - expect(Secp256k1.isValidPrivateKey(randomPrivateKey)).toBe(true); + expect(Secp256k1.isValidPrivateKey(privateKey)).toBe(true); + }); + + test('error <- mock no hw support for cryptography', async () => { + jest.spyOn(Secp256k1, 'generatePrivateKey').mockImplementation( + () => { + throw new InvalidSecp256k1PrivateKey( + 'Secp256k1.generatePrivateKey', + 'Private key generation failed: ensure you have a secure random number generator available at runtime.', + undefined + ); + } + ); + await expect( + async () => await Secp256k1.generatePrivateKey() + ).rejects.toThrowError(InvalidSecp256k1PrivateKey); }); }); - describe('Secp256k1 - inflatePublicKey', () => { - test('Secp256k1 - inflatePublicKey - compressed', () => { + describe('inflatePublicKey', () => { + test('ok <- compressed', () => { expect( - Secp256k1.inflatePublicKey(publicKeyCompressed) - ).toStrictEqual(publicKeyUncompressed); + Secp256k1.inflatePublicKey(KEYS.public.compressed) + ).toStrictEqual(KEYS.public.uncompressed); }); - test('Secp256k1 - inflatePublicKey - uncompressed', () => { + test('ok <- uncompressed', () => { expect( - Secp256k1.inflatePublicKey(publicKeyUncompressed) - ).toStrictEqual(publicKeyUncompressed); + Secp256k1.inflatePublicKey(KEYS.public.uncompressed) + ).toStrictEqual(KEYS.public.uncompressed); }); }); - describe('Secp256k1 - isValidMessageHash', () => { - test('Secp256k1 - isValidMessageHash - true', () => { - validMessageHashes.forEach((messageHash: Uint8Array) => { - expect(Secp256k1.isValidMessageHash(messageHash)).toBe(true); - }); + describe('isValidMessageHash', () => { + test('true <- valid', () => { + expect(Secp256k1.isValidMessageHash(HASHES.valid)).toBe(true); }); - test('Secp256k1 - isValidMessageHash - false', () => { - invalidMessageHashes.forEach((messageHash: Uint8Array) => { - expect(Secp256k1.isValidMessageHash(messageHash)).toBe(false); - }); + test('false <- invalid', () => { + expect(Secp256k1.isValidMessageHash(HASHES.invalid)).toBe(false); }); }); - describe('Secp256k1 - isValidPrivateKey', () => { - test('Secp256k1 - isValidPrivateKey - true', () => { - validPrivateKeys.forEach((privateKey: Uint8Array) => { - expect(Secp256k1.isValidPrivateKey(privateKey)).toBe(true); - }); + describe('isValidPrivateKey', () => { + test('true <- valid', () => { + expect(Secp256k1.isValidPrivateKey(KEYS.private.valid)).toBe(true); }); - test('Secp256k1 - isValidPrivateKey - false', () => { - validPrivateKeys.forEach((privateKey: Uint8Array) => { - expect(Secp256k1.isValidPrivateKey(privateKey)).toBe(true); - }); + test('false <- invalid', () => { + expect(Secp256k1.isValidPrivateKey(KEYS.private.invalid)).toBe( + false + ); }); }); - describe('Secp256k1 - sign', () => { - test('Secp256k1 - sign - success', () => { - expect(Secp256k1.sign(messageHashBuffer, privateKey)).toStrictEqual( - signature - ); + describe('sign', () => { + test('ok - valid hash', () => { + expect( + Secp256k1.sign(HASHES.valid, KEYS.private.valid) + ).toStrictEqual(SIGNATURES.valid); }); - test('Secp256k1 - sign - failure - invalid message hash', () => { - expect(() => Secp256k1.sign(invalid, privateKey)).toThrowError( - InvalidSecp256k1MessageHash - ); + test('error <- invalid hash', () => { + expect(() => + Secp256k1.sign(HASHES.invalid, KEYS.private.valid) + ).toThrowError(InvalidSecp256k1MessageHash); }); - test('Secp256k1 - sign - failure - invalid private key', () => { + test('error <- invalid private key', () => { expect(() => - Secp256k1.sign( - messageHashBuffer, - HexUInt.of( - 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - ).bytes - ) + Secp256k1.sign(HASHES.valid, KEYS.private.invalid) ).toThrowError(InvalidSecp256k1PrivateKey); }); }); - describe('Secp256k1 - randomBytes', () => { - test('Secp256k1 - randomBytes - without parameters', () => { + describe('randomBytes', () => { + test('ok <- default', () => { const result = Secp256k1.randomBytes(); - expect(result.length).toBeGreaterThan(0); + expect(result.length).toBe(32); }); - test('Secp256k1 - randomBytes - with param', () => { + test('ok <- set length', () => { const result = Secp256k1.randomBytes(16); expect(result.length).toBe(16); }); - - test('Secp256k1 - randomBytes - with param', () => { - expect(() => Secp256k1.randomBytes(28)).toBeDefined(); - }); }); - describe('Secp256k1 - recover', () => { - test('Secp256k1 - recover - success', () => { + describe('recover', () => { + test('ok < - valid', () => { expect( - Secp256k1.recover(messageHashBuffer, signature) - ).toStrictEqual(publicKeyUncompressed); + Secp256k1.recover(HASHES.valid, SIGNATURES.valid) + ).toStrictEqual(KEYS.public.uncompressed); }); - test('Secp256k1 - recover - invalid message hash', () => { - expect(() => Secp256k1.recover(invalid, signature)).toThrowError( - InvalidSecp256k1MessageHash - ); - }); - - test('Secp256k1 - recover - invalid signature', () => { - // Invalid signature + test('error <- invalid hash', () => { expect(() => - Secp256k1.recover(messageHashBuffer, invalid) - ).toThrowError(InvalidSecp256k1Signature); + Secp256k1.recover(HASHES.invalid, SIGNATURES.valid) + ).toThrowError(InvalidSecp256k1MessageHash); }); - test('Secp256k1 - recover - failure', () => { - // Invalid signature recovery - const invalidSignatureRecovery = new Uint8Array(signature); - invalidSignatureRecovery[64] = 8; + test('error <- invalid signature', () => { + // Forge an invalid signature... + const invalidSignature = new Uint8Array(SIGNATURES.valid); + // ... altering the last byte. + invalidSignature[64] = 8; expect(() => - Secp256k1.recover(messageHashBuffer, invalidSignatureRecovery) + Secp256k1.recover(HASHES.valid, invalidSignature) ).toThrowError(InvalidSecp256k1Signature); }); }); diff --git a/packages/core/tests/secp256k1/fixture.ts b/packages/core/tests/secp256k1/fixture.ts deleted file mode 100644 index e14fb1845..000000000 --- a/packages/core/tests/secp256k1/fixture.ts +++ /dev/null @@ -1,49 +0,0 @@ -import * as n_utils from '@noble/curves/abstract/utils'; -import { Keccak256, Txt } from '../../src'; - -/** - * Simple public key and private key pair with corresponding signature - */ -const privateKey = n_utils.hexToBytes( - '7582be841ca040aa940fff6c05773129e135623e41acce3e0b8ba520dc1ae26a' -); - -const publicKeyCompressed = n_utils.hexToBytes( - '03b90e9bb2617387eba4502c730de65a33878ef384a46f1096d86f2da19043304a' -); - -const publicKeyUncompressed = n_utils.hexToBytes( - '04b90e9bb2617387eba4502c730de65a33878ef384a46f1096d86f2da19043304afa67d0ad09cf2bea0c6f2d1767a9e62a7a7ecc41facf18f2fa505d92243a658f' -); - -const signature = n_utils.hexToBytes( - 'f8fe82c74f9e1f5bf443f8a7f8eb968140f554968fdcab0a6ffe904e451c8b9244be44bccb1feb34dd20d9d8943f8c131227e55861736907b02d32c06b934d7200' -); - -/** - * Simple message hashes - */ -const messageHashBuffer = Keccak256.of(Txt.of('hello world').bytes).bytes; -const validMessageHashes = [messageHashBuffer]; -const invalidMessageHashes = [Txt.of('some_invalid_stuff').bytes]; - -/** - * Valid and invalid private keys - */ -const validPrivateKeys = [ - // PLEASE: Don't use this private key for your wallet :D - n_utils.hexToBytes( - '7582be841ca040aa940fff6c05773129e135623e41acce3e0b8ba520dc1ae26a' - ) -]; - -export { - invalidMessageHashes, - messageHashBuffer, - privateKey, - publicKeyCompressed, - publicKeyUncompressed, - signature, - validMessageHashes, - validPrivateKeys -}; diff --git a/packages/core/tests/vcdm/Address.unit.test.ts b/packages/core/tests/vcdm/Address.unit.test.ts index a981131c3..efcb22c74 100644 --- a/packages/core/tests/vcdm/Address.unit.test.ts +++ b/packages/core/tests/vcdm/Address.unit.test.ts @@ -1,10 +1,6 @@ import { describe, expect, test } from '@jest/globals'; import { hexToBytes } from '@noble/ciphers/utils'; -import { - InvalidDataType, - InvalidSecp256k1PrivateKey -} from '@vechain/sdk-errors'; -import { fail } from 'assert'; +import { InvalidDataType } from '@vechain/sdk-errors'; import { Address } from '../../src'; /** @@ -13,47 +9,39 @@ import { Address } from '../../src'; */ describe('Address class tests', () => { describe('Construction tests', () => { - test('Return an Address instance if the passed argument is valid', () => { - let exp = '0xcfb79a9c950b78e14c43efa621ebcf9660dbe01f'; - let address = Address.of(exp); + test('ok <- valid lowercase', () => { + const exp = '0xcfb79a9c950b78e14c43efa621ebcf9660dbe01f'; + const address = Address.of(exp); expect(address).toBeInstanceOf(Address); - exp = '0xCfb79a9c950b78E14c43efa621ebcf9660dbe01F'; - address = Address.of(exp); + }); + + test('ok <- valid checksum format', () => { + const exp = '0xCfb79a9c950b78E14c43efa621ebcf9660dbe01F'; + const address = Address.of(exp); expect(address).toBeInstanceOf(Address); - exp = '0xCFB79A9C950B78E14C43EFA621EBCF9660DBE01F'; - address = Address.of(exp); + }); + + test('ok <- valid uppercase', () => { + const exp = '0xCFB79A9C950B78E14C43EFA621EBCF9660DBE01F'; + const address = Address.of(exp); expect(address).toBeInstanceOf(Address); - exp = '0xcaffee'; - address = Address.of(exp); + }); + + test('ok <- valid from shorter expression', () => { + const exp = '0xcaffee'; + const address = Address.of(exp); expect(address).toBeInstanceOf(Address); expect(address.toString().length).toBe(Address.DIGITS + 2); }); - test('Throw an error if the passed argument is an invalid address', () => { + + test('error <- invalid', () => { const exp = '-0xcaffee'; - try { - Address.of(exp); - fail('This should have thrown an error'); - } catch (e) { - expect(e).toBeInstanceOf(InvalidDataType); - if (e instanceof InvalidDataType) { - expect(e.message).toBe( - `Method 'Address.of' failed.` + - `\n-Reason: 'not a valid hexadecimal positive integer expression'` + - `\n-Parameters: \n\t{\n "exp": "-0xcaffee"\n}` + - `\n-Internal error: \n\tMethod 'HexUInt.of' failed.` + - `\n-Reason: 'not a hexadecimal positive integer expression'` + - `\n-Parameters: \n\t{\n "exp": "${exp}",\n "e": {\n "methodName": "HexUInt.of",\n "errorMessage": "not positive",\n "data": {\n "exp": "-0xcaffee"\n }\n }\n}` + - `\n-Internal error: ` + - `\n\tMethod 'HexUInt.of' failed.` + - `\n-Reason: 'not positive'` + - `\n-Parameters: \n\t{\n "exp": "${exp}"\n}` - ); - } - } + expect(() => Address.of(exp)).toThrow(InvalidDataType); }); }); - describe('Key tests', () => { - test('Should get the address from a given private key', () => { + + describe('ofPrivateKey', () => { + test('ok <- private key', () => { const privateKey = hexToBytes( '5434c159b817c377a55f6be66369622976014e78bce2adfd3e44e5de88ce502f' ); @@ -62,23 +50,16 @@ describe('Address class tests', () => { '0x769E8AA372c8309c834EA6749B88861FF73581FF' ); }); - test('Should throw an invalid data type error if the private key is invalid', () => { + + test('error <- invalid', () => { const privateKey = new Uint8Array([1, 2, 3, 4, 5]); - try { - Address.ofPrivateKey(privateKey); - fail('This should have thrown an error'); - } catch (e) { - expect(e).toBeInstanceOf(InvalidSecp256k1PrivateKey); - if (e instanceof InvalidSecp256k1PrivateKey) { - expect(e.message).toBe( - `Method 'Secp256k1.derivePublicKey' failed.` + - `\n-Reason: 'Invalid private key given as input. Ensure it is a valid 32-byte secp256k1 private key.'` + - `\n-Parameters: \n\tundefined` - ); - } - } + expect(() => Address.ofPrivateKey(privateKey)).toThrow( + InvalidDataType + ); }); - test('Should get the address from a given public key', () => { + }); + describe('ofPublicKey', () => { + test('ok <- valid', () => { const publicKey = hexToBytes( '04a6711e14234b1d4e69aeed2acf18b9c3bd0e97db317b509516bd3a87e5b732685ccaf855d9f8a955bc1f420b4ebf8f682c2e480d98a360e7fd0c08e6eef65607' ); @@ -87,22 +68,12 @@ describe('Address class tests', () => { '0x769E8AA372c8309c834EA6749B88861FF73581FF' ); }); - test('Should throw an invalid data type error if the public key is invalid', () => { + + test('error <- invalid', () => { const publicKey = new Uint8Array([1, 2, 3, 4, 5]); - try { - Address.ofPublicKey(publicKey); - fail('This should have thrown an error'); - } catch (e) { - expect(e).toBeInstanceOf(InvalidDataType); - if (e instanceof InvalidDataType) { - expect(e.message).toBe( - `Method 'Address.ofPublicKey' failed.` + - `\n-Reason: 'not a valid public key'` + - `\n-Parameters: \n\t{\n "publicKey": "${publicKey}"\n}` + - `\n-Internal error: \n\tPoint of length 5 was invalid. Expected 33 compressed bytes or 65 uncompressed bytes` - ); - } - } + expect(() => Address.ofPublicKey(publicKey)).toThrow( + InvalidDataType + ); }); }); });