1(()=>{2 let g = globalThis3 if (g.fluorine) return4 let N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n, s = crypto.subtle5 let bytes = (h)=>Uint8Array.from(h.match(/../g) ?? [], (x)=>parseInt(x, 16))6 let cat = (...a)=>{7 let o = new Uint8Array(a.reduce((n, x)=>n + x.length, 0)), i = 08 for (let x of a) o.set(x, i), i += x.length9 return o10 }11 let hmac = async(k, ...a)=>new Uint8Array(await s.sign("HMAC", await s.importKey("raw", k, {name:"HMAC", hash:"SHA-256"}, false, ["sign"]), cat(...a)))12 let fail = (m)=>{ throw Error(m) }13 let pad = (n)=>{14 let c = Math.max(32, 2 ** Math.ceil(Math.log2(n)) / 8)15 return c * Math.ceil(n / c)16 }17 let chacha = (key, nonce, m)=>{18 let st = new Uint32Array(16), x = new Uint32Array(16), xb = new Uint8Array(x.buffer), o = new Uint8Array(m.length)19 st.set([0x61707865, 0x3320646e, 0x79622d32, 0x6b206574])20 st.set(new Uint32Array(key.slice().buffer), 4)21 st.set(new Uint32Array(nonce.slice().buffer), 13)22 let r = (a, b, d, n)=>{23 x[a] += x[b]24 x[d] ^= x[a]25 x[d] = x[d] << n | x[d] >>> 32 - n26 }27 let q = (a, b, c, d)=>(r(a, b, d, 16), r(c, d, b, 12), r(a, b, d, 8), r(c, d, b, 7))28 for (let i = 0; i < m.length; i += 64, st[12]++){29 x.set(st)30 for (let j = 0; j < 10; j++) for (let k = 0; k < 8; k++) k < 4 ? q(k, k + 4, k + 8, k + 12) : q(k - 4, 4 + (k + 1) % 4, 8 + (k + 2) % 4, 12 + (k + 3) % 4)31 for (let j = 0; j < 16; j++) x[j] += st[j]32 for (let j = 0; j < 64 && i + j < m.length; j++) o[i + j] = m[i + j] ^ xb[j]33 }34 return o35 }36 let keys = async(ck, nonce)=>{37 let t1 = await hmac(ck, nonce, [1]), t2 = await hmac(ck, t1, nonce, [2]), t3 = await hmac(ck, t2, nonce, [3]), k = cat(t1, t2, t3)38 return [k.slice(0, 32), k.slice(32, 44), k.slice(44, 76)]39 }40 let key = async(sk, pk)=>{41 let d = BigInt("0x" + sk)42 if (!d || d >= N) fail("bad key")43 return hmac(new TextEncoder().encode("nip44-v2"), bytes(g.helium.shared(sk, pk)))44 }45 let encrypt = async(text, ck, nonce = crypto.getRandomValues(new Uint8Array(32)))=>{46 let m = new TextEncoder().encode(text), n = m.length47 if (!n || n > 65535) fail("bad length")48 let p = new Uint8Array(2 + pad(n)), [ek, en, hk] = await keys(ck, nonce)49 p.set([n >> 8, n & 255])50 p.set(m, 2)51 let c = chacha(ek, en, p), b = cat([2], nonce, c, await hmac(hk, nonce, c)), out = ""52 for (let x of b) out += String.fromCharCode(x)53 return btoa(out)54 }55 let decrypt = async(payload, ck)=>{56 let l = payload.length57 if (payload[0] == "#") fail("unsupported version")58 if (l < 132 || l > 87472) fail("bad payload length")59 let b = Uint8Array.from(atob(payload), (x)=>x.charCodeAt(0))60 if (b.length < 99 || b.length > 65603) fail("bad data length")61 if (b[0] != 2) fail("unknown version " + b[0])62 let nonce = b.slice(1, 33), c = b.slice(33, -32), mac = b.slice(-32), [ek, en, hk] = await keys(ck, nonce), m = await hmac(hk, nonce, c), d = 063 for (let i = 0; i < 32; i++) d |= m[i] ^ mac[i]64 if (d) fail("invalid MAC")65 let p = chacha(ek, en, c), n = p[0] << 8 | p[1]66 if (!n || p.length != 2 + pad(n)) fail("invalid padding")67 return new TextDecoder().decode(p.slice(2, 2 + n))68 }69 let nip44 = (sk, sks = ()=>sk, cache = {})=>{70 let ck = (pk, k = sks())=>cache[k + pk] ||= key(k, pk)71 return {encrypt:async(pk, text)=>encrypt(text, await ck(pk)), decrypt:async(pk, payload)=>decrypt(payload, await ck(pk))}72 }73 g.fluorine = {key, encrypt, decrypt, nip44, pad}74 let signer = g.helium?.signer75 if (signer) signer.nip44 = nip44(null, ()=>g.helium.key())76})()