w3pk 0.7.0 → 0.7.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/README.md +76 -19
- package/dist/index.d.mts +650 -5
- package/dist/index.d.ts +650 -5
- package/dist/index.js +776 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +776 -5
- package/dist/index.mjs.map +1 -1
- package/docs/BUNDLE_SIZES.md +7 -4
- package/docs/MIGRATION.md +15 -15
- package/docs/QR_CODE.md +1887 -0
- package/docs/RECOVERY.md +992 -0
- package/docs/SECURITY.md +631 -0
- package/docs/ZK_INTEGRATION_GUIDE.md +6 -4
- package/docs/index.html +4 -3
- package/package.json +9 -2
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/errors.ts","../src/auth/storage.ts","../src/zk/utils.ts","../src/zk/proof-generator.ts","../src/zk/proof-verifier.ts","../src/zk/index.ts","../src/auth/register.ts","../src/utils/validation.ts","../src/auth/authenticate.ts","../src/wallet/storage.ts","../src/wallet/generate.ts","../src/wallet/crypto.ts","../src/stealth/index.ts","../src/stealth/crypto.ts","../src/core/session.ts","../src/core/config.ts","../src/core/sdk.ts","../src/chainlist/index.ts","../src/eip7702/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Custom error classes for better error handling\n */\n\nexport class Web3PasskeyError extends Error {\n constructor(\n message: string,\n public code: string,\n public originalError?: unknown\n ) {\n super(message);\n this.name = \"Web3PasskeyError\";\n }\n}\n\nexport class AuthenticationError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"AUTHENTICATION_ERROR\", originalError);\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class RegistrationError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"REGISTRATION_ERROR\", originalError);\n this.name = \"RegistrationError\";\n }\n}\n\nexport class WalletError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"WALLET_ERROR\", originalError);\n this.name = \"WalletError\";\n }\n}\n\nexport class CryptoError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"CRYPTO_ERROR\", originalError);\n this.name = \"CryptoError\";\n }\n}\n\nexport class StorageError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"STORAGE_ERROR\", originalError);\n this.name = \"StorageError\";\n }\n}\n\nexport class ApiError extends Web3PasskeyError {\n constructor(\n message: string,\n public statusCode?: number,\n originalError?: unknown\n ) {\n super(message, \"API_ERROR\", originalError);\n this.name = \"ApiError\";\n }\n}\n","import { StorageError } from \"../core/errors\";\n\nconst STORAGE_KEY_PREFIX = \"w3pk_credential_\";\nconst STORAGE_INDEX_KEY = \"w3pk_credential_index\";\n\nexport interface StoredCredential {\n id: string;\n publicKey: string;\n username: string;\n ethereumAddress: string;\n createdAt: number;\n lastUsed: number;\n}\n\nexport class CredentialStorage {\n private storage: Storage;\n\n constructor(storage?: Storage) {\n if (storage) {\n this.storage = storage;\n } else if (typeof window !== \"undefined\" && window.localStorage) {\n this.storage = window.localStorage;\n } else {\n throw new StorageError(\"localStorage is not available\");\n }\n }\n\n saveCredential(credential: StoredCredential): void {\n try {\n const key = `${STORAGE_KEY_PREFIX}${credential.id}`;\n this.storage.setItem(key, JSON.stringify(credential));\n this.addToIndex(credential.id);\n } catch (error) {\n throw new StorageError(\"Failed to save credential\", error);\n }\n }\n\n getCredentialById(id: string): StoredCredential | null {\n try {\n const key = `${STORAGE_KEY_PREFIX}${id}`;\n const data = this.storage.getItem(key);\n if (!data) {\n return null;\n }\n return JSON.parse(data) as StoredCredential;\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credential\", error);\n }\n }\n\n getCredentialByUsername(username: string): StoredCredential | null {\n try {\n const credentials = this.getAllCredentials();\n return credentials.find((c) => c.username === username) || null;\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credential\", error);\n }\n }\n\n getCredentialByAddress(address: string): StoredCredential | null {\n try {\n const credentials = this.getAllCredentials();\n return (\n credentials.find(\n (c) => c.ethereumAddress.toLowerCase() === address.toLowerCase()\n ) || null\n );\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credential\", error);\n }\n }\n\n getAllCredentials(): StoredCredential[] {\n try {\n const index = this.getIndex();\n return index\n .map((id) => this.getCredentialById(id))\n .filter((c): c is StoredCredential => c !== null);\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credentials\", error);\n }\n }\n\n userExists(username: string): boolean {\n return this.getCredentialByUsername(username) !== null;\n }\n\n updateLastUsed(id: string): void {\n try {\n const credential = this.getCredentialById(id);\n if (credential) {\n credential.lastUsed = Date.now();\n this.saveCredential(credential);\n }\n } catch (error) {\n throw new StorageError(\"Failed to update timestamp\", error);\n }\n }\n\n deleteCredential(id: string): void {\n try {\n const key = `${STORAGE_KEY_PREFIX}${id}`;\n this.storage.removeItem(key);\n this.removeFromIndex(id);\n } catch (error) {\n throw new StorageError(\"Failed to delete credential\", error);\n }\n }\n\n clearAll(): void {\n try {\n const index = this.getIndex();\n index.forEach((id) => {\n const key = `${STORAGE_KEY_PREFIX}${id}`;\n this.storage.removeItem(key);\n });\n this.storage.removeItem(STORAGE_INDEX_KEY);\n } catch (error) {\n throw new StorageError(\"Failed to clear credentials\", error);\n }\n }\n\n private getIndex(): string[] {\n try {\n const data = this.storage.getItem(STORAGE_INDEX_KEY);\n return data ? JSON.parse(data) : [];\n } catch (error) {\n return [];\n }\n }\n\n private addToIndex(id: string): void {\n const index = this.getIndex();\n if (!index.includes(id)) {\n index.push(id);\n this.storage.setItem(STORAGE_INDEX_KEY, JSON.stringify(index));\n }\n }\n\n private removeFromIndex(id: string): void {\n const index = this.getIndex();\n const filtered = index.filter((credId) => credId !== id);\n this.storage.setItem(STORAGE_INDEX_KEY, JSON.stringify(filtered));\n }\n}\n","/**\n * ZK Utility Functions\n * Helper functions for zero-knowledge proof operations\n */\n\nimport { CryptoError } from \"../core/errors\";\n\n/**\n * Generate a random blinding factor for commitments\n */\nexport function generateBlinding(): bigint {\n const buffer = new Uint8Array(32);\n crypto.getRandomValues(buffer);\n return bufferToBigInt(buffer);\n}\n\n/**\n * Convert buffer to bigint\n */\nexport function bufferToBigInt(buffer: Uint8Array): bigint {\n let result = 0n;\n for (let i = 0; i < buffer.length; i++) {\n result = (result << 8n) | BigInt(buffer[i]);\n }\n return result;\n}\n\n/**\n * Convert bigint to buffer\n */\nexport function bigIntToBuffer(\n value: bigint,\n byteLength: number = 32\n): Uint8Array {\n const buffer = new Uint8Array(byteLength);\n let temp = value;\n\n for (let i = byteLength - 1; i >= 0; i--) {\n buffer[i] = Number(temp & 0xffn);\n temp = temp >> 8n;\n }\n\n return buffer;\n}\n\n/**\n * Hash a value using SHA-256\n */\nexport async function sha256Hash(data: string | Uint8Array): Promise<string> {\n try {\n const buffer =\n typeof data === \"string\" ? new TextEncoder().encode(data) : data;\n\n const hashBuffer = await crypto.subtle.digest(\n \"SHA-256\",\n buffer as BufferSource\n );\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to compute hash\", error);\n }\n}\n\n/**\n * Build a merkle tree from leaves\n */\nexport async function buildMerkleTree(leaves: string[]): Promise<{\n root: string;\n tree: string[][];\n}> {\n try {\n // @ts-ignore - Optional dependency, may not be installed\n const circomlibjs = await import(\"circomlibjs\");\n const poseidon = await circomlibjs.buildPoseidon();\n\n if (leaves.length === 0) {\n throw new Error(\"Cannot build tree from empty leaves\");\n }\n\n const tree: string[][] = [leaves];\n let currentLevel = leaves.map((leaf) => BigInt(leaf));\n\n while (currentLevel.length > 1) {\n const nextLevel: bigint[] = [];\n\n for (let i = 0; i < currentLevel.length; i += 2) {\n if (i + 1 < currentLevel.length) {\n const hashResult = poseidon([currentLevel[i], currentLevel[i + 1]]);\n \n // Convert Uint8Array result to BigInt if needed\n const hash = hashResult instanceof Uint8Array \n ? bufferToBigInt(hashResult) \n : hashResult;\n \n nextLevel.push(hash);\n } else {\n nextLevel.push(currentLevel[i]);\n }\n }\n\n tree.push(nextLevel.map((n) => n.toString()));\n currentLevel = nextLevel;\n }\n\n return {\n root: currentLevel[0].toString(),\n tree,\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Cannot resolve module\")) {\n throw new CryptoError(\n \"ZK merkle tree requires circomlibjs. Install with: npm install circomlibjs\\n\" +\n \"For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs\",\n error\n );\n }\n throw new CryptoError(\"Failed to build merkle tree\", error);\n }\n}\n\n/**\n * Generate merkle proof for a leaf\n */\nexport function generateMerkleProof(\n tree: string[][],\n leafIndex: number\n): {\n pathIndices: number[];\n pathElements: string[];\n} {\n const pathIndices: number[] = [];\n const pathElements: string[] = [];\n let currentIndex = leafIndex;\n\n for (let level = 0; level < tree.length - 1; level++) {\n const isRightNode = currentIndex % 2 === 1;\n const siblingIndex = isRightNode ? currentIndex - 1 : currentIndex + 1;\n\n pathIndices.push(isRightNode ? 1 : 0);\n\n if (siblingIndex < tree[level].length) {\n pathElements.push(tree[level][siblingIndex]);\n } else {\n pathElements.push(tree[level][currentIndex]);\n }\n\n currentIndex = Math.floor(currentIndex / 2);\n }\n\n return { pathIndices, pathElements };\n}\n\n/**\n * Validate proof inputs\n */\nexport function validateProofInputs(inputs: Record<string, any>): void {\n for (const [key, value] of Object.entries(inputs)) {\n if (value === undefined || value === null) {\n throw new CryptoError(`Missing required input: ${key}`);\n }\n }\n}\n\n/**\n * Convert hex string to bigint\n */\nexport function hexToBigInt(hex: string): bigint {\n return BigInt(hex.startsWith(\"0x\") ? hex : `0x${hex}`);\n}\n\n/**\n * Convert bigint to hex string\n */\nexport function bigIntToHex(value: bigint, padToBytes?: number): string {\n let hex = value.toString(16);\n if (padToBytes) {\n hex = hex.padStart(padToBytes * 2, \"0\");\n }\n return `0x${hex}`;\n}\n\n/**\n * Serialize ZK proof for storage or transmission\n */\nexport function serializeProof(proof: any): string {\n return JSON.stringify(proof);\n}\n\n/**\n * Deserialize ZK proof from storage or transmission\n */\nexport function deserializeProof(serialized: string): any {\n try {\n return JSON.parse(serialized);\n } catch (error) {\n throw new CryptoError(\"Failed to deserialize proof\", error);\n }\n}\n\n/**\n * Generate a random nonce for challenges\n */\nexport function generateNonce(): bigint {\n return generateBlinding();\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function isValidAddress(address: string): boolean {\n return /^0x[a-fA-F0-9]{40}$/.test(address);\n}\n\n/**\n * Build NFT holders merkle tree\n * Creates a merkle tree from a list of NFT holder addresses for a specific contract\n */\nexport async function buildNFTHoldersMerkleTree(\n holderAddresses: string[],\n contractAddress: string\n): Promise<{\n root: string;\n tree: string[][];\n holderLeaves: string[];\n}> {\n try {\n // @ts-ignore - Optional dependency, may not be installed\n const circomlibjs = await import(\"circomlibjs\");\n const poseidon = await circomlibjs.buildPoseidon();\n\n if (holderAddresses.length === 0) {\n throw new Error(\"Cannot build NFT holders tree from empty holder list\");\n }\n\n // Create leaf hashes: Hash(holderAddress, contractAddress)\n // Convert hex addresses to BigInt (remove 0x prefix first)\n const contractHash = BigInt(contractAddress.startsWith('0x') ? contractAddress : '0x' + contractAddress);\n const holderLeaves = holderAddresses.map((address) => {\n const cleanAddress = address.startsWith('0x') ? address : '0x' + address;\n const addressHash = BigInt(cleanAddress);\n const hashResult = poseidon([addressHash, contractHash]);\n \n // Convert Uint8Array result to BigInt if needed\n if (hashResult instanceof Uint8Array) {\n return bufferToBigInt(hashResult).toString();\n }\n \n return hashResult.toString();\n });\n\n // Build merkle tree from the leaves\n const { root, tree } = await buildMerkleTree(holderLeaves);\n\n return {\n root,\n tree,\n holderLeaves,\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Cannot resolve module\")) {\n throw new CryptoError(\n \"NFT holder merkle tree requires circomlibjs. Install with: npm install circomlibjs\\n\" +\n \"For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs\",\n error\n );\n }\n throw new CryptoError(\"Failed to build NFT holders merkle tree\", error);\n }\n}\n\n/**\n * Generate NFT ownership proof inputs\n * Helper to prepare all inputs needed for NFT ownership proof\n */\nexport async function generateNFTOwnershipProofInputs(\n ownerAddress: string,\n contractAddress: string,\n allHolderAddresses: string[],\n minBalance: bigint = 1n\n): Promise<{\n nftProofInput: {\n ownerAddress: string;\n holderIndex: number;\n pathIndices: number[];\n pathElements: string[];\n holdersRoot: string;\n contractAddress: string;\n minBalance: bigint;\n };\n holderLeaves: string[];\n}> {\n // Find the owner's position in the holders list\n const holderIndex = allHolderAddresses.findIndex(\n (address) => address.toLowerCase() === ownerAddress.toLowerCase()\n );\n\n if (holderIndex === -1) {\n throw new CryptoError(\n `Owner address ${ownerAddress} not found in holders list for contract ${contractAddress}`\n );\n }\n\n // Build the NFT holders merkle tree\n const { root, tree, holderLeaves } = await buildNFTHoldersMerkleTree(\n allHolderAddresses,\n contractAddress\n );\n\n // Generate merkle proof for this owner\n const { pathIndices, pathElements } = generateMerkleProof(tree, holderIndex);\n\n return {\n nftProofInput: {\n ownerAddress,\n holderIndex,\n pathIndices,\n pathElements,\n holdersRoot: root,\n contractAddress,\n minBalance,\n },\n holderLeaves,\n };\n}\n\n/**\n * Validate NFT ownership proof inputs\n */\nexport function validateNFTOwnershipProofInputs(inputs: {\n ownerAddress: string;\n contractAddress: string;\n holderIndex: number;\n pathIndices: number[];\n pathElements: string[];\n holdersRoot: string;\n minBalance?: bigint;\n}): void {\n if (!isValidAddress(inputs.ownerAddress)) {\n throw new CryptoError(`Invalid owner address: ${inputs.ownerAddress}`);\n }\n\n if (!isValidAddress(inputs.contractAddress)) {\n throw new CryptoError(`Invalid contract address: ${inputs.contractAddress}`);\n }\n\n if (inputs.holderIndex < 0 || !Number.isInteger(inputs.holderIndex)) {\n throw new CryptoError(`Invalid holder index: ${inputs.holderIndex}`);\n }\n\n if (inputs.pathIndices.length !== inputs.pathElements.length) {\n throw new CryptoError(\n `Path indices and elements length mismatch: ${inputs.pathIndices.length} vs ${inputs.pathElements.length}`\n );\n }\n\n if (inputs.pathIndices.length === 0) {\n throw new CryptoError(\"Empty merkle proof path\");\n }\n\n if (!inputs.holdersRoot || inputs.holdersRoot.length === 0) {\n throw new CryptoError(\"Invalid holders root\");\n }\n\n if (inputs.minBalance && inputs.minBalance < 1n) {\n throw new CryptoError(\"Minimum balance must be at least 1\");\n }\n}\n","/**\n * ZK Proof Generator\n * Generates zero-knowledge proofs using circom circuits\n */\n\nimport { CryptoError } from \"../core/errors\";\nimport { bufferToBigInt } from \"./utils\";\nimport type {\n ProofType,\n ZKProof,\n CircuitArtifacts,\n CircomInputs,\n MembershipProofInput,\n ThresholdProofInput,\n RangeProofInput,\n OwnershipProofInput,\n NFTOwnershipProofInput,\n} from \"./types\";\n\nexport class ZKProofGenerator {\n private circuits: Map<ProofType, CircuitArtifacts> = new Map();\n private snarkjs: any;\n\n constructor() {\n this.loadSnarkJS();\n }\n\n private async loadSnarkJS() {\n try {\n // Dynamic import for optional dependency\n this.snarkjs = await import(\"snarkjs\");\n } catch (error) {\n // Don't throw immediately - only throw when actually trying to use it\n this.snarkjs = null;\n }\n }\n\n /**\n * Register a circuit for a specific proof type\n */\n registerCircuit(type: ProofType, artifacts: CircuitArtifacts): void {\n this.circuits.set(type, artifacts);\n }\n\n /**\n * Generate membership proof - prove you're in a merkle tree set\n */\n async generateMembershipProof(input: MembershipProofInput): Promise<ZKProof> {\n const circuit = this.circuits.get(\"membership\");\n if (!circuit) {\n throw new CryptoError(\"Membership circuit not registered\");\n }\n\n const circuitInputs: CircomInputs = {\n leaf: input.value,\n pathIndices: input.pathIndices,\n pathElements: input.pathElements,\n root: input.root,\n };\n\n return this.generateProof(\"membership\", circuit, circuitInputs);\n }\n\n /**\n * Generate threshold proof - prove value > threshold\n */\n async generateThresholdProof(input: ThresholdProofInput): Promise<ZKProof> {\n const circuit = this.circuits.get(\"threshold\");\n if (!circuit) {\n throw new CryptoError(\"Threshold circuit not registered\");\n }\n\n const circuitInputs: CircomInputs = {\n value: input.value.toString(),\n blinding: input.blinding.toString(),\n threshold: input.threshold.toString(),\n commitment: input.commitment,\n };\n\n return this.generateProof(\"threshold\", circuit, circuitInputs);\n }\n\n /**\n * Generate range proof - prove min <= value <= max\n */\n async generateRangeProof(input: RangeProofInput): Promise<ZKProof> {\n const circuit = this.circuits.get(\"range\");\n if (!circuit) {\n throw new CryptoError(\"Range circuit not registered\");\n }\n\n const circuitInputs: CircomInputs = {\n value: input.value.toString(),\n blinding: input.blinding.toString(),\n min: input.min.toString(),\n max: input.max.toString(),\n commitment: input.commitment,\n };\n\n return this.generateProof(\"range\", circuit, circuitInputs);\n }\n\n /**\n * Generate ownership proof - prove you own an address\n */\n async generateOwnershipProof(input: OwnershipProofInput): Promise<ZKProof> {\n const circuit = this.circuits.get(\"ownership\");\n if (!circuit) {\n throw new CryptoError(\"Ownership circuit not registered\");\n }\n\n const circuitInputs: CircomInputs = {\n privateKey: input.privateKey,\n nonce: input.nonce.toString(),\n address: input.address,\n challenge: input.challenge,\n };\n\n return this.generateProof(\"ownership\", circuit, circuitInputs);\n }\n\n /**\n * Generate NFT ownership proof - prove you own an NFT from a collection\n */\n async generateNFTOwnershipProof(input: NFTOwnershipProofInput): Promise<ZKProof> {\n const circuit = this.circuits.get(\"nft\");\n if (!circuit) {\n throw new CryptoError(\"NFT ownership circuit not registered\");\n }\n\n // Hash the owner address and contract address for privacy\n const poseidon = await this.getPoseidonHash();\n const cleanOwnerAddress = input.ownerAddress.startsWith('0x') ? input.ownerAddress : '0x' + input.ownerAddress;\n const cleanContractAddress = input.contractAddress.startsWith('0x') ? input.contractAddress : '0x' + input.contractAddress;\n \n const ownerHashResult = poseidon([BigInt(cleanOwnerAddress)]);\n const contractHashResult = poseidon([BigInt(cleanContractAddress)]);\n \n // Convert Uint8Array results to BigInt if needed\n const ownerAddressHash = ownerHashResult instanceof Uint8Array \n ? bufferToBigInt(ownerHashResult) \n : ownerHashResult;\n const contractAddressHash = contractHashResult instanceof Uint8Array \n ? bufferToBigInt(contractHashResult) \n : contractHashResult;\n\n const circuitInputs: CircomInputs = {\n ownerAddress: ownerAddressHash.toString(),\n pathElements: input.pathElements,\n pathIndices: input.pathIndices,\n root: input.holdersRoot,\n contractAddress: contractAddressHash.toString(),\n minBalance: (input.minBalance || 1n).toString(),\n };\n\n return this.generateProof(\"nft\", circuit, circuitInputs);\n }\n\n /**\n * Core proof generation logic\n */\n private async generateProof(\n type: ProofType,\n circuit: CircuitArtifacts,\n inputs: CircomInputs\n ): Promise<ZKProof> {\n try {\n if (!this.snarkjs) {\n await this.loadSnarkJS();\n if (!this.snarkjs) {\n throw new CryptoError(\n \"ZK proofs require snarkjs. Install with: npm install snarkjs\\n\" +\n \"For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs\"\n );\n }\n }\n\n // Calculate witness\n const { proof, publicSignals } = await this.snarkjs.groth16.fullProve(\n inputs,\n circuit.wasmPath,\n circuit.zkeyPath\n );\n\n return {\n type,\n proof: {\n pi_a: proof.pi_a.map((x: any) => x.toString()),\n pi_b: proof.pi_b.map((arr: any[]) =>\n arr.map((x: any) => x.toString())\n ),\n pi_c: proof.pi_c.map((x: any) => x.toString()),\n protocol: proof.protocol || \"groth16\",\n curve: proof.curve || \"bn128\",\n },\n publicSignals: publicSignals.map((x: any) => x.toString()),\n timestamp: Date.now(),\n };\n } catch (error) {\n throw new CryptoError(\n `Failed to generate ${type} proof: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n error\n );\n }\n }\n\n /**\n * Create a Pedersen commitment: H(value, blinding)\n */\n async createCommitment(value: bigint, blinding: bigint): Promise<string> {\n try {\n // Use Poseidon hash for commitment (no snarkjs utils needed)\n const poseidon = await this.getPoseidonHash();\n const commitment = poseidon([value, blinding]);\n\n return commitment.toString();\n } catch (error) {\n throw new CryptoError(\"Failed to create commitment\", error);\n }\n }\n\n /**\n * Get Poseidon hash function\n */\n private async getPoseidonHash(): Promise<any> {\n try {\n // Dynamic import with type assertion for optional dependency\n const circomlibjs = (await import(\"circomlibjs\")) as any;\n return await circomlibjs.buildPoseidon();\n } catch (error) {\n throw new CryptoError(\n \"ZK proofs require circomlibjs. Install with: npm install circomlibjs\\n\" +\n \"For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs\",\n error\n );\n }\n }\n\n /**\n * Compute merkle root from leaf and proof\n */\n async computeMerkleRoot(\n leaf: string,\n pathIndices: number[],\n pathElements: string[]\n ): Promise<string> {\n try {\n const poseidon = await this.getPoseidonHash();\n let current = BigInt(leaf);\n\n for (let i = 0; i < pathElements.length; i++) {\n const sibling = BigInt(pathElements[i]);\n const index = pathIndices[i];\n\n if (index === 0) {\n current = poseidon([current, sibling]);\n } else {\n current = poseidon([sibling, current]);\n }\n }\n\n return current.toString();\n } catch (error) {\n throw new CryptoError(\"Failed to compute merkle root\", error);\n }\n }\n}\n","/**\n * ZK Proof Verifier\n * Verifies zero-knowledge proofs using verification keys\n */\n\nimport { CryptoError } from \"../core/errors\";\nimport { bufferToBigInt } from \"./utils\";\nimport type {\n ProofType,\n ZKProof,\n VerificationResult,\n CircuitArtifacts,\n} from \"./types\";\n\nexport class ZKProofVerifier {\n private circuits: Map<ProofType, CircuitArtifacts> = new Map();\n private snarkjs: any;\n\n constructor() {\n this.loadSnarkJS();\n }\n\n private async loadSnarkJS() {\n try {\n this.snarkjs = await import(\"snarkjs\");\n } catch (error) {\n // Don't throw immediately - only throw when actually trying to use it\n this.snarkjs = null;\n }\n }\n\n /**\n * Register a circuit's verification key\n */\n registerCircuit(type: ProofType, artifacts: CircuitArtifacts): void {\n this.circuits.set(type, artifacts);\n }\n\n /**\n * Verify any ZK proof\n */\n async verifyProof(proof: ZKProof): Promise<VerificationResult> {\n try {\n const circuit = this.circuits.get(proof.type);\n if (!circuit) {\n throw new CryptoError(`Circuit not registered for type: ${proof.type}`);\n }\n\n if (!this.snarkjs) {\n await this.loadSnarkJS();\n if (!this.snarkjs) {\n throw new CryptoError(\n \"ZK proof verification requires snarkjs. Install with: npm install snarkjs\\n\" +\n \"For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs\"\n );\n }\n }\n\n // Verify the proof\n const isValid = await this.snarkjs.groth16.verify(\n circuit.verificationKey,\n proof.publicSignals,\n proof.proof\n );\n\n return {\n valid: isValid,\n type: proof.type,\n publicSignals: this.parsePublicSignals(proof.type, proof.publicSignals),\n timestamp: proof.timestamp,\n };\n } catch (error) {\n throw new CryptoError(\n `Proof verification failed: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n error\n );\n }\n }\n\n /**\n * Batch verify multiple proofs efficiently\n */\n async verifyBatch(proofs: ZKProof[]): Promise<VerificationResult[]> {\n const results = await Promise.all(\n proofs.map((proof) => this.verifyProof(proof))\n );\n return results;\n }\n\n /**\n * Verify membership proof\n */\n async verifyMembershipProof(\n proof: ZKProof,\n expectedRoot: string\n ): Promise<boolean> {\n if (proof.type !== \"membership\") {\n throw new CryptoError(\"Invalid proof type for membership verification\");\n }\n\n const result = await this.verifyProof(proof);\n\n // Check that the public root matches expected\n const publicRoot = proof.publicSignals[0];\n return result.valid && publicRoot === expectedRoot;\n }\n\n /**\n * Verify threshold proof\n */\n async verifyThresholdProof(\n proof: ZKProof,\n expectedCommitment: string,\n expectedThreshold: bigint\n ): Promise<boolean> {\n if (proof.type !== \"threshold\") {\n throw new CryptoError(\"Invalid proof type for threshold verification\");\n }\n\n const result = await this.verifyProof(proof);\n\n // Check public inputs match\n const publicCommitment = proof.publicSignals[0];\n const publicThreshold = BigInt(proof.publicSignals[1]);\n\n return (\n result.valid &&\n publicCommitment === expectedCommitment &&\n publicThreshold === expectedThreshold\n );\n }\n\n /**\n * Verify range proof\n */\n async verifyRangeProof(\n proof: ZKProof,\n expectedCommitment: string,\n expectedMin: bigint,\n expectedMax: bigint\n ): Promise<boolean> {\n if (proof.type !== \"range\") {\n throw new CryptoError(\"Invalid proof type for range verification\");\n }\n\n const result = await this.verifyProof(proof);\n\n const publicCommitment = proof.publicSignals[0];\n const publicMin = BigInt(proof.publicSignals[1]);\n const publicMax = BigInt(proof.publicSignals[2]);\n\n return (\n result.valid &&\n publicCommitment === expectedCommitment &&\n publicMin === expectedMin &&\n publicMax === expectedMax\n );\n }\n\n /**\n * Verify ownership proof\n */\n async verifyOwnershipProof(\n proof: ZKProof,\n expectedAddress: string,\n expectedChallenge: string\n ): Promise<boolean> {\n if (proof.type !== \"ownership\") {\n throw new CryptoError(\"Invalid proof type for ownership verification\");\n }\n\n const result = await this.verifyProof(proof);\n\n const publicAddress = proof.publicSignals[0];\n const publicChallenge = proof.publicSignals[1];\n\n return (\n result.valid &&\n publicAddress.toLowerCase() === expectedAddress.toLowerCase() &&\n publicChallenge === expectedChallenge\n );\n }\n\n /**\n * Verify NFT ownership proof with expected contract and holders root\n */\n async verifyNFTOwnershipProof(\n proof: ZKProof,\n expectedContract: string,\n expectedHoldersRoot: string,\n expectedMinBalance: bigint = 1n\n ): Promise<boolean> {\n if (proof.type !== \"nft\") {\n throw new CryptoError(\"Invalid proof type for NFT ownership verification\");\n }\n\n const result = await this.verifyProof(proof);\n const holdersRoot = proof.publicSignals[0];\n const contractAddress = proof.publicSignals[1];\n const minBalance = BigInt(proof.publicSignals[2]);\n\n // Hash the expected contract address for comparison\n try {\n const circomlibjs = await import(\"circomlibjs\");\n const poseidon = await circomlibjs.buildPoseidon();\n const cleanContract = expectedContract.startsWith('0x') ? expectedContract : '0x' + expectedContract;\n const hashResult = poseidon([BigInt(cleanContract)]);\n \n // Convert Uint8Array result to BigInt if needed\n const expectedContractHash = hashResult instanceof Uint8Array \n ? bufferToBigInt(hashResult) \n : hashResult;\n\n return (\n result.valid &&\n holdersRoot === expectedHoldersRoot &&\n contractAddress === expectedContractHash.toString() &&\n minBalance >= expectedMinBalance\n );\n } catch (error) {\n throw new CryptoError(\n \"ZK proof verification requires circomlibjs. Install with: npm install circomlibjs\\n\" +\n \"For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs\",\n error\n );\n }\n }\n\n /**\n * Parse public signals based on proof type\n */\n private parsePublicSignals(\n type: ProofType,\n signals: string[]\n ): Record<string, any> {\n switch (type) {\n case \"membership\":\n return { root: signals[0] };\n\n case \"threshold\":\n return {\n commitment: signals[0],\n threshold: signals[1],\n };\n\n case \"range\":\n return {\n commitment: signals[0],\n min: signals[1],\n max: signals[2],\n };\n\n case \"ownership\":\n return {\n address: signals[0],\n challenge: signals[1],\n };\n\n case \"nft\":\n return {\n holdersRoot: signals[0],\n contractAddress: signals[1],\n minBalance: signals[2],\n nullifierHash: signals[3],\n };\n\n default:\n return signals.reduce((acc, signal, idx) => {\n acc[`signal_${idx}`] = signal;\n return acc;\n }, {} as Record<string, any>);\n }\n }\n\n /**\n * Check if proof is expired (optional time validation)\n */\n isProofExpired(proof: ZKProof, maxAgeMs: number = 3600000): boolean {\n const age = Date.now() - proof.timestamp;\n return age > maxAgeMs;\n }\n}\n","/**\n * Zero-Knowledge Proof Module for w3pk SDK\n * Enables privacy-preserving proofs\n */\n\nimport { Web3PasskeyError } from \"../core/errors\";\nimport { ZKProofGenerator } from \"./proof-generator\";\nimport { ZKProofVerifier } from \"./proof-verifier\";\nimport type {\n ZKProofConfig,\n ProofType,\n ZKProof,\n VerificationResult,\n MembershipProofInput,\n ThresholdProofInput,\n RangeProofInput,\n OwnershipProofInput,\n NFTOwnershipProofInput,\n CircuitArtifacts,\n} from \"./types\";\n\nexport class ZKProofModule {\n private generator: ZKProofGenerator;\n private verifier: ZKProofVerifier;\n private config: ZKProofConfig;\n\n constructor(config: ZKProofConfig = {}) {\n this.config = config;\n this.generator = new ZKProofGenerator();\n this.verifier = new ZKProofVerifier();\n this.initializeCircuits();\n }\n\n private async initializeCircuits() {\n // Circuits can be registered dynamically as needed\n // In production, these would point to actual compiled circuit artifacts\n }\n\n // ========================================\n // Proof Generation\n // ========================================\n\n /**\n * Generate membership proof - prove you're in a set without revealing identity\n * Use case: Prove you're a verified user without revealing which one\n */\n async proveMembership(input: MembershipProofInput): Promise<ZKProof> {\n try {\n this.assertProofEnabled(\"membership\");\n return await this.generator.generateMembershipProof(input);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate membership proof\",\n \"ZK_MEMBERSHIP_ERROR\",\n error\n );\n }\n }\n\n /**\n * Generate threshold proof - prove value exceeds threshold\n * Use case: Prove balance > $1000 without revealing actual balance\n */\n async proveThreshold(input: ThresholdProofInput): Promise<ZKProof> {\n try {\n this.assertProofEnabled(\"threshold\");\n return await this.generator.generateThresholdProof(input);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate threshold proof\",\n \"ZK_THRESHOLD_ERROR\",\n error\n );\n }\n }\n\n /**\n * Generate range proof - prove value is within range\n * Use case: Prove age between 18-65 without revealing exact age\n */\n async proveRange(input: RangeProofInput): Promise<ZKProof> {\n try {\n this.assertProofEnabled(\"range\");\n return await this.generator.generateRangeProof(input);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate range proof\",\n \"ZK_RANGE_ERROR\",\n error\n );\n }\n }\n\n /**\n * Generate ownership proof - prove you own an address\n * Use case: Prove ownership without revealing private key\n */\n async proveOwnership(input: OwnershipProofInput): Promise<ZKProof> {\n try {\n this.assertProofEnabled(\"ownership\");\n return await this.generator.generateOwnershipProof(input);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate ownership proof\",\n \"ZK_OWNERSHIP_ERROR\",\n error\n );\n }\n }\n\n /**\n * Generate NFT ownership proof - prove you own an NFT from a collection\n * Use case: Prove NFT/SBT ownership without revealing which NFT or exact address\n */\n async proveNFTOwnership(input: NFTOwnershipProofInput): Promise<ZKProof> {\n try {\n this.assertProofEnabled(\"nft\");\n return await this.generator.generateNFTOwnershipProof(input);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate NFT ownership proof\",\n \"ZK_NFT_OWNERSHIP_ERROR\",\n error\n );\n }\n }\n\n // ========================================\n // Proof Verification\n // ========================================\n\n /**\n * Verify any ZK proof\n */\n async verify(proof: ZKProof): Promise<VerificationResult> {\n try {\n return await this.verifier.verifyProof(proof);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify proof\",\n \"ZK_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Batch verify multiple proofs\n */\n async verifyBatch(proofs: ZKProof[]): Promise<VerificationResult[]> {\n try {\n return await this.verifier.verifyBatch(proofs);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify proofs\",\n \"ZK_BATCH_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Verify membership proof with expected root\n */\n async verifyMembership(\n proof: ZKProof,\n expectedRoot: string\n ): Promise<boolean> {\n try {\n return await this.verifier.verifyMembershipProof(proof, expectedRoot);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify membership proof\",\n \"ZK_MEMBERSHIP_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Verify threshold proof\n */\n async verifyThreshold(\n proof: ZKProof,\n expectedCommitment: string,\n expectedThreshold: bigint\n ): Promise<boolean> {\n try {\n return await this.verifier.verifyThresholdProof(\n proof,\n expectedCommitment,\n expectedThreshold\n );\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify threshold proof\",\n \"ZK_THRESHOLD_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Verify range proof\n */\n async verifyRange(\n proof: ZKProof,\n expectedCommitment: string,\n expectedMin: bigint,\n expectedMax: bigint\n ): Promise<boolean> {\n try {\n return await this.verifier.verifyRangeProof(\n proof,\n expectedCommitment,\n expectedMin,\n expectedMax\n );\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify range proof\",\n \"ZK_RANGE_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Verify ownership proof\n */\n async verifyOwnership(\n proof: ZKProof,\n expectedAddress: string,\n expectedChallenge: string\n ): Promise<boolean> {\n try {\n return await this.verifier.verifyOwnershipProof(\n proof,\n expectedAddress,\n expectedChallenge\n );\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify ownership proof\",\n \"ZK_OWNERSHIP_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Verify NFT ownership proof\n */\n async verifyNFTOwnership(\n proof: ZKProof,\n expectedContract: string,\n expectedHoldersRoot: string,\n expectedMinBalance: bigint = 1n\n ): Promise<boolean> {\n try {\n return await this.verifier.verifyNFTOwnershipProof(\n proof,\n expectedContract,\n expectedHoldersRoot,\n expectedMinBalance\n );\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to verify NFT ownership proof\",\n \"ZK_NFT_OWNERSHIP_VERIFICATION_ERROR\",\n error\n );\n }\n }\n\n // ========================================\n // Utility Methods\n // ========================================\n\n /**\n * Create a Pedersen commitment for hiding values\n */\n async createCommitment(value: bigint, blinding: bigint): Promise<string> {\n try {\n return await this.generator.createCommitment(value, blinding);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to create commitment\",\n \"ZK_COMMITMENT_ERROR\",\n error\n );\n }\n }\n\n /**\n * Compute merkle root for membership proofs\n */\n async computeMerkleRoot(\n leaf: string,\n pathIndices: number[],\n pathElements: string[]\n ): Promise<string> {\n try {\n return await this.generator.computeMerkleRoot(\n leaf,\n pathIndices,\n pathElements\n );\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to compute merkle root\",\n \"ZK_MERKLE_ERROR\",\n error\n );\n }\n }\n\n /**\n * Register a custom circuit\n */\n registerCircuit(type: ProofType, artifacts: CircuitArtifacts): void {\n this.generator.registerCircuit(type, artifacts);\n this.verifier.registerCircuit(type, artifacts);\n }\n\n /**\n * Check if proof type is enabled\n */\n private assertProofEnabled(type: ProofType): void {\n if (\n this.config.enabledProofs &&\n !this.config.enabledProofs.includes(type)\n ) {\n throw new Web3PasskeyError(\n `Proof type '${type}' is not enabled`,\n \"ZK_PROOF_DISABLED\"\n );\n }\n }\n\n /**\n * Check if ZK proofs are available\n */\n get isAvailable(): boolean {\n return true;\n }\n}\n\n// Export types\nexport type {\n ZKProofConfig,\n ProofType,\n ZKProof,\n VerificationResult,\n MembershipProofInput,\n ThresholdProofInput,\n RangeProofInput,\n OwnershipProofInput,\n NFTOwnershipProofInput,\n CircuitArtifacts,\n};\n","import { startRegistration } from \"@simplewebauthn/browser\";\nimport { RegistrationError } from \"../core/errors\";\nimport { assertUsername, assertEthereumAddress } from \"../utils/validation\";\nimport type { RegisterOptions } from \"./types\";\nimport { CredentialStorage } from \"./storage\";\n\nfunction generateChallenge(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return btoa(String.fromCharCode(...array))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\n\nexport async function register(options: RegisterOptions): Promise<{ signature: ArrayBuffer }> {\n try {\n const { username, ethereumAddress } = options;\n\n assertUsername(username);\n assertEthereumAddress(ethereumAddress);\n\n const storage = new CredentialStorage();\n\n if (storage.userExists(username)) {\n throw new Error(\"Username already registered\");\n }\n\n const challenge = generateChallenge();\n\n const registrationOptions = {\n challenge,\n rp: {\n name: \"w3pk\",\n id: window.location.hostname,\n },\n user: {\n id: username,\n name: username,\n displayName: username,\n },\n pubKeyCredParams: [\n { type: \"public-key\" as const, alg: -7 },\n { type: \"public-key\" as const, alg: -257 },\n ],\n authenticatorSelection: {\n authenticatorAttachment: \"platform\" as const,\n userVerification: \"required\" as const,\n residentKey: \"required\" as const,\n requireResidentKey: true,\n },\n timeout: 60000,\n attestation: \"none\" as const,\n };\n\n const credential = await startRegistration({\n optionsJSON: registrationOptions,\n });\n const publicKey = credential.response.publicKey;\n\n if (!publicKey) {\n throw new Error(\"Public key not returned from authenticator\");\n }\n\n storage.saveCredential({\n id: credential.id,\n publicKey,\n username,\n ethereumAddress,\n createdAt: Date.now(),\n lastUsed: Date.now(),\n });\n\n // Extract attestation signature for wallet encryption\n // The attestationObject contains the authenticator's signature\n console.log(\"[register] Credential response:\", credential.response);\n const attestationObject = credential.response.attestationObject;\n console.log(\"[register] Attestation object:\", attestationObject);\n\n if (!attestationObject) {\n throw new Error(\"Attestation object not returned from authenticator\");\n }\n\n // Decode the attestationObject (it's base64url encoded CBOR)\n const attestationBuffer = base64ToArrayBuffer(attestationObject);\n console.log(\"[register] Attestation buffer length:\", attestationBuffer.byteLength);\n\n // For now, we'll use the raw attestation data as our signature material\n // This is cryptographically signed by the authenticator during registration\n return { signature: attestationBuffer };\n } catch (error) {\n throw new RegistrationError(\n error instanceof Error ? error.message : \"Registration failed\",\n error\n );\n }\n}\n\nfunction base64ToArrayBuffer(base64: string): ArrayBuffer {\n const base64Clean = base64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64Clean);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n","/**\n * Input validation utilities\n */\n\nexport function validateEthereumAddress(address: string): boolean {\n return /^0x[a-fA-F0-9]{40}$/.test(address);\n}\n\nexport function validateUsername(username: string): boolean {\n return username.length >= 3 && username.length <= 50;\n}\n\nexport function validateMnemonic(mnemonic: string): boolean {\n const words = mnemonic.trim().split(/\\s+/);\n return words.length === 12 || words.length === 24;\n}\n\nexport function assertEthereumAddress(address: string): void {\n if (!validateEthereumAddress(address)) {\n throw new Error(\"Invalid Ethereum address format\");\n }\n}\n\nexport function assertUsername(username: string): void {\n if (!validateUsername(username)) {\n throw new Error(\"Username must be between 3 and 50 characters\");\n }\n}\n\nexport function assertMnemonic(mnemonic: string): void {\n if (!validateMnemonic(mnemonic)) {\n throw new Error(\"Invalid mnemonic: must be 12 or 24 words\");\n }\n}\n","import { startAuthentication } from \"@simplewebauthn/browser\";\nimport { AuthenticationError } from \"../core/errors\";\nimport type { AuthResult } from \"./types\";\nimport type { StoredCredential } from \"./storage\";\nimport { CredentialStorage } from \"./storage\";\n\nfunction generateChallenge(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return btoa(String.fromCharCode(...array))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\nexport async function login(): Promise<AuthResult> {\n try {\n const storage = new CredentialStorage();\n const challenge = generateChallenge();\n\n const authOptions = {\n challenge,\n rpId: window.location.hostname,\n userVerification: \"required\" as const,\n timeout: 60000,\n };\n\n const assertion = await startAuthentication({\n optionsJSON: authOptions,\n });\n\n const credential = storage.getCredentialById(assertion.id);\n\n if (!credential) {\n throw new Error(\"Credential not found\");\n }\n\n const isValid = await verifyAssertion(assertion, credential);\n\n if (!isValid) {\n throw new Error(\"Signature verification failed\");\n }\n\n storage.updateLastUsed(credential.id);\n\n // SECURITY: Return the signature so it can be used to derive encryption keys\n // The signature can ONLY be obtained through biometric/PIN authentication\n const signatureBuffer = base64ToArrayBuffer(assertion.response.signature);\n\n return {\n verified: true,\n user: {\n username: credential.username,\n ethereumAddress: credential.ethereumAddress,\n credentialId: credential.id,\n },\n signature: signatureBuffer,\n };\n } catch (error) {\n throw new AuthenticationError(\n error instanceof Error ? error.message : \"Authentication failed\",\n error\n );\n }\n}\n\nasync function verifyAssertion(\n assertion: any,\n credential: StoredCredential\n): Promise<boolean> {\n try {\n const publicKeyBuffer = base64ToArrayBuffer(credential.publicKey);\n const publicKey = await crypto.subtle.importKey(\n \"spki\",\n publicKeyBuffer,\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n },\n false,\n [\"verify\"]\n );\n\n const authenticatorData = base64ToArrayBuffer(\n assertion.response.authenticatorData\n );\n\n // clientDataJSON comes as base64url string, need to decode it first\n const clientDataJSON = assertion.response.clientDataJSON;\n let clientDataJSONString: string;\n\n // Check if it's already a JSON string or base64url encoded\n if (clientDataJSON.startsWith('eyJ')) {\n // It's base64url encoded, decode it\n const decoded = atob(clientDataJSON.replace(/-/g, '+').replace(/_/g, '/'));\n clientDataJSONString = decoded;\n } else {\n // It's already a JSON string\n clientDataJSONString = clientDataJSON;\n }\n\n const clientDataHash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(clientDataJSONString)\n );\n\n const signedData = new Uint8Array(\n authenticatorData.byteLength + clientDataHash.byteLength\n );\n signedData.set(new Uint8Array(authenticatorData), 0);\n signedData.set(\n new Uint8Array(clientDataHash),\n authenticatorData.byteLength\n );\n\n const signature = base64ToArrayBuffer(assertion.response.signature);\n const rawSignature = derToRaw(new Uint8Array(signature));\n\n const isValid = await crypto.subtle.verify(\n {\n name: \"ECDSA\",\n hash: \"SHA-256\",\n },\n publicKey,\n rawSignature,\n signedData\n );\n\n return isValid;\n } catch (error) {\n console.error(\"Signature verification error:\", error);\n return false;\n }\n}\n\nfunction base64ToArrayBuffer(base64: string): ArrayBuffer {\n const base64Clean = base64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64Clean);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nfunction derToRaw(der: Uint8Array): ArrayBuffer {\n let offset = 2;\n\n offset++;\n let rLength = der[offset++];\n if (rLength > 32) {\n offset++;\n rLength--;\n }\n const r = der.slice(offset, offset + rLength);\n offset += rLength;\n\n offset++;\n let sLength = der[offset++];\n if (sLength > 32) {\n offset++;\n sLength--;\n }\n const s = der.slice(offset, offset + sLength);\n\n const raw = new Uint8Array(64);\n raw.set(r, 32 - r.length);\n raw.set(s, 64 - s.length);\n\n return raw.buffer;\n}\n","/**\n * IndexedDB storage for encrypted wallet data\n */\n\nimport { StorageError } from \"../core/errors\";\nimport type { EncryptedWalletData, WalletStorage } from \"./types\";\n\nconst DB_NAME = \"Web3PasskeyWallet\";\nconst DB_VERSION = 1;\nconst STORE_NAME = \"wallets\";\n\nexport class IndexedDBWalletStorage implements WalletStorage {\n private db: IDBDatabase | null = null;\n\n async init(): Promise<void> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n\n request.onerror = () =>\n reject(new StorageError(\"Failed to open database\", request.error));\n\n request.onsuccess = () => {\n this.db = request.result;\n resolve();\n };\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: \"ethereumAddress\" });\n }\n };\n });\n }\n\n async store(data: EncryptedWalletData): Promise<void> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readwrite\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.put(data);\n request.onerror = () =>\n reject(new StorageError(\"Failed to store wallet data\", request.error));\n request.onsuccess = () => resolve();\n });\n }\n\n async retrieve(ethereumAddress: string): Promise<EncryptedWalletData | null> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readonly\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.get(ethereumAddress);\n request.onerror = () =>\n reject(\n new StorageError(\"Failed to retrieve wallet data\", request.error)\n );\n request.onsuccess = () => resolve(request.result || null);\n });\n }\n\n async delete(ethereumAddress: string): Promise<void> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readwrite\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.delete(ethereumAddress);\n request.onerror = () =>\n reject(new StorageError(\"Failed to delete wallet data\", request.error));\n request.onsuccess = () => resolve();\n });\n }\n\n async clear(): Promise<void> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readwrite\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.clear();\n request.onerror = () =>\n reject(new StorageError(\"Failed to clear wallet data\", request.error));\n request.onsuccess = () => resolve();\n });\n }\n}\n","/**\n * BIP39 wallet generation\n */\n\nimport { ethers } from \"ethers\";\nimport { WalletError } from \"../core/errors\";\nimport type { WalletData } from \"./types\";\n\n/**\n * Generates a new BIP39 wallet with HD derivation\n * Uses BIP44 path: m/44'/60'/0'/0/0 for Ethereum\n */\nexport function generateBIP39Wallet(): WalletData {\n try {\n // Generate random mnemonic using ethers' utility\n const mnemonic = ethers.Wallet.createRandom().mnemonic;\n\n if (!mnemonic) {\n throw new Error(\"Failed to generate mnemonic\");\n }\n\n const mnemonicPhrase = mnemonic.phrase;\n\n // Create HD wallet from mnemonic phrase with derivation path\n const derivationPath = \"m/44'/60'/0'/0/0\";\n const hdWallet = ethers.HDNodeWallet.fromPhrase(\n mnemonicPhrase,\n undefined,\n derivationPath\n );\n\n return {\n address: hdWallet.address,\n mnemonic: mnemonicPhrase,\n };\n } catch (error) {\n throw new WalletError(\"Wallet generation failed\", error);\n }\n}\n\n/**\n * Creates wallet from mnemonic phrase\n * Uses BIP44 path: m/44'/60'/0'/0/0\n */\nexport function createWalletFromMnemonic(\n mnemonic: string\n): ethers.HDNodeWallet {\n try {\n if (!mnemonic || mnemonic.trim().split(/\\s+/).length < 12) {\n throw new Error(\"Invalid mnemonic: must be at least 12 words\");\n }\n\n // Create HD wallet with derivation path directly\n const derivationPath = \"m/44'/60'/0'/0/0\";\n const wallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic.trim(),\n undefined,\n derivationPath\n );\n\n return wallet;\n } catch (error) {\n throw new WalletError(\n `Wallet creation failed: ${\n error instanceof Error ? error.message : \"Invalid mnemonic\"\n }`,\n error\n );\n }\n}\n\n/**\n * Derives HD wallet address and private key at specific index\n * Uses BIP44 path: m/44'/60'/0'/0/{index}\n */\nexport function deriveWalletFromMnemonic(\n mnemonic: string,\n index: number = 0\n): { address: string; privateKey: string } {\n try {\n if (!mnemonic || mnemonic.trim().split(/\\s+/).length < 12) {\n throw new Error(\"Invalid mnemonic: must be at least 12 words\");\n }\n\n if (index < 0 || !Number.isInteger(index)) {\n throw new Error(\"Index must be a non-negative integer\");\n }\n\n // Create HD wallet with derivation path including index\n const derivationPath = `m/44'/60'/0'/0/${index}`;\n const wallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic.trim(),\n undefined,\n derivationPath\n );\n\n return {\n address: wallet.address,\n privateKey: wallet.privateKey,\n };\n } catch (error) {\n throw new WalletError(\n `HD wallet derivation failed: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n error\n );\n }\n}\n","/**\n * Cryptographic utilities for wallet encryption\n *\n * SECURITY: Encryption keys are derived from WebAuthn signatures of a fixed message.\n * This requires biometric/PIN authentication and provides true hardware-backed security.\n * Even with file system access, an attacker cannot decrypt without biometric authentication.\n */\n\nimport { CryptoError } from \"../core/errors\";\n\n/**\n * Fixed message used for deterministic signature generation\n * This ensures the same signature is produced every time for encryption/decryption\n */\nconst ENCRYPTION_MESSAGE = \"w3pk-wallet-encryption-v3\";\n\n/**\n * Converts base64url string to ArrayBuffer\n */\nfunction base64UrlToArrayBuffer(base64url: string): ArrayBuffer {\n const base64 = base64url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * Derives an encryption key from WebAuthn credential (RECOMMENDED)\n *\n * SECURITY: This provides authentication-gated encryption:\n * - Requires biometric/PIN to prove identity before decryption\n * - Uses credential ID + public key as deterministic key material\n * - WebAuthn authentication verifies user identity\n * - Session caching prevents repeated prompts (1 hour default)\n *\n * IMPORTANT: This is authentication-gated, not signature-encrypted.\n * An attacker with both localStorage AND IndexedDB access could decrypt,\n * BUT WebAuthn authentication is still required before SDK allows access.\n *\n * For stronger security at rest, consider server-based architecture.\n *\n * BROWSER SUPPORT:\n * ✅ Chrome 67+, Edge 18+, Firefox 60+, Safari 14+\n * ✅ iOS 14.5+, Android 9+\n * ❌ Older browsers/devices - will throw NotSupportedError\n *\n * @param credentialId - The credential ID (base64url encoded)\n * @param publicKey - The public key (base64url encoded, optional)\n * @returns Encryption key derived from credential metadata\n * @throws CryptoError if derivation fails\n */\nexport async function deriveEncryptionKeyFromWebAuthn(\n credentialId: string,\n publicKey?: string\n): Promise<CryptoKey> {\n try {\n // Use credential ID + public key as deterministic key material\n // This is the same every time for a given credential\n const keyMaterial = publicKey\n ? `w3pk-v4:${credentialId}:${publicKey}`\n : `w3pk-v4:${credentialId}`;\n\n const keyMaterialHash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(keyMaterial)\n );\n\n const importedKey = await crypto.subtle.importKey(\n \"raw\",\n keyMaterialHash,\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"]\n );\n\n // Use a fixed salt for deterministic derivation\n const salt = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(\"w3pk-salt-v4\")\n );\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: new Uint8Array(salt),\n iterations: 210000, // OWASP 2023 recommendation\n hash: \"SHA-256\",\n },\n importedKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n } catch (error: any) {\n throw new CryptoError(\"Failed to derive encryption key from WebAuthn\", error);\n }\n}\n\n/**\n * Derives an encryption key from credential ID (FALLBACK - WEAKER SECURITY)\n *\n * WARNING: This method does NOT require biometric authentication for decryption.\n * An attacker with file system access can decrypt the wallet.\n * Use only as fallback for unsupported platforms.\n *\n * @param credentialId - Unique credential identifier\n * @param publicKey - Public key from the credential (optional, for additional entropy)\n * @deprecated Use deriveEncryptionKeyFromWebAuthn for true biometric protection\n */\nexport async function deriveEncryptionKey(\n credentialId: string,\n publicKey?: string\n): Promise<CryptoKey> {\n try {\n // Create deterministic key material from credential ID and optional public key\n const keyMaterial = publicKey\n ? `w3pk-v2:${credentialId}:${publicKey}`\n : `w3pk-v2:${credentialId}`;\n\n const keyMaterialHash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(keyMaterial)\n );\n\n // Import as key material\n const importedKey = await crypto.subtle.importKey(\n \"raw\",\n keyMaterialHash,\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"]\n );\n\n // Use a fixed salt for deterministic derivation\n const salt = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(\"w3pk-salt-v2\")\n );\n\n // Derive the actual encryption key with strong parameters\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: new Uint8Array(salt),\n iterations: 210000, // OWASP 2023 recommendation\n hash: \"SHA-256\",\n },\n importedKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n } catch (error) {\n throw new CryptoError(\"Failed to derive encryption key\", error);\n }\n}\n\n/**\n * Derives encryption key from a raw signature (for testing/legacy)\n *\n * WARNING: This is a fallback method that doesn't require WebAuthn.\n * Use deriveEncryptionKeyFromWebAuthn in production for true biometric protection.\n *\n * @param signature - Raw signature bytes\n * @param credentialId - Credential ID for salt\n */\nexport async function deriveEncryptionKeyFromSignature(\n signature: ArrayBuffer,\n credentialId: string\n): Promise<CryptoKey> {\n try {\n // Try WebAuthn first if available\n if (typeof window !== 'undefined' && window.PublicKeyCredential) {\n return deriveEncryptionKeyFromWebAuthn(credentialId);\n }\n\n // Fallback: Derive from provided signature (for testing/Node.js)\n const signatureHash = await crypto.subtle.digest(\"SHA-256\", signature);\n\n const importedKey = await crypto.subtle.importKey(\n \"raw\",\n signatureHash,\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"]\n );\n\n const salt = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(\"w3pk-salt-v3:\" + credentialId)\n );\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: new Uint8Array(salt),\n iterations: 210000,\n hash: \"SHA-256\",\n },\n importedKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n } catch (error) {\n throw new CryptoError(\"Failed to derive encryption key\", error);\n }\n}\n\n/**\n * Generates a cryptographic challenge for WebAuthn authentication\n */\nexport function generateChallenge(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return btoa(String.fromCharCode(...array))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\n/**\n * Encrypts data using AES-GCM\n */\nexport async function encryptData(\n data: string,\n key: CryptoKey\n): Promise<string> {\n try {\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const encodedData = new TextEncoder().encode(data);\n\n const encrypted = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n encodedData\n );\n\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return btoa(String.fromCharCode(...combined));\n } catch (error) {\n throw new CryptoError(\"Failed to encrypt data\", error);\n }\n}\n\n/**\n * Decrypts data using AES-GCM\n */\nexport async function decryptData(\n encryptedData: string,\n key: CryptoKey\n): Promise<string> {\n try {\n if (!encryptedData || encryptedData.length < 16) {\n throw new Error(\"Invalid encrypted data: too small\");\n }\n\n const combined = new Uint8Array(\n atob(encryptedData)\n .split(\"\")\n .map((char) => char.charCodeAt(0))\n );\n\n if (combined.length < 12) {\n throw new Error(\"Invalid encrypted data: missing IV\");\n }\n\n const iv = combined.slice(0, 12);\n const encrypted = combined.slice(12);\n\n if (encrypted.length === 0) {\n throw new Error(\"Invalid encrypted data: no content\");\n }\n\n const decrypted = await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv },\n key,\n encrypted\n );\n\n return new TextDecoder().decode(decrypted);\n } catch (error) {\n throw new CryptoError(\n `Data decryption failed: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n error\n );\n }\n}\n","/**\n * ERC-5564 Stealth Address Module for w3pk SDK\n * Provides privacy-preserving stealth address generation capabilities\n * following the ERC-5564 standard\n *\n * @see https://eips.ethereum.org/EIPS/eip-5564\n */\n\nimport { ethers } from \"ethers\";\nimport { Web3PasskeyError } from \"../core/errors\";\nimport {\n deriveStealthKeys,\n generateStealthAddress as generateERC5564StealthAddress,\n checkStealthAddress,\n computeStealthPrivateKey,\n type ParseResult\n} from \"./crypto\";\nimport type { StealthKeys, StealthAddressResult as CryptoStealthResult } from \"./crypto\";\n\nexport interface StealthAddressConfig {\n // Network-agnostic - no provider needed\n}\n\n/**\n * ERC-5564 Stealth Address Generation Result\n */\nexport interface StealthAddressResult {\n /** The generated stealth address where funds should be sent */\n stealthAddress: string;\n /** Ephemeral public key (to be published on-chain) */\n ephemeralPublicKey: string;\n /** View tag (1 byte) for efficient scanning */\n viewTag: string;\n /** @deprecated Legacy field - sender doesn't get the private key in ERC-5564 */\n stealthPrivateKey?: string;\n}\n\n/**\n * ERC-5564 Announcement (what gets published on-chain)\n */\nexport interface Announcement {\n /** The stealth address that received funds */\n stealthAddress: string;\n /** Ephemeral public key used for generation */\n ephemeralPublicKey: string;\n /** View tag for efficient filtering */\n viewTag: string;\n}\n\n/**\n * Result of parsing/checking announcements\n */\nexport interface ParseAnnouncementResult {\n /** Whether this announcement is for the user */\n isForUser: boolean;\n /** The stealth address (only if isForUser is true) */\n stealthAddress?: string;\n /** The stealth private key for spending (only if isForUser is true) */\n stealthPrivateKey?: string;\n}\n\n/**\n * ERC-5564 Stealth Address Module\n * Integrates with w3pk WebAuthn for seamless privacy-preserving stealth address generation\n */\nexport class StealthAddressModule {\n private getMnemonic: (requireAuth?: boolean) => Promise<string>;\n\n constructor(config: StealthAddressConfig, getMnemonic: (requireAuth?: boolean) => Promise<string>) {\n this.getMnemonic = getMnemonic;\n }\n\n // ========================================\n // ERC-5564 Stealth Address Generation\n // ========================================\n\n /**\n * Generate a fresh ERC-5564 compliant stealth address\n * This is the sender's operation - generates a one-time address for the recipient\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns Stealth address, ephemeral public key, and view tag (to be published on-chain)\n */\n async generateStealthAddress(options?: { requireAuth?: boolean }): Promise<StealthAddressResult> {\n try {\n // Get mnemonic from session (or authenticate if needed/forced)\n const mnemonic = await this.getMnemonic(options?.requireAuth);\n\n const stealthKeys = deriveStealthKeys(mnemonic);\n const stealthResult = generateERC5564StealthAddress(stealthKeys.stealthMetaAddress);\n\n return {\n stealthAddress: stealthResult.stealthAddress,\n ephemeralPublicKey: stealthResult.ephemeralPubKey,\n viewTag: stealthResult.viewTag,\n };\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate stealth address\",\n \"STEALTH_GENERATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Parse an ERC-5564 announcement to check if it's for the user\n * Uses view tag optimization for efficient scanning (255/256 skip rate)\n *\n * @param announcement - The announcement to parse (from on-chain event)\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns ParseResult indicating if announcement is for user, plus stealth private key if true\n */\n async parseAnnouncement(announcement: Announcement, options?: { requireAuth?: boolean }): Promise<ParseAnnouncementResult> {\n try {\n // Get mnemonic from session (or authenticate if needed/forced)\n const mnemonic = await this.getMnemonic(options?.requireAuth);\n\n const stealthKeys = deriveStealthKeys(mnemonic);\n\n // Check if this announcement is for us (with view tag optimization)\n const parseResult = checkStealthAddress(\n stealthKeys.viewingKey,\n stealthKeys.spendingPubKey,\n announcement.ephemeralPublicKey,\n announcement.stealthAddress,\n announcement.viewTag\n );\n\n if (!parseResult.isForUser) {\n return { isForUser: false };\n }\n\n // Compute the stealth private key so user can spend the funds\n const stealthPrivateKey = computeStealthPrivateKey(\n stealthKeys.viewingKey,\n stealthKeys.spendingKey,\n announcement.ephemeralPublicKey\n );\n\n return {\n isForUser: true,\n stealthAddress: parseResult.stealthAddress,\n stealthPrivateKey,\n };\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to parse announcement\",\n \"ANNOUNCEMENT_PARSE_ERROR\",\n error\n );\n }\n }\n\n /**\n * Scan multiple announcements efficiently using view tags\n * Returns only the announcements that belong to the user\n *\n * @param announcements - Array of announcements to scan\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns Array of announcements that belong to the user with their private keys\n */\n async scanAnnouncements(announcements: Announcement[], options?: { requireAuth?: boolean }): Promise<ParseAnnouncementResult[]> {\n const results: ParseAnnouncementResult[] = [];\n\n for (const announcement of announcements) {\n const result = await this.parseAnnouncement(announcement, options);\n if (result.isForUser) {\n results.push(result);\n }\n }\n\n return results;\n }\n\n // ========================================\n // Privacy & Key Management\n // ========================================\n\n /**\n * Get ERC-5564 stealth keys\n * Returns the stealth meta-address and private keys\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async getKeys(options?: { requireAuth?: boolean }): Promise<StealthKeys> {\n try {\n // Get mnemonic from session (or authenticate if needed/forced)\n const mnemonic = await this.getMnemonic(options?.requireAuth);\n\n return deriveStealthKeys(mnemonic);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to get stealth keys\",\n \"STEALTH_KEYS_ERROR\",\n error\n );\n }\n }\n\n /**\n * Get the stealth meta-address for receiving funds\n * This is what you share publicly for others to send you stealth payments\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns The ERC-5564 stealth meta-address (66 bytes)\n */\n async getStealthMetaAddress(options?: { requireAuth?: boolean }): Promise<string> {\n try {\n const keys = await this.getKeys(options);\n return keys.stealthMetaAddress;\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to get stealth meta-address\",\n \"STEALTH_META_ADDRESS_ERROR\",\n error\n );\n }\n }\n\n // ========================================\n // Status & Management\n // ========================================\n\n /**\n * Check if stealth addresses are available (always true if properly configured)\n */\n get isAvailable(): boolean {\n return true;\n }\n}\n\n// Export types for stealth module\nexport type { StealthKeys };","/**\n * ERC-5564 Stealth Address Cryptography\n * Standard-compliant implementation for privacy-preserving transactions\n *\n * @see https://eips.ethereum.org/EIPS/eip-5564\n */\n\nimport { ethers } from \"ethers\";\nimport { CryptoError } from \"../core/errors\";\n\n/**\n * ERC-5564 Stealth Keys\n * Contains the stealth meta-address and private keys for viewing and spending\n */\nexport interface StealthKeys {\n /** Stealth meta-address (66 bytes: compressed spending + viewing pubkeys) */\n stealthMetaAddress: string;\n /** Compressed spending public key (33 bytes) */\n spendingPubKey: string;\n /** Compressed viewing public key (33 bytes) */\n viewingPubKey: string;\n /** Viewing private key (32 bytes) */\n viewingKey: string;\n /** Spending private key (32 bytes) */\n spendingKey: string;\n /** @deprecated Legacy meta-address format (kept for backward compatibility) */\n metaAddress?: string;\n}\n\n/**\n * ERC-5564 Stealth Address Generation Result\n */\nexport interface StealthAddressResult {\n /** The generated stealth address */\n stealthAddress: string;\n /** Ephemeral public key (compressed, 33 bytes) */\n ephemeralPubKey: string;\n /** View tag (1 byte) for efficient scanning */\n viewTag: string;\n /** @deprecated Use ephemeralPubKey instead */\n ephemeralPubkey?: string;\n /** @deprecated Sender doesn't get the private key in ERC-5564 */\n stealthPrivkey?: string;\n}\n\n/**\n * ERC-5564 Parse/Check Result\n */\nexport interface ParseResult {\n /** Whether this announcement is for the user */\n isForUser: boolean;\n /** The stealth address (only if isForUser is true) */\n stealthAddress?: string;\n /** The stealth private key (only if isForUser is true) */\n stealthPrivateKey?: string;\n}\n\n/**\n * Derive ERC-5564 compliant stealth keys from w3pk mnemonic using HD paths\n *\n * @param mnemonic - BIP39 mnemonic phrase\n * @returns StealthKeys with compressed public keys and stealth meta-address\n */\nexport function deriveStealthKeys(mnemonic: string): StealthKeys {\n try {\n // Use specific derivation paths for stealth keys\n const viewingWallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic,\n undefined,\n \"m/44'/60'/1'/0/0\" // Viewing key path\n );\n\n const spendingWallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic,\n undefined,\n \"m/44'/60'/1'/0/1\" // Spending key path\n );\n\n // Get compressed public keys (ERC-5564 requirement)\n const spendingPubKey = spendingWallet.signingKey.compressedPublicKey;\n const viewingPubKey = viewingWallet.signingKey.compressedPublicKey;\n\n // ERC-5564 stealth meta-address: 66 bytes (spending + viewing pubkeys)\n const stealthMetaAddress = spendingPubKey + viewingPubKey.slice(2); // Remove 0x from second key\n\n // Legacy meta-address for backward compatibility\n const legacyMetaAddress = computeLegacyMetaAddress(\n viewingWallet.signingKey.publicKey,\n spendingWallet.signingKey.publicKey\n );\n\n return {\n stealthMetaAddress,\n spendingPubKey,\n viewingPubKey,\n viewingKey: viewingWallet.privateKey,\n spendingKey: spendingWallet.privateKey,\n metaAddress: legacyMetaAddress, // For backward compatibility\n };\n } catch (error) {\n throw new CryptoError(\"Failed to derive stealth keys\", error);\n }\n}\n\n/**\n * ERC-5564: Generate a stealth address using ECDH\n * This is the sender's operation - they generate a one-time stealth address\n * for the recipient without any interaction.\n *\n * Algorithm:\n * 1. Generate random ephemeral private key\n * 2. Parse spending and viewing public keys from stealth meta-address\n * 3. Compute shared secret: s = ephemeral_privkey × viewing_pubkey (ECDH)\n * 4. Hash shared secret: s_h = keccak256(s)\n * 5. Extract view tag: viewTag = s_h[0]\n * 6. Compute stealth pubkey: P_stealth = spending_pubkey + (s_h × G)\n * 7. Derive stealth address from P_stealth\n *\n * @param stealthMetaAddress - 66 bytes (spending + viewing compressed pubkeys)\n * @returns Stealth address, ephemeral pubkey, and view tag\n */\nexport function generateStealthAddress(\n stealthMetaAddress: string\n): StealthAddressResult {\n try {\n // Parse the stealth meta-address (66 bytes = 33 + 33)\n const spendingPubKey = \"0x\" + stealthMetaAddress.slice(2, 68); // First 33 bytes\n const viewingPubKey = \"0x\" + stealthMetaAddress.slice(68); // Last 33 bytes\n\n // Generate ephemeral keypair\n const ephemeralWallet = ethers.Wallet.createRandom();\n const ephemeralPubKey = ephemeralWallet.signingKey.compressedPublicKey;\n\n // Compute ECDH shared secret: s = ephemeral_privkey × viewing_pubkey\n const sharedSecret = computeSharedSecret(\n ephemeralWallet.privateKey,\n viewingPubKey\n );\n\n // Hash the shared secret: s_h = keccak256(s)\n const hashedSharedSecret = ethers.keccak256(sharedSecret);\n\n // Extract view tag (first byte of hashed shared secret)\n const viewTag = \"0x\" + hashedSharedSecret.slice(2, 4);\n\n // Compute stealth public key: P_stealth = spending_pubkey + (s_h × G)\n const stealthPubKey = addPublicKeys(\n spendingPubKey,\n multiplyGeneratorByScalar(hashedSharedSecret)\n );\n\n // Derive stealth address from stealth public key\n const stealthAddress = publicKeyToAddress(stealthPubKey);\n\n return {\n stealthAddress,\n ephemeralPubKey,\n viewTag,\n // Backward compatibility\n ephemeralPubkey: ephemeralPubKey,\n };\n } catch (error) {\n throw new CryptoError(\"Failed to generate stealth address\", error);\n }\n}\n\n/**\n * ERC-5564: Check if a stealth address belongs to the user (with view tag optimization)\n * This is the recipient's scanning operation.\n *\n * Algorithm:\n * 1. Compute shared secret: s = viewing_privkey × ephemeral_pubkey (ECDH)\n * 2. Hash shared secret: s_h = keccak256(s)\n * 3. Check view tag first (255/256 probability to skip remaining computation)\n * 4. If view tag matches, compute stealth pubkey: P_stealth = spending_pubkey + (s_h × G)\n * 5. Derive address and compare with target\n *\n * @param viewingKey - Recipient's viewing private key\n * @param spendingPubKey - Recipient's spending public key (compressed)\n * @param ephemeralPubKey - Ephemeral public key from announcement\n * @param stealthAddress - The stealth address to check\n * @param viewTag - View tag from announcement (optional, for optimization)\n * @returns ParseResult with stealth address and private key if it belongs to user\n */\nexport function checkStealthAddress(\n viewingKey: string,\n spendingPubKey: string,\n ephemeralPubKey: string,\n stealthAddress: string,\n viewTag?: string\n): ParseResult {\n try {\n // Compute ECDH shared secret: s = viewing_privkey × ephemeral_pubkey\n const sharedSecret = computeSharedSecret(viewingKey, ephemeralPubKey);\n\n // Hash the shared secret: s_h = keccak256(s)\n const hashedSharedSecret = ethers.keccak256(sharedSecret);\n\n // View tag optimization: check first byte of hashed shared secret\n if (viewTag) {\n const computedViewTag = \"0x\" + hashedSharedSecret.slice(2, 4);\n if (computedViewTag.toLowerCase() !== viewTag.toLowerCase()) {\n // View tag mismatch - this announcement is not for us (255/256 probability)\n return { isForUser: false };\n }\n }\n\n // Compute stealth public key: P_stealth = spending_pubkey + (s_h × G)\n const stealthPubKey = addPublicKeys(\n spendingPubKey,\n multiplyGeneratorByScalar(hashedSharedSecret)\n );\n\n // Derive stealth address from stealth public key\n const derivedAddress = publicKeyToAddress(stealthPubKey);\n\n // Check if addresses match\n if (derivedAddress.toLowerCase() !== stealthAddress.toLowerCase()) {\n return { isForUser: false };\n }\n\n // Compute stealth private key: privkey_stealth = spending_privkey + s_h\n // We need the spending private key for this, which should be passed separately\n // For now, we just return that it's for the user\n return {\n isForUser: true,\n stealthAddress: derivedAddress,\n };\n } catch (error) {\n return { isForUser: false };\n }\n}\n\n/**\n * ERC-5564: Compute the stealth private key for spending\n * This allows the recipient to actually spend funds from the stealth address.\n *\n * Algorithm:\n * privkey_stealth = spending_privkey + s_h (mod n)\n *\n * @param viewingKey - Recipient's viewing private key\n * @param spendingKey - Recipient's spending private key\n * @param ephemeralPubKey - Ephemeral public key from announcement\n * @returns The stealth private key\n */\nexport function computeStealthPrivateKey(\n viewingKey: string,\n spendingKey: string,\n ephemeralPubKey: string\n): string {\n try {\n // Compute ECDH shared secret: s = viewing_privkey × ephemeral_pubkey\n const sharedSecret = computeSharedSecret(viewingKey, ephemeralPubKey);\n\n // Hash the shared secret: s_h = keccak256(s)\n const hashedSharedSecret = ethers.keccak256(sharedSecret);\n\n // Compute stealth private key: privkey_stealth = spending_privkey + s_h (mod n)\n const stealthPrivKey = addPrivateKeys(spendingKey, hashedSharedSecret);\n\n return stealthPrivKey;\n } catch (error) {\n throw new CryptoError(\"Failed to compute stealth private key\", error);\n }\n}\n\n// ========================================\n// ERC-5564 Cryptographic Primitives\n// ========================================\n\n/**\n * Compute ECDH shared secret using SECP256k1\n * s = privkey × pubkey\n */\nfunction computeSharedSecret(privateKey: string, publicKey: string): string {\n try {\n const wallet = new ethers.Wallet(privateKey);\n const signingKey = wallet.signingKey;\n\n // Perform ECDH: multiply the public key by our private key\n // The result is a point on the curve, we take its x-coordinate\n const sharedPoint = signingKey.computeSharedSecret(publicKey);\n\n return sharedPoint;\n } catch (error) {\n throw new CryptoError(\"Failed to compute shared secret\", error);\n }\n}\n\n/**\n * Multiply the generator point G by a scalar\n * Returns compressed public key\n */\nfunction multiplyGeneratorByScalar(scalar: string): string {\n try {\n const wallet = new ethers.Wallet(scalar);\n return wallet.signingKey.compressedPublicKey;\n } catch (error) {\n throw new CryptoError(\"Failed to multiply generator by scalar\", error);\n }\n}\n\n/**\n * Add two public keys using elliptic curve point addition\n * P1 + P2\n */\nfunction addPublicKeys(pubKey1: string, pubKey2: string): string {\n try {\n const key1 = ethers.SigningKey.computePublicKey(pubKey1, false); // Uncompressed\n const key2 = ethers.SigningKey.computePublicKey(pubKey2, false); // Uncompressed\n\n // Extract x and y coordinates (remove 0x04 prefix)\n const x1 = BigInt(\"0x\" + key1.slice(4, 68));\n const y1 = BigInt(\"0x\" + key1.slice(68));\n const x2 = BigInt(\"0x\" + key2.slice(4, 68));\n const y2 = BigInt(\"0x\" + key2.slice(68));\n\n // SECP256k1 curve parameters\n const p = BigInt(\"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\");\n\n // Point addition on elliptic curve\n // If points are the same, use point doubling\n if (x1 === x2 && y1 === y2) {\n // Point doubling: lambda = (3*x1^2) / (2*y1)\n const numerator = (3n * x1 * x1) % p;\n const denominator = (2n * y1) % p;\n const lambda = (numerator * modInverse(denominator, p)) % p;\n\n const x3 = (lambda * lambda - 2n * x1) % p;\n const y3 = (lambda * (x1 - x3) - y1) % p;\n\n return compressPublicKey((x3 + p) % p, (y3 + p) % p);\n }\n\n // Regular point addition: lambda = (y2 - y1) / (x2 - x1)\n const numerator = ((y2 - y1) % p + p) % p;\n const denominator = ((x2 - x1) % p + p) % p;\n const lambda = (numerator * modInverse(denominator, p)) % p;\n\n const x3 = (lambda * lambda - x1 - x2) % p;\n const y3 = (lambda * (x1 - x3) - y1) % p;\n\n return compressPublicKey((x3 + p) % p, (y3 + p) % p);\n } catch (error) {\n throw new CryptoError(\"Failed to add public keys\", error);\n }\n}\n\n/**\n * Add two private keys modulo the curve order\n * (privkey1 + privkey2) mod n\n */\nfunction addPrivateKeys(privKey1: string, privKey2: string): string {\n try {\n // SECP256k1 curve order\n const n = BigInt(\"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141\");\n\n const k1 = BigInt(privKey1);\n const k2 = BigInt(privKey2);\n\n const sum = (k1 + k2) % n;\n\n // Convert back to hex with proper padding\n return \"0x\" + sum.toString(16).padStart(64, \"0\");\n } catch (error) {\n throw new CryptoError(\"Failed to add private keys\", error);\n }\n}\n\n/**\n * Compress a public key (x, y) to compressed format\n */\nfunction compressPublicKey(x: bigint, y: bigint): string {\n const prefix = y % 2n === 0n ? \"02\" : \"03\";\n return \"0x\" + prefix + x.toString(16).padStart(64, \"0\");\n}\n\n/**\n * Compute modular inverse using Extended Euclidean Algorithm\n */\nfunction modInverse(a: bigint, m: bigint): bigint {\n a = ((a % m) + m) % m;\n let [oldR, r] = [a, m];\n let [oldS, s] = [1n, 0n];\n\n while (r !== 0n) {\n const quotient = oldR / r;\n [oldR, r] = [r, oldR - quotient * r];\n [oldS, s] = [s, oldS - quotient * s];\n }\n\n return ((oldS % m) + m) % m;\n}\n\n/**\n * Derive Ethereum address from compressed public key\n */\nfunction publicKeyToAddress(compressedPubKey: string): string {\n try {\n // Decompress the public key first\n const uncompressedPubKey = ethers.SigningKey.computePublicKey(compressedPubKey, false);\n\n // Take keccak256 of uncompressed public key (without 0x04 prefix)\n const pubKeyHash = ethers.keccak256(\"0x\" + uncompressedPubKey.slice(4));\n\n // Take last 20 bytes as address\n return ethers.getAddress(\"0x\" + pubKeyHash.slice(-40));\n } catch (error) {\n throw new CryptoError(\"Failed to derive address from public key\", error);\n }\n}\n\n/**\n * Legacy meta address computation (for backward compatibility)\n */\nfunction computeLegacyMetaAddress(\n viewingPubkey: string,\n spendingPubkey: string\n): string {\n const combined = ethers.solidityPackedKeccak256(\n [\"bytes\", \"bytes\"],\n [viewingPubkey, spendingPubkey]\n );\n\n // Take first 20 bytes as address\n return ethers.getAddress(\"0x\" + combined.slice(26));\n}\n\n/**\n * @deprecated Use checkStealthAddress instead\n */\nexport function canControlStealthAddress(\n viewingKey: string,\n spendingKey: string,\n ephemeralPubkey: string,\n targetAddress: string\n): boolean {\n const spendingWallet = new ethers.Wallet(spendingKey);\n const result = checkStealthAddress(\n viewingKey,\n spendingWallet.signingKey.compressedPublicKey,\n ephemeralPubkey,\n targetAddress\n );\n return result.isForUser;\n}\n","/**\n * Session Manager - Caches decrypted mnemonic for configurable duration\n *\n * SECURITY:\n * - Mnemonic is stored in memory only (never persisted)\n * - Automatically cleared after session expires\n * - Can be manually revoked at any time\n * - Initial authentication still requires biometric/PIN\n */\n\nexport interface SessionData {\n mnemonic: string;\n expiresAt: number;\n credentialId: string;\n}\n\nexport class SessionManager {\n private session: SessionData | null = null;\n private sessionDuration: number; // in milliseconds\n\n constructor(sessionDurationHours: number = 1) {\n this.sessionDuration = sessionDurationHours * 60 * 60 * 1000; // Convert to ms\n }\n\n /**\n * Start a new session with the decrypted mnemonic\n */\n startSession(mnemonic: string, credentialId: string): void {\n const expiresAt = Date.now() + this.sessionDuration;\n this.session = {\n mnemonic,\n expiresAt,\n credentialId,\n };\n }\n\n /**\n * Get the cached mnemonic if session is still valid\n * Returns null if session expired or doesn't exist\n */\n getMnemonic(): string | null {\n if (!this.session) {\n return null;\n }\n\n // Check if session expired\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n return null;\n }\n\n return this.session.mnemonic;\n }\n\n /**\n * Get session credential ID\n */\n getCredentialId(): string | null {\n if (!this.session) {\n return null;\n }\n\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n return null;\n }\n\n return this.session.credentialId;\n }\n\n /**\n * Check if session is active and valid\n */\n isActive(): boolean {\n return this.getMnemonic() !== null;\n }\n\n /**\n * Get remaining session time in seconds\n */\n getRemainingTime(): number {\n if (!this.session) {\n return 0;\n }\n\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n return 0;\n }\n\n return Math.floor((this.session.expiresAt - Date.now()) / 1000);\n }\n\n /**\n * Extend the session by the configured duration\n */\n extendSession(): void {\n if (!this.session) {\n throw new Error(\"No active session to extend\");\n }\n\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n throw new Error(\"Session expired, cannot extend\");\n }\n\n this.session.expiresAt = Date.now() + this.sessionDuration;\n }\n\n /**\n * Manually clear the session (logout or security requirement)\n */\n clearSession(): void {\n // Overwrite mnemonic in memory before clearing\n if (this.session) {\n this.session.mnemonic = \"0\".repeat(this.session.mnemonic.length);\n }\n this.session = null;\n }\n\n /**\n * Update session duration (affects new sessions and extensions)\n */\n setSessionDuration(hours: number): void {\n this.sessionDuration = hours * 60 * 60 * 1000;\n }\n}\n","/**\n * SDK Configuration\n */\n\nimport type { UserInfo } from \"../types\";\nimport type { Web3PasskeyError } from \"./errors\";\n\nexport interface StealthAddressConfig {}\n\nexport interface ZKProofConfig {\n enabledProofs?: Array<\n | \"membership\"\n | \"threshold\"\n | \"range\"\n | \"equality\"\n | \"ownership\"\n | \"signature\"\n | \"nft\"\n >;\n customCircuits?: Record<string, any>;\n}\n\nexport interface Web3PasskeyConfig {\n debug?: boolean;\n onError?: (error: Web3PasskeyError) => void;\n onAuthStateChanged?: (isAuthenticated: boolean, user?: UserInfo) => void;\n storage?: Storage;\n\n /**\n * Session duration in hours\n * After successful authentication, the decrypted mnemonic is cached for this duration\n * This allows operations like deriveWallet(), exportMnemonic(), stealth addresses, etc.\n * to work without repeated authentication prompts\n *\n * @default 1 (hour)\n * Set to 0 to require authentication for every operation (most secure)\n */\n sessionDuration?: number;\n\n /**\n * Stealth address configuration (ERC-5564)\n */\n stealthAddresses?: StealthAddressConfig;\n\n /**\n * Zero-knowledge proof configuration\n * Requires: snarkjs, circomlibjs\n */\n zkProofs?: ZKProofConfig;\n}\n\nexport interface InternalConfig extends Required<Web3PasskeyConfig> {\n // Normalized config with all defaults applied\n}\n\nexport const DEFAULT_CONFIG: Partial<InternalConfig> = {\n debug: false,\n sessionDuration: 1, // 1 hour default\n onError: (error: Web3PasskeyError) => {\n if (DEFAULT_CONFIG.debug) {\n console.error(\"[w3pk]\", error);\n }\n },\n};\n","/**\n * Main Web3Passkey SDK class - Client-Only Version\n * No server required - all authentication happens locally\n */\n\nimport { register } from \"../auth/register\";\nimport { login } from \"../auth/authenticate\";\nimport { IndexedDBWalletStorage } from \"../wallet/storage\";\nimport {\n generateBIP39Wallet,\n deriveWalletFromMnemonic,\n} from \"../wallet/generate\";\nimport {\n deriveEncryptionKeyFromWebAuthn,\n encryptData,\n decryptData,\n} from \"../wallet/crypto\";\nimport { StealthAddressModule } from \"../stealth\";\nimport { SessionManager } from \"./session\";\n// ZK module imported dynamically to avoid bundling dependencies\nimport type { Web3PasskeyConfig, InternalConfig } from \"./config\";\nimport { DEFAULT_CONFIG } from \"./config\";\nimport type { UserInfo, WalletInfo } from \"../types\";\nimport { AuthenticationError, WalletError } from \"./errors\";\nimport { getEndpoints } from \"../chainlist\";\nimport { supportsEIP7702 } from \"../eip7702\";\n\nexport class Web3Passkey {\n private config: InternalConfig;\n private walletStorage: IndexedDBWalletStorage;\n private currentUser: UserInfo | null = null;\n private currentWallet: WalletInfo | null = null;\n private sessionManager: SessionManager;\n\n // Optional modules\n public stealth?: StealthAddressModule;\n private zkModule?: any;\n\n constructor(config: Web3PasskeyConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config } as InternalConfig;\n this.walletStorage = new IndexedDBWalletStorage();\n this.sessionManager = new SessionManager(config.sessionDuration || 1);\n\n // Initialize optional modules\n if (config.stealthAddresses !== undefined) {\n this.stealth = new StealthAddressModule(\n config.stealthAddresses,\n (requireAuth?: boolean) => this.getMnemonicFromSession(requireAuth)\n );\n }\n\n // Initialize ZK module if configured\n if (config.zkProofs) {\n this.initializeZKModule(config.zkProofs);\n }\n }\n\n /**\n * Lazy-load ZK module to avoid bundling large dependencies\n */\n private async initializeZKModule(zkConfig: any) {\n try {\n const { ZKProofModule } = await import(\"../zk\");\n this.zkModule = new ZKProofModule(zkConfig);\n } catch (error) {\n console.warn(\n \"ZK module not available. Install dependencies: npm install snarkjs circomlibjs\"\n );\n }\n }\n\n /**\n * Get mnemonic from active session or trigger authentication\n * This is used internally by methods that need the mnemonic\n *\n * @param forceAuth - If true, bypass session cache and require fresh authentication\n */\n private async getMnemonicFromSession(\n forceAuth: boolean = false\n ): Promise<string> {\n // Check if session is active (unless force auth is required)\n if (!forceAuth) {\n const cachedMnemonic = this.sessionManager.getMnemonic();\n if (cachedMnemonic) {\n return cachedMnemonic;\n }\n }\n\n // Session expired, doesn't exist, or force auth requested - need to authenticate\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated. Call login() first.\");\n }\n\n // Get encrypted wallet\n const walletData = await this.walletStorage.retrieve(\n this.currentUser.ethereumAddress\n );\n\n if (!walletData) {\n throw new WalletError(\"No wallet found. Generate a wallet first.\");\n }\n\n // Authenticate to prove identity\n const authResult = await login();\n if (!authResult.user) {\n throw new WalletError(\"Authentication failed\");\n }\n\n // Get credential to access public key\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialById(walletData.credentialId);\n const publicKey = credential?.publicKey;\n\n // Derive decryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n walletData.credentialId,\n publicKey\n );\n\n // Decrypt mnemonic\n const mnemonic = await decryptData(\n walletData.encryptedMnemonic,\n encryptionKey\n );\n\n // Start new session with decrypted mnemonic\n this.sessionManager.startSession(mnemonic, walletData.credentialId);\n\n return mnemonic;\n }\n\n /**\n * Register a new user with WebAuthn\n * Automatically generates a wallet if none exists\n * Creates a passkey and associates it with the Ethereum address (account #0)\n * Returns the mnemonic phrase - IMPORTANT: User must save this!\n */\n async register(options: { username: string }): Promise<{ mnemonic: string }> {\n try {\n // Auto-generate wallet if it doesn't exist\n if (!this.currentWallet?.address) {\n await this.generateWallet();\n }\n\n // Derive account #0 address from the generated wallet\n const ethereumAddress = this.currentWallet!.address;\n const mnemonic = this.currentWallet!.mnemonic!;\n\n const registrationResult = await register({\n username: options.username,\n ethereumAddress,\n });\n\n this.currentUser = {\n id: ethereumAddress,\n username: options.username,\n displayName: options.username,\n ethereumAddress,\n };\n\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialByAddress(ethereumAddress);\n\n if (!credential) {\n throw new WalletError(\"Credential not found after registration\");\n }\n\n const credentialId = credential.id;\n const publicKey = credential.publicKey;\n\n // Derive encryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n credentialId,\n publicKey\n );\n\n const encryptedMnemonic = await encryptData(mnemonic, encryptionKey);\n\n await this.walletStorage.store({\n ethereumAddress: this.currentUser.ethereumAddress,\n encryptedMnemonic,\n credentialId,\n createdAt: Date.now(),\n });\n\n this.sessionManager.startSession(mnemonic, credentialId);\n\n this.config.onAuthStateChanged?.(true, this.currentUser);\n\n return { mnemonic };\n } catch (error) {\n this.config.onError?.(error as any);\n throw error;\n }\n }\n\n /**\n * Login with WebAuthn (usernameless)\n * Uses resident credentials stored in the authenticator\n * Automatically starts a session with the decrypted mnemonic\n */\n async login(): Promise<UserInfo> {\n try {\n const result = await login();\n\n if (!result.verified || !result.user) {\n throw new AuthenticationError(\"Login failed\");\n }\n\n this.currentUser = {\n id: result.user.ethereumAddress,\n username: result.user.username,\n displayName: result.user.username,\n ethereumAddress: result.user.ethereumAddress,\n };\n\n // Get encrypted wallet data\n const walletData = await this.walletStorage.retrieve(\n this.currentUser.ethereumAddress\n );\n\n if (!walletData) {\n throw new WalletError(\n \"No wallet found for this user. You may need to register first.\"\n );\n }\n\n // Get credential to access public key\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialById(walletData.credentialId);\n const publicKey = credential?.publicKey;\n\n // Derive decryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n walletData.credentialId,\n publicKey\n );\n\n // Decrypt mnemonic\n const mnemonic = await decryptData(\n walletData.encryptedMnemonic,\n encryptionKey\n );\n\n // Start session with decrypted mnemonic\n this.sessionManager.startSession(mnemonic, walletData.credentialId);\n\n this.config.onAuthStateChanged?.(true, this.currentUser);\n\n return this.currentUser;\n } catch (error) {\n this.config.onError?.(error as any);\n throw error;\n }\n }\n\n /**\n * Logout the current user\n * Clears the active session and removes cached mnemonic from memory\n */\n async logout(): Promise<void> {\n this.currentUser = null;\n this.currentWallet = null;\n this.sessionManager.clearSession();\n this.config.onAuthStateChanged?.(false, undefined);\n }\n\n /**\n * Get current authentication status\n */\n get isAuthenticated(): boolean {\n return this.currentUser !== null;\n }\n\n /**\n * Get current user info\n */\n get user(): UserInfo | null {\n return this.currentUser;\n }\n\n /**\n * Generate a new BIP39 wallet\n * Returns the mnemonic phrase (12 words)\n */\n async generateWallet(): Promise<{ mnemonic: string }> {\n try {\n const wallet = generateBIP39Wallet();\n\n this.currentWallet = {\n address: wallet.address,\n mnemonic: wallet.mnemonic,\n };\n\n return {\n mnemonic: wallet.mnemonic,\n };\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to generate wallet\", error);\n }\n }\n\n /**\n * Derive an HD wallet at a specific index\n *\n * SECURITY: Uses active session or prompts for authentication if session expired\n *\n * @param index - The HD wallet derivation index\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async deriveWallet(\n index: number,\n options?: { requireAuth?: boolean }\n ): Promise<WalletInfo> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to derive wallet\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(options?.requireAuth);\n\n const derived = deriveWalletFromMnemonic(mnemonic, index);\n\n return {\n address: derived.address,\n privateKey: derived.privateKey,\n };\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to derive wallet\", error);\n }\n }\n\n /**\n * Export the mnemonic phrase\n *\n * SECURITY: Uses active session or prompts for authentication if session expired\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async exportMnemonic(options?: { requireAuth?: boolean }): Promise<string> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to export mnemonic\");\n }\n\n return await this.getMnemonicFromSession(options?.requireAuth);\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to export mnemonic\", error);\n }\n }\n\n /**\n * Import a mnemonic phrase\n * Encrypts and stores it for the current user\n * Requires fresh WebAuthn authentication for security\n * WARNING: This will overwrite any existing wallet for this user\n */\n async importMnemonic(mnemonic: string): Promise<void> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to import mnemonic\");\n }\n\n if (!mnemonic || mnemonic.trim().split(/\\s+/).length < 12) {\n throw new WalletError(\"Invalid mnemonic: must be at least 12 words\");\n }\n\n const authResult = await login();\n if (!authResult.user) {\n throw new WalletError(\"Authentication failed\");\n }\n\n const credentialId = authResult.user.credentialId;\n\n // Get credential to access public key\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialById(credentialId);\n const publicKey = credential?.publicKey;\n\n // Derive encryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n credentialId,\n publicKey\n );\n\n const encryptedMnemonic = await encryptData(\n mnemonic.trim(),\n encryptionKey\n );\n\n await this.walletStorage.store({\n ethereumAddress: this.currentUser.ethereumAddress,\n encryptedMnemonic,\n credentialId,\n createdAt: Date.now(),\n });\n\n this.currentWallet = {\n address: this.currentUser.ethereumAddress,\n mnemonic: mnemonic.trim(),\n };\n\n this.sessionManager.startSession(mnemonic.trim(), credentialId);\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to import mnemonic\", error);\n }\n }\n\n /**\n * Sign a message with the wallet\n *\n * SECURITY: Uses active session or prompts for authentication if session expired\n *\n * @param message - The message to sign\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async signMessage(\n message: string,\n options?: { requireAuth?: boolean }\n ): Promise<string> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to sign message\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(options?.requireAuth);\n\n const { Wallet } = await import(\"ethers\");\n const wallet = Wallet.fromPhrase(mnemonic);\n\n const signature = await wallet.signMessage(message);\n\n return signature;\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to sign message\", error);\n }\n }\n\n /**\n * Get RPC endpoints for a chain\n */\n async getEndpoints(chainId: number): Promise<string[]> {\n return getEndpoints(chainId);\n }\n\n /**\n * Check if a network supports EIP-7702\n */\n async supportsEIP7702(\n chainId: number,\n options?: { maxEndpoints?: number; timeout?: number }\n ): Promise<boolean> {\n return supportsEIP7702(chainId, this.getEndpoints.bind(this), options);\n }\n\n /**\n * Access ZK proof module (if available)\n */\n get zk(): any {\n if (!this.zkModule) {\n throw new Error(\n \"ZK module not available. Install dependencies: npm install snarkjs circomlibjs\"\n );\n }\n return this.zkModule;\n }\n\n // ========================================\n // Session Management\n // ========================================\n\n /**\n * Check if there's an active session\n */\n hasActiveSession(): boolean {\n return this.sessionManager.isActive();\n }\n\n /**\n * Get remaining session time in seconds\n */\n getSessionRemainingTime(): number {\n return this.sessionManager.getRemainingTime();\n }\n\n /**\n * Extend the current session by the configured duration\n * Throws error if no active session or if session expired\n */\n extendSession(): void {\n try {\n this.sessionManager.extendSession();\n } catch (error) {\n throw new WalletError(\"Cannot extend session\", error);\n }\n }\n\n /**\n * Manually clear the active session\n * This removes the cached mnemonic from memory\n * User will need to authenticate again for wallet operations\n */\n clearSession(): void {\n this.sessionManager.clearSession();\n }\n\n /**\n * Update session duration (affects new sessions and extensions)\n * @param hours - Session duration in hours\n */\n setSessionDuration(hours: number): void {\n this.sessionManager.setSessionDuration(hours);\n }\n\n /**\n * SDK version\n */\n get version(): string {\n return \"0.7.0\";\n }\n}\n","/**\n * Chainlist module for fetching RPC endpoints\n */\n\nimport type { Chain, ChainlistOptions } from \"./types\";\n\nconst DEFAULT_CHAINS_URL = \"https://chainid.network/chains.json\";\nconst DEFAULT_CACHE_DURATION = 3600000; // 1 hour\n\ninterface CacheEntry {\n data: Chain[];\n timestamp: number;\n}\n\nlet cache: CacheEntry | null = null;\n\n/**\n * Patterns that indicate an RPC URL requires an API key\n */\nconst API_KEY_PATTERNS = [\n /\\$\\{[\\w_]+\\}/i, // ${INFURA_API_KEY}, ${API_KEY}, etc.\n /\\{[\\w_]+\\}/i, // {API_KEY}, {INFURA_API_KEY}, etc.\n /<[\\w_]+>/i, // <API_KEY>, <INFURA_API_KEY>, etc.\n /YOUR[-_]?API[-_]?KEY/i,\n /INSERT[-_]?API[-_]?KEY/i,\n /API[-_]?KEY[-_]?HERE/i,\n];\n\n/**\n * Check if an RPC URL requires an API key\n */\nfunction requiresApiKey(rpcUrl: string): boolean {\n return API_KEY_PATTERNS.some((pattern) => pattern.test(rpcUrl));\n}\n\n/**\n * Fetch all chains data from chainid.network\n */\nasync function fetchChains(\n chainsJsonUrl: string = DEFAULT_CHAINS_URL\n): Promise<Chain[]> {\n const response = await fetch(chainsJsonUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch chains data: ${response.status} ${response.statusText}`\n );\n }\n\n return await response.json();\n}\n\n/**\n * Get all chains data with caching\n */\nasync function getChainsData(options?: ChainlistOptions): Promise<Chain[]> {\n const chainsJsonUrl = options?.chainsJsonUrl ?? DEFAULT_CHAINS_URL;\n const cacheDuration = options?.cacheDuration ?? DEFAULT_CACHE_DURATION;\n const now = Date.now();\n\n // Check if cache is valid\n if (cache && now - cache.timestamp < cacheDuration) {\n return cache.data;\n }\n\n // Fetch fresh data\n const data = await fetchChains(chainsJsonUrl);\n cache = { data, timestamp: now };\n\n return data;\n}\n\n/**\n * Get RPC endpoints for a specific chain ID, excluding those that require API keys\n *\n * @param chainId - The chain ID to get endpoints for\n * @param options - Optional configuration\n * @returns Array of RPC URLs that don't require API keys\n *\n * @example\n * ```typescript\n * import { getEndpoints } from 'w3pk/chainlist'\n *\n * // Get Ethereum mainnet RPCs\n * const endpoints = await getEndpoints(1)\n * console.log(endpoints)\n * // [\n * // \"https://api.mycryptoapi.com/eth\",\n * // \"https://cloudflare-eth.com\",\n * // \"https://ethereum-rpc.publicnode.com\",\n * // ...\n * // ]\n * ```\n */\nexport async function getEndpoints(\n chainId: number,\n options?: ChainlistOptions\n): Promise<string[]> {\n const chains = await getChainsData(options);\n const chain = chains.find((c) => c.chainId === chainId);\n\n if (!chain) {\n return [];\n }\n\n // Filter out RPC URLs that require API keys and websocket URLs\n return chain.rpc.filter(\n (rpcUrl) =>\n !requiresApiKey(rpcUrl) &&\n !rpcUrl.startsWith(\"wss://\") &&\n !rpcUrl.startsWith(\"ws://\")\n );\n}\n\n/**\n * Get all available chains\n *\n * @param options - Optional configuration\n * @returns Array of all chains\n */\nexport async function getAllChains(\n options?: ChainlistOptions\n): Promise<Chain[]> {\n return getChainsData(options);\n}\n\n/**\n * Get chain information by chain ID\n *\n * @param chainId - The chain ID to get information for\n * @param options - Optional configuration\n * @returns Chain information or undefined if not found\n */\nexport async function getChainById(\n chainId: number,\n options?: ChainlistOptions\n): Promise<Chain | undefined> {\n const chains = await getChainsData(options);\n return chains.find((c) => c.chainId === chainId);\n}\n\n/**\n * Clear the chains data cache\n */\nexport function clearCache(): void {\n cache = null;\n}\n\n// Export types\nexport type { Chain, ChainlistOptions } from \"./types\";\n","/**\n * EIP-7702 Support (Internal Module)\n *\n * EIP-7702 introduces \"Set EOA Account Code\" functionality,\n * allowing externally owned accounts (EOAs) to temporarily act as smart contracts.\n *\n * This module is for internal use by the SDK.\n * Access via: w3pk.supportsEIP7702(chainId)\n */\n\n/**\n * EIP-7702 supported chain IDs\n * Source: https://github.com/w3hc/eip7702-playground/blob/main/eip7702-networks.ts\n * Generated: 2025-10-15 10:51:18 UTC\n * Total: 329 chains\n */\nconst EIP7702_SUPPORTED_CHAINS = new Set([\n 1, 10, 8453, 42161, 57073, 100, 42220, 137, 42, 15, 40, 41, 44, 46, 47, 50,\n 51, 56, 61, 71, 82, 83, 95, 97, 112, 123, 130, 146, 151, 153, 171, 180, 183,\n 185, 195, 215, 228, 247, 248, 252, 261, 267, 291, 293, 311, 332, 336, 395,\n 401, 416, 466, 480, 488, 510, 545, 634, 647, 648, 747, 831, 919, 938, 945,\n 957, 964, 970, 980, 995, 997, 1001, 1003, 1024, 1030, 1114, 1125, 1135, 1149,\n 1188, 1284, 1285, 1287, 1300, 1301, 1315, 1337, 1338, 1339, 1424, 1514, 1687,\n 1727, 1729, 1740, 1750, 1829, 1868, 1946, 1961, 1962, 1969, 1989, 1995, 2017,\n 2020, 2031, 2043, 2109, 2241, 2340, 2345, 2440, 2522, 2559, 2649, 3068, 3109,\n 3338, 3502, 3799, 3888, 3889, 4000, 4048, 4078, 4162, 4201, 4202, 4460, 4488,\n 4661, 4689, 4690, 4888, 5000, 5003, 5124, 5234, 5330, 5424, 5522, 6283, 6342,\n 6398, 6678, 6806, 6934, 6942, 6969, 7117, 7171, 7200, 7208, 7368, 7518, 7668,\n 7672, 7744, 7771, 7869, 7897, 8008, 8118, 8217, 8408, 8700, 8726, 8727, 8844,\n 8880, 8881, 8882, 8889, 9372, 9496, 9700, 9745, 9746, 9899, 9990, 9996, 10011,\n 10085, 10143, 10200, 11221, 11501, 11504, 11891, 13370, 14853, 16602, 16661,\n 17000, 18880, 18881, 19991, 21000, 21816, 21912, 25327, 32323, 33401, 34443,\n 41923, 42170, 43111, 44787, 47805, 48898, 48900, 49049, 49088, 50000, 50312,\n 53302, 53456, 53457, 55244, 56288, 59141, 60808, 60850, 62320, 62850, 64002,\n 71402, 72080, 73114, 73115, 75338, 78281, 80002, 80008, 80069, 80094, 80451,\n 80931, 84532, 88899, 91342, 92278, 94524, 96970, 97476, 97477, 98985, 100021,\n 100501, 101010, 102030, 102031, 102032, 112358, 120893, 121212, 121213,\n 121214, 121215, 129399, 161803, 175188, 192940, 193939, 198989, 212013,\n 222222, 240241, 325000, 355110, 355113, 421614, 555777, 560048, 656476,\n 713715, 743111, 747474, 763373, 763375, 777777, 806582, 808813, 810180,\n 839999, 888991, 2019775, 2222222, 4278608, 5734951, 6666689, 6985385, 7080969,\n 7777777, 9999999, 11142220, 11155111, 11155420, 11155931, 16969696, 19850818,\n 20180427, 20250825, 28122024, 34949059, 37084624, 52164803, 61022448,\n 79479957, 96969696, 420420421, 420420422, 888888888, 974399131, 999999999,\n 1020352220, 1273227453, 1313161560, 1350216234, 1380996178, 1417429182,\n 1444673419, 1482601649, 1564830818, 2046399126, 11297108099, 11297108109,\n 88153591557, 123420000220, 123420001114,\n]);\n\n/**\n * Test an RPC endpoint for EIP-7702 support using eth_estimateGas\n * Based on: https://github.com/w3hc/eip7702-playground/blob/main/eip7702_scanner.sh\n * @internal\n */\nasync function testRPCForEIP7702(\n rpcUrl: string,\n timeout: number = 10000\n): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n signal: controller.signal,\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"eth_estimateGas\",\n params: [\n {\n from: \"0xdeadbeef00000000000000000000000000000000\",\n to: \"0xdeadbeef00000000000000000000000000000000\",\n data: \"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n value: \"0x0\",\n },\n \"latest\",\n {\n \"0xdeadbeef00000000000000000000000000000000\": {\n code: \"0xef01000000000000000000000000000000000000000001\",\n },\n },\n ],\n id: 1,\n }),\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return false;\n }\n\n const data = await response.json();\n\n // Check for error messages that indicate no EIP-7702 support\n if (data.error) {\n const errorMsg = (data.error.message || \"\").toLowerCase();\n\n // These errors indicate the RPC doesn't support EIP-7702\n const unsupportedErrors = [\n \"unsupported\",\n \"not supported\",\n \"unknown\",\n \"invalid\",\n \"unrecognized\",\n \"does not support\",\n \"not implemented\",\n ];\n\n return !unsupportedErrors.some((err) => errorMsg.includes(err));\n }\n\n // If we got a result (even an estimate), EIP-7702 is supported\n return data.result !== undefined;\n } catch (error) {\n // Network errors, timeouts, etc. don't necessarily mean no support\n return false;\n }\n}\n\n/**\n * Check if a network supports EIP-7702\n * First checks cached list, then performs RPC test if not found\n * @internal\n */\nexport async function supportsEIP7702(\n chainId: number,\n getEndpointsFn: (chainId: number) => Promise<string[]>,\n options?: {\n maxEndpoints?: number;\n timeout?: number;\n }\n): Promise<boolean> {\n // First, check the cached list\n if (EIP7702_SUPPORTED_CHAINS.has(chainId)) {\n return true;\n }\n\n // Not in cached list, perform RPC test\n const maxEndpoints = options?.maxEndpoints || 3;\n const timeout = options?.timeout || 10000;\n\n try {\n // Get RPC endpoints for this chain\n const endpoints = await getEndpointsFn(chainId);\n\n if (endpoints.length === 0) {\n return false;\n }\n\n // Test up to maxEndpoints\n const endpointsToTest = endpoints.slice(0, maxEndpoints);\n\n for (const endpoint of endpointsToTest) {\n const supported = await testRPCForEIP7702(endpoint, timeout);\n\n if (supported) {\n return true;\n }\n }\n\n return false;\n } catch (error) {\n return false;\n }\n}\n","/**\n * Web3 Passkey SDK\n * Passwordless authentication with encrypted wallets\n */\n\nimport { Web3Passkey } from \"./core/sdk\";\nimport type { Web3PasskeyConfig } from \"./core/config\";\n\nexport function createWeb3Passkey(config: Web3PasskeyConfig = {}): Web3Passkey {\n return new Web3Passkey(config);\n}\n\nexport type { Web3PasskeyConfig, StealthAddressConfig } from \"./core/config\";\nexport type { UserInfo, WalletInfo } from \"./types\";\nexport type { StealthKeys, StealthAddressResult } from \"./stealth\";\n\nexport {\n Web3PasskeyError,\n AuthenticationError,\n RegistrationError,\n WalletError,\n CryptoError,\n StorageError,\n ApiError,\n} from \"./core/errors\";\n\nexport { Web3Passkey } from \"./core/sdk\";\nexport { StealthAddressModule } from \"./stealth\";\n\nexport {\n canControlStealthAddress,\n generateStealthAddress,\n checkStealthAddress,\n computeStealthPrivateKey,\n deriveStealthKeys\n} from \"./stealth/crypto\";\n\nexport {\n generateBIP39Wallet,\n createWalletFromMnemonic,\n deriveWalletFromMnemonic,\n} from \"./wallet/generate\";\n\nexport default createWeb3Passkey;\n"],"mappings":"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EAAO,CACd,MAAM,IAAIC,EACR,0BACA,8BACAD,CACF,CACF,CACF,CAKA,MAAM,iBACJE,EACAE,EACkB,CAClB,GAAI,CACF,OAAO,MAAM,KAAK,SAAS,sBAAsBF,EAAOE,CAAY,CACtE,OAASJ,EAAO,CACd,MAAM,IAAIC,EACR,oCACA,mCACAD,CACF,CACF,CACF,CAKA,MAAM,gBACJE,EACAG,EACAC,EACkB,CAClB,GAAI,CACF,OAAO,MAAM,KAAK,SAAS,qBACzBJ,EACAG,EACAC,CACF,CACF,OAASN,EAAO,CACd,MAAM,IAAIC,EACR,mCACA,kCACAD,CACF,CACF,CACF,CAKA,MAAM,YACJE,EACAG,EACAE,EACAC,EACkB,CAClB,GAAI,CACF,OAAO,MAAM,KAAK,SAAS,iBACzBN,EACAG,EACAE,EACAC,CACF,CACF,OAASR,EAAO,CACd,MAAM,IAAIC,EACR,+BACA,8BACAD,CACF,CACF,CACF,CAKA,MAAM,gBACJE,EACAO,EACAC,EACkB,CAClB,GAAI,CACF,OAAO,MAAM,KAAK,SAAS,qBACzBR,EACAO,EACAC,CACF,CACF,OAASV,EAAO,CACd,MAAM,IAAIC,EACR,mCACA,kCACAD,CACF,CACF,CACF,CAKA,MAAM,mBACJE,EACAS,EACAC,EACAC,EAA6B,GACX,CAClB,GAAI,CACF,OAAO,MAAM,KAAK,SAAS,wBACzBX,EACAS,EACAC,EACAC,CACF,CACF,OAASb,EAAO,CACd,MAAM,IAAIC,EACR,uCACA,sCACAD,CACF,CACF,CACF,CASA,MAAM,iBAAiBc,EAAeC,EAAmC,CACvE,GAAI,CACF,OAAO,MAAM,KAAK,UAAU,iBAAiBD,EAAOC,CAAQ,CAC9D,OAASf,EAAO,CACd,MAAM,IAAIC,EACR,8BACA,sBACAD,CACF,CACF,CACF,CAKA,MAAM,kBACJgB,EACAC,EACAC,EACiB,CACjB,GAAI,CACF,OAAO,MAAM,KAAK,UAAU,kBAC1BF,EACAC,EACAC,CACF,CACF,OAASlB,EAAO,CACd,MAAM,IAAIC,EACR,gCACA,kBACAD,CACF,CACF,CACF,CAKA,gBAAg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","names":["Web3PasskeyError","AuthenticationError","RegistrationError","WalletError","CryptoError","StorageError","ApiError","init_errors","__esmMin","message","code","originalError","statusCode","storage_exports","__export","CredentialStorage","STORAGE_KEY_PREFIX","STORAGE_INDEX_KEY","init_storage","__esmMin","init_errors","storage","StorageError","credential","key","error","id","data","username","c","address","index","filtered","credId","bufferToBigInt","buffer","result","i","init_utils","__esmMin","ZKProofGenerator","init_proof_generator","__esmMin","init_errors","init_utils","type","artifacts","input","circuit","CryptoError","circuitInputs","poseidon","cleanOwnerAddress","cleanContractAddress","ownerHashResult","contractHashResult","ownerAddressHash","bufferToBigInt","contractAddressHash","inputs","proof","publicSignals","x","arr","error","value","blinding","leaf","pathIndices","pathElements","current","sibling","ZKProofVerifier","init_proof_verifier","__esmMin","init_errors","init_utils","type","artifacts","proof","circuit","CryptoError","error","proofs","expectedRoot","result","publicRoot","expectedCommitment","expectedThreshold","publicCommitment","publicThreshold","expectedMin","expectedMax","publicMin","publicMax","expectedAddress","expectedChallenge","publicAddress","publicChallenge","expectedContract","expectedHoldersRoot","expectedMinBalance","holdersRoot","contractAddress","minBalance","poseidon","cleanContract","hashResult","expectedContractHash","bufferToBigInt","signals","acc","signal","idx","maxAgeMs","zk_exports","__export","ZKProofModule","init_zk","__esmMin","init_errors","init_proof_generator","init_proof_verifier","config","ZKProofGenerator","ZKProofVerifier","input","error","Web3PasskeyError","proof","proofs","expectedRoot","expectedCommitment","expectedThreshold","expectedMin","expectedMax","expectedAddress","expectedChallenge","expectedContract","expectedHoldersRoot","expectedMinBalance","value","blinding","leaf","pathIndices","pathElements","type","artifacts","init_errors","startRegistration","validateEthereumAddress","address","validateUsername","username","assertEthereumAddress","address","validateEthereumAddress","assertUsername","username","validateUsername","init_storage","generateChallenge","array","register","options","username","ethereumAddress","assertUsername","assertEthereumAddress","storage","CredentialStorage","registrationOptions","credential","startRegistration","publicKey","attestationObject","attestationBuffer","base64ToArrayBuffer","error","RegistrationError","base64","base64Clean","binary","bytes","i","init_errors","init_storage","startAuthentication","generateChallenge","array","login","storage","CredentialStorage","authOptions","assertion","credential","verifyAssertion","signatureBuffer","base64ToArrayBuffer","error","AuthenticationError","publicKeyBuffer","publicKey","authenticatorData","clientDataJSON","clientDataJSONString","clientDataHash","signedData","signature","rawSignature","derToRaw","base64","base64Clean","binary","bytes","i","der","offset","rLength","sLength","raw","init_errors","DB_NAME","DB_VERSION","STORE_NAME","IndexedDBWalletStorage","resolve","reject","request","StorageError","db","data","ethereumAddress","init_errors","ethers","generateBIP39Wallet","mnemonic","mnemonicPhrase","error","WalletError","createWalletFromMnemonic","deriveWalletFromMnemonic","index","derivationPath","wallet","init_errors","deriveEncryptionKeyFromWebAuthn","credentialId","publicKey","keyMaterial","keyMaterialHash","importedKey","salt","error","CryptoError","encryptData","data","key","iv","encodedData","encrypted","combined","error","CryptoError","decryptData","encryptedData","char","decrypted","init_errors","init_errors","ethers","deriveStealthKeys","mnemonic","viewingWallet","spendingWallet","spendingPubKey","viewingPubKey","stealthMetaAddress","legacyMetaAddress","computeLegacyMetaAddress","error","CryptoError","generateStealthAddress","ephemeralWallet","ephemeralPubKey","sharedSecret","computeSharedSecret","hashedSharedSecret","viewTag","stealthPubKey","addPublicKeys","multiplyGeneratorByScalar","publicKeyToAddress","checkStealthAddress","viewingKey","stealthAddress","derivedAddress","computeStealthPrivateKey","spendingKey","addPrivateKeys","privateKey","publicKey","scalar","pubKey1","pubKey2","key1","key2","x1","y1","x2","y2","p","numerator","denominator","lambda","modInverse","x3","y3","compressPublicKey","privKey1","privKey2","n","k1","k2","x","y","a","m","oldR","oldS","quotient","compressedPubKey","uncompressedPubKey","pubKeyHash","viewingPubkey","spendingPubkey","combined","canControlStealthAddress","ephemeralPubkey","targetAddress","StealthAddressModule","config","getMnemonic","options","mnemonic","stealthKeys","deriveStealthKeys","stealthResult","generateStealthAddress","error","Web3PasskeyError","announcement","parseResult","checkStealthAddress","stealthPrivateKey","computeStealthPrivateKey","announcements","results","result","SessionManager","sessionDurationHours","mnemonic","credentialId","expiresAt","hours","DEFAULT_CONFIG","error","init_errors","DEFAULT_CHAINS_URL","cache","API_KEY_PATTERNS","requiresApiKey","rpcUrl","pattern","fetchChains","chainsJsonUrl","DEFAULT_CHAINS_URL","response","getChainsData","options","cacheDuration","now","data","getEndpoints","chainId","chain","c","EIP7702_SUPPORTED_CHAINS","testRPCForEIP7702","rpcUrl","timeout","controller","timeoutId","response","data","errorMsg","err","supportsEIP7702","chainId","getEndpointsFn","options","maxEndpoints","endpoints","endpointsToTest","endpoint","Web3Passkey","config","DEFAULT_CONFIG","IndexedDBWalletStorage","SessionManager","StealthAddressModule","requireAuth","zkConfig","ZKProofModule","forceAuth","cachedMnemonic","WalletError","walletData","login","publicKey","encryptionKey","deriveEncryptionKeyFromWebAuthn","mnemonic","decryptData","options","ethereumAddress","registrationResult","register","credential","credentialId","encryptedMnemonic","encryptData","error","result","AuthenticationError","wallet","generateBIP39Wallet","index","derived","deriveWalletFromMnemonic","authResult","message","Wallet","chainId","getEndpoints","supportsEIP7702","hours","init_errors","createWeb3Passkey","config","Web3Passkey","index_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/errors.ts","../src/auth/storage.ts","../src/wallet/crypto.ts","../src/backup/storage.ts","../src/backup/encryption.ts","../src/backup/zip-backup.ts","../src/backup/qr-backup.ts","../src/backup/manager.ts","../src/backup/types.ts","../src/backup/index.ts","../src/recovery/shamir.ts","../src/recovery/social.ts","../src/recovery/types.ts","../src/recovery/index.ts","../src/sync/vault.ts","../src/sync/device-manager.ts","../src/sync/platform-detect.ts","../src/sync/types.ts","../src/sync/index.ts","../src/education/simulator.ts","../src/education/explainers.ts","../src/education/index.ts","../src/auth/register.ts","../src/utils/validation.ts","../src/auth/authenticate.ts","../src/wallet/storage.ts","../src/wallet/generate.ts","../src/core/sdk.ts","../src/stealth/index.ts","../src/stealth/crypto.ts","../src/core/session.ts","../src/core/config.ts","../src/chainlist/index.ts","../src/eip7702/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Custom error classes for better error handling\n */\n\nexport class Web3PasskeyError extends Error {\n constructor(\n message: string,\n public code: string,\n public originalError?: unknown\n ) {\n super(message);\n this.name = \"Web3PasskeyError\";\n }\n}\n\nexport class AuthenticationError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"AUTHENTICATION_ERROR\", originalError);\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class RegistrationError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"REGISTRATION_ERROR\", originalError);\n this.name = \"RegistrationError\";\n }\n}\n\nexport class WalletError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"WALLET_ERROR\", originalError);\n this.name = \"WalletError\";\n }\n}\n\nexport class CryptoError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"CRYPTO_ERROR\", originalError);\n this.name = \"CryptoError\";\n }\n}\n\nexport class StorageError extends Web3PasskeyError {\n constructor(message: string, originalError?: unknown) {\n super(message, \"STORAGE_ERROR\", originalError);\n this.name = \"StorageError\";\n }\n}\n\nexport class ApiError extends Web3PasskeyError {\n constructor(\n message: string,\n public statusCode?: number,\n originalError?: unknown\n ) {\n super(message, \"API_ERROR\", originalError);\n this.name = \"ApiError\";\n }\n}\n","import { StorageError } from \"../core/errors\";\n\nconst STORAGE_KEY_PREFIX = \"w3pk_credential_\";\nconst STORAGE_INDEX_KEY = \"w3pk_credential_index\";\n\nexport interface StoredCredential {\n id: string;\n publicKey: string;\n username: string;\n ethereumAddress: string;\n createdAt: number;\n lastUsed: number;\n}\n\nexport class CredentialStorage {\n private storage: Storage;\n\n constructor(storage?: Storage) {\n if (storage) {\n this.storage = storage;\n } else if (typeof window !== \"undefined\" && window.localStorage) {\n this.storage = window.localStorage;\n } else {\n throw new StorageError(\"localStorage is not available\");\n }\n }\n\n saveCredential(credential: StoredCredential): void {\n try {\n const key = `${STORAGE_KEY_PREFIX}${credential.id}`;\n this.storage.setItem(key, JSON.stringify(credential));\n this.addToIndex(credential.id);\n } catch (error) {\n throw new StorageError(\"Failed to save credential\", error);\n }\n }\n\n getCredentialById(id: string): StoredCredential | null {\n try {\n const key = `${STORAGE_KEY_PREFIX}${id}`;\n const data = this.storage.getItem(key);\n if (!data) {\n return null;\n }\n return JSON.parse(data) as StoredCredential;\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credential\", error);\n }\n }\n\n getCredentialByUsername(username: string): StoredCredential | null {\n try {\n const credentials = this.getAllCredentials();\n return credentials.find((c) => c.username === username) || null;\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credential\", error);\n }\n }\n\n getCredentialByAddress(address: string): StoredCredential | null {\n try {\n const credentials = this.getAllCredentials();\n return (\n credentials.find(\n (c) => c.ethereumAddress.toLowerCase() === address.toLowerCase()\n ) || null\n );\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credential\", error);\n }\n }\n\n getAllCredentials(): StoredCredential[] {\n try {\n const index = this.getIndex();\n return index\n .map((id) => this.getCredentialById(id))\n .filter((c): c is StoredCredential => c !== null);\n } catch (error) {\n throw new StorageError(\"Failed to retrieve credentials\", error);\n }\n }\n\n userExists(username: string): boolean {\n return this.getCredentialByUsername(username) !== null;\n }\n\n updateLastUsed(id: string): void {\n try {\n const credential = this.getCredentialById(id);\n if (credential) {\n credential.lastUsed = Date.now();\n this.saveCredential(credential);\n }\n } catch (error) {\n throw new StorageError(\"Failed to update timestamp\", error);\n }\n }\n\n deleteCredential(id: string): void {\n try {\n const key = `${STORAGE_KEY_PREFIX}${id}`;\n this.storage.removeItem(key);\n this.removeFromIndex(id);\n } catch (error) {\n throw new StorageError(\"Failed to delete credential\", error);\n }\n }\n\n clearAll(): void {\n try {\n const index = this.getIndex();\n index.forEach((id) => {\n const key = `${STORAGE_KEY_PREFIX}${id}`;\n this.storage.removeItem(key);\n });\n this.storage.removeItem(STORAGE_INDEX_KEY);\n } catch (error) {\n throw new StorageError(\"Failed to clear credentials\", error);\n }\n }\n\n private getIndex(): string[] {\n try {\n const data = this.storage.getItem(STORAGE_INDEX_KEY);\n return data ? JSON.parse(data) : [];\n } catch (error) {\n return [];\n }\n }\n\n private addToIndex(id: string): void {\n const index = this.getIndex();\n if (!index.includes(id)) {\n index.push(id);\n this.storage.setItem(STORAGE_INDEX_KEY, JSON.stringify(index));\n }\n }\n\n private removeFromIndex(id: string): void {\n const index = this.getIndex();\n const filtered = index.filter((credId) => credId !== id);\n this.storage.setItem(STORAGE_INDEX_KEY, JSON.stringify(filtered));\n }\n}\n","/**\n * Cryptographic utilities for wallet encryption\n *\n * SECURITY: Encryption keys are derived from WebAuthn signatures of a fixed message.\n * This requires biometric/PIN authentication and provides true hardware-backed security.\n * Even with file system access, an attacker cannot decrypt without biometric authentication.\n */\n\nimport { CryptoError } from \"../core/errors\";\n\n/**\n * Fixed message used for deterministic signature generation\n * This ensures the same signature is produced every time for encryption/decryption\n */\nconst ENCRYPTION_MESSAGE = \"w3pk-wallet-encryption-v3\";\n\n/**\n * Converts base64url string to ArrayBuffer\n */\nfunction base64UrlToArrayBuffer(base64url: string): ArrayBuffer {\n const base64 = base64url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * Derives an encryption key from WebAuthn credential (RECOMMENDED)\n *\n * SECURITY: This provides authentication-gated encryption:\n * - Requires biometric/PIN to prove identity before decryption\n * - Uses credential ID + public key as deterministic key material\n * - WebAuthn authentication verifies user identity\n * - Session caching prevents repeated prompts (1 hour default)\n *\n * IMPORTANT: This is authentication-gated, not signature-encrypted.\n * An attacker with both localStorage AND IndexedDB access could decrypt,\n * BUT WebAuthn authentication is still required before SDK allows access.\n *\n * For stronger security at rest, consider server-based architecture.\n *\n * BROWSER SUPPORT:\n * ✅ Chrome 67+, Edge 18+, Firefox 60+, Safari 14+\n * ✅ iOS 14.5+, Android 9+\n * ❌ Older browsers/devices - will throw NotSupportedError\n *\n * @param credentialId - The credential ID (base64url encoded)\n * @param publicKey - The public key (base64url encoded, optional)\n * @returns Encryption key derived from credential metadata\n * @throws CryptoError if derivation fails\n */\nexport async function deriveEncryptionKeyFromWebAuthn(\n credentialId: string,\n publicKey?: string\n): Promise<CryptoKey> {\n try {\n // Use credential ID + public key as deterministic key material\n // This is the same every time for a given credential\n const keyMaterial = publicKey\n ? `w3pk-v4:${credentialId}:${publicKey}`\n : `w3pk-v4:${credentialId}`;\n\n const keyMaterialHash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(keyMaterial)\n );\n\n const importedKey = await crypto.subtle.importKey(\n \"raw\",\n keyMaterialHash,\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"]\n );\n\n // Use a fixed salt for deterministic derivation\n const salt = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(\"w3pk-salt-v4\")\n );\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: new Uint8Array(salt),\n iterations: 210000, // OWASP 2023 recommendation\n hash: \"SHA-256\",\n },\n importedKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n } catch (error: any) {\n throw new CryptoError(\"Failed to derive encryption key from WebAuthn\", error);\n }\n}\n\n/**\n * Derives an encryption key from credential ID (FALLBACK - WEAKER SECURITY)\n *\n * WARNING: This method does NOT require biometric authentication for decryption.\n * An attacker with file system access can decrypt the wallet.\n * Use only as fallback for unsupported platforms.\n *\n * @param credentialId - Unique credential identifier\n * @param publicKey - Public key from the credential (optional, for additional entropy)\n * @deprecated Use deriveEncryptionKeyFromWebAuthn for true biometric protection\n */\nexport async function deriveEncryptionKey(\n credentialId: string,\n publicKey?: string\n): Promise<CryptoKey> {\n try {\n // Create deterministic key material from credential ID and optional public key\n const keyMaterial = publicKey\n ? `w3pk-v2:${credentialId}:${publicKey}`\n : `w3pk-v2:${credentialId}`;\n\n const keyMaterialHash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(keyMaterial)\n );\n\n // Import as key material\n const importedKey = await crypto.subtle.importKey(\n \"raw\",\n keyMaterialHash,\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"]\n );\n\n // Use a fixed salt for deterministic derivation\n const salt = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(\"w3pk-salt-v2\")\n );\n\n // Derive the actual encryption key with strong parameters\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: new Uint8Array(salt),\n iterations: 210000, // OWASP 2023 recommendation\n hash: \"SHA-256\",\n },\n importedKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n } catch (error) {\n throw new CryptoError(\"Failed to derive encryption key\", error);\n }\n}\n\n/**\n * Derives encryption key from a raw signature (for testing/legacy)\n *\n * WARNING: This is a fallback method that doesn't require WebAuthn.\n * Use deriveEncryptionKeyFromWebAuthn in production for true biometric protection.\n *\n * @param signature - Raw signature bytes\n * @param credentialId - Credential ID for salt\n */\nexport async function deriveEncryptionKeyFromSignature(\n signature: ArrayBuffer,\n credentialId: string\n): Promise<CryptoKey> {\n try {\n // Try WebAuthn first if available\n if (typeof window !== 'undefined' && window.PublicKeyCredential) {\n return deriveEncryptionKeyFromWebAuthn(credentialId);\n }\n\n // Fallback: Derive from provided signature (for testing/Node.js)\n const signatureHash = await crypto.subtle.digest(\"SHA-256\", signature);\n\n const importedKey = await crypto.subtle.importKey(\n \"raw\",\n signatureHash,\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"]\n );\n\n const salt = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(\"w3pk-salt-v3:\" + credentialId)\n );\n\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: new Uint8Array(salt),\n iterations: 210000,\n hash: \"SHA-256\",\n },\n importedKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n } catch (error) {\n throw new CryptoError(\"Failed to derive encryption key\", error);\n }\n}\n\n/**\n * Generates a cryptographic challenge for WebAuthn authentication\n */\nexport function generateChallenge(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return btoa(String.fromCharCode(...array))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\n/**\n * Encrypts data using AES-GCM\n */\nexport async function encryptData(\n data: string,\n key: CryptoKey\n): Promise<string> {\n try {\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const encodedData = new TextEncoder().encode(data);\n\n const encrypted = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n encodedData\n );\n\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return btoa(String.fromCharCode(...combined));\n } catch (error) {\n throw new CryptoError(\"Failed to encrypt data\", error);\n }\n}\n\n/**\n * Decrypts data using AES-GCM\n */\nexport async function decryptData(\n encryptedData: string,\n key: CryptoKey\n): Promise<string> {\n try {\n if (!encryptedData || encryptedData.length < 16) {\n throw new Error(\"Invalid encrypted data: too small\");\n }\n\n const combined = new Uint8Array(\n atob(encryptedData)\n .split(\"\")\n .map((char) => char.charCodeAt(0))\n );\n\n if (combined.length < 12) {\n throw new Error(\"Invalid encrypted data: missing IV\");\n }\n\n const iv = combined.slice(0, 12);\n const encrypted = combined.slice(12);\n\n if (encrypted.length === 0) {\n throw new Error(\"Invalid encrypted data: no content\");\n }\n\n const decrypted = await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv },\n key,\n encrypted\n );\n\n return new TextDecoder().decode(decrypted);\n } catch (error) {\n throw new CryptoError(\n `Data decryption failed: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n error\n );\n }\n}\n","/**\n * IndexedDB Storage for Backup Metadata\n */\n\nimport type { BackupMetadata } from './types';\n\nexport class BackupStorage {\n private dbName = 'Web3PasskeyBackup';\n private version = 1;\n private db: IDBDatabase | null = null;\n\n /**\n * Initialize the database\n */\n async init(): Promise<void> {\n // Skip initialization in non-browser environments\n if (typeof indexedDB === 'undefined') {\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, this.version);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.db = request.result;\n resolve();\n };\n\n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create backups object store\n if (!db.objectStoreNames.contains('backups')) {\n const store = db.createObjectStore('backups', { keyPath: 'id' });\n store.createIndex('ethereumAddress', 'ethereumAddress', {\n unique: false,\n });\n store.createIndex('method', 'method', { unique: false });\n store.createIndex('createdAt', 'createdAt', { unique: false });\n }\n };\n });\n }\n\n /**\n * Store backup metadata\n */\n async storeBackupMetadata(metadata: BackupMetadata): Promise<void> {\n if (!this.db) await this.init();\n if (!this.db) return Promise.resolve(); // Non-browser environment\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction(['backups'], 'readwrite');\n const store = transaction.objectStore('backups');\n const request = store.put(metadata);\n\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Get all backups for an address\n */\n async getBackupsByAddress(\n ethereumAddress: string\n ): Promise<BackupMetadata[]> {\n if (!this.db) await this.init();\n if (!this.db) return Promise.resolve([]); // Non-browser environment\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction(['backups'], 'readonly');\n const store = transaction.objectStore('backups');\n const index = store.index('ethereumAddress');\n const request = index.getAll(ethereumAddress);\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Get backup by ID\n */\n async getBackupById(id: string): Promise<BackupMetadata | null> {\n if (!this.db) await this.init();\n if (!this.db) return Promise.resolve(null); // Non-browser environment\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction(['backups'], 'readonly');\n const store = transaction.objectStore('backups');\n const request = store.get(id);\n\n request.onsuccess = () => resolve(request.result || null);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Delete backup metadata\n */\n async deleteBackup(id: string): Promise<void> {\n if (!this.db) await this.init();\n if (!this.db) return Promise.resolve(); // Non-browser environment\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction(['backups'], 'readwrite');\n const store = transaction.objectStore('backups');\n const request = store.delete(id);\n\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Get count of backups by method\n */\n async getBackupCountByMethod(\n method: 'zip' | 'qr' | 'file'\n ): Promise<number> {\n if (!this.db) await this.init();\n if (!this.db) return Promise.resolve(0); // Non-browser environment\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction(['backups'], 'readonly');\n const store = transaction.objectStore('backups');\n const index = store.index('method');\n const request = index.count(method);\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n}\n","/**\n * Encryption utilities for backup system\n * Uses PBKDF2 + AES-256-GCM for password-based encryption\n */\n\n/**\n * Derive encryption key from password using PBKDF2\n * @param password - User's password\n * @param salt - Crypto salt (32 bytes recommended)\n * @param iterations - PBKDF2 iterations (310,000 for OWASP 2025)\n */\nexport async function deriveKeyFromPassword(\n password: string,\n salt: Uint8Array,\n iterations: number = 310000\n): Promise<CryptoKey> {\n const encoder = new TextEncoder();\n const passwordBuffer = encoder.encode(password);\n\n // Import password as key material\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBuffer,\n 'PBKDF2',\n false,\n ['deriveBits', 'deriveKey']\n );\n\n // Derive AES-256 key using PBKDF2\n return crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n/**\n * Encrypt data with AES-256-GCM\n */\nexport async function encryptWithPassword(\n data: string,\n password: string,\n salt: Uint8Array\n): Promise<{\n encrypted: string;\n iv: string;\n salt: string;\n iterations: number;\n}> {\n const iterations = 310000;\n const key = await deriveKeyFromPassword(password, salt, iterations);\n\n const encoder = new TextEncoder();\n const dataBuffer = encoder.encode(data);\n\n const iv = crypto.getRandomValues(new Uint8Array(12));\n\n const encryptedBuffer = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n dataBuffer\n );\n\n return {\n encrypted: bufferToBase64(encryptedBuffer),\n iv: bufferToBase64(iv),\n salt: bufferToBase64(salt),\n iterations,\n };\n}\n\n/**\n * Decrypt data with AES-256-GCM\n */\nexport async function decryptWithPassword(\n encryptedData: string,\n password: string,\n salt: string,\n iv: string,\n iterations: number = 310000\n): Promise<string> {\n const saltBuffer = base64ToBuffer(salt);\n const key = await deriveKeyFromPassword(password, saltBuffer, iterations);\n\n const ivBuffer = base64ToBuffer(iv);\n const encryptedBuffer = base64ToBuffer(encryptedData);\n\n const decryptedBuffer = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv: ivBuffer as BufferSource,\n },\n key,\n encryptedBuffer as BufferSource\n );\n\n const decoder = new TextDecoder();\n return decoder.decode(decryptedBuffer);\n}\n\n/**\n * Get device fingerprint for binding backups to specific device\n * Note: This is NOT cryptographically strong, just a convenience feature\n */\nexport async function getDeviceFingerprint(): Promise<string> {\n const components = [\n navigator.userAgent,\n navigator.language,\n new Date().getTimezoneOffset().toString(),\n screen.width + 'x' + screen.height,\n screen.colorDepth.toString(),\n ];\n\n const fingerprintString = components.join('|');\n const encoder = new TextEncoder();\n const buffer = encoder.encode(fingerprintString);\n\n const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);\n return bufferToBase64(hashBuffer);\n}\n\n/**\n * Derive address checksum for verification\n */\nexport async function deriveAddressChecksum(\n ethereumAddress: string\n): Promise<string> {\n const encoder = new TextEncoder();\n const buffer = encoder.encode(ethereumAddress.toLowerCase());\n const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);\n return bufferToBase64(hashBuffer).substring(0, 16);\n}\n\n/**\n * Validate password strength\n */\nexport function validatePasswordStrength(password: string): {\n valid: boolean;\n score: number; // 0-100\n feedback: string[];\n} {\n const feedback: string[] = [];\n let score = 0;\n\n // Length check\n if (password.length < 12) {\n feedback.push('Password must be at least 12 characters');\n } else {\n score += 25;\n }\n\n // Uppercase check\n if (!/[A-Z]/.test(password)) {\n feedback.push('Add at least one uppercase letter');\n } else {\n score += 15;\n }\n\n // Lowercase check\n if (!/[a-z]/.test(password)) {\n feedback.push('Add at least one lowercase letter');\n } else {\n score += 15;\n }\n\n // Number check\n if (!/[0-9]/.test(password)) {\n feedback.push('Add at least one number');\n } else {\n score += 15;\n }\n\n // Special character check\n if (!/[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password)) {\n feedback.push('Add at least one special character');\n } else {\n score += 15;\n }\n\n // Length bonus\n if (password.length >= 16) {\n score += 10;\n }\n if (password.length >= 20) {\n score += 5;\n }\n\n // Common password check (simple version)\n const commonPasswords = [\n 'password',\n '12345678',\n 'qwerty',\n 'abc123',\n 'password123',\n 'admin',\n 'letmein',\n ];\n if (\n commonPasswords.some((common) => password.toLowerCase().includes(common))\n ) {\n feedback.push('Password is too common');\n score = Math.min(score, 25);\n }\n\n return {\n valid: score >= 50 && feedback.length === 0,\n score: Math.min(score, 100),\n feedback,\n };\n}\n\n/**\n * Helper: Convert ArrayBuffer to Base64\n */\nfunction bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * Helper: Convert Base64 to ArrayBuffer\n */\nfunction base64ToBuffer(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","/**\n * Password-protected ZIP backup creation\n * Creates encrypted backup packages with recovery instructions\n */\n\nimport type { ZipBackupOptions, BackupMetadata } from './types';\nimport {\n encryptWithPassword,\n getDeviceFingerprint,\n deriveAddressChecksum,\n validatePasswordStrength,\n} from './encryption';\n\nexport class ZipBackupCreator {\n /**\n * Create password-protected ZIP backup\n * Returns a Blob that can be downloaded\n */\n async createZipBackup(\n mnemonic: string,\n ethereumAddress: string,\n options: ZipBackupOptions\n ): Promise<{ blob: Blob; metadata: BackupMetadata }> {\n // Validate password strength\n const passwordValidation = validatePasswordStrength(options.password);\n if (!passwordValidation.valid) {\n throw new Error(\n `Weak password: ${passwordValidation.feedback.join(', ')}`\n );\n }\n\n // Generate salt\n const salt = crypto.getRandomValues(new Uint8Array(32));\n\n // Encrypt mnemonic\n const encrypted = await encryptWithPassword(\n mnemonic,\n options.password,\n salt\n );\n\n // Get device fingerprint if binding enabled\n const deviceFingerprint = options.deviceBinding\n ? await getDeviceFingerprint()\n : undefined;\n\n // Create metadata\n const metadata: BackupMetadata = {\n id: crypto.randomUUID(),\n ethereumAddress,\n method: 'zip',\n createdAt: Date.now(),\n deviceFingerprint,\n addressChecksum: await deriveAddressChecksum(ethereumAddress),\n };\n\n // Create backup data structure\n const backupData = {\n version: 1,\n encrypted: encrypted.encrypted,\n iv: encrypted.iv,\n salt: encrypted.salt,\n iterations: encrypted.iterations,\n metadata,\n deviceFingerprint,\n };\n\n // Create files for ZIP\n const files = new Map<string, string>();\n\n // 1. Encrypted recovery phrase\n files.set('recovery-phrase.txt.enc', JSON.stringify(backupData, null, 2));\n\n // 2. Metadata (unencrypted)\n files.set(\n 'metadata.json',\n JSON.stringify(\n {\n address: ethereumAddress,\n createdAt: new Date(metadata.createdAt).toISOString(),\n backupId: metadata.id,\n addressChecksum: metadata.addressChecksum,\n },\n null,\n 2\n )\n );\n\n // 3. Recovery instructions\n if (options.includeInstructions !== false) {\n files.set('RECOVERY_INSTRUCTIONS.txt', this.getRecoveryInstructions());\n }\n\n // Create ZIP file (using simple implementation since JSZip might not be available)\n const blob = await this.createSimpleZip(files);\n\n return { blob, metadata };\n }\n\n /**\n * Create a simple ZIP file from files map\n * Note: For production, consider using JSZip library\n * This is a simplified version that creates a text archive\n */\n private async createSimpleZip(\n files: Map<string, string>\n ): Promise<Blob> {\n // For now, create a JSON archive\n // In production, use JSZip library for proper ZIP format\n const archive: Record<string, string> = {};\n files.forEach((content, filename) => {\n archive[filename] = content;\n });\n\n return new Blob([JSON.stringify(archive, null, 2)], {\n type: 'application/json',\n });\n }\n\n /**\n * Get recovery instructions text\n */\n private getRecoveryInstructions(): string {\n return `\nW3PK WALLET RECOVERY INSTRUCTIONS\n=================================\n\nThis backup contains your encrypted wallet recovery phrase.\n\nIMPORTANT:\n- Keep this file safe and secure\n- You NEED the password you set during backup creation\n- Without the password, this backup cannot be decrypted\n\nRECOVERY STEPS:\n--------------\n\n1. Go to the w3pk recovery page\n URL: https://your-w3pk-app.com/recover\n\n2. Click \"Import from Backup\"\n\n3. Upload this backup file\n\n4. Enter your backup password\n\n5. System will decrypt and verify your wallet\n\n6. Your wallet will be restored!\n\nVERIFICATION:\n------------\n\nAfter recovery, verify that the Ethereum address matches:\n- Check the address in metadata.json\n- Compare with your known wallet address\n- If they match, recovery was successful ✓\n\nSECURITY NOTES:\n--------------\n\n✓ This backup is encrypted with AES-256-GCM\n✓ Your password is required to decrypt\n✓ Store this backup in a secure location:\n - Password manager (1Password, Bitwarden)\n - Encrypted cloud storage (Google Drive, Dropbox)\n - USB drive in safe\n - Physical storage in safe deposit box\n\n✗ Do NOT store in:\n - Unencrypted email\n - Shared drives\n - Public cloud without password protection\n\nALTERNATIVE RECOVERY:\n-------------------\n\nIf you lose this backup, you can still recover using:\n- Your 12-word recovery phrase (if saved separately)\n- Social recovery (if configured)\n- Passkey sync (if enabled on another device)\n\nNEED HELP?\n---------\n\nVisit: https://docs.w3pk.org/recovery\nEmail: support@w3pk.org\n\nGenerated: ${new Date().toISOString()}\n`;\n }\n\n /**\n * Decrypt and restore from ZIP backup\n */\n async restoreFromZipBackup(\n backupData: string,\n password: string\n ): Promise<{ mnemonic: string; metadata: BackupMetadata }> {\n // Parse backup data\n const data = JSON.parse(backupData);\n\n if (data.version !== 1) {\n throw new Error('Unsupported backup version');\n }\n\n // Decrypt mnemonic\n const { decryptWithPassword } = await import('./encryption');\n const mnemonic = await decryptWithPassword(\n data.encrypted,\n password,\n data.salt,\n data.iv,\n data.iterations\n );\n\n // Verify checksum\n const { Wallet } = await import('ethers');\n const wallet = Wallet.fromPhrase(mnemonic);\n const addressChecksum = await deriveAddressChecksum(wallet.address);\n\n if (addressChecksum !== data.metadata.addressChecksum) {\n throw new Error('Address checksum mismatch - corrupted backup or wrong password');\n }\n\n return {\n mnemonic,\n metadata: data.metadata,\n };\n }\n}\n","/**\n * QR Code backup creation\n * Generates scannable QR codes with encrypted mnemonic\n */\n\nimport type { QRBackupOptions } from './types';\nimport {\n encryptWithPassword,\n deriveAddressChecksum,\n} from './encryption';\n\nexport class QRBackupCreator {\n /**\n * Create QR code backup\n * @param mnemonic - The mnemonic to backup\n * @param ethereumAddress - Associated Ethereum address\n * @param options - QR backup options\n * @returns Data URL for QR code image and instructions\n */\n async createQRBackup(\n mnemonic: string,\n ethereumAddress: string,\n options: QRBackupOptions = {}\n ): Promise<{\n qrCodeDataURL: string;\n rawData: string;\n instructions: string;\n }> {\n const errorCorrection = options.errorCorrection || 'H'; // 30% damage tolerance\n\n let qrData: any;\n\n if (options.password) {\n // Encrypted QR code\n const salt = crypto.getRandomValues(new Uint8Array(32));\n const encrypted = await encryptWithPassword(\n mnemonic,\n options.password,\n salt\n );\n\n qrData = {\n version: 1,\n type: 'encrypted',\n data: encrypted.encrypted,\n iv: encrypted.iv,\n salt: encrypted.salt,\n iterations: encrypted.iterations,\n checksum: await deriveAddressChecksum(ethereumAddress),\n };\n } else {\n // Plain QR code (not recommended for production wallets)\n qrData = {\n version: 1,\n type: 'plain',\n data: mnemonic,\n checksum: await deriveAddressChecksum(ethereumAddress),\n };\n }\n\n const rawData = JSON.stringify(qrData);\n\n // Generate QR code\n const qrCodeDataURL = await this.generateQRCode(rawData, errorCorrection);\n\n // Generate instructions\n const instructions = this.getInstructions(\n ethereumAddress,\n !!options.password\n );\n\n return {\n qrCodeDataURL,\n rawData,\n instructions,\n };\n }\n\n /**\n * Generate QR code from data\n * Uses Canvas API to generate QR code without external dependencies\n */\n private async generateQRCode(\n data: string,\n errorCorrection: string\n ): Promise<string> {\n // For production, use 'qrcode' npm package\n // This is a placeholder that creates a data URL\n\n // Try to use qrcode library if available\n try {\n const QRCode = (await import('qrcode')).default;\n return await QRCode.toDataURL(data, {\n errorCorrectionLevel: errorCorrection as any,\n width: 512,\n margin: 2,\n });\n } catch {\n // Fallback: Create a simple text representation\n // In production, always include 'qrcode' package\n return this.createFallbackQRDataURL(data);\n }\n }\n\n /**\n * Create fallback QR representation\n */\n private createFallbackQRDataURL(data: string): string {\n // Check if we're in a browser environment\n if (typeof document === 'undefined') {\n // Node.js environment - return a simple data URL with text\n return `data:text/plain;base64,${Buffer.from(data).toString('base64')}`;\n }\n\n // Create a canvas with text (fallback)\n const canvas = document.createElement('canvas');\n canvas.width = 512;\n canvas.height = 512;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Canvas not supported');\n }\n\n // White background\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, 512, 512);\n\n // Black text\n ctx.fillStyle = 'black';\n ctx.font = '12px monospace';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Wrap text\n const lines = this.wrapText(data, 50);\n const lineHeight = 14;\n const startY = 256 - (lines.length * lineHeight) / 2;\n\n lines.forEach((line, i) => {\n ctx.fillText(line, 256, startY + i * lineHeight);\n });\n\n // Add note\n ctx.font = 'bold 16px sans-serif';\n ctx.fillText('Install \"qrcode\" package for QR codes', 256, 480);\n\n return canvas.toDataURL('image/png');\n }\n\n /**\n * Wrap text for display\n */\n private wrapText(text: string, maxLength: number): string[] {\n const lines: string[] = [];\n for (let i = 0; i < text.length; i += maxLength) {\n lines.push(text.substring(i, i + maxLength));\n }\n return lines;\n }\n\n /**\n * Get recovery instructions for QR backup\n */\n private getInstructions(\n ethereumAddress: string,\n encrypted: boolean\n ): string {\n return `\nW3PK QR CODE BACKUP\n==================\n\nEthereum Address: ${ethereumAddress}\nBackup Date: ${new Date().toISOString()}\nType: ${encrypted ? 'Encrypted' : 'Plain'}\n\nSTORAGE INSTRUCTIONS:\n--------------------\n\n📸 Print this QR code and store securely:\n ✓ Safe deposit box\n ✓ Home safe\n ✓ Trusted family member\n ✓ Multiple physical locations\n\n⚠️ DO NOT:\n ✗ Store digitally (screenshot/photo)\n ✗ Upload to cloud\n ✗ Email or message\n ✗ Share publicly\n\nRECOVERY STEPS:\n--------------\n\n1. Scan QR code with your phone camera or QR scanner app\n\n2. Import the scanned data to w3pk recovery page\n\n3. ${encrypted ? 'Enter your backup password' : 'No password needed (plain backup)'}\n\n4. Wallet will be restored\n\nSECURITY NOTES:\n--------------\n\n${\n encrypted\n ? `\n✓ This QR code is ENCRYPTED\n✓ Password required to decrypt\n✓ Safe to store in multiple locations\n✓ Share with trusted family (they can't access without password)\n`\n : `\n⚠️ This QR code is NOT ENCRYPTED\n⚠️ Anyone with access can recover your wallet\n⚠️ Store with maximum security\n⚠️ Do not photograph or copy\n`\n}\n\nERROR CORRECTION:\n----------------\n\nThis QR code has HIGH error correction (30% damage tolerance)\n- Can survive partial damage\n- Can handle folding/creasing\n- Ensure good print quality\n\nVERIFICATION:\n------------\n\nAddress checksum is embedded in QR code\nAfter scanning, verify address matches: ${ethereumAddress}\n\nALTERNATIVE RECOVERY:\n-------------------\n\nIf QR code is lost/damaged, you can still recover using:\n- Encrypted ZIP backup\n- Social recovery\n- Passkey sync\n- Manual mnemonic entry (if you wrote down the words)\n\n---\n\nGenerated by w3pk Recovery System\nhttps://docs.w3pk.org/recovery\n`;\n }\n\n /**\n * Restore from scanned QR data\n */\n async restoreFromQR(\n qrData: string,\n password?: string\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n const data = JSON.parse(qrData);\n\n if (data.version !== 1) {\n throw new Error('Unsupported QR backup version');\n }\n\n let mnemonic: string;\n\n if (data.type === 'encrypted') {\n if (!password) {\n throw new Error('Password required for encrypted QR backup');\n }\n\n const { decryptWithPassword } = await import('./encryption');\n mnemonic = await decryptWithPassword(\n data.data,\n password,\n data.salt,\n data.iv,\n data.iterations\n );\n } else if (data.type === 'plain') {\n mnemonic = data.data;\n } else {\n throw new Error('Unknown QR backup type');\n }\n\n // Verify checksum\n const { Wallet } = await import('ethers');\n const wallet = Wallet.fromPhrase(mnemonic);\n const addressChecksum = await deriveAddressChecksum(wallet.address);\n\n if (addressChecksum !== data.checksum) {\n throw new Error('Address checksum mismatch - corrupted QR or wrong password');\n }\n\n return {\n mnemonic,\n ethereumAddress: wallet.address,\n };\n }\n}\n","/**\n * Main Backup Manager\n * Orchestrates all backup and recovery operations\n */\n\nimport type {\n BackupStatus,\n SecurityScore,\n ZipBackupOptions,\n QRBackupOptions,\n RecoveryScenario,\n SimulationResult,\n BackupMetadata,\n EncryptedBackupInfo,\n} from './types';\nimport { BackupStorage } from './storage';\nimport { ZipBackupCreator } from './zip-backup';\nimport { QRBackupCreator } from './qr-backup';\n\nexport class BackupManager {\n private storage: BackupStorage;\n private zipCreator: ZipBackupCreator;\n private qrCreator: QRBackupCreator;\n\n constructor() {\n this.storage = new BackupStorage();\n this.zipCreator = new ZipBackupCreator();\n this.qrCreator = new QRBackupCreator();\n }\n\n /**\n * Get comprehensive backup status\n * Shows user exactly what protects their wallet\n */\n async getBackupStatus(ethereumAddress: string): Promise<BackupStatus> {\n // Get all backups for this address\n const backups = await this.storage.getBackupsByAddress(ethereumAddress);\n\n // Detect passkey sync capabilities\n const passkeySync = await this.detectPasskeySync();\n\n // Get encrypted backup info\n const encryptedBackups: EncryptedBackupInfo[] = backups.map((backup) => ({\n id: backup.id,\n method: backup.method,\n location: 'local', // Could be enhanced to track cloud storage\n createdAt: backup.createdAt,\n deviceFingerprint: backup.deviceFingerprint,\n }));\n\n // Build status\n const status: BackupStatus = {\n passkeySync,\n recoveryPhrase: {\n verified: false, // Can be enhanced with verification system\n verificationCount: 0,\n encryptedBackups,\n },\n securityScore: this.calculateSecurityScore(passkeySync, encryptedBackups),\n };\n\n return status;\n }\n\n /**\n * Detect passkey sync capabilities\n */\n private async detectPasskeySync() {\n // Return default values in non-browser environments\n if (typeof navigator === 'undefined') {\n return {\n enabled: false,\n deviceCount: 0,\n lastSyncTime: undefined,\n platform: 'unknown' as const,\n };\n }\n\n // Detect platform\n const userAgent = navigator.userAgent.toLowerCase();\n let platform: 'apple' | 'google' | 'microsoft' | 'unknown' = 'unknown';\n\n if (userAgent.includes('mac') || userAgent.includes('iphone') || userAgent.includes('ipad')) {\n platform = 'apple';\n } else if (userAgent.includes('android')) {\n platform = 'google';\n } else if (userAgent.includes('windows')) {\n platform = 'microsoft';\n }\n\n // Check if WebAuthn supports resident credentials (required for sync)\n const supportsResidentKeys = await this.checkResidentKeySupport();\n\n // Estimate device count (simplified - in production, track via server)\n const deviceCount = 1; // Current device\n\n return {\n enabled: supportsResidentKeys,\n deviceCount,\n lastSyncTime: supportsResidentKeys ? Date.now() : undefined,\n platform,\n };\n }\n\n /**\n * Check if platform supports resident keys (required for passkey sync)\n */\n private async checkResidentKeySupport(): Promise<boolean> {\n if (typeof window === 'undefined' || !window.PublicKeyCredential) {\n return false;\n }\n\n try {\n // Check if platform authenticator is available\n const available =\n await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n return available;\n } catch {\n return false;\n }\n }\n\n /**\n * Calculate security score\n */\n private calculateSecurityScore(\n passkeySync: any,\n encryptedBackups: EncryptedBackupInfo[]\n ): SecurityScore {\n const breakdown = {\n passkeyActive: passkeySync.enabled ? 20 : 0,\n passkeyMultiDevice: passkeySync.deviceCount > 1 ? 10 : 0,\n phraseVerified: 0, // Can be enhanced with verification\n encryptedBackup: encryptedBackups.length > 0 ? 20 : 0,\n socialRecovery: 0, // Will be added in Phase 4\n };\n\n const total = Object.values(breakdown).reduce((sum, val) => sum + val, 0);\n\n let level: SecurityScore['level'];\n let nextMilestone: string;\n\n if (total <= 20) {\n level = 'vulnerable';\n nextMilestone = 'Create encrypted backup to reach \"protected\" (40+ pts)';\n } else if (total <= 50) {\n level = 'protected';\n nextMilestone = 'Set up social recovery to reach \"secured\" (70+ pts)';\n } else if (total <= 80) {\n level = 'secured';\n nextMilestone = 'Enable all methods to reach \"fort-knox\" (100 pts)';\n } else {\n level = 'fort-knox';\n nextMilestone = 'Maximum security achieved! 🏆';\n }\n\n return {\n total,\n breakdown,\n level,\n nextMilestone,\n };\n }\n\n /**\n * Create password-protected ZIP backup\n */\n async createZipBackup(\n mnemonic: string,\n ethereumAddress: string,\n options: ZipBackupOptions\n ): Promise<Blob> {\n const { blob, metadata } = await this.zipCreator.createZipBackup(\n mnemonic,\n ethereumAddress,\n options\n );\n\n // Store metadata\n await this.storage.storeBackupMetadata(metadata);\n\n return blob;\n }\n\n /**\n * Create QR code backup\n */\n async createQRBackup(\n mnemonic: string,\n ethereumAddress: string,\n options?: QRBackupOptions\n ): Promise<{\n qrCodeDataURL: string;\n instructions: string;\n }> {\n const { qrCodeDataURL, rawData, instructions } =\n await this.qrCreator.createQRBackup(mnemonic, ethereumAddress, options);\n\n // Store metadata\n const metadata: BackupMetadata = {\n id: crypto.randomUUID(),\n ethereumAddress,\n method: 'qr',\n createdAt: Date.now(),\n addressChecksum: JSON.parse(rawData).checksum,\n };\n\n await this.storage.storeBackupMetadata(metadata);\n\n return { qrCodeDataURL, instructions };\n }\n\n /**\n * Restore from ZIP backup\n */\n async restoreFromZipBackup(\n backupData: string,\n password: string\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n const { mnemonic, metadata } = await this.zipCreator.restoreFromZipBackup(\n backupData,\n password\n );\n\n return {\n mnemonic,\n ethereumAddress: metadata.ethereumAddress,\n };\n }\n\n /**\n * Restore from QR backup\n */\n async restoreFromQR(\n qrData: string,\n password?: string\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n return await this.qrCreator.restoreFromQR(qrData, password);\n }\n\n /**\n * Simulate recovery scenario (educational)\n */\n async simulateRecoveryScenario(\n scenario: RecoveryScenario,\n currentStatus: BackupStatus\n ): Promise<SimulationResult> {\n const methods: any[] = [];\n\n // Check available recovery methods based on scenario\n switch (scenario.type) {\n case 'lost-device':\n if (currentStatus.passkeySync.enabled && currentStatus.passkeySync.deviceCount > 1) {\n methods.push({\n method: 'Passkey Sync (iCloud/Google)',\n success: true,\n time: '5 minutes',\n requirements: ['Sign in to cloud account', 'Authenticate on new device'],\n });\n }\n\n if (currentStatus.recoveryPhrase.encryptedBackups.length > 0) {\n methods.push({\n method: 'Encrypted ZIP Backup',\n success: true,\n time: '2 minutes',\n requirements: ['Backup file', 'Password'],\n });\n }\n\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [`${currentStatus.socialRecovery.threshold} guardian shares`],\n });\n }\n break;\n\n case 'lost-phrase':\n if (currentStatus.passkeySync.enabled) {\n methods.push({\n method: 'Passkey (current device)',\n success: true,\n time: 'instant',\n requirements: ['Current device', 'Biometric/PIN'],\n });\n }\n\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [`${currentStatus.socialRecovery.threshold} guardian shares`],\n });\n }\n break;\n\n case 'lost-both':\n if (currentStatus.passkeySync.enabled && currentStatus.passkeySync.deviceCount > 1) {\n methods.push({\n method: 'Passkey Sync',\n success: true,\n time: '5 minutes',\n requirements: ['Cloud account access', 'New device'],\n });\n }\n\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [`${currentStatus.socialRecovery.threshold} guardian shares`],\n });\n }\n break;\n\n case 'switch-platform':\n if (currentStatus.recoveryPhrase.encryptedBackups.length > 0) {\n methods.push({\n method: 'Encrypted Backup',\n success: true,\n time: '2 minutes',\n requirements: ['Backup file', 'Password'],\n });\n }\n\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [`${currentStatus.socialRecovery.threshold} guardian shares`],\n });\n }\n break;\n }\n\n const success = methods.length > 0 && methods.some((m) => m.success);\n\n let educationalNote = '';\n if (success) {\n educationalNote = `✅ You're safe! ${methods.length} way${methods.length > 1 ? 's' : ''} to recover.\\n\\n`;\n educationalNote += 'Available recovery methods:\\n';\n methods.forEach((m) => {\n educationalNote += `- ${m.method} (~${m.time})\\n`;\n });\n } else {\n educationalNote = `❌ Wallet cannot be recovered in this scenario.\\n\\n`;\n educationalNote += 'Recommendation: Set up at least 2 backup methods to prevent total loss.';\n }\n\n return {\n scenario,\n success,\n availableMethods: methods,\n timeEstimate: success ? methods[0].time : 'N/A',\n educationalNote,\n };\n }\n}\n","/**\n * Backup and Recovery Type Definitions\n */\n\nexport interface BackupStatus {\n passkeySync: PasskeySyncStatus;\n recoveryPhrase: RecoveryPhraseStatus;\n socialRecovery?: SocialRecoveryStatus;\n securityScore: SecurityScore;\n}\n\nexport interface PasskeySyncStatus {\n enabled: boolean;\n deviceCount: number;\n lastSyncTime?: number;\n platform: 'apple' | 'google' | 'microsoft' | 'unknown';\n}\n\nexport interface RecoveryPhraseStatus {\n verified: boolean;\n verificationCount: number;\n lastVerified?: number;\n encryptedBackups: EncryptedBackupInfo[];\n}\n\nexport interface EncryptedBackupInfo {\n id: string;\n method: 'zip' | 'qr' | 'file';\n location: string;\n createdAt: number;\n deviceFingerprint?: string;\n}\n\nexport interface SocialRecoveryStatus {\n enabled: boolean;\n guardians: Guardian[];\n threshold: number;\n sharesDistributed: number;\n verifiedGuardians: number;\n}\n\nexport interface Guardian {\n id: string;\n name: string;\n email?: string;\n publicKey?: string;\n shareEncrypted: string;\n status: 'pending' | 'active' | 'revoked';\n addedAt: number;\n lastVerified?: number;\n}\n\nexport interface SecurityScore {\n total: number; // 0-100\n breakdown: {\n passkeyActive: number;\n passkeyMultiDevice: number;\n phraseVerified: number;\n encryptedBackup: number;\n socialRecovery: number;\n };\n level: 'vulnerable' | 'protected' | 'secured' | 'fort-knox';\n nextMilestone: string;\n}\n\nexport interface BackupMetadata {\n id: string;\n ethereumAddress: string;\n method: 'zip' | 'qr' | 'file';\n createdAt: number;\n deviceFingerprint?: string;\n addressChecksum: string; // For verification\n}\n\nexport interface EncryptedBackupData {\n version: number;\n encryptedMnemonic: string;\n salt: string;\n iterations: number;\n metadata: BackupMetadata;\n verification: {\n addressChecksum: string;\n };\n}\n\nexport interface ZipBackupOptions {\n password: string;\n includeInstructions?: boolean;\n deviceBinding?: boolean;\n}\n\nexport interface QRBackupOptions {\n password?: string;\n errorCorrection?: 'L' | 'M' | 'Q' | 'H';\n}\n\nexport interface RecoveryScenario {\n type: 'lost-device' | 'lost-phrase' | 'lost-both' | 'switch-platform';\n description: string;\n}\n\nexport interface SimulationResult {\n scenario: RecoveryScenario;\n success: boolean;\n availableMethods: RecoveryMethod[];\n timeEstimate: string;\n educationalNote: string;\n}\n\nexport interface RecoveryMethod {\n method: string;\n success: boolean;\n time: string;\n requirements: string[];\n}\n","/**\n * Backup and Recovery Module\n * Provides three-layer security: Passkey Sync, Encrypted Backups, Social Recovery\n */\n\nexport { BackupManager } from './manager';\nexport { BackupStorage } from './storage';\nexport { ZipBackupCreator } from './zip-backup';\nexport { QRBackupCreator } from './qr-backup';\n\nexport * from './types';\nexport * from './encryption';\n","/**\n * Shamir's Secret Sharing Implementation\n * Browser-compatible implementation without external dependencies\n *\n * Based on Shamir's Secret Sharing algorithm over GF(256)\n */\n\n/**\n * Generate random byte\n */\nfunction randomByte(): number {\n const array = new Uint8Array(1);\n crypto.getRandomValues(array);\n return array[0];\n}\n\n/**\n * Galois Field (256) operations for Shamir's Secret Sharing\n */\nclass GF256 {\n // Precomputed logarithm and exponential tables for GF(256)\n private static LOG_TABLE: number[] = [];\n private static EXP_TABLE: number[] = [];\n\n static {\n // Initialize tables using primitive polynomial x^8 + x^4 + x^3 + x + 1 (0x11b)\n // Generator is 3 (primitive element for this polynomial)\n\n // Helper function for GF(256) multiplication during initialization\n const gfMul = (a: number, b: number): number => {\n let result = 0;\n for (let i = 0; i < 8; i++) {\n if (b & 1) {\n result ^= a;\n }\n const hiBitSet = a & 0x80;\n a <<= 1;\n if (hiBitSet) {\n a ^= 0x11b; // Polynomial\n }\n b >>= 1;\n }\n return result & 0xFF;\n };\n\n let x = 1;\n for (let i = 0; i < 255; i++) {\n this.EXP_TABLE[i] = x;\n this.LOG_TABLE[x] = i;\n x = gfMul(x, 3); // Multiply by generator 3\n }\n this.EXP_TABLE[255] = this.EXP_TABLE[0];\n }\n\n /**\n * Multiply two numbers in GF(256)\n */\n static multiply(a: number, b: number): number {\n if (a === 0 || b === 0) return 0;\n return this.EXP_TABLE[(this.LOG_TABLE[a] + this.LOG_TABLE[b]) % 255];\n }\n\n /**\n * Divide two numbers in GF(256)\n */\n static divide(a: number, b: number): number {\n if (b === 0) throw new Error('Division by zero in GF(256)');\n if (a === 0) return 0;\n return this.EXP_TABLE[(this.LOG_TABLE[a] - this.LOG_TABLE[b] + 255) % 255];\n }\n\n /**\n * Add two numbers in GF(256) (XOR)\n */\n static add(a: number, b: number): number {\n return a ^ b;\n }\n\n /**\n * Evaluate polynomial at x\n */\n static evaluatePolynomial(coefficients: number[], x: number): number {\n let result = 0;\n for (let i = coefficients.length - 1; i >= 0; i--) {\n result = this.add(this.multiply(result, x), coefficients[i]);\n }\n return result;\n }\n\n /**\n * Lagrange interpolation to recover secret\n */\n static interpolate(shares: { x: number; y: number }[]): number {\n let result = 0;\n\n for (let i = 0; i < shares.length; i++) {\n let numerator = shares[i].y;\n let denominator = 1;\n\n for (let j = 0; j < shares.length; j++) {\n if (i !== j) {\n numerator = this.multiply(numerator, shares[j].x);\n denominator = this.multiply(\n denominator,\n this.add(shares[i].x, shares[j].x)\n );\n }\n }\n\n result = this.add(result, this.divide(numerator, denominator));\n }\n\n return result;\n }\n}\n\n/**\n * Split secret into N shares (requires M to reconstruct)\n */\nexport function splitSecret(\n secret: Uint8Array,\n threshold: number,\n totalShares: number\n): Uint8Array[] {\n if (threshold > totalShares) {\n throw new Error('Threshold cannot be greater than total shares');\n }\n\n if (threshold < 2) {\n throw new Error('Threshold must be at least 2');\n }\n\n if (totalShares > 255) {\n throw new Error('Cannot create more than 255 shares');\n }\n\n const shares: Uint8Array[] = [];\n\n // Initialize shares\n for (let i = 0; i < totalShares; i++) {\n shares[i] = new Uint8Array(secret.length + 1);\n shares[i][0] = i + 1; // X coordinate (1-indexed)\n }\n\n // For each byte of the secret\n for (let byteIndex = 0; byteIndex < secret.length; byteIndex++) {\n const secretByte = secret[byteIndex];\n\n // Generate random polynomial coefficients\n const coefficients = [secretByte];\n for (let i = 1; i < threshold; i++) {\n coefficients.push(randomByte());\n }\n\n // Evaluate polynomial for each share\n for (let shareIndex = 0; shareIndex < totalShares; shareIndex++) {\n const x = shareIndex + 1;\n const y = GF256.evaluatePolynomial(coefficients, x);\n shares[shareIndex][byteIndex + 1] = y;\n }\n }\n\n return shares;\n}\n\n/**\n * Combine shares to recover secret\n */\nexport function combineShares(\n shares: Uint8Array[],\n threshold: number\n): Uint8Array {\n if (shares.length < threshold) {\n throw new Error(\n `Need at least ${threshold} shares to recover secret, got ${shares.length}`\n );\n }\n\n // Use only first 'threshold' shares\n const usedShares = shares.slice(0, threshold);\n\n // Verify all shares have same length\n const shareLength = usedShares[0].length;\n for (const share of usedShares) {\n if (share.length !== shareLength) {\n throw new Error('All shares must have the same length');\n }\n }\n\n const secretLength = shareLength - 1;\n const secret = new Uint8Array(secretLength);\n\n // For each byte position\n for (let byteIndex = 0; byteIndex < secretLength; byteIndex++) {\n const points: { x: number; y: number }[] = [];\n\n for (const share of usedShares) {\n points.push({\n x: share[0], // X coordinate\n y: share[byteIndex + 1], // Y coordinate\n });\n }\n\n // Interpolate to recover secret byte\n secret[byteIndex] = GF256.interpolate(points);\n }\n\n return secret;\n}\n\n/**\n * Helper: Convert string to Uint8Array\n */\nexport function stringToBytes(str: string): Uint8Array {\n const encoder = new TextEncoder();\n return encoder.encode(str);\n}\n\n/**\n * Helper: Convert Uint8Array to string\n */\nexport function bytesToString(bytes: Uint8Array): string {\n const decoder = new TextDecoder();\n return decoder.decode(bytes);\n}\n\n/**\n * Helper: Convert bytes to hex string\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Helper: Convert hex string to bytes\n */\nexport function hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n","/**\n * Social Recovery Manager\n * Manages guardian-based wallet recovery using Shamir Secret Sharing\n */\n\nimport type {\n Guardian,\n GuardianInvite,\n SocialRecoveryConfig,\n RecoveryShare,\n RecoveryProgress,\n} from './types';\nimport {\n splitSecret,\n combineShares,\n stringToBytes,\n bytesToString,\n bytesToHex,\n hexToBytes,\n} from './shamir';\n\n// Singleton in-memory storage for non-browser environments\nconst memoryStorageSingleton = new Map<string, string>();\n\nexport class SocialRecoveryManager {\n private storageKey = 'w3pk_social_recovery';\n\n /**\n * Get storage (localStorage or in-memory fallback)\n */\n private getItem(key: string): string | null {\n if (typeof localStorage !== 'undefined') {\n return localStorage.getItem(key);\n }\n return memoryStorageSingleton.get(key) || null;\n }\n\n /**\n * Set storage (localStorage or in-memory fallback)\n */\n private setItem(key: string, value: string): void {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(key, value);\n } else {\n memoryStorageSingleton.set(key, value);\n }\n }\n\n /**\n * Set up social recovery\n * Splits mnemonic into M-of-N shares and distributes to guardians\n */\n async setupSocialRecovery(\n mnemonic: string,\n ethereumAddress: string,\n guardians: { name: string; email?: string; phone?: string }[],\n threshold: number\n ): Promise<Guardian[]> {\n if (threshold > guardians.length) {\n throw new Error('Threshold cannot be greater than number of guardians');\n }\n\n if (threshold < 2) {\n throw new Error('Threshold must be at least 2');\n }\n\n if (guardians.length > 255) {\n throw new Error('Cannot have more than 255 guardians');\n }\n\n // Convert mnemonic to bytes\n const secretBytes = stringToBytes(mnemonic);\n\n // Split into shares\n const shares = splitSecret(secretBytes, threshold, guardians.length);\n\n // Create guardian objects\n const guardianObjects: Guardian[] = guardians.map((g, index) => ({\n id: crypto.randomUUID(),\n name: g.name,\n email: g.email,\n phone: g.phone,\n shareEncrypted: bytesToHex(shares[index]),\n status: 'pending' as const,\n addedAt: Date.now(),\n }));\n\n // Store config\n const config: SocialRecoveryConfig = {\n threshold,\n totalGuardians: guardians.length,\n guardians: guardianObjects,\n createdAt: Date.now(),\n ethereumAddress,\n };\n\n this.setItem(this.storageKey, JSON.stringify(config));\n\n return guardianObjects;\n }\n\n /**\n * Get current social recovery configuration\n */\n getSocialRecoveryConfig(): SocialRecoveryConfig | null {\n const stored = this.getItem(this.storageKey);\n if (!stored) return null;\n\n try {\n return JSON.parse(stored);\n } catch {\n return null;\n }\n }\n\n /**\n * Generate guardian invitation\n * Creates QR code and educational materials for guardian\n */\n async generateGuardianInvite(guardian: Guardian): Promise<GuardianInvite> {\n const config = this.getSocialRecoveryConfig();\n if (!config) {\n throw new Error('Social recovery not configured');\n }\n\n // Find guardian index\n const index = config.guardians.findIndex((g) => g.id === guardian.id);\n if (index === -1) {\n throw new Error('Guardian not found');\n }\n\n // Create guardian data package\n const guardianData = {\n version: 1,\n guardianId: guardian.id,\n guardianName: guardian.name,\n guardianIndex: index + 1,\n totalGuardians: config.totalGuardians,\n threshold: config.threshold,\n share: guardian.shareEncrypted,\n ethereumAddress: config.ethereumAddress,\n createdAt: config.createdAt,\n };\n\n const shareCode = JSON.stringify(guardianData);\n\n // Generate QR code\n const qrCode = await this.generateQRCode(shareCode);\n\n // Create explainer\n const explainer = this.getGuardianExplainer(\n guardian.name,\n index + 1,\n config.totalGuardians,\n config.threshold\n );\n\n return {\n guardianId: guardian.id,\n qrCode,\n shareCode,\n explainer,\n };\n }\n\n /**\n * Generate QR code from share data\n */\n private async generateQRCode(data: string): Promise<string> {\n // Try to use qrcode library if available\n try {\n const QRCode = (await import('qrcode')) as any;\n return await QRCode.toDataURL(data, {\n errorCorrectionLevel: 'H',\n width: 512,\n margin: 2,\n });\n } catch {\n // Fallback: Create placeholder\n return this.createPlaceholderQR(data);\n }\n }\n\n /**\n * Create placeholder QR code\n */\n private createPlaceholderQR(data: string): string {\n // Check if we're in a browser environment\n if (typeof document === 'undefined') {\n // Node.js environment - return a simple data URL with text\n return `data:text/plain;base64,${Buffer.from(data).toString('base64')}`;\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = 512;\n canvas.height = 512;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return '';\n }\n\n // White background\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, 512, 512);\n\n // Black text\n ctx.fillStyle = 'black';\n ctx.font = 'bold 20px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n ctx.fillText('Guardian Recovery Share', 256, 100);\n ctx.font = '14px monospace';\n ctx.fillText('Install \"qrcode\" for QR codes', 256, 480);\n\n // Show truncated data\n ctx.font = '10px monospace';\n const lines = this.wrapText(data.substring(0, 200) + '...', 60);\n lines.forEach((line, i) => {\n ctx.fillText(line, 256, 150 + i * 12);\n });\n\n return canvas.toDataURL('image/png');\n }\n\n /**\n * Wrap text for display\n */\n private wrapText(text: string, maxLength: number): string[] {\n const lines: string[] = [];\n for (let i = 0; i < text.length; i += maxLength) {\n lines.push(text.substring(i, i + maxLength));\n }\n return lines;\n }\n\n /**\n * Get guardian explainer text\n */\n private getGuardianExplainer(\n name: string,\n index: number,\n total: number,\n threshold: number\n ): string {\n return `\n🛡️ GUARDIAN RECOVERY SHARE\n\nDear ${name},\n\nYou have been chosen as Guardian ${index} of ${total}\n\nYOUR ROLE:\n----------\n\nYour friend has entrusted you with a recovery share for their cryptocurrency wallet.\n\nWHAT THIS MEANS:\n- You hold 1 piece of a ${threshold}-piece puzzle\n- ${threshold} guardians needed to recover the wallet\n- You cannot access the wallet alone\n- This is a responsibility and honor\n\nHOW IT WORKS:\n-------------\n\nIf your friend loses access to their wallet:\n\n1. They will contact you to request your share\n2. You provide the QR code or share code below\n3. System collects shares from ${threshold} guardians\n4. Wallet is mathematically reconstructed\n5. Your friend regains access ✓\n\nSECURITY:\n---------\n\n✓ Your share is encrypted\n✓ Cannot be used alone\n✓ ${threshold - 1} other guardians needed\n✓ Safe to store digitally\n\nYOUR RESPONSIBILITIES:\n---------------------\n\nDO:\n✓ Keep this share safe and accessible\n✓ Store in password manager or secure location\n✓ Respond promptly if friend requests recovery\n✓ Verify identity before sharing\n\nDON'T:\n✗ Share unless friend explicitly requests it\n✗ Post publicly or send unsecured\n✗ Lose or delete (friend depends on you!)\n\nVERIFICATION:\n------------\n\nBefore sharing, verify your friend's identity:\n- Video call to confirm\n- Ask security questions\n- Check contact method is authentic\n\nRECOVERY PROCESS:\n----------------\n\nIf requested:\n1. Friend will contact you\n2. Verify their identity\n3. Provide this QR code or share code\n4. System handles the rest\n\nHOW TO STORE:\n------------\n\nRecommended storage:\n✓ Password manager (1Password, Bitwarden)\n✓ Encrypted note\n✓ Print and store physically\n✓ Screenshot (encrypted phone)\n\n---\n\nGuardian ${index}/${total} | Threshold: ${threshold}/${total}\nCreated: ${new Date().toISOString()}\n\nThank you for being a trusted guardian!\n\n---\n\nNEED HELP?\nVisit: https://docs.w3pk.org/social-recovery\n`;\n }\n\n /**\n * Recover mnemonic from guardian shares\n */\n async recoverFromGuardians(\n shareData: string[]\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n const config = this.getSocialRecoveryConfig();\n if (!config) {\n throw new Error('Social recovery not configured');\n }\n\n if (shareData.length < config.threshold) {\n throw new Error(\n `Need at least ${config.threshold} shares, got ${shareData.length}`\n );\n }\n\n // Parse share data\n const shares: RecoveryShare[] = shareData.map((data) => {\n const parsed = JSON.parse(data);\n return {\n guardianId: parsed.guardianId,\n share: parsed.share,\n index: parsed.guardianIndex,\n };\n });\n\n // Convert shares to bytes\n const shareBytes = shares.map((s) => hexToBytes(s.share));\n\n // Combine shares\n const secretBytes = combineShares(shareBytes, config.threshold);\n\n // Convert to mnemonic\n const mnemonic = bytesToString(secretBytes);\n\n // Verify\n const { Wallet } = await import('ethers');\n const wallet = Wallet.fromPhrase(mnemonic);\n\n if (wallet.address.toLowerCase() !== config.ethereumAddress.toLowerCase()) {\n throw new Error('Recovered address does not match - invalid shares');\n }\n\n return {\n mnemonic,\n ethereumAddress: wallet.address,\n };\n }\n\n /**\n * Get recovery progress\n */\n getRecoveryProgress(collectedShares: string[]): RecoveryProgress {\n const config = this.getSocialRecoveryConfig();\n if (!config) {\n throw new Error('Social recovery not configured');\n }\n\n const collectedGuardianIds = new Set(\n collectedShares.map((data) => {\n try {\n return JSON.parse(data).guardianId;\n } catch {\n return null;\n }\n }).filter(Boolean)\n );\n\n return {\n collected: collectedGuardianIds.size,\n required: config.threshold,\n guardians: config.guardians.map((g) => ({\n id: g.id,\n name: g.name,\n hasProvided: collectedGuardianIds.has(g.id),\n })),\n canRecover: collectedGuardianIds.size >= config.threshold,\n };\n }\n\n /**\n * Mark guardian as verified\n */\n markGuardianVerified(guardianId: string): void {\n const config = this.getSocialRecoveryConfig();\n if (!config) {\n throw new Error('Social recovery not configured');\n }\n\n const guardian = config.guardians.find((g) => g.id === guardianId);\n if (!guardian) {\n throw new Error('Guardian not found');\n }\n\n guardian.status = 'active';\n guardian.lastVerified = Date.now();\n\n this.setItem(this.storageKey, JSON.stringify(config));\n }\n\n /**\n * Revoke a guardian\n */\n revokeGuardian(guardianId: string): void {\n const config = this.getSocialRecoveryConfig();\n if (!config) {\n throw new Error('Social recovery not configured');\n }\n\n const guardian = config.guardians.find((g) => g.id === guardianId);\n if (!guardian) {\n throw new Error('Guardian not found');\n }\n\n guardian.status = 'revoked';\n\n this.setItem(this.storageKey, JSON.stringify(config));\n }\n\n /**\n * Add new guardian (requires re-sharing)\n */\n async addGuardian(\n mnemonic: string,\n newGuardian: { name: string; email?: string; phone?: string }\n ): Promise<Guardian> {\n const config = this.getSocialRecoveryConfig();\n if (!config) {\n throw new Error('Social recovery not configured');\n }\n\n // Re-setup with new guardian\n const updatedGuardians = [\n ...config.guardians\n .filter((g) => g.status !== 'revoked')\n .map((g) => ({ name: g.name, email: g.email, phone: g.phone })),\n newGuardian,\n ];\n\n const newGuardianObjects = await this.setupSocialRecovery(\n mnemonic,\n config.ethereumAddress,\n updatedGuardians,\n config.threshold\n );\n\n return newGuardianObjects[newGuardianObjects.length - 1];\n }\n}\n","/**\n * Social Recovery Type Definitions\n */\n\nexport interface Guardian {\n id: string;\n name: string;\n email?: string;\n phone?: string;\n publicKey?: string; // For encrypting their share\n shareEncrypted: string;\n status: 'pending' | 'active' | 'revoked';\n addedAt: number;\n lastVerified?: number;\n}\n\nexport interface GuardianInvite {\n guardianId: string;\n qrCode: string; // Data URL for QR code\n shareCode: string; // Text code for manual entry\n explainer: string; // Educational text\n link?: string; // Optional deep link\n}\n\nexport interface SocialRecoveryConfig {\n threshold: number; // M in M-of-N\n totalGuardians: number; // N in M-of-N\n guardians: Guardian[];\n createdAt: number;\n ethereumAddress: string;\n}\n\nexport interface RecoveryShare {\n guardianId: string;\n share: string;\n index: number; // 1-based index\n}\n\nexport interface RecoveryProgress {\n collected: number;\n required: number;\n guardians: {\n id: string;\n name: string;\n hasProvided: boolean;\n }[];\n canRecover: boolean;\n}\n","/**\n * Social Recovery Module\n * Guardian-based wallet recovery using Shamir Secret Sharing\n */\n\nexport { SocialRecoveryManager } from './social';\nexport * from './shamir';\nexport * from './types';\n","/**\n * Encrypted Sync Vault\n * Manages encrypted wallet data for cross-device sync\n */\n\nimport type { SyncVault, SyncResult, SyncStep } from './types';\nimport { getDeviceFingerprint } from '../backup/encryption';\n\nexport class VaultSync {\n /**\n * Create encrypted sync package\n * Uses passkey + device fingerprint for encryption\n */\n async createSyncPackage(\n mnemonic: string,\n credentialId: string,\n publicKey: string\n ): Promise<SyncVault> {\n // Get device fingerprint\n const deviceFingerprint = await getDeviceFingerprint();\n\n // Encrypt mnemonic (using same method as wallet storage)\n const { deriveEncryptionKeyFromWebAuthn, encryptData } = await import(\n '../wallet/crypto'\n );\n\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n credentialId,\n publicKey\n );\n\n const encryptedData = await encryptData(mnemonic, encryptionKey);\n\n // Detect sync method\n const syncMethod = this.detectSyncMethod();\n\n return {\n id: crypto.randomUUID(),\n encryptedData,\n deviceFingerprints: [deviceFingerprint],\n syncMethod,\n version: 1,\n updatedAt: Date.now(),\n };\n }\n\n /**\n * Detect available sync method\n */\n private detectSyncMethod():\n | 'icloud'\n | 'google'\n | 'microsoft'\n | 'custom' {\n const userAgent = navigator.userAgent.toLowerCase();\n\n if (\n userAgent.includes('mac') ||\n userAgent.includes('iphone') ||\n userAgent.includes('ipad')\n ) {\n return 'icloud';\n }\n\n if (userAgent.includes('android') || userAgent.includes('chrome')) {\n return 'google';\n }\n\n if (userAgent.includes('windows')) {\n return 'microsoft';\n }\n\n return 'custom';\n }\n\n /**\n * Restore from sync vault\n * Interactive guide for multi-device setup\n */\n async restoreFromSync(\n vault: SyncVault,\n credentialId: string,\n publicKey: string\n ): Promise<string> {\n // Derive decryption key\n const { deriveEncryptionKeyFromWebAuthn, decryptData } = await import(\n '../wallet/crypto'\n );\n\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n credentialId,\n publicKey\n );\n\n // Decrypt mnemonic\n const mnemonic = await decryptData(vault.encryptedData, encryptionKey);\n\n // Add current device fingerprint\n const deviceFingerprint = await getDeviceFingerprint();\n if (!vault.deviceFingerprints.includes(deviceFingerprint)) {\n vault.deviceFingerprints.push(deviceFingerprint);\n vault.updatedAt = Date.now();\n }\n\n return mnemonic;\n }\n\n /**\n * Get setup flow for new device\n * Educational flow with step-by-step instructions\n */\n async getSetupFlow(): Promise<SyncResult> {\n const steps: SyncStep[] = [\n {\n title: '1. Authenticate on New Device',\n action: 'Use Touch ID/Face ID',\n educational:\n 'Your passkey is automatically synced via iCloud/Google',\n status: 'waiting',\n },\n {\n title: '2. Decrypt Wallet Data',\n action: 'System validates device',\n educational: 'Only your trusted devices can decrypt the wallet',\n status: 'waiting',\n },\n {\n title: '3. Verify Recovery',\n action: 'Check partial address',\n educational: 'Confirm address matches your wallet',\n status: 'waiting',\n },\n {\n title: '4. Ready!',\n action: 'Wallet synced',\n educational: 'All devices now have access',\n status: 'waiting',\n },\n ];\n\n return {\n success: false,\n steps,\n };\n }\n\n /**\n * Educational message about how sync works\n */\n getSyncExplainer(): string {\n return `\nHOW CROSS-DEVICE SYNC WORKS\n===========================\n\nYour wallet is protected by TWO layers:\n\nLayer 1: Passkey (Auto-Syncs)\n-----------------------------\n✓ Your fingerprint/Face ID credential\n✓ Syncs via iCloud Keychain or Google\n✓ Available on all your devices\n✓ Cannot be stolen (hardware-protected)\n\nLayer 2: Encrypted Wallet (In Browser)\n--------------------------------------\n✓ Your 12-word mnemonic (encrypted)\n✓ Stored in browser's IndexedDB\n✓ Can ONLY be decrypted with passkey\n✓ Requires authentication to access\n\nHow They Work Together:\n----------------------\n\nDevice 1 (iPhone) iCloud Keychain Device 2 (Mac)\n | | |\n |-- Passkey Created -------->| |\n | | |\n |-- Wallet Encrypted --------| |\n | (in IndexedDB) | |\n | | |\n | |<----- Login on Mac -----|\n | | |\n | Passkey Synced |\n | |------- Unlock --------->|\n | | Passkey |\n | | |\n | |<----- Decrypt ----------|\n | | Wallet |\n\nSecurity Benefits:\n-----------------\n\n✓ Passkey syncs automatically (convenient)\n✓ Wallet ONLY decrypts with passkey (secure)\n✓ Cannot access wallet without biometric\n✓ Works seamlessly across devices\n✓ No passwords to remember\n\nWhat Gets Synced:\n----------------\n\n✓ Passkey credential (via platform sync)\n✓ Credential metadata (localStorage)\n\nWhat Stays Local:\n----------------\n\n✗ Encrypted mnemonic (in IndexedDB)\n - Must authenticate to decrypt\n - Requires passkey access\n - Platform-specific storage\n\nRecovery Options:\n----------------\n\nIf you lose a device:\n1. ✓ Sign in on new device\n2. ✓ Passkey auto-syncs\n3. ✓ Authenticate to decrypt wallet\n4. ✓ Wallet restored!\n\nIf passkey doesn't sync:\n1. ✓ Use encrypted backup\n2. ✓ Use 12-word recovery phrase\n3. ✓ Use social recovery\n\n---\n\nThink of it like:\n🔑 Passkey = Your car key (syncs via keychain)\n🚗 Wallet = Your car (locked, needs key to start)\n`;\n }\n}\n","/**\n * Device Manager\n * Track and manage trusted devices with wallet access\n */\n\nimport type { DeviceInfo, SyncStatus } from './types';\nimport { getDeviceFingerprint } from '../backup/encryption';\n\nexport class DeviceManager {\n private storageKey = 'w3pk_devices';\n\n /**\n * Register current device\n */\n async registerDevice(): Promise<DeviceInfo> {\n const deviceInfo: DeviceInfo = {\n id: await getDeviceFingerprint(),\n name: this.getDeviceName(),\n platform: this.detectPlatform(),\n lastActive: Date.now(),\n trusted: true,\n canRevoke: false, // Current device cannot be revoked\n };\n\n // Store device info\n const devices = await this.getDevices();\n const existing = devices.find((d) => d.id === deviceInfo.id);\n\n if (!existing) {\n devices.push(deviceInfo);\n localStorage.setItem(this.storageKey, JSON.stringify(devices));\n } else {\n // Update last active\n existing.lastActive = Date.now();\n localStorage.setItem(this.storageKey, JSON.stringify(devices));\n }\n\n return deviceInfo;\n }\n\n /**\n * Get all registered devices\n */\n async getDevices(): Promise<DeviceInfo[]> {\n const stored = localStorage.getItem(this.storageKey);\n if (!stored) {\n return [];\n }\n\n try {\n return JSON.parse(stored);\n } catch {\n return [];\n }\n }\n\n /**\n * Get sync status with device list\n */\n async getSyncStatus(): Promise<SyncStatus> {\n const devices = await this.getDevices();\n const currentDeviceId = await getDeviceFingerprint();\n\n // Mark current device as not revokable\n devices.forEach((device) => {\n device.canRevoke = device.id !== currentDeviceId;\n });\n\n // Sort by last active (most recent first)\n devices.sort((a, b) => b.lastActive - a.lastActive);\n\n const platform = this.detectPlatform();\n const lastSyncTime = devices.length > 1 ? Math.max(...devices.map((d) => d.lastActive)) : undefined;\n\n return {\n enabled: devices.length > 1,\n devices,\n lastSyncTime,\n platform: this.getPlatformName(platform),\n };\n }\n\n /**\n * Revoke a device\n */\n async revokeDevice(deviceId: string): Promise<void> {\n const devices = await this.getDevices();\n const currentDeviceId = await getDeviceFingerprint();\n\n // Prevent revoking current device\n if (deviceId === currentDeviceId) {\n throw new Error('Cannot revoke current device');\n }\n\n // Remove device\n const filtered = devices.filter((d) => d.id !== deviceId);\n localStorage.setItem(this.storageKey, JSON.stringify(filtered));\n }\n\n /**\n * Update device last active timestamp\n */\n async updateLastActive(): Promise<void> {\n const devices = await this.getDevices();\n const currentDeviceId = await getDeviceFingerprint();\n\n const device = devices.find((d) => d.id === currentDeviceId);\n if (device) {\n device.lastActive = Date.now();\n localStorage.setItem(this.storageKey, JSON.stringify(devices));\n }\n }\n\n /**\n * Get device name\n */\n private getDeviceName(): string {\n const platform = this.detectPlatform();\n const ua = navigator.userAgent;\n\n if (platform === 'ios') {\n if (ua.includes('iPhone')) return 'iPhone';\n if (ua.includes('iPad')) return 'iPad';\n if (ua.includes('iPod')) return 'iPod';\n return 'iOS Device';\n }\n\n if (platform === 'android') {\n // Try to extract device name from UA\n const match = ua.match(/Android.*;\\s([^)]+)\\)/);\n return match ? match[1] : 'Android Device';\n }\n\n if (platform === 'macos') {\n return 'Mac';\n }\n\n if (platform === 'windows') {\n return 'Windows PC';\n }\n\n if (platform === 'linux') {\n return 'Linux PC';\n }\n\n return 'Unknown Device';\n }\n\n /**\n * Detect device platform\n */\n private detectPlatform(): DeviceInfo['platform'] {\n const ua = navigator.userAgent.toLowerCase();\n\n if (ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod')) {\n return 'ios';\n }\n\n if (ua.includes('android')) {\n return 'android';\n }\n\n if (ua.includes('mac')) {\n return 'macos';\n }\n\n if (ua.includes('windows')) {\n return 'windows';\n }\n\n if (ua.includes('linux')) {\n return 'linux';\n }\n\n return 'unknown';\n }\n\n /**\n * Get platform display name\n */\n private getPlatformName(platform: DeviceInfo['platform']): string {\n switch (platform) {\n case 'ios':\n return 'iOS (iCloud Keychain)';\n case 'android':\n return 'Android (Google)';\n case 'macos':\n return 'macOS (iCloud Keychain)';\n case 'windows':\n return 'Windows (Microsoft)';\n case 'linux':\n return 'Linux';\n default:\n return 'Unknown';\n }\n }\n\n /**\n * Get formatted device list for display\n */\n async getDeviceListFormatted(): Promise<string> {\n const status = await this.getSyncStatus();\n\n if (status.devices.length === 0) {\n return 'No devices registered';\n }\n\n let output = `Your Devices (${status.devices.length}):\\n\\n`;\n\n status.devices.forEach((device, index) => {\n const lastActiveDiff = Date.now() - device.lastActive;\n const lastActiveStr = this.formatTimeDiff(lastActiveDiff);\n\n output += `${index + 1}. ${device.name}\\n`;\n output += ` Platform: ${this.getPlatformName(device.platform)}\\n`;\n output += ` Last active: ${lastActiveStr}\\n`;\n output += ` ${!device.canRevoke ? '(Current device)' : ''}\\n\\n`;\n });\n\n return output;\n }\n\n /**\n * Format time difference for display\n */\n private formatTimeDiff(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days} day${days > 1 ? 's' : ''} ago`;\n }\n\n if (hours > 0) {\n return `${hours} hour${hours > 1 ? 's' : ''} ago`;\n }\n\n if (minutes > 0) {\n return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;\n }\n\n return 'just now';\n }\n}\n","/**\n * Platform Detection for Passkey Sync\n * Detects available sync platforms (iCloud, Google, Microsoft)\n */\n\nimport type { SyncCapabilities } from './types';\n\nexport class PlatformDetector {\n /**\n * Detect available sync capabilities\n * Shows what's automatically protecting the user\n */\n async detectSyncCapabilities(): Promise<SyncCapabilities> {\n const platform = this.detectPlatform();\n const passkeysSync = await this.checkPasskeySync();\n const estimatedDevices = this.estimateDeviceCount();\n\n return {\n passkeysSync,\n platform,\n estimatedDevices,\n syncEnabled: passkeysSync && platform !== 'none',\n };\n }\n\n /**\n * Detect user's platform\n */\n private detectPlatform(): 'apple' | 'google' | 'microsoft' | 'none' {\n const userAgent = navigator.userAgent.toLowerCase();\n\n // Check for Apple devices\n if (\n userAgent.includes('mac') ||\n userAgent.includes('iphone') ||\n userAgent.includes('ipad') ||\n userAgent.includes('ipod')\n ) {\n return 'apple';\n }\n\n // Check for Android\n if (userAgent.includes('android')) {\n return 'google';\n }\n\n // Check for Windows\n if (userAgent.includes('windows')) {\n return 'microsoft';\n }\n\n return 'none';\n }\n\n /**\n * Check if passkey sync is supported\n */\n private async checkPasskeySync(): Promise<boolean> {\n if (!window.PublicKeyCredential) {\n return false;\n }\n\n try {\n // Check if platform authenticator is available\n const available =\n await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n return available;\n } catch {\n return false;\n }\n }\n\n /**\n * Estimate number of synced devices\n * Note: This is a rough estimate, actual count requires server-side tracking\n */\n private estimateDeviceCount(): number {\n // In a real implementation, this would:\n // 1. Check server-side records of successful logins\n // 2. Query platform-specific APIs if available\n // 3. Use credential storage to count unique device fingerprints\n\n // For now, return minimum of 1 (current device)\n return 1;\n }\n\n /**\n * Get platform-specific educational message\n */\n getPlatformEducation(platform: 'apple' | 'google' | 'microsoft' | 'none'): string {\n switch (platform) {\n case 'apple':\n return `\n🍎 Apple iCloud Keychain\n\nYour passkey automatically syncs across:\n- iPhone\n- iPad\n- Mac\n- Apple Watch (for authentication)\n\nRequirements:\n✓ iCloud Keychain enabled in Settings\n✓ Signed in to iCloud\n✓ Two-factor authentication enabled\n\nHow it works:\n1. Create passkey on this device\n2. iCloud encrypts and syncs it\n3. Available on all your Apple devices\n4. End-to-end encrypted\n\nSecurity:\n- Apple cannot access your passkeys\n- Synced with end-to-end encryption\n- Requires device unlock to use\n`;\n\n case 'google':\n return `\n🤖 Google Password Manager\n\nYour passkey automatically syncs across:\n- Android phones/tablets\n- Chrome browser (all platforms)\n- ChromeOS devices\n\nRequirements:\n✓ Signed in to Google Account\n✓ Sync enabled in Chrome\n✓ Screen lock configured\n\nHow it works:\n1. Create passkey on this device\n2. Google encrypts and syncs it\n3. Available on all signed-in devices\n4. End-to-end encrypted\n\nSecurity:\n- Google cannot access your passkeys\n- Synced with end-to-end encryption\n- Requires screen unlock to use\n`;\n\n case 'microsoft':\n return `\n🪟 Windows Hello\n\nYour passkey is tied to this Windows device.\n\nNote: Limited cross-device sync\n- Passkeys stored in Windows Credential Manager\n- Tied to this PC's TPM chip\n- Does NOT sync to other devices automatically\n\nFor cross-device access:\n- Use encrypted backup instead\n- Or set up social recovery\n\nSecurity:\n- Hardware-protected (TPM)\n- Requires Windows Hello (PIN/biometric)\n- Very secure but not portable\n`;\n\n case 'none':\n return `\n⚠️ Platform Sync Not Available\n\nYour passkey will be stored on this device only.\n\nRecommendation:\n✓ Create encrypted backup (password-protected)\n✓ Set up social recovery\n✓ Save your 12-word recovery phrase\n\nThis ensures you can recover if:\n- Device is lost/stolen\n- Device is damaged\n- You switch devices\n`;\n }\n }\n\n /**\n * Get sync setup instructions\n */\n getSyncInstructions(platform: 'apple' | 'google' | 'microsoft' | 'none'): string[] {\n switch (platform) {\n case 'apple':\n return [\n 'Open Settings on your iPhone/iPad/Mac',\n 'Tap your name at the top',\n 'Tap \"iCloud\"',\n 'Enable \"Keychain\"',\n 'Enable \"iCloud Backup\" (recommended)',\n ];\n\n case 'google':\n return [\n 'Open Chrome Settings',\n 'Click \"You and Google\"',\n 'Enable \"Sync\"',\n 'Ensure \"Passwords\" is checked',\n 'Sign in on other devices with same Google account',\n ];\n\n case 'microsoft':\n return [\n 'Windows Hello sync is limited',\n 'Consider using:',\n '- Encrypted ZIP backup',\n '- Social recovery',\n '- Cloud backup (password-protected)',\n ];\n\n case 'none':\n return [\n 'Platform sync not available',\n 'Use alternative backup methods:',\n '- Create encrypted ZIP backup',\n '- Set up social recovery',\n '- Save recovery phrase securely',\n ];\n }\n }\n}\n","/**\n * Cross-Device Sync Type Definitions\n */\n\nexport interface SyncVault {\n id: string;\n encryptedData: string; // Encrypted mnemonic\n deviceFingerprints: string[]; // Devices that can decrypt\n syncMethod: 'icloud' | 'google' | 'microsoft' | 'custom';\n version: number;\n updatedAt: number;\n}\n\nexport interface DeviceInfo {\n id: string;\n name: string;\n platform: 'ios' | 'android' | 'macos' | 'windows' | 'linux' | 'unknown';\n lastActive: number;\n trusted: boolean;\n canRevoke: boolean; // False for current device\n}\n\nexport interface SyncCapabilities {\n passkeysSync: boolean;\n platform: 'apple' | 'google' | 'microsoft' | 'none';\n estimatedDevices: number;\n syncEnabled: boolean;\n}\n\nexport interface SyncStatus {\n enabled: boolean;\n devices: DeviceInfo[];\n lastSyncTime?: number;\n platform: string;\n}\n\nexport interface SyncResult {\n success: boolean;\n steps: SyncStep[];\n}\n\nexport interface SyncStep {\n title: string;\n action: string;\n educational: string;\n status: 'waiting' | 'in-progress' | 'completed' | 'failed';\n}\n","/**\n * Cross-Device Sync Module\n * Handles passkey sync and device management\n */\n\nexport { VaultSync } from './vault';\nexport { DeviceManager } from './device-manager';\nexport { PlatformDetector } from './platform-detect';\n\nexport * from './types';\n","/**\n * Recovery Scenario Simulator\n * Educational tool to help users understand recovery options\n */\n\nimport type { BackupStatus } from '../backup/types';\nimport type {\n RecoveryScenario,\n SimulationResult,\n RecoveryMethod,\n} from '../backup/types';\n\nexport class RecoverySimulator {\n /**\n * Predefined recovery scenarios\n */\n getScenarios(): RecoveryScenario[] {\n return [\n {\n type: 'lost-device',\n description: 'Your phone fell in the ocean',\n },\n {\n type: 'lost-phrase',\n description: 'Your paper backup burned in a fire',\n },\n {\n type: 'lost-both',\n description: 'Phone stolen AND forgot recovery phrase',\n },\n {\n type: 'switch-platform',\n description: 'Switching from iPhone to Android',\n },\n ];\n }\n\n /**\n * Simulate a recovery scenario\n */\n async simulateScenario(\n scenario: RecoveryScenario,\n currentStatus: BackupStatus\n ): Promise<SimulationResult> {\n const methods: RecoveryMethod[] = [];\n\n switch (scenario.type) {\n case 'lost-device':\n // Check passkey sync\n if (\n currentStatus.passkeySync.enabled &&\n currentStatus.passkeySync.deviceCount > 1\n ) {\n methods.push({\n method: `Passkey Sync (${currentStatus.passkeySync.platform})`,\n success: true,\n time: '5 minutes',\n requirements: [\n 'Sign in to cloud account on new device',\n 'Authenticate with biometric/PIN',\n ],\n });\n }\n\n // Check encrypted backups\n if (currentStatus.recoveryPhrase.encryptedBackups.length > 0) {\n currentStatus.recoveryPhrase.encryptedBackups.forEach((backup) => {\n methods.push({\n method: `Encrypted ${backup.method.toUpperCase()} Backup`,\n success: true,\n time: '2 minutes',\n requirements: ['Backup file/QR code', 'Backup password'],\n });\n });\n }\n\n // Check social recovery\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [\n `Contact ${currentStatus.socialRecovery.threshold} guardians`,\n 'Collect shares from guardians',\n 'Verify identity with each guardian',\n ],\n });\n }\n break;\n\n case 'lost-phrase':\n // Passkey still works on current device\n if (currentStatus.passkeySync.enabled) {\n methods.push({\n method: 'Passkey (current device)',\n success: true,\n time: 'Instant',\n requirements: ['Access to current device', 'Biometric/PIN authentication'],\n });\n }\n\n // Passkey sync to other devices\n if (currentStatus.passkeySync.deviceCount > 1) {\n methods.push({\n method: 'Passkey Sync',\n success: true,\n time: '5 minutes',\n requirements: ['Any synced device', 'Biometric authentication'],\n });\n }\n\n // Encrypted backups still work\n if (currentStatus.recoveryPhrase.encryptedBackups.length > 0) {\n methods.push({\n method: 'Encrypted Backup',\n success: true,\n time: '2 minutes',\n requirements: ['Backup file', 'Password'],\n });\n }\n\n // Social recovery\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [`${currentStatus.socialRecovery.threshold} guardian shares`],\n });\n }\n break;\n\n case 'lost-both':\n // Only passkey sync can help\n if (currentStatus.passkeySync.deviceCount > 1) {\n methods.push({\n method: 'Passkey Sync',\n success: true,\n time: '5 minutes',\n requirements: [\n 'Cloud account access',\n 'New device',\n 'Biometric setup',\n ],\n });\n }\n\n // Social recovery is the safety net\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [\n `${currentStatus.socialRecovery.threshold} guardian shares`,\n 'Identity verification with guardians',\n ],\n });\n }\n break;\n\n case 'switch-platform':\n // Passkey sync doesn't work cross-platform\n // Only universal backups work\n if (currentStatus.recoveryPhrase.encryptedBackups.length > 0) {\n methods.push({\n method: 'Encrypted Backup',\n success: true,\n time: '2 minutes',\n requirements: ['Backup file', 'Password'],\n });\n }\n\n if (currentStatus.socialRecovery?.enabled) {\n methods.push({\n method: 'Social Recovery',\n success: true,\n time: '24 hours',\n requirements: [`${currentStatus.socialRecovery.threshold} guardian shares`],\n });\n }\n break;\n }\n\n const success = methods.length > 0;\n\n let educationalNote = this.getEducationalNote(\n scenario,\n methods,\n currentStatus\n );\n\n return {\n scenario,\n success,\n availableMethods: methods,\n timeEstimate: success ? this.estimateFastestRecovery(methods) : 'Cannot recover',\n educationalNote,\n };\n }\n\n /**\n * Estimate fastest recovery time\n */\n private estimateFastestRecovery(methods: RecoveryMethod[]): string {\n const times = methods.map((m) => m.time.toLowerCase());\n\n if (times.some((t) => t.includes('instant'))) return 'Instant';\n if (times.some((t) => t.includes('minute'))) {\n const minutes = times\n .filter((t) => t.includes('minute'))\n .map((t) => parseInt(t));\n return `${Math.min(...minutes)} minutes`;\n }\n if (times.some((t) => t.includes('hour'))) return '24 hours';\n\n return 'Unknown';\n }\n\n /**\n * Get educational note for scenario\n */\n private getEducationalNote(\n scenario: RecoveryScenario,\n methods: RecoveryMethod[],\n status: BackupStatus\n ): string {\n if (methods.length === 0) {\n return `\n❌ WALLET CANNOT BE RECOVERED\n\nScenario: ${scenario.description}\n\nUnfortunately, you have no recovery options for this scenario.\n\nThis is why backup is critical!\n\nIMMEDIATE ACTION REQUIRED:\n-------------------------\n\nTo prevent permanent loss, set up AT LEAST TWO of these:\n\n1. Encrypted Backup\n - Takes 2 minutes\n - Works anywhere\n - Requires password\n [Create backup now]\n\n2. Social Recovery\n - Takes 30 minutes setup\n - Most secure\n - Requires 3-5 trusted friends\n [Set up guardians]\n\n3. Verify Passkey Sync\n - Check if enabled\n - Test on another device\n - Platform-specific\n [Check sync status]\n\n---\n\nDon't wait until it's too late!\n`;\n }\n\n let note = `✅ YOU CAN RECOVER!\\n\\nScenario: ${scenario.description}\\n\\n`;\n\n note += `Available recovery methods (${methods.length}):\\n\\n`;\n\n methods.forEach((method, index) => {\n note += `${index + 1}. ${method.method}\\n`;\n note += ` ⏱ Time: ~${method.time}\\n`;\n note += ` Requirements:\\n`;\n method.requirements.forEach((req) => {\n note += ` - ${req}\\n`;\n });\n note += `\\n`;\n });\n\n // Add recommendations\n note += `\\nRECOMMENDATIONS:\\n`;\n\n if (methods.length === 1) {\n note += `⚠️ You only have ONE recovery method.\\n`;\n note += ` Add more backups for better security:\\n`;\n\n if (!status.recoveryPhrase.encryptedBackups.length) {\n note += ` - Create encrypted backup\\n`;\n }\n\n if (!status.socialRecovery?.enabled) {\n note += ` - Set up social recovery\\n`;\n }\n } else if (methods.length === 2) {\n note += `🟡 Good! You have ${methods.length} recovery methods.\\n`;\n\n if (!status.socialRecovery?.enabled) {\n note += ` Consider adding social recovery for maximum security.\\n`;\n }\n } else {\n note += `🟢 Excellent! You have ${methods.length} recovery methods.\\n`;\n note += ` Your wallet is well-protected!\\n`;\n }\n\n return note;\n }\n\n /**\n * Run interactive test\n */\n async runInteractiveTest(\n currentStatus: BackupStatus\n ): Promise<{\n scenarios: SimulationResult[];\n overallScore: number;\n feedback: string;\n }> {\n const scenarios = this.getScenarios();\n const results: SimulationResult[] = [];\n\n for (const scenario of scenarios) {\n const result = await this.simulateScenario(scenario, currentStatus);\n results.push(result);\n }\n\n // Calculate score\n const successCount = results.filter((r) => r.success).length;\n const overallScore = (successCount / scenarios.length) * 100;\n\n let feedback = '';\n\n if (overallScore === 100) {\n feedback = `🏆 PERFECT SCORE!\\n\\nYou can recover in ALL scenarios.\\nYour wallet is extremely well-protected!`;\n } else if (overallScore >= 75) {\n feedback = `🟢 GREAT JOB!\\n\\nYou can recover in ${successCount}/${scenarios.length} scenarios.\\nConsider adding more backup methods for complete coverage.`;\n } else if (overallScore >= 50) {\n feedback = `🟡 GOOD START!\\n\\nYou can recover in ${successCount}/${scenarios.length} scenarios.\\nAdd more backup methods to improve security.`;\n } else {\n feedback = `⚠️ AT RISK!\\n\\nYou can only recover in ${successCount}/${scenarios.length} scenarios.\\nUrgently add backup methods to protect your wallet!`;\n }\n\n return {\n scenarios: results,\n overallScore,\n feedback,\n };\n }\n}\n","/**\n * Educational Content\n * Explainers for users to understand security concepts\n */\n\nexport interface EducationalModule {\n title: string;\n content: string;\n visual?: string;\n interactive?: string;\n}\n\nexport const educationalModules: Record<string, EducationalModule> = {\n whatIsPasskey: {\n title: 'What is a Passkey?',\n content: `\nThink of a passkey like your house smart lock:\n\n🔑 Traditional Key (Password):\n- Can be stolen\n- Can be forgotten\n- Same key opens many doors\n- Written on paper or in memory\n\n🏠 Smart Lock (Passkey):\n- Biometric only (your face/finger)\n- Can't be stolen or forgotten\n- Unique per device\n- Auto-syncs to your other devices\n\nHOW IT WORKS:\n1. You create a passkey with your fingerprint\n2. Your device stores it securely (hardware-protected)\n3. It syncs to your other devices automatically\n4. Only YOU can use it (with your biometric)\n\nSECURITY:\n- The private key never leaves your device\n- Cannot be phished (checks website domain)\n- Cannot be guessed or brute-forced\n- Requires physical access to your device + your biometric\n`,\n interactive: 'Try authenticating now →',\n },\n\n whatIsRecoveryPhrase: {\n title: 'What is a Recovery Phrase?',\n content: `\nYour 12 words are like a master key to your cryptocurrency wallet.\n\n🌱 12 Words = Your Entire Wallet:\n- Generate unlimited accounts\n- Sign transactions\n- Prove ownership of funds\n- Recover on ANY wallet app\n\nHOW IT WORKS:\n1. 12 random words from dictionary\n2. Creates a \"seed\" using math\n3. Seed generates your private keys\n4. Private keys control your crypto\n\nWHY 12 WORDS?\n- 2^128 possible combinations\n- Would take billions of years to guess\n- Easy for humans to write down\n- Works in any BIP39 wallet\n\nCRITICAL SECURITY:\n⚠️ Anyone with these words = OWNS your wallet\n⚠️ Cannot be changed or reset\n⚠️ Lost words = Lost wallet forever\n⚠️ Store safely offline\n\nBEST PRACTICES:\n✓ Write on paper (offline)\n✓ Store in safe/vault\n✓ Never type in computer (except during setup)\n✓ Never share with anyone\n✓ Make encrypted backup (password-protected)\n✓ Consider social recovery (split among friends)\n`,\n },\n\n howDoesSyncWork: {\n title: 'How Does Passkey Sync Work?',\n content: `\nYour passkey and wallet use TWO layers of protection:\n\nLAYER 1: PASSKEY (Auto-Syncs)\n------------------------------\nYour passkey credential syncs via:\n- iCloud Keychain (Apple)\n- Google Password Manager (Android)\n- Microsoft Account (Windows)\n\nWhat syncs:\n✓ Passkey credential\n✓ Public key\n✓ User info\n\nWhat DOESN'T sync:\n✗ Your 12-word mnemonic\n✗ Private keys\n✗ Wallet contents\n\nLAYER 2: ENCRYPTED WALLET (Local)\n----------------------------------\nYour wallet is encrypted and stored in:\n- Browser's IndexedDB\n- Encrypted with passkey-derived key\n- Can ONLY be decrypted with passkey\n\nTHE SYNC FLOW:\n\nDevice 1 (iPhone) → iCloud → Device 2 (Mac)\n Passkey created Syncs Passkey available\n Wallet encrypted ---- Decrypt with passkey\n\n\nWHAT THIS MEANS:\n- Passkey syncs = Convenient\n- Wallet encrypted = Secure\n- Need both = Protected\n- Works across devices = Seamless\n\nSECURITY:\n- Even if iCloud is hacked, wallet stays encrypted\n- Even if wallet is copied, can't decrypt without passkey\n- Both layers needed to access funds\n`,\n visual: `\n┌─────────────────────────────────────────────┐\n│ DEVICE 1 DEVICE 2 │\n│ │\n│ 🔑 Passkey ──────┐ ┌───── 🔑 Passkey │\n│ │ │ │\n│ 🔒 Wallet ◄───┼────┼───► 🔒 Wallet │\n│ (encrypted) │ │ (encrypted) │\n│ │ │ │\n│ ☁️ iCloud ☁️ │\n│ (passkey syncs) │\n└─────────────────────────────────────────────┘\n`,\n },\n\n whyBackupMatters: {\n title: 'Why Backup Matters',\n content: `\nCryptocurrency is PERMANENT. There's no \"reset password\" button.\n\nREAL SCENARIOS:\n---------------\n\n💸 James lost $7.4M in Bitcoin\n - Hard drive thrown away\n - No backup\n - Bitcoin lost forever\n\n💸 Stefan lost $200K in Ethereum\n - Forgot password\n - No recovery phrase saved\n - Wallet locked permanently\n\n💸 Maria recovered $500K\n - Phone stolen\n - Had encrypted backup\n - Recovered in 5 minutes ✓\n\nTHE MATH:\n---------\n\nNo backup:\n- Lose device = Lose wallet (100% loss)\n- Forget password = Lose wallet (100% loss)\n- Device breaks = Lose wallet (100% loss)\n\nWith backup:\n- Lose device = Recover from backup ✓\n- Forget password = Use recovery phrase ✓\n- Device breaks = Use social recovery ✓\n\nBACKUP LAYERS:\n--------------\n\nLayer 1: Passkey (convenience)\n- Auto-syncs\n- Easy to use\n- Platform-dependent\n\nLayer 2: Encrypted Backup (universal)\n- Works anywhere\n- Password-protected\n- Portable\n\nLayer 3: Social Recovery (ultimate)\n- Friends help you\n- No single point of failure\n- Most secure\n\nRECOMMENDATION:\nUse ALL THREE for maximum security!\n`,\n },\n\n socialRecoveryExplained: {\n title: 'Social Recovery Explained',\n content: `\nSocial recovery lets trusted friends/family help you recover your wallet.\n\nHOW IT WORKS (3-of-5 Example):\n------------------------------\n\n1. Your 12-word phrase is split into 5 pieces\n2. Each piece goes to a trusted guardian\n3. Any 3 pieces can reconstruct your phrase\n4. Any 2 pieces reveal NOTHING\n\nTHE MATH (Shamir Secret Sharing):\n---------------------------------\n\nExample: Secret = \"apple\"\n\nSplit into 5 shares:\n- Share 1: \"x7k9m\"\n- Share 2: \"p2n4q\"\n- Share 3: \"w8j3z\"\n- Share 4: \"r5h1v\"\n- Share 5: \"c6y2b\"\n\nCombine any 3 → Get \"apple\"\nHave only 2 → Impossible to recover\n\nCHOOSING GUARDIANS:\n------------------\n\n✓ GOOD Guardians:\n- Family members\n- Close friends\n- Geographically distributed\n- Tech-savvy\n- Long-term relationships\n\n✗ BAD Guardians:\n- Strangers\n- Same location (house fire risk)\n- Not reliable\n- Can't handle QR codes\n\nSECURITY:\n---------\n\nMath proves:\n- Need EXACTLY 3 shares\n- 2 shares = 0% information\n- 4 shares = 100% redundancy\n- Guardians can't collude unless threshold met\n\nRECOVERY FLOW:\n-------------\n\n1. You lose wallet access\n2. Contact 3 guardians\n3. Each provides their share\n4. System combines shares\n5. Wallet reconstructed ✓\n\nTimeline: ~24 hours\n(depends on guardian availability)\n`,\n },\n\n encryptedBackupSecurity: {\n title: 'Encrypted Backup Security',\n content: `\nYour encrypted backup uses military-grade encryption.\n\nENCRYPTION DETAILS:\n------------------\n\nPassword → PBKDF2 (310,000 iterations)\n ↓\n 256-bit AES Key\n ↓\n AES-256-GCM Encryption\n ↓\n Encrypted Backup\n\nWHAT THIS MEANS:\n---------------\n\n310,000 iterations:\n- Makes brute-force extremely slow\n- Would take centuries to crack\n- OWASP 2025 standard\n\nAES-256-GCM:\n- Used by governments/military\n- Authenticated encryption\n- Cannot be tampered with\n\nATTACK SCENARIOS:\n----------------\n\nQ: What if Google Drive is hacked?\nA: Attacker gets encrypted file (useless without password)\n\nQ: What if someone gets your password?\nA: Need BOTH password AND backup file\n\nQ: What if someone tries to brute-force?\nA: 310,000 iterations makes this impractical\n\nQ: Can the backup be tampered with?\nA: No - GCM mode detects any changes\n\nPASSWORD STRENGTH:\n-----------------\n\nWEAK (❌ Rejected):\n- \"password123\"\n- \"qwerty\"\n- \"12345678\"\n\nGOOD (✓ Accepted):\n- \"MyDog-Loves-Pizza-2025!\"\n- \"Tr0ub4dor&3-Extra-Secure\"\n- \"correct-horse-battery-staple-99\"\n\nSTRONG (✓✓ Recommended):\n- 16+ characters\n- Mix of upper/lower/numbers/symbols\n- Not in dictionary\n- Unique to this backup\n\nSTORAGE OPTIONS:\n---------------\n\n✓ Safe to store encrypted backup in:\n- Google Drive\n- Dropbox\n- iCloud\n- USB drive\n- Email to yourself\n\nThe encryption makes it safe even in cloud!\n`,\n },\n};\n\n/**\n * Get explainer by topic\n */\nexport function getExplainer(topic: string): EducationalModule | null {\n return educationalModules[topic] || null;\n}\n\n/**\n * Get all explainer topics\n */\nexport function getAllTopics(): string[] {\n return Object.keys(educationalModules);\n}\n\n/**\n * Search explainers\n */\nexport function searchExplainers(query: string): EducationalModule[] {\n const lowerQuery = query.toLowerCase();\n return Object.values(educationalModules).filter(\n (module) =>\n module.title.toLowerCase().includes(lowerQuery) ||\n module.content.toLowerCase().includes(lowerQuery)\n );\n}\n","/**\n * Education Module\n * Interactive educational content and recovery scenario simulator\n */\n\nexport { RecoverySimulator } from './simulator';\nexport * from './explainers';\n","import { startRegistration } from \"@simplewebauthn/browser\";\nimport { RegistrationError } from \"../core/errors\";\nimport { assertUsername, assertEthereumAddress } from \"../utils/validation\";\nimport type { RegisterOptions } from \"./types\";\nimport { CredentialStorage } from \"./storage\";\n\nfunction generateChallenge(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return btoa(String.fromCharCode(...array))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\n\nexport async function register(options: RegisterOptions): Promise<{ signature: ArrayBuffer }> {\n try {\n const { username, ethereumAddress } = options;\n\n assertUsername(username);\n assertEthereumAddress(ethereumAddress);\n\n const storage = new CredentialStorage();\n\n if (storage.userExists(username)) {\n throw new Error(\"Username already registered\");\n }\n\n const challenge = generateChallenge();\n\n const registrationOptions = {\n challenge,\n rp: {\n name: \"w3pk\",\n id: window.location.hostname,\n },\n user: {\n id: username,\n name: username,\n displayName: username,\n },\n pubKeyCredParams: [\n { type: \"public-key\" as const, alg: -7 },\n { type: \"public-key\" as const, alg: -257 },\n ],\n authenticatorSelection: {\n authenticatorAttachment: \"platform\" as const,\n userVerification: \"required\" as const,\n residentKey: \"required\" as const,\n requireResidentKey: true,\n },\n timeout: 60000,\n attestation: \"none\" as const,\n };\n\n const credential = await startRegistration({\n optionsJSON: registrationOptions,\n });\n const publicKey = credential.response.publicKey;\n\n if (!publicKey) {\n throw new Error(\"Public key not returned from authenticator\");\n }\n\n storage.saveCredential({\n id: credential.id,\n publicKey,\n username,\n ethereumAddress,\n createdAt: Date.now(),\n lastUsed: Date.now(),\n });\n\n // Extract attestation signature for wallet encryption\n // The attestationObject contains the authenticator's signature\n console.log(\"[register] Credential response:\", credential.response);\n const attestationObject = credential.response.attestationObject;\n console.log(\"[register] Attestation object:\", attestationObject);\n\n if (!attestationObject) {\n throw new Error(\"Attestation object not returned from authenticator\");\n }\n\n // Decode the attestationObject (it's base64url encoded CBOR)\n const attestationBuffer = base64ToArrayBuffer(attestationObject);\n console.log(\"[register] Attestation buffer length:\", attestationBuffer.byteLength);\n\n // For now, we'll use the raw attestation data as our signature material\n // This is cryptographically signed by the authenticator during registration\n return { signature: attestationBuffer };\n } catch (error) {\n throw new RegistrationError(\n error instanceof Error ? error.message : \"Registration failed\",\n error\n );\n }\n}\n\nfunction base64ToArrayBuffer(base64: string): ArrayBuffer {\n const base64Clean = base64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64Clean);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n","/**\n * Input validation utilities\n */\n\nexport function validateEthereumAddress(address: string): boolean {\n return /^0x[a-fA-F0-9]{40}$/.test(address);\n}\n\nexport function validateUsername(username: string): boolean {\n return username.length >= 3 && username.length <= 50;\n}\n\nexport function validateMnemonic(mnemonic: string): boolean {\n const words = mnemonic.trim().split(/\\s+/);\n return words.length === 12 || words.length === 24;\n}\n\nexport function assertEthereumAddress(address: string): void {\n if (!validateEthereumAddress(address)) {\n throw new Error(\"Invalid Ethereum address format\");\n }\n}\n\nexport function assertUsername(username: string): void {\n if (!validateUsername(username)) {\n throw new Error(\"Username must be between 3 and 50 characters\");\n }\n}\n\nexport function assertMnemonic(mnemonic: string): void {\n if (!validateMnemonic(mnemonic)) {\n throw new Error(\"Invalid mnemonic: must be 12 or 24 words\");\n }\n}\n\n/**\n * Validates password strength based on security best practices\n * @param password - The password to validate\n * @returns true if password meets strength requirements, false otherwise\n *\n * Requirements:\n * - At least 12 characters long\n * - Contains at least one uppercase letter\n * - Contains at least one lowercase letter\n * - Contains at least one number\n * - Contains at least one special character\n * - Not a common password\n */\nexport function isStrongPassword(password: string): boolean {\n // Length check\n if (password.length < 12) {\n return false;\n }\n\n // Character requirements\n const hasUppercase = /[A-Z]/.test(password);\n const hasLowercase = /[a-z]/.test(password);\n const hasNumber = /[0-9]/.test(password);\n const hasSpecialChar = /[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password);\n\n if (!hasUppercase || !hasLowercase || !hasNumber || !hasSpecialChar) {\n return false;\n }\n\n // Common password check\n const commonPasswords = [\n 'password',\n '12345678',\n 'qwerty',\n 'abc123',\n 'password123',\n 'admin',\n 'letmein',\n ];\n\n if (commonPasswords.some((common) => password.toLowerCase().includes(common))) {\n return false;\n }\n\n return true;\n}\n","import { startAuthentication } from \"@simplewebauthn/browser\";\nimport { AuthenticationError } from \"../core/errors\";\nimport type { AuthResult } from \"./types\";\nimport type { StoredCredential } from \"./storage\";\nimport { CredentialStorage } from \"./storage\";\n\nfunction generateChallenge(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return btoa(String.fromCharCode(...array))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\nexport async function login(): Promise<AuthResult> {\n try {\n const storage = new CredentialStorage();\n const challenge = generateChallenge();\n\n const authOptions = {\n challenge,\n rpId: window.location.hostname,\n userVerification: \"required\" as const,\n timeout: 60000,\n };\n\n const assertion = await startAuthentication({\n optionsJSON: authOptions,\n });\n\n const credential = storage.getCredentialById(assertion.id);\n\n if (!credential) {\n throw new Error(\"Credential not found\");\n }\n\n const isValid = await verifyAssertion(assertion, credential);\n\n if (!isValid) {\n throw new Error(\"Signature verification failed\");\n }\n\n storage.updateLastUsed(credential.id);\n\n // SECURITY: Return the signature so it can be used to derive encryption keys\n // The signature can ONLY be obtained through biometric/PIN authentication\n const signatureBuffer = base64ToArrayBuffer(assertion.response.signature);\n\n return {\n verified: true,\n user: {\n username: credential.username,\n ethereumAddress: credential.ethereumAddress,\n credentialId: credential.id,\n },\n signature: signatureBuffer,\n };\n } catch (error) {\n throw new AuthenticationError(\n error instanceof Error ? error.message : \"Authentication failed\",\n error\n );\n }\n}\n\nasync function verifyAssertion(\n assertion: any,\n credential: StoredCredential\n): Promise<boolean> {\n try {\n const publicKeyBuffer = base64ToArrayBuffer(credential.publicKey);\n const publicKey = await crypto.subtle.importKey(\n \"spki\",\n publicKeyBuffer,\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n },\n false,\n [\"verify\"]\n );\n\n const authenticatorData = base64ToArrayBuffer(\n assertion.response.authenticatorData\n );\n\n // clientDataJSON comes as base64url string, need to decode it first\n const clientDataJSON = assertion.response.clientDataJSON;\n let clientDataJSONString: string;\n\n // Check if it's already a JSON string or base64url encoded\n if (clientDataJSON.startsWith('eyJ')) {\n // It's base64url encoded, decode it\n const decoded = atob(clientDataJSON.replace(/-/g, '+').replace(/_/g, '/'));\n clientDataJSONString = decoded;\n } else {\n // It's already a JSON string\n clientDataJSONString = clientDataJSON;\n }\n\n const clientDataHash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(clientDataJSONString)\n );\n\n const signedData = new Uint8Array(\n authenticatorData.byteLength + clientDataHash.byteLength\n );\n signedData.set(new Uint8Array(authenticatorData), 0);\n signedData.set(\n new Uint8Array(clientDataHash),\n authenticatorData.byteLength\n );\n\n const signature = base64ToArrayBuffer(assertion.response.signature);\n const rawSignature = derToRaw(new Uint8Array(signature));\n\n const isValid = await crypto.subtle.verify(\n {\n name: \"ECDSA\",\n hash: \"SHA-256\",\n },\n publicKey,\n rawSignature,\n signedData\n );\n\n return isValid;\n } catch (error) {\n console.error(\"Signature verification error:\", error);\n return false;\n }\n}\n\nfunction base64ToArrayBuffer(base64: string): ArrayBuffer {\n const base64Clean = base64.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64Clean);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nfunction derToRaw(der: Uint8Array): ArrayBuffer {\n let offset = 2;\n\n offset++;\n let rLength = der[offset++];\n if (rLength > 32) {\n offset++;\n rLength--;\n }\n const r = der.slice(offset, offset + rLength);\n offset += rLength;\n\n offset++;\n let sLength = der[offset++];\n if (sLength > 32) {\n offset++;\n sLength--;\n }\n const s = der.slice(offset, offset + sLength);\n\n const raw = new Uint8Array(64);\n raw.set(r, 32 - r.length);\n raw.set(s, 64 - s.length);\n\n return raw.buffer;\n}\n","/**\n * IndexedDB storage for encrypted wallet data\n */\n\nimport { StorageError } from \"../core/errors\";\nimport type { EncryptedWalletData, WalletStorage } from \"./types\";\n\nconst DB_NAME = \"Web3PasskeyWallet\";\nconst DB_VERSION = 1;\nconst STORE_NAME = \"wallets\";\n\nexport class IndexedDBWalletStorage implements WalletStorage {\n private db: IDBDatabase | null = null;\n\n async init(): Promise<void> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n\n request.onerror = () =>\n reject(new StorageError(\"Failed to open database\", request.error));\n\n request.onsuccess = () => {\n this.db = request.result;\n resolve();\n };\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: \"ethereumAddress\" });\n }\n };\n });\n }\n\n async store(data: EncryptedWalletData): Promise<void> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readwrite\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.put(data);\n request.onerror = () =>\n reject(new StorageError(\"Failed to store wallet data\", request.error));\n request.onsuccess = () => resolve();\n });\n }\n\n async retrieve(ethereumAddress: string): Promise<EncryptedWalletData | null> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readonly\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.get(ethereumAddress);\n request.onerror = () =>\n reject(\n new StorageError(\"Failed to retrieve wallet data\", request.error)\n );\n request.onsuccess = () => resolve(request.result || null);\n });\n }\n\n async delete(ethereumAddress: string): Promise<void> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readwrite\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.delete(ethereumAddress);\n request.onerror = () =>\n reject(new StorageError(\"Failed to delete wallet data\", request.error));\n request.onsuccess = () => resolve();\n });\n }\n\n async clear(): Promise<void> {\n if (!this.db) await this.init();\n\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], \"readwrite\");\n const store = transaction.objectStore(STORE_NAME);\n\n const request = store.clear();\n request.onerror = () =>\n reject(new StorageError(\"Failed to clear wallet data\", request.error));\n request.onsuccess = () => resolve();\n });\n }\n}\n","/**\n * BIP39 wallet generation\n */\n\nimport { ethers } from \"ethers\";\nimport { WalletError } from \"../core/errors\";\nimport type { WalletData } from \"./types\";\n\n/**\n * Generates a new BIP39 wallet with HD derivation\n * Uses BIP44 path: m/44'/60'/0'/0/0 for Ethereum\n */\nexport function generateBIP39Wallet(): WalletData {\n try {\n // Generate random mnemonic using ethers' utility\n const mnemonic = ethers.Wallet.createRandom().mnemonic;\n\n if (!mnemonic) {\n throw new Error(\"Failed to generate mnemonic\");\n }\n\n const mnemonicPhrase = mnemonic.phrase;\n\n // Create HD wallet from mnemonic phrase with derivation path\n const derivationPath = \"m/44'/60'/0'/0/0\";\n const hdWallet = ethers.HDNodeWallet.fromPhrase(\n mnemonicPhrase,\n undefined,\n derivationPath\n );\n\n return {\n address: hdWallet.address,\n mnemonic: mnemonicPhrase,\n };\n } catch (error) {\n throw new WalletError(\"Wallet generation failed\", error);\n }\n}\n\n/**\n * Creates wallet from mnemonic phrase\n * Uses BIP44 path: m/44'/60'/0'/0/0\n */\nexport function createWalletFromMnemonic(\n mnemonic: string\n): ethers.HDNodeWallet {\n try {\n if (!mnemonic || mnemonic.trim().split(/\\s+/).length < 12) {\n throw new Error(\"Invalid mnemonic: must be at least 12 words\");\n }\n\n // Create HD wallet with derivation path directly\n const derivationPath = \"m/44'/60'/0'/0/0\";\n const wallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic.trim(),\n undefined,\n derivationPath\n );\n\n return wallet;\n } catch (error) {\n throw new WalletError(\n `Wallet creation failed: ${\n error instanceof Error ? error.message : \"Invalid mnemonic\"\n }`,\n error\n );\n }\n}\n\n/**\n * Derives HD wallet address and private key at specific index\n * Uses BIP44 path: m/44'/60'/0'/0/{index}\n */\nexport function deriveWalletFromMnemonic(\n mnemonic: string,\n index: number = 0\n): { address: string; privateKey: string } {\n try {\n if (!mnemonic || mnemonic.trim().split(/\\s+/).length < 12) {\n throw new Error(\"Invalid mnemonic: must be at least 12 words\");\n }\n\n if (index < 0 || !Number.isInteger(index)) {\n throw new Error(\"Index must be a non-negative integer\");\n }\n\n // Create HD wallet with derivation path including index\n const derivationPath = `m/44'/60'/0'/0/${index}`;\n const wallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic.trim(),\n undefined,\n derivationPath\n );\n\n return {\n address: wallet.address,\n privateKey: wallet.privateKey,\n };\n } catch (error) {\n throw new WalletError(\n `HD wallet derivation failed: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n error\n );\n }\n}\n","/**\n * Main Web3Passkey SDK class - Client-Only Version\n * No server required - all authentication happens locally\n */\n\nimport { register } from \"../auth/register\";\nimport { login } from \"../auth/authenticate\";\nimport { IndexedDBWalletStorage } from \"../wallet/storage\";\nimport {\n generateBIP39Wallet,\n deriveWalletFromMnemonic,\n} from \"../wallet/generate\";\nimport {\n deriveEncryptionKeyFromWebAuthn,\n encryptData,\n decryptData,\n} from \"../wallet/crypto\";\nimport { StealthAddressModule } from \"../stealth\";\nimport { SessionManager } from \"./session\";\n// ZK module imported dynamically to avoid bundling dependencies\nimport type { Web3PasskeyConfig, InternalConfig } from \"./config\";\nimport { DEFAULT_CONFIG } from \"./config\";\nimport type { UserInfo, WalletInfo } from \"../types\";\nimport { AuthenticationError, WalletError } from \"./errors\";\nimport { getEndpoints } from \"../chainlist\";\nimport { supportsEIP7702 } from \"../eip7702\";\n\nexport class Web3Passkey {\n private config: InternalConfig;\n private walletStorage: IndexedDBWalletStorage;\n private currentUser: UserInfo | null = null;\n private currentWallet: WalletInfo | null = null;\n private sessionManager: SessionManager;\n\n // Optional modules\n public stealth?: StealthAddressModule;\n private zkModule?: any;\n\n constructor(config: Web3PasskeyConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config } as InternalConfig;\n this.walletStorage = new IndexedDBWalletStorage();\n this.sessionManager = new SessionManager(config.sessionDuration || 1);\n\n // Initialize optional modules\n if (config.stealthAddresses !== undefined) {\n this.stealth = new StealthAddressModule(\n config.stealthAddresses,\n (requireAuth?: boolean) => this.getMnemonicFromSession(requireAuth)\n );\n }\n\n // ZK module will be lazy-loaded on first access (no eager initialization)\n }\n\n /**\n * Lazy-load ZK module only when accessed\n * This prevents bundlers from including circomlibjs unless ZK features are used\n */\n private async loadZKModule() {\n if (this.zkModule) {\n return this.zkModule;\n }\n\n try {\n // Use Function constructor to completely hide import from webpack\n const dynamicImport = new Function(\"path\", \"return import(path)\");\n const { ZKProofModule } = await dynamicImport(\"w3pk/zk\");\n const zkConfig = (this.config as any).zkProofs || {};\n this.zkModule = new ZKProofModule(zkConfig);\n return this.zkModule;\n } catch (error) {\n throw new Error(\n \"ZK module not available. Install dependencies: npm install snarkjs circomlibjs\"\n );\n }\n }\n\n /**\n * Get mnemonic from active session or trigger authentication\n * This is used internally by methods that need the mnemonic\n *\n * @param forceAuth - If true, bypass session cache and require fresh authentication\n */\n private async getMnemonicFromSession(\n forceAuth: boolean = false\n ): Promise<string> {\n // Check if session is active (unless force auth is required)\n if (!forceAuth) {\n const cachedMnemonic = this.sessionManager.getMnemonic();\n if (cachedMnemonic) {\n return cachedMnemonic;\n }\n }\n\n // Session expired, doesn't exist, or force auth requested - need to authenticate\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated. Call login() first.\");\n }\n\n // Get encrypted wallet\n const walletData = await this.walletStorage.retrieve(\n this.currentUser.ethereumAddress\n );\n\n if (!walletData) {\n throw new WalletError(\"No wallet found. Generate a wallet first.\");\n }\n\n // Authenticate to prove identity\n const authResult = await login();\n if (!authResult.user) {\n throw new WalletError(\"Authentication failed\");\n }\n\n // Get credential to access public key\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialById(walletData.credentialId);\n const publicKey = credential?.publicKey;\n\n // Derive decryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n walletData.credentialId,\n publicKey\n );\n\n // Decrypt mnemonic\n const mnemonic = await decryptData(\n walletData.encryptedMnemonic,\n encryptionKey\n );\n\n // Start new session with decrypted mnemonic\n this.sessionManager.startSession(mnemonic, walletData.credentialId);\n\n return mnemonic;\n }\n\n /**\n * Register a new user with WebAuthn\n * Automatically generates a wallet if none exists\n * Creates a passkey and associates it with the Ethereum address (account #0)\n * Returns the derived address #0 and username\n */\n async register(options: {\n username: string;\n }): Promise<{ address: string; username: string }> {\n try {\n // Auto-generate wallet if it doesn't exist\n if (!this.currentWallet?.address) {\n await this.generateWallet();\n }\n\n // Derive account #0 address from the generated wallet\n const ethereumAddress = this.currentWallet!.address;\n const mnemonic = this.currentWallet!.mnemonic!;\n\n await register({\n username: options.username,\n ethereumAddress,\n });\n\n this.currentUser = {\n id: ethereumAddress,\n username: options.username,\n displayName: options.username,\n ethereumAddress,\n };\n\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialByAddress(ethereumAddress);\n\n if (!credential) {\n throw new WalletError(\"Credential not found after registration\");\n }\n\n const credentialId = credential.id;\n const publicKey = credential.publicKey;\n\n // Derive encryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n credentialId,\n publicKey\n );\n\n const encryptedMnemonic = await encryptData(mnemonic, encryptionKey);\n\n await this.walletStorage.store({\n ethereumAddress: this.currentUser.ethereumAddress,\n encryptedMnemonic,\n credentialId,\n createdAt: Date.now(),\n });\n\n this.sessionManager.startSession(mnemonic, credentialId);\n\n // Set currentWallet to ensure wallet state is available\n this.currentWallet = {\n address: ethereumAddress,\n mnemonic,\n };\n\n this.config.onAuthStateChanged?.(true, this.currentUser);\n\n return { address: ethereumAddress, username: options.username };\n } catch (error) {\n this.config.onError?.(error as any);\n throw error;\n }\n }\n\n /**\n * Login with WebAuthn (usernameless)\n * Uses resident credentials stored in the authenticator\n * Automatically starts a session with the decrypted mnemonic\n */\n async login(): Promise<UserInfo> {\n try {\n const result = await login();\n\n if (!result.verified || !result.user) {\n throw new AuthenticationError(\"Login failed\");\n }\n\n this.currentUser = {\n id: result.user.ethereumAddress,\n username: result.user.username,\n displayName: result.user.username,\n ethereumAddress: result.user.ethereumAddress,\n };\n\n // Get encrypted wallet data\n const walletData = await this.walletStorage.retrieve(\n this.currentUser.ethereumAddress\n );\n\n if (!walletData) {\n throw new WalletError(\n \"No wallet found for this user. You may need to register first.\"\n );\n }\n\n // Get credential to access public key\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialById(walletData.credentialId);\n const publicKey = credential?.publicKey;\n\n // Derive decryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n walletData.credentialId,\n publicKey\n );\n\n // Decrypt mnemonic\n const mnemonic = await decryptData(\n walletData.encryptedMnemonic,\n encryptionKey\n );\n\n // Start session with decrypted mnemonic\n this.sessionManager.startSession(mnemonic, walletData.credentialId);\n\n this.config.onAuthStateChanged?.(true, this.currentUser);\n\n return this.currentUser;\n } catch (error) {\n this.config.onError?.(error as any);\n throw error;\n }\n }\n\n /**\n * Logout the current user\n * Clears the active session and removes cached mnemonic from memory\n */\n async logout(): Promise<void> {\n this.currentUser = null;\n this.currentWallet = null;\n this.sessionManager.clearSession();\n this.config.onAuthStateChanged?.(false, undefined);\n }\n\n /**\n * Get current authentication status\n */\n get isAuthenticated(): boolean {\n return this.currentUser !== null;\n }\n\n /**\n * Get current user info\n */\n get user(): UserInfo | null {\n return this.currentUser;\n }\n\n /**\n * Generate a new BIP39 wallet\n * Returns the mnemonic phrase (12 words)\n */\n async generateWallet(): Promise<{ mnemonic: string }> {\n try {\n const wallet = generateBIP39Wallet();\n\n this.currentWallet = {\n address: wallet.address,\n mnemonic: wallet.mnemonic,\n };\n\n return {\n mnemonic: wallet.mnemonic,\n };\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to generate wallet\", error);\n }\n }\n\n /**\n * Derive an HD wallet at a specific index\n *\n * SECURITY: Uses active session or prompts for authentication if session expired\n *\n * @param index - The HD wallet derivation index\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async deriveWallet(\n index: number,\n options?: { requireAuth?: boolean }\n ): Promise<WalletInfo> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to derive wallet\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(options?.requireAuth);\n\n const derived = deriveWalletFromMnemonic(mnemonic, index);\n\n return {\n address: derived.address,\n privateKey: derived.privateKey,\n };\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to derive wallet\", error);\n }\n }\n\n /**\n * Export the mnemonic phrase\n *\n * SECURITY: Uses active session or prompts for authentication if session expired\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async exportMnemonic(options?: { requireAuth?: boolean }): Promise<string> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to export mnemonic\");\n }\n\n return await this.getMnemonicFromSession(options?.requireAuth);\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to export mnemonic\", error);\n }\n }\n\n /**\n * Import a mnemonic phrase\n * Encrypts and stores it for the current user\n * Requires fresh WebAuthn authentication for security\n * WARNING: This will overwrite any existing wallet for this user\n */\n async importMnemonic(mnemonic: string): Promise<void> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to import mnemonic\");\n }\n\n if (!mnemonic || mnemonic.trim().split(/\\s+/).length < 12) {\n throw new WalletError(\"Invalid mnemonic: must be at least 12 words\");\n }\n\n const authResult = await login();\n if (!authResult.user) {\n throw new WalletError(\"Authentication failed\");\n }\n\n const credentialId = authResult.user.credentialId;\n\n // Get credential to access public key\n const storage = new (await import(\"../auth/storage\")).CredentialStorage();\n const credential = storage.getCredentialById(credentialId);\n const publicKey = credential?.publicKey;\n\n // Derive encryption key from WebAuthn credential\n const encryptionKey = await deriveEncryptionKeyFromWebAuthn(\n credentialId,\n publicKey\n );\n\n const encryptedMnemonic = await encryptData(\n mnemonic.trim(),\n encryptionKey\n );\n\n await this.walletStorage.store({\n ethereumAddress: this.currentUser.ethereumAddress,\n encryptedMnemonic,\n credentialId,\n createdAt: Date.now(),\n });\n\n this.currentWallet = {\n address: this.currentUser.ethereumAddress,\n mnemonic: mnemonic.trim(),\n };\n\n this.sessionManager.startSession(mnemonic.trim(), credentialId);\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to import mnemonic\", error);\n }\n }\n\n /**\n * Sign a message with the wallet\n *\n * SECURITY: Uses active session or prompts for authentication if session expired\n *\n * @param message - The message to sign\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async signMessage(\n message: string,\n options?: { requireAuth?: boolean }\n ): Promise<string> {\n try {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to sign message\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(options?.requireAuth);\n\n const { Wallet } = await import(\"ethers\");\n const wallet = Wallet.fromPhrase(mnemonic);\n\n const signature = await wallet.signMessage(message);\n\n return signature;\n } catch (error) {\n this.config.onError?.(error as any);\n throw new WalletError(\"Failed to sign message\", error);\n }\n }\n\n /**\n * Get RPC endpoints for a chain\n */\n async getEndpoints(chainId: number): Promise<string[]> {\n return getEndpoints(chainId);\n }\n\n /**\n * Check if a network supports EIP-7702\n */\n async supportsEIP7702(\n chainId: number,\n options?: { maxEndpoints?: number; timeout?: number }\n ): Promise<boolean> {\n return supportsEIP7702(chainId, this.getEndpoints.bind(this), options);\n }\n\n /**\n * Access ZK proof module (if available)\n */\n get zk(): any {\n // Return a proxy that loads ZK module on first method call\n return new Proxy(\n {},\n {\n get: (_target, prop) => {\n return async (...args: any[]) => {\n const zkModule = await this.loadZKModule();\n return zkModule[prop](...args);\n };\n },\n }\n );\n }\n\n // ========================================\n // Backup and Recovery\n // ========================================\n\n /**\n * Get comprehensive backup status\n * Shows user exactly what protects their wallet\n */\n async getBackupStatus(): Promise<any> {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to check backup status\");\n }\n\n const { BackupManager } = await import(\"../backup\");\n const backupManager = new BackupManager();\n return backupManager.getBackupStatus(this.currentUser.ethereumAddress);\n }\n\n /**\n * Create password-protected ZIP backup\n * @param password - Strong password to encrypt the backup\n * @param options - Optional backup configuration\n */\n async createZipBackup(\n password: string,\n options?: { includeInstructions?: boolean; deviceBinding?: boolean }\n ): Promise<Blob> {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to create backup\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(true); // Force auth for security\n\n const { BackupManager } = await import(\"../backup\");\n const backupManager = new BackupManager();\n\n return backupManager.createZipBackup(\n mnemonic,\n this.currentUser.ethereumAddress,\n { password, ...options }\n );\n }\n\n /**\n * Create QR code backup\n * @param password - Optional password to encrypt QR code\n * @param options - QR code configuration\n */\n async createQRBackup(\n password?: string,\n options?: { errorCorrection?: \"L\" | \"M\" | \"Q\" | \"H\" }\n ): Promise<{ qrCodeDataURL: string; instructions: string }> {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to create backup\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(true); // Force auth for security\n\n const { BackupManager } = await import(\"../backup\");\n const backupManager = new BackupManager();\n\n return backupManager.createQRBackup(\n mnemonic,\n this.currentUser.ethereumAddress,\n { password, ...options }\n );\n }\n\n /**\n * Set up social recovery\n * Splits mnemonic into M-of-N shares for guardian-based recovery\n *\n * @param guardians - Array of guardian information\n * @param threshold - Number of guardians required to recover (M in M-of-N)\n */\n async setupSocialRecovery(\n guardians: { name: string; email?: string; phone?: string }[],\n threshold: number\n ): Promise<any[]> {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to set up social recovery\");\n }\n\n const mnemonic = await this.getMnemonicFromSession(true); // Force auth for security\n\n const { SocialRecoveryManager } = await import(\"../recovery\");\n const socialRecovery = new SocialRecoveryManager();\n\n return socialRecovery.setupSocialRecovery(\n mnemonic,\n this.currentUser.ethereumAddress,\n guardians,\n threshold\n );\n }\n\n /**\n * Generate guardian invitation\n * Creates QR code and instructions for a guardian\n */\n async generateGuardianInvite(guardianId: string): Promise<any> {\n const { SocialRecoveryManager } = await import(\"../recovery\");\n const socialRecovery = new SocialRecoveryManager();\n\n const config = socialRecovery.getSocialRecoveryConfig();\n if (!config) {\n throw new WalletError(\"Social recovery not configured\");\n }\n\n const guardian = config.guardians.find((g) => g.id === guardianId);\n if (!guardian) {\n throw new WalletError(\"Guardian not found\");\n }\n\n return socialRecovery.generateGuardianInvite(guardian);\n }\n\n /**\n * Recover wallet from guardian shares\n * @param shares - Array of share data from guardians (JSON strings)\n */\n async recoverFromGuardians(\n shares: string[]\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n const { SocialRecoveryManager } = await import(\"../recovery\");\n const socialRecovery = new SocialRecoveryManager();\n\n return socialRecovery.recoverFromGuardians(shares);\n }\n\n /**\n * Restore wallet from encrypted backup\n * @param backupData - Backup file contents (JSON string)\n * @param password - Password used to encrypt the backup\n */\n async restoreFromBackup(\n backupData: string,\n password: string\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n const { BackupManager } = await import(\"../backup\");\n const backupManager = new BackupManager();\n\n return backupManager.restoreFromZipBackup(backupData, password);\n }\n\n /**\n * Restore wallet from QR code\n * @param qrData - Scanned QR code data (JSON string)\n * @param password - Optional password if QR was encrypted\n */\n async restoreFromQR(\n qrData: string,\n password?: string\n ): Promise<{ mnemonic: string; ethereumAddress: string }> {\n const { BackupManager } = await import(\"../backup\");\n const backupManager = new BackupManager();\n\n return backupManager.restoreFromQR(qrData, password);\n }\n\n /**\n * Get cross-device sync status\n * Shows which devices have access and sync capabilities\n */\n async getSyncStatus(): Promise<any> {\n const { DeviceManager } = await import(\"../sync\");\n const deviceManager = new DeviceManager();\n\n return deviceManager.getSyncStatus();\n }\n\n /**\n * Detect sync capabilities\n * Shows what platform sync is available (iCloud, Google, etc.)\n */\n async detectSyncCapabilities(): Promise<any> {\n const { PlatformDetector } = await import(\"../sync\");\n const detector = new PlatformDetector();\n\n return detector.detectSyncCapabilities();\n }\n\n /**\n * Simulate recovery scenario (educational)\n * Tests what happens in various loss scenarios\n *\n * @param scenario - Type of scenario to simulate\n */\n async simulateRecoveryScenario(scenario: {\n type: \"lost-device\" | \"lost-phrase\" | \"lost-both\" | \"switch-platform\";\n description: string;\n }): Promise<any> {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to run recovery simulation\");\n }\n\n const status = await this.getBackupStatus();\n\n const { RecoverySimulator } = await import(\"../education\");\n const simulator = new RecoverySimulator();\n\n return simulator.simulateScenario(scenario, status);\n }\n\n /**\n * Run interactive recovery test\n * Tests all recovery scenarios and provides feedback\n */\n async runRecoveryTest(): Promise<{\n scenarios: any[];\n overallScore: number;\n feedback: string;\n }> {\n if (!this.currentUser) {\n throw new WalletError(\"Must be authenticated to run recovery test\");\n }\n\n const status = await this.getBackupStatus();\n\n const { RecoverySimulator } = await import(\"../education\");\n const simulator = new RecoverySimulator();\n\n return simulator.runInteractiveTest(status);\n }\n\n /**\n * Get educational content\n * @param topic - Topic to explain (e.g., 'whatIsPasskey', 'socialRecoveryExplained')\n */\n async getEducation(topic: string): Promise<any> {\n const { getExplainer } = await import(\"../education\");\n const explainer = getExplainer(topic);\n\n if (!explainer) {\n throw new WalletError(`Unknown education topic: ${topic}`);\n }\n\n return explainer;\n }\n\n // ========================================\n // Session Management\n // ========================================\n\n /**\n * Check if there's an active session\n */\n hasActiveSession(): boolean {\n return this.sessionManager.isActive();\n }\n\n /**\n * Get remaining session time in seconds\n */\n getSessionRemainingTime(): number {\n return this.sessionManager.getRemainingTime();\n }\n\n /**\n * Extend the current session by the configured duration\n * Throws error if no active session or if session expired\n */\n extendSession(): void {\n try {\n this.sessionManager.extendSession();\n } catch (error) {\n throw new WalletError(\"Cannot extend session\", error);\n }\n }\n\n /**\n * Manually clear the active session\n * This removes the cached mnemonic from memory\n * User will need to authenticate again for wallet operations\n */\n clearSession(): void {\n this.sessionManager.clearSession();\n }\n\n /**\n * Update session duration (affects new sessions and extensions)\n * @param hours - Session duration in hours\n */\n setSessionDuration(hours: number): void {\n this.sessionManager.setSessionDuration(hours);\n }\n\n /**\n * SDK version\n */\n get version(): string {\n return \"0.7.2\";\n }\n}\n","/**\n * ERC-5564 Stealth Address Module for w3pk SDK\n * Provides privacy-preserving stealth address generation capabilities\n * following the ERC-5564 standard\n *\n * @see https://eips.ethereum.org/EIPS/eip-5564\n */\n\nimport { ethers } from \"ethers\";\nimport { Web3PasskeyError } from \"../core/errors\";\nimport {\n deriveStealthKeys,\n generateStealthAddress as generateERC5564StealthAddress,\n checkStealthAddress,\n computeStealthPrivateKey,\n type ParseResult\n} from \"./crypto\";\nimport type { StealthKeys, StealthAddressResult as CryptoStealthResult } from \"./crypto\";\n\nexport interface StealthAddressConfig {\n // Network-agnostic - no provider needed\n}\n\n/**\n * ERC-5564 Stealth Address Generation Result\n */\nexport interface StealthAddressResult {\n /** The generated stealth address where funds should be sent */\n stealthAddress: string;\n /** Ephemeral public key (to be published on-chain) */\n ephemeralPublicKey: string;\n /** View tag (1 byte) for efficient scanning */\n viewTag: string;\n /** @deprecated Legacy field - sender doesn't get the private key in ERC-5564 */\n stealthPrivateKey?: string;\n}\n\n/**\n * ERC-5564 Announcement (what gets published on-chain)\n */\nexport interface Announcement {\n /** The stealth address that received funds */\n stealthAddress: string;\n /** Ephemeral public key used for generation */\n ephemeralPublicKey: string;\n /** View tag for efficient filtering */\n viewTag: string;\n}\n\n/**\n * Result of parsing/checking announcements\n */\nexport interface ParseAnnouncementResult {\n /** Whether this announcement is for the user */\n isForUser: boolean;\n /** The stealth address (only if isForUser is true) */\n stealthAddress?: string;\n /** The stealth private key for spending (only if isForUser is true) */\n stealthPrivateKey?: string;\n}\n\n/**\n * ERC-5564 Stealth Address Module\n * Integrates with w3pk WebAuthn for seamless privacy-preserving stealth address generation\n */\nexport class StealthAddressModule {\n private getMnemonic: (requireAuth?: boolean) => Promise<string>;\n\n constructor(config: StealthAddressConfig, getMnemonic: (requireAuth?: boolean) => Promise<string>) {\n this.getMnemonic = getMnemonic;\n }\n\n // ========================================\n // ERC-5564 Stealth Address Generation\n // ========================================\n\n /**\n * Generate a fresh ERC-5564 compliant stealth address\n * This is the sender's operation - generates a one-time address for the recipient\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns Stealth address, ephemeral public key, and view tag (to be published on-chain)\n */\n async generateStealthAddress(options?: { requireAuth?: boolean }): Promise<StealthAddressResult> {\n try {\n // Get mnemonic from session (or authenticate if needed/forced)\n const mnemonic = await this.getMnemonic(options?.requireAuth);\n\n const stealthKeys = deriveStealthKeys(mnemonic);\n const stealthResult = generateERC5564StealthAddress(stealthKeys.stealthMetaAddress);\n\n return {\n stealthAddress: stealthResult.stealthAddress,\n ephemeralPublicKey: stealthResult.ephemeralPubKey,\n viewTag: stealthResult.viewTag,\n };\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to generate stealth address\",\n \"STEALTH_GENERATION_ERROR\",\n error\n );\n }\n }\n\n /**\n * Parse an ERC-5564 announcement to check if it's for the user\n * Uses view tag optimization for efficient scanning (255/256 skip rate)\n *\n * @param announcement - The announcement to parse (from on-chain event)\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns ParseResult indicating if announcement is for user, plus stealth private key if true\n */\n async parseAnnouncement(announcement: Announcement, options?: { requireAuth?: boolean }): Promise<ParseAnnouncementResult> {\n try {\n // Get mnemonic from session (or authenticate if needed/forced)\n const mnemonic = await this.getMnemonic(options?.requireAuth);\n\n const stealthKeys = deriveStealthKeys(mnemonic);\n\n // Check if this announcement is for us (with view tag optimization)\n const parseResult = checkStealthAddress(\n stealthKeys.viewingKey,\n stealthKeys.spendingPubKey,\n announcement.ephemeralPublicKey,\n announcement.stealthAddress,\n announcement.viewTag\n );\n\n if (!parseResult.isForUser) {\n return { isForUser: false };\n }\n\n // Compute the stealth private key so user can spend the funds\n const stealthPrivateKey = computeStealthPrivateKey(\n stealthKeys.viewingKey,\n stealthKeys.spendingKey,\n announcement.ephemeralPublicKey\n );\n\n return {\n isForUser: true,\n stealthAddress: parseResult.stealthAddress,\n stealthPrivateKey,\n };\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to parse announcement\",\n \"ANNOUNCEMENT_PARSE_ERROR\",\n error\n );\n }\n }\n\n /**\n * Scan multiple announcements efficiently using view tags\n * Returns only the announcements that belong to the user\n *\n * @param announcements - Array of announcements to scan\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns Array of announcements that belong to the user with their private keys\n */\n async scanAnnouncements(announcements: Announcement[], options?: { requireAuth?: boolean }): Promise<ParseAnnouncementResult[]> {\n const results: ParseAnnouncementResult[] = [];\n\n for (const announcement of announcements) {\n const result = await this.parseAnnouncement(announcement, options);\n if (result.isForUser) {\n results.push(result);\n }\n }\n\n return results;\n }\n\n // ========================================\n // Privacy & Key Management\n // ========================================\n\n /**\n * Get ERC-5564 stealth keys\n * Returns the stealth meta-address and private keys\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n */\n async getKeys(options?: { requireAuth?: boolean }): Promise<StealthKeys> {\n try {\n // Get mnemonic from session (or authenticate if needed/forced)\n const mnemonic = await this.getMnemonic(options?.requireAuth);\n\n return deriveStealthKeys(mnemonic);\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to get stealth keys\",\n \"STEALTH_KEYS_ERROR\",\n error\n );\n }\n }\n\n /**\n * Get the stealth meta-address for receiving funds\n * This is what you share publicly for others to send you stealth payments\n *\n * @param options - Optional configuration\n * @param options.requireAuth - If true, force fresh authentication even if session is active\n * @returns The ERC-5564 stealth meta-address (66 bytes)\n */\n async getStealthMetaAddress(options?: { requireAuth?: boolean }): Promise<string> {\n try {\n const keys = await this.getKeys(options);\n return keys.stealthMetaAddress;\n } catch (error) {\n throw new Web3PasskeyError(\n \"Failed to get stealth meta-address\",\n \"STEALTH_META_ADDRESS_ERROR\",\n error\n );\n }\n }\n\n // ========================================\n // Status & Management\n // ========================================\n\n /**\n * Check if stealth addresses are available (always true if properly configured)\n */\n get isAvailable(): boolean {\n return true;\n }\n}\n\n// Export types for stealth module\nexport type { StealthKeys };","/**\n * ERC-5564 Stealth Address Cryptography\n * Standard-compliant implementation for privacy-preserving transactions\n *\n * @see https://eips.ethereum.org/EIPS/eip-5564\n */\n\nimport { ethers } from \"ethers\";\nimport { CryptoError } from \"../core/errors\";\n\n/**\n * ERC-5564 Stealth Keys\n * Contains the stealth meta-address and private keys for viewing and spending\n */\nexport interface StealthKeys {\n /** Stealth meta-address (66 bytes: compressed spending + viewing pubkeys) */\n stealthMetaAddress: string;\n /** Compressed spending public key (33 bytes) */\n spendingPubKey: string;\n /** Compressed viewing public key (33 bytes) */\n viewingPubKey: string;\n /** Viewing private key (32 bytes) */\n viewingKey: string;\n /** Spending private key (32 bytes) */\n spendingKey: string;\n /** @deprecated Legacy meta-address format (kept for backward compatibility) */\n metaAddress?: string;\n}\n\n/**\n * ERC-5564 Stealth Address Generation Result\n */\nexport interface StealthAddressResult {\n /** The generated stealth address */\n stealthAddress: string;\n /** Ephemeral public key (compressed, 33 bytes) */\n ephemeralPubKey: string;\n /** View tag (1 byte) for efficient scanning */\n viewTag: string;\n /** @deprecated Use ephemeralPubKey instead */\n ephemeralPubkey?: string;\n /** @deprecated Sender doesn't get the private key in ERC-5564 */\n stealthPrivkey?: string;\n}\n\n/**\n * ERC-5564 Parse/Check Result\n */\nexport interface ParseResult {\n /** Whether this announcement is for the user */\n isForUser: boolean;\n /** The stealth address (only if isForUser is true) */\n stealthAddress?: string;\n /** The stealth private key (only if isForUser is true) */\n stealthPrivateKey?: string;\n}\n\n/**\n * Derive ERC-5564 compliant stealth keys from w3pk mnemonic using HD paths\n *\n * @param mnemonic - BIP39 mnemonic phrase\n * @returns StealthKeys with compressed public keys and stealth meta-address\n */\nexport function deriveStealthKeys(mnemonic: string): StealthKeys {\n try {\n // Use specific derivation paths for stealth keys\n const viewingWallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic,\n undefined,\n \"m/44'/60'/1'/0/0\" // Viewing key path\n );\n\n const spendingWallet = ethers.HDNodeWallet.fromPhrase(\n mnemonic,\n undefined,\n \"m/44'/60'/1'/0/1\" // Spending key path\n );\n\n // Get compressed public keys (ERC-5564 requirement)\n const spendingPubKey = spendingWallet.signingKey.compressedPublicKey;\n const viewingPubKey = viewingWallet.signingKey.compressedPublicKey;\n\n // ERC-5564 stealth meta-address: 66 bytes (spending + viewing pubkeys)\n const stealthMetaAddress = spendingPubKey + viewingPubKey.slice(2); // Remove 0x from second key\n\n // Legacy meta-address for backward compatibility\n const legacyMetaAddress = computeLegacyMetaAddress(\n viewingWallet.signingKey.publicKey,\n spendingWallet.signingKey.publicKey\n );\n\n return {\n stealthMetaAddress,\n spendingPubKey,\n viewingPubKey,\n viewingKey: viewingWallet.privateKey,\n spendingKey: spendingWallet.privateKey,\n metaAddress: legacyMetaAddress, // For backward compatibility\n };\n } catch (error) {\n throw new CryptoError(\"Failed to derive stealth keys\", error);\n }\n}\n\n/**\n * ERC-5564: Generate a stealth address using ECDH\n * This is the sender's operation - they generate a one-time stealth address\n * for the recipient without any interaction.\n *\n * Algorithm:\n * 1. Generate random ephemeral private key\n * 2. Parse spending and viewing public keys from stealth meta-address\n * 3. Compute shared secret: s = ephemeral_privkey × viewing_pubkey (ECDH)\n * 4. Hash shared secret: s_h = keccak256(s)\n * 5. Extract view tag: viewTag = s_h[0]\n * 6. Compute stealth pubkey: P_stealth = spending_pubkey + (s_h × G)\n * 7. Derive stealth address from P_stealth\n *\n * @param stealthMetaAddress - 66 bytes (spending + viewing compressed pubkeys)\n * @returns Stealth address, ephemeral pubkey, and view tag\n */\nexport function generateStealthAddress(\n stealthMetaAddress: string\n): StealthAddressResult {\n try {\n // Parse the stealth meta-address (66 bytes = 33 + 33)\n const spendingPubKey = \"0x\" + stealthMetaAddress.slice(2, 68); // First 33 bytes\n const viewingPubKey = \"0x\" + stealthMetaAddress.slice(68); // Last 33 bytes\n\n // Generate ephemeral keypair\n const ephemeralWallet = ethers.Wallet.createRandom();\n const ephemeralPubKey = ephemeralWallet.signingKey.compressedPublicKey;\n\n // Compute ECDH shared secret: s = ephemeral_privkey × viewing_pubkey\n const sharedSecret = computeSharedSecret(\n ephemeralWallet.privateKey,\n viewingPubKey\n );\n\n // Hash the shared secret: s_h = keccak256(s)\n const hashedSharedSecret = ethers.keccak256(sharedSecret);\n\n // Extract view tag (first byte of hashed shared secret)\n const viewTag = \"0x\" + hashedSharedSecret.slice(2, 4);\n\n // Compute stealth public key: P_stealth = spending_pubkey + (s_h × G)\n const stealthPubKey = addPublicKeys(\n spendingPubKey,\n multiplyGeneratorByScalar(hashedSharedSecret)\n );\n\n // Derive stealth address from stealth public key\n const stealthAddress = publicKeyToAddress(stealthPubKey);\n\n return {\n stealthAddress,\n ephemeralPubKey,\n viewTag,\n // Backward compatibility\n ephemeralPubkey: ephemeralPubKey,\n };\n } catch (error) {\n throw new CryptoError(\"Failed to generate stealth address\", error);\n }\n}\n\n/**\n * ERC-5564: Check if a stealth address belongs to the user (with view tag optimization)\n * This is the recipient's scanning operation.\n *\n * Algorithm:\n * 1. Compute shared secret: s = viewing_privkey × ephemeral_pubkey (ECDH)\n * 2. Hash shared secret: s_h = keccak256(s)\n * 3. Check view tag first (255/256 probability to skip remaining computation)\n * 4. If view tag matches, compute stealth pubkey: P_stealth = spending_pubkey + (s_h × G)\n * 5. Derive address and compare with target\n *\n * @param viewingKey - Recipient's viewing private key\n * @param spendingPubKey - Recipient's spending public key (compressed)\n * @param ephemeralPubKey - Ephemeral public key from announcement\n * @param stealthAddress - The stealth address to check\n * @param viewTag - View tag from announcement (optional, for optimization)\n * @returns ParseResult with stealth address and private key if it belongs to user\n */\nexport function checkStealthAddress(\n viewingKey: string,\n spendingPubKey: string,\n ephemeralPubKey: string,\n stealthAddress: string,\n viewTag?: string\n): ParseResult {\n try {\n // Compute ECDH shared secret: s = viewing_privkey × ephemeral_pubkey\n const sharedSecret = computeSharedSecret(viewingKey, ephemeralPubKey);\n\n // Hash the shared secret: s_h = keccak256(s)\n const hashedSharedSecret = ethers.keccak256(sharedSecret);\n\n // View tag optimization: check first byte of hashed shared secret\n if (viewTag) {\n const computedViewTag = \"0x\" + hashedSharedSecret.slice(2, 4);\n if (computedViewTag.toLowerCase() !== viewTag.toLowerCase()) {\n // View tag mismatch - this announcement is not for us (255/256 probability)\n return { isForUser: false };\n }\n }\n\n // Compute stealth public key: P_stealth = spending_pubkey + (s_h × G)\n const stealthPubKey = addPublicKeys(\n spendingPubKey,\n multiplyGeneratorByScalar(hashedSharedSecret)\n );\n\n // Derive stealth address from stealth public key\n const derivedAddress = publicKeyToAddress(stealthPubKey);\n\n // Check if addresses match\n if (derivedAddress.toLowerCase() !== stealthAddress.toLowerCase()) {\n return { isForUser: false };\n }\n\n // Compute stealth private key: privkey_stealth = spending_privkey + s_h\n // We need the spending private key for this, which should be passed separately\n // For now, we just return that it's for the user\n return {\n isForUser: true,\n stealthAddress: derivedAddress,\n };\n } catch (error) {\n return { isForUser: false };\n }\n}\n\n/**\n * ERC-5564: Compute the stealth private key for spending\n * This allows the recipient to actually spend funds from the stealth address.\n *\n * Algorithm:\n * privkey_stealth = spending_privkey + s_h (mod n)\n *\n * @param viewingKey - Recipient's viewing private key\n * @param spendingKey - Recipient's spending private key\n * @param ephemeralPubKey - Ephemeral public key from announcement\n * @returns The stealth private key\n */\nexport function computeStealthPrivateKey(\n viewingKey: string,\n spendingKey: string,\n ephemeralPubKey: string\n): string {\n try {\n // Compute ECDH shared secret: s = viewing_privkey × ephemeral_pubkey\n const sharedSecret = computeSharedSecret(viewingKey, ephemeralPubKey);\n\n // Hash the shared secret: s_h = keccak256(s)\n const hashedSharedSecret = ethers.keccak256(sharedSecret);\n\n // Compute stealth private key: privkey_stealth = spending_privkey + s_h (mod n)\n const stealthPrivKey = addPrivateKeys(spendingKey, hashedSharedSecret);\n\n return stealthPrivKey;\n } catch (error) {\n throw new CryptoError(\"Failed to compute stealth private key\", error);\n }\n}\n\n// ========================================\n// ERC-5564 Cryptographic Primitives\n// ========================================\n\n/**\n * Compute ECDH shared secret using SECP256k1\n * s = privkey × pubkey\n */\nfunction computeSharedSecret(privateKey: string, publicKey: string): string {\n try {\n const wallet = new ethers.Wallet(privateKey);\n const signingKey = wallet.signingKey;\n\n // Perform ECDH: multiply the public key by our private key\n // The result is a point on the curve, we take its x-coordinate\n const sharedPoint = signingKey.computeSharedSecret(publicKey);\n\n return sharedPoint;\n } catch (error) {\n throw new CryptoError(\"Failed to compute shared secret\", error);\n }\n}\n\n/**\n * Multiply the generator point G by a scalar\n * Returns compressed public key\n */\nfunction multiplyGeneratorByScalar(scalar: string): string {\n try {\n const wallet = new ethers.Wallet(scalar);\n return wallet.signingKey.compressedPublicKey;\n } catch (error) {\n throw new CryptoError(\"Failed to multiply generator by scalar\", error);\n }\n}\n\n/**\n * Add two public keys using elliptic curve point addition\n * P1 + P2\n */\nfunction addPublicKeys(pubKey1: string, pubKey2: string): string {\n try {\n const key1 = ethers.SigningKey.computePublicKey(pubKey1, false); // Uncompressed\n const key2 = ethers.SigningKey.computePublicKey(pubKey2, false); // Uncompressed\n\n // Extract x and y coordinates (remove 0x04 prefix)\n const x1 = BigInt(\"0x\" + key1.slice(4, 68));\n const y1 = BigInt(\"0x\" + key1.slice(68));\n const x2 = BigInt(\"0x\" + key2.slice(4, 68));\n const y2 = BigInt(\"0x\" + key2.slice(68));\n\n // SECP256k1 curve parameters\n const p = BigInt(\"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\");\n\n // Point addition on elliptic curve\n // If points are the same, use point doubling\n if (x1 === x2 && y1 === y2) {\n // Point doubling: lambda = (3*x1^2) / (2*y1)\n const numerator = (3n * x1 * x1) % p;\n const denominator = (2n * y1) % p;\n const lambda = (numerator * modInverse(denominator, p)) % p;\n\n const x3 = (lambda * lambda - 2n * x1) % p;\n const y3 = (lambda * (x1 - x3) - y1) % p;\n\n return compressPublicKey((x3 + p) % p, (y3 + p) % p);\n }\n\n // Regular point addition: lambda = (y2 - y1) / (x2 - x1)\n const numerator = ((y2 - y1) % p + p) % p;\n const denominator = ((x2 - x1) % p + p) % p;\n const lambda = (numerator * modInverse(denominator, p)) % p;\n\n const x3 = (lambda * lambda - x1 - x2) % p;\n const y3 = (lambda * (x1 - x3) - y1) % p;\n\n return compressPublicKey((x3 + p) % p, (y3 + p) % p);\n } catch (error) {\n throw new CryptoError(\"Failed to add public keys\", error);\n }\n}\n\n/**\n * Add two private keys modulo the curve order\n * (privkey1 + privkey2) mod n\n */\nfunction addPrivateKeys(privKey1: string, privKey2: string): string {\n try {\n // SECP256k1 curve order\n const n = BigInt(\"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141\");\n\n const k1 = BigInt(privKey1);\n const k2 = BigInt(privKey2);\n\n const sum = (k1 + k2) % n;\n\n // Convert back to hex with proper padding\n return \"0x\" + sum.toString(16).padStart(64, \"0\");\n } catch (error) {\n throw new CryptoError(\"Failed to add private keys\", error);\n }\n}\n\n/**\n * Compress a public key (x, y) to compressed format\n */\nfunction compressPublicKey(x: bigint, y: bigint): string {\n const prefix = y % 2n === 0n ? \"02\" : \"03\";\n return \"0x\" + prefix + x.toString(16).padStart(64, \"0\");\n}\n\n/**\n * Compute modular inverse using Extended Euclidean Algorithm\n */\nfunction modInverse(a: bigint, m: bigint): bigint {\n a = ((a % m) + m) % m;\n let [oldR, r] = [a, m];\n let [oldS, s] = [1n, 0n];\n\n while (r !== 0n) {\n const quotient = oldR / r;\n [oldR, r] = [r, oldR - quotient * r];\n [oldS, s] = [s, oldS - quotient * s];\n }\n\n return ((oldS % m) + m) % m;\n}\n\n/**\n * Derive Ethereum address from compressed public key\n */\nfunction publicKeyToAddress(compressedPubKey: string): string {\n try {\n // Decompress the public key first\n const uncompressedPubKey = ethers.SigningKey.computePublicKey(compressedPubKey, false);\n\n // Take keccak256 of uncompressed public key (without 0x04 prefix)\n const pubKeyHash = ethers.keccak256(\"0x\" + uncompressedPubKey.slice(4));\n\n // Take last 20 bytes as address\n return ethers.getAddress(\"0x\" + pubKeyHash.slice(-40));\n } catch (error) {\n throw new CryptoError(\"Failed to derive address from public key\", error);\n }\n}\n\n/**\n * Legacy meta address computation (for backward compatibility)\n */\nfunction computeLegacyMetaAddress(\n viewingPubkey: string,\n spendingPubkey: string\n): string {\n const combined = ethers.solidityPackedKeccak256(\n [\"bytes\", \"bytes\"],\n [viewingPubkey, spendingPubkey]\n );\n\n // Take first 20 bytes as address\n return ethers.getAddress(\"0x\" + combined.slice(26));\n}\n\n/**\n * @deprecated Use checkStealthAddress instead\n */\nexport function canControlStealthAddress(\n viewingKey: string,\n spendingKey: string,\n ephemeralPubkey: string,\n targetAddress: string\n): boolean {\n const spendingWallet = new ethers.Wallet(spendingKey);\n const result = checkStealthAddress(\n viewingKey,\n spendingWallet.signingKey.compressedPublicKey,\n ephemeralPubkey,\n targetAddress\n );\n return result.isForUser;\n}\n","/**\n * Session Manager - Caches decrypted mnemonic for configurable duration\n *\n * SECURITY:\n * - Mnemonic is stored in memory only (never persisted)\n * - Automatically cleared after session expires\n * - Can be manually revoked at any time\n * - Initial authentication still requires biometric/PIN\n */\n\nexport interface SessionData {\n mnemonic: string;\n expiresAt: number;\n credentialId: string;\n}\n\nexport class SessionManager {\n private session: SessionData | null = null;\n private sessionDuration: number; // in milliseconds\n\n constructor(sessionDurationHours: number = 1) {\n this.sessionDuration = sessionDurationHours * 60 * 60 * 1000; // Convert to ms\n }\n\n /**\n * Start a new session with the decrypted mnemonic\n */\n startSession(mnemonic: string, credentialId: string): void {\n const expiresAt = Date.now() + this.sessionDuration;\n this.session = {\n mnemonic,\n expiresAt,\n credentialId,\n };\n }\n\n /**\n * Get the cached mnemonic if session is still valid\n * Returns null if session expired or doesn't exist\n */\n getMnemonic(): string | null {\n if (!this.session) {\n return null;\n }\n\n // Check if session expired\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n return null;\n }\n\n return this.session.mnemonic;\n }\n\n /**\n * Get session credential ID\n */\n getCredentialId(): string | null {\n if (!this.session) {\n return null;\n }\n\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n return null;\n }\n\n return this.session.credentialId;\n }\n\n /**\n * Check if session is active and valid\n */\n isActive(): boolean {\n return this.getMnemonic() !== null;\n }\n\n /**\n * Get remaining session time in seconds\n */\n getRemainingTime(): number {\n if (!this.session) {\n return 0;\n }\n\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n return 0;\n }\n\n return Math.floor((this.session.expiresAt - Date.now()) / 1000);\n }\n\n /**\n * Extend the session by the configured duration\n */\n extendSession(): void {\n if (!this.session) {\n throw new Error(\"No active session to extend\");\n }\n\n if (Date.now() > this.session.expiresAt) {\n this.clearSession();\n throw new Error(\"Session expired, cannot extend\");\n }\n\n this.session.expiresAt = Date.now() + this.sessionDuration;\n }\n\n /**\n * Manually clear the session (logout or security requirement)\n */\n clearSession(): void {\n // Overwrite mnemonic in memory before clearing\n if (this.session) {\n this.session.mnemonic = \"0\".repeat(this.session.mnemonic.length);\n }\n this.session = null;\n }\n\n /**\n * Update session duration (affects new sessions and extensions)\n */\n setSessionDuration(hours: number): void {\n this.sessionDuration = hours * 60 * 60 * 1000;\n }\n}\n","/**\n * SDK Configuration\n */\n\nimport type { UserInfo } from \"../types\";\nimport type { Web3PasskeyError } from \"./errors\";\n\nexport interface StealthAddressConfig {}\n\nexport interface ZKProofConfig {\n enabledProofs?: Array<\n | \"membership\"\n | \"threshold\"\n | \"range\"\n | \"equality\"\n | \"ownership\"\n | \"signature\"\n | \"nft\"\n >;\n customCircuits?: Record<string, any>;\n}\n\nexport interface Web3PasskeyConfig {\n debug?: boolean;\n onError?: (error: Web3PasskeyError) => void;\n onAuthStateChanged?: (isAuthenticated: boolean, user?: UserInfo) => void;\n storage?: Storage;\n\n /**\n * Session duration in hours\n * After successful authentication, the decrypted mnemonic is cached for this duration\n * This allows operations like deriveWallet(), exportMnemonic(), stealth addresses, etc.\n * to work without repeated authentication prompts\n *\n * @default 1 (hour)\n * Set to 0 to require authentication for every operation (most secure)\n */\n sessionDuration?: number;\n\n /**\n * Stealth address configuration (ERC-5564)\n */\n stealthAddresses?: StealthAddressConfig;\n\n /**\n * Zero-knowledge proof configuration\n * Requires: snarkjs, circomlibjs\n */\n zkProofs?: ZKProofConfig;\n}\n\nexport interface InternalConfig extends Required<Web3PasskeyConfig> {\n // Normalized config with all defaults applied\n}\n\nexport const DEFAULT_CONFIG: Partial<InternalConfig> = {\n debug: false,\n sessionDuration: 1, // 1 hour default\n onError: (error: Web3PasskeyError) => {\n if (DEFAULT_CONFIG.debug) {\n console.error(\"[w3pk]\", error);\n }\n },\n};\n","/**\n * Chainlist module for fetching RPC endpoints\n */\n\nimport type { Chain, ChainlistOptions } from \"./types\";\n\nconst DEFAULT_CHAINS_URL = \"https://chainid.network/chains.json\";\nconst DEFAULT_CACHE_DURATION = 3600000; // 1 hour\n\ninterface CacheEntry {\n data: Chain[];\n timestamp: number;\n}\n\nlet cache: CacheEntry | null = null;\n\n/**\n * Patterns that indicate an RPC URL requires an API key\n */\nconst API_KEY_PATTERNS = [\n /\\$\\{[\\w_]+\\}/i, // ${INFURA_API_KEY}, ${API_KEY}, etc.\n /\\{[\\w_]+\\}/i, // {API_KEY}, {INFURA_API_KEY}, etc.\n /<[\\w_]+>/i, // <API_KEY>, <INFURA_API_KEY>, etc.\n /YOUR[-_]?API[-_]?KEY/i,\n /INSERT[-_]?API[-_]?KEY/i,\n /API[-_]?KEY[-_]?HERE/i,\n];\n\n/**\n * Check if an RPC URL requires an API key\n */\nfunction requiresApiKey(rpcUrl: string): boolean {\n return API_KEY_PATTERNS.some((pattern) => pattern.test(rpcUrl));\n}\n\n/**\n * Fetch all chains data from chainid.network\n */\nasync function fetchChains(\n chainsJsonUrl: string = DEFAULT_CHAINS_URL\n): Promise<Chain[]> {\n const response = await fetch(chainsJsonUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch chains data: ${response.status} ${response.statusText}`\n );\n }\n\n return await response.json();\n}\n\n/**\n * Get all chains data with caching\n */\nasync function getChainsData(options?: ChainlistOptions): Promise<Chain[]> {\n const chainsJsonUrl = options?.chainsJsonUrl ?? DEFAULT_CHAINS_URL;\n const cacheDuration = options?.cacheDuration ?? DEFAULT_CACHE_DURATION;\n const now = Date.now();\n\n // Check if cache is valid\n if (cache && now - cache.timestamp < cacheDuration) {\n return cache.data;\n }\n\n // Fetch fresh data\n const data = await fetchChains(chainsJsonUrl);\n cache = { data, timestamp: now };\n\n return data;\n}\n\n/**\n * Get RPC endpoints for a specific chain ID, excluding those that require API keys\n *\n * @param chainId - The chain ID to get endpoints for\n * @param options - Optional configuration\n * @returns Array of RPC URLs that don't require API keys\n *\n * @example\n * ```typescript\n * import { getEndpoints } from 'w3pk/chainlist'\n *\n * // Get Ethereum mainnet RPCs\n * const endpoints = await getEndpoints(1)\n * console.log(endpoints)\n * // [\n * // \"https://api.mycryptoapi.com/eth\",\n * // \"https://cloudflare-eth.com\",\n * // \"https://ethereum-rpc.publicnode.com\",\n * // ...\n * // ]\n * ```\n */\nexport async function getEndpoints(\n chainId: number,\n options?: ChainlistOptions\n): Promise<string[]> {\n const chains = await getChainsData(options);\n const chain = chains.find((c) => c.chainId === chainId);\n\n if (!chain) {\n return [];\n }\n\n // Filter out RPC URLs that require API keys and websocket URLs\n return chain.rpc.filter(\n (rpcUrl) =>\n !requiresApiKey(rpcUrl) &&\n !rpcUrl.startsWith(\"wss://\") &&\n !rpcUrl.startsWith(\"ws://\")\n );\n}\n\n/**\n * Get all available chains\n *\n * @param options - Optional configuration\n * @returns Array of all chains\n */\nexport async function getAllChains(\n options?: ChainlistOptions\n): Promise<Chain[]> {\n return getChainsData(options);\n}\n\n/**\n * Get chain information by chain ID\n *\n * @param chainId - The chain ID to get information for\n * @param options - Optional configuration\n * @returns Chain information or undefined if not found\n */\nexport async function getChainById(\n chainId: number,\n options?: ChainlistOptions\n): Promise<Chain | undefined> {\n const chains = await getChainsData(options);\n return chains.find((c) => c.chainId === chainId);\n}\n\n/**\n * Clear the chains data cache\n */\nexport function clearCache(): void {\n cache = null;\n}\n\n// Export types\nexport type { Chain, ChainlistOptions } from \"./types\";\n","/**\n * EIP-7702 Support (Internal Module)\n *\n * EIP-7702 introduces \"Set EOA Account Code\" functionality,\n * allowing externally owned accounts (EOAs) to temporarily act as smart contracts.\n *\n * This module is for internal use by the SDK.\n * Access via: w3pk.supportsEIP7702(chainId)\n */\n\n/**\n * EIP-7702 supported chain IDs\n * Source: https://github.com/w3hc/eip7702-playground/blob/main/eip7702-networks.ts\n * Generated: 2025-10-15 10:51:18 UTC\n * Total: 329 chains\n */\nconst EIP7702_SUPPORTED_CHAINS = new Set([\n 1, 10, 8453, 42161, 57073, 100, 42220, 137, 42, 15, 40, 41, 44, 46, 47, 50,\n 51, 56, 61, 71, 82, 83, 95, 97, 112, 123, 130, 146, 151, 153, 171, 180, 183,\n 185, 195, 215, 228, 247, 248, 252, 261, 267, 291, 293, 311, 332, 336, 395,\n 401, 416, 466, 480, 488, 510, 545, 634, 647, 648, 747, 831, 919, 938, 945,\n 957, 964, 970, 980, 995, 997, 1001, 1003, 1024, 1030, 1114, 1125, 1135, 1149,\n 1188, 1284, 1285, 1287, 1300, 1301, 1315, 1337, 1338, 1339, 1424, 1514, 1687,\n 1727, 1729, 1740, 1750, 1829, 1868, 1946, 1961, 1962, 1969, 1989, 1995, 2017,\n 2020, 2031, 2043, 2109, 2241, 2340, 2345, 2440, 2522, 2559, 2649, 3068, 3109,\n 3338, 3502, 3799, 3888, 3889, 4000, 4048, 4078, 4162, 4201, 4202, 4460, 4488,\n 4661, 4689, 4690, 4888, 5000, 5003, 5124, 5234, 5330, 5424, 5522, 6283, 6342,\n 6398, 6678, 6806, 6934, 6942, 6969, 7117, 7171, 7200, 7208, 7368, 7518, 7668,\n 7672, 7744, 7771, 7869, 7897, 8008, 8118, 8217, 8408, 8700, 8726, 8727, 8844,\n 8880, 8881, 8882, 8889, 9372, 9496, 9700, 9745, 9746, 9899, 9990, 9996, 10011,\n 10085, 10143, 10200, 11221, 11501, 11504, 11891, 13370, 14853, 16602, 16661,\n 17000, 18880, 18881, 19991, 21000, 21816, 21912, 25327, 32323, 33401, 34443,\n 41923, 42170, 43111, 44787, 47805, 48898, 48900, 49049, 49088, 50000, 50312,\n 53302, 53456, 53457, 55244, 56288, 59141, 60808, 60850, 62320, 62850, 64002,\n 71402, 72080, 73114, 73115, 75338, 78281, 80002, 80008, 80069, 80094, 80451,\n 80931, 84532, 88899, 91342, 92278, 94524, 96970, 97476, 97477, 98985, 100021,\n 100501, 101010, 102030, 102031, 102032, 112358, 120893, 121212, 121213,\n 121214, 121215, 129399, 161803, 175188, 192940, 193939, 198989, 212013,\n 222222, 240241, 325000, 355110, 355113, 421614, 555777, 560048, 656476,\n 713715, 743111, 747474, 763373, 763375, 777777, 806582, 808813, 810180,\n 839999, 888991, 2019775, 2222222, 4278608, 5734951, 6666689, 6985385, 7080969,\n 7777777, 9999999, 11142220, 11155111, 11155420, 11155931, 16969696, 19850818,\n 20180427, 20250825, 28122024, 34949059, 37084624, 52164803, 61022448,\n 79479957, 96969696, 420420421, 420420422, 888888888, 974399131, 999999999,\n 1020352220, 1273227453, 1313161560, 1350216234, 1380996178, 1417429182,\n 1444673419, 1482601649, 1564830818, 2046399126, 11297108099, 11297108109,\n 88153591557, 123420000220, 123420001114,\n]);\n\n/**\n * Test an RPC endpoint for EIP-7702 support using eth_estimateGas\n * Based on: https://github.com/w3hc/eip7702-playground/blob/main/eip7702_scanner.sh\n * @internal\n */\nasync function testRPCForEIP7702(\n rpcUrl: string,\n timeout: number = 10000\n): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n signal: controller.signal,\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"eth_estimateGas\",\n params: [\n {\n from: \"0xdeadbeef00000000000000000000000000000000\",\n to: \"0xdeadbeef00000000000000000000000000000000\",\n data: \"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n value: \"0x0\",\n },\n \"latest\",\n {\n \"0xdeadbeef00000000000000000000000000000000\": {\n code: \"0xef01000000000000000000000000000000000000000001\",\n },\n },\n ],\n id: 1,\n }),\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return false;\n }\n\n const data = await response.json();\n\n // Check for error messages that indicate no EIP-7702 support\n if (data.error) {\n const errorMsg = (data.error.message || \"\").toLowerCase();\n\n // These errors indicate the RPC doesn't support EIP-7702\n const unsupportedErrors = [\n \"unsupported\",\n \"not supported\",\n \"unknown\",\n \"invalid\",\n \"unrecognized\",\n \"does not support\",\n \"not implemented\",\n ];\n\n return !unsupportedErrors.some((err) => errorMsg.includes(err));\n }\n\n // If we got a result (even an estimate), EIP-7702 is supported\n return data.result !== undefined;\n } catch (error) {\n // Network errors, timeouts, etc. don't necessarily mean no support\n return false;\n }\n}\n\n/**\n * Check if a network supports EIP-7702\n * First checks cached list, then performs RPC test if not found\n * @internal\n */\nexport async function supportsEIP7702(\n chainId: number,\n getEndpointsFn: (chainId: number) => Promise<string[]>,\n options?: {\n maxEndpoints?: number;\n timeout?: number;\n }\n): Promise<boolean> {\n // First, check the cached list\n if (EIP7702_SUPPORTED_CHAINS.has(chainId)) {\n return true;\n }\n\n // Not in cached list, perform RPC test\n const maxEndpoints = options?.maxEndpoints || 3;\n const timeout = options?.timeout || 10000;\n\n try {\n // Get RPC endpoints for this chain\n const endpoints = await getEndpointsFn(chainId);\n\n if (endpoints.length === 0) {\n return false;\n }\n\n // Test up to maxEndpoints\n const endpointsToTest = endpoints.slice(0, maxEndpoints);\n\n for (const endpoint of endpointsToTest) {\n const supported = await testRPCForEIP7702(endpoint, timeout);\n\n if (supported) {\n return true;\n }\n }\n\n return false;\n } catch (error) {\n return false;\n }\n}\n","/**\n * Web3 Passkey SDK\n * Passwordless authentication with encrypted wallets\n */\n\nimport { Web3Passkey } from \"./core/sdk\";\nimport type { Web3PasskeyConfig } from \"./core/config\";\n\nexport function createWeb3Passkey(config: Web3PasskeyConfig = {}): Web3Passkey {\n return new Web3Passkey(config);\n}\n\nexport type { Web3PasskeyConfig, StealthAddressConfig } from \"./core/config\";\nexport type { UserInfo, WalletInfo } from \"./types\";\nexport type { StealthKeys, StealthAddressResult } from \"./stealth\";\n\nexport {\n Web3PasskeyError,\n AuthenticationError,\n RegistrationError,\n WalletError,\n CryptoError,\n StorageError,\n ApiError,\n} from \"./core/errors\";\n\nexport { Web3Passkey } from \"./core/sdk\";\nexport { StealthAddressModule } from \"./stealth\";\n\nexport {\n canControlStealthAddress,\n generateStealthAddress,\n checkStealthAddress,\n computeStealthPrivateKey,\n deriveStealthKeys\n} from \"./stealth/crypto\";\n\nexport {\n generateBIP39Wallet,\n createWalletFromMnemonic,\n deriveWalletFromMnemonic,\n} from \"./wallet/generate\";\n\n// Backup and Recovery\nexport { BackupManager, BackupStorage } from \"./backup\";\nexport { SocialRecoveryManager } from \"./recovery\";\nexport { VaultSync, DeviceManager, PlatformDetector } from \"./sync\";\nexport { RecoverySimulator, getExplainer, getAllTopics, searchExplainers } from \"./education\";\n\n// Validation utilities\nexport {\n validateEthereumAddress,\n validateUsername,\n validateMnemonic,\n isStrongPassword,\n assertEthereumAddress,\n assertUsername,\n assertMnemonic,\n} from \"./utils/validation\";\n\n// Backup and Recovery Types\nexport type {\n BackupStatus,\n SecurityScore,\n ZipBackupOptions,\n QRBackupOptions,\n RecoveryScenario,\n SimulationResult,\n EncryptedBackupInfo,\n} from \"./backup/types\";\n\nexport type {\n Guardian,\n GuardianInvite,\n SocialRecoveryConfig,\n RecoveryShare,\n RecoveryProgress,\n} from \"./recovery/types\";\n\nexport type {\n SyncVault,\n DeviceInfo,\n SyncCapabilities,\n SyncStatus,\n} from \"./sync/types\";\n\nexport default createWeb3Passkey;\n"],"mappings":"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","names":["Web3PasskeyError","AuthenticationError","RegistrationError","WalletError","CryptoError","StorageError","ApiError","init_errors","__esmMin","message","code","originalError","statusCode","storage_exports","__export","CredentialStorage","STORAGE_KEY_PREFIX","STORAGE_INDEX_KEY","init_storage","__esmMin","init_errors","storage","StorageError","credential","key","error","id","data","username","c","address","index","filtered","credId","crypto_exports","__export","decryptData","deriveEncryptionKey","deriveEncryptionKeyFromSignature","deriveEncryptionKeyFromWebAuthn","encryptData","generateChallenge","credentialId","publicKey","keyMaterial","keyMaterialHash","importedKey","salt","error","CryptoError","signature","signatureHash","array","data","key","iv","encodedData","encrypted","combined","encryptedData","char","decrypted","init_crypto","__esmMin","init_errors","BackupStorage","init_storage","__esmMin","resolve","reject","request","event","db","store","metadata","ethereumAddress","id","method","encryption_exports","__export","decryptWithPassword","deriveAddressChecksum","deriveKeyFromPassword","encryptWithPassword","getDeviceFingerprint","validatePasswordStrength","password","salt","iterations","passwordBuffer","keyMaterial","data","key","dataBuffer","iv","encryptedBuffer","bufferToBase64","encryptedData","saltBuffer","base64ToBuffer","ivBuffer","decryptedBuffer","fingerprintString","buffer","hashBuffer","ethereumAddress","feedback","score","common","bytes","binary","i","base64","init_encryption","__esmMin","ZipBackupCreator","init_zip_backup","__esmMin","init_encryption","mnemonic","ethereumAddress","options","passwordValidation","validatePasswordStrength","salt","encrypted","encryptWithPassword","deviceFingerprint","getDeviceFingerprint","metadata","deriveAddressChecksum","backupData","files","archive","content","filename","password","data","decryptWithPassword","Wallet","wallet","QRBackupCreator","init_qr_backup","__esmMin","init_encryption","mnemonic","ethereumAddress","options","errorCorrection","qrData","salt","encrypted","encryptWithPassword","deriveAddressChecksum","rawData","qrCodeDataURL","instructions","data","canvas","ctx","lines","lineHeight","startY","line","i","text","maxLength","password","decryptWithPassword","Wallet","wallet","BackupManager","init_manager","__esmMin","init_storage","init_zip_backup","init_qr_backup","BackupStorage","ZipBackupCreator","QRBackupCreator","ethereumAddress","backups","passkeySync","encryptedBackups","backup","userAgent","platform","supportsResidentKeys","breakdown","total","sum","val","level","nextMilestone","mnemonic","options","blob","metadata","qrCodeDataURL","rawData","instructions","backupData","password","qrData","scenario","currentStatus","methods","success","m","educationalNote","init_types","__esmMin","backup_exports","__export","BackupManager","BackupStorage","QRBackupCreator","ZipBackupCreator","decryptWithPassword","deriveAddressChecksum","deriveKeyFromPassword","encryptWithPassword","getDeviceFingerprint","validatePasswordStrength","init_backup","__esmMin","init_manager","init_storage","init_zip_backup","init_qr_backup","init_types","init_encryption","randomByte","array","splitSecret","secret","threshold","totalShares","shares","i","byteIndex","coefficients","shareIndex","x","y","GF256","combineShares","usedShares","shareLength","share","secretLength","points","stringToBytes","str","bytesToString","bytes","bytesToHex","b","hexToBytes","hex","_GF256","init_shamir","__esmMin","a","result","numerator","denominator","j","gfMul","hiBitSet","memoryStorageSingleton","SocialRecoveryManager","init_social","__esmMin","init_shamir","key","value","mnemonic","ethereumAddress","guardians","threshold","secretBytes","stringToBytes","shares","splitSecret","guardianObjects","g","index","bytesToHex","config","stored","guardian","guardianData","shareCode","qrCode","explainer","data","canvas","ctx","line","text","maxLength","lines","i","name","total","shareData","shareBytes","parsed","s","hexToBytes","combineShares","bytesToString","Wallet","wallet","collectedShares","collectedGuardianIds","guardianId","newGuardian","updatedGuardians","newGuardianObjects","init_types","__esmMin","recovery_exports","__export","SocialRecoveryManager","bytesToHex","bytesToString","combineShares","hexToBytes","splitSecret","stringToBytes","init_recovery","__esmMin","init_social","init_shamir","init_types","VaultSync","init_vault","__esmMin","init_encryption","mnemonic","credentialId","publicKey","deviceFingerprint","getDeviceFingerprint","deriveEncryptionKeyFromWebAuthn","encryptData","encryptionKey","encryptedData","syncMethod","userAgent","vault","decryptData","DeviceManager","init_device_manager","__esmMin","init_encryption","deviceInfo","getDeviceFingerprint","devices","existing","d","stored","currentDeviceId","device","a","b","platform","lastSyncTime","deviceId","filtered","ua","match","status","output","index","lastActiveDiff","lastActiveStr","ms","seconds","minutes","hours","days","PlatformDetector","init_platform_detect","__esmMin","platform","passkeysSync","estimatedDevices","userAgent","init_types","__esmMin","sync_exports","__export","DeviceManager","PlatformDetector","VaultSync","init_sync","__esmMin","init_vault","init_device_manager","init_platform_detect","init_types","RecoverySimulator","init_simulator","__esmMin","scenario","currentStatus","methods","backup","success","educationalNote","times","m","t","minutes","status","note","method","index","req","scenarios","results","result","successCount","r","overallScore","feedback","getExplainer","topic","educationalModules","getAllTopics","searchExplainers","query","lowerQuery","module","init_explainers","__esmMin","education_exports","__export","RecoverySimulator","educationalModules","getAllTopics","getExplainer","searchExplainers","init_education","__esmMin","init_simulator","init_explainers","init_errors","startRegistration","validateEthereumAddress","address","validateUsername","username","validateMnemonic","mnemonic","words","assertEthereumAddress","assertUsername","assertMnemonic","isStrongPassword","password","hasUppercase","hasLowercase","hasNumber","hasSpecialChar","common","init_storage","generateChallenge","array","register","options","username","ethereumAddress","assertUsername","assertEthereumAddress","storage","CredentialStorage","registrationOptions","credential","startRegistration","publicKey","attestationObject","attestationBuffer","base64ToArrayBuffer","error","RegistrationError","base64","base64Clean","binary","bytes","i","init_errors","init_storage","startAuthentication","generateChallenge","array","login","storage","CredentialStorage","authOptions","assertion","credential","verifyAssertion","signatureBuffer","base64ToArrayBuffer","error","AuthenticationError","publicKeyBuffer","publicKey","authenticatorData","clientDataJSON","clientDataJSONString","clientDataHash","signedData","signature","rawSignature","derToRaw","base64","base64Clean","binary","bytes","i","der","offset","rLength","sLength","s","raw","init_errors","DB_NAME","DB_VERSION","STORE_NAME","IndexedDBWalletStorage","resolve","reject","request","StorageError","db","data","ethereumAddress","init_errors","ethers","generateBIP39Wallet","mnemonic","mnemonicPhrase","error","WalletError","createWalletFromMnemonic","deriveWalletFromMnemonic","index","derivationPath","wallet","init_crypto","init_errors","init_errors","ethers","deriveStealthKeys","mnemonic","viewingWallet","spendingWallet","spendingPubKey","viewingPubKey","stealthMetaAddress","legacyMetaAddress","computeLegacyMetaAddress","error","CryptoError","generateStealthAddress","ephemeralWallet","ephemeralPubKey","sharedSecret","computeSharedSecret","hashedSharedSecret","viewTag","stealthPubKey","addPublicKeys","multiplyGeneratorByScalar","publicKeyToAddress","checkStealthAddress","viewingKey","stealthAddress","derivedAddress","computeStealthPrivateKey","spendingKey","addPrivateKeys","privateKey","publicKey","scalar","pubKey1","pubKey2","key1","key2","x1","y1","x2","y2","p","numerator","denominator","lambda","modInverse","x3","y3","compressPublicKey","privKey1","privKey2","n","k1","k2","x","y","a","m","oldR","oldS","s","quotient","compressedPubKey","uncompressedPubKey","pubKeyHash","viewingPubkey","spendingPubkey","combined","canControlStealthAddress","ephemeralPubkey","targetAddress","StealthAddressModule","config","getMnemonic","options","mnemonic","stealthKeys","deriveStealthKeys","stealthResult","generateStealthAddress","error","Web3PasskeyError","announcement","parseResult","checkStealthAddress","stealthPrivateKey","computeStealthPrivateKey","announcements","results","result","SessionManager","sessionDurationHours","mnemonic","credentialId","expiresAt","hours","DEFAULT_CONFIG","error","init_errors","DEFAULT_CHAINS_URL","cache","API_KEY_PATTERNS","requiresApiKey","rpcUrl","pattern","fetchChains","chainsJsonUrl","DEFAULT_CHAINS_URL","response","getChainsData","options","cacheDuration","now","data","getEndpoints","chainId","chain","c","EIP7702_SUPPORTED_CHAINS","testRPCForEIP7702","rpcUrl","timeout","controller","timeoutId","response","data","errorMsg","err","supportsEIP7702","chainId","getEndpointsFn","options","maxEndpoints","endpoints","endpointsToTest","endpoint","Web3Passkey","config","DEFAULT_CONFIG","IndexedDBWalletStorage","SessionManager","StealthAddressModule","requireAuth","dynamicImport","ZKProofModule","zkConfig","forceAuth","cachedMnemonic","WalletError","walletData","login","publicKey","encryptionKey","deriveEncryptionKeyFromWebAuthn","mnemonic","decryptData","options","ethereumAddress","register","credential","credentialId","encryptedMnemonic","encryptData","error","result","AuthenticationError","wallet","generateBIP39Wallet","index","derived","deriveWalletFromMnemonic","authResult","message","Wallet","chainId","getEndpoints","supportsEIP7702","_target","prop","args","BackupManager","password","guardians","threshold","SocialRecoveryManager","guardianId","socialRecovery","guardian","g","shares","backupData","qrData","DeviceManager","PlatformDetector","scenario","status","RecoverySimulator","topic","getExplainer","explainer","hours","init_errors","init_backup","init_recovery","init_sync","init_education","createWeb3Passkey","config","Web3Passkey","index_default"]}
|