import { describe, expect, it } from 'vitest' import { getWebCrypto, randomBytes, timingSafeEqual } from '../src/crypto-provider.js' import { CryptoUnavailableError } from '../src/errors.js' describe('T1 crypto-provider', () => { it('getWebCrypto returns a SubtleCrypto in the node vitest environment', () => { const subtle = getWebCrypto() expect(typeof subtle.digest).toBe('function') expect(typeof subtle.generateKey).toBe('function') }) it('randomBytes(32) has length 32, differs across calls, and is not all-zero', () => { const a = randomBytes(32) const b = randomBytes(32) expect(a.length).toBe(32) expect(bytesEqual(a, b)).toBe(false) expect(a.every((x) => x === 0)).toBe(false) }) it('randomBytes rejects a non-integer / negative length (fail-fast)', () => { expect(() => randomBytes(-1)).toThrow(CryptoUnavailableError) expect(() => randomBytes(1.5)).toThrow(CryptoUnavailableError) }) describe('timingSafeEqual', () => { it('equal buffers → true', () => { expect(timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3]))).toBe(true) }) it('single-bit flip → false', () => { expect(timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 2]))).toBe(false) }) it('length mismatch → false (no short-circuit ordering)', () => { expect(timingSafeEqual(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2]))).toBe(false) expect(timingSafeEqual(new Uint8Array([1, 2]), new Uint8Array([1, 2, 3]))).toBe(false) }) it('empty buffers → true', () => { expect(timingSafeEqual(new Uint8Array(0), new Uint8Array(0))).toBe(true) }) }) }) function bytesEqual(a: Uint8Array, b: Uint8Array): boolean { if (a.length !== b.length) return false return a.every((x, i) => x === b[i]) }