/** * Constant-time byte comparison. Mirrors `@shade/core` `constantTimeEqual` * but is duplicated here so the KT package has no runtime dependency on * `@shade/core` for primitive comparisons (it depends on it for error * types only). */ export function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean { if (a.length !== b.length) return false; let diff = 0; for (let i = 0; i < a.length; i++) { diff |= a[i]! ^ b[i]!; } return diff === 0; } /** * Encode bytes to standard base64 (no URL variant). Avoids platform-specific * `Buffer` so the KT package works in browsers, Bun, and Workers. */ export function toBase64(bytes: Uint8Array): string { if (typeof Buffer !== 'undefined') return Buffer.from(bytes).toString('base64'); let str = ''; for (let i = 0; i < bytes.length; i++) str += String.fromCharCode(bytes[i]!); return btoa(str); } export function fromBase64(s: string): Uint8Array { if (typeof Buffer !== 'undefined') return new Uint8Array(Buffer.from(s, 'base64')); const str = atob(s); const out = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) out[i] = str.charCodeAt(i); return out; } /** Stable hex encoding for log_id rendering. */ export function toHex(bytes: Uint8Array): string { let s = ''; for (let i = 0; i < bytes.length; i++) { s += bytes[i]!.toString(16).padStart(2, '0'); } return s; }