Appearance
Veilix’s Approach
Veilix breaks the on-chain link between a deposit address and a withdrawal address. The user keeps a secret note. The chain keeps a commitment. A zero-knowledge proof spends the note later, and a relayer submits that proof.
Design choices
| Choice | What it means |
|---|---|
| Non-custodial | The program releases funds only for a valid proof. The spending key is inside the user’s note. |
| Any amount | A note holds whatever you deposit, up to that asset’s cap. You can withdraw part of it. |
| One tree per asset | SOL, VEILIX, USDC, wBTC, and wETH each have a single shared tree. Every note of that asset is in the same set. |
| Client-side proofs | The secret never needs to leave the device that builds the proof. |
| Relayed withdrawals | The relayer signs the withdrawal. The recipient does not. |
| Split fee | A withdrawal pays a relayer fee and a platform fee. Both are taken from the withdrawn amount. The recipient receives the remainder. |
| Optional note backup | The note can be sealed on-chain under a key derived from the wallet, so the same wallet can find it later. |
How the link is broken
A deposit and a withdrawal are both ordinary Solana transactions, but they do not share a signer, and the proof does not name the deposit.
Commitments. A deposit creates a note: an amount, a spending key, and a random blinding factor. Those values are hashed into a commitment. The commitment is appended to the asset’s Merkle tree. The amount that entered the treasury is public. The spending key is not.
Proofs. To spend, the user proves knowledge of a note whose commitment sits in the tree, and proves that the public outputs (recipient, fee, change commitment) match that note. The verifier learns that some note in the tree was spent. It does not learn which leaf.
Nullifiers. Spending publishes a nullifier derived from the note and its position in the tree. The program stores that nullifier. A second spend of the same note fails. Observers see that a nullifier was used. They do not see which commitment produced it.
Change. If the withdrawal is smaller than the note, the proof inserts a new commitment for the remainder. That change note is a new secret. It stays in the pool until it is spent. The public payment does not have to equal the original deposit.
Variable amounts and the anonymity set
Privacy comes from the set of notes that could explain a withdrawal.
In a fixed-denomination pool, every note is the same size, so the amount itself carries no identity. Veilix does not do that. Notes in one asset tree can have different amounts. That is more flexible, and it changes the privacy story:
- The cryptographic proof still hides which note was spent.
- A distinctive amount can still narrow the candidates. A deposit of 7.3491 SOL followed by a withdrawal of 7.3491 SOL is easy to pair, because almost no other note has that size.
- Withdrawing a different amount, or leaving a change note in the pool, avoids echoing the deposit. The change note is itself a new member of the tree.
- The anonymity set is everyone else’s unspent notes of that same asset, not a separate crowd for each denomination. More deposits of that asset make the set larger. SOL and USDC never share a set.
Veilix does not compute a privacy score. The practical test is whether the amount you move publicly is common among recent notes in that tree, and whether you are willing to wait while other notes join it.
Public balance and shielded balance
Your Solana wallet remains a normal public balance. Tokens sitting in a Veilix tree are a second balance. That shielded balance is the sum of the unspent notes you can open. The chain shows commitments and, on withdrawal, a recipient and an amount. It does not show a token account whose balance is “your Veilix holdings.”
If you seal notes with your wallet’s encryption key, the same wallet can scan the tree and reconstruct that balance. Anyone without the key sees ciphertext.
One program for every product
A note created to hold funds and a note created for Private Send are the same kind of object in the same tree. Private Send deposits, then withdraws to the recipient you named. There is no second pool and no claim transaction for the recipient.
The on-chain program id shipped with the SDK is HbatG5gpfs2g3N4gc2Qkfmmeu4zaBEVxzrDdYtWNLyyA.