Threat Model
What ZKMix protects against and its limitations
Threat Model
Understanding what ZKMix does and does not protect against is essential for users who depend on it for financial privacy. No privacy system is perfect, and ZKMix is no exception. This page provides a comprehensive threat model that describes the protections offered, the known limitations, and practical recommendations for maximizing privacy.
What ZKMix Protects Against
Transaction Linkability
Protection level: Strong
The primary goal of ZKMix is to break the on-chain link between a deposit address and a withdrawal address. When a user deposits 1 SOL from Address A and later withdraws 1 SOL to Address B, an on-chain observer cannot determine that these two transactions are related.
This protection is provided by the zero-knowledge proof system. The withdrawal proof demonstrates that the withdrawer knows the secret corresponding to some deposit in the pool, without revealing which deposit. From the blockchain's perspective, the withdrawal could correspond to any of the deposits in the anonymity set.
The strength of this protection is proportional to the anonymity set size. A pool with 10,000 deposits provides much stronger unlinkability than a pool with 100 deposits, because there are more candidate deposits that the withdrawal could correspond to.
Deposit Amount Privacy
Protection level: Partial (by design)
Because all deposits in a given pool are the same denomination, an observer cannot distinguish deposits within a pool based on amount. However, the denomination itself is public -- an observer can see that a deposit of 1 SOL was made. The privacy comes from the fact that all 1 SOL deposits look identical, not from hiding the amount.
Withdrawal Recipient Privacy
Protection level: Strong (with relayer)
When a relayer submits the withdrawal transaction, the recipient address appears in the transaction but is not linked to the depositor. The relayer is the transaction signer, not the recipient. An on-chain observer sees that the relayer submitted a withdrawal to Address B, but cannot determine who requested it or which deposit is being claimed.
Without a relayer, the entity signing the withdrawal transaction may be linkable to the recipient, depending on how the signer obtained SOL for gas fees.
Double-Spend Prevention
Protection level: Absolute
Each deposit can only be withdrawn exactly once. The nullifier hash, derived deterministically from the deposit's secret nullifier value, is recorded on-chain during withdrawal. Any subsequent attempt to use the same nullifier is rejected by the program. This guarantee is enforced at the protocol level and cannot be circumvented.
What ZKMix Does NOT Protect Against
Timing Analysis
Protection level: Weak
If a user deposits and withdraws within a short time window (e.g., deposit at 2:00 PM, withdraw at 2:05 PM), and few other deposits and withdrawals occur during that window, an observer can narrow down the likely correspondence based on timing alone.
Example attack scenario: An observer monitors the SOL-1 pool and sees one deposit at 14:00:00 and one withdrawal at 14:03:22, with no other activity in between. The observer can reasonably conclude these are linked, despite the zero-knowledge proof providing on-chain unlinkability.
Mitigation: Wait a significant amount of time between deposit and withdrawal. The longer you wait, and the more deposits that accumulate in the pool during the waiting period, the larger your effective anonymity set becomes. We recommend waiting at least 24 hours and ideally several days or more.
Amount Correlation Within the Same Denomination
Protection level: None
If a user deposits 5 times into the SOL-1 pool and later withdraws 5 times to the same address, an observer can see that some entity deposited 5 SOL and some entity withdrew 5 SOL. While the observer cannot prove these are the same entity using on-chain data alone, the correlation is suggestive, especially if the timing is close.
Mitigation: Withdraw to different addresses rather than consolidating all withdrawals to a single address. Add random delays between withdrawals. Consider splitting deposits across different time periods.
IP Address Tracking
Protection level: None
ZKMix operates at the blockchain layer and does not provide network-layer privacy. When a user submits a deposit transaction or communicates with a relayer, their IP address is visible to the RPC provider, the relayer operator, and potentially network observers.
An RPC provider that logs requests could correlate the IP address that submitted a deposit with the IP address that later submitted a withdrawal (or contacted a relayer). This is particularly dangerous if the user uses the same RPC provider for both operations.
Mitigation: Use Tor or a VPN when interacting with ZKMix. Use different RPC providers for deposit and withdrawal. Run your own Solana RPC node.
Chain Analysis Heuristics
Protection level: Varies
Sophisticated blockchain analysis firms use heuristics beyond simple transaction tracing. These can include:
- Gas source analysis: Tracing where the recipient's initial SOL balance came from (mitigated by using a relayer).
- Wallet fingerprinting: Identifying wallet software patterns, transaction timing patterns, or compute budget settings that are consistent between deposit and withdrawal transactions.
- Multi-denomination correlation: If a user deposits 1 SOL to the SOL-1 pool and 0.1 SOL to the SOL-0.1 pool in the same transaction or block, and later withdraws from both pools in close succession, the deposits can be linked through temporal clustering.
- Change output analysis: Less relevant on Solana (which uses an account model), but the pattern of token account creations and closures can provide fingerprinting information.
Mitigation: Use a single denomination per session. Do not combine mixer operations with other identifiable on-chain activity in the same transaction or time window.
Compromised User Device
Protection level: None
If the user's device is compromised (malware, keylogger, screen capture), the secret and nullifier values can be exfiltrated, allowing an attacker to link the deposit and withdrawal. ZKMix cannot protect against endpoint compromise.
Mitigation: Use a secure, up-to-date device. Consider using a hardware wallet for signing (though the secret and nullifier are generated in software, not on the hardware wallet).
Regulatory and Legal Compulsion
Protection level: None
ZKMix provides technical privacy but does not provide legal protection. If a user is compelled by law to disclose their deposit note or transaction history, the zero-knowledge proof system does not help. The deposit note directly reveals the link between deposit and withdrawal.
Front-Running and Sandwich Attacks
Protection level: Strong
The recipient address is a public input to the zero-knowledge proof. An attacker who observes a pending withdrawal transaction cannot change the recipient to steal the funds, because the proof is only valid for the specified recipient. This binding prevents front-running attacks.
Known Limitations
Anonymity Set Size Dependency
The privacy provided by ZKMix is only as strong as the anonymity set. New or unpopular pools with few deposits provide minimal privacy. Users should check the anonymity set size before depositing and prefer pools with at least 1,000 deposits.
Deterministic Nullifier Derivation
Each deposit produces exactly one nullifier hash. If an attacker knows the secret and nullifier (e.g., from a stolen deposit note), they can compute the nullifier hash and identify the withdrawal transaction on-chain. Secure storage of the deposit note is the user's responsibility.
Merkle Tree Capacity
Each pool's Merkle tree has a finite capacity (2^20 = 1,048,576 deposits for a depth-20 tree). Once full, no more deposits can be accepted. This is a technical limitation, not a security limitation, but it means pools may eventually need to be replaced with new instances.
Trusted Setup Dependency
ZKMix uses Groth16, which requires a trusted setup ceremony. If the toxic waste from the ceremony is not properly destroyed, it could be used to forge proofs -- effectively creating counterfeit withdrawals. See Trusted Setup for details on how ZKMix mitigates this risk through multi-party computation.
Recommendations for Users
Basic Privacy Hygiene
- Use a relayer for all withdrawals. Never fund a fresh recipient address from a known address before withdrawing.
- Wait at least 24 hours between deposit and withdrawal. Longer is better.
- Do not withdraw all deposits to the same address. Use a different fresh address for each withdrawal.
- Use Tor or a VPN when interacting with ZKMix, especially when communicating with relayers.
Advanced Privacy Practices
- Use different RPC endpoints for deposit and withdrawal transactions. Better yet, run your own Solana validator or RPC node.
- Randomize withdrawal timing. Do not withdraw at predictable intervals. Add random delays of hours or days.
- Avoid multi-denomination correlation. If you use multiple pool denominations, space out the deposits and withdrawals across days or weeks.
- Do not interact with ZKMix from an address that has been KYC'd (e.g., a centralized exchange withdrawal address). Create a fresh address, fund it through an intermediate step, and then deposit from that address.
- Clear browser data between deposit and withdrawal sessions if using a web interface, to prevent cookie-based or localStorage-based tracking.
- Verify the frontend. If using a web interface, verify that the site is the official ZKMix frontend by checking the URL, TLS certificate, and ideally the source code hash.
What to Do If Your Deposit Note Is Compromised
If you believe your deposit note has been exposed:
- Withdraw immediately to a fresh address. A compromised note does not allow an attacker to steal funds (the note does not contain a private key), but it does allow them to deanonymize the link between your deposit and withdrawal.
- If funds have not been withdrawn yet, the attacker knows which deposit is yours but cannot claim the funds. Only you (or anyone with the note) can generate a valid withdrawal proof.
- If you and the attacker both have the note, the first valid withdrawal wins. The nullifier can only be spent once.