{"version":3,"sources":["../../../src/crypto/ecies/browser.ts"],"sourcesContent":["/**\n * Browser implementation of ECIES using @noble/secp256k1 with Uint8Array\n *\n * @remarks\n * Uses native browser crypto APIs and @noble/secp256k1 for elliptic curve operations.\n * This implementation is polyfill-free and works in all modern browsers.\n */\n\nimport * as secp256k1 from \"@noble/secp256k1\";\nimport { BaseECIESUint8 } from \"./base\";\nimport { toHex } from \"viem\";\nimport { hmac } from \"@noble/hashes/hmac\";\nimport { sha256, sha512 as nobleSha512 } from \"@noble/hashes/sha2\";\n\n/**\n * Browser-specific ECIES provider using @noble/secp256k1\n *\n * @remarks\n * This implementation uses:\n * - Web Crypto API for AES operations\n * - @noble/secp256k1 for elliptic curve operations\n * - @noble/hashes for SHA and HMAC operations\n * - No Buffer or Node.js dependencies\n */\nexport class BrowserECIESUint8Provider extends BaseECIESUint8 {\n  protected generateRandomBytes(length: number): Uint8Array {\n    const bytes = new Uint8Array(length);\n    crypto.getRandomValues(bytes);\n    return bytes;\n  }\n\n  protected verifyPrivateKey(privateKey: Uint8Array): boolean {\n    try {\n      return secp256k1.utils.isValidPrivateKey(privateKey);\n    } catch {\n      return false;\n    }\n  }\n\n  protected createPublicKey(\n    privateKey: Uint8Array,\n    compressed: boolean,\n  ): Uint8Array | null {\n    try {\n      return secp256k1.getPublicKey(privateKey, compressed);\n    } catch {\n      return null;\n    }\n  }\n\n  protected validatePublicKey(publicKey: Uint8Array): boolean {\n    try {\n      // @noble/secp256k1 will throw if the point is not on the curve\n      secp256k1.Point.fromHex(publicKey);\n      return true;\n    } catch {\n      return false;\n    }\n  }\n\n  protected decompressPublicKey(publicKey: Uint8Array): Uint8Array | null {\n    try {\n      // @noble/secp256k1 handles both compressed and uncompressed\n      const point = secp256k1.Point.fromHex(publicKey);\n      return point.toRawBytes(false); // false = uncompressed\n    } catch {\n      return null;\n    }\n  }\n\n  protected performECDH(\n    publicKey: Uint8Array,\n    privateKey: Uint8Array,\n  ): Uint8Array {\n    try {\n      // Use @noble/secp256k1's getSharedSecret which is optimized and secure\n      // The 'true' parameter returns the raw x-coordinate (32 bytes)\n      // This matches eccrypto's behavior\n      const sharedPoint = secp256k1.getSharedSecret(\n        privateKey,\n        publicKey,\n        true,\n      );\n\n      // getSharedSecret returns compressed point (33 bytes) when true\n      // We need just the x-coordinate (32 bytes) for eccrypto compatibility\n      // Remove the prefix byte\n      return sharedPoint.slice(1);\n    } catch (error) {\n      throw new Error(\n        `ECDH failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n      );\n    }\n  }\n\n  protected sha512(data: Uint8Array): Uint8Array {\n    return nobleSha512(data);\n  }\n\n  protected hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array {\n    return hmac(sha256, key, data);\n  }\n\n  protected async aesEncrypt(\n    key: Uint8Array,\n    iv: Uint8Array,\n    plaintext: Uint8Array,\n  ): Promise<Uint8Array> {\n    // Import the key for AES-CBC\n    const cryptoKey = await crypto.subtle.importKey(\n      \"raw\",\n      key as BufferSource,\n      { name: \"AES-CBC\" },\n      false,\n      [\"encrypt\"],\n    );\n\n    // Encrypt with Web Crypto API\n    // Note: Web Crypto API automatically handles PKCS#7 padding for AES-CBC\n    const encrypted = await crypto.subtle.encrypt(\n      { name: \"AES-CBC\", iv: iv as BufferSource },\n      cryptoKey,\n      plaintext as BufferSource,\n    );\n\n    return new Uint8Array(encrypted);\n  }\n\n  protected async aesDecrypt(\n    key: Uint8Array,\n    iv: Uint8Array,\n    ciphertext: Uint8Array,\n  ): Promise<Uint8Array> {\n    // Import the key for AES-CBC\n    const cryptoKey = await crypto.subtle.importKey(\n      \"raw\",\n      key as BufferSource,\n      { name: \"AES-CBC\" },\n      false,\n      [\"decrypt\"],\n    );\n\n    // Decrypt with Web Crypto API\n    // Note: Web Crypto API automatically handles PKCS#7 padding removal\n    const decrypted = await crypto.subtle.decrypt(\n      { name: \"AES-CBC\", iv: iv as BufferSource },\n      cryptoKey,\n      ciphertext as BufferSource,\n    );\n\n    return new Uint8Array(decrypted);\n  }\n\n  /**\n   * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n   * Handles compressed (33 bytes) and uncompressed (65 bytes) formats only.\n   *\n   * @remarks\n   * Strict policy: Does not accept 64-byte raw coordinates to avoid masking\n   * malformed data. Callers must provide properly formatted keys.\n   *\n   * @param publicKey - The public key to normalize (33 or 65 bytes)\n   * @returns The normalized uncompressed public key (65 bytes)\n   * @throws {Error} When public key format is invalid or decompression fails\n   */\n  normalizeToUncompressed(publicKey: Uint8Array): Uint8Array {\n    const len = publicKey.length;\n\n    // Already uncompressed\n    if (len === 65 && publicKey[0] === 0x04) {\n      return publicKey;\n    }\n\n    // Compressed - decompress using @noble/secp256k1\n    if (len === 33 && (publicKey[0] === 0x02 || publicKey[0] === 0x03)) {\n      const decompressed = this.decompressPublicKey(publicKey);\n      if (!decompressed) {\n        throw new Error(\n          `Failed to decompress public key with prefix ${toHex(publicKey[0])}`,\n        );\n      }\n      return decompressed;\n    }\n\n    // Reject raw coordinates (64 bytes) - require proper formatting\n    if (len === 64) {\n      throw new Error(\n        \"Raw public key coordinates (64 bytes) are not accepted. \" +\n          \"Please provide a properly formatted compressed (33 bytes) or uncompressed (65 bytes) public key.\",\n      );\n    }\n\n    throw new Error(\n      `Invalid public key format: expected compressed (33 bytes) or uncompressed (65 bytes), got ${len} bytes`,\n    );\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,gBAA2B;AAC3B,kBAA+B;AAC/B,kBAAsB;AACtB,kBAAqB;AACrB,kBAA8C;AAYvC,MAAM,kCAAkC,2BAAe;AAAA,EAClD,oBAAoB,QAA4B;AACxD,UAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,WAAO,gBAAgB,KAAK;AAC5B,WAAO;AAAA,EACT;AAAA,EAEU,iBAAiB,YAAiC;AAC1D,QAAI;AACF,aAAO,UAAU,MAAM,kBAAkB,UAAU;AAAA,IACrD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEU,gBACR,YACA,YACmB;AACnB,QAAI;AACF,aAAO,UAAU,aAAa,YAAY,UAAU;AAAA,IACtD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEU,kBAAkB,WAAgC;AAC1D,QAAI;AAEF,gBAAU,MAAM,QAAQ,SAAS;AACjC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEU,oBAAoB,WAA0C;AACtE,QAAI;AAEF,YAAM,QAAQ,UAAU,MAAM,QAAQ,SAAS;AAC/C,aAAO,MAAM,WAAW,KAAK;AAAA,IAC/B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEU,YACR,WACA,YACY;AACZ,QAAI;AAIF,YAAM,cAAc,UAAU;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAKA,aAAO,YAAY,MAAM,CAAC;AAAA,IAC5B,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAAA,EAEU,OAAO,MAA8B;AAC7C,eAAO,YAAAA,QAAY,IAAI;AAAA,EACzB;AAAA,EAEU,WAAW,KAAiB,MAA8B;AAClE,eAAO,kBAAK,oBAAQ,KAAK,IAAI;AAAA,EAC/B;AAAA,EAEA,MAAgB,WACd,KACA,IACA,WACqB;AAErB,UAAM,YAAY,MAAM,OAAO,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA,EAAE,MAAM,UAAU;AAAA,MAClB;AAAA,MACA,CAAC,SAAS;AAAA,IACZ;AAIA,UAAM,YAAY,MAAM,OAAO,OAAO;AAAA,MACpC,EAAE,MAAM,WAAW,GAAuB;AAAA,MAC1C;AAAA,MACA;AAAA,IACF;AAEA,WAAO,IAAI,WAAW,SAAS;AAAA,EACjC;AAAA,EAEA,MAAgB,WACd,KACA,IACA,YACqB;AAErB,UAAM,YAAY,MAAM,OAAO,OAAO;AAAA,MACpC;AAAA,MACA;AAAA,MACA,EAAE,MAAM,UAAU;AAAA,MAClB;AAAA,MACA,CAAC,SAAS;AAAA,IACZ;AAIA,UAAM,YAAY,MAAM,OAAO,OAAO;AAAA,MACpC,EAAE,MAAM,WAAW,GAAuB;AAAA,MAC1C;AAAA,MACA;AAAA,IACF;AAEA,WAAO,IAAI,WAAW,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,wBAAwB,WAAmC;AACzD,UAAM,MAAM,UAAU;AAGtB,QAAI,QAAQ,MAAM,UAAU,CAAC,MAAM,GAAM;AACvC,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,OAAO,UAAU,CAAC,MAAM,KAAQ,UAAU,CAAC,MAAM,IAAO;AAClE,YAAM,eAAe,KAAK,oBAAoB,SAAS;AACvD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI;AAAA,UACR,mDAA+C,mBAAM,UAAU,CAAC,CAAC,CAAC;AAAA,QACpE;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,IAAI;AACd,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAEA,UAAM,IAAI;AAAA,MACR,6FAA6F,GAAG;AAAA,IAClG;AAAA,EACF;AACF;","names":["nobleSha512"]}