{"_id":"@cheny56/zk-confidential-offchain","name":"@cheny56/zk-confidential-offchain","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@cheny56/zk-confidential-offchain","version":"1.0.0","description":"Confidential smart contracts using ZK proofs - Off-chain proof generation with snarkjs/Circom. Works on ANY EVM chain.","main":"lib/index.js","types":"lib/index.d.ts","exports":{".":{"require":"./lib/index.js","types":"./lib/index.d.ts"},"./lib":{"require":"./lib/index.js","types":"./lib/index.d.ts"}},"scripts":{"test":"node examples/verify-setup.js","example:balance":"node examples/basic-balance.js","example:transfer":"node examples/transfer-simulation.js","circuits:compile":"bash scripts/compile-circuits.sh","circuits:setup":"bash scripts/trusted-setup.sh","contracts:compile":"npx hardhat compile"},"keywords":["zk","zero-knowledge","zkp","snark","groth16","privacy","confidential","token","ethereum","solidity","circom","snarkjs","poseidon","merkle-tree"],"author":{"name":"cheny56"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/cheny56/zk-confidential-offchain.git"},"homepage":"https://github.com/cheny56/zk-confidential-offchain#readme","bugs":{"url":"https://github.com/cheny56/zk-confidential-offchain/issues"},"dependencies":{"circomlibjs":"^0.1.7"},"devDependencies":{"circomlib":"^2.0.5","snarkjs":"^0.7.3","hardhat":"^2.19.0","@nomicfoundation/hardhat-toolbox":"^4.0.0"},"peerDependencies":{"ethers":"^6.0.0"},"engines":{"node":">=18.0.0"},"directories":{"example":"examples","lib":"lib"},"_id":"@cheny56/zk-confidential-offchain@1.0.0","gitHead":"5aef9ba68d7f501d9ddc5b7d7da2339bebf1c6bd","_nodeVersion":"22.21.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-WFrpaPCt1hqfIgocjoTtKLJ496mJIukwL4iF2Ads9O6V3JuQkVCU9tXRZZAWObM82917QzPHvxzYMtSaWpW1xA==","shasum":"44c4326bdc658e8311cbbc2906e36d8ebd22af5d","tarball":"https://registry.npmjs.org/@cheny56/zk-confidential-offchain/-/zk-confidential-offchain-1.0.0.tgz","fileCount":16,"unpackedSize":88436,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIB0a19qZgzTotmq2jON3/QHwFvmf5qLNTXymqgaWwosCAiEAkfL3DqG4FHW3Q0loFJpas/b6nKy4OYmY4Dh2bD4iTNU="}]},"_npmUser":{"name":"cheny56","email":"cheny5dyh@gmail.com"},"maintainers":[{"name":"cheny56","email":"cheny5dyh@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/zk-confidential-offchain_1.0.0_1768989176692_0.587015141966525"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-21T09:52:56.639Z","1.0.0":"2026-01-21T09:52:56.840Z","modified":"2026-01-21T09:52:57.535Z"},"maintainers":[{"name":"cheny56","email":"cheny5dyh@gmail.com"}],"description":"Confidential smart contracts using ZK proofs - Off-chain proof generation with snarkjs/Circom. Works on ANY EVM chain.","homepage":"https://github.com/cheny56/zk-confidential-offchain#readme","keywords":["zk","zero-knowledge","zkp","snark","groth16","privacy","confidential","token","ethereum","solidity","circom","snarkjs","poseidon","merkle-tree"],"repository":{"type":"git","url":"git+https://github.com/cheny56/zk-confidential-offchain.git"},"author":{"name":"cheny56"},"bugs":{"url":"https://github.com/cheny56/zk-confidential-offchain/issues"},"license":"MIT","readme":"# @cheny56/zk-confidential-offchain\n\n**Confidential Smart Contracts using Zero-Knowledge Proofs (Off-Chain Verification)**\n\nA privacy-preserving token system where:\n- ✅ **Inputs are private** - Transfer amounts are hidden\n- ✅ **State is hidden** - Balances stored as commitments  \n- ✅ **Only proofs are public** - ZK proofs verify correctness without revealing data\n\nThis package uses **snarkjs/Circom** for proof generation and works on **ANY EVM chain**.\n\n[![npm version](https://img.shields.io/npm/v/@cheny56/zk-confidential-offchain.svg)](https://www.npmjs.com/package/@cheny56/zk-confidential-offchain)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Features\n\n- 🌐 **Any EVM Chain** - Works on Ethereum, Polygon, BSC, Quorum, etc.\n- 🌍 **Browser Compatible** - Proofs can be generated in web browsers\n- 🔒 **Full Privacy** - Balances, transfers, identities all hidden\n- 📦 **Self-Contained** - No external dependencies on special nodes\n- 🛠️ **Customizable** - Modify Circom circuits as needed\n\n## Installation\n\n```bash\nnpm install @cheny56/zk-confidential-offchain\n```\n\n## Quick Start\n\n```javascript\nconst { \n    NoteWallet, \n    Note, \n    MerkleTree,\n    poseidonHash \n} = require('@cheny56/zk-confidential-offchain');\n\n// Create a wallet\nconst wallet = new NoteWallet();\nawait wallet.init();\n\n// Create a private note (hidden balance)\nconst note = await wallet.createNote(1000n);\nconsole.log('Commitment:', note.getCommitmentHex());\n\n// Check balance (only you know this)\nconsole.log('Balance:', wallet.getBalance());\n```\n\n## Table of Contents\n\n- [How It Works](#how-it-works)\n- [Core Concepts](#core-concepts)\n- [API Reference](#api-reference)\n- [Step-by-Step Guide](#step-by-step-guide)\n- [Examples](#examples)\n- [Circuit Compilation](#circuit-compilation)\n- [Contract Deployment](#contract-deployment)\n- [Security Considerations](#security-considerations)\n\n## How It Works\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         CONFIDENTIAL TOKEN FLOW                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                         │\n│  DEPOSIT (Public ETH → Private Balance)                                 │\n│  ┌────────────┐     ┌────────────┐     ┌────────────────────────┐      │\n│  │ ETH        │ --> │ ZK Proof   │ --> │ Commitment stored      │      │\n│  │ (public)   │     │ (snarkjs)  │     │ in Merkle tree         │      │\n│  └────────────┘     └────────────┘     └────────────────────────┘      │\n│                                                                         │\n│  TRANSFER (Private → Private)                                           │\n│  ┌────────────────────────────────────────────────────────────────┐    │\n│  │  Sender creates proof showing:                                  │    │\n│  │    1. They own the input note (know secret)                     │    │\n│  │    2. Input note exists in Merkle tree                         │    │\n│  │    3. Input value = Output values (conservation)               │    │\n│  │    4. Nullifier prevents double-spending                        │    │\n│  │                                                                 │    │\n│  │  Public: nullifier, new commitments                            │    │\n│  │  Hidden: sender, recipient, amounts                            │    │\n│  └────────────────────────────────────────────────────────────────┘    │\n│                                                                         │\n│  WITHDRAW (Private Balance → Public ETH)                                │\n│  ┌────────────┐     ┌────────────┐     ┌────────────────────────┐      │\n│  │ Commitment │ --> │ ZK Proof   │ --> │ ETH sent to            │      │\n│  │ (private)  │     │            │     │ recipient (public)     │      │\n│  └────────────┘     └────────────┘     └────────────────────────┘      │\n│                                                                         │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n## Core Concepts\n\n### Note\n\nA **Note** is a private balance unit (like a UTXO):\n\n```javascript\nNote = {\n    value: 1000,           // Hidden amount\n    ownerSecret: 0x...,    // Only owner knows this\n    nonce: 0x...,          // Random value\n    commitment: Hash(value, ownerSecret, nonce)  // Public\n}\n```\n\n### Commitment\n\nA **Commitment** hides the note's contents:\n- `commitment = Poseidon(value, ownerSecret, nonce)`\n- Anyone can see the commitment\n- Nobody can determine value or owner from it\n\n### Nullifier\n\nA **Nullifier** prevents double-spending:\n- `nullifier = Poseidon(commitment, ownerSecret, leafIndex)`\n- Revealed when spending a note\n- Can't be linked back to the commitment\n\n### Merkle Tree\n\nAll commitments are stored in a **Merkle Tree**:\n- Efficient membership proofs (O(log n))\n- ZK-friendly with Poseidon hash\n\n## API Reference\n\n### NoteWallet\n\n```javascript\nconst { NoteWallet } = require('@cheny56/zk-confidential-offchain');\n\nconst wallet = new NoteWallet();\nawait wallet.init();\n\n// Create a note\nconst note = await wallet.createNote(amount);\n\n// Get balance\nconst balance = wallet.getBalance();\n\n// Get spendable notes\nconst notes = wallet.getSpendableNotes();\n\n// Select notes for transfer\nconst selected = wallet.selectNotesForAmount(amount);\n\n// Export for backup\nconst backup = wallet.toJSON();\n\n// Restore from backup\nconst restored = NoteWallet.fromJSON(backup);\n```\n\n### Note\n\n```javascript\nconst { Note } = require('@cheny56/zk-confidential-offchain');\n\n// Create manually\nconst note = new Note(value, ownerSecret, nonce);\n\n// Get commitment\nconst commitment = note.getCommitmentHex();\n\n// Get nullifier (after tree insertion)\nconst nullifier = note.getNullifierHex();\n\n// Check if spendable\nconst canSpend = note.canSpend();\n\n// Get private inputs for ZK proof\nconst inputs = note.getPrivateInputs();\n```\n\n### MerkleTree\n\n```javascript\nconst { MerkleTree } = require('@cheny56/zk-confidential-offchain');\n\nconst tree = new MerkleTree(20); // depth 20\nawait tree.init();\n\n// Insert commitment\nconst index = await tree.insert(commitment);\n\n// Get root\nconst root = tree.getRoot();\n\n// Generate proof\nconst { path, indices } = await tree.generateProof(index);\n\n// Verify proof\nconst valid = MerkleTree.verifyProof(leaf, index, path, indices, root);\n```\n\n### Poseidon Hash\n\n```javascript\nconst { poseidonHash, toHex32 } = require('@cheny56/zk-confidential-offchain');\n\n// Hash values\nconst hash = await poseidonHash(value1, value2, value3);\nconsole.log(toHex32(hash));\n```\n\n## Step-by-Step Guide\n\n### Step 1: Install and Initialize\n\n```bash\n# Create project\nmkdir my-confidential-app\ncd my-confidential-app\nnpm init -y\n\n# Install package\nnpm install @cheny56/zk-confidential-offchain\n```\n\n### Step 2: Create a Wallet\n\n```javascript\nconst { NoteWallet } = require('@cheny56/zk-confidential-offchain');\n\nasync function main() {\n    // Create wallet\n    const wallet = new NoteWallet();\n    await wallet.init();\n    \n    console.log('Wallet created!');\n    console.log('Master secret (KEEP SAFE):', wallet.getMasterSecretHex());\n}\n\nmain();\n```\n\n### Step 3: Create Notes (Private Balances)\n\n```javascript\n// Create notes representing private balances\nconst note1 = await wallet.createNote(1000n);\nconst note2 = await wallet.createNote(500n);\nconst note3 = await wallet.createNote(250n);\n\nconsole.log('Created notes:');\nconsole.log('  Note 1:', note1.value, '→', note1.getCommitmentHex().slice(0, 20) + '...');\nconsole.log('  Note 2:', note2.value, '→', note2.getCommitmentHex().slice(0, 20) + '...');\nconsole.log('  Note 3:', note3.value, '→', note3.getCommitmentHex().slice(0, 20) + '...');\n\nconsole.log('Total balance:', wallet.getBalance());\n```\n\n### Step 4: Insert into Merkle Tree\n\n```javascript\nconst { MerkleTree } = require('@cheny56/zk-confidential-offchain');\n\nconst tree = new MerkleTree(20);\nawait tree.init();\n\n// Insert notes (simulates on-chain deposit)\nfor (const note of wallet.getSpendableNotes()) {\n    const index = await tree.insert(note.commitment);\n    const { path, indices } = await tree.generateProof(index);\n    note.setTreePosition(index, tree.getRoot(), path, indices);\n    console.log(`Inserted note at index ${index}`);\n}\n\nconsole.log('Merkle root:', tree.getRootHex());\n```\n\n### Step 5: Generate Transfer Inputs\n\n```javascript\n// Select notes to spend\nconst amountToSend = 300n;\nconst notesToSpend = wallet.selectNotesForAmount(amountToSend);\n\n// Get private inputs for ZK proof\nfor (const note of notesToSpend) {\n    const inputs = note.getPrivateInputs();\n    console.log('Private inputs:', inputs);\n}\n```\n\n### Step 6: Verify Your Setup\n\n```bash\n# Run the verification example\nnode examples/verify-setup.js\n```\n\n## Examples\n\n### Basic Balance Management\n\n```javascript\n// examples/basic-balance.js\nconst { NoteWallet, MerkleTree, toHex32 } = require('@cheny56/zk-confidential-offchain');\n\nasync function main() {\n    console.log('=== Private Balance Management ===\\n');\n    \n    // 1. Create wallet\n    const wallet = new NoteWallet();\n    await wallet.init();\n    \n    // 2. Create Merkle tree\n    const tree = new MerkleTree(20);\n    await tree.init();\n    \n    // 3. Create notes\n    const amounts = [1000n, 500n, 250n];\n    for (const amount of amounts) {\n        const note = await wallet.createNote(amount);\n        const index = await tree.insert(note.commitment);\n        const { path, indices } = await tree.generateProof(index);\n        note.setTreePosition(index, tree.getRoot(), path, indices);\n        console.log(`Created note: ${amount} → ${note.getCommitmentHex().slice(0, 30)}...`);\n    }\n    \n    // 4. Check balance\n    console.log(`\\nTotal private balance: ${wallet.getBalance()}`);\n    console.log(`Spendable notes: ${wallet.getSpendableNotes().length}`);\n    \n    // 5. Select for transfer\n    const selected = wallet.selectNotesForAmount(600n);\n    console.log(`\\nTo send 600, would spend ${selected.length} notes totaling ${selected.reduce((s, n) => s + n.value, 0n)}`);\n}\n\nmain().catch(console.error);\n```\n\n### Transfer Simulation\n\n```javascript\n// examples/transfer-simulation.js\nconst { NoteWallet, Note, MerkleTree, toHex32, generateOwnerSecret } = require('@cheny56/zk-confidential-offchain');\n\nasync function main() {\n    console.log('=== Private Transfer Simulation ===\\n');\n    \n    // Alice's wallet\n    const aliceWallet = new NoteWallet();\n    await aliceWallet.init();\n    \n    // Bob's receiving secret\n    const bobSecret = generateOwnerSecret();\n    \n    // Shared Merkle tree (on-chain)\n    const tree = new MerkleTree(20);\n    await tree.init();\n    \n    // Alice deposits 1000\n    console.log('1. Alice deposits 1000');\n    const aliceNote = await aliceWallet.createNote(1000n);\n    const aliceIndex = await tree.insert(aliceNote.commitment);\n    const aliceProof = await tree.generateProof(aliceIndex);\n    aliceNote.setTreePosition(aliceIndex, tree.getRoot(), aliceProof.path, aliceProof.indices);\n    console.log(`   Commitment: ${aliceNote.getCommitmentHex().slice(0, 30)}...`);\n    \n    // Alice transfers 300 to Bob\n    console.log('\\n2. Alice transfers 300 to Bob');\n    \n    // Create Bob's note\n    const bobNote = new Note(300n, bobSecret);\n    console.log(`   Bob's commitment: ${bobNote.getCommitmentHex().slice(0, 30)}...`);\n    \n    // Create Alice's change note\n    const aliceChangeNote = await aliceWallet.createNote(700n);\n    console.log(`   Alice's change: ${aliceChangeNote.getCommitmentHex().slice(0, 30)}...`);\n    \n    // Compute nullifier (prevents double-spend)\n    const nullifier = aliceNote.getNullifierHex();\n    console.log(`   Nullifier: ${nullifier.slice(0, 30)}...`);\n    \n    // Mark Alice's original note as spent\n    aliceNote.markSpent();\n    \n    // Insert new notes into tree\n    const bobIndex = await tree.insert(bobNote.commitment);\n    const changeIndex = await tree.insert(aliceChangeNote.commitment);\n    \n    // Update positions\n    const bobProof = await tree.generateProof(bobIndex);\n    bobNote.setTreePosition(bobIndex, tree.getRoot(), bobProof.path, bobProof.indices);\n    \n    const changeProof = await tree.generateProof(changeIndex);\n    aliceChangeNote.setTreePosition(changeIndex, tree.getRoot(), changeProof.path, changeProof.indices);\n    \n    // Final state\n    console.log('\\n3. Final State');\n    console.log(`   Alice's balance: ${aliceWallet.getBalance()}`);\n    console.log(`   Bob's note value: ${bobNote.value}`);\n    console.log(`   Merkle root: ${tree.getRootHex().slice(0, 30)}...`);\n    \n    // Privacy summary\n    console.log('\\n4. Privacy Summary');\n    console.log('   PUBLIC: nullifier, new commitments, merkle root');\n    console.log('   HIDDEN: Alice, Bob, 300 transferred, 700 change');\n}\n\nmain().catch(console.error);\n```\n\n## Circuit Compilation\n\nIf you need to customize the circuits:\n\n```bash\n# Install circom globally\nnpm install -g circom snarkjs\n\n# Compile mint circuit\ncircom circuits/mint.circom --r1cs --wasm --sym -o build/\n\n# Compile transfer circuit  \ncircom circuits/transfer.circom --r1cs --wasm --sym -o build/\n\n# Download powers of tau (if needed)\nwget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_12.ptau -O pot12_final.ptau\n\n# Generate proving keys\nsnarkjs groth16 setup build/mint.r1cs pot12_final.ptau build/mint.zkey\nsnarkjs groth16 setup build/transfer.r1cs pot12_final.ptau build/transfer.zkey\n\n# Export Solidity verifiers\nsnarkjs zkey export solidityverifier build/mint.zkey contracts/MintVerifier.sol\nsnarkjs zkey export solidityverifier build/transfer.zkey contracts/TransferVerifier.sol\n```\n\n## Contract Deployment\n\n```javascript\nconst { ethers } = require('ethers');\n\nasync function deploy() {\n    const provider = new ethers.JsonRpcProvider('http://localhost:8545');\n    const wallet = new ethers.Wallet(PRIVATE_KEY, provider);\n    \n    // Deploy MintVerifier\n    const MintVerifier = await ethers.ContractFactory.fromSolidity(\n        require('./artifacts/MintVerifier.json'),\n        wallet\n    );\n    const mintVerifier = await MintVerifier.deploy();\n    \n    // Deploy TransferVerifier\n    const TransferVerifier = await ethers.ContractFactory.fromSolidity(\n        require('./artifacts/TransferVerifier.json'),\n        wallet\n    );\n    const transferVerifier = await TransferVerifier.deploy();\n    \n    // Deploy ConfidentialToken\n    const ConfidentialToken = await ethers.ContractFactory.fromSolidity(\n        require('./artifacts/ConfidentialToken.json'),\n        wallet\n    );\n    const token = await ConfidentialToken.deploy(\n        'Private Token',\n        'PRIV',\n        await mintVerifier.getAddress(),\n        await transferVerifier.getAddress()\n    );\n    \n    console.log('Contracts deployed:');\n    console.log('  MintVerifier:', await mintVerifier.getAddress());\n    console.log('  TransferVerifier:', await transferVerifier.getAddress());\n    console.log('  ConfidentialToken:', await token.getAddress());\n}\n```\n\n## Security Considerations\n\n1. **Backup Your Wallet**: Losing your master secret means losing all funds\n2. **Trusted Setup**: The proving keys require a trusted setup ceremony\n3. **Nullifier Tracking**: On-chain nullifier set prevents double-spending\n4. **Gas Costs**: Solidity verification costs ~5M gas per proof\n5. **Timing Attacks**: Consider using a relayer to hide sender address\n\n## Package Contents\n\n```\nzk-confidential-offchain/\n├── lib/\n│   ├── index.js           # Main exports\n│   ├── poseidon.js        # Poseidon hash\n│   ├── merkle.js          # Merkle tree\n│   ├── note.js            # Note management\n│   └── commitment.js      # Commitment utilities\n├── client/\n│   └── confidential-client.js  # Contract interaction\n├── contracts/\n│   ├── ConfidentialToken.sol\n│   ├── CommitmentTree.sol\n│   └── interfaces/\n├── circuits/\n│   ├── mint.circom\n│   └── transfer.circom\n├── examples/\n│   ├── basic-balance.js\n│   ├── transfer-simulation.js\n│   └── verify-setup.js\n├── package.json\n└── README.md\n```\n\n## License\n\nMIT\n\n## Related\n\n- [@cheny56/zk-confidential-onchain](../zk-confidential-onchain) - Native precompile version\n- [@cheny56/zk-voting](../zk-voting) - ZK voting system\n","readmeFilename":"README.md","_rev":"1-8b734d915911680e4abd16b9c76712d4"}