// Generated, do not edit. sha256:c9e44c618374bc6218029ec68095d9d8a62c6e5839ffe1dd3084b46600ccb118 import { secp256k1, sha256, chacha20, hkdfExtract, hkdfExpand, hmac, base64, hexToBytes, utf8ToBytes, concatBytes, } from '../vendor/crypto/noble-scure.js'; const VERSION = 2; const SALT = utf8ToBytes('nip44-v2'); const MIN = 1; const MAX = 65535; const asBytes = (x) => (typeof x === 'string' ? hexToBytes(x) : x); export function conversationKey(secret, pubkey) { const shared = secp256k1.getSharedSecret(asBytes(secret), concatBytes(Uint8Array.of(2), asBytes(pubkey))); return hkdfExtract(sha256, shared.subarray(1, 33), SALT); } export function messageKeys(convKey, nonce) { const keys = hkdfExpand(sha256, asBytes(convKey), asBytes(nonce), 76); return { chachaKey: keys.subarray(0, 32), chachaNonce: keys.subarray(32, 44), hmacKey: keys.subarray(44, 76) }; } export function paddedLength(len) { if (len <= 32) return 32; const next = 1 << (Math.floor(Math.log2(len - 1)) + 1); const chunk = next <= 256 ? 32 : next / 8; return chunk * (Math.floor((len - 1) / chunk) + 1); } function pad(text) { const bytes = utf8ToBytes(text); if (bytes.length < MIN || bytes.length > MAX) throw new Error(`A NIP-44 message is ${MIN} to ${MAX} bytes.`); const out = new Uint8Array(2 + paddedLength(bytes.length)); out[0] = bytes.length >> 8; out[1] = bytes.length & 0xff; out.set(bytes, 2); return out; } function unpad(padded) { const len = (padded[0] << 8) | padded[1]; if (len < MIN || padded.length !== 2 + paddedLength(len)) throw new Error('Invalid padding.'); return new TextDecoder('utf-8', { fatal: true }).decode(padded.subarray(2, 2 + len)); } function sameBytes(a, b) { if (a.length !== b.length) return false; let d = 0; for (let i = 0; i < a.length; i++) d |= a[i] ^ b[i]; return d === 0; } export function encrypt(text, convKey, nonce = crypto.getRandomValues(new Uint8Array(32))) { const n = asBytes(nonce); const { chachaKey, chachaNonce, hmacKey } = messageKeys(convKey, n); const ciphertext = chacha20(chachaKey, chachaNonce, pad(text)); const mac = hmac(sha256, hmacKey, concatBytes(n, ciphertext)); return base64.encode(concatBytes(Uint8Array.of(VERSION), n, ciphertext, mac)); } export function decrypt(payload, convKey) { const p = String(payload ?? ''); if (!p || p[0] === '#') throw new Error('Unknown NIP-44 version.'); if (p.length < 132 || p.length > 87472) throw new Error('Invalid NIP-44 payload length.'); const data = base64.decode(p); if (data[0] !== VERSION) throw new Error(`Unknown NIP-44 version ${data[0]}.`); const nonce = data.subarray(1, 33); const ciphertext = data.subarray(33, data.length - 32); const mac = data.subarray(data.length - 32); const { chachaKey, chachaNonce, hmacKey } = messageKeys(convKey, nonce); if (!sameBytes(mac, hmac(sha256, hmacKey, concatBytes(nonce, ciphertext)))) throw new Error('Invalid MAC.'); return unpad(chacha20(chachaKey, chachaNonce, ciphertext)); }