import { Address, Bytes, Engine, Hex, Mnemonic, PublicKey, Secp256k1 } from 'ox' import { describe, expect, test } from 'vp/test' import { accounts } from '../../../test/constants/accounts.js' describe('getPublicKey', () => { test('default', () => { { const publicKey = Secp256k1.getPublicKey({ privateKey: accounts[0].privateKey, }) expect(publicKey).toMatchInlineSnapshot( ` { "prefix": 4, "x": "0x8318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75", "y": "0x3547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5", } `, ) expect(Address.fromPublicKey(publicKey).toLowerCase()).toEqual( accounts[0].address, ) } { const publicKey = Secp256k1.getPublicKey({ privateKey: Bytes.fromHex(accounts[0].privateKey), }) expect(publicKey).toMatchInlineSnapshot( ` { "prefix": 4, "x": "0x8318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75", "y": "0x3547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5", } `, ) expect(Address.fromPublicKey(publicKey).toLowerCase()).toEqual( accounts[0].address, ) } }) }) describe('createKeyPair', () => { test('default', () => { const keyPair = Secp256k1.createKeyPair() expect(keyPair).toHaveProperty('privateKey') expect(keyPair).toHaveProperty('publicKey') expect(typeof keyPair.privateKey).toBe('string') expect(keyPair.privateKey).toMatch(/^0x[0-9a-f]{64}$/) expect(keyPair.privateKey.length).toBe(66) expect(keyPair.publicKey).toHaveProperty('prefix') expect(keyPair.publicKey).toHaveProperty('x') expect(keyPair.publicKey).toHaveProperty('y') expect(keyPair.publicKey.prefix).toBe(4) expect(typeof keyPair.publicKey.x).toBe('string') expect(typeof keyPair.publicKey.y).toBe('string') }) test('behavior: deterministic public key derivation', () => { const keyPair = Secp256k1.createKeyPair() const derivedPublicKey = Secp256k1.getPublicKey({ privateKey: keyPair.privateKey, }) expect(keyPair.publicKey).toEqual(derivedPublicKey) }) test('behavior: unique key pairs', () => { const keyPair1 = Secp256k1.createKeyPair() const keyPair2 = Secp256k1.createKeyPair() expect(keyPair1.privateKey).not.toEqual(keyPair2.privateKey) expect(keyPair1.publicKey).not.toEqual(keyPair2.publicKey) }) test('behavior: valid for signing and verification', () => { const keyPair = Secp256k1.createKeyPair() const payload = '0xdeadbeef' const signature = Secp256k1.sign({ payload, privateKey: keyPair.privateKey, }) const isValid = Secp256k1.verify({ publicKey: keyPair.publicKey, payload, signature, }) expect(isValid).toBe(true) }) test('options: as (Hex)', () => { const keyPair = Secp256k1.createKeyPair({ as: 'Hex' }) expect(typeof keyPair.privateKey).toBe('string') expect(keyPair.privateKey).toMatch(/^0x[0-9a-f]{64}$/) expect(keyPair.privateKey.length).toBe(66) }) test('options: as (Bytes)', () => { const keyPair = Secp256k1.createKeyPair({ as: 'Bytes' }) expect(keyPair.privateKey).toBeInstanceOf(Uint8Array) expect(keyPair.privateKey.length).toBe(32) expect(keyPair.publicKey).toHaveProperty('prefix') expect(keyPair.publicKey.prefix).toBe(4) }) test('behavior: bytes format works with other functions', () => { const keyPair = Secp256k1.createKeyPair({ as: 'Bytes' }) const derivedPublicKey = Secp256k1.getPublicKey({ privateKey: keyPair.privateKey, }) expect(keyPair.publicKey).toEqual(derivedPublicKey) }) }) describe('fromPrf', () => { test.each([ { privateKey: '0xd23e6d2bbfdc109c1d4706bc3a78a32356682a4e6ef09c3bbeabf5460235de36', prf: '0x0000000000000000000000000000000000000000000000000000000000000000', }, { privateKey: '0xcf0eab798d92f274ee2b9b6f3397186cdd3a08b09c77b7313fb1abf529611bc5', prf: '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', }, ] as const)('vector: $prf', ({ privateKey, prf }) => { expect(Secp256k1.fromPrf(prf)).toBe(privateKey) }) test('value: Bytes', () => { const prf = Bytes.fromHex( '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', ) expect(Secp256k1.fromPrf(prf)).toMatchInlineSnapshot( `"0xcf0eab798d92f274ee2b9b6f3397186cdd3a08b09c77b7313fb1abf529611bc5"`, ) }) test('options: as', () => { const privateKey = Secp256k1.fromPrf( '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', { as: 'Bytes' }, ) expect(privateKey).toEqual( Bytes.fromHex( '0xcf0eab798d92f274ee2b9b6f3397186cdd3a08b09c77b7313fb1abf529611bc5', ), ) }) test('behavior: output is a valid secp256k1 private key', () => { const privateKey = Secp256k1.fromPrf(Bytes.random(32), { as: 'Bytes' }) expect(Secp256k1.noble.utils.isValidSecretKey(privateKey)).toBe(true) }) test('behavior: skips invalid scalar candidates', () => { const messages: Hex.Hex[] = [] const privateKey = Engine.with( { Hash: { hmacSha256: (_key, message) => { messages.push(Hex.fromBytes(message)) if (messages.length === 1) return new Uint8Array(32) return Bytes.fromHex( '0xef3f982137910a4c362017e69ba173fbb342325802ec827767aa6942027af35b', ) }, }, }, () => Secp256k1.fromPrf( '0x0000000000000000000000000000000000000000000000000000000000000000', ), ) expect(privateKey).toBe( '0xef3f982137910a4c362017e69ba173fbb342325802ec827767aa6942027af35b', ) expect(messages).toMatchInlineSnapshot(` [ "0x6f782e736563703235366b312e66726f6d5072662e763100000000", "0x6f782e736563703235366b312e66726f6d5072662e763100000001", ] `) }) test('error: PRF output is too short', () => { expect(() => Secp256k1.fromPrf(new Uint8Array(31))) .toThrowErrorMatchingInlineSnapshot(` [Secp256k1.InvalidPrfSizeError: PRF output must be exactly 32 bytes. Received 31 bytes.] `) }) test('error: PRF output is too long', () => { expect(() => Secp256k1.fromPrf(new Uint8Array(33))) .toThrowErrorMatchingInlineSnapshot(` [Secp256k1.InvalidPrfSizeError: PRF output must be exactly 32 bytes. Received 33 bytes.] `) }) }) describe('fromMnemonic', () => { const mnemonic = 'test test test test test test test test test test test junk' test('default', () => { const privateKey = Secp256k1.fromMnemonic(mnemonic) expect(privateKey).toBe(Mnemonic.toPrivateKey(mnemonic, { as: 'Hex' })) expect(privateKey).toMatchInlineSnapshot( `"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"`, ) }) test('options: passphrase', () => { expect( Secp256k1.fromMnemonic(mnemonic, { passphrase: 'qwerty' }), ).toMatchInlineSnapshot( `"0x0bef893b1cc27e9ce726d5f12f75d61a07d4df87c02106083463cd712ac5c478"`, ) }) test('options: as', () => { const privateKey = Secp256k1.fromMnemonic(mnemonic, { as: 'Bytes' }) expect(privateKey).toBeInstanceOf(Uint8Array) expect(privateKey).toHaveLength(32) }) test('options: path', () => { const path = "m/44'/60'/0'/0/1" expect(Secp256k1.fromMnemonic(mnemonic, { path })).toBe( Mnemonic.toPrivateKey(mnemonic, { as: 'Hex', path }), ) }) }) describe('fromSeed', () => { const seed = '0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f' test('vector', () => { expect(Secp256k1.fromSeed(seed)).toMatchInlineSnapshot( `"0x5f7dcbba41adaafa378861d78b144f7b2827e79fa994a341628f5470d5bfbdd4"`, ) }) test('value: Bytes', () => { expect(Secp256k1.fromSeed(Bytes.fromHex(seed))).toMatchInlineSnapshot( `"0x5f7dcbba41adaafa378861d78b144f7b2827e79fa994a341628f5470d5bfbdd4"`, ) }) test('options: as', () => { expect(Secp256k1.fromSeed(seed, { as: 'Bytes' })).toEqual( Bytes.fromHex( '0x5f7dcbba41adaafa378861d78b144f7b2827e79fa994a341628f5470d5bfbdd4', ), ) }) test('behavior: accepts seeds longer than 32 bytes', () => { const privateKey = Secp256k1.fromSeed(new Uint8Array(64), { as: 'Bytes' }) expect(Secp256k1.noble.utils.isValidSecretKey(privateKey)).toBe(true) }) test('behavior: domain is distinct from fromPrf', () => { expect(Secp256k1.fromSeed(seed)).not.toBe(Secp256k1.fromPrf(seed)) }) test('behavior: skips invalid scalar candidates', () => { const invalid = new Uint8Array(32).fill(0xff) const messages: Hex.Hex[] = [] const privateKey = Engine.with( { Hash: { hmacSha256: (_key, message) => { messages.push(Hex.fromBytes(message)) if (messages.length === 1) return invalid return Bytes.fromHex( '0xef3f982137910a4c362017e69ba173fbb342325802ec827767aa6942027af35b', ) }, }, }, () => Secp256k1.fromSeed(new Uint8Array(32)), ) expect(privateKey).toBe( '0xef3f982137910a4c362017e69ba173fbb342325802ec827767aa6942027af35b', ) expect(invalid).toEqual(new Uint8Array(32)) expect(messages).toMatchInlineSnapshot(` [ "0x6f782e736563703235366b312e66726f6d536565642e763100000000", "0x6f782e736563703235366b312e66726f6d536565642e763100000001", ] `) }) test('error: seed is too short', () => { expect(() => Secp256k1.fromSeed(new Uint8Array(31))) .toThrowErrorMatchingInlineSnapshot(` [Secp256k1.InvalidSeedSizeError: Seed must contain at least 32 bytes. Received 31 bytes.] `) }) }) describe('getSharedSecret', () => { test('default', () => { const privateKeyA = accounts[0].privateKey const privateKeyB = accounts[1].privateKey const publicKeyA = Secp256k1.getPublicKey({ privateKey: privateKeyA }) const publicKeyB = Secp256k1.getPublicKey({ privateKey: privateKeyB }) // Compute shared secret from A's perspective const sharedSecretA = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) // Compute shared secret from B's perspective const sharedSecretB = Secp256k1.getSharedSecret({ privateKey: privateKeyB, publicKey: publicKeyA, }) // ECDH property: both should be equal expect(sharedSecretA).toEqual(sharedSecretB) expect(typeof sharedSecretA).toBe('string') expect(sharedSecretA).toMatch(/^0x[0-9a-f]{66}$/) }) test('behavior: different input types', () => { const privateKeyA = accounts[0].privateKey const privateKeyB = accounts[1].privateKey const publicKeyB = Secp256k1.getPublicKey({ privateKey: privateKeyB }) // Test with Hex private key const sharedSecret1 = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) // Test with Bytes private key const sharedSecret2 = Secp256k1.getSharedSecret({ privateKey: Bytes.fromHex(privateKeyA), publicKey: publicKeyB, }) expect(sharedSecret1).toEqual(sharedSecret2) }) test('behavior: compressed public key', () => { const privateKeyA = accounts[0].privateKey const privateKeyB = accounts[1].privateKey const publicKeyB = Secp256k1.getPublicKey({ privateKey: privateKeyB }) const compressedPublicKeyB = PublicKey.compress(publicKeyB) const sharedSecret1 = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) const sharedSecret2 = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: compressedPublicKeyB, }) expect(sharedSecret1).toEqual(sharedSecret2) }) test('options: as', () => { const privateKeyA = accounts[0].privateKey const privateKeyB = accounts[1].privateKey const publicKeyB = Secp256k1.getPublicKey({ privateKey: privateKeyB }) // Test Hex output (default) const sharedSecretHex = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) // Test Bytes output const sharedSecretBytes = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, as: 'Bytes', }) // Verify formats expect(typeof sharedSecretHex).toBe('string') expect(sharedSecretHex).toMatch(/^0x[0-9a-f]{66}$/) expect(sharedSecretBytes).toBeInstanceOf(Uint8Array) expect(sharedSecretBytes.length).toBe(33) // 33 bytes for compressed point // Verify they represent the same data expect(Hex.fromBytes(sharedSecretBytes)).toEqual(sharedSecretHex) }) test('behavior: deterministic', () => { const privateKeyA = accounts[0].privateKey const privateKeyB = accounts[1].privateKey const publicKeyB = Secp256k1.getPublicKey({ privateKey: privateKeyB }) const sharedSecret1 = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) const sharedSecret2 = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) // Should be deterministic - same inputs produce same output expect(sharedSecret1).toEqual(sharedSecret2) }) test('behavior: different key pairs produce different secrets', () => { const privateKeyA = accounts[0].privateKey const privateKeyB = accounts[1].privateKey // Generate a third private key for testing const privateKeyC = Secp256k1.randomPrivateKey() const publicKeyB = Secp256k1.getPublicKey({ privateKey: privateKeyB }) const publicKeyC = Secp256k1.getPublicKey({ privateKey: privateKeyC }) const sharedSecretAB = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) const sharedSecretAC = Secp256k1.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyC, }) // Different key pairs should produce different shared secrets expect(sharedSecretAB).not.toEqual(sharedSecretAC) }) }) describe('randomPrivateKey', () => { test('default', () => { const privateKey = Secp256k1.randomPrivateKey() expect(privateKey.length).toBe(66) }) test('options: as', () => { const privateKey = Secp256k1.randomPrivateKey({ as: 'Bytes' }) expect(privateKey.length).toBe(32) }) }) describe('recoverAddress', () => { const address = accounts[0].address const privateKey = accounts[0].privateKey test('default', () => { const payload = '0xdeadbeef' const signature = Secp256k1.sign({ payload, privateKey }) expect(Secp256k1.recoverAddress({ payload, signature })).toBe( Address.from(address), ) }) }) describe('recoverPublicKey', () => { const privateKey = accounts[0].privateKey test('default', () => { const payload = '0xdeadbeef' const signature = Secp256k1.sign({ payload, privateKey }) expect(Secp256k1.recoverPublicKey({ payload, signature })).toStrictEqual( Secp256k1.getPublicKey({ privateKey }), ) }) }) describe('sign', () => { test('default', async () => { { const signature = Secp256k1.sign({ payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) expect(signature).toMatchInlineSnapshot( ` { "r": "0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf1", "s": "0x5fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b", "yParity": 0, } `, ) expect( Secp256k1.verify({ address: accounts[0].address, payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', signature, }), ).toBe(true) } { const signature = Secp256k1.sign({ payload: Bytes.fromHex( '0x9a74cb859ad30835ffb2da406423233c212cf6dd78e6c2c98b0c9289568954ae', ), privateKey: accounts[0].privateKey, }) expect(signature).toMatchInlineSnapshot( ` { "r": "0xc4d8bcda762d35ea79d9542b23200f46c2c1899db15bf929bbacaf609581db08", "s": "0x31538374a01206517edd934e474212a0f1e2d62e9a01cd64f1cf94ea2e098849", "yParity": 1, } `, ) expect( Secp256k1.verify({ address: accounts[0].address, payload: '0x9a74cb859ad30835ffb2da406423233c212cf6dd78e6c2c98b0c9289568954ae', signature, }), ).toBe(true) } }) test('options: extraEntropy', () => { { const signature_1 = Secp256k1.sign({ extraEntropy: false, payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) const signature_2 = Secp256k1.sign({ extraEntropy: false, payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) expect(signature_1).toEqual(signature_2) } { const signature_1 = Secp256k1.sign({ extraEntropy: Hex.random(32), payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) const signature_2 = Secp256k1.sign({ extraEntropy: Hex.random(32), payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) expect(signature_1).not.toEqual(signature_2) } { const signature_1 = Secp256k1.sign({ extraEntropy: Bytes.random(32), payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) const signature_2 = Secp256k1.sign({ extraEntropy: Bytes.random(32), payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) expect(signature_1).not.toEqual(signature_2) } }) test('options: hash', () => { const signature = Secp256k1.sign({ hash: true, payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', privateKey: accounts[0].privateKey, }) expect(signature).toMatchInlineSnapshot( ` { "r": "0x5dbae23786cd5e6400c475b88dd49ae003e28c28dd141943f9d242b028a05eae", "s": "0x43398aa40015d03a771c8b036e4525d2bf5cc8fb2a3f372f3d6f402ae69677b2", "yParity": 1, } `, ) const publicKey = Secp256k1.getPublicKey({ privateKey: accounts[0].privateKey, }) expect( Secp256k1.verify({ publicKey, hash: true, payload: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', signature, }), ).toBe(true) }) }) describe('verify', () => { const address = accounts[0].address const privateKey = accounts[0].privateKey test('behavior: verify w/ address', () => { const payload = '0xdeadbeef' const signature = Secp256k1.sign({ payload, privateKey }) expect(Secp256k1.verify({ address, payload, signature })).toBe(true) }) test('behavior: bytes payload', () => { const payload = '0xdeadbeef' const signature = Secp256k1.sign({ payload, privateKey }) expect( Secp256k1.verify({ address, payload: Bytes.fromHex(payload), signature }), ).toBe(true) }) test('behavior: verify w/ publicKey', () => { const payload = '0xdeadbeef' const { r, s } = Secp256k1.sign({ payload, privateKey }) const publicKey = Secp256k1.getPublicKey({ privateKey }) expect(Secp256k1.verify({ publicKey, payload, signature: { r, s } })).toBe( true, ) }) test('behavior: verify w/ compressed publicKey', () => { const payload = '0xdeadbeef' const { r, s } = Secp256k1.sign({ payload, privateKey }) const publicKey = Secp256k1.getPublicKey({ privateKey }) const compressed = PublicKey.compress(publicKey) expect( Secp256k1.verify({ publicKey: compressed, payload, signature: { r, s } }), ).toBe(true) }) test('options: hash', () => { const payload = '0xdeadbeef' const { r, s } = Secp256k1.sign({ hash: true, payload, privateKey }) const publicKey = Secp256k1.getPublicKey({ privateKey }) expect( Secp256k1.verify({ hash: true, publicKey, payload, signature: { r, s } }), ).toBe(true) }) }) test('exports', () => { expect(Object.keys(Secp256k1)).toMatchInlineSnapshot(` [ "noble", "createKeyPair", "fromPrf", "fromMnemonic", "fromSeed", "getPublicKey", "getSharedSecret", "randomPrivateKey", "recoverAddress", "recoverPublicKey", "sign", "verify", "InvalidPrfSizeError", "InvalidSeedSizeError", ] `) }) describe('as option', () => { test("sign + recoverPublicKey + getPublicKey: as 'Hex'", () => { const privateKey = accounts[0].privateKey const sigHex = Secp256k1.sign({ payload: '0xdeadbeef', privateKey, as: 'Hex', }) expect(typeof sigHex).toBe('string') expect((sigHex as Hex.Hex).startsWith('0x')).toBe(true) const pkHex = Secp256k1.getPublicKey({ privateKey, as: 'Hex' }) expect(typeof pkHex).toBe('string') const recoveredHex = Secp256k1.recoverPublicKey({ payload: '0xdeadbeef', signature: sigHex, as: 'Hex', }) expect(recoveredHex).toBe(pkHex) }) test("sign + recoverPublicKey + getPublicKey: as 'Bytes'", () => { const privateKey = accounts[0].privateKey const sigBytes = Secp256k1.sign({ payload: '0xdeadbeef', privateKey, as: 'Bytes', }) expect(sigBytes).toBeInstanceOf(Uint8Array) const pkBytes = Secp256k1.getPublicKey({ privateKey, as: 'Bytes' }) expect(pkBytes).toBeInstanceOf(Uint8Array) const recoveredBytes = Secp256k1.recoverPublicKey({ payload: '0xdeadbeef', signature: sigBytes, as: 'Bytes', }) expect(recoveredBytes).toEqual(pkBytes) }) test('default as remains Object (no behavior regression)', () => { const sigObj = Secp256k1.sign({ payload: '0xdeadbeef', privateKey: accounts[0].privateKey, }) expect(typeof sigObj).toBe('object') expect('r' in (sigObj as object)).toBe(true) }) test('verify accepts Hex signature + Hex publicKey', () => { const privateKey = accounts[0].privateKey const sigHex = Secp256k1.sign({ payload: '0xdeadbeef', privateKey, as: 'Hex', }) const pkHex = Secp256k1.getPublicKey({ privateKey, as: 'Hex' }) expect( Secp256k1.verify({ payload: '0xdeadbeef', publicKey: pkHex, signature: sigHex, }), ).toBe(true) }) test('verify accepts Bytes signature + Bytes publicKey', () => { const privateKey = accounts[0].privateKey const sigBytes = Secp256k1.sign({ payload: '0xdeadbeef', privateKey, as: 'Bytes', }) const pkBytes = Secp256k1.getPublicKey({ privateKey, as: 'Bytes' }) expect( Secp256k1.verify({ payload: '0xdeadbeef', publicKey: pkBytes, signature: sigBytes, }), ).toBe(true) }) test('recoverAddress accepts Hex signature', () => { const privateKey = accounts[0].privateKey const sigHex = Secp256k1.sign({ payload: '0xdeadbeef', privateKey, as: 'Hex', }) expect( Secp256k1.recoverAddress({ payload: '0xdeadbeef', signature: sigHex, }), ).toBe(Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey }))) }) test('getSharedSecret accepts Hex publicKey', () => { const a = Secp256k1.createKeyPair() const b = Secp256k1.createKeyPair() const bPubHex = PublicKey.toHex(b.publicKey) const ss1 = Secp256k1.getSharedSecret({ privateKey: a.privateKey, publicKey: bPubHex, }) const ss2 = Secp256k1.getSharedSecret({ privateKey: a.privateKey, publicKey: b.publicKey, }) expect(ss1).toBe(ss2) }) })