← Back to App

Documentation

Table of Contents

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:

How It Works

1. The Privacy Process

ZK Pulse uses a simple three-step process to provide privacy:

  1. Deposit: You deposit PLS into one of the denomination pools and receive a secret note
  2. Wait: Let time pass and allow others to deposit, increasing your anonymity set
  3. 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:

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:

How to Verify the Hasher Yourself

Method 1: Using Remix IDE

  1. Go to Remix IDE
  2. Create a new file with this interface:
    interface IHasher { function MiMCSponge(uint256 in_xL, uint256 in_xR) external pure returns (uint256 xL, uint256 xR); }
  3. Compile and deploy to "At Address": 0x5Aa1eE340a2E9F199f068DB35a855956429067cf
  4. Call MiMCSponge with inputs (0, 0)
  5. 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:

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: 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:

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:

It has processed billions in value without a single mathematical error or vulnerability.

How to Use

Making a Deposit

  1. Connect Wallet: Click "Connect Wallet" and approve the connection
  2. Select Amount: Choose one of the denomination pools (1M, 10M, 100M, or 1B PLS)
  3. Deposit: Click "Deposit X PLS" and confirm the transaction
  4. 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.
  5. Wait: Allow time to pass (recommended: wait for at least 10 more deposits)

Making a Withdrawal

  1. Switch to Withdraw Tab: Click the "Withdraw" tab at the top
  2. Enter Note: Paste your saved deposit note
  3. 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
  4. Generate Proof: Click "Withdraw" to generate the zero-knowledge proof
  5. Confirm Transaction: Approve the withdrawal transaction in your wallet

Best Practices for Privacy

Security & Privacy

Security Features

Privacy Guarantees

Important Privacy Considerations:

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:

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:

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:

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:

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