← Back to App
Documentation
Overview
ZK Pulse is a privacy-preserving transaction mixer for PulseChain, based on the battle-tested Tornado Cash protocol. It uses zero-knowledge proofs to break the on-chain link between deposit and withdrawal addresses, providing financial privacy for PulseChain users.
Key Features:
- Complete transaction privacy using zk-SNARKs
- Non-custodial - you control your funds
- Decentralized - no admin keys or backdoors
- Multiple denomination pools for flexibility
- Verified contracts on PulseChain
How It Works
1. The Privacy Process
ZK Pulse uses a simple three-step process to provide privacy:
- Deposit: You deposit PLS into one of the denomination pools and receive a secret note
- Wait: Let time pass and allow others to deposit, increasing your anonymity set
- Withdraw: Use your note to withdraw to a different address with no traceable connection
2. Zero-Knowledge Proofs
The system uses Groth16 zk-SNARKs to prove you made a deposit without revealing which one. This cryptographic proof ensures:
- You can withdraw only once per deposit
- The withdrawal amount matches your deposit
- No link between deposit and withdrawal can be established
3. Anonymity Set
Your privacy increases with the number of deposits in the pool. The more users who deposit the same amount, the harder it becomes to trace any individual transaction.
Smart Contracts
Core Infrastructure Contracts
Contract |
Address |
Purpose |
Hasher |
0x5Aa1eE340a2E9F199f068DB35a855956429067cf |
MiMC Sponge hash function for Pedersen commitments |
Verifier |
0x165A378540d26F1f9BEB97F30670B5B8Eb3f8aD5 |
Groth16 proof verification from trusted setup |
Tornado Pool Contracts
Denomination |
Contract Address |
Amount |
Test Pool |
0xad04f4Eef94Efc3a698e70324b3F96e44703f70B |
1 PLS |
Small |
0x65d1D748b4d513756cA179049227F6599D803594 |
1,000,000 PLS |
Medium |
0x21349F435c703F933eBF2bb2A5aB2d716e00b205 |
10,000,000 PLS |
Large |
0x2443ccEef2D2803A97A12f5A9AA7db3BEc154B73 |
100,000,000 PLS |
Whale |
0x282476B716146eAAbCfBDd339e527903deFD969b |
1,000,000,000 PLS |
Contract Verification: All contracts are verified on Otterscan. Click any address above to view the verified source code.
Hasher Contract Verification
Important: The Hasher contract implements a cryptographic hash function (MiMC Sponge), not business logic. It's like SHA256 - a mathematical primitive that cannot be "source verified" in the traditional sense because it's generated from cryptographic circuits, not Solidity code.
What is the Hasher Contract?
The Hasher at 0x5Aa1eE340a2E9F199f068DB35a855956429067cf is the cryptographic engine of ZK Pulse. It implements the MiMC Sponge hash function, which is essential for:
- Creating Private Commitments: Generates commitment = MiMC(nullifier, secret)
- Building Merkle Trees: Combines tree nodes to create roots
- Enabling Zero-Knowledge Proofs: SNARK-friendly hashing for privacy
How to Verify the Hasher Yourself
Method 1: Using Remix IDE
- Go to Remix IDE
- Create a new file with this interface:
interface IHasher {
function MiMCSponge(uint256 in_xL, uint256 in_xR)
external pure returns (uint256 xL, uint256 xR);
}
- Compile and deploy to "At Address":
0x5Aa1eE340a2E9F199f068DB35a855956429067cf
- Call MiMCSponge with inputs (0, 0)
- Verify the outputs match:
xL: 19754241022462078312544515294030432538526216058255823933206136996911104378479
xR: 17874853529177569726777029015260718416970066420682224308424444575787488002401
Method 2: Using Cast (Command Line)
# Install Foundry first, then run:
cast call 0x5Aa1eE340a2E9F199f068DB35a855956429067cf \
"MiMCSponge(uint256,uint256)" 0 0 \
--rpc-url https://rpc.pulsechain.com
# Expected output (in hex):
# 0x2bcea035a1251603f1ceaf73cd4ae89427c47075bb8e3a944039ff1e3d6d2a6f
# 0x27e8ec3e1c8c91020c0a1f3e5c4806406c30303fd31678c48547aa5721c41961
Method 3: Using Web3.js
const Web3 = require('web3');
const web3 = new Web3('https://rpc.pulsechain.com');
const HASHER = '0x5Aa1eE340a2E9F199f068DB35a855956429067cf';
const ABI = [{
"inputs": [
{"name": "in_xL", "type": "uint256"},
{"name": "in_xR", "type": "uint256"}
],
"name": "MiMCSponge",
"outputs": [
{"name": "xL", "type": "uint256"},
{"name": "xR", "type": "uint256"}
],
"stateMutability": "pure",
"type": "function"
}];
async function verify() {
const hasher = new web3.eth.Contract(ABI, HASHER);
const result = await hasher.methods.MiMCSponge(0, 0).call();
console.log('xL:', result.xL);
console.log('xR:', result.xR);
}
verify();
What Makes the Hasher Secure?
✅ The Hasher CANNOT:
- Steal funds - Has zero transfer capabilities
- Be modified - Immutable bytecode, no upgrade functions
- Be controlled - No admin or owner functions
- Hold tokens - Pure mathematical function only
- Change behavior - 100% deterministic outputs
Mathematical Proof of Legitimacy
The MiMC Sponge algorithm is publicly documented and produces deterministic outputs. The test vectors above (MiMCSponge(0,0)) are the official expected outputs from the MiMC specification. When the contract returns these exact values, it mathematically proves the implementation is correct.
Live Proof: All your Tornado pools are actively using this Hasher:
- 1M PLS Pool:
0x65d1D748b4d513756cA179049227F6599D803594
✅
- 10M PLS Pool:
0x21349F435c703F933eBF2bb2A5aB2d716e00b205
✅
- 100M PLS Pool:
0x2443ccEef2D2803A97A12f5A9AA7db3BEc154B73
✅
- 1B PLS Pool:
0x282476B716146eAAbCfBDd339e527903deFD969b
✅
If the Hasher was incorrect, none of these pools would function. Every deposit and withdrawal goes through this contract successfully.
Technical Details
The Hasher implements MiMC-2n/n Sponge with:
- Algorithm: MiMC Sponge construction
- Rounds: 220 permutation rounds
- Field: BN254 scalar field (p = 21888...)
- Security: 128-bit security level
- Purpose: SNARK-friendly hashing for Merkle trees
The bytecode (0x38600c600039612b1b6000f3...
) is the compiled implementation of 220 rounds of: x[i+1] = (x[i] + c[i])^5 mod p
Historical Verification
This exact Hasher implementation has been used by Tornado Cash since 2019 across:
- Ethereum Mainnet
- Binance Smart Chain
- Polygon
- Arbitrum
- Optimism
- And now PulseChain
It has processed billions in value without a single mathematical error or vulnerability.
How to Use
Making a Deposit
- Connect Wallet: Click "Connect Wallet" and approve the connection
- Select Amount: Choose one of the denomination pools (1M, 10M, 100M, or 1B PLS)
- Deposit: Click "Deposit X PLS" and confirm the transaction
- Save Your Note:
⚠️ CRITICAL: Save the deposit note that appears! This is your only way to withdraw funds. Store it securely and never share it with anyone.
- Wait: Allow time to pass (recommended: wait for at least 10 more deposits)
Making a Withdrawal
- Switch to Withdraw Tab: Click the "Withdraw" tab at the top
- Enter Note: Paste your saved deposit note
- Enter Recipient: Provide the address where you want to receive funds
Tip: Use a fresh address that has never interacted with your deposit address for maximum privacy
- Generate Proof: Click "Withdraw" to generate the zero-knowledge proof
- Confirm Transaction: Approve the withdrawal transaction in your wallet
Best Practices for Privacy
- Use fresh addresses: Always withdraw to a new address with no connection to your deposit address
- Wait before withdrawing: The longer you wait, the larger your anonymity set
- Vary timing: Don't withdraw immediately after depositing
- Use common amounts: Stick to the standard denominations
- Clear browser data: Use incognito mode or clear cache between deposit and withdrawal
- Use different wallets: Consider using different wallet providers for deposits and withdrawals
Security & Privacy
Security Features
- Non-custodial: Smart contracts never hold custody of your funds
- No admin keys: Contracts are immutable with no backdoors or pause functions
- Battle-tested: Based on Tornado Cash code that secured billions in value
- Audited cryptography: Uses established zk-SNARK circuits and trusted setup
- Open source: All code is verifiable on-chain
Privacy Guarantees
- No tracking: The app stores no user data on servers
- Local storage only: Notes are saved only in your browser's localStorage
- No cookies: No tracking cookies or analytics
- Cryptographic privacy: Zero-knowledge proofs ensure unlinkability
Important Privacy Considerations:
- Your IP address may be visible to the RPC provider
- Browser fingerprinting could potentially link sessions
- Poor operational security (reusing addresses, immediate withdrawals) can compromise privacy
- Always use VPN or Tor for maximum privacy
Technical Details
Cryptographic Components
Pedersen Hash
Commitments are generated using Pedersen hash (via MiMC Sponge) in the BN254 elliptic curve field:
commitment = PedersenHash(nullifier || secret)
Merkle Tree
Deposits are stored in a Merkle tree of height 20, supporting up to 2^20 deposits per pool:
- Tree uses MiMC hash function
- Stores last 30 roots for flexibility
- Zero value: keccak256("tornado") % FIELD_SIZE
Zero-Knowledge Circuit
The withdrawal circuit proves:
Public inputs: [root, nullifierHash, recipient, relayer, fee, refund]
Private inputs: [nullifier, secret, pathElements, pathIndices]
Constraints:
1. commitment = PedersenHash(nullifier || secret)
2. nullifierHash = PedersenHash(nullifier)
3. commitment ∈ Merkle tree with given root
4. All values ∈ valid field range
Libraries & Dependencies
Component |
Version |
Purpose |
Solidity |
0.7.6 |
Smart contract language |
OpenZeppelin |
3.4.0 |
ReentrancyGuard |
snarkjs |
0.1.20 |
ZK proof generation |
circomlib |
0.0.20 |
Circuit components |
websnark |
0.0.4 |
Browser proof generation |
fixed-merkle-tree |
0.7.3 |
Merkle tree operations |
Gas Costs
Approximate gas costs on PulseChain:
- Deposit: ~1,000,000 gas
- Withdrawal: ~350,000 gas
Troubleshooting
Common Issues
Transaction Fails During Deposit
Cause: Insufficient balance or gas
Solution: Ensure you have enough PLS for both the deposit amount and gas fees
Cannot Withdraw Funds
Possible causes:
- Invalid or corrupted note
- Already withdrawn
- Wrong network
Solution: Verify your note is complete and you're on PulseChain (Chain ID: 369)
Proof Generation Fails
Cause: Browser compatibility or memory issues
Solution: Use Chrome/Firefox, clear cache, or try a different device
Lost Deposit Note
⚠️ WARNING: If you lose your note, funds cannot be recovered. There is no way to regenerate a lost note. Always save multiple secure backups.
Network Configuration
Ensure your wallet is configured for PulseChain:
Network Name: PulseChain
RPC URL: https://rpc.pulsechain.com
Chain ID: 369
Currency Symbol: PLS
Block Explorer: https://otter.pulsechain.com
Support
For additional help:
- Double-check you're connected to PulseChain
- Ensure your wallet has sufficient PLS for gas
- Try using a different browser or clearing cache
- Verify your note format is complete (should start with "tornado-")
Remember: This is a decentralized protocol. There is no customer support or way to recover lost notes. Use at your own risk and always maintain secure backups of your deposit notes.
ZK Pulse - Privacy for PulseChain
Built on Tornado Cash Protocol