@unicitylabs/sphere-sdk 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -58,7 +58,9 @@ var STORAGE_KEYS_GLOBAL = {
58
58
  /** Nametag cache per address (separate from tracked addresses registry) */
59
59
  ADDRESS_NAMETAGS: "address_nametags",
60
60
  /** Active addresses registry (JSON: TrackedAddressesStorage) */
61
- TRACKED_ADDRESSES: "tracked_addresses"
61
+ TRACKED_ADDRESSES: "tracked_addresses",
62
+ /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
63
+ LAST_WALLET_EVENT_TS: "last_wallet_event_ts"
62
64
  };
63
65
  var STORAGE_KEYS_ADDRESS = {
64
66
  /** Pending transfers for this address */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../impl/browser/ipfs.ts","../../../constants.ts","../../../node_modules/@noble/hashes/src/utils.ts","../../../node_modules/@noble/hashes/src/hmac.ts","../../../node_modules/@noble/hashes/src/hkdf.ts","../../../node_modules/@noble/hashes/src/_md.ts","../../../node_modules/@noble/hashes/src/sha2.ts","../../../impl/browser/storage/IpfsStorageProvider.ts"],"sourcesContent":["/**\n * Browser IPFS Storage Provider\n *\n * Separate entry point for IPFS functionality.\n * Requires helia and @helia/* packages to be installed.\n *\n * @example\n * ```ts\n * import { IpfsStorageProvider, createIpfsStorageProvider } from '@unicitylabs/sphere-sdk/impl/browser/ipfs';\n * ```\n */\nexport {\n IpfsStorageProvider,\n createIpfsStorageProvider,\n type IpfsStorageProviderConfig,\n} from './storage/IpfsStorageProvider';\n","/**\n * SDK2 Constants\n * Default configuration values and storage keys\n */\n\n// =============================================================================\n// Storage Keys\n// =============================================================================\n\n/** Default prefix for all storage keys */\nexport const STORAGE_PREFIX = 'sphere_' as const;\n\n/**\n * Default encryption key for wallet data\n * WARNING: This is a placeholder. In production, use user-provided password.\n * This key is used when no password is provided to encrypt/decrypt mnemonic.\n */\nexport const DEFAULT_ENCRYPTION_KEY = 'sphere-default-key' as const;\n\n/**\n * Global storage keys (one per wallet, no address index)\n * Final key format: sphere_{key}\n */\nexport const STORAGE_KEYS_GLOBAL = {\n /** Encrypted BIP39 mnemonic */\n MNEMONIC: 'mnemonic',\n /** Encrypted master private key */\n MASTER_KEY: 'master_key',\n /** BIP32 chain code */\n CHAIN_CODE: 'chain_code',\n /** HD derivation path (full path like m/44'/0'/0'/0/0) */\n DERIVATION_PATH: 'derivation_path',\n /** Base derivation path (like m/44'/0'/0' without chain/index) */\n BASE_PATH: 'base_path',\n /** Derivation mode: bip32, wif_hmac, legacy_hmac */\n DERIVATION_MODE: 'derivation_mode',\n /** Wallet source: mnemonic, file, unknown */\n WALLET_SOURCE: 'wallet_source',\n /** Wallet existence flag */\n WALLET_EXISTS: 'wallet_exists',\n /** Current active address index */\n CURRENT_ADDRESS_INDEX: 'current_address_index',\n /** Nametag cache per address (separate from tracked addresses registry) */\n ADDRESS_NAMETAGS: 'address_nametags',\n /** Active addresses registry (JSON: TrackedAddressesStorage) */\n TRACKED_ADDRESSES: 'tracked_addresses',\n} as const;\n\n/**\n * Per-address storage keys (one per derived address)\n * Final key format: sphere_{DIRECT_xxx_yyy}_{key}\n * Example: sphere_DIRECT_abc123_xyz789_pending_transfers\n *\n * Note: Token data (tokens, tombstones, archived, forked) is stored via\n * TokenStorageProvider, not here. This avoids duplication.\n */\nexport const STORAGE_KEYS_ADDRESS = {\n /** Pending transfers for this address */\n PENDING_TRANSFERS: 'pending_transfers',\n /** Transfer outbox for this address */\n OUTBOX: 'outbox',\n /** Conversations for this address */\n CONVERSATIONS: 'conversations',\n /** Messages for this address */\n MESSAGES: 'messages',\n /** Transaction history for this address */\n TRANSACTION_HISTORY: 'transaction_history',\n} as const;\n\n/** @deprecated Use STORAGE_KEYS_GLOBAL and STORAGE_KEYS_ADDRESS instead */\nexport const STORAGE_KEYS = {\n ...STORAGE_KEYS_GLOBAL,\n ...STORAGE_KEYS_ADDRESS,\n} as const;\n\n/**\n * Build a per-address storage key using address identifier\n * @param addressId - Short identifier for the address (e.g., first 8 chars of pubkey hash, or direct address hash)\n * @param key - The key from STORAGE_KEYS_ADDRESS\n * @returns Key in format: \"{addressId}_{key}\" e.g., \"a1b2c3d4_tokens\"\n */\nexport function getAddressStorageKey(addressId: string, key: string): string {\n return `${addressId}_${key}`;\n}\n\n/**\n * Create a readable address identifier from directAddress or chainPubkey\n * Format: DIRECT_first6_last6 (sanitized for filesystem/storage)\n * @param directAddress - The L3 direct address (DIRECT:xxx) or chainPubkey\n * @returns Sanitized identifier like \"DIRECT_abc123_xyz789\"\n */\nexport function getAddressId(directAddress: string): string {\n // Remove DIRECT:// or DIRECT: prefix if present\n let hash = directAddress;\n if (hash.startsWith('DIRECT://')) {\n hash = hash.slice(9);\n } else if (hash.startsWith('DIRECT:')) {\n hash = hash.slice(7);\n }\n // Format: DIRECT_first6_last6 (sanitized)\n const first = hash.slice(0, 6).toLowerCase();\n const last = hash.slice(-6).toLowerCase();\n return `DIRECT_${first}_${last}`;\n}\n\n// =============================================================================\n// Nostr Defaults\n// =============================================================================\n\n/** Default Nostr relays */\nexport const DEFAULT_NOSTR_RELAYS = [\n 'wss://relay.unicity.network',\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n] as const;\n\n/** Nostr event kinds used by SDK - must match @unicitylabs/nostr-js-sdk */\nexport const NOSTR_EVENT_KINDS = {\n /** NIP-04 encrypted direct message */\n DIRECT_MESSAGE: 4,\n /** Token transfer (Unicity custom - 31113) */\n TOKEN_TRANSFER: 31113,\n /** Payment request (Unicity custom - 31115) */\n PAYMENT_REQUEST: 31115,\n /** Payment request response (Unicity custom - 31116) */\n PAYMENT_REQUEST_RESPONSE: 31116,\n /** Nametag binding (NIP-78 app-specific data) */\n NAMETAG_BINDING: 30078,\n /** Public broadcast */\n BROADCAST: 1,\n} as const;\n\n// =============================================================================\n// Aggregator (Oracle) Defaults\n// =============================================================================\n\n/**\n * Default aggregator URL\n * Note: The aggregator is conceptually an oracle - a trusted service that provides\n * verifiable truth about token state through cryptographic inclusion proofs.\n */\nexport const DEFAULT_AGGREGATOR_URL = 'https://aggregator.unicity.network/rpc' as const;\n\n/** Dev aggregator URL */\nexport const DEV_AGGREGATOR_URL = 'https://dev-aggregator.dyndns.org/rpc' as const;\n\n/** Test aggregator URL (Goggregator) */\nexport const TEST_AGGREGATOR_URL = 'https://goggregator-test.unicity.network' as const;\n\n/** Default aggregator request timeout (ms) */\nexport const DEFAULT_AGGREGATOR_TIMEOUT = 30000;\n\n/** Default API key for aggregator authentication */\nexport const DEFAULT_AGGREGATOR_API_KEY = 'sk_06365a9c44654841a366068bcfc68986' as const;\n\n// =============================================================================\n// IPFS Defaults\n// =============================================================================\n\n/** Default IPFS gateways */\nexport const DEFAULT_IPFS_GATEWAYS = [\n 'https://ipfs.unicity.network',\n 'https://dweb.link',\n 'https://ipfs.io',\n] as const;\n\n/** Unicity IPFS bootstrap peers */\nexport const DEFAULT_IPFS_BOOTSTRAP_PEERS = [\n '/dns4/unicity-ipfs2.dyndns.org/tcp/4001/p2p/12D3KooWLNi5NDPPHbrfJakAQqwBqymYTTwMQXQKEWuCrJNDdmfh',\n '/dns4/unicity-ipfs3.dyndns.org/tcp/4001/p2p/12D3KooWQ4aujVE4ShLjdusNZBdffq3TbzrwT2DuWZY9H1Gxhwn6',\n '/dns4/unicity-ipfs4.dyndns.org/tcp/4001/p2p/12D3KooWJ1ByPfUzUrpYvgxKU8NZrR8i6PU1tUgMEbQX9Hh2DEn1',\n '/dns4/unicity-ipfs5.dyndns.org/tcp/4001/p2p/12D3KooWB1MdZZGHN5B8TvWXntbycfe7Cjcz7n6eZ9eykZadvmDv',\n] as const;\n\n// =============================================================================\n// Wallet Defaults\n// =============================================================================\n\n/** Default BIP32 base path (without chain/index) */\nexport const DEFAULT_BASE_PATH = \"m/44'/0'/0'\" as const;\n\n/** Default BIP32 derivation path (full path with chain/index) */\nexport const DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0` as const;\n\n/** Coin types */\nexport const COIN_TYPES = {\n /** ALPHA token (L1 blockchain) */\n ALPHA: 'ALPHA',\n /** Test token */\n TEST: 'TEST',\n} as const;\n\n// =============================================================================\n// L1 (ALPHA Blockchain) Defaults\n// =============================================================================\n\n/** Default Fulcrum electrum server for mainnet */\nexport const DEFAULT_ELECTRUM_URL = 'wss://fulcrum.alpha.unicity.network:50004' as const;\n\n/** Testnet Fulcrum electrum server */\nexport const TEST_ELECTRUM_URL = 'wss://fulcrum.alpha.testnet.unicity.network:50004' as const;\n\n// =============================================================================\n// Network Defaults\n// =============================================================================\n\n/** Testnet Nostr relays */\nexport const TEST_NOSTR_RELAYS = [\n 'wss://nostr-relay.testnet.unicity.network',\n] as const;\n\n/** Network configurations */\nexport const NETWORKS = {\n mainnet: {\n name: 'Mainnet',\n aggregatorUrl: DEFAULT_AGGREGATOR_URL,\n nostrRelays: DEFAULT_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: DEFAULT_ELECTRUM_URL,\n },\n testnet: {\n name: 'Testnet',\n aggregatorUrl: TEST_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n dev: {\n name: 'Development',\n aggregatorUrl: DEV_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n} as const;\n\nexport type NetworkType = keyof typeof NETWORKS;\nexport type NetworkConfig = (typeof NETWORKS)[NetworkType];\n\n// =============================================================================\n// Timeouts & Limits\n// =============================================================================\n\n/** Default timeouts (ms) */\nexport const TIMEOUTS = {\n /** WebSocket connection timeout */\n WEBSOCKET_CONNECT: 10000,\n /** Nostr relay reconnect delay */\n NOSTR_RECONNECT_DELAY: 3000,\n /** Max reconnect attempts */\n MAX_RECONNECT_ATTEMPTS: 5,\n /** Proof polling interval */\n PROOF_POLL_INTERVAL: 1000,\n /** Sync interval */\n SYNC_INTERVAL: 60000,\n} as const;\n\n/** Validation limits */\nexport const LIMITS = {\n /** Min nametag length */\n NAMETAG_MIN_LENGTH: 3,\n /** Max nametag length */\n NAMETAG_MAX_LENGTH: 20,\n /** Max memo length */\n MEMO_MAX_LENGTH: 500,\n /** Max message length */\n MESSAGE_MAX_LENGTH: 10000,\n} as const;\n","/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is positive integer. */\nexport function anumber(n: number, title: string = ''): void {\n if (!Number.isSafeInteger(n) || n < 0) {\n const prefix = title && `\"${title}\" `;\n throw new Error(`${prefix}expected integer >= 0, got ${n}`);\n }\n}\n\n/** Asserts something is Uint8Array. */\nexport function abytes(value: Uint8Array, length?: number, title: string = ''): Uint8Array {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n}\n\n/** Asserts something is hash */\nexport function ahash(h: CHash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash must wrapped by utils.createHasher');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out: any, instance: any): void {\n abytes(out, undefined, 'digestInto() output');\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('\"digestInto() output\" expected to be of length >=' + min);\n }\n}\n\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays: TypedArray[]): void {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\n\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n\n/** The byte swap operation for uint32 */\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const swap8IfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n return arr;\n}\n\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\n ? (u: Uint32Array) => u\n : byteSwap32;\n\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // @ts-ignore\n if (hasHexBuiltin) return bytes.toHex();\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n // @ts-ignore\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise<void> => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise<void> {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\n\n/**\n * Converts string to bytes using UTF8 encoding.\n * Built-in doesn't validate input to be string: we do the check.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/** KDFs can accept string or Uint8Array for user convenience. */\nexport type KDFInput = string | Uint8Array;\n\n/**\n * Helper for KDFs: consumes uint8array or string.\n * When string is passed, does utf8 decoding, using TextDecoder.\n */\nexport function kdfInputToBytes(data: KDFInput, errorTitle = ''): Uint8Array {\n if (typeof data === 'string') return utf8ToBytes(data);\n return abytes(data, undefined, errorTitle);\n}\n\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\ntype EmptyObj = {};\n/** Merges default options and passed options. */\nexport function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('options must be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Common interface for all hashes. */\nexport interface Hash<T> {\n blockLen: number; // Bytes per block\n outputLen: number; // Bytes in output\n update(buf: Uint8Array): this;\n digestInto(buf: Uint8Array): void;\n digest(): Uint8Array;\n destroy(): void;\n _cloneInto(to?: T): T;\n clone(): T;\n}\n\n/** PseudoRandom (number) Generator */\nexport interface PRG {\n addEntropy(seed: Uint8Array): void;\n randomBytes(length: number): Uint8Array;\n clean(): void;\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF<T extends Hash<T>> = Hash<T> & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\n/** Hash constructor */\nexport type HasherCons<T, Opts = undefined> = Opts extends undefined ? () => T : (opts?: Opts) => T;\n/** Optional hash params. */\nexport type HashInfo = {\n oid?: Uint8Array; // DER encoded OID in bytes\n};\n/** Hash function */\nexport type CHash<T extends Hash<T> = Hash<any>, Opts = undefined> = {\n outputLen: number;\n blockLen: number;\n} & HashInfo &\n (Opts extends undefined\n ? {\n (msg: Uint8Array): Uint8Array;\n create(): T;\n }\n : {\n (msg: Uint8Array, opts?: Opts): Uint8Array;\n create(opts?: Opts): T;\n });\n/** XOF with output */\nexport type CHashXOF<T extends HashXOF<T> = HashXOF<any>, Opts = undefined> = CHash<T, Opts>;\n\n/** Creates function with outputLen, blockLen, create properties from a class constructor. */\nexport function createHasher<T extends Hash<T>, Opts = undefined>(\n hashCons: HasherCons<T, Opts>,\n info: HashInfo = {}\n): CHash<T, Opts> {\n const hashC: any = (msg: Uint8Array, opts?: Opts) => hashCons(opts).update(msg).digest();\n const tmp = hashCons(undefined);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: Opts) => hashCons(opts);\n Object.assign(hashC, info);\n return Object.freeze(hashC);\n}\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n const cr = typeof globalThis === 'object' ? (globalThis as any).crypto : null;\n if (typeof cr?.getRandomValues !== 'function')\n throw new Error('crypto.getRandomValues must be defined');\n return cr.getRandomValues(new Uint8Array(bytesLength));\n}\n\n/** Creates OID opts for NIST hashes, with prefix 06 09 60 86 48 01 65 03 04 02. */\nexport const oidNist = (suffix: number): Required<HashInfo> => ({\n oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),\n});\n","/**\n * HMAC: RFC2104 message authentication code.\n * @module\n */\nimport { abytes, aexists, ahash, clean, type CHash, type Hash } from './utils.ts';\n\n/** Internal class for HMAC. */\nexport class _HMAC<T extends Hash<T>> implements Hash<_HMAC<T>> {\n oHash: T;\n iHash: T;\n blockLen: number;\n outputLen: number;\n private finished = false;\n private destroyed = false;\n\n constructor(hash: CHash, key: Uint8Array) {\n ahash(hash);\n abytes(key, undefined, 'key');\n this.iHash = hash.create() as T;\n if (typeof this.iHash.update !== 'function')\n throw new Error('Expected instance of class which extends utils.Hash');\n this.blockLen = this.iHash.blockLen;\n this.outputLen = this.iHash.outputLen;\n const blockLen = this.blockLen;\n const pad = new Uint8Array(blockLen);\n // blockLen can be bigger than outputLen\n pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;\n this.iHash.update(pad);\n // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone\n this.oHash = hash.create() as T;\n // Undo internal XOR && apply outer XOR\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;\n this.oHash.update(pad);\n clean(pad);\n }\n update(buf: Uint8Array): this {\n aexists(this);\n this.iHash.update(buf);\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n abytes(out, this.outputLen, 'output');\n this.finished = true;\n this.iHash.digestInto(out);\n this.oHash.update(out);\n this.oHash.digestInto(out);\n this.destroy();\n }\n digest(): Uint8Array {\n const out = new Uint8Array(this.oHash.outputLen);\n this.digestInto(out);\n return out;\n }\n _cloneInto(to?: _HMAC<T>): _HMAC<T> {\n // Create new instance without calling constructor since key already in state and we don't know it.\n to ||= Object.create(Object.getPrototypeOf(this), {});\n const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;\n to = to as this;\n to.finished = finished;\n to.destroyed = destroyed;\n to.blockLen = blockLen;\n to.outputLen = outputLen;\n to.oHash = oHash._cloneInto(to.oHash);\n to.iHash = iHash._cloneInto(to.iHash);\n return to;\n }\n clone(): _HMAC<T> {\n return this._cloneInto();\n }\n destroy(): void {\n this.destroyed = true;\n this.oHash.destroy();\n this.iHash.destroy();\n }\n}\n\n/**\n * HMAC: RFC2104 message authentication code.\n * @param hash - function that would be used e.g. sha256\n * @param key - message key\n * @param message - message data\n * @example\n * import { hmac } from '@noble/hashes/hmac';\n * import { sha256 } from '@noble/hashes/sha2';\n * const mac1 = hmac(sha256, 'key', 'message');\n */\nexport const hmac: {\n (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array;\n create(hash: CHash, key: Uint8Array): _HMAC<any>;\n} = (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array =>\n new _HMAC<any>(hash, key).update(message).digest();\nhmac.create = (hash: CHash, key: Uint8Array) => new _HMAC<any>(hash, key);\n","/**\n * HKDF (RFC 5869): extract + expand in one step.\n * See https://soatok.blog/2021/11/17/understanding-hkdf/.\n * @module\n */\nimport { hmac } from './hmac.ts';\nimport { abytes, ahash, anumber, type CHash, clean } from './utils.ts';\n\n/**\n * HKDF-extract from spec. Less important part. `HKDF-Extract(IKM, salt) -> PRK`\n * Arguments position differs from spec (IKM is first one, since it is not optional)\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n */\nexport function extract(hash: CHash, ikm: Uint8Array, salt?: Uint8Array): Uint8Array {\n ahash(hash);\n // NOTE: some libraries treat zero-length array as 'not provided';\n // we don't, since we have undefined as 'not provided'\n // https://github.com/RustCrypto/KDFs/issues/15\n if (salt === undefined) salt = new Uint8Array(hash.outputLen);\n return hmac(hash, salt, ikm);\n}\n\nconst HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);\nconst EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();\n\n/**\n * HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM`\n * @param hash - hash function that would be used (e.g. sha256)\n * @param prk - a pseudorandom key of at least HashLen octets (usually, the output from the extract step)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n */\nexport function expand(\n hash: CHash,\n prk: Uint8Array,\n info?: Uint8Array,\n length: number = 32\n): Uint8Array {\n ahash(hash);\n anumber(length, 'length');\n const olen = hash.outputLen;\n if (length > 255 * olen) throw new Error('Length must be <= 255*HashLen');\n const blocks = Math.ceil(length / olen);\n if (info === undefined) info = EMPTY_BUFFER;\n else abytes(info, undefined, 'info');\n // first L(ength) octets of T\n const okm = new Uint8Array(blocks * olen);\n // Re-use HMAC instance between blocks\n const HMAC = hmac.create(hash, prk);\n const HMACTmp = HMAC._cloneInto();\n const T = new Uint8Array(HMAC.outputLen);\n for (let counter = 0; counter < blocks; counter++) {\n HKDF_COUNTER[0] = counter + 1;\n // T(0) = empty string (zero length)\n // T(N) = HMAC-Hash(PRK, T(N-1) | info | N)\n HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T)\n .update(info)\n .update(HKDF_COUNTER)\n .digestInto(T);\n okm.set(T, olen * counter);\n HMAC._cloneInto(HMACTmp);\n }\n HMAC.destroy();\n HMACTmp.destroy();\n clean(T, HKDF_COUNTER);\n return okm.slice(0, length);\n}\n\n/**\n * HKDF (RFC 5869): derive keys from an initial input.\n * Combines hkdf_extract + hkdf_expand in one step\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n * @example\n * import { hkdf } from '@noble/hashes/hkdf';\n * import { sha256 } from '@noble/hashes/sha2';\n * import { randomBytes } from '@noble/hashes/utils';\n * const inputKey = randomBytes(32);\n * const salt = randomBytes(32);\n * const info = 'application-key';\n * const hk1 = hkdf(sha256, inputKey, salt, info, 32);\n */\nexport const hkdf = (\n hash: CHash,\n ikm: Uint8Array,\n salt: Uint8Array | undefined,\n info: Uint8Array | undefined,\n length: number\n): Uint8Array => expand(hash, extract(hash, ikm, salt), info, length);\n","/**\n * Internal Merkle-Damgard hash utils.\n * @module\n */\nimport { abytes, aexists, aoutput, clean, createView, type Hash } from './utils.ts';\n\n/** Choice: a ? b : c */\nexport function Chi(a: number, b: number, c: number): number {\n return (a & b) ^ (~a & c);\n}\n\n/** Majority function, true if any two inputs is true. */\nexport function Maj(a: number, b: number, c: number): number {\n return (a & b) ^ (a & c) ^ (b & c);\n}\n\n/**\n * Merkle-Damgard hash construction base class.\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\n */\nexport abstract class HashMD<T extends HashMD<T>> implements Hash<T> {\n protected abstract process(buf: DataView, offset: number): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected abstract roundClean(): void;\n\n readonly blockLen: number;\n readonly outputLen: number;\n readonly padOffset: number;\n readonly isLE: boolean;\n\n // For partial updates less than block size\n protected buffer: Uint8Array;\n protected view: DataView;\n protected finished = false;\n protected length = 0;\n protected pos = 0;\n protected destroyed = false;\n\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data: Uint8Array): this {\n aexists(this);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n // Fast path: we have at least one block in input, cast it to view and process\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n // Padding\n // We can avoid allocation of buffer for padding completely if it\n // was previously not allocated here. But it won't change performance.\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n // append the bit '1' to the message\n buffer[pos++] = 0b10000000;\n clean(this.buffer.subarray(pos));\n // we have less than padOffset left in buffer, so we cannot put length in\n // current block, need process it and pad again\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n // Pad until full block byte with zeros\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\n // So we just write lowest 64 bits of that value.\n view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT\n if (len % 4) throw new Error('_sha2: outputLen must be aligned to 32bit');\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n to ||= new (this.constructor as any)() as T;\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen) to.buffer.set(buffer);\n return to as unknown as any;\n }\n clone(): T {\n return this._cloneInto();\n }\n}\n\n/**\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\n */\n\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n]);\n\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\n]);\n\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\n]);\n\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\n]);\n","/**\n * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.\n * SHA256 is the fastest hash implementable in JS, even faster than Blake3.\n * Check out [RFC 4634](https://www.rfc-editor.org/rfc/rfc4634) and\n * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\n * @module\n */\nimport { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from './_md.ts';\nimport * as u64 from './_u64.ts';\nimport { type CHash, clean, createHasher, oidNist, rotr } from './utils.ts';\n\n/**\n * Round constants:\n * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)\n */\n// prettier-ignore\nconst SHA256_K = /* @__PURE__ */ Uint32Array.from([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n]);\n\n/** Reusable temporary buffer. \"W\" comes straight from spec. */\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\n\n/** Internal 32-byte base SHA2 hash class. */\nabstract class SHA2_32B<T extends SHA2_32B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected abstract A: number;\n protected abstract B: number;\n protected abstract C: number;\n protected abstract D: number;\n protected abstract E: number;\n protected abstract F: number;\n protected abstract G: number;\n protected abstract H: number;\n\n constructor(outputLen: number) {\n super(64, outputLen, 8, false);\n }\n protected get(): [number, number, number, number, number, number, number, number] {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n protected set(\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\n ): void {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\n }\n // Compression function main loop, 64 rounds\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\n H = G;\n G = F;\n F = E;\n E = (D + T1) | 0;\n D = C;\n C = B;\n B = A;\n A = (T1 + T2) | 0;\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n E = (E + this.E) | 0;\n F = (F + this.F) | 0;\n G = (G + this.G) | 0;\n H = (H + this.H) | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n protected roundClean(): void {\n clean(SHA256_W);\n }\n destroy(): void {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n}\n\n/** Internal SHA2-256 hash class. */\nexport class _SHA256 extends SHA2_32B<_SHA256> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected A: number = SHA256_IV[0] | 0;\n protected B: number = SHA256_IV[1] | 0;\n protected C: number = SHA256_IV[2] | 0;\n protected D: number = SHA256_IV[3] | 0;\n protected E: number = SHA256_IV[4] | 0;\n protected F: number = SHA256_IV[5] | 0;\n protected G: number = SHA256_IV[6] | 0;\n protected H: number = SHA256_IV[7] | 0;\n constructor() {\n super(32);\n }\n}\n\n/** Internal SHA2-224 hash class. */\nexport class _SHA224 extends SHA2_32B<_SHA224> {\n protected A: number = SHA224_IV[0] | 0;\n protected B: number = SHA224_IV[1] | 0;\n protected C: number = SHA224_IV[2] | 0;\n protected D: number = SHA224_IV[3] | 0;\n protected E: number = SHA224_IV[4] | 0;\n protected F: number = SHA224_IV[5] | 0;\n protected G: number = SHA224_IV[6] | 0;\n protected H: number = SHA224_IV[7] | 0;\n constructor() {\n super(28);\n }\n}\n\n// SHA2-512 is slower than sha256 in js because u64 operations are slow.\n\n// Round contants\n// First 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409\n// prettier-ignore\nconst K512 = /* @__PURE__ */ (() => u64.split([\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\n].map(n => BigInt(n))))();\nconst SHA512_Kh = /* @__PURE__ */ (() => K512[0])();\nconst SHA512_Kl = /* @__PURE__ */ (() => K512[1])();\n\n// Reusable temporary buffers\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\n\n/** Internal 64-byte base SHA2 hash class. */\nabstract class SHA2_64B<T extends SHA2_64B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n // h -- high 32 bits, l -- low 32 bits\n protected abstract Ah: number;\n protected abstract Al: number;\n protected abstract Bh: number;\n protected abstract Bl: number;\n protected abstract Ch: number;\n protected abstract Cl: number;\n protected abstract Dh: number;\n protected abstract Dl: number;\n protected abstract Eh: number;\n protected abstract El: number;\n protected abstract Fh: number;\n protected abstract Fl: number;\n protected abstract Gh: number;\n protected abstract Gl: number;\n protected abstract Hh: number;\n protected abstract Hl: number;\n\n constructor(outputLen: number) {\n super(128, outputLen, 16, false);\n }\n // prettier-ignore\n protected get(): [\n number, number, number, number, number, number, number, number,\n number, number, number, number, number, number, number, number\n ] {\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\n }\n // prettier-ignore\n protected set(\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\n ): void {\n this.Ah = Ah | 0;\n this.Al = Al | 0;\n this.Bh = Bh | 0;\n this.Bl = Bl | 0;\n this.Ch = Ch | 0;\n this.Cl = Cl | 0;\n this.Dh = Dh | 0;\n this.Dl = Dl | 0;\n this.Eh = Eh | 0;\n this.El = El | 0;\n this.Fh = Fh | 0;\n this.Fl = Fl | 0;\n this.Gh = Gh | 0;\n this.Gl = Gl | 0;\n this.Hh = Hh | 0;\n this.Hl = Hl | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) {\n SHA512_W_H[i] = view.getUint32(offset);\n SHA512_W_L[i] = view.getUint32((offset += 4));\n }\n for (let i = 16; i < 80; i++) {\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\n const W15h = SHA512_W_H[i - 15] | 0;\n const W15l = SHA512_W_L[i - 15] | 0;\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\n const W2h = SHA512_W_H[i - 2] | 0;\n const W2l = SHA512_W_L[i - 2] | 0;\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\n SHA512_W_H[i] = SUMh | 0;\n SHA512_W_L[i] = SUMl | 0;\n }\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n // Compression function main loop, 80 rounds\n for (let i = 0; i < 80; i++) {\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\n const CHIl = (El & Fl) ^ (~El & Gl);\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\n // prettier-ignore\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\n const T1l = T1ll | 0;\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\n Hh = Gh | 0;\n Hl = Gl | 0;\n Gh = Fh | 0;\n Gl = Fl | 0;\n Fh = Eh | 0;\n Fl = El | 0;\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\n Dh = Ch | 0;\n Dl = Cl | 0;\n Ch = Bh | 0;\n Cl = Bl | 0;\n Bh = Ah | 0;\n Bl = Al | 0;\n const All = u64.add3L(T1l, sigma0l, MAJl);\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\n Al = All | 0;\n }\n // Add the compressed chunk to the current hash value\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\n }\n protected roundClean(): void {\n clean(SHA512_W_H, SHA512_W_L);\n }\n destroy(): void {\n clean(this.buffer);\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\n/** Internal SHA2-512 hash class. */\nexport class _SHA512 extends SHA2_64B<_SHA512> {\n protected Ah: number = SHA512_IV[0] | 0;\n protected Al: number = SHA512_IV[1] | 0;\n protected Bh: number = SHA512_IV[2] | 0;\n protected Bl: number = SHA512_IV[3] | 0;\n protected Ch: number = SHA512_IV[4] | 0;\n protected Cl: number = SHA512_IV[5] | 0;\n protected Dh: number = SHA512_IV[6] | 0;\n protected Dl: number = SHA512_IV[7] | 0;\n protected Eh: number = SHA512_IV[8] | 0;\n protected El: number = SHA512_IV[9] | 0;\n protected Fh: number = SHA512_IV[10] | 0;\n protected Fl: number = SHA512_IV[11] | 0;\n protected Gh: number = SHA512_IV[12] | 0;\n protected Gl: number = SHA512_IV[13] | 0;\n protected Hh: number = SHA512_IV[14] | 0;\n protected Hl: number = SHA512_IV[15] | 0;\n\n constructor() {\n super(64);\n }\n}\n\n/** Internal SHA2-384 hash class. */\nexport class _SHA384 extends SHA2_64B<_SHA384> {\n protected Ah: number = SHA384_IV[0] | 0;\n protected Al: number = SHA384_IV[1] | 0;\n protected Bh: number = SHA384_IV[2] | 0;\n protected Bl: number = SHA384_IV[3] | 0;\n protected Ch: number = SHA384_IV[4] | 0;\n protected Cl: number = SHA384_IV[5] | 0;\n protected Dh: number = SHA384_IV[6] | 0;\n protected Dl: number = SHA384_IV[7] | 0;\n protected Eh: number = SHA384_IV[8] | 0;\n protected El: number = SHA384_IV[9] | 0;\n protected Fh: number = SHA384_IV[10] | 0;\n protected Fl: number = SHA384_IV[11] | 0;\n protected Gh: number = SHA384_IV[12] | 0;\n protected Gl: number = SHA384_IV[13] | 0;\n protected Hh: number = SHA384_IV[14] | 0;\n protected Hl: number = SHA384_IV[15] | 0;\n\n constructor() {\n super(48);\n }\n}\n\n/**\n * Truncated SHA512/256 and SHA512/224.\n * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as \"intermediary\" IV of SHA512/t.\n * Then t hashes string to produce result IV.\n * See `test/misc/sha2-gen-iv.js`.\n */\n\n/** SHA512/224 IV */\nconst T224_IV = /* @__PURE__ */ Uint32Array.from([\n 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf,\n 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1,\n]);\n\n/** SHA512/256 IV */\nconst T256_IV = /* @__PURE__ */ Uint32Array.from([\n 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd,\n 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2,\n]);\n\n/** Internal SHA2-512/224 hash class. */\nexport class _SHA512_224 extends SHA2_64B<_SHA512_224> {\n protected Ah: number = T224_IV[0] | 0;\n protected Al: number = T224_IV[1] | 0;\n protected Bh: number = T224_IV[2] | 0;\n protected Bl: number = T224_IV[3] | 0;\n protected Ch: number = T224_IV[4] | 0;\n protected Cl: number = T224_IV[5] | 0;\n protected Dh: number = T224_IV[6] | 0;\n protected Dl: number = T224_IV[7] | 0;\n protected Eh: number = T224_IV[8] | 0;\n protected El: number = T224_IV[9] | 0;\n protected Fh: number = T224_IV[10] | 0;\n protected Fl: number = T224_IV[11] | 0;\n protected Gh: number = T224_IV[12] | 0;\n protected Gl: number = T224_IV[13] | 0;\n protected Hh: number = T224_IV[14] | 0;\n protected Hl: number = T224_IV[15] | 0;\n\n constructor() {\n super(28);\n }\n}\n\n/** Internal SHA2-512/256 hash class. */\nexport class _SHA512_256 extends SHA2_64B<_SHA512_256> {\n protected Ah: number = T256_IV[0] | 0;\n protected Al: number = T256_IV[1] | 0;\n protected Bh: number = T256_IV[2] | 0;\n protected Bl: number = T256_IV[3] | 0;\n protected Ch: number = T256_IV[4] | 0;\n protected Cl: number = T256_IV[5] | 0;\n protected Dh: number = T256_IV[6] | 0;\n protected Dl: number = T256_IV[7] | 0;\n protected Eh: number = T256_IV[8] | 0;\n protected El: number = T256_IV[9] | 0;\n protected Fh: number = T256_IV[10] | 0;\n protected Fl: number = T256_IV[11] | 0;\n protected Gh: number = T256_IV[12] | 0;\n protected Gl: number = T256_IV[13] | 0;\n protected Hh: number = T256_IV[14] | 0;\n protected Hl: number = T256_IV[15] | 0;\n\n constructor() {\n super(32);\n }\n}\n\n/**\n * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:\n *\n * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.\n * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\n * - Each sha256 hash is executing 2^18 bit operations.\n * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.\n */\nexport const sha256: CHash<_SHA256> = /* @__PURE__ */ createHasher(\n () => new _SHA256(),\n /* @__PURE__ */ oidNist(0x01)\n);\n/** SHA2-224 hash function from RFC 4634 */\nexport const sha224: CHash<_SHA224> = /* @__PURE__ */ createHasher(\n () => new _SHA224(),\n /* @__PURE__ */ oidNist(0x04)\n);\n\n/** SHA2-512 hash function from RFC 4634. */\nexport const sha512: CHash<_SHA512> = /* @__PURE__ */ createHasher(\n () => new _SHA512(),\n /* @__PURE__ */ oidNist(0x03)\n);\n/** SHA2-384 hash function from RFC 4634. */\nexport const sha384: CHash<_SHA384> = /* @__PURE__ */ createHasher(\n () => new _SHA384(),\n /* @__PURE__ */ oidNist(0x02)\n);\n\n/**\n * SHA2-512/256 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_256: CHash<_SHA512_256> = /* @__PURE__ */ createHasher(\n () => new _SHA512_256(),\n /* @__PURE__ */ oidNist(0x06)\n);\n/**\n * SHA2-512/224 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_224: CHash<_SHA512_224> = /* @__PURE__ */ createHasher(\n () => new _SHA512_224(),\n /* @__PURE__ */ oidNist(0x05)\n);\n","/**\n * Browser IPFS Storage Provider\n * Implements TokenStorageProvider using IPFS/IPNS for decentralized storage\n *\n * Uses a hybrid approach:\n * - HTTP API to backend gateways for fast publishing/resolution\n * - Helia for browser-based DHT operations as backup\n */\n\nimport type { ProviderStatus, FullIdentity } from '../../../types';\nimport type {\n TokenStorageProvider,\n TxfStorageDataBase,\n TxfTombstone,\n SaveResult,\n LoadResult,\n SyncResult,\n StorageEvent,\n StorageEventCallback,\n} from '../../../storage';\nimport {\n DEFAULT_IPFS_GATEWAYS,\n DEFAULT_IPFS_BOOTSTRAP_PEERS,\n} from '../../../constants';\n\n// Helia and IPFS types (runtime imports are dynamic)\nimport type { Helia } from 'helia';\nimport type { JSON as HeliaJSON } from '@helia/json';\nimport type { PrivateKey } from '@libp2p/interface';\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\n\n// Dynamic import cache\nlet heliaModule: typeof import('helia') | null = null;\nlet heliaJsonModule: typeof import('@helia/json') | null = null;\nlet libp2pBootstrapModule: typeof import('@libp2p/bootstrap') | null = null;\nlet libp2pCryptoModule: typeof import('@libp2p/crypto/keys') | null = null;\nlet libp2pPeerIdModule: typeof import('@libp2p/peer-id') | null = null;\nlet multiformatsCidModule: typeof import('multiformats/cid') | null = null;\n\nasync function loadHeliaModules() {\n if (!heliaModule) {\n [\n heliaModule,\n heliaJsonModule,\n libp2pBootstrapModule,\n libp2pCryptoModule,\n libp2pPeerIdModule,\n multiformatsCidModule,\n ] = await Promise.all([\n import('helia'),\n import('@helia/json'),\n import('@libp2p/bootstrap'),\n import('@libp2p/crypto/keys'),\n import('@libp2p/peer-id'),\n import('multiformats/cid'),\n ]);\n }\n return {\n createHelia: heliaModule!.createHelia,\n json: heliaJsonModule!.json,\n bootstrap: libp2pBootstrapModule!.bootstrap,\n generateKeyPairFromSeed: libp2pCryptoModule!.generateKeyPairFromSeed,\n peerIdFromPrivateKey: libp2pPeerIdModule!.peerIdFromPrivateKey,\n CID: multiformatsCidModule!.CID,\n };\n}\n\n/** HKDF info for IPNS key derivation */\nconst HKDF_INFO = new TextEncoder().encode('ipfs-storage-key');\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface IpfsStorageProviderConfig {\n /** IPFS gateway URLs for HTTP API */\n gateways?: string[];\n /** Bootstrap peers for DHT */\n bootstrapPeers?: string[];\n /** Enable IPNS for mutable addressing */\n enableIpns?: boolean;\n /** IPNS publish timeout (ms) */\n ipnsTimeout?: number;\n /** Content fetch timeout (ms) */\n fetchTimeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class IpfsStorageProvider<TData extends TxfStorageDataBase = TxfStorageDataBase>\n implements TokenStorageProvider<TData>\n{\n readonly id = 'ipfs';\n readonly name = 'IPFS Storage';\n readonly type = 'p2p' as const;\n readonly description = 'Decentralized storage via IPFS/IPNS';\n\n private config: Required<IpfsStorageProviderConfig>;\n private identity: FullIdentity | null = null;\n private status: ProviderStatus = 'disconnected';\n private ipnsName: string | null = null;\n private lastCid: string | null = null;\n private eventCallbacks: Set<StorageEventCallback> = new Set();\n\n // Helia instance for browser-based IPFS\n private helia: Helia | null = null;\n private heliaJson: HeliaJSON | null = null;\n private ipnsKeyPair: PrivateKey | null = null;\n\n /** Get the last published CID */\n getLastCid(): string | null {\n return this.lastCid;\n }\n\n // Local cache for faster loads\n private localCache: TData | null = null;\n private cacheTimestamp = 0;\n\n constructor(config?: IpfsStorageProviderConfig) {\n this.config = {\n gateways: config?.gateways ?? [...DEFAULT_IPFS_GATEWAYS],\n bootstrapPeers: config?.bootstrapPeers ?? [...DEFAULT_IPFS_BOOTSTRAP_PEERS],\n enableIpns: config?.enableIpns ?? true,\n ipnsTimeout: config?.ipnsTimeout ?? 30000,\n fetchTimeout: config?.fetchTimeout ?? 15000,\n debug: config?.debug ?? false,\n };\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n try {\n // Test gateway connectivity first (fast path)\n await this.testGatewayConnectivity();\n\n // Initialize Helia for browser-based DHT\n await this.initializeHelia();\n\n this.status = 'connected';\n this.log('Connected to IPFS gateways and Helia initialized');\n } catch (error) {\n this.status = 'error';\n throw new Error(`IPFS connection failed: ${error}`);\n }\n }\n\n /**\n * Initialize Helia browser IPFS node\n */\n private async initializeHelia(): Promise<void> {\n if (this.helia) return;\n\n try {\n this.log('Initializing Helia with bootstrap peers...');\n\n const { createHelia, json, bootstrap } = await loadHeliaModules();\n\n this.helia = await createHelia({\n libp2p: {\n peerDiscovery: [\n bootstrap({ list: this.config.bootstrapPeers }),\n ],\n connectionManager: {\n maxConnections: 10,\n },\n },\n });\n\n this.heliaJson = json(this.helia);\n\n const peerId = this.helia.libp2p.peerId.toString();\n this.log('Helia initialized, browser peer ID:', peerId.slice(0, 20) + '...');\n\n // Log connections after a short delay\n setTimeout(() => {\n const connections = this.helia?.libp2p.getConnections() || [];\n this.log(`Active Helia connections: ${connections.length}`);\n }, 3000);\n } catch (error) {\n this.log('Helia initialization failed (will use HTTP only):', error);\n // Non-fatal - HTTP gateways still work\n }\n }\n\n async disconnect(): Promise<void> {\n // Stop Helia\n if (this.helia) {\n try {\n await this.helia.stop();\n } catch (error) {\n this.log('Error stopping Helia:', error);\n }\n this.helia = null;\n this.heliaJson = null;\n }\n\n this.status = 'disconnected';\n this.localCache = null;\n this.ipnsKeyPair = null;\n this.log('Disconnected from IPFS');\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // TokenStorageProvider Implementation\n // ===========================================================================\n\n async setIdentity(identity: FullIdentity): Promise<void> {\n this.identity = identity;\n\n // Derive IPNS key pair from wallet private key using HKDF\n try {\n const { generateKeyPairFromSeed, peerIdFromPrivateKey } = await loadHeliaModules();\n const walletSecret = this.hexToBytes(identity.privateKey);\n const derivedKey = hkdf(sha256, walletSecret, undefined, HKDF_INFO, 32);\n\n // Generate libp2p Ed25519 key pair for IPNS\n this.ipnsKeyPair = await generateKeyPairFromSeed('Ed25519', derivedKey);\n const peerId = peerIdFromPrivateKey(this.ipnsKeyPair);\n this.ipnsName = peerId.toString();\n\n this.log('Identity set, IPNS name:', this.ipnsName);\n } catch {\n // Fallback to provided IPNS name or simple derivation\n this.ipnsName = identity.ipnsName ?? this.deriveIpnsNameSimple(identity.privateKey);\n this.log('Identity set with fallback IPNS name:', this.ipnsName);\n }\n }\n\n async initialize(): Promise<boolean> {\n if (!this.identity) {\n throw new Error('Identity must be set before initialization');\n }\n\n try {\n await this.connect();\n return true;\n } catch {\n return false;\n }\n }\n\n async shutdown(): Promise<void> {\n await this.disconnect();\n }\n\n async save(data: TData): Promise<SaveResult> {\n this.ensureReady();\n this.emitEvent({ type: 'storage:saving', timestamp: Date.now() });\n\n try {\n // Update metadata\n const dataToSave: TData = {\n ...data,\n _meta: {\n ...data._meta,\n updatedAt: Date.now(),\n ipnsName: this.ipnsName ?? undefined,\n },\n };\n\n // Publish to IPFS (parallel to all gateways)\n const cid = await this.publishToGateways(dataToSave);\n\n // Update IPNS if enabled\n if (this.config.enableIpns && this.ipnsName) {\n await this.publishIpns(cid);\n }\n\n // Update local cache\n this.localCache = dataToSave;\n this.cacheTimestamp = Date.now();\n this.lastCid = cid;\n\n this.emitEvent({ type: 'storage:saved', timestamp: Date.now(), data: { cid } });\n\n return {\n success: true,\n cid,\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitEvent({ type: 'storage:error', timestamp: Date.now(), error: errorMsg });\n\n return {\n success: false,\n error: errorMsg,\n timestamp: Date.now(),\n };\n }\n }\n\n async load(identifier?: string): Promise<LoadResult<TData>> {\n this.ensureReady();\n this.emitEvent({ type: 'storage:loading', timestamp: Date.now() });\n\n try {\n // Try local cache first (if recent)\n const cacheAge = Date.now() - this.cacheTimestamp;\n if (this.localCache && cacheAge < 60000) {\n this.log('Returning cached data');\n return {\n success: true,\n data: this.localCache,\n source: 'cache',\n timestamp: Date.now(),\n };\n }\n\n // Resolve IPNS or use direct CID\n let cid: string | null = identifier ?? null;\n\n if (!cid && this.config.enableIpns && this.ipnsName) {\n cid = await this.resolveIpns(this.ipnsName);\n }\n\n if (!cid) {\n // No remote data found\n return {\n success: true,\n data: undefined,\n source: 'remote',\n timestamp: Date.now(),\n };\n }\n\n // Fetch content\n const data = await this.fetchFromGateways<TData>(cid);\n\n // Update cache\n this.localCache = data;\n this.cacheTimestamp = Date.now();\n this.lastCid = cid;\n\n this.emitEvent({ type: 'storage:loaded', timestamp: Date.now() });\n\n return {\n success: true,\n data,\n source: 'remote',\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitEvent({ type: 'storage:error', timestamp: Date.now(), error: errorMsg });\n\n // Fallback to cache on error\n if (this.localCache) {\n return {\n success: true,\n data: this.localCache,\n source: 'cache',\n timestamp: Date.now(),\n };\n }\n\n return {\n success: false,\n error: errorMsg,\n source: 'remote',\n timestamp: Date.now(),\n };\n }\n }\n\n async sync(localData: TData): Promise<SyncResult<TData>> {\n this.ensureReady();\n this.emitEvent({ type: 'sync:started', timestamp: Date.now() });\n\n try {\n // Load remote data\n const remoteResult = await this.load();\n const remoteData = remoteResult.data;\n\n if (!remoteData) {\n // No remote data, just save local\n await this.save(localData);\n this.emitEvent({ type: 'sync:completed', timestamp: Date.now() });\n return {\n success: true,\n merged: localData,\n added: 0,\n removed: 0,\n conflicts: 0,\n };\n }\n\n // Merge data\n const mergeResult = this.mergeData(localData, remoteData);\n\n // Save merged result\n await this.save(mergeResult.merged);\n\n this.emitEvent({ type: 'sync:completed', timestamp: Date.now() });\n\n return {\n success: true,\n merged: mergeResult.merged,\n added: mergeResult.added,\n removed: mergeResult.removed,\n conflicts: mergeResult.conflicts,\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitEvent({ type: 'sync:error', timestamp: Date.now(), error: errorMsg });\n\n return {\n success: false,\n added: 0,\n removed: 0,\n conflicts: 0,\n error: errorMsg,\n };\n }\n }\n\n async exists(): Promise<boolean> {\n if (!this.ipnsName) return false;\n\n try {\n const cid = await this.resolveIpns(this.ipnsName);\n return cid !== null;\n } catch {\n return false;\n }\n }\n\n async clear(): Promise<boolean> {\n // IPFS is immutable, we can only publish empty data\n const emptyData = {\n _meta: {\n version: 0,\n address: this.identity?.l1Address ?? '',\n formatVersion: '2.0',\n updatedAt: Date.now(),\n },\n _tombstones: [],\n } as unknown as TData;\n\n const result = await this.save(emptyData);\n return result.success;\n }\n\n onEvent(callback: StorageEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => this.eventCallbacks.delete(callback);\n }\n\n // ===========================================================================\n // Private: IPFS Operations\n // ===========================================================================\n\n private async testGatewayConnectivity(): Promise<void> {\n const gateway = this.config.gateways[0];\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n\n try {\n const response = await fetch(`${gateway}/api/v0/version`, {\n method: 'POST',\n signal: controller.signal,\n });\n if (!response.ok) throw new Error('Gateway not responding');\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async publishToGateways(data: TData): Promise<string> {\n const content = JSON.stringify(data);\n const blob = new Blob([content], { type: 'application/json' });\n\n // Strategy: Try both HTTP and Helia in parallel, return first success\n const promises: Promise<string>[] = [];\n\n // HTTP gateway publishing (fast path)\n for (const gateway of this.config.gateways) {\n promises.push(this.publishToGateway(gateway, blob));\n }\n\n // Helia DHT publishing (backup path)\n if (this.heliaJson) {\n promises.push(this.publishToHelia(data));\n }\n\n try {\n const cid = await Promise.any(promises);\n this.log('Published to IPFS, CID:', cid);\n return cid;\n } catch {\n throw new Error('All publish attempts failed');\n }\n }\n\n /**\n * Publish data via Helia (browser DHT)\n */\n private async publishToHelia(data: TData): Promise<string> {\n if (!this.heliaJson) {\n throw new Error('Helia not initialized');\n }\n\n const cid = await this.heliaJson.add(data);\n this.log('Published via Helia, CID:', cid.toString());\n return cid.toString();\n }\n\n private async publishToGateway(gateway: string, blob: Blob): Promise<string> {\n const formData = new FormData();\n formData.append('file', blob);\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.fetchTimeout);\n\n try {\n const response = await fetch(`${gateway}/api/v0/add?pin=true`, {\n method: 'POST',\n body: formData,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Gateway ${gateway} returned ${response.status}`);\n }\n\n const result = await response.json();\n return result.Hash;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async publishIpns(cid: string): Promise<void> {\n if (!this.identity) return;\n\n // Publish to all gateways in parallel\n const promises = this.config.gateways.map((gateway) =>\n this.publishIpnsToGateway(gateway, cid).catch(() => null)\n );\n\n await Promise.allSettled(promises);\n this.log('Published IPNS:', this.ipnsName, '->', cid);\n }\n\n private async publishIpnsToGateway(gateway: string, cid: string): Promise<void> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.ipnsTimeout);\n\n try {\n const response = await fetch(\n `${gateway}/api/v0/name/publish?arg=${cid}&key=${this.ipnsName}`,\n {\n method: 'POST',\n signal: controller.signal,\n }\n );\n\n if (!response.ok) {\n throw new Error(`IPNS publish failed: ${response.status}`);\n }\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async resolveIpns(name: string): Promise<string | null> {\n // Try each gateway\n for (const gateway of this.config.gateways) {\n try {\n return await this.resolveIpnsFromGateway(gateway, name);\n } catch {\n continue;\n }\n }\n return null;\n }\n\n private async resolveIpnsFromGateway(gateway: string, name: string): Promise<string> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.fetchTimeout);\n\n try {\n const response = await fetch(`${gateway}/api/v0/name/resolve?arg=${name}`, {\n method: 'POST',\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`IPNS resolve failed: ${response.status}`);\n }\n\n const result = await response.json();\n // Path is like \"/ipfs/Qm...\"\n return result.Path.replace('/ipfs/', '');\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async fetchFromGateways<T>(cid: string): Promise<T> {\n // Strategy: Try both HTTP and Helia in parallel\n const promises: Promise<T>[] = [];\n\n // HTTP gateway fetching (fast path)\n for (const gateway of this.config.gateways) {\n promises.push(this.fetchFromGateway<T>(gateway, cid));\n }\n\n // Helia DHT fetching (backup path)\n if (this.heliaJson) {\n promises.push(this.fetchFromHelia<T>(cid));\n }\n\n return Promise.any(promises);\n }\n\n /**\n * Fetch content via Helia (browser DHT)\n */\n private async fetchFromHelia<T>(cidString: string): Promise<T> {\n if (!this.heliaJson) {\n throw new Error('Helia not initialized');\n }\n\n const { CID } = await loadHeliaModules();\n const cid = CID.parse(cidString);\n const data = await this.heliaJson.get(cid);\n this.log('Fetched via Helia, CID:', cidString);\n return data as T;\n }\n\n private async fetchFromGateway<T>(gateway: string, cid: string): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.fetchTimeout);\n\n try {\n const response = await fetch(`${gateway}/ipfs/${cid}`, {\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status}`);\n }\n\n return response.json();\n } finally {\n clearTimeout(timeout);\n }\n }\n\n // ===========================================================================\n // Private: Merge Logic\n // ===========================================================================\n\n private mergeData(\n local: TData,\n remote: TData\n ): { merged: TData; added: number; removed: number; conflicts: number } {\n const localVersion = local._meta?.version ?? 0;\n const remoteVersion = remote._meta?.version ?? 0;\n\n // Simple strategy: newer version wins for meta\n const baseMeta = remoteVersion > localVersion ? remote._meta : local._meta;\n\n // Merge tombstones (union)\n const tombstones = new Map<string, TxfTombstone>();\n for (const t of local._tombstones ?? []) {\n tombstones.set(t.tokenId, t);\n }\n for (const t of remote._tombstones ?? []) {\n const existing = tombstones.get(t.tokenId);\n if (!existing || t.timestamp > existing.timestamp) {\n tombstones.set(t.tokenId, t);\n }\n }\n\n // Merge token entries (newer wins, respect tombstones)\n const merged = {\n _meta: {\n ...baseMeta,\n version: Math.max(localVersion, remoteVersion) + 1,\n updatedAt: Date.now(),\n },\n _tombstones: Array.from(tombstones.values()),\n } as unknown as TData;\n\n let added = 0;\n let conflicts = 0;\n\n // Process all token entries from both sources\n const processedKeys = new Set<string>();\n\n for (const key of Object.keys(local)) {\n if (!key.startsWith('_') || key === '_meta' || key === '_tombstones') continue;\n processedKeys.add(key);\n\n const tokenId = key.slice(1); // Remove leading _\n if (tombstones.has(tokenId)) continue; // Deleted\n\n const localToken = local[key as keyof TData];\n const remoteToken = remote[key as keyof TData];\n\n if (remoteToken) {\n // Both have it - conflict resolution\n conflicts++;\n // Use local (could be smarter based on timestamps)\n (merged as Record<string, unknown>)[key] = localToken;\n } else {\n (merged as Record<string, unknown>)[key] = localToken;\n }\n }\n\n for (const key of Object.keys(remote)) {\n if (!key.startsWith('_') || key === '_meta' || key === '_tombstones') continue;\n if (processedKeys.has(key)) continue;\n\n const tokenId = key.slice(1);\n if (tombstones.has(tokenId)) continue;\n\n (merged as Record<string, unknown>)[key] = remote[key as keyof TData];\n added++;\n }\n\n return { merged, added, removed: 0, conflicts };\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureReady(): void {\n if (this.status !== 'connected') {\n throw new Error('IpfsStorageProvider not connected');\n }\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n }\n\n /**\n * Simple IPNS name derivation (fallback when libp2p is unavailable)\n */\n private deriveIpnsNameSimple(privateKey: string): string {\n // Fallback: use truncated hash of private key\n return `12D3KooW${privateKey.slice(0, 40)}`;\n }\n\n /**\n * Convert hex string to Uint8Array\n */\n private hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n }\n return bytes;\n }\n\n private emitEvent(event: StorageEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n console.error('[IpfsStorageProvider] Event callback error:', error);\n }\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[IpfsStorageProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\nexport function createIpfsStorageProvider<TData extends TxfStorageDataBase = TxfStorageDataBase>(\n config?: IpfsStorageProviderConfig\n): IpfsStorageProvider<TData> {\n return new IpfsStorageProvider<TData>(config);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../impl/browser/ipfs.ts","../../../constants.ts","../../../node_modules/@noble/hashes/src/utils.ts","../../../node_modules/@noble/hashes/src/hmac.ts","../../../node_modules/@noble/hashes/src/hkdf.ts","../../../node_modules/@noble/hashes/src/_md.ts","../../../node_modules/@noble/hashes/src/sha2.ts","../../../impl/browser/storage/IpfsStorageProvider.ts"],"sourcesContent":["/**\n * Browser IPFS Storage Provider\n *\n * Separate entry point for IPFS functionality.\n * Requires helia and @helia/* packages to be installed.\n *\n * @example\n * ```ts\n * import { IpfsStorageProvider, createIpfsStorageProvider } from '@unicitylabs/sphere-sdk/impl/browser/ipfs';\n * ```\n */\nexport {\n IpfsStorageProvider,\n createIpfsStorageProvider,\n type IpfsStorageProviderConfig,\n} from './storage/IpfsStorageProvider';\n","/**\n * SDK2 Constants\n * Default configuration values and storage keys\n */\n\n// =============================================================================\n// Storage Keys\n// =============================================================================\n\n/** Default prefix for all storage keys */\nexport const STORAGE_PREFIX = 'sphere_' as const;\n\n/**\n * Default encryption key for wallet data\n * WARNING: This is a placeholder. In production, use user-provided password.\n * This key is used when no password is provided to encrypt/decrypt mnemonic.\n */\nexport const DEFAULT_ENCRYPTION_KEY = 'sphere-default-key' as const;\n\n/**\n * Global storage keys (one per wallet, no address index)\n * Final key format: sphere_{key}\n */\nexport const STORAGE_KEYS_GLOBAL = {\n /** Encrypted BIP39 mnemonic */\n MNEMONIC: 'mnemonic',\n /** Encrypted master private key */\n MASTER_KEY: 'master_key',\n /** BIP32 chain code */\n CHAIN_CODE: 'chain_code',\n /** HD derivation path (full path like m/44'/0'/0'/0/0) */\n DERIVATION_PATH: 'derivation_path',\n /** Base derivation path (like m/44'/0'/0' without chain/index) */\n BASE_PATH: 'base_path',\n /** Derivation mode: bip32, wif_hmac, legacy_hmac */\n DERIVATION_MODE: 'derivation_mode',\n /** Wallet source: mnemonic, file, unknown */\n WALLET_SOURCE: 'wallet_source',\n /** Wallet existence flag */\n WALLET_EXISTS: 'wallet_exists',\n /** Current active address index */\n CURRENT_ADDRESS_INDEX: 'current_address_index',\n /** Nametag cache per address (separate from tracked addresses registry) */\n ADDRESS_NAMETAGS: 'address_nametags',\n /** Active addresses registry (JSON: TrackedAddressesStorage) */\n TRACKED_ADDRESSES: 'tracked_addresses',\n /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */\n LAST_WALLET_EVENT_TS: 'last_wallet_event_ts',\n} as const;\n\n/**\n * Per-address storage keys (one per derived address)\n * Final key format: sphere_{DIRECT_xxx_yyy}_{key}\n * Example: sphere_DIRECT_abc123_xyz789_pending_transfers\n *\n * Note: Token data (tokens, tombstones, archived, forked) is stored via\n * TokenStorageProvider, not here. This avoids duplication.\n */\nexport const STORAGE_KEYS_ADDRESS = {\n /** Pending transfers for this address */\n PENDING_TRANSFERS: 'pending_transfers',\n /** Transfer outbox for this address */\n OUTBOX: 'outbox',\n /** Conversations for this address */\n CONVERSATIONS: 'conversations',\n /** Messages for this address */\n MESSAGES: 'messages',\n /** Transaction history for this address */\n TRANSACTION_HISTORY: 'transaction_history',\n} as const;\n\n/** @deprecated Use STORAGE_KEYS_GLOBAL and STORAGE_KEYS_ADDRESS instead */\nexport const STORAGE_KEYS = {\n ...STORAGE_KEYS_GLOBAL,\n ...STORAGE_KEYS_ADDRESS,\n} as const;\n\n/**\n * Build a per-address storage key using address identifier\n * @param addressId - Short identifier for the address (e.g., first 8 chars of pubkey hash, or direct address hash)\n * @param key - The key from STORAGE_KEYS_ADDRESS\n * @returns Key in format: \"{addressId}_{key}\" e.g., \"a1b2c3d4_tokens\"\n */\nexport function getAddressStorageKey(addressId: string, key: string): string {\n return `${addressId}_${key}`;\n}\n\n/**\n * Create a readable address identifier from directAddress or chainPubkey\n * Format: DIRECT_first6_last6 (sanitized for filesystem/storage)\n * @param directAddress - The L3 direct address (DIRECT:xxx) or chainPubkey\n * @returns Sanitized identifier like \"DIRECT_abc123_xyz789\"\n */\nexport function getAddressId(directAddress: string): string {\n // Remove DIRECT:// or DIRECT: prefix if present\n let hash = directAddress;\n if (hash.startsWith('DIRECT://')) {\n hash = hash.slice(9);\n } else if (hash.startsWith('DIRECT:')) {\n hash = hash.slice(7);\n }\n // Format: DIRECT_first6_last6 (sanitized)\n const first = hash.slice(0, 6).toLowerCase();\n const last = hash.slice(-6).toLowerCase();\n return `DIRECT_${first}_${last}`;\n}\n\n// =============================================================================\n// Nostr Defaults\n// =============================================================================\n\n/** Default Nostr relays */\nexport const DEFAULT_NOSTR_RELAYS = [\n 'wss://relay.unicity.network',\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.nostr.band',\n] as const;\n\n/** Nostr event kinds used by SDK - must match @unicitylabs/nostr-js-sdk */\nexport const NOSTR_EVENT_KINDS = {\n /** NIP-04 encrypted direct message */\n DIRECT_MESSAGE: 4,\n /** Token transfer (Unicity custom - 31113) */\n TOKEN_TRANSFER: 31113,\n /** Payment request (Unicity custom - 31115) */\n PAYMENT_REQUEST: 31115,\n /** Payment request response (Unicity custom - 31116) */\n PAYMENT_REQUEST_RESPONSE: 31116,\n /** Nametag binding (NIP-78 app-specific data) */\n NAMETAG_BINDING: 30078,\n /** Public broadcast */\n BROADCAST: 1,\n} as const;\n\n// =============================================================================\n// Aggregator (Oracle) Defaults\n// =============================================================================\n\n/**\n * Default aggregator URL\n * Note: The aggregator is conceptually an oracle - a trusted service that provides\n * verifiable truth about token state through cryptographic inclusion proofs.\n */\nexport const DEFAULT_AGGREGATOR_URL = 'https://aggregator.unicity.network/rpc' as const;\n\n/** Dev aggregator URL */\nexport const DEV_AGGREGATOR_URL = 'https://dev-aggregator.dyndns.org/rpc' as const;\n\n/** Test aggregator URL (Goggregator) */\nexport const TEST_AGGREGATOR_URL = 'https://goggregator-test.unicity.network' as const;\n\n/** Default aggregator request timeout (ms) */\nexport const DEFAULT_AGGREGATOR_TIMEOUT = 30000;\n\n/** Default API key for aggregator authentication */\nexport const DEFAULT_AGGREGATOR_API_KEY = 'sk_06365a9c44654841a366068bcfc68986' as const;\n\n// =============================================================================\n// IPFS Defaults\n// =============================================================================\n\n/** Default IPFS gateways */\nexport const DEFAULT_IPFS_GATEWAYS = [\n 'https://ipfs.unicity.network',\n 'https://dweb.link',\n 'https://ipfs.io',\n] as const;\n\n/** Unicity IPFS bootstrap peers */\nexport const DEFAULT_IPFS_BOOTSTRAP_PEERS = [\n '/dns4/unicity-ipfs2.dyndns.org/tcp/4001/p2p/12D3KooWLNi5NDPPHbrfJakAQqwBqymYTTwMQXQKEWuCrJNDdmfh',\n '/dns4/unicity-ipfs3.dyndns.org/tcp/4001/p2p/12D3KooWQ4aujVE4ShLjdusNZBdffq3TbzrwT2DuWZY9H1Gxhwn6',\n '/dns4/unicity-ipfs4.dyndns.org/tcp/4001/p2p/12D3KooWJ1ByPfUzUrpYvgxKU8NZrR8i6PU1tUgMEbQX9Hh2DEn1',\n '/dns4/unicity-ipfs5.dyndns.org/tcp/4001/p2p/12D3KooWB1MdZZGHN5B8TvWXntbycfe7Cjcz7n6eZ9eykZadvmDv',\n] as const;\n\n// =============================================================================\n// Wallet Defaults\n// =============================================================================\n\n/** Default BIP32 base path (without chain/index) */\nexport const DEFAULT_BASE_PATH = \"m/44'/0'/0'\" as const;\n\n/** Default BIP32 derivation path (full path with chain/index) */\nexport const DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0` as const;\n\n/** Coin types */\nexport const COIN_TYPES = {\n /** ALPHA token (L1 blockchain) */\n ALPHA: 'ALPHA',\n /** Test token */\n TEST: 'TEST',\n} as const;\n\n// =============================================================================\n// L1 (ALPHA Blockchain) Defaults\n// =============================================================================\n\n/** Default Fulcrum electrum server for mainnet */\nexport const DEFAULT_ELECTRUM_URL = 'wss://fulcrum.alpha.unicity.network:50004' as const;\n\n/** Testnet Fulcrum electrum server */\nexport const TEST_ELECTRUM_URL = 'wss://fulcrum.alpha.testnet.unicity.network:50004' as const;\n\n// =============================================================================\n// Network Defaults\n// =============================================================================\n\n/** Testnet Nostr relays */\nexport const TEST_NOSTR_RELAYS = [\n 'wss://nostr-relay.testnet.unicity.network',\n] as const;\n\n/** Network configurations */\nexport const NETWORKS = {\n mainnet: {\n name: 'Mainnet',\n aggregatorUrl: DEFAULT_AGGREGATOR_URL,\n nostrRelays: DEFAULT_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: DEFAULT_ELECTRUM_URL,\n },\n testnet: {\n name: 'Testnet',\n aggregatorUrl: TEST_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n dev: {\n name: 'Development',\n aggregatorUrl: DEV_AGGREGATOR_URL,\n nostrRelays: TEST_NOSTR_RELAYS,\n ipfsGateways: DEFAULT_IPFS_GATEWAYS,\n electrumUrl: TEST_ELECTRUM_URL,\n },\n} as const;\n\nexport type NetworkType = keyof typeof NETWORKS;\nexport type NetworkConfig = (typeof NETWORKS)[NetworkType];\n\n// =============================================================================\n// Timeouts & Limits\n// =============================================================================\n\n/** Default timeouts (ms) */\nexport const TIMEOUTS = {\n /** WebSocket connection timeout */\n WEBSOCKET_CONNECT: 10000,\n /** Nostr relay reconnect delay */\n NOSTR_RECONNECT_DELAY: 3000,\n /** Max reconnect attempts */\n MAX_RECONNECT_ATTEMPTS: 5,\n /** Proof polling interval */\n PROOF_POLL_INTERVAL: 1000,\n /** Sync interval */\n SYNC_INTERVAL: 60000,\n} as const;\n\n/** Validation limits */\nexport const LIMITS = {\n /** Min nametag length */\n NAMETAG_MIN_LENGTH: 3,\n /** Max nametag length */\n NAMETAG_MAX_LENGTH: 20,\n /** Max memo length */\n MEMO_MAX_LENGTH: 500,\n /** Max message length */\n MESSAGE_MAX_LENGTH: 10000,\n} as const;\n","/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is positive integer. */\nexport function anumber(n: number, title: string = ''): void {\n if (!Number.isSafeInteger(n) || n < 0) {\n const prefix = title && `\"${title}\" `;\n throw new Error(`${prefix}expected integer >= 0, got ${n}`);\n }\n}\n\n/** Asserts something is Uint8Array. */\nexport function abytes(value: Uint8Array, length?: number, title: string = ''): Uint8Array {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n}\n\n/** Asserts something is hash */\nexport function ahash(h: CHash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash must wrapped by utils.createHasher');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out: any, instance: any): void {\n abytes(out, undefined, 'digestInto() output');\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('\"digestInto() output\" expected to be of length >=' + min);\n }\n}\n\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays: TypedArray[]): void {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\n\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n\n/** The byte swap operation for uint32 */\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const swap8IfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n return arr;\n}\n\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\n ? (u: Uint32Array) => u\n : byteSwap32;\n\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // @ts-ignore\n if (hasHexBuiltin) return bytes.toHex();\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n // @ts-ignore\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise<void> => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise<void> {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\n\n/**\n * Converts string to bytes using UTF8 encoding.\n * Built-in doesn't validate input to be string: we do the check.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/** KDFs can accept string or Uint8Array for user convenience. */\nexport type KDFInput = string | Uint8Array;\n\n/**\n * Helper for KDFs: consumes uint8array or string.\n * When string is passed, does utf8 decoding, using TextDecoder.\n */\nexport function kdfInputToBytes(data: KDFInput, errorTitle = ''): Uint8Array {\n if (typeof data === 'string') return utf8ToBytes(data);\n return abytes(data, undefined, errorTitle);\n}\n\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\ntype EmptyObj = {};\n/** Merges default options and passed options. */\nexport function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('options must be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Common interface for all hashes. */\nexport interface Hash<T> {\n blockLen: number; // Bytes per block\n outputLen: number; // Bytes in output\n update(buf: Uint8Array): this;\n digestInto(buf: Uint8Array): void;\n digest(): Uint8Array;\n destroy(): void;\n _cloneInto(to?: T): T;\n clone(): T;\n}\n\n/** PseudoRandom (number) Generator */\nexport interface PRG {\n addEntropy(seed: Uint8Array): void;\n randomBytes(length: number): Uint8Array;\n clean(): void;\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF<T extends Hash<T>> = Hash<T> & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\n/** Hash constructor */\nexport type HasherCons<T, Opts = undefined> = Opts extends undefined ? () => T : (opts?: Opts) => T;\n/** Optional hash params. */\nexport type HashInfo = {\n oid?: Uint8Array; // DER encoded OID in bytes\n};\n/** Hash function */\nexport type CHash<T extends Hash<T> = Hash<any>, Opts = undefined> = {\n outputLen: number;\n blockLen: number;\n} & HashInfo &\n (Opts extends undefined\n ? {\n (msg: Uint8Array): Uint8Array;\n create(): T;\n }\n : {\n (msg: Uint8Array, opts?: Opts): Uint8Array;\n create(opts?: Opts): T;\n });\n/** XOF with output */\nexport type CHashXOF<T extends HashXOF<T> = HashXOF<any>, Opts = undefined> = CHash<T, Opts>;\n\n/** Creates function with outputLen, blockLen, create properties from a class constructor. */\nexport function createHasher<T extends Hash<T>, Opts = undefined>(\n hashCons: HasherCons<T, Opts>,\n info: HashInfo = {}\n): CHash<T, Opts> {\n const hashC: any = (msg: Uint8Array, opts?: Opts) => hashCons(opts).update(msg).digest();\n const tmp = hashCons(undefined);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: Opts) => hashCons(opts);\n Object.assign(hashC, info);\n return Object.freeze(hashC);\n}\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n const cr = typeof globalThis === 'object' ? (globalThis as any).crypto : null;\n if (typeof cr?.getRandomValues !== 'function')\n throw new Error('crypto.getRandomValues must be defined');\n return cr.getRandomValues(new Uint8Array(bytesLength));\n}\n\n/** Creates OID opts for NIST hashes, with prefix 06 09 60 86 48 01 65 03 04 02. */\nexport const oidNist = (suffix: number): Required<HashInfo> => ({\n oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),\n});\n","/**\n * HMAC: RFC2104 message authentication code.\n * @module\n */\nimport { abytes, aexists, ahash, clean, type CHash, type Hash } from './utils.ts';\n\n/** Internal class for HMAC. */\nexport class _HMAC<T extends Hash<T>> implements Hash<_HMAC<T>> {\n oHash: T;\n iHash: T;\n blockLen: number;\n outputLen: number;\n private finished = false;\n private destroyed = false;\n\n constructor(hash: CHash, key: Uint8Array) {\n ahash(hash);\n abytes(key, undefined, 'key');\n this.iHash = hash.create() as T;\n if (typeof this.iHash.update !== 'function')\n throw new Error('Expected instance of class which extends utils.Hash');\n this.blockLen = this.iHash.blockLen;\n this.outputLen = this.iHash.outputLen;\n const blockLen = this.blockLen;\n const pad = new Uint8Array(blockLen);\n // blockLen can be bigger than outputLen\n pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;\n this.iHash.update(pad);\n // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone\n this.oHash = hash.create() as T;\n // Undo internal XOR && apply outer XOR\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;\n this.oHash.update(pad);\n clean(pad);\n }\n update(buf: Uint8Array): this {\n aexists(this);\n this.iHash.update(buf);\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n abytes(out, this.outputLen, 'output');\n this.finished = true;\n this.iHash.digestInto(out);\n this.oHash.update(out);\n this.oHash.digestInto(out);\n this.destroy();\n }\n digest(): Uint8Array {\n const out = new Uint8Array(this.oHash.outputLen);\n this.digestInto(out);\n return out;\n }\n _cloneInto(to?: _HMAC<T>): _HMAC<T> {\n // Create new instance without calling constructor since key already in state and we don't know it.\n to ||= Object.create(Object.getPrototypeOf(this), {});\n const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;\n to = to as this;\n to.finished = finished;\n to.destroyed = destroyed;\n to.blockLen = blockLen;\n to.outputLen = outputLen;\n to.oHash = oHash._cloneInto(to.oHash);\n to.iHash = iHash._cloneInto(to.iHash);\n return to;\n }\n clone(): _HMAC<T> {\n return this._cloneInto();\n }\n destroy(): void {\n this.destroyed = true;\n this.oHash.destroy();\n this.iHash.destroy();\n }\n}\n\n/**\n * HMAC: RFC2104 message authentication code.\n * @param hash - function that would be used e.g. sha256\n * @param key - message key\n * @param message - message data\n * @example\n * import { hmac } from '@noble/hashes/hmac';\n * import { sha256 } from '@noble/hashes/sha2';\n * const mac1 = hmac(sha256, 'key', 'message');\n */\nexport const hmac: {\n (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array;\n create(hash: CHash, key: Uint8Array): _HMAC<any>;\n} = (hash: CHash, key: Uint8Array, message: Uint8Array): Uint8Array =>\n new _HMAC<any>(hash, key).update(message).digest();\nhmac.create = (hash: CHash, key: Uint8Array) => new _HMAC<any>(hash, key);\n","/**\n * HKDF (RFC 5869): extract + expand in one step.\n * See https://soatok.blog/2021/11/17/understanding-hkdf/.\n * @module\n */\nimport { hmac } from './hmac.ts';\nimport { abytes, ahash, anumber, type CHash, clean } from './utils.ts';\n\n/**\n * HKDF-extract from spec. Less important part. `HKDF-Extract(IKM, salt) -> PRK`\n * Arguments position differs from spec (IKM is first one, since it is not optional)\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n */\nexport function extract(hash: CHash, ikm: Uint8Array, salt?: Uint8Array): Uint8Array {\n ahash(hash);\n // NOTE: some libraries treat zero-length array as 'not provided';\n // we don't, since we have undefined as 'not provided'\n // https://github.com/RustCrypto/KDFs/issues/15\n if (salt === undefined) salt = new Uint8Array(hash.outputLen);\n return hmac(hash, salt, ikm);\n}\n\nconst HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);\nconst EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();\n\n/**\n * HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM`\n * @param hash - hash function that would be used (e.g. sha256)\n * @param prk - a pseudorandom key of at least HashLen octets (usually, the output from the extract step)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n */\nexport function expand(\n hash: CHash,\n prk: Uint8Array,\n info?: Uint8Array,\n length: number = 32\n): Uint8Array {\n ahash(hash);\n anumber(length, 'length');\n const olen = hash.outputLen;\n if (length > 255 * olen) throw new Error('Length must be <= 255*HashLen');\n const blocks = Math.ceil(length / olen);\n if (info === undefined) info = EMPTY_BUFFER;\n else abytes(info, undefined, 'info');\n // first L(ength) octets of T\n const okm = new Uint8Array(blocks * olen);\n // Re-use HMAC instance between blocks\n const HMAC = hmac.create(hash, prk);\n const HMACTmp = HMAC._cloneInto();\n const T = new Uint8Array(HMAC.outputLen);\n for (let counter = 0; counter < blocks; counter++) {\n HKDF_COUNTER[0] = counter + 1;\n // T(0) = empty string (zero length)\n // T(N) = HMAC-Hash(PRK, T(N-1) | info | N)\n HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T)\n .update(info)\n .update(HKDF_COUNTER)\n .digestInto(T);\n okm.set(T, olen * counter);\n HMAC._cloneInto(HMACTmp);\n }\n HMAC.destroy();\n HMACTmp.destroy();\n clean(T, HKDF_COUNTER);\n return okm.slice(0, length);\n}\n\n/**\n * HKDF (RFC 5869): derive keys from an initial input.\n * Combines hkdf_extract + hkdf_expand in one step\n * @param hash - hash function that would be used (e.g. sha256)\n * @param ikm - input keying material, the initial key\n * @param salt - optional salt value (a non-secret random value)\n * @param info - optional context and application specific information (can be a zero-length string)\n * @param length - length of output keying material in bytes\n * @example\n * import { hkdf } from '@noble/hashes/hkdf';\n * import { sha256 } from '@noble/hashes/sha2';\n * import { randomBytes } from '@noble/hashes/utils';\n * const inputKey = randomBytes(32);\n * const salt = randomBytes(32);\n * const info = 'application-key';\n * const hk1 = hkdf(sha256, inputKey, salt, info, 32);\n */\nexport const hkdf = (\n hash: CHash,\n ikm: Uint8Array,\n salt: Uint8Array | undefined,\n info: Uint8Array | undefined,\n length: number\n): Uint8Array => expand(hash, extract(hash, ikm, salt), info, length);\n","/**\n * Internal Merkle-Damgard hash utils.\n * @module\n */\nimport { abytes, aexists, aoutput, clean, createView, type Hash } from './utils.ts';\n\n/** Choice: a ? b : c */\nexport function Chi(a: number, b: number, c: number): number {\n return (a & b) ^ (~a & c);\n}\n\n/** Majority function, true if any two inputs is true. */\nexport function Maj(a: number, b: number, c: number): number {\n return (a & b) ^ (a & c) ^ (b & c);\n}\n\n/**\n * Merkle-Damgard hash construction base class.\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\n */\nexport abstract class HashMD<T extends HashMD<T>> implements Hash<T> {\n protected abstract process(buf: DataView, offset: number): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected abstract roundClean(): void;\n\n readonly blockLen: number;\n readonly outputLen: number;\n readonly padOffset: number;\n readonly isLE: boolean;\n\n // For partial updates less than block size\n protected buffer: Uint8Array;\n protected view: DataView;\n protected finished = false;\n protected length = 0;\n protected pos = 0;\n protected destroyed = false;\n\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data: Uint8Array): this {\n aexists(this);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n // Fast path: we have at least one block in input, cast it to view and process\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n // Padding\n // We can avoid allocation of buffer for padding completely if it\n // was previously not allocated here. But it won't change performance.\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n // append the bit '1' to the message\n buffer[pos++] = 0b10000000;\n clean(this.buffer.subarray(pos));\n // we have less than padOffset left in buffer, so we cannot put length in\n // current block, need process it and pad again\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n // Pad until full block byte with zeros\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\n // So we just write lowest 64 bits of that value.\n view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n // NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT\n if (len % 4) throw new Error('_sha2: outputLen must be aligned to 32bit');\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n to ||= new (this.constructor as any)() as T;\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen) to.buffer.set(buffer);\n return to as unknown as any;\n }\n clone(): T {\n return this._cloneInto();\n }\n}\n\n/**\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\n */\n\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n]);\n\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\n]);\n\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\n]);\n\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\n]);\n","/**\n * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.\n * SHA256 is the fastest hash implementable in JS, even faster than Blake3.\n * Check out [RFC 4634](https://www.rfc-editor.org/rfc/rfc4634) and\n * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\n * @module\n */\nimport { Chi, HashMD, Maj, SHA224_IV, SHA256_IV, SHA384_IV, SHA512_IV } from './_md.ts';\nimport * as u64 from './_u64.ts';\nimport { type CHash, clean, createHasher, oidNist, rotr } from './utils.ts';\n\n/**\n * Round constants:\n * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)\n */\n// prettier-ignore\nconst SHA256_K = /* @__PURE__ */ Uint32Array.from([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n]);\n\n/** Reusable temporary buffer. \"W\" comes straight from spec. */\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\n\n/** Internal 32-byte base SHA2 hash class. */\nabstract class SHA2_32B<T extends SHA2_32B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected abstract A: number;\n protected abstract B: number;\n protected abstract C: number;\n protected abstract D: number;\n protected abstract E: number;\n protected abstract F: number;\n protected abstract G: number;\n protected abstract H: number;\n\n constructor(outputLen: number) {\n super(64, outputLen, 8, false);\n }\n protected get(): [number, number, number, number, number, number, number, number] {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n protected set(\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\n ): void {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\n }\n // Compression function main loop, 64 rounds\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\n H = G;\n G = F;\n F = E;\n E = (D + T1) | 0;\n D = C;\n C = B;\n B = A;\n A = (T1 + T2) | 0;\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n E = (E + this.E) | 0;\n F = (F + this.F) | 0;\n G = (G + this.G) | 0;\n H = (H + this.H) | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n protected roundClean(): void {\n clean(SHA256_W);\n }\n destroy(): void {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n clean(this.buffer);\n }\n}\n\n/** Internal SHA2-256 hash class. */\nexport class _SHA256 extends SHA2_32B<_SHA256> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected A: number = SHA256_IV[0] | 0;\n protected B: number = SHA256_IV[1] | 0;\n protected C: number = SHA256_IV[2] | 0;\n protected D: number = SHA256_IV[3] | 0;\n protected E: number = SHA256_IV[4] | 0;\n protected F: number = SHA256_IV[5] | 0;\n protected G: number = SHA256_IV[6] | 0;\n protected H: number = SHA256_IV[7] | 0;\n constructor() {\n super(32);\n }\n}\n\n/** Internal SHA2-224 hash class. */\nexport class _SHA224 extends SHA2_32B<_SHA224> {\n protected A: number = SHA224_IV[0] | 0;\n protected B: number = SHA224_IV[1] | 0;\n protected C: number = SHA224_IV[2] | 0;\n protected D: number = SHA224_IV[3] | 0;\n protected E: number = SHA224_IV[4] | 0;\n protected F: number = SHA224_IV[5] | 0;\n protected G: number = SHA224_IV[6] | 0;\n protected H: number = SHA224_IV[7] | 0;\n constructor() {\n super(28);\n }\n}\n\n// SHA2-512 is slower than sha256 in js because u64 operations are slow.\n\n// Round contants\n// First 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409\n// prettier-ignore\nconst K512 = /* @__PURE__ */ (() => u64.split([\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\n].map(n => BigInt(n))))();\nconst SHA512_Kh = /* @__PURE__ */ (() => K512[0])();\nconst SHA512_Kl = /* @__PURE__ */ (() => K512[1])();\n\n// Reusable temporary buffers\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\n\n/** Internal 64-byte base SHA2 hash class. */\nabstract class SHA2_64B<T extends SHA2_64B<T>> extends HashMD<T> {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n // h -- high 32 bits, l -- low 32 bits\n protected abstract Ah: number;\n protected abstract Al: number;\n protected abstract Bh: number;\n protected abstract Bl: number;\n protected abstract Ch: number;\n protected abstract Cl: number;\n protected abstract Dh: number;\n protected abstract Dl: number;\n protected abstract Eh: number;\n protected abstract El: number;\n protected abstract Fh: number;\n protected abstract Fl: number;\n protected abstract Gh: number;\n protected abstract Gl: number;\n protected abstract Hh: number;\n protected abstract Hl: number;\n\n constructor(outputLen: number) {\n super(128, outputLen, 16, false);\n }\n // prettier-ignore\n protected get(): [\n number, number, number, number, number, number, number, number,\n number, number, number, number, number, number, number, number\n ] {\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\n }\n // prettier-ignore\n protected set(\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\n ): void {\n this.Ah = Ah | 0;\n this.Al = Al | 0;\n this.Bh = Bh | 0;\n this.Bl = Bl | 0;\n this.Ch = Ch | 0;\n this.Cl = Cl | 0;\n this.Dh = Dh | 0;\n this.Dl = Dl | 0;\n this.Eh = Eh | 0;\n this.El = El | 0;\n this.Fh = Fh | 0;\n this.Fl = Fl | 0;\n this.Gh = Gh | 0;\n this.Gl = Gl | 0;\n this.Hh = Hh | 0;\n this.Hl = Hl | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) {\n SHA512_W_H[i] = view.getUint32(offset);\n SHA512_W_L[i] = view.getUint32((offset += 4));\n }\n for (let i = 16; i < 80; i++) {\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\n const W15h = SHA512_W_H[i - 15] | 0;\n const W15l = SHA512_W_L[i - 15] | 0;\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\n const W2h = SHA512_W_H[i - 2] | 0;\n const W2l = SHA512_W_L[i - 2] | 0;\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\n SHA512_W_H[i] = SUMh | 0;\n SHA512_W_L[i] = SUMl | 0;\n }\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n // Compression function main loop, 80 rounds\n for (let i = 0; i < 80; i++) {\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\n const CHIl = (El & Fl) ^ (~El & Gl);\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\n // prettier-ignore\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\n const T1l = T1ll | 0;\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\n Hh = Gh | 0;\n Hl = Gl | 0;\n Gh = Fh | 0;\n Gl = Fl | 0;\n Fh = Eh | 0;\n Fl = El | 0;\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\n Dh = Ch | 0;\n Dl = Cl | 0;\n Ch = Bh | 0;\n Cl = Bl | 0;\n Bh = Ah | 0;\n Bl = Al | 0;\n const All = u64.add3L(T1l, sigma0l, MAJl);\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\n Al = All | 0;\n }\n // Add the compressed chunk to the current hash value\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\n }\n protected roundClean(): void {\n clean(SHA512_W_H, SHA512_W_L);\n }\n destroy(): void {\n clean(this.buffer);\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\n/** Internal SHA2-512 hash class. */\nexport class _SHA512 extends SHA2_64B<_SHA512> {\n protected Ah: number = SHA512_IV[0] | 0;\n protected Al: number = SHA512_IV[1] | 0;\n protected Bh: number = SHA512_IV[2] | 0;\n protected Bl: number = SHA512_IV[3] | 0;\n protected Ch: number = SHA512_IV[4] | 0;\n protected Cl: number = SHA512_IV[5] | 0;\n protected Dh: number = SHA512_IV[6] | 0;\n protected Dl: number = SHA512_IV[7] | 0;\n protected Eh: number = SHA512_IV[8] | 0;\n protected El: number = SHA512_IV[9] | 0;\n protected Fh: number = SHA512_IV[10] | 0;\n protected Fl: number = SHA512_IV[11] | 0;\n protected Gh: number = SHA512_IV[12] | 0;\n protected Gl: number = SHA512_IV[13] | 0;\n protected Hh: number = SHA512_IV[14] | 0;\n protected Hl: number = SHA512_IV[15] | 0;\n\n constructor() {\n super(64);\n }\n}\n\n/** Internal SHA2-384 hash class. */\nexport class _SHA384 extends SHA2_64B<_SHA384> {\n protected Ah: number = SHA384_IV[0] | 0;\n protected Al: number = SHA384_IV[1] | 0;\n protected Bh: number = SHA384_IV[2] | 0;\n protected Bl: number = SHA384_IV[3] | 0;\n protected Ch: number = SHA384_IV[4] | 0;\n protected Cl: number = SHA384_IV[5] | 0;\n protected Dh: number = SHA384_IV[6] | 0;\n protected Dl: number = SHA384_IV[7] | 0;\n protected Eh: number = SHA384_IV[8] | 0;\n protected El: number = SHA384_IV[9] | 0;\n protected Fh: number = SHA384_IV[10] | 0;\n protected Fl: number = SHA384_IV[11] | 0;\n protected Gh: number = SHA384_IV[12] | 0;\n protected Gl: number = SHA384_IV[13] | 0;\n protected Hh: number = SHA384_IV[14] | 0;\n protected Hl: number = SHA384_IV[15] | 0;\n\n constructor() {\n super(48);\n }\n}\n\n/**\n * Truncated SHA512/256 and SHA512/224.\n * SHA512_IV is XORed with 0xa5a5a5a5a5a5a5a5, then used as \"intermediary\" IV of SHA512/t.\n * Then t hashes string to produce result IV.\n * See `test/misc/sha2-gen-iv.js`.\n */\n\n/** SHA512/224 IV */\nconst T224_IV = /* @__PURE__ */ Uint32Array.from([\n 0x8c3d37c8, 0x19544da2, 0x73e19966, 0x89dcd4d6, 0x1dfab7ae, 0x32ff9c82, 0x679dd514, 0x582f9fcf,\n 0x0f6d2b69, 0x7bd44da8, 0x77e36f73, 0x04c48942, 0x3f9d85a8, 0x6a1d36c8, 0x1112e6ad, 0x91d692a1,\n]);\n\n/** SHA512/256 IV */\nconst T256_IV = /* @__PURE__ */ Uint32Array.from([\n 0x22312194, 0xfc2bf72c, 0x9f555fa3, 0xc84c64c2, 0x2393b86b, 0x6f53b151, 0x96387719, 0x5940eabd,\n 0x96283ee2, 0xa88effe3, 0xbe5e1e25, 0x53863992, 0x2b0199fc, 0x2c85b8aa, 0x0eb72ddc, 0x81c52ca2,\n]);\n\n/** Internal SHA2-512/224 hash class. */\nexport class _SHA512_224 extends SHA2_64B<_SHA512_224> {\n protected Ah: number = T224_IV[0] | 0;\n protected Al: number = T224_IV[1] | 0;\n protected Bh: number = T224_IV[2] | 0;\n protected Bl: number = T224_IV[3] | 0;\n protected Ch: number = T224_IV[4] | 0;\n protected Cl: number = T224_IV[5] | 0;\n protected Dh: number = T224_IV[6] | 0;\n protected Dl: number = T224_IV[7] | 0;\n protected Eh: number = T224_IV[8] | 0;\n protected El: number = T224_IV[9] | 0;\n protected Fh: number = T224_IV[10] | 0;\n protected Fl: number = T224_IV[11] | 0;\n protected Gh: number = T224_IV[12] | 0;\n protected Gl: number = T224_IV[13] | 0;\n protected Hh: number = T224_IV[14] | 0;\n protected Hl: number = T224_IV[15] | 0;\n\n constructor() {\n super(28);\n }\n}\n\n/** Internal SHA2-512/256 hash class. */\nexport class _SHA512_256 extends SHA2_64B<_SHA512_256> {\n protected Ah: number = T256_IV[0] | 0;\n protected Al: number = T256_IV[1] | 0;\n protected Bh: number = T256_IV[2] | 0;\n protected Bl: number = T256_IV[3] | 0;\n protected Ch: number = T256_IV[4] | 0;\n protected Cl: number = T256_IV[5] | 0;\n protected Dh: number = T256_IV[6] | 0;\n protected Dl: number = T256_IV[7] | 0;\n protected Eh: number = T256_IV[8] | 0;\n protected El: number = T256_IV[9] | 0;\n protected Fh: number = T256_IV[10] | 0;\n protected Fl: number = T256_IV[11] | 0;\n protected Gh: number = T256_IV[12] | 0;\n protected Gl: number = T256_IV[13] | 0;\n protected Hh: number = T256_IV[14] | 0;\n protected Hl: number = T256_IV[15] | 0;\n\n constructor() {\n super(32);\n }\n}\n\n/**\n * SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:\n *\n * - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.\n * - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\n * - Each sha256 hash is executing 2^18 bit operations.\n * - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.\n */\nexport const sha256: CHash<_SHA256> = /* @__PURE__ */ createHasher(\n () => new _SHA256(),\n /* @__PURE__ */ oidNist(0x01)\n);\n/** SHA2-224 hash function from RFC 4634 */\nexport const sha224: CHash<_SHA224> = /* @__PURE__ */ createHasher(\n () => new _SHA224(),\n /* @__PURE__ */ oidNist(0x04)\n);\n\n/** SHA2-512 hash function from RFC 4634. */\nexport const sha512: CHash<_SHA512> = /* @__PURE__ */ createHasher(\n () => new _SHA512(),\n /* @__PURE__ */ oidNist(0x03)\n);\n/** SHA2-384 hash function from RFC 4634. */\nexport const sha384: CHash<_SHA384> = /* @__PURE__ */ createHasher(\n () => new _SHA384(),\n /* @__PURE__ */ oidNist(0x02)\n);\n\n/**\n * SHA2-512/256 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_256: CHash<_SHA512_256> = /* @__PURE__ */ createHasher(\n () => new _SHA512_256(),\n /* @__PURE__ */ oidNist(0x06)\n);\n/**\n * SHA2-512/224 \"truncated\" hash function, with improved resistance to length extension attacks.\n * See the paper on [truncated SHA512](https://eprint.iacr.org/2010/548.pdf).\n */\nexport const sha512_224: CHash<_SHA512_224> = /* @__PURE__ */ createHasher(\n () => new _SHA512_224(),\n /* @__PURE__ */ oidNist(0x05)\n);\n","/**\n * Browser IPFS Storage Provider\n * Implements TokenStorageProvider using IPFS/IPNS for decentralized storage\n *\n * Uses a hybrid approach:\n * - HTTP API to backend gateways for fast publishing/resolution\n * - Helia for browser-based DHT operations as backup\n */\n\nimport type { ProviderStatus, FullIdentity } from '../../../types';\nimport type {\n TokenStorageProvider,\n TxfStorageDataBase,\n TxfTombstone,\n SaveResult,\n LoadResult,\n SyncResult,\n StorageEvent,\n StorageEventCallback,\n} from '../../../storage';\nimport {\n DEFAULT_IPFS_GATEWAYS,\n DEFAULT_IPFS_BOOTSTRAP_PEERS,\n} from '../../../constants';\n\n// Helia and IPFS types (runtime imports are dynamic)\nimport type { Helia } from 'helia';\nimport type { JSON as HeliaJSON } from '@helia/json';\nimport type { PrivateKey } from '@libp2p/interface';\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\n\n// Dynamic import cache\nlet heliaModule: typeof import('helia') | null = null;\nlet heliaJsonModule: typeof import('@helia/json') | null = null;\nlet libp2pBootstrapModule: typeof import('@libp2p/bootstrap') | null = null;\nlet libp2pCryptoModule: typeof import('@libp2p/crypto/keys') | null = null;\nlet libp2pPeerIdModule: typeof import('@libp2p/peer-id') | null = null;\nlet multiformatsCidModule: typeof import('multiformats/cid') | null = null;\n\nasync function loadHeliaModules() {\n if (!heliaModule) {\n [\n heliaModule,\n heliaJsonModule,\n libp2pBootstrapModule,\n libp2pCryptoModule,\n libp2pPeerIdModule,\n multiformatsCidModule,\n ] = await Promise.all([\n import('helia'),\n import('@helia/json'),\n import('@libp2p/bootstrap'),\n import('@libp2p/crypto/keys'),\n import('@libp2p/peer-id'),\n import('multiformats/cid'),\n ]);\n }\n return {\n createHelia: heliaModule!.createHelia,\n json: heliaJsonModule!.json,\n bootstrap: libp2pBootstrapModule!.bootstrap,\n generateKeyPairFromSeed: libp2pCryptoModule!.generateKeyPairFromSeed,\n peerIdFromPrivateKey: libp2pPeerIdModule!.peerIdFromPrivateKey,\n CID: multiformatsCidModule!.CID,\n };\n}\n\n/** HKDF info for IPNS key derivation */\nconst HKDF_INFO = new TextEncoder().encode('ipfs-storage-key');\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface IpfsStorageProviderConfig {\n /** IPFS gateway URLs for HTTP API */\n gateways?: string[];\n /** Bootstrap peers for DHT */\n bootstrapPeers?: string[];\n /** Enable IPNS for mutable addressing */\n enableIpns?: boolean;\n /** IPNS publish timeout (ms) */\n ipnsTimeout?: number;\n /** Content fetch timeout (ms) */\n fetchTimeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\nexport class IpfsStorageProvider<TData extends TxfStorageDataBase = TxfStorageDataBase>\n implements TokenStorageProvider<TData>\n{\n readonly id = 'ipfs';\n readonly name = 'IPFS Storage';\n readonly type = 'p2p' as const;\n readonly description = 'Decentralized storage via IPFS/IPNS';\n\n private config: Required<IpfsStorageProviderConfig>;\n private identity: FullIdentity | null = null;\n private status: ProviderStatus = 'disconnected';\n private ipnsName: string | null = null;\n private lastCid: string | null = null;\n private eventCallbacks: Set<StorageEventCallback> = new Set();\n\n // Helia instance for browser-based IPFS\n private helia: Helia | null = null;\n private heliaJson: HeliaJSON | null = null;\n private ipnsKeyPair: PrivateKey | null = null;\n\n /** Get the last published CID */\n getLastCid(): string | null {\n return this.lastCid;\n }\n\n // Local cache for faster loads\n private localCache: TData | null = null;\n private cacheTimestamp = 0;\n\n constructor(config?: IpfsStorageProviderConfig) {\n this.config = {\n gateways: config?.gateways ?? [...DEFAULT_IPFS_GATEWAYS],\n bootstrapPeers: config?.bootstrapPeers ?? [...DEFAULT_IPFS_BOOTSTRAP_PEERS],\n enableIpns: config?.enableIpns ?? true,\n ipnsTimeout: config?.ipnsTimeout ?? 30000,\n fetchTimeout: config?.fetchTimeout ?? 15000,\n debug: config?.debug ?? false,\n };\n }\n\n // ===========================================================================\n // BaseProvider Implementation\n // ===========================================================================\n\n async connect(): Promise<void> {\n if (this.status === 'connected') return;\n\n this.status = 'connecting';\n\n try {\n // Test gateway connectivity first (fast path)\n await this.testGatewayConnectivity();\n\n // Initialize Helia for browser-based DHT\n await this.initializeHelia();\n\n this.status = 'connected';\n this.log('Connected to IPFS gateways and Helia initialized');\n } catch (error) {\n this.status = 'error';\n throw new Error(`IPFS connection failed: ${error}`);\n }\n }\n\n /**\n * Initialize Helia browser IPFS node\n */\n private async initializeHelia(): Promise<void> {\n if (this.helia) return;\n\n try {\n this.log('Initializing Helia with bootstrap peers...');\n\n const { createHelia, json, bootstrap } = await loadHeliaModules();\n\n this.helia = await createHelia({\n libp2p: {\n peerDiscovery: [\n bootstrap({ list: this.config.bootstrapPeers }),\n ],\n connectionManager: {\n maxConnections: 10,\n },\n },\n });\n\n this.heliaJson = json(this.helia);\n\n const peerId = this.helia.libp2p.peerId.toString();\n this.log('Helia initialized, browser peer ID:', peerId.slice(0, 20) + '...');\n\n // Log connections after a short delay\n setTimeout(() => {\n const connections = this.helia?.libp2p.getConnections() || [];\n this.log(`Active Helia connections: ${connections.length}`);\n }, 3000);\n } catch (error) {\n this.log('Helia initialization failed (will use HTTP only):', error);\n // Non-fatal - HTTP gateways still work\n }\n }\n\n async disconnect(): Promise<void> {\n // Stop Helia\n if (this.helia) {\n try {\n await this.helia.stop();\n } catch (error) {\n this.log('Error stopping Helia:', error);\n }\n this.helia = null;\n this.heliaJson = null;\n }\n\n this.status = 'disconnected';\n this.localCache = null;\n this.ipnsKeyPair = null;\n this.log('Disconnected from IPFS');\n }\n\n isConnected(): boolean {\n return this.status === 'connected';\n }\n\n getStatus(): ProviderStatus {\n return this.status;\n }\n\n // ===========================================================================\n // TokenStorageProvider Implementation\n // ===========================================================================\n\n async setIdentity(identity: FullIdentity): Promise<void> {\n this.identity = identity;\n\n // Derive IPNS key pair from wallet private key using HKDF\n try {\n const { generateKeyPairFromSeed, peerIdFromPrivateKey } = await loadHeliaModules();\n const walletSecret = this.hexToBytes(identity.privateKey);\n const derivedKey = hkdf(sha256, walletSecret, undefined, HKDF_INFO, 32);\n\n // Generate libp2p Ed25519 key pair for IPNS\n this.ipnsKeyPair = await generateKeyPairFromSeed('Ed25519', derivedKey);\n const peerId = peerIdFromPrivateKey(this.ipnsKeyPair);\n this.ipnsName = peerId.toString();\n\n this.log('Identity set, IPNS name:', this.ipnsName);\n } catch {\n // Fallback to provided IPNS name or simple derivation\n this.ipnsName = identity.ipnsName ?? this.deriveIpnsNameSimple(identity.privateKey);\n this.log('Identity set with fallback IPNS name:', this.ipnsName);\n }\n }\n\n async initialize(): Promise<boolean> {\n if (!this.identity) {\n throw new Error('Identity must be set before initialization');\n }\n\n try {\n await this.connect();\n return true;\n } catch {\n return false;\n }\n }\n\n async shutdown(): Promise<void> {\n await this.disconnect();\n }\n\n async save(data: TData): Promise<SaveResult> {\n this.ensureReady();\n this.emitEvent({ type: 'storage:saving', timestamp: Date.now() });\n\n try {\n // Update metadata\n const dataToSave: TData = {\n ...data,\n _meta: {\n ...data._meta,\n updatedAt: Date.now(),\n ipnsName: this.ipnsName ?? undefined,\n },\n };\n\n // Publish to IPFS (parallel to all gateways)\n const cid = await this.publishToGateways(dataToSave);\n\n // Update IPNS if enabled\n if (this.config.enableIpns && this.ipnsName) {\n await this.publishIpns(cid);\n }\n\n // Update local cache\n this.localCache = dataToSave;\n this.cacheTimestamp = Date.now();\n this.lastCid = cid;\n\n this.emitEvent({ type: 'storage:saved', timestamp: Date.now(), data: { cid } });\n\n return {\n success: true,\n cid,\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitEvent({ type: 'storage:error', timestamp: Date.now(), error: errorMsg });\n\n return {\n success: false,\n error: errorMsg,\n timestamp: Date.now(),\n };\n }\n }\n\n async load(identifier?: string): Promise<LoadResult<TData>> {\n this.ensureReady();\n this.emitEvent({ type: 'storage:loading', timestamp: Date.now() });\n\n try {\n // Try local cache first (if recent)\n const cacheAge = Date.now() - this.cacheTimestamp;\n if (this.localCache && cacheAge < 60000) {\n this.log('Returning cached data');\n return {\n success: true,\n data: this.localCache,\n source: 'cache',\n timestamp: Date.now(),\n };\n }\n\n // Resolve IPNS or use direct CID\n let cid: string | null = identifier ?? null;\n\n if (!cid && this.config.enableIpns && this.ipnsName) {\n cid = await this.resolveIpns(this.ipnsName);\n }\n\n if (!cid) {\n // No remote data found\n return {\n success: true,\n data: undefined,\n source: 'remote',\n timestamp: Date.now(),\n };\n }\n\n // Fetch content\n const data = await this.fetchFromGateways<TData>(cid);\n\n // Update cache\n this.localCache = data;\n this.cacheTimestamp = Date.now();\n this.lastCid = cid;\n\n this.emitEvent({ type: 'storage:loaded', timestamp: Date.now() });\n\n return {\n success: true,\n data,\n source: 'remote',\n timestamp: Date.now(),\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitEvent({ type: 'storage:error', timestamp: Date.now(), error: errorMsg });\n\n // Fallback to cache on error\n if (this.localCache) {\n return {\n success: true,\n data: this.localCache,\n source: 'cache',\n timestamp: Date.now(),\n };\n }\n\n return {\n success: false,\n error: errorMsg,\n source: 'remote',\n timestamp: Date.now(),\n };\n }\n }\n\n async sync(localData: TData): Promise<SyncResult<TData>> {\n this.ensureReady();\n this.emitEvent({ type: 'sync:started', timestamp: Date.now() });\n\n try {\n // Load remote data\n const remoteResult = await this.load();\n const remoteData = remoteResult.data;\n\n if (!remoteData) {\n // No remote data, just save local\n await this.save(localData);\n this.emitEvent({ type: 'sync:completed', timestamp: Date.now() });\n return {\n success: true,\n merged: localData,\n added: 0,\n removed: 0,\n conflicts: 0,\n };\n }\n\n // Merge data\n const mergeResult = this.mergeData(localData, remoteData);\n\n // Save merged result\n await this.save(mergeResult.merged);\n\n this.emitEvent({ type: 'sync:completed', timestamp: Date.now() });\n\n return {\n success: true,\n merged: mergeResult.merged,\n added: mergeResult.added,\n removed: mergeResult.removed,\n conflicts: mergeResult.conflicts,\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitEvent({ type: 'sync:error', timestamp: Date.now(), error: errorMsg });\n\n return {\n success: false,\n added: 0,\n removed: 0,\n conflicts: 0,\n error: errorMsg,\n };\n }\n }\n\n async exists(): Promise<boolean> {\n if (!this.ipnsName) return false;\n\n try {\n const cid = await this.resolveIpns(this.ipnsName);\n return cid !== null;\n } catch {\n return false;\n }\n }\n\n async clear(): Promise<boolean> {\n // IPFS is immutable, we can only publish empty data\n const emptyData = {\n _meta: {\n version: 0,\n address: this.identity?.l1Address ?? '',\n formatVersion: '2.0',\n updatedAt: Date.now(),\n },\n _tombstones: [],\n } as unknown as TData;\n\n const result = await this.save(emptyData);\n return result.success;\n }\n\n onEvent(callback: StorageEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => this.eventCallbacks.delete(callback);\n }\n\n // ===========================================================================\n // Private: IPFS Operations\n // ===========================================================================\n\n private async testGatewayConnectivity(): Promise<void> {\n const gateway = this.config.gateways[0];\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n\n try {\n const response = await fetch(`${gateway}/api/v0/version`, {\n method: 'POST',\n signal: controller.signal,\n });\n if (!response.ok) throw new Error('Gateway not responding');\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async publishToGateways(data: TData): Promise<string> {\n const content = JSON.stringify(data);\n const blob = new Blob([content], { type: 'application/json' });\n\n // Strategy: Try both HTTP and Helia in parallel, return first success\n const promises: Promise<string>[] = [];\n\n // HTTP gateway publishing (fast path)\n for (const gateway of this.config.gateways) {\n promises.push(this.publishToGateway(gateway, blob));\n }\n\n // Helia DHT publishing (backup path)\n if (this.heliaJson) {\n promises.push(this.publishToHelia(data));\n }\n\n try {\n const cid = await Promise.any(promises);\n this.log('Published to IPFS, CID:', cid);\n return cid;\n } catch {\n throw new Error('All publish attempts failed');\n }\n }\n\n /**\n * Publish data via Helia (browser DHT)\n */\n private async publishToHelia(data: TData): Promise<string> {\n if (!this.heliaJson) {\n throw new Error('Helia not initialized');\n }\n\n const cid = await this.heliaJson.add(data);\n this.log('Published via Helia, CID:', cid.toString());\n return cid.toString();\n }\n\n private async publishToGateway(gateway: string, blob: Blob): Promise<string> {\n const formData = new FormData();\n formData.append('file', blob);\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.fetchTimeout);\n\n try {\n const response = await fetch(`${gateway}/api/v0/add?pin=true`, {\n method: 'POST',\n body: formData,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Gateway ${gateway} returned ${response.status}`);\n }\n\n const result = await response.json();\n return result.Hash;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async publishIpns(cid: string): Promise<void> {\n if (!this.identity) return;\n\n // Publish to all gateways in parallel\n const promises = this.config.gateways.map((gateway) =>\n this.publishIpnsToGateway(gateway, cid).catch(() => null)\n );\n\n await Promise.allSettled(promises);\n this.log('Published IPNS:', this.ipnsName, '->', cid);\n }\n\n private async publishIpnsToGateway(gateway: string, cid: string): Promise<void> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.ipnsTimeout);\n\n try {\n const response = await fetch(\n `${gateway}/api/v0/name/publish?arg=${cid}&key=${this.ipnsName}`,\n {\n method: 'POST',\n signal: controller.signal,\n }\n );\n\n if (!response.ok) {\n throw new Error(`IPNS publish failed: ${response.status}`);\n }\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async resolveIpns(name: string): Promise<string | null> {\n // Try each gateway\n for (const gateway of this.config.gateways) {\n try {\n return await this.resolveIpnsFromGateway(gateway, name);\n } catch {\n continue;\n }\n }\n return null;\n }\n\n private async resolveIpnsFromGateway(gateway: string, name: string): Promise<string> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.fetchTimeout);\n\n try {\n const response = await fetch(`${gateway}/api/v0/name/resolve?arg=${name}`, {\n method: 'POST',\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`IPNS resolve failed: ${response.status}`);\n }\n\n const result = await response.json();\n // Path is like \"/ipfs/Qm...\"\n return result.Path.replace('/ipfs/', '');\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async fetchFromGateways<T>(cid: string): Promise<T> {\n // Strategy: Try both HTTP and Helia in parallel\n const promises: Promise<T>[] = [];\n\n // HTTP gateway fetching (fast path)\n for (const gateway of this.config.gateways) {\n promises.push(this.fetchFromGateway<T>(gateway, cid));\n }\n\n // Helia DHT fetching (backup path)\n if (this.heliaJson) {\n promises.push(this.fetchFromHelia<T>(cid));\n }\n\n return Promise.any(promises);\n }\n\n /**\n * Fetch content via Helia (browser DHT)\n */\n private async fetchFromHelia<T>(cidString: string): Promise<T> {\n if (!this.heliaJson) {\n throw new Error('Helia not initialized');\n }\n\n const { CID } = await loadHeliaModules();\n const cid = CID.parse(cidString);\n const data = await this.heliaJson.get(cid);\n this.log('Fetched via Helia, CID:', cidString);\n return data as T;\n }\n\n private async fetchFromGateway<T>(gateway: string, cid: string): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.fetchTimeout);\n\n try {\n const response = await fetch(`${gateway}/ipfs/${cid}`, {\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status}`);\n }\n\n return response.json();\n } finally {\n clearTimeout(timeout);\n }\n }\n\n // ===========================================================================\n // Private: Merge Logic\n // ===========================================================================\n\n private mergeData(\n local: TData,\n remote: TData\n ): { merged: TData; added: number; removed: number; conflicts: number } {\n const localVersion = local._meta?.version ?? 0;\n const remoteVersion = remote._meta?.version ?? 0;\n\n // Simple strategy: newer version wins for meta\n const baseMeta = remoteVersion > localVersion ? remote._meta : local._meta;\n\n // Merge tombstones (union)\n const tombstones = new Map<string, TxfTombstone>();\n for (const t of local._tombstones ?? []) {\n tombstones.set(t.tokenId, t);\n }\n for (const t of remote._tombstones ?? []) {\n const existing = tombstones.get(t.tokenId);\n if (!existing || t.timestamp > existing.timestamp) {\n tombstones.set(t.tokenId, t);\n }\n }\n\n // Merge token entries (newer wins, respect tombstones)\n const merged = {\n _meta: {\n ...baseMeta,\n version: Math.max(localVersion, remoteVersion) + 1,\n updatedAt: Date.now(),\n },\n _tombstones: Array.from(tombstones.values()),\n } as unknown as TData;\n\n let added = 0;\n let conflicts = 0;\n\n // Process all token entries from both sources\n const processedKeys = new Set<string>();\n\n for (const key of Object.keys(local)) {\n if (!key.startsWith('_') || key === '_meta' || key === '_tombstones') continue;\n processedKeys.add(key);\n\n const tokenId = key.slice(1); // Remove leading _\n if (tombstones.has(tokenId)) continue; // Deleted\n\n const localToken = local[key as keyof TData];\n const remoteToken = remote[key as keyof TData];\n\n if (remoteToken) {\n // Both have it - conflict resolution\n conflicts++;\n // Use local (could be smarter based on timestamps)\n (merged as Record<string, unknown>)[key] = localToken;\n } else {\n (merged as Record<string, unknown>)[key] = localToken;\n }\n }\n\n for (const key of Object.keys(remote)) {\n if (!key.startsWith('_') || key === '_meta' || key === '_tombstones') continue;\n if (processedKeys.has(key)) continue;\n\n const tokenId = key.slice(1);\n if (tombstones.has(tokenId)) continue;\n\n (merged as Record<string, unknown>)[key] = remote[key as keyof TData];\n added++;\n }\n\n return { merged, added, removed: 0, conflicts };\n }\n\n // ===========================================================================\n // Private: Helpers\n // ===========================================================================\n\n private ensureReady(): void {\n if (this.status !== 'connected') {\n throw new Error('IpfsStorageProvider not connected');\n }\n if (!this.identity) {\n throw new Error('Identity not set');\n }\n }\n\n /**\n * Simple IPNS name derivation (fallback when libp2p is unavailable)\n */\n private deriveIpnsNameSimple(privateKey: string): string {\n // Fallback: use truncated hash of private key\n return `12D3KooW${privateKey.slice(0, 40)}`;\n }\n\n /**\n * Convert hex string to Uint8Array\n */\n private hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n }\n return bytes;\n }\n\n private emitEvent(event: StorageEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n console.error('[IpfsStorageProvider] Event callback error:', error);\n }\n }\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[IpfsStorageProvider]', ...args);\n }\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\nexport function createIpfsStorageProvider<TData extends TxfStorageDataBase = TxfStorageDataBase>(\n config?: IpfsStorageProviderConfig\n): IpfsStorageProvider<TData> {\n return new IpfsStorageProvider<TData>(config);\n}\n"],"mappings":"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","names":[]}
@@ -21,7 +21,9 @@ var STORAGE_KEYS_GLOBAL = {
21
21
  /** Nametag cache per address (separate from tracked addresses registry) */
22
22
  ADDRESS_NAMETAGS: "address_nametags",
23
23
  /** Active addresses registry (JSON: TrackedAddressesStorage) */
24
- TRACKED_ADDRESSES: "tracked_addresses"
24
+ TRACKED_ADDRESSES: "tracked_addresses",
25
+ /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
26
+ LAST_WALLET_EVENT_TS: "last_wallet_event_ts"
25
27
  };
26
28
  var STORAGE_KEYS_ADDRESS = {
27
29
  /** Pending transfers for this address */