Privacy Documentation

How Privacy Works

A deep dive into the cryptography, architecture, and security model that makes UTXOpia a universal shielded pool for BTC, SOL, USDC, and any token on Solana.

The Problem

Why Tokens Need Privacy

Every blockchain transaction is permanently public. Whether you're using BTC, SOL, or USDC — your balances, transfers, and trading patterns are visible to anyone. UTXOpia shields all your tokens in a single privacy pool.

Comparison
Tokens
Traditional: Single asset (wBTC)
Private: Multi-token (BTC, SOL, USDC, USDT)
Balances
Traditional: Visible on-chain
Private: Hidden as commitments
Transfers
Traditional: Traceable amounts
Private: ZK-proven, zero knowledge
Addresses
Traditional: Linkable & reusable
Private: One-time stealth addresses
Deposits
Traditional: Public token minting
Private: Shielded Merkle insertion
Withdrawals
Traditional: Traceable burn + send
Private: Unlinkable via nullifiers
Custody
Traditional: Multisig / MPC
Private: Ika dWallet · Solana-controlled
Protocol Flow

End-to-End Journey

From shielding any token to private transfers to withdrawal — every step preserves your privacy across BTC, SOL, USDC, and more.

ShieldBTC / SOL / USDC
VerifySPV (BTC only)
CommitMerkle Tree
TransferZK Proof
UnshieldSPL / BTC
01

Shield Any Token

Deposit BTC via Taproot, or shield SOL/USDC/USDT directly from your Solana wallet. Every token enters the same privacy pool — a shared Merkle tree where all commitments look identical regardless of token type or amount.

BTC: Taproot + SPV · SPL: Shield (disc=29)
02

BTC SPV Verification

Bitcoin deposits require a special step: the backend submits an SPV Merkle inclusion proof to the on-chain BTC light client. The Solana program independently validates the Bitcoin transaction was confirmed in a real block — trustless cross-chain verification without any oracle.

On-chain header chain · 6+ confirmations
03

Commitment Creation

Your deposit becomes Poseidon(npk, tokenId, amount) — a cryptographic commitment. The token_id is derived from the SPL mint address: Poseidon(reduce(mint), 0). All tokens share the same depth-16 Merkle tree, making deposits indistinguishable.

Poseidon hash · Token-agnostic · 65,536 leaves
04

Private Transfer

Every transfer uses a Groth16 zero-knowledge proof that consumes N input notes and produces M output notes. The proof verifies balance conservation, token consistency, nullifier uniqueness, and Merkle membership — all without revealing any values. The same circuit works for BTC, SOL, USDC, or any shielded token.

Groth16 · 256 bytes · Token-agnostic circuit
05

Stealth Receive

Recipients use one-time stealth addresses generated via X25519 Diffie-Hellman key agreement. Each deposit or transfer creates a fresh address. The recipient scans announcements with their viewing key to find their notes — even repeat payments are unlinkable.

X25519 ECDH · Ed25519 viewing keys
06

Unshield or Withdraw

Exit the privacy pool in two ways: unshield SPL tokens back to your Solana wallet instantly, or withdraw BTC via an Ika dWallet whose authority is controlled by this Solana program (2PC-MPC, no off-chain signer committee). Both operations use a JoinSplit proof — the nullifier prevents double-spending without revealing which note you're spending.

SPL: instant · BTC: Ika dWallet (Solana-controlled)
Cryptography

Under the Hood

The cryptographic primitives that make shielded transactions possible.

Commitment Scheme

Poseidon(npk, token_id, amount)

Each note is a Poseidon hash of the note public key, token ID, and amount. The token_id = Poseidon(reduce(mint), 0) makes commitments token-specific — the same circuit verifies BTC, SOL, USDC, or any token. Only the owner knows the preimage.

Nullifier Generation

Poseidon(nullifyingKey, leafIndex)

When spending a note, the nullifier is derived from the nullifying key (itself derived from the spending key) and the note's Merkle leaf index. Publishing a nullifier prevents double-spending without revealing which note was consumed.

Master Public Key

Poseidon(spendPub.x, spendPub.y, nullKey)

The MPK combines the Baby Jubjub spending public key coordinates with the nullifying key. This is used to derive per-note public keys: NPK = Poseidon(MPK, random), ensuring each note has a unique cryptographic identity.

JoinSplit Circuit

JoinSplit(N, M, depth=16)

A single parameterized circom template handles all transfer types. Inputs: N note nullifiers + Merkle proofs. Outputs: M new commitments. The circuit verifies balance (Σin = Σout), nullifier validity, Merkle membership, and EdDSA-Poseidon signatures — all in one Groth16 proof.

EdDSA-Poseidon Signatures

Sign(spendingKey, message)

Transaction authorization uses EdDSA over the Poseidon hash function on the Baby Jubjub curve. The message includes the Merkle root, bound parameters hash, all nullifiers, and all output commitments — binding the proof to a specific state.

Stealth Key Agreement

sharedSecret = ECDH(ephemeral, viewKey)

Senders generate a random ephemeral keypair and compute a shared secret with the recipient's viewing public key. This derives the one-time note public key. Only the recipient can scan announcements using their viewing private key to detect incoming notes.

Key Architecture

Dual-Key Model

Two keys give you full control: one to spend, one to observe. The nullifying key is derived automatically from your spending key — you never manage it directly.

Spending Key

Baby Jubjub elliptic curve keypair. Signs all JoinSplit transactions using EdDSA-Poseidon. The nullifying key is deterministically derived from this key — it generates the nullifier hash that prevents double-spending.

Signs transactions (EdDSA-Poseidon)
Derives nullifying key automatically
Generates master public key (MPK)

Viewing Key

Ed25519 keypair used exclusively for scanning stealth announcements. Can detect incoming notes by matching the note public key (NPK). Share with auditors or compliance officers — they can see your balance history but never spend your funds.

Scans stealth announcements
Read-only access to balances
Shareable for selective disclosure
Security

Security & Compliance

Privacy doesn't mean unaccountable. Multiple layers of security and compliance are built into the protocol.

On-Chain Policy Gate

Signing policy lives in the Solana program itself: amount limits, fee bounds, paused state, and destination whitelist are checked on-chain before the program issues the Ika `approve_message` CPI. A compromised backend cannot drain funds by submitting forged sighashes.

Ika dWallet Custody

BTC is held by an Ika dWallet whose authority is a PDA derived from this Solana program (`["__ika_cpi_authority"]`). 2PC-MPC means the Ika network and our program must both participate in every signature — no single key, no off-chain signer committee. Pre-alpha runs a single mock signer; real distributed MPC ships at Ika mainnet.

Trustless Verification

Bitcoin deposits are verified on-chain via SPV proofs against a light client tracking BTC block headers. The Solana program validates Merkle inclusion directly — no oracle or trusted third party.

Double-Spend Prevention

Each note can only be spent once. Publishing a nullifier (derived from spending key + leaf index) marks the note as consumed. The on-chain program rejects duplicate nullifiers permanently.

Selective Disclosure

Share your viewing key with auditors, accountants, or compliance officers. They gain read-only access to your transaction history and balances — without any ability to spend or transfer your funds.

Auditable CPI Trail

Every redemption emits an `approve_message` CPI on-chain, with the sighash, dWallet ID, and signature scheme recorded as inner instructions in the Solana transaction. The full signing history is reconstructable from RPC alone — no separate audit log to operate.

Ready to Go Private?

Shield BTC, SOL, USDC, or USDT. Transfer privately. Withdraw anonymously.