/** * Performance Test for Signing Operations * * Validates that signing operations meet the <50ms performance requirement * across all platforms and under various load conditions. */ import { CredentialManager } from '@/core/credential-manager/CredentialManager' import { UnifiedSigner } from '@/core/credential-manager/UnifiedSigner' import { Platform } from '@/types/credential' describe('Signing Performance Test', () => { let credentialManager: CredentialManager let unifiedSigner: UnifiedSigner beforeEach(async () => { const config = { accounts: [ { id: 'perf-pacifica', name: 'Performance Test Pacifica', platform: Platform.PACIFICA, enabled: true, credentials: { type: 'ed25519' as const, privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5' } }, { id: 'perf-aster', name: 'Performance Test Aster', platform: Platform.ASTER, enabled: true, credentials: { type: 'secp256k1' as const, privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' } }, { id: 'perf-binance', name: 'Performance Test Binance', platform: Platform.BINANCE, enabled: true, credentials: { type: 'hmac' as const, apiKey: 'test-api-key', secretKey: 'test-secret-key' } } ] } credentialManager = new CredentialManager() unifiedSigner = new UnifiedSigner() await credentialManager.loadConfiguration(config) unifiedSigner.setAccountGetter(async (accountId: string) => { return credentialManager.getAccount(accountId) }) }) afterEach(async () => { await credentialManager.shutdown() }) describe('Single Operation Performance', () => { test('Pacifica signing should complete within 50ms', async () => { const message = new TextEncoder().encode('performance test message') const startTime = performance.now() const result = await credentialManager.sign('perf-pacifica', message) const duration = performance.now() - startTime expect(result.success).toBe(true) expect(duration).toBeLessThan(50) expect(result.metadata?.duration).toBeLessThan(50) }) test('Aster signing should complete within 50ms', async () => { const message = new TextEncoder().encode('performance test message') const startTime = performance.now() const result = await credentialManager.sign('perf-aster', message) const duration = performance.now() - startTime expect(result.success).toBe(true) expect(duration).toBeLessThan(50) expect(result.metadata?.duration).toBeLessThan(50) }) test('Binance signing should complete within 50ms', async () => { const message = new TextEncoder().encode('performance test message') const startTime = performance.now() const result = await credentialManager.sign('perf-binance', message) const duration = performance.now() - startTime expect(result.success).toBe(true) expect(duration).toBeLessThan(50) expect(result.metadata?.duration).toBeLessThan(50) }) test('UnifiedSigner should meet performance requirements', async () => { const message = new TextEncoder().encode('unified signer test') const platforms = [ { accountId: 'perf-pacifica', platform: Platform.PACIFICA }, { accountId: 'perf-aster', platform: Platform.ASTER }, { accountId: 'perf-binance', platform: Platform.BINANCE } ] for (const { accountId, platform } of platforms) { const startTime = performance.now() const result = await unifiedSigner.sign(accountId, message, { forcePlatform: platform, collectMetrics: true }) const duration = performance.now() - startTime expect(result.success).toBe(true) expect(duration).toBeLessThan(50) expect(result.metadata?.duration).toBeLessThan(50) } }) }) describe('Batch Operation Performance', () => { test('should handle 10 concurrent signing operations within performance limits', async () => { const message = new TextEncoder().encode('concurrent test message') const operations = Array.from({ length: 10 }, (_, i) => ({ accountId: ['perf-pacifica', 'perf-aster', 'perf-binance'][i % 3], message })) const startTime = performance.now() const results = await Promise.all( operations.map(op => credentialManager.sign(op.accountId, op.message)) ) const totalDuration = performance.now() - startTime expect(results).toHaveLength(10) expect(results.every(r => r.success)).toBe(true) // Total time for 10 concurrent operations should be reasonable expect(totalDuration).toBeLessThan(200) // Average time per operation const averageTime = totalDuration / 10 expect(averageTime).toBeLessThan(20) // Each individual operation should meet requirement results.forEach(result => { expect(result.metadata?.duration).toBeLessThan(50) }) }) test('should handle batch signing with UnifiedSigner', async () => { const message = new TextEncoder().encode('batch test message') const batchRequests = [ { accountId: 'perf-pacifica', message }, { accountId: 'perf-aster', message }, { accountId: 'perf-binance', message }, { accountId: 'perf-pacifica', message }, { accountId: 'perf-aster', message } ] const startTime = performance.now() const results = await unifiedSigner.signBatch(batchRequests) const totalDuration = performance.now() - startTime expect(results).toHaveLength(5) expect(results.every(r => r.success)).toBe(true) // Batch should complete efficiently expect(totalDuration).toBeLessThan(150) // Results should be in original order expect(results[0].accountId).toBe('perf-pacifica') expect(results[1].accountId).toBe('perf-aster') expect(results[2].accountId).toBe('perf-binance') }) }) describe('High-Load Performance', () => { test('should maintain performance under high load', async () => { const message = new TextEncoder().encode('high load test') const operationCount = 50 const operations = Array.from({ length: operationCount }, (_, i) => ({ accountId: ['perf-pacifica', 'perf-aster', 'perf-binance'][i % 3], message })) const startTime = performance.now() const results = await Promise.all( operations.map(op => credentialManager.sign(op.accountId, op.message)) ) const totalDuration = performance.now() - startTime expect(results).toHaveLength(operationCount) expect(results.every(r => r.success)).toBe(true) // Should handle 50 operations efficiently expect(totalDuration).toBeLessThan(1000) // 1 second for 50 operations // Calculate percentiles const durations = results .map(r => r.metadata?.duration || 0) .sort((a, b) => a - b) const p50 = durations[Math.floor(durations.length * 0.5)] const p95 = durations[Math.floor(durations.length * 0.95)] const p99 = durations[Math.floor(durations.length * 0.99)] expect(p50).toBeLessThan(30) // 50th percentile < 30ms expect(p95).toBeLessThan(50) // 95th percentile < 50ms (requirement) expect(p99).toBeLessThan(75) // 99th percentile < 75ms (allows for outliers) }) test('should handle sustained load without performance degradation', async () => { const message = new TextEncoder().encode('sustained load test') const batchSize = 10 const batchCount = 5 const batchResults: number[] = [] for (let batch = 0; batch < batchCount; batch++) { const operations = Array.from({ length: batchSize }, (_, i) => ({ accountId: ['perf-pacifica', 'perf-aster', 'perf-binance'][i % 3], message })) const batchStartTime = performance.now() const results = await Promise.all( operations.map(op => credentialManager.sign(op.accountId, op.message)) ) const batchDuration = performance.now() - batchStartTime expect(results.every(r => r.success)).toBe(true) batchResults.push(batchDuration) // Small delay between batches await new Promise(resolve => setTimeout(resolve, 10)) } // Performance should not degrade significantly across batches const firstBatch = batchResults[0] const lastBatch = batchResults[batchResults.length - 1] // Last batch should not be more than 50% slower than first batch expect(lastBatch).toBeLessThan(firstBatch * 1.5) // All batches should complete within reasonable time batchResults.forEach(duration => { expect(duration).toBeLessThan(200) // 10 operations in 200ms }) }) }) describe('Memory and Resource Performance', () => { test('should not leak memory during repeated operations', async () => { const message = new TextEncoder().encode('memory test') const initialMemory = process.memoryUsage() // Perform many signing operations for (let i = 0; i < 100; i++) { const accountId = ['perf-pacifica', 'perf-aster', 'perf-binance'][i % 3] const result = await credentialManager.sign(accountId, message) expect(result.success).toBe(true) } // Force garbage collection if available if (global.gc) { global.gc() await new Promise(resolve => setTimeout(resolve, 100)) } const finalMemory = process.memoryUsage() // Memory increase should be reasonable (less than 10MB) const heapIncrease = finalMemory.heapUsed - initialMemory.heapUsed expect(heapIncrease).toBeLessThan(10 * 1024 * 1024) // 10MB }) test('should maintain consistent performance across different message sizes', async () => { const messageSizes = [100, 1000, 10000, 100000] // bytes const performanceResults: Record = {} for (const size of messageSizes) { const message = new TextEncoder().encode('x'.repeat(size)) const durations: number[] = [] // Test each size multiple times for (let i = 0; i < 10; i++) { const startTime = performance.now() const result = await credentialManager.sign('perf-pacifica', message) const duration = performance.now() - startTime expect(result.success).toBe(true) durations.push(duration) } performanceResults[size] = durations } // All message sizes should meet performance requirements Object.entries(performanceResults).forEach(([size, durations]) => { const averageDuration = durations.reduce((a, b) => a + b, 0) / durations.length const maxDuration = Math.max(...durations) expect(averageDuration).toBeLessThan(50) // Average < 50ms expect(maxDuration).toBeLessThan(100) // Max < 100ms (allowing for larger messages) }) // Performance should scale reasonably with message size const avg100 = performanceResults[100].reduce((a, b) => a + b, 0) / 10 const avg100k = performanceResults[100000].reduce((a, b) => a + b, 0) / 10 // 1000x larger message should not be more than 10x slower expect(avg100k).toBeLessThan(avg100 * 10) }) }) describe('Platform-Specific Performance', () => { test('Ed25519 (Pacifica) should be fastest', async () => { const message = new TextEncoder().encode('ed25519 performance test') const iterations = 20 const durations: number[] = [] for (let i = 0; i < iterations; i++) { const startTime = performance.now() const result = await credentialManager.sign('perf-pacifica', message) const duration = performance.now() - startTime expect(result.success).toBe(true) durations.push(duration) } const averageDuration = durations.reduce((a, b) => a + b, 0) / iterations const maxDuration = Math.max(...durations) // Ed25519 should be very fast expect(averageDuration).toBeLessThan(20) expect(maxDuration).toBeLessThan(50) }) test('ECDSA (Aster) should meet performance requirements', async () => { const message = new TextEncoder().encode('ecdsa performance test') const iterations = 20 const durations: number[] = [] for (let i = 0; i < iterations; i++) { const startTime = performance.now() const result = await credentialManager.sign('perf-aster', message) const duration = performance.now() - startTime expect(result.success).toBe(true) durations.push(duration) } const averageDuration = durations.reduce((a, b) => a + b, 0) / iterations const maxDuration = Math.max(...durations) // ECDSA should meet requirements expect(averageDuration).toBeLessThan(40) expect(maxDuration).toBeLessThan(50) }) test('HMAC (Binance) should be very fast', async () => { const message = new TextEncoder().encode('hmac performance test') const iterations = 20 const durations: number[] = [] for (let i = 0; i < iterations; i++) { const startTime = performance.now() const result = await credentialManager.sign('perf-binance', message) const duration = performance.now() - startTime expect(result.success).toBe(true) durations.push(duration) } const averageDuration = durations.reduce((a, b) => a + b, 0) / iterations const maxDuration = Math.max(...durations) // HMAC should be fastest expect(averageDuration).toBeLessThan(10) expect(maxDuration).toBeLessThan(25) }) }) describe('Performance Metrics Collection', () => { test('should collect accurate performance metrics', async () => { const message = new TextEncoder().encode('metrics test') // Reset metrics unifiedSigner.resetMetrics() // Perform signing operations await unifiedSigner.sign('perf-pacifica', message, { collectMetrics: true }) await unifiedSigner.sign('perf-aster', message, { collectMetrics: true }) await unifiedSigner.sign('perf-binance', message, { collectMetrics: true }) const metrics = unifiedSigner.getMetrics() expect(metrics.totalOperations).toBe(3) expect(metrics.successfulOperations).toBe(3) expect(metrics.failedOperations).toBe(0) expect(metrics.averageSigningTime).toBeGreaterThan(0) expect(metrics.averageSigningTime).toBeLessThan(50) // Platform-specific metrics expect(metrics.platformBreakdown[Platform.PACIFICA].operations).toBe(1) expect(metrics.platformBreakdown[Platform.ASTER].operations).toBe(1) expect(metrics.platformBreakdown[Platform.BINANCE].operations).toBe(1) expect(metrics.platformBreakdown[Platform.PACIFICA].successRate).toBe(1) expect(metrics.platformBreakdown[Platform.ASTER].successRate).toBe(1) expect(metrics.platformBreakdown[Platform.BINANCE].successRate).toBe(1) }) test('should track performance degradation', async () => { const message = new TextEncoder().encode('degradation test') unifiedSigner.resetMetrics() // Perform operations and check if performance remains consistent const operationCount = 50 const checkpoints = [10, 25, 50] const performanceAtCheckpoints: number[] = [] for (let i = 1; i <= operationCount; i++) { const accountId = ['perf-pacifica', 'perf-aster', 'perf-binance'][i % 3] await unifiedSigner.sign(accountId, message, { collectMetrics: true }) if (checkpoints.includes(i)) { const metrics = unifiedSigner.getMetrics() performanceAtCheckpoints.push(metrics.averageSigningTime) } } // Performance should not degrade significantly const [perf10, perf25, perf50] = performanceAtCheckpoints expect(perf10).toBeLessThan(50) expect(perf25).toBeLessThan(50) expect(perf50).toBeLessThan(50) // Performance at 50 operations should not be more than 50% worse than at 10 expect(perf50).toBeLessThan(perf10 * 1.5) }) }) })