w3pk 0.10.2 → 0.10.4

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/errors.ts","../../src/zk/utils.ts","../../src/zk/proof-generator.ts","../../src/zk/proof-verifier.ts","../../src/zk/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","/**\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 * Stretch a key using PBKDF2\n * Use case: Password hashing, deterministic key derivation\n *\n * @param input - The input string to stretch (e.g., password)\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of iterations (default: 10000)\n * @param keyLength - Output key length in bytes (default: 32)\n * @returns Hex-encoded stretched key\n */\nexport async function stretchKey(\n input: string,\n salt: string,\n iterations: number = 10000,\n keyLength: number = 32\n): Promise<string> {\n try {\n const encoder = new TextEncoder();\n const inputBuffer = encoder.encode(input);\n const saltBuffer = encoder.encode(salt);\n\n // Import the password as a key for PBKDF2\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n inputBuffer,\n \"PBKDF2\",\n false,\n [\"deriveBits\"]\n );\n\n // Derive bits using PBKDF2\n const derivedBits = await crypto.subtle.deriveBits(\n {\n name: \"PBKDF2\",\n salt: saltBuffer,\n iterations: iterations,\n hash: \"SHA-256\",\n },\n keyMaterial,\n keyLength * 8 // Convert bytes to bits\n );\n\n // Convert to hex string\n const hashArray = Array.from(new Uint8Array(derivedBits));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to stretch key\", error);\n }\n}\n\n/**\n * Hash data with salt using SHA-256\n * Use case: Creating deterministic identifiers\n *\n * @param data - The data to hash\n * @param salt - Salt value for additional entropy\n * @returns Hex-encoded hash\n */\nexport async function hashWithSalt(\n data: string,\n salt: string\n): Promise<string> {\n try {\n const combined = data + salt;\n return await sha256Hash(combined);\n } catch (error) {\n throw new CryptoError(\"Failed to hash with salt\", error);\n }\n}\n\n/**\n * Hash data multiple times (key stretching)\n * Use case: Making brute-force attacks impractical\n *\n * @param data - The data to hash\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of hash iterations\n * @returns Hex-encoded hash after multiple iterations\n */\nexport async function iterativeHash(\n data: string,\n salt: string,\n iterations: number\n): Promise<string> {\n try {\n if (iterations < 1) {\n throw new Error(\"Iterations must be at least 1\");\n }\n\n // Initial hash with salt\n let hash = await hashWithSalt(data, salt);\n\n // Iteratively hash the result\n for (let i = 1; i < iterations; i++) {\n hash = await sha256Hash(hash);\n }\n\n return hash;\n } catch (error) {\n throw new CryptoError(\"Failed to perform iterative 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: new Date().toISOString(),\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() - new Date(proof.timestamp).getTime();\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"],"mappings":"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","names":["Web3PasskeyError","message","code","originalError","CryptoError","Web3PasskeyError","message","originalError","bufferToBigInt","buffer","result","i","ZKProofGenerator","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","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","ZKProofModule","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"]}
1
+ {"version":3,"sources":["../../src/core/errors.ts","../../src/zk/utils.ts","../../src/zk/proof-generator.ts","../../src/zk/proof-verifier.ts","../../src/zk/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\n/**\n * The passkey authenticated, but this device has no credential metadata.\n * The app should start a sync or restore flow.\n */\nexport class SyncRequiredError extends Web3PasskeyError {\n constructor(public credentialId: string) {\n super(\n \"Passkey authenticated but this device has no data for it. Sync this device or restore from a backup.\",\n \"SYNC_REQUIRED\"\n );\n this.name = \"SyncRequiredError\";\n }\n}\n\n/**\n * The credential metadata is on this device, but the wallet record is gone.\n * The app should offer a restore from backup.\n */\nexport class WalletMissingError extends Web3PasskeyError {\n constructor(\n public credentialId: string,\n public ethereumAddress: string\n ) {\n super(\n \"Passkey authenticated but no wallet was found on this device. Restore it from a backup.\",\n \"WALLET_MISSING\"\n );\n this.name = \"WalletMissingError\";\n }\n}\n\nexport type SyncBootstrapReason =\n | \"PASSKEY_BACKUP\"\n | \"NO_CREDENTIAL\"\n | \"CREDENTIAL_MISMATCH\"\n | \"PUBLIC_KEY_MISMATCH\";\n\nconst SYNC_BOOTSTRAP_MESSAGES: Record<SyncBootstrapReason, string> = {\n PASSKEY_BACKUP:\n \"This device has no data for the passkey, and a passkey-encrypted backup can't set it up. Sync with a backup from exportForSync() or a password backup instead.\",\n NO_CREDENTIAL:\n \"This backup doesn't name its passkey, so it can't set up this device. Create a new password backup on a device where you're logged in.\",\n CREDENTIAL_MISMATCH:\n \"This backup belongs to a different passkey than the one selected.\",\n PUBLIC_KEY_MISMATCH:\n \"The passkey's signature doesn't match the public key in this backup. The backup may have been tampered with.\",\n};\n\n/**\n * A sync can't set up this device's passkey metadata from the backup.\n */\nexport class SyncBootstrapError extends Web3PasskeyError {\n constructor(\n public reason: SyncBootstrapReason,\n public credentialId: string\n ) {\n super(SYNC_BOOTSTRAP_MESSAGES[reason], \"SYNC_BOOTSTRAP_FAILED\");\n this.name = \"SyncBootstrapError\";\n }\n}\n\n/**\n * The authenticator returned no WebAuthn PRF output, so no\n * passkey-bound secret can be derived. There is no fallback.\n */\nexport class PrfUnsupportedError extends Web3PasskeyError {\n constructor(public credentialId: string) {\n super(\n \"This passkey's authenticator doesn't support the WebAuthn PRF extension.\",\n \"PRF_UNSUPPORTED\"\n );\n this.name = \"PrfUnsupportedError\";\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 * Stretch a key using PBKDF2\n * Use case: Password hashing, deterministic key derivation\n *\n * @param input - The input string to stretch (e.g., password)\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of iterations (default: 10000)\n * @param keyLength - Output key length in bytes (default: 32)\n * @returns Hex-encoded stretched key\n */\nexport async function stretchKey(\n input: string,\n salt: string,\n iterations: number = 10000,\n keyLength: number = 32\n): Promise<string> {\n try {\n const encoder = new TextEncoder();\n const inputBuffer = encoder.encode(input);\n const saltBuffer = encoder.encode(salt);\n\n // Import the password as a key for PBKDF2\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n inputBuffer,\n \"PBKDF2\",\n false,\n [\"deriveBits\"]\n );\n\n // Derive bits using PBKDF2\n const derivedBits = await crypto.subtle.deriveBits(\n {\n name: \"PBKDF2\",\n salt: saltBuffer,\n iterations: iterations,\n hash: \"SHA-256\",\n },\n keyMaterial,\n keyLength * 8 // Convert bytes to bits\n );\n\n // Convert to hex string\n const hashArray = Array.from(new Uint8Array(derivedBits));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to stretch key\", error);\n }\n}\n\n/**\n * Hash data with salt using SHA-256\n * Use case: Creating deterministic identifiers\n *\n * @param data - The data to hash\n * @param salt - Salt value for additional entropy\n * @returns Hex-encoded hash\n */\nexport async function hashWithSalt(\n data: string,\n salt: string\n): Promise<string> {\n try {\n const combined = data + salt;\n return await sha256Hash(combined);\n } catch (error) {\n throw new CryptoError(\"Failed to hash with salt\", error);\n }\n}\n\n/**\n * Hash data multiple times (key stretching)\n * Use case: Making brute-force attacks impractical\n *\n * @param data - The data to hash\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of hash iterations\n * @returns Hex-encoded hash after multiple iterations\n */\nexport async function iterativeHash(\n data: string,\n salt: string,\n iterations: number\n): Promise<string> {\n try {\n if (iterations < 1) {\n throw new Error(\"Iterations must be at least 1\");\n }\n\n // Initial hash with salt\n let hash = await hashWithSalt(data, salt);\n\n // Iteratively hash the result\n for (let i = 1; i < iterations; i++) {\n hash = await sha256Hash(hash);\n }\n\n return hash;\n } catch (error) {\n throw new CryptoError(\"Failed to perform iterative 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: new Date().toISOString(),\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() - new Date(proof.timestamp).getTime();\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"],"mappings":"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","names":["Web3PasskeyError","message","code","originalError","CryptoError","Web3PasskeyError","message","originalError","bufferToBigInt","buffer","result","i","ZKProofGenerator","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","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","ZKProofModule","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"]}
package/dist/zk/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var v=Object.create;var d=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty;var F=(t,r)=>{for(var e in r)d(t,e,{get:r[e],enumerable:!0})},b=(t,r,e,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of P(r))!T.call(t,n)&&n!==e&&d(t,n,{get:()=>r[n],enumerable:!(o=k(r,n))||o.enumerable});return t};var x=(t,r,e)=>(e=t!=null?v(B(t)):{},b(r||!t||!t.__esModule?d(e,"default",{value:t,enumerable:!0}):e,t)),S=t=>b(d({},"__esModule",{value:!0}),t);var K={};F(K,{bigIntToBuffer:()=>O,bigIntToHex:()=>U,bufferToBigInt:()=>g,buildMerkleTree:()=>R,buildNFTHoldersMerkleTree:()=>A,deserializeProof:()=>H,generateBlinding:()=>y,generateMerkleProof:()=>E,generateNFTOwnershipProofInputs:()=>_,generateNonce:()=>M,hashWithSalt:()=>I,hexToBigInt:()=>C,isValidAddress:()=>p,iterativeHash:()=>j,serializeProof:()=>L,sha256Hash:()=>w,stretchKey:()=>N,validateNFTOwnershipProofInputs:()=>z,validateProofInputs:()=>$});module.exports=S(K);var m=class extends Error{constructor(e,o,n){super(e);this.code=o;this.originalError=n;this.name="Web3PasskeyError"}};var i=class extends m{constructor(r,e){super(r,"CRYPTO_ERROR",e),this.name="CryptoError"}};function y(){let t=new Uint8Array(32);return crypto.getRandomValues(t),g(t)}function g(t){let r=0n;for(let e=0;e<t.length;e++)r=r<<8n|BigInt(t[e]);return r}function O(t,r=32){let e=new Uint8Array(r),o=t;for(let n=r-1;n>=0;n--)e[n]=Number(o&0xffn),o=o>>8n;return e}async function w(t){try{let r=typeof t=="string"?new TextEncoder().encode(t):t,e=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(e)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(r){throw new i("Failed to compute hash",r)}}async function N(t,r,e=1e4,o=32){try{let n=new TextEncoder,s=n.encode(t),a=n.encode(r),c=await crypto.subtle.importKey("raw",s,"PBKDF2",!1,["deriveBits"]),l=await crypto.subtle.deriveBits({name:"PBKDF2",salt:a,iterations:e,hash:"SHA-256"},c,o*8);return Array.from(new Uint8Array(l)).map(h=>h.toString(16).padStart(2,"0")).join("")}catch(n){throw new i("Failed to stretch key",n)}}async function I(t,r){try{let e=t+r;return await w(e)}catch(e){throw new i("Failed to hash with salt",e)}}async function j(t,r,e){try{if(e<1)throw new Error("Iterations must be at least 1");let o=await I(t,r);for(let n=1;n<e;n++)o=await w(o);return o}catch(o){throw new i("Failed to perform iterative hash",o)}}async function R(t){try{let e=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build tree from empty leaves");let o=[t],n=t.map(s=>BigInt(s));for(;n.length>1;){let s=[];for(let a=0;a<n.length;a+=2)if(a+1<n.length){let c=e([n[a],n[a+1]]),l=c instanceof Uint8Array?g(c):c;s.push(l)}else s.push(n[a]);o.push(s.map(a=>a.toString())),n=s}return{root:n[0].toString(),tree:o}}catch(r){throw r instanceof Error&&r.message.includes("Cannot resolve module")?new i(`ZK merkle tree requires circomlibjs. Install with: npm install circomlibjs
2
- For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,r):new i("Failed to build merkle tree",r)}}function E(t,r){let e=[],o=[],n=r;for(let s=0;s<t.length-1;s++){let a=n%2===1,c=a?n-1:n+1;e.push(a?1:0),c<t[s].length?o.push(t[s][c]):o.push(t[s][n]),n=Math.floor(n/2)}return{pathIndices:e,pathElements:o}}function $(t){for(let[r,e]of Object.entries(t))if(e==null)throw new i(`Missing required input: ${r}`)}function C(t){return BigInt(t.startsWith("0x")?t:`0x${t}`)}function U(t,r){let e=t.toString(16);return r&&(e=e.padStart(r*2,"0")),`0x${e}`}function L(t){return JSON.stringify(t)}function H(t){try{return JSON.parse(t)}catch(r){throw new i("Failed to deserialize proof",r)}}function M(){return y()}function p(t){return/^0x[a-fA-F0-9]{40}$/.test(t)}async function A(t,r){try{let o=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build NFT holders tree from empty holder list");let n=BigInt(r.startsWith("0x")?r:"0x"+r),s=t.map(l=>{let u=l.startsWith("0x")?l:"0x"+l,h=BigInt(u),f=o([h,n]);return f instanceof Uint8Array?g(f).toString():f.toString()}),{root:a,tree:c}=await R(s);return{root:a,tree:c,holderLeaves:s}}catch(e){throw e instanceof Error&&e.message.includes("Cannot resolve module")?new i(`NFT holder merkle tree requires circomlibjs. Install with: npm install circomlibjs
3
- For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,e):new i("Failed to build NFT holders merkle tree",e)}}async function _(t,r,e,o=1n){let n=e.findIndex(h=>h.toLowerCase()===t.toLowerCase());if(n===-1)throw new i(`Owner address ${t} not found in holders list for contract ${r}`);let{root:s,tree:a,holderLeaves:c}=await A(e,r),{pathIndices:l,pathElements:u}=E(a,n);return{nftProofInput:{ownerAddress:t,holderIndex:n,pathIndices:l,pathElements:u,holdersRoot:s,contractAddress:r,minBalance:o},holderLeaves:c}}function z(t){if(!p(t.ownerAddress))throw new i(`Invalid owner address: ${t.ownerAddress}`);if(!p(t.contractAddress))throw new i(`Invalid contract address: ${t.contractAddress}`);if(t.holderIndex<0||!Number.isInteger(t.holderIndex))throw new i(`Invalid holder index: ${t.holderIndex}`);if(t.pathIndices.length!==t.pathElements.length)throw new i(`Path indices and elements length mismatch: ${t.pathIndices.length} vs ${t.pathElements.length}`);if(t.pathIndices.length===0)throw new i("Empty merkle proof path");if(!t.holdersRoot||t.holdersRoot.length===0)throw new i("Invalid holders root");if(t.minBalance&&t.minBalance<1n)throw new i("Minimum balance must be at least 1")}
1
+ "use strict";var S=Object.create;var d=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,v=Object.prototype.hasOwnProperty;var B=(t,e)=>{for(var r in e)d(t,r,{get:e[r],enumerable:!0})},b=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of T(e))!v.call(t,n)&&n!==r&&d(t,n,{get:()=>e[n],enumerable:!(o=k(e,n))||o.enumerable});return t};var x=(t,e,r)=>(r=t!=null?S(P(t)):{},b(e||!t||!t.__esModule?d(r,"default",{value:t,enumerable:!0}):r,t)),C=t=>b(d({},"__esModule",{value:!0}),t);var D={};B(D,{bigIntToBuffer:()=>N,bigIntToHex:()=>M,bufferToBigInt:()=>p,buildMerkleTree:()=>R,buildNFTHoldersMerkleTree:()=>A,deserializeProof:()=>H,generateBlinding:()=>y,generateMerkleProof:()=>E,generateNFTOwnershipProofInputs:()=>K,generateNonce:()=>j,hashWithSalt:()=>I,hexToBigInt:()=>L,isValidAddress:()=>m,iterativeHash:()=>_,serializeProof:()=>U,sha256Hash:()=>w,stretchKey:()=>O,validateNFTOwnershipProofInputs:()=>$,validateProofInputs:()=>F});module.exports=C(D);var f=class extends Error{constructor(r,o,n){super(r);this.code=o;this.originalError=n;this.name="Web3PasskeyError"}};var s=class extends f{constructor(e,r){super(e,"CRYPTO_ERROR",r),this.name="CryptoError"}};function y(){let t=new Uint8Array(32);return crypto.getRandomValues(t),p(t)}function p(t){let e=0n;for(let r=0;r<t.length;r++)e=e<<8n|BigInt(t[r]);return e}function N(t,e=32){let r=new Uint8Array(e),o=t;for(let n=e-1;n>=0;n--)r[n]=Number(o&0xffn),o=o>>8n;return r}async function w(t){try{let e=typeof t=="string"?new TextEncoder().encode(t):t,r=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(e){throw new s("Failed to compute hash",e)}}async function O(t,e,r=1e4,o=32){try{let n=new TextEncoder,i=n.encode(t),a=n.encode(e),c=await crypto.subtle.importKey("raw",i,"PBKDF2",!1,["deriveBits"]),h=await crypto.subtle.deriveBits({name:"PBKDF2",salt:a,iterations:r,hash:"SHA-256"},c,o*8);return Array.from(new Uint8Array(h)).map(l=>l.toString(16).padStart(2,"0")).join("")}catch(n){throw new s("Failed to stretch key",n)}}async function I(t,e){try{let r=t+e;return await w(r)}catch(r){throw new s("Failed to hash with salt",r)}}async function _(t,e,r){try{if(r<1)throw new Error("Iterations must be at least 1");let o=await I(t,e);for(let n=1;n<r;n++)o=await w(o);return o}catch(o){throw new s("Failed to perform iterative hash",o)}}async function R(t){try{let r=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build tree from empty leaves");let o=[t],n=t.map(i=>BigInt(i));for(;n.length>1;){let i=[];for(let a=0;a<n.length;a+=2)if(a+1<n.length){let c=r([n[a],n[a+1]]),h=c instanceof Uint8Array?p(c):c;i.push(h)}else i.push(n[a]);o.push(i.map(a=>a.toString())),n=i}return{root:n[0].toString(),tree:o}}catch(e){throw e instanceof Error&&e.message.includes("Cannot resolve module")?new s(`ZK merkle tree requires circomlibjs. Install with: npm install circomlibjs
2
+ For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,e):new s("Failed to build merkle tree",e)}}function E(t,e){let r=[],o=[],n=e;for(let i=0;i<t.length-1;i++){let a=n%2===1,c=a?n-1:n+1;r.push(a?1:0),c<t[i].length?o.push(t[i][c]):o.push(t[i][n]),n=Math.floor(n/2)}return{pathIndices:r,pathElements:o}}function F(t){for(let[e,r]of Object.entries(t))if(r==null)throw new s(`Missing required input: ${e}`)}function L(t){return BigInt(t.startsWith("0x")?t:`0x${t}`)}function M(t,e){let r=t.toString(16);return e&&(r=r.padStart(e*2,"0")),`0x${r}`}function U(t){return JSON.stringify(t)}function H(t){try{return JSON.parse(t)}catch(e){throw new s("Failed to deserialize proof",e)}}function j(){return y()}function m(t){return/^0x[a-fA-F0-9]{40}$/.test(t)}async function A(t,e){try{let o=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build NFT holders tree from empty holder list");let n=BigInt(e.startsWith("0x")?e:"0x"+e),i=t.map(h=>{let u=h.startsWith("0x")?h:"0x"+h,l=BigInt(u),g=o([l,n]);return g instanceof Uint8Array?p(g).toString():g.toString()}),{root:a,tree:c}=await R(i);return{root:a,tree:c,holderLeaves:i}}catch(r){throw r instanceof Error&&r.message.includes("Cannot resolve module")?new s(`NFT holder merkle tree requires circomlibjs. Install with: npm install circomlibjs
3
+ For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,r):new s("Failed to build NFT holders merkle tree",r)}}async function K(t,e,r,o=1n){let n=r.findIndex(l=>l.toLowerCase()===t.toLowerCase());if(n===-1)throw new s(`Owner address ${t} not found in holders list for contract ${e}`);let{root:i,tree:a,holderLeaves:c}=await A(r,e),{pathIndices:h,pathElements:u}=E(a,n);return{nftProofInput:{ownerAddress:t,holderIndex:n,pathIndices:h,pathElements:u,holdersRoot:i,contractAddress:e,minBalance:o},holderLeaves:c}}function $(t){if(!m(t.ownerAddress))throw new s(`Invalid owner address: ${t.ownerAddress}`);if(!m(t.contractAddress))throw new s(`Invalid contract address: ${t.contractAddress}`);if(t.holderIndex<0||!Number.isInteger(t.holderIndex))throw new s(`Invalid holder index: ${t.holderIndex}`);if(t.pathIndices.length!==t.pathElements.length)throw new s(`Path indices and elements length mismatch: ${t.pathIndices.length} vs ${t.pathElements.length}`);if(t.pathIndices.length===0)throw new s("Empty merkle proof path");if(!t.holdersRoot||t.holdersRoot.length===0)throw new s("Invalid holders root");if(t.minBalance&&t.minBalance<1n)throw new s("Minimum balance must be at least 1")}
4
4
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/zk/utils.ts","../../src/core/errors.ts"],"sourcesContent":["/**\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 * Stretch a key using PBKDF2\n * Use case: Password hashing, deterministic key derivation\n *\n * @param input - The input string to stretch (e.g., password)\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of iterations (default: 10000)\n * @param keyLength - Output key length in bytes (default: 32)\n * @returns Hex-encoded stretched key\n */\nexport async function stretchKey(\n input: string,\n salt: string,\n iterations: number = 10000,\n keyLength: number = 32\n): Promise<string> {\n try {\n const encoder = new TextEncoder();\n const inputBuffer = encoder.encode(input);\n const saltBuffer = encoder.encode(salt);\n\n // Import the password as a key for PBKDF2\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n inputBuffer,\n \"PBKDF2\",\n false,\n [\"deriveBits\"]\n );\n\n // Derive bits using PBKDF2\n const derivedBits = await crypto.subtle.deriveBits(\n {\n name: \"PBKDF2\",\n salt: saltBuffer,\n iterations: iterations,\n hash: \"SHA-256\",\n },\n keyMaterial,\n keyLength * 8 // Convert bytes to bits\n );\n\n // Convert to hex string\n const hashArray = Array.from(new Uint8Array(derivedBits));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to stretch key\", error);\n }\n}\n\n/**\n * Hash data with salt using SHA-256\n * Use case: Creating deterministic identifiers\n *\n * @param data - The data to hash\n * @param salt - Salt value for additional entropy\n * @returns Hex-encoded hash\n */\nexport async function hashWithSalt(\n data: string,\n salt: string\n): Promise<string> {\n try {\n const combined = data + salt;\n return await sha256Hash(combined);\n } catch (error) {\n throw new CryptoError(\"Failed to hash with salt\", error);\n }\n}\n\n/**\n * Hash data multiple times (key stretching)\n * Use case: Making brute-force attacks impractical\n *\n * @param data - The data to hash\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of hash iterations\n * @returns Hex-encoded hash after multiple iterations\n */\nexport async function iterativeHash(\n data: string,\n salt: string,\n iterations: number\n): Promise<string> {\n try {\n if (iterations < 1) {\n throw new Error(\"Iterations must be at least 1\");\n }\n\n // Initial hash with salt\n let hash = await hashWithSalt(data, salt);\n\n // Iteratively hash the result\n for (let i = 1; i < iterations; i++) {\n hash = await sha256Hash(hash);\n }\n\n return hash;\n } catch (error) {\n throw new CryptoError(\"Failed to perform iterative 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 * 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"],"mappings":"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","names":["utils_exports","__export","bigIntToBuffer","bigIntToHex","bufferToBigInt","buildMerkleTree","buildNFTHoldersMerkleTree","deserializeProof","generateBlinding","generateMerkleProof","generateNFTOwnershipProofInputs","generateNonce","hashWithSalt","hexToBigInt","isValidAddress","iterativeHash","serializeProof","sha256Hash","stretchKey","validateNFTOwnershipProofInputs","validateProofInputs","__toCommonJS","Web3PasskeyError","message","code","originalError","CryptoError","Web3PasskeyError","message","originalError","generateBlinding","buffer","bufferToBigInt","result","i","bigIntToBuffer","value","byteLength","temp","sha256Hash","data","hashBuffer","b","error","CryptoError","stretchKey","input","salt","iterations","keyLength","encoder","inputBuffer","saltBuffer","keyMaterial","derivedBits","hashWithSalt","combined","iterativeHash","hash","buildMerkleTree","leaves","poseidon","tree","currentLevel","leaf","nextLevel","hashResult","n","generateMerkleProof","leafIndex","pathIndices","pathElements","currentIndex","level","isRightNode","siblingIndex","validateProofInputs","inputs","key","hexToBigInt","hex","bigIntToHex","padToBytes","serializeProof","proof","deserializeProof","serialized","generateNonce","isValidAddress","address","buildNFTHoldersMerkleTree","holderAddresses","contractAddress","contractHash","holderLeaves","cleanAddress","addressHash","root","generateNFTOwnershipProofInputs","ownerAddress","allHolderAddresses","minBalance","holderIndex","validateNFTOwnershipProofInputs"]}
1
+ {"version":3,"sources":["../../src/zk/utils.ts","../../src/core/errors.ts"],"sourcesContent":["/**\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 * Stretch a key using PBKDF2\n * Use case: Password hashing, deterministic key derivation\n *\n * @param input - The input string to stretch (e.g., password)\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of iterations (default: 10000)\n * @param keyLength - Output key length in bytes (default: 32)\n * @returns Hex-encoded stretched key\n */\nexport async function stretchKey(\n input: string,\n salt: string,\n iterations: number = 10000,\n keyLength: number = 32\n): Promise<string> {\n try {\n const encoder = new TextEncoder();\n const inputBuffer = encoder.encode(input);\n const saltBuffer = encoder.encode(salt);\n\n // Import the password as a key for PBKDF2\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n inputBuffer,\n \"PBKDF2\",\n false,\n [\"deriveBits\"]\n );\n\n // Derive bits using PBKDF2\n const derivedBits = await crypto.subtle.deriveBits(\n {\n name: \"PBKDF2\",\n salt: saltBuffer,\n iterations: iterations,\n hash: \"SHA-256\",\n },\n keyMaterial,\n keyLength * 8 // Convert bytes to bits\n );\n\n // Convert to hex string\n const hashArray = Array.from(new Uint8Array(derivedBits));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to stretch key\", error);\n }\n}\n\n/**\n * Hash data with salt using SHA-256\n * Use case: Creating deterministic identifiers\n *\n * @param data - The data to hash\n * @param salt - Salt value for additional entropy\n * @returns Hex-encoded hash\n */\nexport async function hashWithSalt(\n data: string,\n salt: string\n): Promise<string> {\n try {\n const combined = data + salt;\n return await sha256Hash(combined);\n } catch (error) {\n throw new CryptoError(\"Failed to hash with salt\", error);\n }\n}\n\n/**\n * Hash data multiple times (key stretching)\n * Use case: Making brute-force attacks impractical\n *\n * @param data - The data to hash\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of hash iterations\n * @returns Hex-encoded hash after multiple iterations\n */\nexport async function iterativeHash(\n data: string,\n salt: string,\n iterations: number\n): Promise<string> {\n try {\n if (iterations < 1) {\n throw new Error(\"Iterations must be at least 1\");\n }\n\n // Initial hash with salt\n let hash = await hashWithSalt(data, salt);\n\n // Iteratively hash the result\n for (let i = 1; i < iterations; i++) {\n hash = await sha256Hash(hash);\n }\n\n return hash;\n } catch (error) {\n throw new CryptoError(\"Failed to perform iterative 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 * 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\n/**\n * The passkey authenticated, but this device has no credential metadata.\n * The app should start a sync or restore flow.\n */\nexport class SyncRequiredError extends Web3PasskeyError {\n constructor(public credentialId: string) {\n super(\n \"Passkey authenticated but this device has no data for it. Sync this device or restore from a backup.\",\n \"SYNC_REQUIRED\"\n );\n this.name = \"SyncRequiredError\";\n }\n}\n\n/**\n * The credential metadata is on this device, but the wallet record is gone.\n * The app should offer a restore from backup.\n */\nexport class WalletMissingError extends Web3PasskeyError {\n constructor(\n public credentialId: string,\n public ethereumAddress: string\n ) {\n super(\n \"Passkey authenticated but no wallet was found on this device. Restore it from a backup.\",\n \"WALLET_MISSING\"\n );\n this.name = \"WalletMissingError\";\n }\n}\n\nexport type SyncBootstrapReason =\n | \"PASSKEY_BACKUP\"\n | \"NO_CREDENTIAL\"\n | \"CREDENTIAL_MISMATCH\"\n | \"PUBLIC_KEY_MISMATCH\";\n\nconst SYNC_BOOTSTRAP_MESSAGES: Record<SyncBootstrapReason, string> = {\n PASSKEY_BACKUP:\n \"This device has no data for the passkey, and a passkey-encrypted backup can't set it up. Sync with a backup from exportForSync() or a password backup instead.\",\n NO_CREDENTIAL:\n \"This backup doesn't name its passkey, so it can't set up this device. Create a new password backup on a device where you're logged in.\",\n CREDENTIAL_MISMATCH:\n \"This backup belongs to a different passkey than the one selected.\",\n PUBLIC_KEY_MISMATCH:\n \"The passkey's signature doesn't match the public key in this backup. The backup may have been tampered with.\",\n};\n\n/**\n * A sync can't set up this device's passkey metadata from the backup.\n */\nexport class SyncBootstrapError extends Web3PasskeyError {\n constructor(\n public reason: SyncBootstrapReason,\n public credentialId: string\n ) {\n super(SYNC_BOOTSTRAP_MESSAGES[reason], \"SYNC_BOOTSTRAP_FAILED\");\n this.name = \"SyncBootstrapError\";\n }\n}\n\n/**\n * The authenticator returned no WebAuthn PRF output, so no\n * passkey-bound secret can be derived. There is no fallback.\n */\nexport class PrfUnsupportedError extends Web3PasskeyError {\n constructor(public credentialId: string) {\n super(\n \"This passkey's authenticator doesn't support the WebAuthn PRF extension.\",\n \"PRF_UNSUPPORTED\"\n );\n this.name = \"PrfUnsupportedError\";\n }\n}\n"],"mappings":"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","names":["utils_exports","__export","bigIntToBuffer","bigIntToHex","bufferToBigInt","buildMerkleTree","buildNFTHoldersMerkleTree","deserializeProof","generateBlinding","generateMerkleProof","generateNFTOwnershipProofInputs","generateNonce","hashWithSalt","hexToBigInt","isValidAddress","iterativeHash","serializeProof","sha256Hash","stretchKey","validateNFTOwnershipProofInputs","validateProofInputs","__toCommonJS","Web3PasskeyError","message","code","originalError","CryptoError","Web3PasskeyError","message","originalError","generateBlinding","buffer","bufferToBigInt","result","i","bigIntToBuffer","value","byteLength","temp","sha256Hash","data","hashBuffer","b","error","CryptoError","stretchKey","input","salt","iterations","keyLength","encoder","inputBuffer","saltBuffer","keyMaterial","derivedBits","hashWithSalt","combined","iterativeHash","hash","buildMerkleTree","leaves","poseidon","tree","currentLevel","leaf","nextLevel","hashResult","n","generateMerkleProof","leafIndex","pathIndices","pathElements","currentIndex","level","isRightNode","siblingIndex","validateProofInputs","inputs","key","hexToBigInt","hex","bigIntToHex","padToBytes","serializeProof","proof","deserializeProof","serialized","generateNonce","isValidAddress","address","buildNFTHoldersMerkleTree","holderAddresses","contractAddress","contractHash","holderLeaves","cleanAddress","addressHash","root","generateNFTOwnershipProofInputs","ownerAddress","allHolderAddresses","minBalance","holderIndex","validateNFTOwnershipProofInputs"]}
package/dist/zk/utils.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var g=class extends Error{constructor(e,o,n){super(e);this.code=o;this.originalError=n;this.name="Web3PasskeyError"}};var i=class extends g{constructor(r,e){super(r,"CRYPTO_ERROR",e),this.name="CryptoError"}};function w(){let t=new Uint8Array(32);return crypto.getRandomValues(t),f(t)}function f(t){let r=0n;for(let e=0;e<t.length;e++)r=r<<8n|BigInt(t[e]);return r}function A(t,r=32){let e=new Uint8Array(r),o=t;for(let n=r-1;n>=0;n--)e[n]=Number(o&0xffn),o=o>>8n;return e}async function p(t){try{let r=typeof t=="string"?new TextEncoder().encode(t):t,e=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(e)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(r){throw new i("Failed to compute hash",r)}}async function v(t,r,e=1e4,o=32){try{let n=new TextEncoder,s=n.encode(t),a=n.encode(r),c=await crypto.subtle.importKey("raw",s,"PBKDF2",!1,["deriveBits"]),l=await crypto.subtle.deriveBits({name:"PBKDF2",salt:a,iterations:e,hash:"SHA-256"},c,o*8);return Array.from(new Uint8Array(l)).map(h=>h.toString(16).padStart(2,"0")).join("")}catch(n){throw new i("Failed to stretch key",n)}}async function b(t,r){try{let e=t+r;return await p(e)}catch(e){throw new i("Failed to hash with salt",e)}}async function k(t,r,e){try{if(e<1)throw new Error("Iterations must be at least 1");let o=await b(t,r);for(let n=1;n<e;n++)o=await p(o);return o}catch(o){throw new i("Failed to perform iterative hash",o)}}async function x(t){try{let e=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build tree from empty leaves");let o=[t],n=t.map(s=>BigInt(s));for(;n.length>1;){let s=[];for(let a=0;a<n.length;a+=2)if(a+1<n.length){let c=e([n[a],n[a+1]]),l=c instanceof Uint8Array?f(c):c;s.push(l)}else s.push(n[a]);o.push(s.map(a=>a.toString())),n=s}return{root:n[0].toString(),tree:o}}catch(r){throw r instanceof Error&&r.message.includes("Cannot resolve module")?new i(`ZK merkle tree requires circomlibjs. Install with: npm install circomlibjs
2
- For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,r):new i("Failed to build merkle tree",r)}}function y(t,r){let e=[],o=[],n=r;for(let s=0;s<t.length-1;s++){let a=n%2===1,c=a?n-1:n+1;e.push(a?1:0),c<t[s].length?o.push(t[s][c]):o.push(t[s][n]),n=Math.floor(n/2)}return{pathIndices:e,pathElements:o}}function P(t){for(let[r,e]of Object.entries(t))if(e==null)throw new i(`Missing required input: ${r}`)}function B(t){return BigInt(t.startsWith("0x")?t:`0x${t}`)}function T(t,r){let e=t.toString(16);return r&&(e=e.padStart(r*2,"0")),`0x${e}`}function F(t){return JSON.stringify(t)}function S(t){try{return JSON.parse(t)}catch(r){throw new i("Failed to deserialize proof",r)}}function O(){return w()}function m(t){return/^0x[a-fA-F0-9]{40}$/.test(t)}async function I(t,r){try{let o=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build NFT holders tree from empty holder list");let n=BigInt(r.startsWith("0x")?r:"0x"+r),s=t.map(l=>{let u=l.startsWith("0x")?l:"0x"+l,h=BigInt(u),d=o([h,n]);return d instanceof Uint8Array?f(d).toString():d.toString()}),{root:a,tree:c}=await x(s);return{root:a,tree:c,holderLeaves:s}}catch(e){throw e instanceof Error&&e.message.includes("Cannot resolve module")?new i(`NFT holder merkle tree requires circomlibjs. Install with: npm install circomlibjs
3
- For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,e):new i("Failed to build NFT holders merkle tree",e)}}async function N(t,r,e,o=1n){let n=e.findIndex(h=>h.toLowerCase()===t.toLowerCase());if(n===-1)throw new i(`Owner address ${t} not found in holders list for contract ${r}`);let{root:s,tree:a,holderLeaves:c}=await I(e,r),{pathIndices:l,pathElements:u}=y(a,n);return{nftProofInput:{ownerAddress:t,holderIndex:n,pathIndices:l,pathElements:u,holdersRoot:s,contractAddress:r,minBalance:o},holderLeaves:c}}function j(t){if(!m(t.ownerAddress))throw new i(`Invalid owner address: ${t.ownerAddress}`);if(!m(t.contractAddress))throw new i(`Invalid contract address: ${t.contractAddress}`);if(t.holderIndex<0||!Number.isInteger(t.holderIndex))throw new i(`Invalid holder index: ${t.holderIndex}`);if(t.pathIndices.length!==t.pathElements.length)throw new i(`Path indices and elements length mismatch: ${t.pathIndices.length} vs ${t.pathElements.length}`);if(t.pathIndices.length===0)throw new i("Empty merkle proof path");if(!t.holdersRoot||t.holdersRoot.length===0)throw new i("Invalid holders root");if(t.minBalance&&t.minBalance<1n)throw new i("Minimum balance must be at least 1")}export{A as bigIntToBuffer,T as bigIntToHex,f as bufferToBigInt,x as buildMerkleTree,I as buildNFTHoldersMerkleTree,S as deserializeProof,w as generateBlinding,y as generateMerkleProof,N as generateNFTOwnershipProofInputs,O as generateNonce,b as hashWithSalt,B as hexToBigInt,m as isValidAddress,k as iterativeHash,F as serializeProof,p as sha256Hash,v as stretchKey,j as validateNFTOwnershipProofInputs,P as validateProofInputs};
1
+ var p=class extends Error{constructor(r,o,n){super(r);this.code=o;this.originalError=n;this.name="Web3PasskeyError"}};var s=class extends p{constructor(e,r){super(e,"CRYPTO_ERROR",r),this.name="CryptoError"}};function w(){let t=new Uint8Array(32);return crypto.getRandomValues(t),g(t)}function g(t){let e=0n;for(let r=0;r<t.length;r++)e=e<<8n|BigInt(t[r]);return e}function A(t,e=32){let r=new Uint8Array(e),o=t;for(let n=e-1;n>=0;n--)r[n]=Number(o&0xffn),o=o>>8n;return r}async function m(t){try{let e=typeof t=="string"?new TextEncoder().encode(t):t,r=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(e){throw new s("Failed to compute hash",e)}}async function S(t,e,r=1e4,o=32){try{let n=new TextEncoder,i=n.encode(t),a=n.encode(e),c=await crypto.subtle.importKey("raw",i,"PBKDF2",!1,["deriveBits"]),h=await crypto.subtle.deriveBits({name:"PBKDF2",salt:a,iterations:r,hash:"SHA-256"},c,o*8);return Array.from(new Uint8Array(h)).map(l=>l.toString(16).padStart(2,"0")).join("")}catch(n){throw new s("Failed to stretch key",n)}}async function b(t,e){try{let r=t+e;return await m(r)}catch(r){throw new s("Failed to hash with salt",r)}}async function k(t,e,r){try{if(r<1)throw new Error("Iterations must be at least 1");let o=await b(t,e);for(let n=1;n<r;n++)o=await m(o);return o}catch(o){throw new s("Failed to perform iterative hash",o)}}async function x(t){try{let r=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build tree from empty leaves");let o=[t],n=t.map(i=>BigInt(i));for(;n.length>1;){let i=[];for(let a=0;a<n.length;a+=2)if(a+1<n.length){let c=r([n[a],n[a+1]]),h=c instanceof Uint8Array?g(c):c;i.push(h)}else i.push(n[a]);o.push(i.map(a=>a.toString())),n=i}return{root:n[0].toString(),tree:o}}catch(e){throw e instanceof Error&&e.message.includes("Cannot resolve module")?new s(`ZK merkle tree requires circomlibjs. Install with: npm install circomlibjs
2
+ For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,e):new s("Failed to build merkle tree",e)}}function y(t,e){let r=[],o=[],n=e;for(let i=0;i<t.length-1;i++){let a=n%2===1,c=a?n-1:n+1;r.push(a?1:0),c<t[i].length?o.push(t[i][c]):o.push(t[i][n]),n=Math.floor(n/2)}return{pathIndices:r,pathElements:o}}function T(t){for(let[e,r]of Object.entries(t))if(r==null)throw new s(`Missing required input: ${e}`)}function P(t){return BigInt(t.startsWith("0x")?t:`0x${t}`)}function v(t,e){let r=t.toString(16);return e&&(r=r.padStart(e*2,"0")),`0x${r}`}function B(t){return JSON.stringify(t)}function C(t){try{return JSON.parse(t)}catch(e){throw new s("Failed to deserialize proof",e)}}function N(){return w()}function f(t){return/^0x[a-fA-F0-9]{40}$/.test(t)}async function I(t,e){try{let o=await(await import("circomlibjs")).buildPoseidon();if(t.length===0)throw new Error("Cannot build NFT holders tree from empty holder list");let n=BigInt(e.startsWith("0x")?e:"0x"+e),i=t.map(h=>{let u=h.startsWith("0x")?h:"0x"+h,l=BigInt(u),d=o([l,n]);return d instanceof Uint8Array?g(d).toString():d.toString()}),{root:a,tree:c}=await x(i);return{root:a,tree:c,holderLeaves:i}}catch(r){throw r instanceof Error&&r.message.includes("Cannot resolve module")?new s(`NFT holder merkle tree requires circomlibjs. Install with: npm install circomlibjs
3
+ For more info: https://github.com/w3hc/w3pk#zero-knowledge-proofs`,r):new s("Failed to build NFT holders merkle tree",r)}}async function O(t,e,r,o=1n){let n=r.findIndex(l=>l.toLowerCase()===t.toLowerCase());if(n===-1)throw new s(`Owner address ${t} not found in holders list for contract ${e}`);let{root:i,tree:a,holderLeaves:c}=await I(r,e),{pathIndices:h,pathElements:u}=y(a,n);return{nftProofInput:{ownerAddress:t,holderIndex:n,pathIndices:h,pathElements:u,holdersRoot:i,contractAddress:e,minBalance:o},holderLeaves:c}}function _(t){if(!f(t.ownerAddress))throw new s(`Invalid owner address: ${t.ownerAddress}`);if(!f(t.contractAddress))throw new s(`Invalid contract address: ${t.contractAddress}`);if(t.holderIndex<0||!Number.isInteger(t.holderIndex))throw new s(`Invalid holder index: ${t.holderIndex}`);if(t.pathIndices.length!==t.pathElements.length)throw new s(`Path indices and elements length mismatch: ${t.pathIndices.length} vs ${t.pathElements.length}`);if(t.pathIndices.length===0)throw new s("Empty merkle proof path");if(!t.holdersRoot||t.holdersRoot.length===0)throw new s("Invalid holders root");if(t.minBalance&&t.minBalance<1n)throw new s("Minimum balance must be at least 1")}export{A as bigIntToBuffer,v as bigIntToHex,g as bufferToBigInt,x as buildMerkleTree,I as buildNFTHoldersMerkleTree,C as deserializeProof,w as generateBlinding,y as generateMerkleProof,O as generateNFTOwnershipProofInputs,N as generateNonce,b as hashWithSalt,P as hexToBigInt,f as isValidAddress,k as iterativeHash,B as serializeProof,m as sha256Hash,S as stretchKey,_ as validateNFTOwnershipProofInputs,T as validateProofInputs};
4
4
  //# sourceMappingURL=utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/errors.ts","../../src/zk/utils.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","/**\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 * Stretch a key using PBKDF2\n * Use case: Password hashing, deterministic key derivation\n *\n * @param input - The input string to stretch (e.g., password)\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of iterations (default: 10000)\n * @param keyLength - Output key length in bytes (default: 32)\n * @returns Hex-encoded stretched key\n */\nexport async function stretchKey(\n input: string,\n salt: string,\n iterations: number = 10000,\n keyLength: number = 32\n): Promise<string> {\n try {\n const encoder = new TextEncoder();\n const inputBuffer = encoder.encode(input);\n const saltBuffer = encoder.encode(salt);\n\n // Import the password as a key for PBKDF2\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n inputBuffer,\n \"PBKDF2\",\n false,\n [\"deriveBits\"]\n );\n\n // Derive bits using PBKDF2\n const derivedBits = await crypto.subtle.deriveBits(\n {\n name: \"PBKDF2\",\n salt: saltBuffer,\n iterations: iterations,\n hash: \"SHA-256\",\n },\n keyMaterial,\n keyLength * 8 // Convert bytes to bits\n );\n\n // Convert to hex string\n const hashArray = Array.from(new Uint8Array(derivedBits));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to stretch key\", error);\n }\n}\n\n/**\n * Hash data with salt using SHA-256\n * Use case: Creating deterministic identifiers\n *\n * @param data - The data to hash\n * @param salt - Salt value for additional entropy\n * @returns Hex-encoded hash\n */\nexport async function hashWithSalt(\n data: string,\n salt: string\n): Promise<string> {\n try {\n const combined = data + salt;\n return await sha256Hash(combined);\n } catch (error) {\n throw new CryptoError(\"Failed to hash with salt\", error);\n }\n}\n\n/**\n * Hash data multiple times (key stretching)\n * Use case: Making brute-force attacks impractical\n *\n * @param data - The data to hash\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of hash iterations\n * @returns Hex-encoded hash after multiple iterations\n */\nexport async function iterativeHash(\n data: string,\n salt: string,\n iterations: number\n): Promise<string> {\n try {\n if (iterations < 1) {\n throw new Error(\"Iterations must be at least 1\");\n }\n\n // Initial hash with salt\n let hash = await hashWithSalt(data, salt);\n\n // Iteratively hash the result\n for (let i = 1; i < iterations; i++) {\n hash = await sha256Hash(hash);\n }\n\n return hash;\n } catch (error) {\n throw new CryptoError(\"Failed to perform iterative 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"],"mappings":"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","names":["Web3PasskeyError","message","code","originalError","CryptoError","Web3PasskeyError","message","originalError","generateBlinding","buffer","bufferToBigInt","result","i","bigIntToBuffer","value","byteLength","temp","sha256Hash","data","hashBuffer","b","error","CryptoError","stretchKey","input","salt","iterations","keyLength","encoder","inputBuffer","saltBuffer","keyMaterial","derivedBits","hashWithSalt","combined","iterativeHash","hash","buildMerkleTree","leaves","poseidon","tree","currentLevel","leaf","nextLevel","hashResult","n","generateMerkleProof","leafIndex","pathIndices","pathElements","currentIndex","level","isRightNode","siblingIndex","validateProofInputs","inputs","key","hexToBigInt","hex","bigIntToHex","padToBytes","serializeProof","proof","deserializeProof","serialized","generateNonce","isValidAddress","address","buildNFTHoldersMerkleTree","holderAddresses","contractAddress","contractHash","holderLeaves","cleanAddress","addressHash","root","generateNFTOwnershipProofInputs","ownerAddress","allHolderAddresses","minBalance","holderIndex","validateNFTOwnershipProofInputs"]}
1
+ {"version":3,"sources":["../../src/core/errors.ts","../../src/zk/utils.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\n/**\n * The passkey authenticated, but this device has no credential metadata.\n * The app should start a sync or restore flow.\n */\nexport class SyncRequiredError extends Web3PasskeyError {\n constructor(public credentialId: string) {\n super(\n \"Passkey authenticated but this device has no data for it. Sync this device or restore from a backup.\",\n \"SYNC_REQUIRED\"\n );\n this.name = \"SyncRequiredError\";\n }\n}\n\n/**\n * The credential metadata is on this device, but the wallet record is gone.\n * The app should offer a restore from backup.\n */\nexport class WalletMissingError extends Web3PasskeyError {\n constructor(\n public credentialId: string,\n public ethereumAddress: string\n ) {\n super(\n \"Passkey authenticated but no wallet was found on this device. Restore it from a backup.\",\n \"WALLET_MISSING\"\n );\n this.name = \"WalletMissingError\";\n }\n}\n\nexport type SyncBootstrapReason =\n | \"PASSKEY_BACKUP\"\n | \"NO_CREDENTIAL\"\n | \"CREDENTIAL_MISMATCH\"\n | \"PUBLIC_KEY_MISMATCH\";\n\nconst SYNC_BOOTSTRAP_MESSAGES: Record<SyncBootstrapReason, string> = {\n PASSKEY_BACKUP:\n \"This device has no data for the passkey, and a passkey-encrypted backup can't set it up. Sync with a backup from exportForSync() or a password backup instead.\",\n NO_CREDENTIAL:\n \"This backup doesn't name its passkey, so it can't set up this device. Create a new password backup on a device where you're logged in.\",\n CREDENTIAL_MISMATCH:\n \"This backup belongs to a different passkey than the one selected.\",\n PUBLIC_KEY_MISMATCH:\n \"The passkey's signature doesn't match the public key in this backup. The backup may have been tampered with.\",\n};\n\n/**\n * A sync can't set up this device's passkey metadata from the backup.\n */\nexport class SyncBootstrapError extends Web3PasskeyError {\n constructor(\n public reason: SyncBootstrapReason,\n public credentialId: string\n ) {\n super(SYNC_BOOTSTRAP_MESSAGES[reason], \"SYNC_BOOTSTRAP_FAILED\");\n this.name = \"SyncBootstrapError\";\n }\n}\n\n/**\n * The authenticator returned no WebAuthn PRF output, so no\n * passkey-bound secret can be derived. There is no fallback.\n */\nexport class PrfUnsupportedError extends Web3PasskeyError {\n constructor(public credentialId: string) {\n super(\n \"This passkey's authenticator doesn't support the WebAuthn PRF extension.\",\n \"PRF_UNSUPPORTED\"\n );\n this.name = \"PrfUnsupportedError\";\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 * Stretch a key using PBKDF2\n * Use case: Password hashing, deterministic key derivation\n *\n * @param input - The input string to stretch (e.g., password)\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of iterations (default: 10000)\n * @param keyLength - Output key length in bytes (default: 32)\n * @returns Hex-encoded stretched key\n */\nexport async function stretchKey(\n input: string,\n salt: string,\n iterations: number = 10000,\n keyLength: number = 32\n): Promise<string> {\n try {\n const encoder = new TextEncoder();\n const inputBuffer = encoder.encode(input);\n const saltBuffer = encoder.encode(salt);\n\n // Import the password as a key for PBKDF2\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n inputBuffer,\n \"PBKDF2\",\n false,\n [\"deriveBits\"]\n );\n\n // Derive bits using PBKDF2\n const derivedBits = await crypto.subtle.deriveBits(\n {\n name: \"PBKDF2\",\n salt: saltBuffer,\n iterations: iterations,\n hash: \"SHA-256\",\n },\n keyMaterial,\n keyLength * 8 // Convert bytes to bits\n );\n\n // Convert to hex string\n const hashArray = Array.from(new Uint8Array(derivedBits));\n return hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n } catch (error) {\n throw new CryptoError(\"Failed to stretch key\", error);\n }\n}\n\n/**\n * Hash data with salt using SHA-256\n * Use case: Creating deterministic identifiers\n *\n * @param data - The data to hash\n * @param salt - Salt value for additional entropy\n * @returns Hex-encoded hash\n */\nexport async function hashWithSalt(\n data: string,\n salt: string\n): Promise<string> {\n try {\n const combined = data + salt;\n return await sha256Hash(combined);\n } catch (error) {\n throw new CryptoError(\"Failed to hash with salt\", error);\n }\n}\n\n/**\n * Hash data multiple times (key stretching)\n * Use case: Making brute-force attacks impractical\n *\n * @param data - The data to hash\n * @param salt - Salt value to prevent rainbow table attacks\n * @param iterations - Number of hash iterations\n * @returns Hex-encoded hash after multiple iterations\n */\nexport async function iterativeHash(\n data: string,\n salt: string,\n iterations: number\n): Promise<string> {\n try {\n if (iterations < 1) {\n throw new Error(\"Iterations must be at least 1\");\n }\n\n // Initial hash with salt\n let hash = await hashWithSalt(data, salt);\n\n // Iteratively hash the result\n for (let i = 1; i < iterations; i++) {\n hash = await sha256Hash(hash);\n }\n\n return hash;\n } catch (error) {\n throw new CryptoError(\"Failed to perform iterative 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"],"mappings":"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","names":["Web3PasskeyError","message","code","originalError","CryptoError","Web3PasskeyError","message","originalError","generateBlinding","buffer","bufferToBigInt","result","i","bigIntToBuffer","value","byteLength","temp","sha256Hash","data","hashBuffer","b","error","CryptoError","stretchKey","input","salt","iterations","keyLength","encoder","inputBuffer","saltBuffer","keyMaterial","derivedBits","hashWithSalt","combined","iterativeHash","hash","buildMerkleTree","leaves","poseidon","tree","currentLevel","leaf","nextLevel","hashResult","n","generateMerkleProof","leafIndex","pathIndices","pathElements","currentIndex","level","isRightNode","siblingIndex","validateProofInputs","inputs","key","hexToBigInt","hex","bigIntToHex","padToBytes","serializeProof","proof","deserializeProof","serialized","generateNonce","isValidAddress","address","buildNFTHoldersMerkleTree","holderAddresses","contractAddress","contractHash","holderLeaves","cleanAddress","addressHash","root","generateNFTOwnershipProofInputs","ownerAddress","allHolderAddresses","minBalance","holderIndex","validateNFTOwnershipProofInputs"]}