A secure, anonymous, and scalable peer-to-peer token exchange system powered by zkSNARK proofs and on-chain withdrawal rights management.
Build a privacy-preserving P2P exchange (e.g., USDT) that protects users from tracking, using zkSNARK-based zero-knowledge proofs and Merkle tree commitments.
| Component | Purpose |
|---|---|
| P2PManager.sol | Smart contract managing deposits, withdrawals, and P2P requests |
| verifier.sol | Verifies zkSNARK proofs generated on the client side |
| Merkle Tree | Commitments tree (Poseidon hash) stored on-chain |
| zk-Circuit | Groth16 proof system verifying nullifier, secret, recipient |
| CLI Tools | Scripts for deposit, requestWithdraw, and withdraw |
| note.json | Stores note details: nullifier, secret, amount, commitment, root |
The Groth16 zkSNARK scheme ensures:
- The user knows the nullifier and secret for an existing commitment
- The note has not been used (
nullifierHashunused) - The note belongs to the current Merkle root
- The recipient can be chosen freely
👉 All without revealing the nullifier, secret, amount, or sender.
- User generates a note
{nullifier, secret} - Creates a commitment:
Poseidon(nullifier, secret) - Calls
P2PManager.deposit(commitment, amount) - Commitment is added to Merkle tree and tokens deposited
- 📝 Note saved in JSON, shareable via private channel
- Send the note to a buyer via Session, QR, or messenger
- Buyer pays in fiat, USDT, or another method
requestWithdraw(commitment, recipientAddress)- Locks withdrawal rights for a recipient
- Includes expiration (
expiresAt) for automatic release if unpaid
-
Buyer generates Merkle proof + zkSNARK proof
-
Calls
withdraw()with proof, root, nullifierHash, recipient -
Contract:
- Verifies proof via
verifier.sol - Ensures note not spent before
- Checks reservation (recipient, expiresAt) if set
- Sends tokens to recipient
- Marks nullifierHash as spent
- Verifies proof via
| Fraud Attempt | Protection |
|---|---|
| Double-spending a note | nullifierHash valid only once |
| Linking deposit to withdrawal | zkSNARK hides all details |
| Seller attempts to withdraw note | requestWithdraw() locks recipient |
| Buyer reserves note but doesn’t pay | expiresAt auto-expires reservation |
cd circuits/
snarkjs groth16 setup mixer.r1cs pot12_final.ptau mixer.zkey
snarkjs zkey export verificationkey mixer.zkey verification_key.json
snarkjs zkey export solidityverifier mixer.zkey verifier.solforge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcastts-node cli/deposit.tsts-node cli/requestWithdraw.ts note.json recipient_addressts-node cli/withdraw.ts note.jsonp2p-mixer/
├── contracts/
│ ├── P2PManager.sol
│ └── verifier.sol
├── circuits/
│ └── mixer.circom
├── cli/
│ ├── deposit.ts
│ ├── requestWithdraw.ts
│ └── withdraw.ts
├── notes/
│ └── note_<timestamp>.json
├── test/
│ └── P2P.t.sol
└── README.md
| Feature | Status |
|---|---|
| 🧾 Note encryption (PGP/QR) | ⏳ |
| ⌛ Time-lock (cheque system) | 🔜 |
| ⚖️ Fee via nominal amount | 🔜 |
| 📱 React GUI + QR support | 🔜 |
| 🔄 Batch transfers | 🔜 |
| 🧩 NFT-based ownership proofs | 🔜 |
💡 Contributions and ideas are welcome!