UNPKG

ox

Version:

Ethereum Standard Library

362 lines (303 loc) 11.7 kB
import { describe, expect, test } from 'vp/test' import * as Bytes from '../Bytes.js' import * as Hex from '../Hex.js' import * as X25519 from '../X25519.js' describe('noble', () => { test('exports noble curves x25519', () => { expect(X25519.noble).toBeDefined() expect(typeof X25519.noble.getPublicKey).toBe('function') expect(typeof X25519.noble.getSharedSecret).toBe('function') expect(typeof X25519.noble.utils.randomSecretKey).toBe('function') }) }) describe('createKeyPair', () => { test('creates key pair with default format (Hex)', () => { const keyPair = X25519.createKeyPair() expect(keyPair.privateKey).toMatch(/^0x[0-9a-f]{64}$/i) expect(keyPair.publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('creates key pair with Hex format', () => { const keyPair = X25519.createKeyPair({ as: 'Hex' }) expect(keyPair.privateKey).toMatch(/^0x[0-9a-f]{64}$/i) expect(keyPair.publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('creates key pair with Bytes format', () => { const keyPair = X25519.createKeyPair({ as: 'Bytes' }) expect(keyPair.privateKey).toBeInstanceOf(Uint8Array) expect(keyPair.publicKey).toBeInstanceOf(Uint8Array) expect(keyPair.privateKey).toHaveLength(32) expect(keyPair.publicKey).toHaveLength(32) }) test('creates different key pairs on each call', () => { const keyPair1 = X25519.createKeyPair() const keyPair2 = X25519.createKeyPair() expect(keyPair1.privateKey).not.toBe(keyPair2.privateKey) expect(keyPair1.publicKey).not.toBe(keyPair2.publicKey) }) test('public key is derived from private key', () => { const keyPair = X25519.createKeyPair() const publicKey = X25519.getPublicKey({ privateKey: keyPair.privateKey }) expect(publicKey).toBe(keyPair.publicKey) }) }) describe('getPublicKey', () => { test('computes public key from private key (Hex input)', () => { const privateKey = '0x7777777777777777777777777777777777777777777777777777777777777777' const publicKey = X25519.getPublicKey({ privateKey }) expect(publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('computes public key from private key (Bytes input)', () => { const privateKey = new Uint8Array(32).fill(0x77) const publicKey = X25519.getPublicKey({ privateKey }) expect(publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('returns public key in Hex format by default', () => { const privateKey = X25519.randomPrivateKey() const publicKey = X25519.getPublicKey({ privateKey }) expect(publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('returns public key in Hex format when specified', () => { const privateKey = X25519.randomPrivateKey() const publicKey = X25519.getPublicKey({ privateKey, as: 'Hex' }) expect(publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('returns public key in Bytes format when specified', () => { const privateKey = X25519.randomPrivateKey() const publicKey = X25519.getPublicKey({ privateKey, as: 'Bytes' }) expect(publicKey).toBeInstanceOf(Uint8Array) expect(publicKey).toHaveLength(32) }) test('is deterministic - same private key produces same public key', () => { const privateKey = '0x7777777777777777777777777777777777777777777777777777777777777777' const publicKey1 = X25519.getPublicKey({ privateKey }) const publicKey2 = X25519.getPublicKey({ privateKey }) expect(publicKey1).toBe(publicKey2) }) test('different private keys produce different public keys', () => { const privateKey1 = '0x7777777777777777777777777777777777777777777777777777777777777777' const privateKey2 = '0x8888888888888888888888888888888888888888888888888888888888888888' const publicKey1 = X25519.getPublicKey({ privateKey: privateKey1 }) const publicKey2 = X25519.getPublicKey({ privateKey: privateKey2 }) expect(publicKey1).not.toBe(publicKey2) }) }) describe('getSharedSecret', () => { test('computes shared secret between two key pairs', () => { const keyPairA = X25519.createKeyPair() const keyPairB = X25519.createKeyPair() const sharedSecretA = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, }) const sharedSecretB = X25519.getSharedSecret({ privateKey: keyPairB.privateKey, publicKey: keyPairA.publicKey, }) expect(sharedSecretA).toBe(sharedSecretB) expect(sharedSecretA).toMatch(/^0x[0-9a-f]{64}$/i) }) test('computes shared secret with Hex inputs', () => { const privateKeyA = '0x7777777777777777777777777777777777777777777777777777777777777777' const publicKeyB = X25519.getPublicKey({ privateKey: '0x8888888888888888888888888888888888888888888888888888888888888888', }) const sharedSecret = X25519.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) expect(sharedSecret).toMatch(/^0x[0-9a-f]{64}$/i) }) test('computes shared secret with Bytes inputs', () => { const privateKeyA = new Uint8Array(32).fill(0x77) const publicKeyB = X25519.getPublicKey({ privateKey: new Uint8Array(32).fill(0x88), }) const sharedSecret = X25519.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) expect(sharedSecret).toMatch(/^0x[0-9a-f]{64}$/i) }) test('returns shared secret in Hex format by default', () => { const keyPairA = X25519.createKeyPair() const keyPairB = X25519.createKeyPair() const sharedSecret = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, }) expect(sharedSecret).toMatch(/^0x[0-9a-f]{64}$/i) }) test('returns shared secret in Hex format when specified', () => { const keyPairA = X25519.createKeyPair() const keyPairB = X25519.createKeyPair() const sharedSecret = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, as: 'Hex', }) expect(sharedSecret).toMatch(/^0x[0-9a-f]{64}$/i) }) test('returns shared secret in Bytes format when specified', () => { const keyPairA = X25519.createKeyPair() const keyPairB = X25519.createKeyPair() const sharedSecret = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, as: 'Bytes', }) expect(sharedSecret).toBeInstanceOf(Uint8Array) expect(sharedSecret).toHaveLength(32) }) test('is deterministic - same inputs produce same shared secret', () => { const privateKeyA = '0x7777777777777777777777777777777777777777777777777777777777777777' const publicKeyB = X25519.getPublicKey({ privateKey: '0x8888888888888888888888888888888888888888888888888888888888888888', }) const sharedSecret1 = X25519.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) const sharedSecret2 = X25519.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) expect(sharedSecret1).toBe(sharedSecret2) }) test('different key pairs produce different shared secrets', () => { const keyPairA = X25519.createKeyPair() const keyPairB = X25519.createKeyPair() const keyPairC = X25519.createKeyPair() const sharedSecretAB = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, }) const sharedSecretAC = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairC.publicKey, }) expect(sharedSecretAB).not.toBe(sharedSecretAC) }) test('mixed format inputs work correctly', () => { const privateKeyHex = '0x7777777777777777777777777777777777777777777777777777777777777777' const publicKeyBytes = X25519.getPublicKey({ privateKey: '0x8888888888888888888888888888888888888888888888888888888888888888', as: 'Bytes', }) const sharedSecret = X25519.getSharedSecret({ privateKey: privateKeyHex, publicKey: publicKeyBytes, }) expect(sharedSecret).toMatch(/^0x[0-9a-f]{64}$/i) }) }) describe('randomPrivateKey', () => { test('generates private key in Hex format by default', () => { const privateKey = X25519.randomPrivateKey() expect(privateKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('generates private key in Hex format when specified', () => { const privateKey = X25519.randomPrivateKey({ as: 'Hex' }) expect(privateKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('generates private key in Bytes format when specified', () => { const privateKey = X25519.randomPrivateKey({ as: 'Bytes' }) expect(privateKey).toBeInstanceOf(Uint8Array) expect(privateKey).toHaveLength(32) }) test('generates different private keys on each call', () => { const privateKey1 = X25519.randomPrivateKey() const privateKey2 = X25519.randomPrivateKey() expect(privateKey1).not.toBe(privateKey2) }) test('generated private keys are valid (can derive public keys)', () => { const privateKey = X25519.randomPrivateKey() const publicKey = X25519.getPublicKey({ privateKey }) expect(publicKey).toMatch(/^0x[0-9a-f]{64}$/i) }) test('generated private keys work for ECDH', () => { const privateKeyA = X25519.randomPrivateKey() const privateKeyB = X25519.randomPrivateKey() const publicKeyA = X25519.getPublicKey({ privateKey: privateKeyA }) const publicKeyB = X25519.getPublicKey({ privateKey: privateKeyB }) const sharedSecretA = X25519.getSharedSecret({ privateKey: privateKeyA, publicKey: publicKeyB, }) const sharedSecretB = X25519.getSharedSecret({ privateKey: privateKeyB, publicKey: publicKeyA, }) expect(sharedSecretA).toBe(sharedSecretB) }) }) describe('error handling', () => { test('handles invalid private key format', () => { expect(() => { X25519.getPublicKey({ privateKey: 'invalid' as any }) }).toThrow() }) test('handles invalid public key format in getSharedSecret', () => { const privateKey = X25519.randomPrivateKey() expect(() => { X25519.getSharedSecret({ privateKey, publicKey: 'invalid' as any, }) }).toThrow() }) test('handles short private key', () => { expect(() => { X25519.getPublicKey({ privateKey: '0x1234' }) }).toThrow() }) test('handles short public key in getSharedSecret', () => { const privateKey = X25519.randomPrivateKey() expect(() => { X25519.getSharedSecret({ privateKey, publicKey: '0x1234', }) }).toThrow() }) }) describe('format conversion consistency', () => { test('Hex and Bytes formats represent same values', () => { const privateKeyHex = '0x7777777777777777777777777777777777777777777777777777777777777777' const privateKeyBytes = Bytes.from(privateKeyHex) const publicKeyHex = X25519.getPublicKey({ privateKey: privateKeyHex, as: 'Hex', }) const publicKeyBytes = X25519.getPublicKey({ privateKey: privateKeyBytes, as: 'Bytes', }) expect(Hex.fromBytes(publicKeyBytes)).toBe(publicKeyHex) }) test('shared secret format conversion consistency', () => { const keyPairA = X25519.createKeyPair() const keyPairB = X25519.createKeyPair() const sharedSecretHex = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, as: 'Hex', }) const sharedSecretBytes = X25519.getSharedSecret({ privateKey: keyPairA.privateKey, publicKey: keyPairB.publicKey, as: 'Bytes', }) expect(Hex.fromBytes(sharedSecretBytes)).toBe(sharedSecretHex) }) })