@opendatalabs/vana-sdk 2.2.0 → 2.2.2
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.
- package/dist/config/features.cjs +1 -24
- package/dist/config/features.cjs.map +1 -1
- package/dist/config/features.d.ts +13 -44
- package/dist/config/features.js +1 -24
- package/dist/config/features.js.map +1 -1
- package/dist/crypto/ecies/__tests__/constants.test.d.ts +1 -1
- package/dist/crypto/ecies/__tests__/serialization.test.d.ts +8 -0
- package/dist/crypto/ecies/base.cjs +43 -20
- package/dist/crypto/ecies/base.cjs.map +1 -1
- package/dist/crypto/ecies/base.js +43 -20
- package/dist/crypto/ecies/base.js.map +1 -1
- package/dist/crypto/ecies/constants.cjs +2 -10
- package/dist/crypto/ecies/constants.cjs.map +1 -1
- package/dist/crypto/ecies/constants.d.ts +0 -9
- package/dist/crypto/ecies/constants.js +1 -8
- package/dist/crypto/ecies/constants.js.map +1 -1
- package/dist/crypto/ecies/index.cjs.map +1 -1
- package/dist/crypto/ecies/index.d.ts +10 -2
- package/dist/crypto/ecies/index.js.map +1 -1
- package/dist/crypto/ecies/interface.cjs +19 -2
- package/dist/crypto/ecies/interface.cjs.map +1 -1
- package/dist/crypto/ecies/interface.js +19 -2
- package/dist/crypto/ecies/interface.js.map +1 -1
- package/dist/index.browser.d.ts +2 -0
- package/dist/index.browser.js +10 -0
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +12 -0
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.d.ts +3 -0
- package/dist/index.node.js +12 -0
- package/dist/index.node.js.map +1 -1
- package/dist/platform/browser.cjs +40 -119
- package/dist/platform/browser.cjs.map +1 -1
- package/dist/platform/browser.d.ts +7 -7
- package/dist/platform/browser.js +40 -119
- package/dist/platform/browser.js.map +1 -1
- package/dist/platform/node.cjs +51 -129
- package/dist/platform/node.cjs.map +1 -1
- package/dist/platform/node.d.ts +5 -5
- package/dist/platform/node.js +51 -129
- package/dist/platform/node.js.map +1 -1
- package/package.json +1 -2
- package/dist/types/eccrypto-js.d.cjs +0 -2
- package/dist/types/eccrypto-js.d.cjs.map +0 -1
- package/dist/types/eccrypto-js.d.js +0 -1
- package/dist/types/eccrypto-js.d.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/base.ts"],"sourcesContent":["import type { ECIESProvider, ECIESEncrypted } from \"./interface\";\nimport { ECIESError, isECIESEncrypted } from \"./interface\";\nimport { CURVE, CIPHER, KDF } from \"./constants\";\nimport { constantTimeEqual } from \"./utils\";\nimport { concat } from \"viem\";\n\n/**\n * Provides shared ECIES encryption logic across platforms using Uint8Array.\n *\n * @remarks\n * Platform implementations extend this class and provide crypto primitives.\n * The base class handles the ECIES protocol flow while maintaining\n * compatibility with the eccrypto data format.\n *\n * **Implementation details:**\n * - KDF: SHA-512(shared_secret) → encKey (32B) || macKey (32B)\n * - Cipher: AES-256-CBC with random 16-byte IV\n * - MAC: HMAC-SHA256(macKey, iv || ephemPublicKey || ciphertext)\n *\n * @category Cryptography\n */\nexport abstract class BaseECIESUint8 implements ECIESProvider {\n // Cache for validated public keys to avoid repeated validation\n private static readonly validatedKeys = new WeakMap<Uint8Array, boolean>();\n\n /**\n * Generates cryptographically secure random bytes.\n *\n * @param length - Number of random bytes to generate.\n * @returns Random bytes array.\n */\n protected abstract generateRandomBytes(length: number): Uint8Array;\n\n /**\n * Verifies a private key is valid for secp256k1.\n *\n * @param privateKey - Private key to verify (32 bytes).\n * @returns `true` if valid private key.\n */\n protected abstract verifyPrivateKey(privateKey: Uint8Array): boolean;\n\n /**\n * Creates a public key from a private key.\n *\n * @param privateKey - Source private key (32 bytes).\n * @param compressed - Generate compressed (33B) or uncompressed (65B) format.\n * @returns Public key or `null` if creation failed.\n */\n protected abstract createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null;\n\n /**\n * Validates a public key on the secp256k1 curve.\n *\n * @param publicKey - Public key to validate.\n * @returns `true` if valid public key.\n */\n protected abstract validatePublicKey(publicKey: Uint8Array): boolean;\n\n /**\n * Decompresses a compressed public key.\n *\n * @param publicKey - Compressed public key (33 bytes).\n * @returns Uncompressed public key (65 bytes) or `null` if decompression failed.\n */\n protected abstract decompressPublicKey(\n publicKey: Uint8Array,\n ): Uint8Array | null;\n\n /**\n * Performs ECDH key agreement.\n *\n * @param publicKey - Other party's public key.\n * @param privateKey - Your private key.\n * @returns Raw X coordinate of shared point (32 bytes).\n */\n protected abstract performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array;\n\n /**\n * Computes SHA-512 hash.\n *\n * @param data - Data to hash.\n * @returns SHA-512 hash (64 bytes).\n */\n protected abstract sha512(data: Uint8Array): Uint8Array;\n\n /**\n * Computes HMAC-SHA256 authentication tag.\n *\n * @param key - HMAC key.\n * @param data - Data to authenticate.\n * @returns HMAC-SHA256 (32 bytes).\n */\n protected abstract hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using AES-256-CBC.\n *\n * @param key - Encryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param plaintext - Data to encrypt.\n * @returns Ciphertext with PKCS#7 padding.\n */\n protected abstract aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Decrypts data using AES-256-CBC.\n *\n * @param key - Decryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param ciphertext - Data to decrypt.\n * @returns Plaintext with padding removed.\n */\n protected abstract aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format.\n *\n * @param publicKey - Public key in any format.\n * @returns Uncompressed public key (65 bytes).\n * @throws {ECIESError} If key format is invalid.\n */\n protected normalizePublicKey(publicKey: Uint8Array): Uint8Array {\n // Check cache first\n if (BaseECIESUint8.validatedKeys.has(publicKey)) {\n return publicKey;\n }\n\n if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {\n if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid uncompressed public key prefix\",\n \"INVALID_KEY\",\n );\n }\n // Validate and cache\n if (!this.validatePublicKey(publicKey)) {\n throw new ECIESError(\"Invalid public key\", \"INVALID_KEY\");\n }\n BaseECIESUint8.validatedKeys.set(publicKey, true);\n return publicKey;\n }\n\n if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new ECIESError(\"Failed to decompress public key\", \"INVALID_KEY\");\n }\n // Cache the decompressed key\n BaseECIESUint8.validatedKeys.set(decompressed, true);\n return decompressed;\n }\n\n throw new ECIESError(\n `Invalid public key length: ${publicKey.length}`,\n \"INVALID_KEY\",\n );\n }\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Must be implemented by derived classes to handle platform-specific operations.\n *\n * @param publicKey - The public key to normalize\n * @returns The normalized uncompressed public key\n */\n public abstract normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using ECIES.\n *\n * @param publicKey - The recipient's public key (compressed or uncompressed)\n * @param message - The data to encrypt\n * @returns Promise resolving to encrypted data structure\n */\n async encrypt(\n publicKey: Uint8Array,\n message: Uint8Array,\n ): Promise<ECIESEncrypted> {\n try {\n // Validate inputs\n if (!(publicKey instanceof Uint8Array)) {\n throw new ECIESError(\"Public key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!(message instanceof Uint8Array)) {\n throw new ECIESError(\n \"Message must be a Uint8Array\",\n \"ENCRYPTION_FAILED\",\n );\n }\n if (publicKey.length === 0) {\n throw new ECIESError(\"Public key cannot be empty\", \"INVALID_KEY\");\n }\n\n // Normalize public key to uncompressed format\n const pubKey = this.normalizePublicKey(publicKey);\n\n // Generate ephemeral key pair\n let ephemeralPrivateKey: Uint8Array;\n do {\n ephemeralPrivateKey = this.generateRandomBytes(\n CURVE.PRIVATE_KEY_LENGTH,\n );\n } while (!this.verifyPrivateKey(ephemeralPrivateKey));\n\n const ephemeralPublicKey = this.createPublicKey(\n ephemeralPrivateKey,\n false,\n );\n if (!ephemeralPublicKey) {\n throw new ECIESError(\n \"Failed to generate ephemeral public key\",\n \"ENCRYPTION_FAILED\",\n );\n }\n\n // Perform ECDH to get shared secret (raw X coordinate)\n const sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Generate random IV and encrypt\n const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);\n const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);\n\n // Calculate MAC (Encrypt-then-MAC)\n const macData = concat([iv, ephemeralPublicKey, ciphertext]);\n const mac = this.hmacSha256(macKey, macData);\n\n // Clear sensitive data\n this.clearBuffer(ephemeralPrivateKey);\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return {\n iv,\n ephemPublicKey: ephemeralPublicKey,\n ciphertext,\n mac,\n };\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Encryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"ENCRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - The recipient's private key (32 bytes)\n * @param encrypted - The encrypted data structure from encrypt()\n * @returns Promise resolving to the original plaintext\n */\n async decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array> {\n try {\n // Validate inputs\n if (!(privateKey instanceof Uint8Array)) {\n throw new ECIESError(\"Private key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!isECIESEncrypted(encrypted)) {\n throw new ECIESError(\n \"Invalid encrypted data structure\",\n \"DECRYPTION_FAILED\",\n );\n }\n if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {\n throw new ECIESError(\n `Invalid private key length: ${privateKey.length}`,\n \"INVALID_KEY\",\n );\n }\n if (!this.verifyPrivateKey(privateKey)) {\n throw new ECIESError(\"Invalid private key\", \"INVALID_KEY\");\n }\n\n // Strict validation: ephemeral keys must be 65-byte uncompressed (eccrypto standard)\n if (\n encrypted.ephemPublicKey.length !== CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH\n ) {\n throw new ECIESError(\n `Invalid ephemeral public key: expected ${CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH} bytes (uncompressed), got ${encrypted.ephemPublicKey.length} bytes`,\n \"INVALID_KEY\",\n );\n }\n if (encrypted.ephemPublicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid ephemeral public key: must be uncompressed format with 0x04 prefix (eccrypto standard)\",\n \"INVALID_KEY\",\n );\n }\n if (!this.validatePublicKey(encrypted.ephemPublicKey)) {\n throw new ECIESError(\"Invalid ephemeral public key\", \"INVALID_KEY\");\n }\n const ephemeralPublicKey = encrypted.ephemPublicKey;\n\n // Perform ECDH to recover shared secret\n const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Verify MAC before decryption (Encrypt-then-MAC)\n const macData = concat([\n encrypted.iv,\n encrypted.ephemPublicKey,\n encrypted.ciphertext,\n ]);\n const expectedMac = this.hmacSha256(macKey, macData);\n\n if (!constantTimeEqual(encrypted.mac, expectedMac)) {\n throw new ECIESError(\"MAC verification failed\", \"MAC_MISMATCH\");\n }\n\n // Decrypt the ciphertext\n const decrypted = await this.aesDecrypt(\n encryptionKey,\n encrypted.iv,\n encrypted.ciphertext,\n );\n\n // Clear sensitive data\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return decrypted;\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Decryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"DECRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Clears sensitive data from memory using multi-pass overwrite.\n *\n * @remarks\n * Uses multiple passes with different patterns to make it harder\n * for JIT compilers to optimize away the operation. While not\n * guaranteed in JavaScript, this is a best-effort approach to\n * clear sensitive data from memory.\n *\n * @param buffer - The buffer to clear\n */\n protected clearBuffer(buffer: Uint8Array): void {\n if (buffer && buffer.length > 0) {\n // Multi-pass overwrite to resist compiler optimization\n buffer.fill(0x00); // Fill with zeros\n buffer.fill(0xff); // Fill with ones\n buffer.fill(0xaa); // Fill with alternating pattern\n buffer.fill(0x00); // Final zero fill\n\n // Additional pattern write to further discourage optimization\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = (i & 0xff) ^ 0x5a; // XOR with pattern\n }\n buffer.fill(0x00); // Final clear\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/base.ts"],"sourcesContent":["import type { ECIESProvider, ECIESEncrypted } from \"./interface\";\nimport { ECIESError, isECIESEncrypted } from \"./interface\";\nimport { CURVE, CIPHER, KDF } from \"./constants\";\nimport { constantTimeEqual } from \"./utils\";\nimport { concat } from \"viem\";\n\n/**\n * Provides shared ECIES encryption logic across platforms using Uint8Array.\n *\n * @remarks\n * Platform implementations extend this class and provide crypto primitives.\n * The base class handles the ECIES protocol flow while maintaining\n * compatibility with the eccrypto data format.\n *\n * **Implementation details:**\n * - KDF: SHA-512(shared_secret) → encKey (32B) || macKey (32B)\n * - Cipher: AES-256-CBC with random 16-byte IV\n * - MAC: HMAC-SHA256(macKey, iv || ephemPublicKey || ciphertext)\n *\n * @category Cryptography\n */\nexport abstract class BaseECIESUint8 implements ECIESProvider {\n // Cache for validated public keys to avoid repeated validation\n private static readonly validatedKeys = new WeakMap<Uint8Array, boolean>();\n\n /**\n * Generates cryptographically secure random bytes.\n *\n * @param length - Number of random bytes to generate.\n * @returns Random bytes array.\n */\n protected abstract generateRandomBytes(length: number): Uint8Array;\n\n /**\n * Verifies a private key is valid for secp256k1.\n *\n * @param privateKey - Private key to verify (32 bytes).\n * @returns `true` if valid private key.\n */\n protected abstract verifyPrivateKey(privateKey: Uint8Array): boolean;\n\n /**\n * Creates a public key from a private key.\n *\n * @param privateKey - Source private key (32 bytes).\n * @param compressed - Generate compressed (33B) or uncompressed (65B) format.\n * @returns Public key or `null` if creation failed.\n */\n protected abstract createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null;\n\n /**\n * Validates a public key on the secp256k1 curve.\n *\n * @param publicKey - Public key to validate.\n * @returns `true` if valid public key.\n */\n protected abstract validatePublicKey(publicKey: Uint8Array): boolean;\n\n /**\n * Decompresses a compressed public key.\n *\n * @param publicKey - Compressed public key (33 bytes).\n * @returns Uncompressed public key (65 bytes) or `null` if decompression failed.\n */\n protected abstract decompressPublicKey(\n publicKey: Uint8Array,\n ): Uint8Array | null;\n\n /**\n * Performs ECDH key agreement.\n *\n * @param publicKey - Other party's public key.\n * @param privateKey - Your private key.\n * @returns Raw X coordinate of shared point (32 bytes).\n */\n protected abstract performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array;\n\n /**\n * Computes SHA-512 hash.\n *\n * @param data - Data to hash.\n * @returns SHA-512 hash (64 bytes).\n */\n protected abstract sha512(data: Uint8Array): Uint8Array;\n\n /**\n * Computes HMAC-SHA256 authentication tag.\n *\n * @param key - HMAC key.\n * @param data - Data to authenticate.\n * @returns HMAC-SHA256 (32 bytes).\n */\n protected abstract hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using AES-256-CBC.\n *\n * @param key - Encryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param plaintext - Data to encrypt.\n * @returns Ciphertext with PKCS#7 padding.\n */\n protected abstract aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Decrypts data using AES-256-CBC.\n *\n * @param key - Decryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param ciphertext - Data to decrypt.\n * @returns Plaintext with padding removed.\n */\n protected abstract aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format.\n *\n * @param publicKey - Public key in any format.\n * @returns Uncompressed public key (65 bytes).\n * @throws {ECIESError} If key format is invalid.\n */\n protected normalizePublicKey(publicKey: Uint8Array): Uint8Array {\n // Check cache first\n if (BaseECIESUint8.validatedKeys.get(publicKey)) {\n return publicKey;\n }\n\n if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {\n if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid uncompressed public key prefix\",\n \"INVALID_KEY\",\n );\n }\n // Validate and cache\n if (!this.validatePublicKey(publicKey)) {\n throw new ECIESError(\"Invalid public key\", \"INVALID_KEY\");\n }\n BaseECIESUint8.validatedKeys.set(publicKey, true);\n return publicKey;\n }\n\n if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {\n if (\n publicKey[0] === CURVE.PREFIX.COMPRESSED_EVEN ||\n publicKey[0] === CURVE.PREFIX.COMPRESSED_ODD\n ) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new ECIESError(\n \"Failed to decompress public key\",\n \"INVALID_KEY\",\n );\n }\n // Cache the decompressed key\n BaseECIESUint8.validatedKeys.set(decompressed, true);\n return decompressed;\n }\n throw new ECIESError(\n `Invalid compressed public key prefix: expected 0x02 or 0x03, got 0x${publicKey[0].toString(16).padStart(2, \"0\")}`,\n \"INVALID_KEY\",\n );\n }\n\n throw new ECIESError(\n `Invalid public key length: ${publicKey.length}`,\n \"INVALID_KEY\",\n );\n }\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Must be implemented by derived classes to handle platform-specific operations.\n *\n * @param publicKey - The public key to normalize\n * @returns The normalized uncompressed public key\n */\n public abstract normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using ECIES.\n *\n * @param publicKey - The recipient's public key (compressed or uncompressed)\n * @param message - The data to encrypt\n * @returns Promise resolving to encrypted data structure\n */\n async encrypt(\n publicKey: Uint8Array,\n message: Uint8Array,\n ): Promise<ECIESEncrypted> {\n // Declare sensitive variables outside try so finally can access them\n let ephemeralPrivateKey: Uint8Array | undefined;\n let sharedSecret: Uint8Array | undefined;\n let kdf: Uint8Array | undefined;\n let encryptionKey: Uint8Array | undefined;\n let macKey: Uint8Array | undefined;\n\n try {\n // Validate inputs\n if (!(publicKey instanceof Uint8Array)) {\n throw new ECIESError(\"Public key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!(message instanceof Uint8Array)) {\n throw new ECIESError(\n \"Message must be a Uint8Array\",\n \"ENCRYPTION_FAILED\",\n );\n }\n if (publicKey.length === 0) {\n throw new ECIESError(\"Public key cannot be empty\", \"INVALID_KEY\");\n }\n\n // Normalize public key to uncompressed format\n const pubKey = this.normalizePublicKey(publicKey);\n\n // Generate ephemeral key pair\n do {\n ephemeralPrivateKey = this.generateRandomBytes(\n CURVE.PRIVATE_KEY_LENGTH,\n );\n } while (!this.verifyPrivateKey(ephemeralPrivateKey));\n\n const ephemeralPublicKey = this.createPublicKey(\n ephemeralPrivateKey,\n false,\n );\n if (!ephemeralPublicKey) {\n throw new ECIESError(\n \"Failed to generate ephemeral public key\",\n \"ENCRYPTION_FAILED\",\n );\n }\n\n // Perform ECDH to get shared secret (raw X coordinate)\n sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n kdf = this.sha512(sharedSecret);\n encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Generate random IV and encrypt\n const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);\n const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);\n\n // Calculate MAC (Encrypt-then-MAC)\n const macData = concat([iv, ephemeralPublicKey, ciphertext]);\n const mac = this.hmacSha256(macKey, macData);\n\n return {\n iv,\n ephemPublicKey: ephemeralPublicKey,\n ciphertext,\n mac,\n };\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Encryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"ENCRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n } finally {\n // Clear sensitive data on all code paths (success, error, throw)\n if (ephemeralPrivateKey) this.clearBuffer(ephemeralPrivateKey);\n if (sharedSecret) this.clearBuffer(sharedSecret);\n if (kdf) this.clearBuffer(kdf);\n if (encryptionKey) this.clearBuffer(encryptionKey);\n if (macKey) this.clearBuffer(macKey);\n }\n }\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - The recipient's private key (32 bytes)\n * @param encrypted - The encrypted data structure from encrypt()\n * @returns Promise resolving to the original plaintext\n */\n async decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array> {\n // Declare sensitive variables outside try so finally can access them\n let sharedSecret: Uint8Array | undefined;\n let kdf: Uint8Array | undefined;\n let encryptionKey: Uint8Array | undefined;\n let macKey: Uint8Array | undefined;\n\n try {\n // Validate inputs\n if (!(privateKey instanceof Uint8Array)) {\n throw new ECIESError(\"Private key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!isECIESEncrypted(encrypted)) {\n throw new ECIESError(\n \"Invalid encrypted data structure\",\n \"DECRYPTION_FAILED\",\n );\n }\n if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {\n throw new ECIESError(\n `Invalid private key length: ${privateKey.length}`,\n \"INVALID_KEY\",\n );\n }\n if (!this.verifyPrivateKey(privateKey)) {\n throw new ECIESError(\"Invalid private key\", \"INVALID_KEY\");\n }\n\n // Strict validation: ephemeral keys must be 65-byte uncompressed (eccrypto standard)\n if (\n encrypted.ephemPublicKey.length !== CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH\n ) {\n throw new ECIESError(\n `Invalid ephemeral public key: expected ${CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH} bytes (uncompressed), got ${encrypted.ephemPublicKey.length} bytes`,\n \"INVALID_KEY\",\n );\n }\n if (encrypted.ephemPublicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid ephemeral public key: must be uncompressed format with 0x04 prefix (eccrypto standard)\",\n \"INVALID_KEY\",\n );\n }\n if (!this.validatePublicKey(encrypted.ephemPublicKey)) {\n throw new ECIESError(\"Invalid ephemeral public key\", \"INVALID_KEY\");\n }\n const ephemeralPublicKey = encrypted.ephemPublicKey;\n\n // Perform ECDH to recover shared secret\n sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n kdf = this.sha512(sharedSecret);\n encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Verify MAC before decryption (Encrypt-then-MAC)\n const macData = concat([\n encrypted.iv,\n encrypted.ephemPublicKey,\n encrypted.ciphertext,\n ]);\n const expectedMac = this.hmacSha256(macKey, macData);\n\n if (!constantTimeEqual(encrypted.mac, expectedMac)) {\n throw new ECIESError(\"MAC verification failed\", \"MAC_MISMATCH\");\n }\n\n // Decrypt the ciphertext\n const decrypted = await this.aesDecrypt(\n encryptionKey,\n encrypted.iv,\n encrypted.ciphertext,\n );\n\n return decrypted;\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Decryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"DECRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n } finally {\n // Clear sensitive data on all code paths (success, error, throw)\n if (sharedSecret) this.clearBuffer(sharedSecret);\n if (kdf) this.clearBuffer(kdf);\n if (encryptionKey) this.clearBuffer(encryptionKey);\n if (macKey) this.clearBuffer(macKey);\n }\n }\n\n /**\n * Clears sensitive data from memory using multi-pass overwrite.\n *\n * @remarks\n * Uses multiple passes with different patterns to make it harder\n * for JIT compilers to optimize away the operation. While not\n * guaranteed in JavaScript, this is a best-effort approach to\n * clear sensitive data from memory.\n *\n * @param buffer - The buffer to clear\n */\n protected clearBuffer(buffer: Uint8Array): void {\n if (buffer && buffer.length > 0) {\n // Multi-pass overwrite to resist compiler optimization\n buffer.fill(0x00); // Fill with zeros\n buffer.fill(0xff); // Fill with ones\n buffer.fill(0xaa); // Fill with alternating pattern\n buffer.fill(0x00); // Final zero fill\n\n // Additional pattern write to further discourage optimization\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = (i & 0xff) ^ 0x5a; // XOR with pattern\n }\n buffer.fill(0x00); // Final clear\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -23,8 +23,7 @@ __export(constants_exports, {
|
|
|
23
23
|
FORMAT: () => FORMAT,
|
|
24
24
|
KDF: () => KDF,
|
|
25
25
|
MAC: () => MAC,
|
|
26
|
-
SECURITY: () => SECURITY
|
|
27
|
-
VALIDATION: () => VALIDATION
|
|
26
|
+
SECURITY: () => SECURITY
|
|
28
27
|
});
|
|
29
28
|
module.exports = __toCommonJS(constants_exports);
|
|
30
29
|
const CURVE = {
|
|
@@ -112,12 +111,6 @@ const SECURITY = {
|
|
|
112
111
|
PATTERN_OFFSET: 13
|
|
113
112
|
}
|
|
114
113
|
};
|
|
115
|
-
const VALIDATION = {
|
|
116
|
-
isValidPrivateKey: (key) => key.length === CURVE.PRIVATE_KEY_LENGTH,
|
|
117
|
-
isValidPublicKey: (key) => key.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH || key.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,
|
|
118
|
-
isCompressedPublicKey: (key) => key.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH && (key[0] === CURVE.PREFIX.COMPRESSED_EVEN || key[0] === CURVE.PREFIX.COMPRESSED_ODD),
|
|
119
|
-
isUncompressedPublicKey: (key) => key.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH && key[0] === CURVE.PREFIX.UNCOMPRESSED
|
|
120
|
-
};
|
|
121
114
|
// Annotate the CommonJS export names for ESM import in node:
|
|
122
115
|
0 && (module.exports = {
|
|
123
116
|
CIPHER,
|
|
@@ -125,7 +118,6 @@ const VALIDATION = {
|
|
|
125
118
|
FORMAT,
|
|
126
119
|
KDF,
|
|
127
120
|
MAC,
|
|
128
|
-
SECURITY
|
|
129
|
-
VALIDATION
|
|
121
|
+
SECURITY
|
|
130
122
|
});
|
|
131
123
|
//# sourceMappingURL=constants.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/constants.ts"],"sourcesContent":["/**\n * ECIES Constants and Format Specification\n *\n * These constants define the eccrypto-compatible ECIES format used throughout the SDK.\n * Maintaining these exact values ensures backward compatibility with data encrypted\n * using the original eccrypto library.\n */\n\n/**\n * Elliptic curve parameters\n */\nexport const CURVE = {\n /** The elliptic curve used (secp256k1 - same as Bitcoin/Ethereum) */\n name: \"secp256k1\",\n /** Private key length in bytes */\n PRIVATE_KEY_LENGTH: 32,\n /** Compressed public key length in bytes (0x02 or 0x03 prefix + 32 bytes) */\n COMPRESSED_PUBLIC_KEY_LENGTH: 33,\n /** Uncompressed public key length in bytes (0x04 prefix + 64 bytes) */\n UNCOMPRESSED_PUBLIC_KEY_LENGTH: 65,\n /** ECDH shared secret X coordinate length */\n SHARED_SECRET_LENGTH: 32,\n /** Public key prefixes */\n PREFIX: {\n /** Uncompressed public key prefix */\n UNCOMPRESSED: 0x04,\n /** Compressed public key prefix for even Y */\n COMPRESSED_EVEN: 0x02,\n /** Compressed public key prefix for odd Y */\n COMPRESSED_ODD: 0x03,\n },\n /** X coordinate starts at byte 1 (after prefix) */\n X_COORDINATE_OFFSET: 1,\n /** X coordinate ends at byte 33 (1 + 32) */\n X_COORDINATE_END: 33,\n} as const;\n\n/**\n * Symmetric encryption parameters (AES-256-CBC)\n */\nexport const CIPHER = {\n /** Cipher algorithm - must match eccrypto */\n algorithm: \"aes-256-cbc\",\n /** AES key length in bytes */\n KEY_LENGTH: 32,\n /** Initialization vector length in bytes */\n IV_LENGTH: 16,\n /** Block size for AES */\n BLOCK_SIZE: 16,\n} as const;\n\n/**\n * Key derivation function parameters\n */\nexport const KDF = {\n /** Hash algorithm for key derivation - must match eccrypto */\n algorithm: \"sha512\",\n /** Output length of SHA-512 in bytes */\n OUTPUT_LENGTH: 64,\n /** Encryption key slice (first 32 bytes of KDF output) */\n ENCRYPTION_KEY_OFFSET: 0,\n ENCRYPTION_KEY_LENGTH: 32,\n /** MAC key slice (last 32 bytes of KDF output) */\n MAC_KEY_OFFSET: 32,\n MAC_KEY_LENGTH: 32,\n} as const;\n\n/**\n * Message authentication code parameters\n */\nexport const MAC = {\n /** MAC algorithm - must match eccrypto */\n algorithm: \"sha256\",\n /** HMAC-SHA256 output length in bytes */\n LENGTH: 32,\n} as const;\n\n/**\n * ECIES encrypted data format offsets and lengths\n * Format: [iv(16)][ephemPublicKey(65)][ciphertext(variable)][mac(32)]\n */\nexport const FORMAT = {\n /** Offsets for each component in serialized format */\n IV_OFFSET: 0,\n IV_LENGTH: CIPHER.IV_LENGTH,\n\n /** Ephemeral public key (always uncompressed in eccrypto format) */\n EPHEMERAL_KEY_OFFSET: CIPHER.IV_LENGTH,\n EPHEMERAL_KEY_LENGTH: CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** Ciphertext starts after IV and ephemeral key */\n CIPHERTEXT_OFFSET: CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** MAC is always the last 32 bytes */\n MAC_LENGTH: MAC.LENGTH,\n\n /** Minimum size of encrypted data (IV + ephemKey + MAC, no ciphertext) */\n MIN_ENCRYPTED_LENGTH:\n CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH + MAC.LENGTH,\n\n /**\n * Helper to calculate total length of encrypted data\n *\n * @param ciphertextLength - Length of the ciphertext portion\n * @returns Total length including all components\n */\n getTotalLength: (ciphertextLength: number) =>\n CIPHER.IV_LENGTH +\n CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH +\n ciphertextLength +\n MAC.LENGTH,\n} as const;\n\n/**\n * Security constants for data clearing\n */\nexport const SECURITY = {\n /** Overwrite patterns for secure data clearing */\n CLEAR_PATTERNS: {\n ZEROS: 0x00,\n ONES: 0xff,\n /** Pattern multiplier for third pass */\n PATTERN_MULTIPLIER: 7,\n /** Pattern offset for third pass */\n PATTERN_OFFSET: 13,\n },\n} as const;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/constants.ts"],"sourcesContent":["/**\n * ECIES Constants and Format Specification\n *\n * These constants define the eccrypto-compatible ECIES format used throughout the SDK.\n * Maintaining these exact values ensures backward compatibility with data encrypted\n * using the original eccrypto library.\n */\n\n/**\n * Elliptic curve parameters\n */\nexport const CURVE = {\n /** The elliptic curve used (secp256k1 - same as Bitcoin/Ethereum) */\n name: \"secp256k1\",\n /** Private key length in bytes */\n PRIVATE_KEY_LENGTH: 32,\n /** Compressed public key length in bytes (0x02 or 0x03 prefix + 32 bytes) */\n COMPRESSED_PUBLIC_KEY_LENGTH: 33,\n /** Uncompressed public key length in bytes (0x04 prefix + 64 bytes) */\n UNCOMPRESSED_PUBLIC_KEY_LENGTH: 65,\n /** ECDH shared secret X coordinate length */\n SHARED_SECRET_LENGTH: 32,\n /** Public key prefixes */\n PREFIX: {\n /** Uncompressed public key prefix */\n UNCOMPRESSED: 0x04,\n /** Compressed public key prefix for even Y */\n COMPRESSED_EVEN: 0x02,\n /** Compressed public key prefix for odd Y */\n COMPRESSED_ODD: 0x03,\n },\n /** X coordinate starts at byte 1 (after prefix) */\n X_COORDINATE_OFFSET: 1,\n /** X coordinate ends at byte 33 (1 + 32) */\n X_COORDINATE_END: 33,\n} as const;\n\n/**\n * Symmetric encryption parameters (AES-256-CBC)\n */\nexport const CIPHER = {\n /** Cipher algorithm - must match eccrypto */\n algorithm: \"aes-256-cbc\",\n /** AES key length in bytes */\n KEY_LENGTH: 32,\n /** Initialization vector length in bytes */\n IV_LENGTH: 16,\n /** Block size for AES */\n BLOCK_SIZE: 16,\n} as const;\n\n/**\n * Key derivation function parameters\n */\nexport const KDF = {\n /** Hash algorithm for key derivation - must match eccrypto */\n algorithm: \"sha512\",\n /** Output length of SHA-512 in bytes */\n OUTPUT_LENGTH: 64,\n /** Encryption key slice (first 32 bytes of KDF output) */\n ENCRYPTION_KEY_OFFSET: 0,\n ENCRYPTION_KEY_LENGTH: 32,\n /** MAC key slice (last 32 bytes of KDF output) */\n MAC_KEY_OFFSET: 32,\n MAC_KEY_LENGTH: 32,\n} as const;\n\n/**\n * Message authentication code parameters\n */\nexport const MAC = {\n /** MAC algorithm - must match eccrypto */\n algorithm: \"sha256\",\n /** HMAC-SHA256 output length in bytes */\n LENGTH: 32,\n} as const;\n\n/**\n * ECIES encrypted data format offsets and lengths\n * Format: [iv(16)][ephemPublicKey(65)][ciphertext(variable)][mac(32)]\n */\nexport const FORMAT = {\n /** Offsets for each component in serialized format */\n IV_OFFSET: 0,\n IV_LENGTH: CIPHER.IV_LENGTH,\n\n /** Ephemeral public key (always uncompressed in eccrypto format) */\n EPHEMERAL_KEY_OFFSET: CIPHER.IV_LENGTH,\n EPHEMERAL_KEY_LENGTH: CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** Ciphertext starts after IV and ephemeral key */\n CIPHERTEXT_OFFSET: CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** MAC is always the last 32 bytes */\n MAC_LENGTH: MAC.LENGTH,\n\n /** Minimum size of encrypted data (IV + ephemKey + MAC, no ciphertext) */\n MIN_ENCRYPTED_LENGTH:\n CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH + MAC.LENGTH,\n\n /**\n * Helper to calculate total length of encrypted data\n *\n * @param ciphertextLength - Length of the ciphertext portion\n * @returns Total length including all components\n */\n getTotalLength: (ciphertextLength: number) =>\n CIPHER.IV_LENGTH +\n CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH +\n ciphertextLength +\n MAC.LENGTH,\n} as const;\n\n/**\n * Security constants for data clearing\n */\nexport const SECURITY = {\n /** Overwrite patterns for secure data clearing */\n CLEAR_PATTERNS: {\n ZEROS: 0x00,\n ONES: 0xff,\n /** Pattern multiplier for third pass */\n PATTERN_MULTIPLIER: 7,\n /** Pattern offset for third pass */\n PATTERN_OFFSET: 13,\n },\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,MAAM,QAAQ;AAAA;AAAA,EAEnB,MAAM;AAAA;AAAA,EAEN,oBAAoB;AAAA;AAAA,EAEpB,8BAA8B;AAAA;AAAA,EAE9B,gCAAgC;AAAA;AAAA,EAEhC,sBAAsB;AAAA;AAAA,EAEtB,QAAQ;AAAA;AAAA,IAEN,cAAc;AAAA;AAAA,IAEd,iBAAiB;AAAA;AAAA,IAEjB,gBAAgB;AAAA,EAClB;AAAA;AAAA,EAEA,qBAAqB;AAAA;AAAA,EAErB,kBAAkB;AACpB;AAKO,MAAM,SAAS;AAAA;AAAA,EAEpB,WAAW;AAAA;AAAA,EAEX,YAAY;AAAA;AAAA,EAEZ,WAAW;AAAA;AAAA,EAEX,YAAY;AACd;AAKO,MAAM,MAAM;AAAA;AAAA,EAEjB,WAAW;AAAA;AAAA,EAEX,eAAe;AAAA;AAAA,EAEf,uBAAuB;AAAA,EACvB,uBAAuB;AAAA;AAAA,EAEvB,gBAAgB;AAAA,EAChB,gBAAgB;AAClB;AAKO,MAAM,MAAM;AAAA;AAAA,EAEjB,WAAW;AAAA;AAAA,EAEX,QAAQ;AACV;AAMO,MAAM,SAAS;AAAA;AAAA,EAEpB,WAAW;AAAA,EACX,WAAW,OAAO;AAAA;AAAA,EAGlB,sBAAsB,OAAO;AAAA,EAC7B,sBAAsB,MAAM;AAAA;AAAA,EAG5B,mBAAmB,OAAO,YAAY,MAAM;AAAA;AAAA,EAG5C,YAAY,IAAI;AAAA;AAAA,EAGhB,sBACE,OAAO,YAAY,MAAM,iCAAiC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhE,gBAAgB,CAAC,qBACf,OAAO,YACP,MAAM,iCACN,mBACA,IAAI;AACR;AAKO,MAAM,WAAW;AAAA;AAAA,EAEtB,gBAAgB;AAAA,IACd,OAAO;AAAA,IACP,MAAM;AAAA;AAAA,IAEN,oBAAoB;AAAA;AAAA,IAEpB,gBAAgB;AAAA,EAClB;AACF;","names":[]}
|
|
@@ -109,12 +109,3 @@ export declare const SECURITY: {
|
|
|
109
109
|
readonly PATTERN_OFFSET: 13;
|
|
110
110
|
};
|
|
111
111
|
};
|
|
112
|
-
/**
|
|
113
|
-
* Validation helpers
|
|
114
|
-
*/
|
|
115
|
-
export declare const VALIDATION: {
|
|
116
|
-
readonly isValidPrivateKey: (key: Uint8Array) => boolean;
|
|
117
|
-
readonly isValidPublicKey: (key: Uint8Array) => boolean;
|
|
118
|
-
readonly isCompressedPublicKey: (key: Uint8Array) => boolean;
|
|
119
|
-
readonly isUncompressedPublicKey: (key: Uint8Array) => boolean;
|
|
120
|
-
};
|
|
@@ -83,19 +83,12 @@ const SECURITY = {
|
|
|
83
83
|
PATTERN_OFFSET: 13
|
|
84
84
|
}
|
|
85
85
|
};
|
|
86
|
-
const VALIDATION = {
|
|
87
|
-
isValidPrivateKey: (key) => key.length === CURVE.PRIVATE_KEY_LENGTH,
|
|
88
|
-
isValidPublicKey: (key) => key.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH || key.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,
|
|
89
|
-
isCompressedPublicKey: (key) => key.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH && (key[0] === CURVE.PREFIX.COMPRESSED_EVEN || key[0] === CURVE.PREFIX.COMPRESSED_ODD),
|
|
90
|
-
isUncompressedPublicKey: (key) => key.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH && key[0] === CURVE.PREFIX.UNCOMPRESSED
|
|
91
|
-
};
|
|
92
86
|
export {
|
|
93
87
|
CIPHER,
|
|
94
88
|
CURVE,
|
|
95
89
|
FORMAT,
|
|
96
90
|
KDF,
|
|
97
91
|
MAC,
|
|
98
|
-
SECURITY
|
|
99
|
-
VALIDATION
|
|
92
|
+
SECURITY
|
|
100
93
|
};
|
|
101
94
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/constants.ts"],"sourcesContent":["/**\n * ECIES Constants and Format Specification\n *\n * These constants define the eccrypto-compatible ECIES format used throughout the SDK.\n * Maintaining these exact values ensures backward compatibility with data encrypted\n * using the original eccrypto library.\n */\n\n/**\n * Elliptic curve parameters\n */\nexport const CURVE = {\n /** The elliptic curve used (secp256k1 - same as Bitcoin/Ethereum) */\n name: \"secp256k1\",\n /** Private key length in bytes */\n PRIVATE_KEY_LENGTH: 32,\n /** Compressed public key length in bytes (0x02 or 0x03 prefix + 32 bytes) */\n COMPRESSED_PUBLIC_KEY_LENGTH: 33,\n /** Uncompressed public key length in bytes (0x04 prefix + 64 bytes) */\n UNCOMPRESSED_PUBLIC_KEY_LENGTH: 65,\n /** ECDH shared secret X coordinate length */\n SHARED_SECRET_LENGTH: 32,\n /** Public key prefixes */\n PREFIX: {\n /** Uncompressed public key prefix */\n UNCOMPRESSED: 0x04,\n /** Compressed public key prefix for even Y */\n COMPRESSED_EVEN: 0x02,\n /** Compressed public key prefix for odd Y */\n COMPRESSED_ODD: 0x03,\n },\n /** X coordinate starts at byte 1 (after prefix) */\n X_COORDINATE_OFFSET: 1,\n /** X coordinate ends at byte 33 (1 + 32) */\n X_COORDINATE_END: 33,\n} as const;\n\n/**\n * Symmetric encryption parameters (AES-256-CBC)\n */\nexport const CIPHER = {\n /** Cipher algorithm - must match eccrypto */\n algorithm: \"aes-256-cbc\",\n /** AES key length in bytes */\n KEY_LENGTH: 32,\n /** Initialization vector length in bytes */\n IV_LENGTH: 16,\n /** Block size for AES */\n BLOCK_SIZE: 16,\n} as const;\n\n/**\n * Key derivation function parameters\n */\nexport const KDF = {\n /** Hash algorithm for key derivation - must match eccrypto */\n algorithm: \"sha512\",\n /** Output length of SHA-512 in bytes */\n OUTPUT_LENGTH: 64,\n /** Encryption key slice (first 32 bytes of KDF output) */\n ENCRYPTION_KEY_OFFSET: 0,\n ENCRYPTION_KEY_LENGTH: 32,\n /** MAC key slice (last 32 bytes of KDF output) */\n MAC_KEY_OFFSET: 32,\n MAC_KEY_LENGTH: 32,\n} as const;\n\n/**\n * Message authentication code parameters\n */\nexport const MAC = {\n /** MAC algorithm - must match eccrypto */\n algorithm: \"sha256\",\n /** HMAC-SHA256 output length in bytes */\n LENGTH: 32,\n} as const;\n\n/**\n * ECIES encrypted data format offsets and lengths\n * Format: [iv(16)][ephemPublicKey(65)][ciphertext(variable)][mac(32)]\n */\nexport const FORMAT = {\n /** Offsets for each component in serialized format */\n IV_OFFSET: 0,\n IV_LENGTH: CIPHER.IV_LENGTH,\n\n /** Ephemeral public key (always uncompressed in eccrypto format) */\n EPHEMERAL_KEY_OFFSET: CIPHER.IV_LENGTH,\n EPHEMERAL_KEY_LENGTH: CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** Ciphertext starts after IV and ephemeral key */\n CIPHERTEXT_OFFSET: CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** MAC is always the last 32 bytes */\n MAC_LENGTH: MAC.LENGTH,\n\n /** Minimum size of encrypted data (IV + ephemKey + MAC, no ciphertext) */\n MIN_ENCRYPTED_LENGTH:\n CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH + MAC.LENGTH,\n\n /**\n * Helper to calculate total length of encrypted data\n *\n * @param ciphertextLength - Length of the ciphertext portion\n * @returns Total length including all components\n */\n getTotalLength: (ciphertextLength: number) =>\n CIPHER.IV_LENGTH +\n CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH +\n ciphertextLength +\n MAC.LENGTH,\n} as const;\n\n/**\n * Security constants for data clearing\n */\nexport const SECURITY = {\n /** Overwrite patterns for secure data clearing */\n CLEAR_PATTERNS: {\n ZEROS: 0x00,\n ONES: 0xff,\n /** Pattern multiplier for third pass */\n PATTERN_MULTIPLIER: 7,\n /** Pattern offset for third pass */\n PATTERN_OFFSET: 13,\n },\n} as const;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/constants.ts"],"sourcesContent":["/**\n * ECIES Constants and Format Specification\n *\n * These constants define the eccrypto-compatible ECIES format used throughout the SDK.\n * Maintaining these exact values ensures backward compatibility with data encrypted\n * using the original eccrypto library.\n */\n\n/**\n * Elliptic curve parameters\n */\nexport const CURVE = {\n /** The elliptic curve used (secp256k1 - same as Bitcoin/Ethereum) */\n name: \"secp256k1\",\n /** Private key length in bytes */\n PRIVATE_KEY_LENGTH: 32,\n /** Compressed public key length in bytes (0x02 or 0x03 prefix + 32 bytes) */\n COMPRESSED_PUBLIC_KEY_LENGTH: 33,\n /** Uncompressed public key length in bytes (0x04 prefix + 64 bytes) */\n UNCOMPRESSED_PUBLIC_KEY_LENGTH: 65,\n /** ECDH shared secret X coordinate length */\n SHARED_SECRET_LENGTH: 32,\n /** Public key prefixes */\n PREFIX: {\n /** Uncompressed public key prefix */\n UNCOMPRESSED: 0x04,\n /** Compressed public key prefix for even Y */\n COMPRESSED_EVEN: 0x02,\n /** Compressed public key prefix for odd Y */\n COMPRESSED_ODD: 0x03,\n },\n /** X coordinate starts at byte 1 (after prefix) */\n X_COORDINATE_OFFSET: 1,\n /** X coordinate ends at byte 33 (1 + 32) */\n X_COORDINATE_END: 33,\n} as const;\n\n/**\n * Symmetric encryption parameters (AES-256-CBC)\n */\nexport const CIPHER = {\n /** Cipher algorithm - must match eccrypto */\n algorithm: \"aes-256-cbc\",\n /** AES key length in bytes */\n KEY_LENGTH: 32,\n /** Initialization vector length in bytes */\n IV_LENGTH: 16,\n /** Block size for AES */\n BLOCK_SIZE: 16,\n} as const;\n\n/**\n * Key derivation function parameters\n */\nexport const KDF = {\n /** Hash algorithm for key derivation - must match eccrypto */\n algorithm: \"sha512\",\n /** Output length of SHA-512 in bytes */\n OUTPUT_LENGTH: 64,\n /** Encryption key slice (first 32 bytes of KDF output) */\n ENCRYPTION_KEY_OFFSET: 0,\n ENCRYPTION_KEY_LENGTH: 32,\n /** MAC key slice (last 32 bytes of KDF output) */\n MAC_KEY_OFFSET: 32,\n MAC_KEY_LENGTH: 32,\n} as const;\n\n/**\n * Message authentication code parameters\n */\nexport const MAC = {\n /** MAC algorithm - must match eccrypto */\n algorithm: \"sha256\",\n /** HMAC-SHA256 output length in bytes */\n LENGTH: 32,\n} as const;\n\n/**\n * ECIES encrypted data format offsets and lengths\n * Format: [iv(16)][ephemPublicKey(65)][ciphertext(variable)][mac(32)]\n */\nexport const FORMAT = {\n /** Offsets for each component in serialized format */\n IV_OFFSET: 0,\n IV_LENGTH: CIPHER.IV_LENGTH,\n\n /** Ephemeral public key (always uncompressed in eccrypto format) */\n EPHEMERAL_KEY_OFFSET: CIPHER.IV_LENGTH,\n EPHEMERAL_KEY_LENGTH: CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** Ciphertext starts after IV and ephemeral key */\n CIPHERTEXT_OFFSET: CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH,\n\n /** MAC is always the last 32 bytes */\n MAC_LENGTH: MAC.LENGTH,\n\n /** Minimum size of encrypted data (IV + ephemKey + MAC, no ciphertext) */\n MIN_ENCRYPTED_LENGTH:\n CIPHER.IV_LENGTH + CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH + MAC.LENGTH,\n\n /**\n * Helper to calculate total length of encrypted data\n *\n * @param ciphertextLength - Length of the ciphertext portion\n * @returns Total length including all components\n */\n getTotalLength: (ciphertextLength: number) =>\n CIPHER.IV_LENGTH +\n CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH +\n ciphertextLength +\n MAC.LENGTH,\n} as const;\n\n/**\n * Security constants for data clearing\n */\nexport const SECURITY = {\n /** Overwrite patterns for secure data clearing */\n CLEAR_PATTERNS: {\n ZEROS: 0x00,\n ONES: 0xff,\n /** Pattern multiplier for third pass */\n PATTERN_MULTIPLIER: 7,\n /** Pattern offset for third pass */\n PATTERN_OFFSET: 13,\n },\n} as const;\n"],"mappings":"AAWO,MAAM,QAAQ;AAAA;AAAA,EAEnB,MAAM;AAAA;AAAA,EAEN,oBAAoB;AAAA;AAAA,EAEpB,8BAA8B;AAAA;AAAA,EAE9B,gCAAgC;AAAA;AAAA,EAEhC,sBAAsB;AAAA;AAAA,EAEtB,QAAQ;AAAA;AAAA,IAEN,cAAc;AAAA;AAAA,IAEd,iBAAiB;AAAA;AAAA,IAEjB,gBAAgB;AAAA,EAClB;AAAA;AAAA,EAEA,qBAAqB;AAAA;AAAA,EAErB,kBAAkB;AACpB;AAKO,MAAM,SAAS;AAAA;AAAA,EAEpB,WAAW;AAAA;AAAA,EAEX,YAAY;AAAA;AAAA,EAEZ,WAAW;AAAA;AAAA,EAEX,YAAY;AACd;AAKO,MAAM,MAAM;AAAA;AAAA,EAEjB,WAAW;AAAA;AAAA,EAEX,eAAe;AAAA;AAAA,EAEf,uBAAuB;AAAA,EACvB,uBAAuB;AAAA;AAAA,EAEvB,gBAAgB;AAAA,EAChB,gBAAgB;AAClB;AAKO,MAAM,MAAM;AAAA;AAAA,EAEjB,WAAW;AAAA;AAAA,EAEX,QAAQ;AACV;AAMO,MAAM,SAAS;AAAA;AAAA,EAEpB,WAAW;AAAA,EACX,WAAW,OAAO;AAAA;AAAA,EAGlB,sBAAsB,OAAO;AAAA,EAC7B,sBAAsB,MAAM;AAAA;AAAA,EAG5B,mBAAmB,OAAO,YAAY,MAAM;AAAA;AAAA,EAG5C,YAAY,IAAI;AAAA;AAAA,EAGhB,sBACE,OAAO,YAAY,MAAM,iCAAiC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhE,gBAAgB,CAAC,qBACf,OAAO,YACP,MAAM,iCACN,mBACA,IAAI;AACR;AAKO,MAAM,WAAW;AAAA;AAAA,EAEtB,gBAAgB;AAAA,IACd,OAAO;AAAA,IACP,MAAM;AAAA;AAAA,IAEN,oBAAoB;AAAA;AAAA,IAEpB,gBAAgB;AAAA,EAClB;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/index.ts"],"sourcesContent":["/**\n * ECIES Module Entry Point\n *\n * Exports interface and utilities for ECIES encryption/decryption
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/index.ts"],"sourcesContent":["/**\n * ECIES Module Entry Point\n *\n * Exports interface and utilities for ECIES encryption/decryption.\n * Platform-specific implementations (BrowserECIESProvider, NodeECIESProvider)\n * are exported from the platform entry points.\n *\n * @remarks\n * Import from platform-specific entry points:\n * - Browser: `import { BrowserECIESProvider, serializeECIES } from '@opendatalabs/vana-sdk/browser'`\n * - Node: `import { NodeECIESProvider, serializeECIES } from '@opendatalabs/vana-sdk/node'`\n *\n * @category Cryptography\n */\n\nexport type { ECIESProvider, ECIESEncrypted, ECIESOptions } from \"./interface\";\n\nexport {\n ECIESError,\n isECIESEncrypted,\n serializeECIES,\n deserializeECIES,\n} from \"./interface\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,uBAKO;","names":[]}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ECIES Module Entry Point
|
|
3
3
|
*
|
|
4
|
-
* Exports interface and utilities for ECIES encryption/decryption
|
|
5
|
-
* Platform-specific implementations
|
|
4
|
+
* Exports interface and utilities for ECIES encryption/decryption.
|
|
5
|
+
* Platform-specific implementations (BrowserECIESProvider, NodeECIESProvider)
|
|
6
|
+
* are exported from the platform entry points.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* Import from platform-specific entry points:
|
|
10
|
+
* - Browser: `import { BrowserECIESProvider, serializeECIES } from '@opendatalabs/vana-sdk/browser'`
|
|
11
|
+
* - Node: `import { NodeECIESProvider, serializeECIES } from '@opendatalabs/vana-sdk/node'`
|
|
12
|
+
*
|
|
13
|
+
* @category Cryptography
|
|
6
14
|
*/
|
|
7
15
|
export type { ECIESProvider, ECIESEncrypted, ECIESOptions } from "./interface";
|
|
8
16
|
export { ECIESError, isECIESEncrypted, serializeECIES, deserializeECIES, } from "./interface";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/index.ts"],"sourcesContent":["/**\n * ECIES Module Entry Point\n *\n * Exports interface and utilities for ECIES encryption/decryption
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/index.ts"],"sourcesContent":["/**\n * ECIES Module Entry Point\n *\n * Exports interface and utilities for ECIES encryption/decryption.\n * Platform-specific implementations (BrowserECIESProvider, NodeECIESProvider)\n * are exported from the platform entry points.\n *\n * @remarks\n * Import from platform-specific entry points:\n * - Browser: `import { BrowserECIESProvider, serializeECIES } from '@opendatalabs/vana-sdk/browser'`\n * - Node: `import { NodeECIESProvider, serializeECIES } from '@opendatalabs/vana-sdk/node'`\n *\n * @category Cryptography\n */\n\nexport type { ECIESProvider, ECIESEncrypted, ECIESOptions } from \"./interface\";\n\nexport {\n ECIESError,\n isECIESEncrypted,\n serializeECIES,\n deserializeECIES,\n} from \"./interface\";\n"],"mappings":"AAiBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
|
|
@@ -59,10 +59,27 @@ function serializeECIES(encrypted) {
|
|
|
59
59
|
function deserializeECIES(hex) {
|
|
60
60
|
const hexWithPrefix = hex.startsWith("0x") ? hex : `0x${hex}`;
|
|
61
61
|
const bytes = (0, import_viem.fromHex)(hexWithPrefix, "bytes");
|
|
62
|
-
const
|
|
62
|
+
const absoluteMinLength = import_constants.FORMAT.IV_LENGTH + 1 + import_constants.MAC.LENGTH + 1;
|
|
63
|
+
if (bytes.length < absoluteMinLength) {
|
|
64
|
+
throw new ECIESError(
|
|
65
|
+
`Invalid ECIES data: too short (${bytes.length} bytes, minimum ${absoluteMinLength} bytes required)`,
|
|
66
|
+
"DECRYPTION_FAILED"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const prefix = bytes[import_constants.FORMAT.EPHEMERAL_KEY_OFFSET];
|
|
70
|
+
if (prefix !== import_constants.CURVE.PREFIX.UNCOMPRESSED) {
|
|
71
|
+
throw new ECIESError(
|
|
72
|
+
`Invalid ephemeral public key: must be uncompressed format (0x04 prefix), got 0x${prefix.toString(16).padStart(2, "0")}`,
|
|
73
|
+
"DECRYPTION_FAILED"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
const ephemKeySize = import_constants.CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH;
|
|
63
77
|
const minLength = import_constants.FORMAT.IV_LENGTH + ephemKeySize + import_constants.MAC.LENGTH + 1;
|
|
64
78
|
if (bytes.length < minLength) {
|
|
65
|
-
throw new ECIESError(
|
|
79
|
+
throw new ECIESError(
|
|
80
|
+
`Invalid ECIES data: too short (${bytes.length} bytes, minimum ${minLength} bytes required)`,
|
|
81
|
+
"DECRYPTION_FAILED"
|
|
82
|
+
);
|
|
66
83
|
}
|
|
67
84
|
return {
|
|
68
85
|
iv: bytes.subarray(import_constants.FORMAT.IV_OFFSET, import_constants.FORMAT.IV_OFFSET + import_constants.FORMAT.IV_LENGTH),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/interface.ts"],"sourcesContent":["/**\n * ECIES (Elliptic Curve Integrated Encryption Scheme) Interface\n *\n * @remarks\n * Defines the contract for platform-specific ECIES implementations.\n * All implementations maintain compatibility with the eccrypto format to ensure\n * backward compatibility with existing encrypted data.\n *\n * **Format specification:**\n * `[iv (16 bytes)][ephemPublicKey (65 bytes)][ciphertext (variable)][mac (32 bytes)]`\n *\n * @category Cryptography\n */\n\nimport { CIPHER, CURVE, MAC, FORMAT } from \"./constants\";\nimport { fromHex, toHex } from \"viem\";\n\n/**\n * Represents ECIES encrypted data in eccrypto-compatible format.\n *\n * @remarks\n * This structure maintains backward compatibility with data encrypted using\n * the legacy eccrypto library.\n */\nexport interface ECIESEncrypted {\n /** Initialization vector (16 bytes) */\n iv: Uint8Array;\n /** Ephemeral public key (65 bytes uncompressed) */\n ephemPublicKey: Uint8Array;\n /** Encrypted data */\n ciphertext: Uint8Array;\n /** Message authentication code (32 bytes) */\n mac: Uint8Array;\n}\n\n/**\n * Provides ECIES encryption and decryption operations.\n *\n * @remarks\n * Platform-specific implementations handle the underlying cryptographic primitives\n * while maintaining consistent data format across environments.\n *\n * @category Cryptography\n */\nexport interface ECIESProvider {\n /**\n * Encrypts data using ECIES with secp256k1.\n *\n * @param publicKey - Recipient's public key (65 bytes uncompressed or 33 bytes compressed).\n * Obtain via `vana.server.getIdentity(userAddress).public_key`.\n * @param message - Data to encrypt.\n * @returns Encrypted data structure compatible with eccrypto format.\n * @throws {ECIESError} When public key is invalid.\n * Verify key format matches secp256k1 requirements.\n *\n * @example\n * ```typescript\n * const encrypted = await provider.encrypt(\n * fromHex(publicKey, 'bytes'),\n * new TextEncoder().encode('sensitive data')\n * );\n * ```\n */\n encrypt(publicKey: Uint8Array, message: Uint8Array): Promise<ECIESEncrypted>;\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - Recipient's private key (32 bytes).\n * @param encrypted - Encrypted data structure from `encrypt()` or legacy eccrypto.\n * @returns Decrypted message as Uint8Array.\n * @throws {ECIESError} When MAC verification fails.\n * Ensure the private key matches the public key used for encryption.\n *\n * @example\n * ```typescript\n * const decrypted = await provider.decrypt(\n * fromHex(privateKey, 'bytes'),\n * encrypted\n * );\n * const message = new TextDecoder().decode(decrypted);\n * ```\n */\n decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n *\n * @remarks\n * Strict policy: Only accepts properly formatted compressed (33 bytes) or\n * uncompressed (65 bytes) public keys. Does not accept 64-byte raw coordinates\n * to ensure data integrity and prevent masking of malformed inputs.\n *\n * @param publicKey - Public key in compressed or uncompressed format\n * @returns Normalized uncompressed public key (65 bytes with 0x04 prefix)\n * @throws {Error} When public key format is invalid, including raw coordinates (64 bytes)\n * @throws {Error} When decompression of compressed key fails\n *\n * @example\n * ```typescript\n * // Compressed key (33 bytes)\n * const compressed = new Uint8Array(33);\n * compressed[0] = 0x02;\n * const uncompressed = provider.normalizeToUncompressed(compressed);\n * console.log(uncompressed.length); // 65\n * console.log(uncompressed[0]); // 0x04\n *\n * // Already uncompressed (65 bytes)\n * const already = provider.normalizeToUncompressed(uncompressedKey);\n * console.log(already === uncompressedKey); // true (returns same reference)\n *\n * // Raw coordinates rejected (64 bytes)\n * const raw = new Uint8Array(64);\n * provider.normalizeToUncompressed(raw); // Throws error\n * ```\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n}\n\n/**\n * Configures ECIES operation behavior.\n */\nexport interface ECIESOptions {\n /** Use compressed public keys (33 bytes) instead of uncompressed (65 bytes) */\n useCompressed?: boolean;\n}\n\n/**\n * Represents failures in ECIES cryptographic operations.\n *\n * @remarks\n * Provides specific error codes to help identify and recover from\n * different failure scenarios.\n *\n * @category Errors\n */\nexport class ECIESError extends Error {\n constructor(\n message: string,\n public readonly code:\n | \"INVALID_KEY\"\n | \"ENCRYPTION_FAILED\"\n | \"DECRYPTION_FAILED\"\n | \"MAC_MISMATCH\"\n | \"ECDH_FAILED\",\n public override readonly cause?: Error,\n ) {\n super(message);\n this.name = \"ECIESError\";\n }\n}\n\n/**\n * Validates if an object conforms to the ECIESEncrypted structure.\n *\n * @param obj - Object to validate.\n * @returns `true` if object is a valid ECIESEncrypted structure.\n *\n * @example\n * ```typescript\n * if (isECIESEncrypted(data)) {\n * const decrypted = await provider.decrypt(privateKey, data);\n * }\n * ```\n */\nexport function isECIESEncrypted(obj: unknown): obj is ECIESEncrypted {\n if (!obj || typeof obj !== \"object\") return false;\n const enc = obj as Record<string, unknown>;\n\n const isUint8Array = (value: unknown): value is Uint8Array => {\n return (\n value instanceof Uint8Array ||\n (typeof Buffer !== \"undefined\" && Buffer.isBuffer(value))\n );\n };\n\n return (\n isUint8Array(enc.iv) &&\n enc.iv.length === CIPHER.IV_LENGTH &&\n isUint8Array(enc.ephemPublicKey) &&\n (enc.ephemPublicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH ||\n enc.ephemPublicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) &&\n isUint8Array(enc.ciphertext) &&\n enc.ciphertext.length > 0 &&\n isUint8Array(enc.mac) &&\n enc.mac.length === MAC.LENGTH\n );\n}\n\n/**\n * Serializes ECIESEncrypted to hex string for storage or transmission.\n *\n * @param encrypted - Encrypted data structure from `encrypt()`.\n * @returns Hex string representation.\n *\n * @example\n * ```typescript\n * const hexString = serializeECIES(encrypted);\n * // Store hexString in database or send over network\n * ```\n */\nexport function serializeECIES(encrypted: ECIESEncrypted): string {\n const combined = new Uint8Array(\n encrypted.iv.length +\n encrypted.ephemPublicKey.length +\n encrypted.ciphertext.length +\n encrypted.mac.length,\n );\n\n let offset = 0;\n combined.set(encrypted.iv, offset);\n offset += encrypted.iv.length;\n combined.set(encrypted.ephemPublicKey, offset);\n offset += encrypted.ephemPublicKey.length;\n combined.set(encrypted.ciphertext, offset);\n offset += encrypted.ciphertext.length;\n combined.set(encrypted.mac, offset);\n\n return toHex(combined).slice(2);\n}\n\n/**\n * Deserializes hex string to ECIESEncrypted structure.\n *\n * @param hex - Hex string from `serializeECIES()` or storage.\n * @returns ECIESEncrypted structure ready for decryption.\n * @throws {ECIESError} When hex string format is invalid.\n * Verify the hex string is complete and uncorrupted.\n *\n * @example\n * ```typescript\n * const encrypted = deserializeECIES(hexString);\n * const decrypted = await provider.decrypt(privateKey, encrypted);\n * ```\n */\nexport function deserializeECIES(hex: string): ECIESEncrypted {\n const hexWithPrefix = hex.startsWith(\"0x\") ? hex : `0x${hex}`;\n const bytes = fromHex(hexWithPrefix as `0x${string}`, \"bytes\");\n\n // Determine ephemPublicKey size based on prefix\n const ephemKeySize =\n bytes[FORMAT.EPHEMERAL_KEY_OFFSET] === CURVE.PREFIX.UNCOMPRESSED\n ? CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH\n : CURVE.COMPRESSED_PUBLIC_KEY_LENGTH;\n\n const minLength = FORMAT.IV_LENGTH + ephemKeySize + MAC.LENGTH + 1; // +1 for at least 1 byte of ciphertext\n if (bytes.length < minLength) {\n throw new ECIESError(\"Invalid ECIES data: too short\", \"DECRYPTION_FAILED\");\n }\n\n return {\n iv: bytes.subarray(FORMAT.IV_OFFSET, FORMAT.IV_OFFSET + FORMAT.IV_LENGTH),\n ephemPublicKey: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET,\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n ),\n ciphertext: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n bytes.length - MAC.LENGTH,\n ),\n mac: bytes.subarray(bytes.length - MAC.LENGTH),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA,uBAA2C;AAC3C,kBAA+B;AA4HxB,MAAM,mBAAmB,MAAM;AAAA,EACpC,YACE,SACgB,MAMS,OACzB;AACA,UAAM,OAAO;AARG;AAMS;AAGzB,SAAK,OAAO;AAAA,EACd;AACF;AAeO,SAAS,iBAAiB,KAAqC;AACpE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAAM;AAEZ,QAAM,eAAe,CAAC,UAAwC;AAC5D,WACE,iBAAiB,cAChB,OAAO,WAAW,eAAe,OAAO,SAAS,KAAK;AAAA,EAE3D;AAEA,SACE,aAAa,IAAI,EAAE,KACnB,IAAI,GAAG,WAAW,wBAAO,aACzB,aAAa,IAAI,cAAc,MAC9B,IAAI,eAAe,WAAW,uBAAM,kCACnC,IAAI,eAAe,WAAW,uBAAM,iCACtC,aAAa,IAAI,UAAU,KAC3B,IAAI,WAAW,SAAS,KACxB,aAAa,IAAI,GAAG,KACpB,IAAI,IAAI,WAAW,qBAAI;AAE3B;AAcO,SAAS,eAAe,WAAmC;AAChE,QAAM,WAAW,IAAI;AAAA,IACnB,UAAU,GAAG,SACX,UAAU,eAAe,SACzB,UAAU,WAAW,SACrB,UAAU,IAAI;AAAA,EAClB;AAEA,MAAI,SAAS;AACb,WAAS,IAAI,UAAU,IAAI,MAAM;AACjC,YAAU,UAAU,GAAG;AACvB,WAAS,IAAI,UAAU,gBAAgB,MAAM;AAC7C,YAAU,UAAU,eAAe;AACnC,WAAS,IAAI,UAAU,YAAY,MAAM;AACzC,YAAU,UAAU,WAAW;AAC/B,WAAS,IAAI,UAAU,KAAK,MAAM;AAElC,aAAO,mBAAM,QAAQ,EAAE,MAAM,CAAC;AAChC;AAgBO,SAAS,iBAAiB,KAA6B;AAC5D,QAAM,gBAAgB,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AAC3D,QAAM,YAAQ,qBAAQ,eAAgC,OAAO;AAG7D,QAAM,eACJ,MAAM,wBAAO,oBAAoB,MAAM,uBAAM,OAAO,eAChD,uBAAM,iCACN,uBAAM;AAEZ,QAAM,YAAY,wBAAO,YAAY,eAAe,qBAAI,SAAS;AACjE,MAAI,MAAM,SAAS,WAAW;AAC5B,UAAM,IAAI,WAAW,iCAAiC,mBAAmB;AAAA,EAC3E;AAEA,SAAO;AAAA,IACL,IAAI,MAAM,SAAS,wBAAO,WAAW,wBAAO,YAAY,wBAAO,SAAS;AAAA,IACxE,gBAAgB,MAAM;AAAA,MACpB,wBAAO;AAAA,MACP,wBAAO,uBAAuB;AAAA,IAChC;AAAA,IACA,YAAY,MAAM;AAAA,MAChB,wBAAO,uBAAuB;AAAA,MAC9B,MAAM,SAAS,qBAAI;AAAA,IACrB;AAAA,IACA,KAAK,MAAM,SAAS,MAAM,SAAS,qBAAI,MAAM;AAAA,EAC/C;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/interface.ts"],"sourcesContent":["/**\n * ECIES (Elliptic Curve Integrated Encryption Scheme) Interface\n *\n * @remarks\n * Defines the contract for platform-specific ECIES implementations.\n * All implementations maintain compatibility with the eccrypto format to ensure\n * backward compatibility with existing encrypted data.\n *\n * **Format specification:**\n * `[iv (16 bytes)][ephemPublicKey (65 bytes)][ciphertext (variable)][mac (32 bytes)]`\n *\n * @category Cryptography\n */\n\nimport { CIPHER, CURVE, MAC, FORMAT } from \"./constants\";\nimport { fromHex, toHex } from \"viem\";\n\n/**\n * Represents ECIES encrypted data in eccrypto-compatible format.\n *\n * @remarks\n * This structure maintains backward compatibility with data encrypted using\n * the legacy eccrypto library.\n */\nexport interface ECIESEncrypted {\n /** Initialization vector (16 bytes) */\n iv: Uint8Array;\n /** Ephemeral public key (65 bytes uncompressed) */\n ephemPublicKey: Uint8Array;\n /** Encrypted data */\n ciphertext: Uint8Array;\n /** Message authentication code (32 bytes) */\n mac: Uint8Array;\n}\n\n/**\n * Provides ECIES encryption and decryption operations.\n *\n * @remarks\n * Platform-specific implementations handle the underlying cryptographic primitives\n * while maintaining consistent data format across environments.\n *\n * @category Cryptography\n */\nexport interface ECIESProvider {\n /**\n * Encrypts data using ECIES with secp256k1.\n *\n * @param publicKey - Recipient's public key (65 bytes uncompressed or 33 bytes compressed).\n * Obtain via `vana.server.getIdentity(userAddress).public_key`.\n * @param message - Data to encrypt.\n * @returns Encrypted data structure compatible with eccrypto format.\n * @throws {ECIESError} When public key is invalid.\n * Verify key format matches secp256k1 requirements.\n *\n * @example\n * ```typescript\n * const encrypted = await provider.encrypt(\n * fromHex(publicKey, 'bytes'),\n * new TextEncoder().encode('sensitive data')\n * );\n * ```\n */\n encrypt(publicKey: Uint8Array, message: Uint8Array): Promise<ECIESEncrypted>;\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - Recipient's private key (32 bytes).\n * @param encrypted - Encrypted data structure from `encrypt()` or legacy eccrypto.\n * @returns Decrypted message as Uint8Array.\n * @throws {ECIESError} When MAC verification fails.\n * Ensure the private key matches the public key used for encryption.\n *\n * @example\n * ```typescript\n * const decrypted = await provider.decrypt(\n * fromHex(privateKey, 'bytes'),\n * encrypted\n * );\n * const message = new TextDecoder().decode(decrypted);\n * ```\n */\n decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n *\n * @remarks\n * Strict policy: Only accepts properly formatted compressed (33 bytes) or\n * uncompressed (65 bytes) public keys. Does not accept 64-byte raw coordinates\n * to ensure data integrity and prevent masking of malformed inputs.\n *\n * @param publicKey - Public key in compressed or uncompressed format\n * @returns Normalized uncompressed public key (65 bytes with 0x04 prefix)\n * @throws {Error} When public key format is invalid, including raw coordinates (64 bytes)\n * @throws {Error} When decompression of compressed key fails\n *\n * @example\n * ```typescript\n * // Compressed key (33 bytes)\n * const compressed = new Uint8Array(33);\n * compressed[0] = 0x02;\n * const uncompressed = provider.normalizeToUncompressed(compressed);\n * console.log(uncompressed.length); // 65\n * console.log(uncompressed[0]); // 0x04\n *\n * // Already uncompressed (65 bytes)\n * const already = provider.normalizeToUncompressed(uncompressedKey);\n * console.log(already === uncompressedKey); // true (returns same reference)\n *\n * // Raw coordinates rejected (64 bytes)\n * const raw = new Uint8Array(64);\n * provider.normalizeToUncompressed(raw); // Throws error\n * ```\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n}\n\n/**\n * Configures ECIES operation behavior.\n */\nexport interface ECIESOptions {\n /** Use compressed public keys (33 bytes) instead of uncompressed (65 bytes) */\n useCompressed?: boolean;\n}\n\n/**\n * Represents failures in ECIES cryptographic operations.\n *\n * @remarks\n * Provides specific error codes to help identify and recover from\n * different failure scenarios.\n *\n * @category Errors\n */\nexport class ECIESError extends Error {\n constructor(\n message: string,\n public readonly code:\n | \"INVALID_KEY\"\n | \"ENCRYPTION_FAILED\"\n | \"DECRYPTION_FAILED\"\n | \"MAC_MISMATCH\"\n | \"ECDH_FAILED\",\n public override readonly cause?: Error,\n ) {\n super(message);\n this.name = \"ECIESError\";\n }\n}\n\n/**\n * Validates if an object conforms to the ECIESEncrypted structure.\n *\n * @param obj - Object to validate.\n * @returns `true` if object is a valid ECIESEncrypted structure.\n *\n * @example\n * ```typescript\n * if (isECIESEncrypted(data)) {\n * const decrypted = await provider.decrypt(privateKey, data);\n * }\n * ```\n */\nexport function isECIESEncrypted(obj: unknown): obj is ECIESEncrypted {\n if (!obj || typeof obj !== \"object\") return false;\n const enc = obj as Record<string, unknown>;\n\n const isUint8Array = (value: unknown): value is Uint8Array => {\n return (\n value instanceof Uint8Array ||\n (typeof Buffer !== \"undefined\" && Buffer.isBuffer(value))\n );\n };\n\n return (\n isUint8Array(enc.iv) &&\n enc.iv.length === CIPHER.IV_LENGTH &&\n isUint8Array(enc.ephemPublicKey) &&\n (enc.ephemPublicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH ||\n enc.ephemPublicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) &&\n isUint8Array(enc.ciphertext) &&\n enc.ciphertext.length > 0 &&\n isUint8Array(enc.mac) &&\n enc.mac.length === MAC.LENGTH\n );\n}\n\n/**\n * Serializes ECIESEncrypted to hex string for storage or transmission.\n *\n * @param encrypted - Encrypted data structure from `encrypt()`.\n * @returns Hex string representation.\n *\n * @example\n * ```typescript\n * const hexString = serializeECIES(encrypted);\n * // Store hexString in database or send over network\n * ```\n */\nexport function serializeECIES(encrypted: ECIESEncrypted): string {\n const combined = new Uint8Array(\n encrypted.iv.length +\n encrypted.ephemPublicKey.length +\n encrypted.ciphertext.length +\n encrypted.mac.length,\n );\n\n let offset = 0;\n combined.set(encrypted.iv, offset);\n offset += encrypted.iv.length;\n combined.set(encrypted.ephemPublicKey, offset);\n offset += encrypted.ephemPublicKey.length;\n combined.set(encrypted.ciphertext, offset);\n offset += encrypted.ciphertext.length;\n combined.set(encrypted.mac, offset);\n\n return toHex(combined).slice(2);\n}\n\n/**\n * Deserializes hex string to ECIESEncrypted structure.\n *\n * @param hex - Hex string from `serializeECIES()` or storage.\n * @returns ECIESEncrypted structure ready for decryption.\n * @throws {ECIESError} When hex string format is invalid.\n * Verify the hex string is complete and uncorrupted.\n *\n * @example\n * ```typescript\n * const encrypted = deserializeECIES(hexString);\n * const decrypted = await provider.decrypt(privateKey, encrypted);\n * ```\n */\nexport function deserializeECIES(hex: string): ECIESEncrypted {\n const hexWithPrefix = hex.startsWith(\"0x\") ? hex : `0x${hex}`;\n const bytes = fromHex(hexWithPrefix as `0x${string}`, \"bytes\");\n\n // Check minimum length before accessing prefix byte\n // Need at least: IV (16 bytes) + 1 byte for prefix check + MAC (32 bytes) + 1 byte ciphertext\n const absoluteMinLength = FORMAT.IV_LENGTH + 1 + MAC.LENGTH + 1;\n if (bytes.length < absoluteMinLength) {\n throw new ECIESError(\n `Invalid ECIES data: too short (${bytes.length} bytes, minimum ${absoluteMinLength} bytes required)`,\n \"DECRYPTION_FAILED\",\n );\n }\n\n // Validate ephemeral public key prefix (must be uncompressed for eccrypto compatibility)\n const prefix = bytes[FORMAT.EPHEMERAL_KEY_OFFSET];\n\n if (prefix !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n `Invalid ephemeral public key: must be uncompressed format (0x04 prefix), got 0x${prefix.toString(16).padStart(2, \"0\")}`,\n \"DECRYPTION_FAILED\",\n );\n }\n\n const ephemKeySize = CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH;\n\n const minLength = FORMAT.IV_LENGTH + ephemKeySize + MAC.LENGTH + 1; // +1 for at least 1 byte of ciphertext\n if (bytes.length < minLength) {\n throw new ECIESError(\n `Invalid ECIES data: too short (${bytes.length} bytes, minimum ${minLength} bytes required)`,\n \"DECRYPTION_FAILED\",\n );\n }\n\n return {\n iv: bytes.subarray(FORMAT.IV_OFFSET, FORMAT.IV_OFFSET + FORMAT.IV_LENGTH),\n ephemPublicKey: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET,\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n ),\n ciphertext: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n bytes.length - MAC.LENGTH,\n ),\n mac: bytes.subarray(bytes.length - MAC.LENGTH),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA,uBAA2C;AAC3C,kBAA+B;AA4HxB,MAAM,mBAAmB,MAAM;AAAA,EACpC,YACE,SACgB,MAMS,OACzB;AACA,UAAM,OAAO;AARG;AAMS;AAGzB,SAAK,OAAO;AAAA,EACd;AACF;AAeO,SAAS,iBAAiB,KAAqC;AACpE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAAM;AAEZ,QAAM,eAAe,CAAC,UAAwC;AAC5D,WACE,iBAAiB,cAChB,OAAO,WAAW,eAAe,OAAO,SAAS,KAAK;AAAA,EAE3D;AAEA,SACE,aAAa,IAAI,EAAE,KACnB,IAAI,GAAG,WAAW,wBAAO,aACzB,aAAa,IAAI,cAAc,MAC9B,IAAI,eAAe,WAAW,uBAAM,kCACnC,IAAI,eAAe,WAAW,uBAAM,iCACtC,aAAa,IAAI,UAAU,KAC3B,IAAI,WAAW,SAAS,KACxB,aAAa,IAAI,GAAG,KACpB,IAAI,IAAI,WAAW,qBAAI;AAE3B;AAcO,SAAS,eAAe,WAAmC;AAChE,QAAM,WAAW,IAAI;AAAA,IACnB,UAAU,GAAG,SACX,UAAU,eAAe,SACzB,UAAU,WAAW,SACrB,UAAU,IAAI;AAAA,EAClB;AAEA,MAAI,SAAS;AACb,WAAS,IAAI,UAAU,IAAI,MAAM;AACjC,YAAU,UAAU,GAAG;AACvB,WAAS,IAAI,UAAU,gBAAgB,MAAM;AAC7C,YAAU,UAAU,eAAe;AACnC,WAAS,IAAI,UAAU,YAAY,MAAM;AACzC,YAAU,UAAU,WAAW;AAC/B,WAAS,IAAI,UAAU,KAAK,MAAM;AAElC,aAAO,mBAAM,QAAQ,EAAE,MAAM,CAAC;AAChC;AAgBO,SAAS,iBAAiB,KAA6B;AAC5D,QAAM,gBAAgB,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AAC3D,QAAM,YAAQ,qBAAQ,eAAgC,OAAO;AAI7D,QAAM,oBAAoB,wBAAO,YAAY,IAAI,qBAAI,SAAS;AAC9D,MAAI,MAAM,SAAS,mBAAmB;AACpC,UAAM,IAAI;AAAA,MACR,kCAAkC,MAAM,MAAM,mBAAmB,iBAAiB;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS,MAAM,wBAAO,oBAAoB;AAEhD,MAAI,WAAW,uBAAM,OAAO,cAAc;AACxC,UAAM,IAAI;AAAA,MACR,kFAAkF,OAAO,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,MACtH;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,uBAAM;AAE3B,QAAM,YAAY,wBAAO,YAAY,eAAe,qBAAI,SAAS;AACjE,MAAI,MAAM,SAAS,WAAW;AAC5B,UAAM,IAAI;AAAA,MACR,kCAAkC,MAAM,MAAM,mBAAmB,SAAS;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,MAAM,SAAS,wBAAO,WAAW,wBAAO,YAAY,wBAAO,SAAS;AAAA,IACxE,gBAAgB,MAAM;AAAA,MACpB,wBAAO;AAAA,MACP,wBAAO,uBAAuB;AAAA,IAChC;AAAA,IACA,YAAY,MAAM;AAAA,MAChB,wBAAO,uBAAuB;AAAA,MAC9B,MAAM,SAAS,qBAAI;AAAA,IACrB;AAAA,IACA,KAAK,MAAM,SAAS,MAAM,SAAS,qBAAI,MAAM;AAAA,EAC/C;AACF;","names":[]}
|
|
@@ -33,10 +33,27 @@ function serializeECIES(encrypted) {
|
|
|
33
33
|
function deserializeECIES(hex) {
|
|
34
34
|
const hexWithPrefix = hex.startsWith("0x") ? hex : `0x${hex}`;
|
|
35
35
|
const bytes = fromHex(hexWithPrefix, "bytes");
|
|
36
|
-
const
|
|
36
|
+
const absoluteMinLength = FORMAT.IV_LENGTH + 1 + MAC.LENGTH + 1;
|
|
37
|
+
if (bytes.length < absoluteMinLength) {
|
|
38
|
+
throw new ECIESError(
|
|
39
|
+
`Invalid ECIES data: too short (${bytes.length} bytes, minimum ${absoluteMinLength} bytes required)`,
|
|
40
|
+
"DECRYPTION_FAILED"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const prefix = bytes[FORMAT.EPHEMERAL_KEY_OFFSET];
|
|
44
|
+
if (prefix !== CURVE.PREFIX.UNCOMPRESSED) {
|
|
45
|
+
throw new ECIESError(
|
|
46
|
+
`Invalid ephemeral public key: must be uncompressed format (0x04 prefix), got 0x${prefix.toString(16).padStart(2, "0")}`,
|
|
47
|
+
"DECRYPTION_FAILED"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const ephemKeySize = CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH;
|
|
37
51
|
const minLength = FORMAT.IV_LENGTH + ephemKeySize + MAC.LENGTH + 1;
|
|
38
52
|
if (bytes.length < minLength) {
|
|
39
|
-
throw new ECIESError(
|
|
53
|
+
throw new ECIESError(
|
|
54
|
+
`Invalid ECIES data: too short (${bytes.length} bytes, minimum ${minLength} bytes required)`,
|
|
55
|
+
"DECRYPTION_FAILED"
|
|
56
|
+
);
|
|
40
57
|
}
|
|
41
58
|
return {
|
|
42
59
|
iv: bytes.subarray(FORMAT.IV_OFFSET, FORMAT.IV_OFFSET + FORMAT.IV_LENGTH),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/interface.ts"],"sourcesContent":["/**\n * ECIES (Elliptic Curve Integrated Encryption Scheme) Interface\n *\n * @remarks\n * Defines the contract for platform-specific ECIES implementations.\n * All implementations maintain compatibility with the eccrypto format to ensure\n * backward compatibility with existing encrypted data.\n *\n * **Format specification:**\n * `[iv (16 bytes)][ephemPublicKey (65 bytes)][ciphertext (variable)][mac (32 bytes)]`\n *\n * @category Cryptography\n */\n\nimport { CIPHER, CURVE, MAC, FORMAT } from \"./constants\";\nimport { fromHex, toHex } from \"viem\";\n\n/**\n * Represents ECIES encrypted data in eccrypto-compatible format.\n *\n * @remarks\n * This structure maintains backward compatibility with data encrypted using\n * the legacy eccrypto library.\n */\nexport interface ECIESEncrypted {\n /** Initialization vector (16 bytes) */\n iv: Uint8Array;\n /** Ephemeral public key (65 bytes uncompressed) */\n ephemPublicKey: Uint8Array;\n /** Encrypted data */\n ciphertext: Uint8Array;\n /** Message authentication code (32 bytes) */\n mac: Uint8Array;\n}\n\n/**\n * Provides ECIES encryption and decryption operations.\n *\n * @remarks\n * Platform-specific implementations handle the underlying cryptographic primitives\n * while maintaining consistent data format across environments.\n *\n * @category Cryptography\n */\nexport interface ECIESProvider {\n /**\n * Encrypts data using ECIES with secp256k1.\n *\n * @param publicKey - Recipient's public key (65 bytes uncompressed or 33 bytes compressed).\n * Obtain via `vana.server.getIdentity(userAddress).public_key`.\n * @param message - Data to encrypt.\n * @returns Encrypted data structure compatible with eccrypto format.\n * @throws {ECIESError} When public key is invalid.\n * Verify key format matches secp256k1 requirements.\n *\n * @example\n * ```typescript\n * const encrypted = await provider.encrypt(\n * fromHex(publicKey, 'bytes'),\n * new TextEncoder().encode('sensitive data')\n * );\n * ```\n */\n encrypt(publicKey: Uint8Array, message: Uint8Array): Promise<ECIESEncrypted>;\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - Recipient's private key (32 bytes).\n * @param encrypted - Encrypted data structure from `encrypt()` or legacy eccrypto.\n * @returns Decrypted message as Uint8Array.\n * @throws {ECIESError} When MAC verification fails.\n * Ensure the private key matches the public key used for encryption.\n *\n * @example\n * ```typescript\n * const decrypted = await provider.decrypt(\n * fromHex(privateKey, 'bytes'),\n * encrypted\n * );\n * const message = new TextDecoder().decode(decrypted);\n * ```\n */\n decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n *\n * @remarks\n * Strict policy: Only accepts properly formatted compressed (33 bytes) or\n * uncompressed (65 bytes) public keys. Does not accept 64-byte raw coordinates\n * to ensure data integrity and prevent masking of malformed inputs.\n *\n * @param publicKey - Public key in compressed or uncompressed format\n * @returns Normalized uncompressed public key (65 bytes with 0x04 prefix)\n * @throws {Error} When public key format is invalid, including raw coordinates (64 bytes)\n * @throws {Error} When decompression of compressed key fails\n *\n * @example\n * ```typescript\n * // Compressed key (33 bytes)\n * const compressed = new Uint8Array(33);\n * compressed[0] = 0x02;\n * const uncompressed = provider.normalizeToUncompressed(compressed);\n * console.log(uncompressed.length); // 65\n * console.log(uncompressed[0]); // 0x04\n *\n * // Already uncompressed (65 bytes)\n * const already = provider.normalizeToUncompressed(uncompressedKey);\n * console.log(already === uncompressedKey); // true (returns same reference)\n *\n * // Raw coordinates rejected (64 bytes)\n * const raw = new Uint8Array(64);\n * provider.normalizeToUncompressed(raw); // Throws error\n * ```\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n}\n\n/**\n * Configures ECIES operation behavior.\n */\nexport interface ECIESOptions {\n /** Use compressed public keys (33 bytes) instead of uncompressed (65 bytes) */\n useCompressed?: boolean;\n}\n\n/**\n * Represents failures in ECIES cryptographic operations.\n *\n * @remarks\n * Provides specific error codes to help identify and recover from\n * different failure scenarios.\n *\n * @category Errors\n */\nexport class ECIESError extends Error {\n constructor(\n message: string,\n public readonly code:\n | \"INVALID_KEY\"\n | \"ENCRYPTION_FAILED\"\n | \"DECRYPTION_FAILED\"\n | \"MAC_MISMATCH\"\n | \"ECDH_FAILED\",\n public override readonly cause?: Error,\n ) {\n super(message);\n this.name = \"ECIESError\";\n }\n}\n\n/**\n * Validates if an object conforms to the ECIESEncrypted structure.\n *\n * @param obj - Object to validate.\n * @returns `true` if object is a valid ECIESEncrypted structure.\n *\n * @example\n * ```typescript\n * if (isECIESEncrypted(data)) {\n * const decrypted = await provider.decrypt(privateKey, data);\n * }\n * ```\n */\nexport function isECIESEncrypted(obj: unknown): obj is ECIESEncrypted {\n if (!obj || typeof obj !== \"object\") return false;\n const enc = obj as Record<string, unknown>;\n\n const isUint8Array = (value: unknown): value is Uint8Array => {\n return (\n value instanceof Uint8Array ||\n (typeof Buffer !== \"undefined\" && Buffer.isBuffer(value))\n );\n };\n\n return (\n isUint8Array(enc.iv) &&\n enc.iv.length === CIPHER.IV_LENGTH &&\n isUint8Array(enc.ephemPublicKey) &&\n (enc.ephemPublicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH ||\n enc.ephemPublicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) &&\n isUint8Array(enc.ciphertext) &&\n enc.ciphertext.length > 0 &&\n isUint8Array(enc.mac) &&\n enc.mac.length === MAC.LENGTH\n );\n}\n\n/**\n * Serializes ECIESEncrypted to hex string for storage or transmission.\n *\n * @param encrypted - Encrypted data structure from `encrypt()`.\n * @returns Hex string representation.\n *\n * @example\n * ```typescript\n * const hexString = serializeECIES(encrypted);\n * // Store hexString in database or send over network\n * ```\n */\nexport function serializeECIES(encrypted: ECIESEncrypted): string {\n const combined = new Uint8Array(\n encrypted.iv.length +\n encrypted.ephemPublicKey.length +\n encrypted.ciphertext.length +\n encrypted.mac.length,\n );\n\n let offset = 0;\n combined.set(encrypted.iv, offset);\n offset += encrypted.iv.length;\n combined.set(encrypted.ephemPublicKey, offset);\n offset += encrypted.ephemPublicKey.length;\n combined.set(encrypted.ciphertext, offset);\n offset += encrypted.ciphertext.length;\n combined.set(encrypted.mac, offset);\n\n return toHex(combined).slice(2);\n}\n\n/**\n * Deserializes hex string to ECIESEncrypted structure.\n *\n * @param hex - Hex string from `serializeECIES()` or storage.\n * @returns ECIESEncrypted structure ready for decryption.\n * @throws {ECIESError} When hex string format is invalid.\n * Verify the hex string is complete and uncorrupted.\n *\n * @example\n * ```typescript\n * const encrypted = deserializeECIES(hexString);\n * const decrypted = await provider.decrypt(privateKey, encrypted);\n * ```\n */\nexport function deserializeECIES(hex: string): ECIESEncrypted {\n const hexWithPrefix = hex.startsWith(\"0x\") ? hex : `0x${hex}`;\n const bytes = fromHex(hexWithPrefix as `0x${string}`, \"bytes\");\n\n // Determine ephemPublicKey size based on prefix\n const ephemKeySize =\n bytes[FORMAT.EPHEMERAL_KEY_OFFSET] === CURVE.PREFIX.UNCOMPRESSED\n ? CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH\n : CURVE.COMPRESSED_PUBLIC_KEY_LENGTH;\n\n const minLength = FORMAT.IV_LENGTH + ephemKeySize + MAC.LENGTH + 1; // +1 for at least 1 byte of ciphertext\n if (bytes.length < minLength) {\n throw new ECIESError(\"Invalid ECIES data: too short\", \"DECRYPTION_FAILED\");\n }\n\n return {\n iv: bytes.subarray(FORMAT.IV_OFFSET, FORMAT.IV_OFFSET + FORMAT.IV_LENGTH),\n ephemPublicKey: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET,\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n ),\n ciphertext: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n bytes.length - MAC.LENGTH,\n ),\n mac: bytes.subarray(bytes.length - MAC.LENGTH),\n };\n}\n"],"mappings":"AAcA,SAAS,QAAQ,OAAO,KAAK,cAAc;AAC3C,SAAS,SAAS,aAAa;AA4HxB,MAAM,mBAAmB,MAAM;AAAA,EACpC,YACE,SACgB,MAMS,OACzB;AACA,UAAM,OAAO;AARG;AAMS;AAGzB,SAAK,OAAO;AAAA,EACd;AACF;AAeO,SAAS,iBAAiB,KAAqC;AACpE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAAM;AAEZ,QAAM,eAAe,CAAC,UAAwC;AAC5D,WACE,iBAAiB,cAChB,OAAO,WAAW,eAAe,OAAO,SAAS,KAAK;AAAA,EAE3D;AAEA,SACE,aAAa,IAAI,EAAE,KACnB,IAAI,GAAG,WAAW,OAAO,aACzB,aAAa,IAAI,cAAc,MAC9B,IAAI,eAAe,WAAW,MAAM,kCACnC,IAAI,eAAe,WAAW,MAAM,iCACtC,aAAa,IAAI,UAAU,KAC3B,IAAI,WAAW,SAAS,KACxB,aAAa,IAAI,GAAG,KACpB,IAAI,IAAI,WAAW,IAAI;AAE3B;AAcO,SAAS,eAAe,WAAmC;AAChE,QAAM,WAAW,IAAI;AAAA,IACnB,UAAU,GAAG,SACX,UAAU,eAAe,SACzB,UAAU,WAAW,SACrB,UAAU,IAAI;AAAA,EAClB;AAEA,MAAI,SAAS;AACb,WAAS,IAAI,UAAU,IAAI,MAAM;AACjC,YAAU,UAAU,GAAG;AACvB,WAAS,IAAI,UAAU,gBAAgB,MAAM;AAC7C,YAAU,UAAU,eAAe;AACnC,WAAS,IAAI,UAAU,YAAY,MAAM;AACzC,YAAU,UAAU,WAAW;AAC/B,WAAS,IAAI,UAAU,KAAK,MAAM;AAElC,SAAO,MAAM,QAAQ,EAAE,MAAM,CAAC;AAChC;AAgBO,SAAS,iBAAiB,KAA6B;AAC5D,QAAM,gBAAgB,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AAC3D,QAAM,QAAQ,QAAQ,eAAgC,OAAO;AAG7D,QAAM,eACJ,MAAM,OAAO,oBAAoB,MAAM,MAAM,OAAO,eAChD,MAAM,iCACN,MAAM;AAEZ,QAAM,YAAY,OAAO,YAAY,eAAe,IAAI,SAAS;AACjE,MAAI,MAAM,SAAS,WAAW;AAC5B,UAAM,IAAI,WAAW,iCAAiC,mBAAmB;AAAA,EAC3E;AAEA,SAAO;AAAA,IACL,IAAI,MAAM,SAAS,OAAO,WAAW,OAAO,YAAY,OAAO,SAAS;AAAA,IACxE,gBAAgB,MAAM;AAAA,MACpB,OAAO;AAAA,MACP,OAAO,uBAAuB;AAAA,IAChC;AAAA,IACA,YAAY,MAAM;AAAA,MAChB,OAAO,uBAAuB;AAAA,MAC9B,MAAM,SAAS,IAAI;AAAA,IACrB;AAAA,IACA,KAAK,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM;AAAA,EAC/C;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/interface.ts"],"sourcesContent":["/**\n * ECIES (Elliptic Curve Integrated Encryption Scheme) Interface\n *\n * @remarks\n * Defines the contract for platform-specific ECIES implementations.\n * All implementations maintain compatibility with the eccrypto format to ensure\n * backward compatibility with existing encrypted data.\n *\n * **Format specification:**\n * `[iv (16 bytes)][ephemPublicKey (65 bytes)][ciphertext (variable)][mac (32 bytes)]`\n *\n * @category Cryptography\n */\n\nimport { CIPHER, CURVE, MAC, FORMAT } from \"./constants\";\nimport { fromHex, toHex } from \"viem\";\n\n/**\n * Represents ECIES encrypted data in eccrypto-compatible format.\n *\n * @remarks\n * This structure maintains backward compatibility with data encrypted using\n * the legacy eccrypto library.\n */\nexport interface ECIESEncrypted {\n /** Initialization vector (16 bytes) */\n iv: Uint8Array;\n /** Ephemeral public key (65 bytes uncompressed) */\n ephemPublicKey: Uint8Array;\n /** Encrypted data */\n ciphertext: Uint8Array;\n /** Message authentication code (32 bytes) */\n mac: Uint8Array;\n}\n\n/**\n * Provides ECIES encryption and decryption operations.\n *\n * @remarks\n * Platform-specific implementations handle the underlying cryptographic primitives\n * while maintaining consistent data format across environments.\n *\n * @category Cryptography\n */\nexport interface ECIESProvider {\n /**\n * Encrypts data using ECIES with secp256k1.\n *\n * @param publicKey - Recipient's public key (65 bytes uncompressed or 33 bytes compressed).\n * Obtain via `vana.server.getIdentity(userAddress).public_key`.\n * @param message - Data to encrypt.\n * @returns Encrypted data structure compatible with eccrypto format.\n * @throws {ECIESError} When public key is invalid.\n * Verify key format matches secp256k1 requirements.\n *\n * @example\n * ```typescript\n * const encrypted = await provider.encrypt(\n * fromHex(publicKey, 'bytes'),\n * new TextEncoder().encode('sensitive data')\n * );\n * ```\n */\n encrypt(publicKey: Uint8Array, message: Uint8Array): Promise<ECIESEncrypted>;\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - Recipient's private key (32 bytes).\n * @param encrypted - Encrypted data structure from `encrypt()` or legacy eccrypto.\n * @returns Decrypted message as Uint8Array.\n * @throws {ECIESError} When MAC verification fails.\n * Ensure the private key matches the public key used for encryption.\n *\n * @example\n * ```typescript\n * const decrypted = await provider.decrypt(\n * fromHex(privateKey, 'bytes'),\n * encrypted\n * );\n * const message = new TextDecoder().decode(decrypted);\n * ```\n */\n decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n *\n * @remarks\n * Strict policy: Only accepts properly formatted compressed (33 bytes) or\n * uncompressed (65 bytes) public keys. Does not accept 64-byte raw coordinates\n * to ensure data integrity and prevent masking of malformed inputs.\n *\n * @param publicKey - Public key in compressed or uncompressed format\n * @returns Normalized uncompressed public key (65 bytes with 0x04 prefix)\n * @throws {Error} When public key format is invalid, including raw coordinates (64 bytes)\n * @throws {Error} When decompression of compressed key fails\n *\n * @example\n * ```typescript\n * // Compressed key (33 bytes)\n * const compressed = new Uint8Array(33);\n * compressed[0] = 0x02;\n * const uncompressed = provider.normalizeToUncompressed(compressed);\n * console.log(uncompressed.length); // 65\n * console.log(uncompressed[0]); // 0x04\n *\n * // Already uncompressed (65 bytes)\n * const already = provider.normalizeToUncompressed(uncompressedKey);\n * console.log(already === uncompressedKey); // true (returns same reference)\n *\n * // Raw coordinates rejected (64 bytes)\n * const raw = new Uint8Array(64);\n * provider.normalizeToUncompressed(raw); // Throws error\n * ```\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n}\n\n/**\n * Configures ECIES operation behavior.\n */\nexport interface ECIESOptions {\n /** Use compressed public keys (33 bytes) instead of uncompressed (65 bytes) */\n useCompressed?: boolean;\n}\n\n/**\n * Represents failures in ECIES cryptographic operations.\n *\n * @remarks\n * Provides specific error codes to help identify and recover from\n * different failure scenarios.\n *\n * @category Errors\n */\nexport class ECIESError extends Error {\n constructor(\n message: string,\n public readonly code:\n | \"INVALID_KEY\"\n | \"ENCRYPTION_FAILED\"\n | \"DECRYPTION_FAILED\"\n | \"MAC_MISMATCH\"\n | \"ECDH_FAILED\",\n public override readonly cause?: Error,\n ) {\n super(message);\n this.name = \"ECIESError\";\n }\n}\n\n/**\n * Validates if an object conforms to the ECIESEncrypted structure.\n *\n * @param obj - Object to validate.\n * @returns `true` if object is a valid ECIESEncrypted structure.\n *\n * @example\n * ```typescript\n * if (isECIESEncrypted(data)) {\n * const decrypted = await provider.decrypt(privateKey, data);\n * }\n * ```\n */\nexport function isECIESEncrypted(obj: unknown): obj is ECIESEncrypted {\n if (!obj || typeof obj !== \"object\") return false;\n const enc = obj as Record<string, unknown>;\n\n const isUint8Array = (value: unknown): value is Uint8Array => {\n return (\n value instanceof Uint8Array ||\n (typeof Buffer !== \"undefined\" && Buffer.isBuffer(value))\n );\n };\n\n return (\n isUint8Array(enc.iv) &&\n enc.iv.length === CIPHER.IV_LENGTH &&\n isUint8Array(enc.ephemPublicKey) &&\n (enc.ephemPublicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH ||\n enc.ephemPublicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) &&\n isUint8Array(enc.ciphertext) &&\n enc.ciphertext.length > 0 &&\n isUint8Array(enc.mac) &&\n enc.mac.length === MAC.LENGTH\n );\n}\n\n/**\n * Serializes ECIESEncrypted to hex string for storage or transmission.\n *\n * @param encrypted - Encrypted data structure from `encrypt()`.\n * @returns Hex string representation.\n *\n * @example\n * ```typescript\n * const hexString = serializeECIES(encrypted);\n * // Store hexString in database or send over network\n * ```\n */\nexport function serializeECIES(encrypted: ECIESEncrypted): string {\n const combined = new Uint8Array(\n encrypted.iv.length +\n encrypted.ephemPublicKey.length +\n encrypted.ciphertext.length +\n encrypted.mac.length,\n );\n\n let offset = 0;\n combined.set(encrypted.iv, offset);\n offset += encrypted.iv.length;\n combined.set(encrypted.ephemPublicKey, offset);\n offset += encrypted.ephemPublicKey.length;\n combined.set(encrypted.ciphertext, offset);\n offset += encrypted.ciphertext.length;\n combined.set(encrypted.mac, offset);\n\n return toHex(combined).slice(2);\n}\n\n/**\n * Deserializes hex string to ECIESEncrypted structure.\n *\n * @param hex - Hex string from `serializeECIES()` or storage.\n * @returns ECIESEncrypted structure ready for decryption.\n * @throws {ECIESError} When hex string format is invalid.\n * Verify the hex string is complete and uncorrupted.\n *\n * @example\n * ```typescript\n * const encrypted = deserializeECIES(hexString);\n * const decrypted = await provider.decrypt(privateKey, encrypted);\n * ```\n */\nexport function deserializeECIES(hex: string): ECIESEncrypted {\n const hexWithPrefix = hex.startsWith(\"0x\") ? hex : `0x${hex}`;\n const bytes = fromHex(hexWithPrefix as `0x${string}`, \"bytes\");\n\n // Check minimum length before accessing prefix byte\n // Need at least: IV (16 bytes) + 1 byte for prefix check + MAC (32 bytes) + 1 byte ciphertext\n const absoluteMinLength = FORMAT.IV_LENGTH + 1 + MAC.LENGTH + 1;\n if (bytes.length < absoluteMinLength) {\n throw new ECIESError(\n `Invalid ECIES data: too short (${bytes.length} bytes, minimum ${absoluteMinLength} bytes required)`,\n \"DECRYPTION_FAILED\",\n );\n }\n\n // Validate ephemeral public key prefix (must be uncompressed for eccrypto compatibility)\n const prefix = bytes[FORMAT.EPHEMERAL_KEY_OFFSET];\n\n if (prefix !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n `Invalid ephemeral public key: must be uncompressed format (0x04 prefix), got 0x${prefix.toString(16).padStart(2, \"0\")}`,\n \"DECRYPTION_FAILED\",\n );\n }\n\n const ephemKeySize = CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH;\n\n const minLength = FORMAT.IV_LENGTH + ephemKeySize + MAC.LENGTH + 1; // +1 for at least 1 byte of ciphertext\n if (bytes.length < minLength) {\n throw new ECIESError(\n `Invalid ECIES data: too short (${bytes.length} bytes, minimum ${minLength} bytes required)`,\n \"DECRYPTION_FAILED\",\n );\n }\n\n return {\n iv: bytes.subarray(FORMAT.IV_OFFSET, FORMAT.IV_OFFSET + FORMAT.IV_LENGTH),\n ephemPublicKey: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET,\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n ),\n ciphertext: bytes.subarray(\n FORMAT.EPHEMERAL_KEY_OFFSET + ephemKeySize,\n bytes.length - MAC.LENGTH,\n ),\n mac: bytes.subarray(bytes.length - MAC.LENGTH),\n };\n}\n"],"mappings":"AAcA,SAAS,QAAQ,OAAO,KAAK,cAAc;AAC3C,SAAS,SAAS,aAAa;AA4HxB,MAAM,mBAAmB,MAAM;AAAA,EACpC,YACE,SACgB,MAMS,OACzB;AACA,UAAM,OAAO;AARG;AAMS;AAGzB,SAAK,OAAO;AAAA,EACd;AACF;AAeO,SAAS,iBAAiB,KAAqC;AACpE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,MAAM;AAEZ,QAAM,eAAe,CAAC,UAAwC;AAC5D,WACE,iBAAiB,cAChB,OAAO,WAAW,eAAe,OAAO,SAAS,KAAK;AAAA,EAE3D;AAEA,SACE,aAAa,IAAI,EAAE,KACnB,IAAI,GAAG,WAAW,OAAO,aACzB,aAAa,IAAI,cAAc,MAC9B,IAAI,eAAe,WAAW,MAAM,kCACnC,IAAI,eAAe,WAAW,MAAM,iCACtC,aAAa,IAAI,UAAU,KAC3B,IAAI,WAAW,SAAS,KACxB,aAAa,IAAI,GAAG,KACpB,IAAI,IAAI,WAAW,IAAI;AAE3B;AAcO,SAAS,eAAe,WAAmC;AAChE,QAAM,WAAW,IAAI;AAAA,IACnB,UAAU,GAAG,SACX,UAAU,eAAe,SACzB,UAAU,WAAW,SACrB,UAAU,IAAI;AAAA,EAClB;AAEA,MAAI,SAAS;AACb,WAAS,IAAI,UAAU,IAAI,MAAM;AACjC,YAAU,UAAU,GAAG;AACvB,WAAS,IAAI,UAAU,gBAAgB,MAAM;AAC7C,YAAU,UAAU,eAAe;AACnC,WAAS,IAAI,UAAU,YAAY,MAAM;AACzC,YAAU,UAAU,WAAW;AAC/B,WAAS,IAAI,UAAU,KAAK,MAAM;AAElC,SAAO,MAAM,QAAQ,EAAE,MAAM,CAAC;AAChC;AAgBO,SAAS,iBAAiB,KAA6B;AAC5D,QAAM,gBAAgB,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AAC3D,QAAM,QAAQ,QAAQ,eAAgC,OAAO;AAI7D,QAAM,oBAAoB,OAAO,YAAY,IAAI,IAAI,SAAS;AAC9D,MAAI,MAAM,SAAS,mBAAmB;AACpC,UAAM,IAAI;AAAA,MACR,kCAAkC,MAAM,MAAM,mBAAmB,iBAAiB;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS,MAAM,OAAO,oBAAoB;AAEhD,MAAI,WAAW,MAAM,OAAO,cAAc;AACxC,UAAM,IAAI;AAAA,MACR,kFAAkF,OAAO,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,MACtH;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,MAAM;AAE3B,QAAM,YAAY,OAAO,YAAY,eAAe,IAAI,SAAS;AACjE,MAAI,MAAM,SAAS,WAAW;AAC5B,UAAM,IAAI;AAAA,MACR,kCAAkC,MAAM,MAAM,mBAAmB,SAAS;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,MAAM,SAAS,OAAO,WAAW,OAAO,YAAY,OAAO,SAAS;AAAA,IACxE,gBAAgB,MAAM;AAAA,MACpB,OAAO;AAAA,MACP,OAAO,uBAAuB;AAAA,IAChC;AAAA,IACA,YAAY,MAAM;AAAA,MAChB,OAAO,uBAAuB;AAAA,MAC9B,MAAM,SAAS,IAAI;AAAA,IACrB;AAAA,IACA,KAAK,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM;AAAA,EAC/C;AACF;","names":[]}
|
package/dist/index.browser.d.ts
CHANGED
|
@@ -147,6 +147,8 @@ export { BaseController, RetryUtility, RateLimiter, MemoryCache, EventEmitter, M
|
|
|
147
147
|
export { BrowserPlatformAdapter } from "./platform/browser";
|
|
148
148
|
export { BrowserECIESUint8Provider as BrowserECIESProvider } from "./crypto/ecies/browser";
|
|
149
149
|
export type { VanaPlatformAdapter } from "./platform/interface";
|
|
150
|
+
export { ECIESError, isECIESEncrypted, serializeECIES, deserializeECIES, } from "./crypto/ecies";
|
|
151
|
+
export type { ECIESProvider, ECIESEncrypted, ECIESOptions, } from "./crypto/ecies";
|
|
150
152
|
export { createBrowserPlatformAdapter, createPlatformAdapterSafe, } from "./platform/browser-only";
|
|
151
153
|
export { detectPlatform, isPlatformSupported, getPlatformCapabilities, } from "./platform/utils";
|
|
152
154
|
export { ApiClient } from "./core/apiClient";
|
package/dist/index.browser.js
CHANGED
|
@@ -67,6 +67,12 @@ import {
|
|
|
67
67
|
} from "./core/generics";
|
|
68
68
|
import { BrowserPlatformAdapter as BrowserPlatformAdapter2 } from "./platform/browser";
|
|
69
69
|
import { BrowserECIESUint8Provider } from "./crypto/ecies/browser";
|
|
70
|
+
import {
|
|
71
|
+
ECIESError,
|
|
72
|
+
isECIESEncrypted,
|
|
73
|
+
serializeECIES,
|
|
74
|
+
deserializeECIES
|
|
75
|
+
} from "./crypto/ecies";
|
|
70
76
|
import {
|
|
71
77
|
createBrowserPlatformAdapter,
|
|
72
78
|
createPlatformAdapterSafe
|
|
@@ -86,6 +92,7 @@ export {
|
|
|
86
92
|
CONTRACTS,
|
|
87
93
|
CircuitBreaker,
|
|
88
94
|
DataController,
|
|
95
|
+
ECIESError,
|
|
89
96
|
EnhancedTransactionResponse,
|
|
90
97
|
EventEmitter,
|
|
91
98
|
MemoryCache,
|
|
@@ -106,6 +113,7 @@ export {
|
|
|
106
113
|
createBrowserPlatformAdapter,
|
|
107
114
|
createPlatformAdapterSafe,
|
|
108
115
|
index_browser_default as default,
|
|
116
|
+
deserializeECIES,
|
|
109
117
|
detectPlatform,
|
|
110
118
|
enhanceResponse,
|
|
111
119
|
getAbi,
|
|
@@ -116,6 +124,7 @@ export {
|
|
|
116
124
|
getPlatformCapabilities,
|
|
117
125
|
getServiceEndpoints,
|
|
118
126
|
isAPIResponse,
|
|
127
|
+
isECIESEncrypted,
|
|
119
128
|
isPlatformSupported,
|
|
120
129
|
isReplicateAPIResponse,
|
|
121
130
|
mainnetServices,
|
|
@@ -124,6 +133,7 @@ export {
|
|
|
124
133
|
mokshaTestnet,
|
|
125
134
|
parseReplicateOutput,
|
|
126
135
|
safeParseJSON,
|
|
136
|
+
serializeECIES,
|
|
127
137
|
vanaMainnet
|
|
128
138
|
};
|
|
129
139
|
//# sourceMappingURL=index.browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.browser.ts"],"sourcesContent":["/**\n * @module Browser\n * Browser-specific implementation of the Vana SDK\n */\n\nimport { BrowserPlatformAdapter } from \"./platform/browser\";\nimport { VanaCore } from \"./core\";\nimport type {\n VanaConfig,\n VanaConfigWithStorage,\n StorageRequiredMarker,\n} from \"./types\";\n\n/**\n * Internal implementation class for browser environments.\n * This class is not exported directly - use the Vana factory function instead.\n */\nclass VanaBrowserImpl extends VanaCore {\n constructor(config: VanaConfig) {\n super(new BrowserPlatformAdapter(), config);\n }\n}\n\n/**\n * Creates a new Vana SDK instance configured for browser environments.\n *\n * @remarks\n * This is the primary entry point for browser applications using the Vana SDK. The function\n * automatically detects your configuration type and provides compile-time type safety:\n * - **With storage configured**: All methods including file upload/download are available\n * - **Without storage**: Storage-dependent methods throw runtime errors and are excluded from TypeScript\n *\n * The SDK supports multiple wallet configurations (direct WalletClient or chain config),\n * various storage providers (IPFS, Pinata, Google Drive), and gasless transactions via relayers.\n * All operations are optimized for browser environments with proper bundle size optimization.\n *\n * @param config - Configuration object containing wallet, storage, and relayer settings\n * @returns A fully configured Vana SDK instance for browser use\n * @throws {InvalidConfigurationError} When configuration parameters are invalid or missing\n * @example\n * ```typescript\n * import { Vana } from '@opendatalabs/vana-sdk/browser';\n * import { createWalletClient, custom } from 'viem';\n * import { IPFSStorage } from '@opendatalabs/vana-sdk/browser';\n *\n * // Complete setup with storage and wallet\n * const walletClient = createWalletClient({\n * chain: mokshaTestnet,\n * transport: custom(window.ethereum)\n * });\n *\n * const vana = Vana({\n * walletClient,\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' }),\n * pinata: new PinataStorage({ apiKey: process.env.PINATA_KEY })\n * },\n * defaultProvider: 'ipfs'\n * },\n * relayerCallbacks: {\n * async submitPermissionGrant(typedData, signature) {\n * const response = await fetch('/api/relay/grant', {\n * method: 'POST',\n * body: JSON.stringify({ typedData, signature })\n * });\n * return (await response.json()).transactionHash;\n * }\n * }\n * });\n *\n * // All operations now available\n * const files = await vana.data.getUserFiles();\n * const permissions = await vana.permissions.getUserPermissions();\n * await vana.data.upload({ content: 'My data', filename: 'data.txt' });\n * ```\n *\n * @example\n * ```typescript\n * // Minimal setup without storage (read-only operations)\n * const vanaReadOnly = Vana({ walletClient });\n *\n * // These work without storage\n * const files = await vanaReadOnly.data.getUserFiles();\n * const permissions = await vanaReadOnly.permissions.getUserPermissions();\n *\n * // This would throw a runtime error\n * // await vanaReadOnly.data.upload(params); // ❌ InvalidConfigurationError\n *\n * // Safe runtime check\n * if (vanaReadOnly.isStorageEnabled()) {\n * await vanaReadOnly.data.upload(params); // ✅ TypeScript allows this\n * } else {\n * console.log('Storage not configured - upload unavailable');\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Using chain configuration instead of wallet client\n * const vana = Vana({\n * chainId: 14800, // Moksha testnet\n * account: '0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36',\n * rpcUrl: 'https://rpc.moksha.vana.org',\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n * ```\n *\n * @see {@link https://docs.vana.org/docs/sdk/getting-started | Getting Started Guide} for setup tutorials\n * @see {@link VanaCore} for the underlying implementation details\n * @category Core SDK\n */\nexport function Vana(\n config: VanaConfigWithStorage,\n): VanaBrowserImpl & StorageRequiredMarker;\nexport function Vana(config: VanaConfig): VanaBrowserImpl;\n/**\n * Creates a new Vana SDK instance.\n *\n * @param config - The configuration for the Vana SDK\n * @returns A new Vana SDK instance\n */\nexport function Vana(config: VanaConfig) {\n return new VanaBrowserImpl(config);\n}\n\n/**\n * The type of a Vana SDK instance in browser environments.\n * Uses InstanceType to properly expose all public methods from the class hierarchy.\n *\n * @see {@link Vana}\n */\nexport type VanaInstance = InstanceType<typeof VanaBrowserImpl>;\n\n// Export as default export\nexport default Vana;\n\n// Re-export everything that was in index.ts (avoiding circular dependency)\n// Core class and factory\nexport { VanaCore, VanaCoreFactory } from \"./core\";\n\n// Types - modular exports\nexport type * from \"./types\";\n\n// Type guards and utilities\nexport {\n isReplicateAPIResponse,\n isAPIResponse,\n safeParseJSON,\n parseReplicateOutput,\n} from \"./types/external-apis\";\n\n// VanaContract is exported from abi to avoid circular dependencies\nexport type { VanaContract } from \"./generated/abi\";\n\n// Enhanced response pattern for improved developer experience\nexport {\n EnhancedTransactionResponse,\n canEnhanceResponse,\n enhanceResponse,\n} from \"./client/enhancedResponse\";\n\n// Error classes\nexport * from \"./errors\";\n\n// Controllers\nexport { PermissionsController } from \"./controllers/permissions\";\nexport { DataController } from \"./controllers/data\";\nexport { ServerController } from \"./controllers/server\";\nexport { ProtocolController } from \"./controllers/protocol\";\nexport { SchemaController } from \"./controllers/schemas\";\nexport { OperationsController } from \"./controllers/operations\";\n\n// Contract controller\nexport * from \"./contracts/contractController\";\n\n// Utilities\nexport * from \"./utils/encryption\";\nexport * from \"./utils/formatters\";\nexport * from \"./utils/grantFiles\";\nexport * from \"./utils/grantValidation\";\nexport * from \"./utils/grants\";\nexport * from \"./utils/ipfs\";\nexport * from \"./utils/schemaValidation\";\nexport * from \"./utils/signatureCache\";\n// TransactionHandle removed - using POJOs instead\nexport type {\n Operation,\n TransactionResult,\n TransactionReceipt,\n PollingOptions,\n TransactionWaitOptions,\n} from \"./types/operations\";\n\n// Storage API\nexport * from \"./storage\";\n\n// Configuration\nexport { getContractAddress, CONTRACTS } from \"./generated/addresses\";\nexport { chains } from \"./config/chains\";\nexport {\n type ServiceEndpoints,\n mainnetServices,\n mokshaServices,\n getServiceEndpoints,\n getDefaultPersonalServerUrl,\n} from \"./config/default-services\";\n\n// Chain configurations with subgraph URLs - explicit exports for better DX\nexport {\n vanaMainnet,\n mokshaTestnet,\n moksha,\n type VanaChainConfig,\n getChainConfig,\n getAllChains,\n} from \"./chains\";\nexport * from \"./chains\";\n\n// ABIs\nexport { getAbi } from \"./generated/abi\";\nexport type { VanaContract as VanaContractAbi } from \"./generated/abi\";\n\n// Generic utilities for extensibility\nexport {\n BaseController,\n RetryUtility,\n RateLimiter,\n MemoryCache,\n EventEmitter,\n MiddlewarePipeline,\n AsyncQueue,\n CircuitBreaker,\n} from \"./core/generics\";\n\n// Platform adapters - browser-safe exports\nexport { BrowserPlatformAdapter } from \"./platform/browser\";\nexport { BrowserECIESUint8Provider as BrowserECIESProvider } from \"./crypto/ecies/browser\";\nexport type { VanaPlatformAdapter } from \"./platform/interface\";\n\n// Browser-only platform adapter utilities\nexport {\n createBrowserPlatformAdapter,\n createPlatformAdapterSafe,\n} from \"./platform/browser-only\";\n\n// Note: createNodePlatformAdapter is not exported in browser bundle to avoid Node.js dependencies\n\n// NodePlatformAdapter is available through dynamic import to avoid bundling Node.js dependencies\n// Use createNodePlatformAdapter() for dynamic import\n\n// Platform utilities - browser-safe only\nexport {\n detectPlatform,\n isPlatformSupported,\n getPlatformCapabilities,\n} from \"./platform/utils\";\n\nexport { ApiClient } from \"./core/apiClient\";\n\nexport type {\n ApiClientConfig,\n HttpMethod,\n RequestOptions,\n} from \"./core/apiClient\";\n\n// Note: Default export is already handled above with the Vana factory function\n\n// For testing purposes, we also export the implementation class\nexport { VanaBrowserImpl };\n"],"mappings":"AAKA,SAAS,8BAA8B;AACvC,SAAS,gBAAgB;AAWzB,MAAM,wBAAwB,SAAS;AAAA,EACrC,YAAY,QAAoB;AAC9B,UAAM,IAAI,uBAAuB,GAAG,MAAM;AAAA,EAC5C;AACF;AAwGO,SAAS,KAAK,QAAoB;AACvC,SAAO,IAAI,gBAAgB,MAAM;AACnC;AAWA,IAAO,wBAAQ;AAIf,SAAS,YAAAA,WAAU,uBAAuB;AAM1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,cAAc;AAGd,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,4BAA4B;AAGrC,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAWd,cAAc;AAGd,SAAS,oBAAoB,iBAAiB;AAC9C,SAAS,cAAc;AACvB;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AACP,cAAc;AAGd,SAAS,cAAc;AAIvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,0BAAAC,+BAA8B;AACvC,SAAsC,iCAA4B;AAIlE;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAQP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,iBAAiB;","names":["VanaCore","BrowserPlatformAdapter"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.browser.ts"],"sourcesContent":["/**\n * @module Browser\n * Browser-specific implementation of the Vana SDK\n */\n\nimport { BrowserPlatformAdapter } from \"./platform/browser\";\nimport { VanaCore } from \"./core\";\nimport type {\n VanaConfig,\n VanaConfigWithStorage,\n StorageRequiredMarker,\n} from \"./types\";\n\n/**\n * Internal implementation class for browser environments.\n * This class is not exported directly - use the Vana factory function instead.\n */\nclass VanaBrowserImpl extends VanaCore {\n constructor(config: VanaConfig) {\n super(new BrowserPlatformAdapter(), config);\n }\n}\n\n/**\n * Creates a new Vana SDK instance configured for browser environments.\n *\n * @remarks\n * This is the primary entry point for browser applications using the Vana SDK. The function\n * automatically detects your configuration type and provides compile-time type safety:\n * - **With storage configured**: All methods including file upload/download are available\n * - **Without storage**: Storage-dependent methods throw runtime errors and are excluded from TypeScript\n *\n * The SDK supports multiple wallet configurations (direct WalletClient or chain config),\n * various storage providers (IPFS, Pinata, Google Drive), and gasless transactions via relayers.\n * All operations are optimized for browser environments with proper bundle size optimization.\n *\n * @param config - Configuration object containing wallet, storage, and relayer settings\n * @returns A fully configured Vana SDK instance for browser use\n * @throws {InvalidConfigurationError} When configuration parameters are invalid or missing\n * @example\n * ```typescript\n * import { Vana } from '@opendatalabs/vana-sdk/browser';\n * import { createWalletClient, custom } from 'viem';\n * import { IPFSStorage } from '@opendatalabs/vana-sdk/browser';\n *\n * // Complete setup with storage and wallet\n * const walletClient = createWalletClient({\n * chain: mokshaTestnet,\n * transport: custom(window.ethereum)\n * });\n *\n * const vana = Vana({\n * walletClient,\n * storage: {\n * providers: {\n * ipfs: new IPFSStorage({ gateway: 'https://gateway.pinata.cloud' }),\n * pinata: new PinataStorage({ apiKey: process.env.PINATA_KEY })\n * },\n * defaultProvider: 'ipfs'\n * },\n * relayerCallbacks: {\n * async submitPermissionGrant(typedData, signature) {\n * const response = await fetch('/api/relay/grant', {\n * method: 'POST',\n * body: JSON.stringify({ typedData, signature })\n * });\n * return (await response.json()).transactionHash;\n * }\n * }\n * });\n *\n * // All operations now available\n * const files = await vana.data.getUserFiles();\n * const permissions = await vana.permissions.getUserPermissions();\n * await vana.data.upload({ content: 'My data', filename: 'data.txt' });\n * ```\n *\n * @example\n * ```typescript\n * // Minimal setup without storage (read-only operations)\n * const vanaReadOnly = Vana({ walletClient });\n *\n * // These work without storage\n * const files = await vanaReadOnly.data.getUserFiles();\n * const permissions = await vanaReadOnly.permissions.getUserPermissions();\n *\n * // This would throw a runtime error\n * // await vanaReadOnly.data.upload(params); // ❌ InvalidConfigurationError\n *\n * // Safe runtime check\n * if (vanaReadOnly.isStorageEnabled()) {\n * await vanaReadOnly.data.upload(params); // ✅ TypeScript allows this\n * } else {\n * console.log('Storage not configured - upload unavailable');\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Using chain configuration instead of wallet client\n * const vana = Vana({\n * chainId: 14800, // Moksha testnet\n * account: '0x742d35Cc6558Fd4D9e9E0E888F0462ef6919Bd36',\n * rpcUrl: 'https://rpc.moksha.vana.org',\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n * ```\n *\n * @see {@link https://docs.vana.org/docs/sdk/getting-started | Getting Started Guide} for setup tutorials\n * @see {@link VanaCore} for the underlying implementation details\n * @category Core SDK\n */\nexport function Vana(\n config: VanaConfigWithStorage,\n): VanaBrowserImpl & StorageRequiredMarker;\nexport function Vana(config: VanaConfig): VanaBrowserImpl;\n/**\n * Creates a new Vana SDK instance.\n *\n * @param config - The configuration for the Vana SDK\n * @returns A new Vana SDK instance\n */\nexport function Vana(config: VanaConfig) {\n return new VanaBrowserImpl(config);\n}\n\n/**\n * The type of a Vana SDK instance in browser environments.\n * Uses InstanceType to properly expose all public methods from the class hierarchy.\n *\n * @see {@link Vana}\n */\nexport type VanaInstance = InstanceType<typeof VanaBrowserImpl>;\n\n// Export as default export\nexport default Vana;\n\n// Re-export everything that was in index.ts (avoiding circular dependency)\n// Core class and factory\nexport { VanaCore, VanaCoreFactory } from \"./core\";\n\n// Types - modular exports\nexport type * from \"./types\";\n\n// Type guards and utilities\nexport {\n isReplicateAPIResponse,\n isAPIResponse,\n safeParseJSON,\n parseReplicateOutput,\n} from \"./types/external-apis\";\n\n// VanaContract is exported from abi to avoid circular dependencies\nexport type { VanaContract } from \"./generated/abi\";\n\n// Enhanced response pattern for improved developer experience\nexport {\n EnhancedTransactionResponse,\n canEnhanceResponse,\n enhanceResponse,\n} from \"./client/enhancedResponse\";\n\n// Error classes\nexport * from \"./errors\";\n\n// Controllers\nexport { PermissionsController } from \"./controllers/permissions\";\nexport { DataController } from \"./controllers/data\";\nexport { ServerController } from \"./controllers/server\";\nexport { ProtocolController } from \"./controllers/protocol\";\nexport { SchemaController } from \"./controllers/schemas\";\nexport { OperationsController } from \"./controllers/operations\";\n\n// Contract controller\nexport * from \"./contracts/contractController\";\n\n// Utilities\nexport * from \"./utils/encryption\";\nexport * from \"./utils/formatters\";\nexport * from \"./utils/grantFiles\";\nexport * from \"./utils/grantValidation\";\nexport * from \"./utils/grants\";\nexport * from \"./utils/ipfs\";\nexport * from \"./utils/schemaValidation\";\nexport * from \"./utils/signatureCache\";\n// TransactionHandle removed - using POJOs instead\nexport type {\n Operation,\n TransactionResult,\n TransactionReceipt,\n PollingOptions,\n TransactionWaitOptions,\n} from \"./types/operations\";\n\n// Storage API\nexport * from \"./storage\";\n\n// Configuration\nexport { getContractAddress, CONTRACTS } from \"./generated/addresses\";\nexport { chains } from \"./config/chains\";\nexport {\n type ServiceEndpoints,\n mainnetServices,\n mokshaServices,\n getServiceEndpoints,\n getDefaultPersonalServerUrl,\n} from \"./config/default-services\";\n\n// Chain configurations with subgraph URLs - explicit exports for better DX\nexport {\n vanaMainnet,\n mokshaTestnet,\n moksha,\n type VanaChainConfig,\n getChainConfig,\n getAllChains,\n} from \"./chains\";\nexport * from \"./chains\";\n\n// ABIs\nexport { getAbi } from \"./generated/abi\";\nexport type { VanaContract as VanaContractAbi } from \"./generated/abi\";\n\n// Generic utilities for extensibility\nexport {\n BaseController,\n RetryUtility,\n RateLimiter,\n MemoryCache,\n EventEmitter,\n MiddlewarePipeline,\n AsyncQueue,\n CircuitBreaker,\n} from \"./core/generics\";\n\n// Platform adapters - browser-safe exports\nexport { BrowserPlatformAdapter } from \"./platform/browser\";\nexport { BrowserECIESUint8Provider as BrowserECIESProvider } from \"./crypto/ecies/browser\";\nexport type { VanaPlatformAdapter } from \"./platform/interface\";\n\n// ECIES utilities and types (exported via module index for consistency)\nexport {\n ECIESError,\n isECIESEncrypted,\n serializeECIES,\n deserializeECIES,\n} from \"./crypto/ecies\";\nexport type {\n ECIESProvider,\n ECIESEncrypted,\n ECIESOptions,\n} from \"./crypto/ecies\";\n\n// Browser-only platform adapter utilities\nexport {\n createBrowserPlatformAdapter,\n createPlatformAdapterSafe,\n} from \"./platform/browser-only\";\n\n// Note: createNodePlatformAdapter is not exported in browser bundle to avoid Node.js dependencies\n\n// NodePlatformAdapter is available through dynamic import to avoid bundling Node.js dependencies\n// Use createNodePlatformAdapter() for dynamic import\n\n// Platform utilities - browser-safe only\nexport {\n detectPlatform,\n isPlatformSupported,\n getPlatformCapabilities,\n} from \"./platform/utils\";\n\nexport { ApiClient } from \"./core/apiClient\";\n\nexport type {\n ApiClientConfig,\n HttpMethod,\n RequestOptions,\n} from \"./core/apiClient\";\n\n// Note: Default export is already handled above with the Vana factory function\n\n// For testing purposes, we also export the implementation class\nexport { VanaBrowserImpl };\n"],"mappings":"AAKA,SAAS,8BAA8B;AACvC,SAAS,gBAAgB;AAWzB,MAAM,wBAAwB,SAAS;AAAA,EACrC,YAAY,QAAoB;AAC9B,UAAM,IAAI,uBAAuB,GAAG,MAAM;AAAA,EAC5C;AACF;AAwGO,SAAS,KAAK,QAAoB;AACvC,SAAO,IAAI,gBAAgB,MAAM;AACnC;AAWA,IAAO,wBAAQ;AAIf,SAAS,YAAAA,WAAU,uBAAuB;AAM1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,cAAc;AAGd,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,4BAA4B;AAGrC,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAWd,cAAc;AAGd,SAAS,oBAAoB,iBAAiB;AAC9C,SAAS,cAAc;AACvB;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AACP,cAAc;AAGd,SAAS,cAAc;AAIvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,0BAAAC,+BAA8B;AACvC,SAAsC,iCAA4B;AAIlE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAQP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,iBAAiB;","names":["VanaCore","BrowserPlatformAdapter"]}
|