function generatePeerId() { const bytes = new Uint8Array(8); crypto.getRandomValues(bytes); return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join(''); } async function generateSecret() { const secret = new Uint8Array(32); crypto.getRandomValues(secret); return secret; } async function commit(secret) { const hash = await crypto.subtle.digest('SHA-256', secret); return new Uint8Array(hash); } function arraysEqual(a, b) { 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; } function combine(secrets) { const result = new Uint8Array(32); for (const secret of secrets) { for (let i = 0; i < 32; i++) { result[i] ^= secret[i]; } } return result[0] & 1; } function bufToBase64(buf) { const bytes = new Uint8Array(buf); let binary = ''; for (let i = 0; i < bytes.length; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); } function base64ToBuf(base64) { const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; } function hexToBuf(hex) { const bytes = new Uint8Array(hex.length / 2); for (let i = 0; i < hex.length; i += 2) { bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16); } return bytes; }