Concepts
Stealth Addresses
How ECDH on Ed25519 enables unlinkable payments on Solana.
The problem
On public blockchains like Solana, every transaction is permanently visible. If you share your wallet address to receive a payment, anyone can see your entire transaction history, total balance, and all future transactions.
This creates serious privacy concerns for both individuals and organizations — salary payments reveal compensation, donations reveal political affiliations, and business transactions reveal commercial relationships.
The solution
Stealth addresses solve this by generating a unique, one-time address for every payment. The receiver shares a single public meta-address, but each sender derives a different stealth address from it. On-chain, these addresses appear completely unrelated.
Key properties
Unlinkable
No observer can determine that two stealth addresses belong to the same person. Each address appears as a fresh, independent wallet.
One-time
Each payment generates a new address. Even the same sender paying the same receiver twice will produce two different addresses.
Spendable
Only the intended receiver can derive the spending key for a stealth address. The receiver computes it deterministically from their private keys and the published ephemeral key.
Cryptographic flow
Cloak uses ECDH (Elliptic Curve Diffie-Hellman) on Ed25519 for stealth address derivation:
- Receiver generates a meta-address with two Ed25519 keypairs:
- Spending keypair (s, S) — for signing transactions
- Viewing keypair (v, V) — for detecting incoming payments
- Sender generates an ephemeral keypair (r, R) and computes the ECDH shared secret:
shared_secret = r * V = r * v * G - Sender derives the stealth address seed:
seed = SHA256("solana-stealth-seed-v1" || S || shared_secret) - Sender creates a Solana keypair from the seed — the public key becomes the stealth address. Sends SOL to this address and publishes R on-chain.
- Receiver computes the same shared secret using their viewing key:
shared_secret = v * R = v * r * G (same value) - Receiver derives the same seed, recreates the keypair, and confirms the public key matches. If it does, they can spend the funds.
Privacy guarantees
With the full Cloak v1.0 privacy stack:
Protected
- Receiver identity (stealth addresses)
- Payment linkability (one-time addresses)
- Payment amounts (zk-SNARK proofs)
- Sender identity (relayer network)
- Total received amount (unlinkable)
Visible
- Amounts (unless using --private mode)
- Transaction timing
- Sender identity (unless using --relayer mode)
- That a stealth payment occurred
Domain separation
Cloak uses domain-separated key derivation to prevent cross-protocol attacks:
- Spending key:
SHA256("solana-stealth-spending-v1" || seed) - Viewing key:
SHA256("solana-stealth-viewing-v1" || seed) - Stealth seed:
SHA256("solana-stealth-seed-v1" || S || shared_secret)