Jat
CONCEPTS

How it works

Two privacy layers on Solana: stealth addresses for who, a fixed-denomination pool for unlinking the payout from your deposit. They compose, and neither delegates a key to anyone.

Stealth addresses (graph privacy)

A recipient holds two scalars, a scan key and a spendkey, and publishes the matching public points as a meta-address. A payer picks an ephemeral key, does an Ed25519 ECDH with the scan point, and derives a one-time address that only the recipient can recognize and spend. The ephemeral public key plus a one-byte view tag are announced on chain so the recipient can scan quickly. There is no zero-knowledge proof here, just key derivation, so it is cheap. The scan key can be delegated to an untrusted indexer to watch on the recipient's behalf without granting any spend power.

The fixed-denomination pool (deposit-payout unlinking)

The pool is a depth-20 on-chain Poseidon-BN254 Merkle tree. A deposit pins the leaf value to the lamports that actually moved and accepts only fixed denominations, so same-size deposits are indistinguishable. The denomination tier is public; what the pool shields is the link between a deposit and its withdrawal. A withdrawal proves, in zero knowledge, that it owns some leaf in the tree without revealing which, and spends a single-use nullifier. The payout comes from a vault PDA via invoke_signed; no operator signs it. The leaf commitment is Poseidon(value, label, Poseidon(nullifier, secret)).

The relayer

A fresh stealth or withdrawal address holds no SOL, so it cannot pay its own first fee, and paying it from a known wallet would re-link the recipient. The relayer pays that fee instead. It is trusted only for liveness and censorship, never for custody: the pool pays out of its vault, not the relayer, and the relayer refuses any transaction that would cost it more than gas.

No delegated keys

There is no operator viewing key and no auditor key anywhere in the design. Whatever a proof hides stays hidden from everyone, because no privileged party can later choose to inspect it. The Merkle root is a deterministic function of the deposits that happened, not a value some authority posts.

Composing the two

The default private path uses both: a payer funds a stealth address (hiding the parties), the recipient claims it into the pool through the relayer (hiding the fee trail), and later withdraws to a clean address (unlinking the payout from the specific deposit). Graph privacy and deposit-payout unlinking in one round-trip.

Go deeper

The blog covers how the proof works and where Jat sits on the Solana privacy map.