Privacy Technologies
Zero-knowledge proofs, multi-party computation, and post-quantum cryptography — delivering true financial privacy on Solana.
System Architecture
System Architecture
Protocol Stack
Core Technologies
21 modules — click to expand technical details and code examples.
Stealth addresses allow recipients to receive funds without revealing their public address. Each payment creates a unique one-time address using Elliptic Curve Diffie-Hellman key exchange.
Key Features
- Sender generates ephemeral keypair for each transaction
- Shared secret computed using ECDH between sender ephemeral key and recipient's public key
- One-time address derived: P = H(shared_secret) * G + recipient_pubkey
- Only the recipient can detect and spend funds using their private key
- v1: X25519 (Curve25519) for efficiency on Solana
- v2: X25519 + ML-KEM-768 (FIPS 203) hybrid ECDH — quantum-resistant
- View tags: 1-byte filter enables O(1) scanning without full decryption
- On-chain registry (EIP-5564 for Solana) via p01_registry program
Code Example
// v1: Generate stealth address (X25519 ECDH)
const ephemeral = Keypair.generate();
const sharedSecret = x25519(ephemeral.secretKey, recipientPubkey);
const stealthKey = deriveStealthKey(sharedSecret, recipientPubkey);
// v2: Hybrid quantum-resistant (X25519 + ML-KEM-768)
const { ciphertext, sharedSecret: hybridSecret } =
mlKem768.encapsulate(recipientMlKemPubkey);
const combinedSecret = hkdf(x25519Secret, hybridSecret);Dual proof system: Groth16 ZK-SNARKs for compact on-chain verification via BN254 pairing, and STARKs (Winterfell) for quantum-resistant proofs over the Goldilocks field. STARKs are hash-based — immune to Shor's algorithm — and are now the default for denominated pool unshielding.
Key Features
- 7 Groth16 circuits: transfer (12,222c), denominated_pool (4,273c), denominated_transfer (5,628c), confidential_balance (1,382c), balance_proof (644c), subscriber_ownership (~500c), note_split (~10,000c)
- 6 STARK AIRs: subscriber_ownership, pool_commitment, balance_proof, merkle_path, confidential_balance, transfer
- STARK: Winterfell prover, Goldilocks field (2^64 - 2^32 + 1), Poseidon AIR (x^7, 30 rounds)
- Compact STARK proofs (9-15KB) with Blake3 Merkle trees, 16 FRI queries, 128-bit security
- On-chain STARK verifier: custom FRI implementation, ~889K CU per verification
- On-chain Groth16: BN254 alt_bn128 pairing precompiles, ~200K CU verification
- Mobile WASM STARK prover via WebView (82KB module, all 6 circuits)
- Trusted setup: Groth16 with pot20_final.ptau + beacon finalization (ceremony pending 3+ contributors)
- Quantum-safe: STARKs are hash-based — immune to both Shor's and Grover's algorithms
Code Example
// Groth16 proof (BN254, compact, fast verification)
const { proof, publicSignals } = await snarkjs.groth16.fullProve(
{ inputs, merkle_path, nullifiers },
"transfer.wasm", "transfer.zkey"
);
// STARK proof (quantum-resistant, hash-based)
const starkProof = await starkProver.generateProof(secret);
// Upload proof buffer → verify on-chain → ~889K CU
await submitStarkProof(program, proofBuffer, commitment, circuitId);Private transfers go through the relayer. The user generates a ZK proof client-side, funds the relayer, and the relayer executes the transfer to a stealth address. On-chain, only the relayer-to-stealth-address link is visible — the original sender is completely hidden.
Key Features
- User generates ZK proof locally — Groth16 or STARK (sender never revealed)
- User funds relayer with amount + 0.5% fee + gas
- Relayer verifies proof off-chain, then sends to stealth address
- On-chain visibility: Relayer → Stealth Address only
- Sparse Merkle tree with depth 20 for commitment tracking
- Instant shield/unshield (~3s) via filledSubtrees optimization — no full tree sync
- Supports SOL and any SPL token
Code Example
// Private transfer flow via relayer
// 1. User generates ZK proof client-side
const { proof, publicSignals } = await generateProof(inputs);
// 2. User funds relayer (amount + fee + gas)
await fundRelayer(amount, feeBps: 50, gasCost);
// 3. Relayer verifies & sends to stealth address
// On-chain: only "Relayer → StealthAddress" is visible
const tx = await relayer.privateSend(proof, stealthAddress);Poseidon is a ZK-friendly hash function designed specifically for use inside arithmetic circuits. It's significantly more efficient than traditional hashes like SHA-256 or Keccak in ZK contexts.
Key Features
- Operates natively over prime fields (BN254 for Groth16, Goldilocks for STARK)
- ~300x fewer constraints than Keccak in Circom circuits
- Used for commitments, nullifiers, and Merkle tree hashing
- Parameters: BN254 (x^5 S-box, 8 full rounds) + Goldilocks (x^7 S-box, 30 full rounds)
- Compatible with circomlib implementation
Code Example
// Poseidon commitment in circuit
template Commitment() {
signal input amount;
signal input ownerPubkey;
signal input randomness;
signal output commitment;
component hash = Poseidon(4);
hash.inputs[0] <== amount;
hash.inputs[1] <== ownerPubkey;
hash.inputs[2] <== randomness;
hash.inputs[3] <== tokenMint;
commitment <== hash.out;
}A Merkle tree stores all commitments, allowing users to prove they have funds in the shielded pool without revealing which commitment they own. The root is stored on-chain and updated with each deposit.
Key Features
- Binary tree with Poseidon hash at each node
- Depth 20 = 2^20 = ~1 million commitments capacity
- Proof size: 20 siblings + 20 path indices
- Incremental insertions for gas efficiency
- Precomputed zero values for empty subtrees
Code Example
// Merkle proof verification in circuit
for (var i = 0; i < TREE_DEPTH; i++) {
left = pathIndices[i] == 0 ? current : siblings[i];
right = pathIndices[i] == 0 ? siblings[i] : current;
current = Poseidon(left, right);
}
root === computedRoot; // Must match on-chain rootNullifiers are unique identifiers that prevent double-spending without revealing which commitment was spent. Each commitment can only produce one valid nullifier.
Key Features
- Nullifier = Poseidon(commitment, spending_key_hash)
- Stored on-chain in a set (prevents reuse)
- Cannot be linked back to the original commitment
- Spending key proves ownership without revealing identity
- Tracked by the relayer to prevent replay attacks
Code Example
// Nullifier computation const spendingKeyHash = Poseidon([spendingKey]); const nullifier = Poseidon([commitment, spendingKeyHash]); // On-chain: require(!nullifierSet.contains(nullifier))
Protocol 01 leverages Solana's native cryptographic syscalls for efficient on-chain ZK proof verification, achieving verification in under 200K compute units.
Key Features
- alt_bn128 syscalls for BN254 Groth16 verification (~200K CU)
- Custom FRI verifier for STARK proofs — Goldilocks field (~889K CU)
- 13 Anchor programs: zk_shielded, zkSPL, specter, subscriptions, streams, quantum_vault, STARK_verifier, registry, relayer, trustless, fee_splitter, whitelist, arcium
- Quantum vault: WOTS+ signatures, hash-timelock, commit-then-reveal (SHA-256 based)
- Cross-program invocations for token transfers and proof verification
- 370+ automated tests: stress tests, E2E flows, SDK unit tests, Rust STARK tests
Code Example
// On-chain Groth16 verification (BN254)
let pairing_result = sol_alt_bn128_pairing(&[...]);
require!(pairing_result == 1, "Invalid Groth16 proof");
// On-chain STARK verification (Goldilocks + Blake3)
let positions = fiat_shamir_positions(trace_root, commitment);
for pos in positions {
verify_merkle_path(proof, pos, trace_root)?;
verify_poseidon_round(trace_row, round_constants)?;
}Fully on-chain relayer program (p01_relayer) that verifies ZK proofs and executes private transfers to stealth addresses. No backend server — the relayer is a Solana program, eliminating trust in any third party.
Key Features
- On-chain Solana program — no backend server, fully trustless
- User generates ZK proof client-side (spending key never leaves device)
- Relayer PDA escrows transfer amount + fee (0.5%) + gas + rent
- On-chain verification: proof checked by the program before executing transfer
- Sends to stealth address — no on-chain link to the original sender
- Local-only proving: snarkjs in WebView (mobile) or browser (extension)
Code Example
// Trustless on-chain relay flow
// 1. User generates ZK proof locally (spending key stays on device)
const { proof, publicSignals } = await snarkjs.groth16.fullProve(
{ inputs, merkle_path, nullifiers },
"transfer.wasm", "transfer.zkey"
);
// 2. Submit proof to on-chain relayer program
await program.methods.relayTransfer(proof, publicSignals, stealthAddress)
.accounts({ relayerPda, pool, recipient: stealthAddress })
.rpc();
// On-chain: relayer verifies proof → transfers to stealth addressZK proofs hide amounts and break the sender-receiver link. But some metadata remains: the relayer sees your transaction, nullifiers are posted in the clear, and registry lookups are observable. Arcium MPC eliminates these residual leaks by distributing every sensitive operation across a decentralized network of nodes — no single node ever sees the plaintext. It is an optional layer that users toggle on for maximum privacy.
Key Features
- Nullifier hiding: MPC nodes jointly compute SHA3(nullifier) — only the hash goes on-chain, the actual nullifier stays encrypted
- Confidential relay: your transaction is encrypted and split across MPC nodes (Rescue-CTR). They reconstruct and execute it together — no single relayer sees the content
- Anonymous registry lookup: query a stealth meta-address through MPC — nobody knows who you looked up
- Confidential balance audit: prove solvency to an auditor without revealing individual balances
- Threshold stealth scan: your viewing key is sharded across nodes — no single node can scan your payments
- Private governance: encrypted ballots tallied inside MPC — only the final result is revealed
- Cerberus protocol: 1-of-N honest node guarantees correctness. 9 circuits deployed on Solana devnet
- Graceful fallback: every MPC operation degrades to the standard (non-MPC) path when disabled — zero overhead
Code Example
// @p01/arcium-sdk — MPC confidential compute
import { ArciumClient } from '@p01/arcium-sdk';
const mpc = new ArciumClient({ connection, wallet, programId });
await mpc.initialize(); // X25519 key exchange + Rescue cipher setup
// Without MPC: nullifier posted in the clear on-chain
// With MPC: nodes compute SHA3(nullifier) together, only hash goes on-chain
await mpc.commitNullifier(nullifierPreimage, secret);
// Without MPC: relayer sees full transaction content
// With MPC: transaction split across nodes, nobody sees the plaintext
await mpc.confidentialRelay(encryptedTransaction);
// Without MPC: RPC lookup reveals who you searched for
// With MPC: query goes through MPC, target stays anonymous
const metaAddress = await mpc.privateLookup(targetHash);Streams and subscriptions do NOT use ZK proofs. They are separate modules with their own privacy model based on obscurement. Users can add noise to amounts and timing to make payments harder to analyze, but they are not fully hidden like ZK transfers.
Key Features
- Streams: time-locked escrow payments (P2P or P2B) — visible on-chain
- Subscriptions: delegated recurring payments via crank — visible on-chain
- Amount noise: 0-20% random variation on each payment
- Timing noise: 0-24 hours random delay on payment execution
- Optional stealth address for recipient obscurement
- Privacy level: obscurement (not full anonymity like ZK transfers)
Code Example
// Subscription with privacy noise (not ZK)
await p01.createSubscription({
amount: 9.99,
interval: 'monthly',
privacyOptions: {
amountNoise: 10, // ±10% random variation
timingNoise: 12, // ±12 hours random delay
useStealth: true // Pay to ephemeral address
}
});
// On-chain: payment is visible but harder to correlateTornado Cash-style fixed-denomination pools for SOL and USDC. All deposits in a pool are the same value, making them indistinguishable. Epoch-based time delays prevent timing correlation attacks.
Key Features
- Fixed denominations: 0.1/1/10/100 SOL or 1/10/100/1000 USDC
- Commitment = Poseidon(nullifier_preimage, secret, deposit_epoch, token_mint)
- PDA-per-nullifier for atomic double-spend prevention (not Bloom filter)
- Epoch-based maturity: deposit_epoch <= min_epoch enforced in circuit and on-chain
- Merkle tree depth 15 = 32,768 notes per pool
- Circuit: denominated_pool.circom (4,273 non-linear constraints)
- P2P note sharing via BLE and NFC for offline transfers
Code Example
// Shield into a 1 SOL denominated pool
const commitment = poseidon([nullifierPreimage, secret, epoch, tokenMint]);
await program.methods.shieldDenominated(commitment, epoch)
.accounts({ pool, depositor, systemProgram })
.rpc();
// Unshield with STARK proof (quantum-resistant, default)
const starkProof = await starkProver.generateProof(secret);
await program.methods.unshieldDenominatedStark(starkProof, commitment)
.accounts({ pool, recipient, nullifierPda, starkBuffer })
.rpc();
// Or with Groth16 proof (classic, faster verification)
const { proof } = await snarkjs.groth16.fullProve(inputs,
"denominated_pool.wasm", "denominated_pool.zkey");
await program.methods.unshieldDenominated(proof, nullifier, root, minEpoch)
.rpc();Account-model confidential tokens using Poseidon hash commitments. Unlike UTXO-based shielded pools, zkSPL maintains a single balance commitment per account that updates with each operation. Quantum-resistant by design.
Key Features
- Balance commitment = Poseidon(balance, salt, owner_pubkey, token_mint)
- Amount commitment = Poseidon(amount, amount_salt) links sender and recipient
- Single circuit handles deposit, withdraw, send, and receive operations
- Conservation law: old_balance + credits === new_balance + debits
- Balance proof: proves balance >= threshold via Num2Bits(64) range check
- Circuit: confidential_balance.circom (1,382 constraints)
- SDK: @p01/zkspl-sdk with ZkSplClient, ZkSplProver, LocalStateManager
Code Example
// Confidential deposit — public tokens become hidden balance
const oldCommitment = poseidon([0, salt, owner, mint]);
const newCommitment = poseidon([amount, newSalt, owner, mint]);
const { proof } = await prover.prove({
old_balance: 0, new_balance: amount,
public_credit: amount, public_debit: 0,
private_credit: 0, private_debit: 0,
old_salt: salt, new_salt: newSalt
});
// Confidential transfer — sender and recipient balances stay hidden
// Amount commitment links the two operations cryptographically
const amountCommitment = poseidon([transferAmount, amountSalt]);On-chain recurring payment vaults with configurable intervals. Retailers create vaults, subscribers deposit funds, and a crank claims payments each period. Supports both normal (public) and ZK-private subscriber modes.
Key Features
- Vault PDA stores: retailer, amount, interval, token mint, subscriber count
- Normal mode: subscriber identity visible, straightforward recurring payments
- Private mode: ZK proof of subscription ownership without revealing identity
- Auto-pause on insufficient funds, resume when topped up
- Retailer claim periods with on-chain settlement
- Circuit: subscriber_ownership.circom for private subscriber proofs
Code Example
// Retailer creates a subscription vault
await program.methods.initSubscriptionVault(
amount, // per-period amount (lamports or token units)
interval, // seconds between payments
tokenMint // SOL (system_program::ID) or SPL token
).accounts({ vault, retailer }).rpc();
// Subscriber joins (normal mode)
await program.methods.subscribeNormal()
.accounts({ vault, subscriber, subscriberRecord })
.rpc();
// Retailer claims a payment period
await program.methods.claimPeriod()
.accounts({ vault, subscriberRecord, retailer })
.rpc();Share denominated pool notes between devices offline using Bluetooth Low Energy or NFC. Notes are encrypted end-to-end and can be transferred without internet connectivity.
Key Features
- BLE: X25519 ECDH key exchange with nacl.box encryption
- NFC: Host Card Emulation (HCE) with PIN-derived nacl.secretbox
- Anti-MITM fingerprint verification for BLE connections
- Fragmentation protocol for large payloads over BLE characteristics
- Native Android modules: BluetoothGattServer + HostApduService
- Works offline — no internet or blockchain access needed for transfer
Code Example
// BLE: Sender (central) connects to receiver (peripheral) // 1. ECDH key exchange const sharedKey = x25519(senderPrivateKey, receiverPublicKey); // 2. Encrypt note data const encrypted = nacl.box(noteJSON, nonce, sharedKey); // 3. Fragment and send over BLE characteristics await bleTransport.sendFragmented(encrypted, characteristicUUID); // NFC: Sender emulates tag via HCE // Receiver taps phone → APDU commands: SELECT → GET LENGTH → GET DATA // Data encrypted with nacl.secretbox(noteJSON, nonce, pinDerivedKey)
Eight TypeScript SDKs covering every use case: stealth wallets, ZK proofs, confidential tokens, MPC compute, merchant integration, Merkle trees, authentication, and RPC infrastructure. All run client-side for maximum privacy.
Key Features
- @p01/specter-sdk — Core privacy: stealth wallets, transfers, quantum vault, registry, indexer
- @p01/zk-sdk — ZK primitives: ShieldedClient, Note, MerkleTree, ZkProver, viewing keys
- @p01/zkspl-sdk — Confidential tokens: deposit, withdraw, transfer, balance proof
- @p01/arcium-sdk — MPC compute: ArciumClient, 6 use-case modules, Rescue cipher
- @p01/p01-js — Merchant SDK: Protocol01 client, subscriptions, payments, React components
- @p01/privacy-toolkit — Incremental Merkle tree, Poseidon, amount hash, proof format
- @p01/auth-sdk — Auth integration: P01AuthClient, P01AuthServer, session management
- @p01/rpc-config — RPC infrastructure: connection manager, priority fallback chain, URL sanitization
Code Example
// === @p01/specter-sdk — Core Privacy SDK ===
import { P01Client, createWallet, sendPrivate } from '@p01/specter-sdk';
const client = new P01Client({ cluster: 'devnet' });
await sendPrivate({ amount: 1.5, recipient: stealthMetaAddress });
// === @p01/zk-sdk — ZK Shielded Pool ===
import { ShieldedClient } from '@p01/zk-sdk';
const zkClient = new ShieldedClient({ rpcUrl, programId });
await zkClient.shield(1_000_000_000n, notes);
// === @p01/zkspl-sdk — Confidential Balances ===
import { ZkSplClient } from '@p01/zkspl-sdk';
await zkspl.deposit(amount, proof); // Public → confidential
await zkspl.send(amount, recipient); // Confidential transfer
// === @p01/arcium-sdk — MPC Compute ===
import { ArciumClient } from '@p01/arcium-sdk';
await mpc.commitNullifier(preimage); // SHA3 via MPC nodes
// === @p01/p01-js — Merchant Integration ===
import { Protocol01 } from '@p01/p01-js';
await p01.createSubscription({ amount: 9.99, interval: 'monthly' });
// === @p01/privacy-toolkit — Merkle + Poseidon ===
import { IncrementalMerkleTree, poseidon2 } from '@p01/privacy-toolkit';
// === @p01/auth-sdk — Auth Integration ===
import { P01AuthClient } from '@p01/auth-sdk';
// === @p01/rpc-config — RPC Infrastructure ===
import { RpcConnectionManager } from '@p01/rpc-config';
const conn = RpcConnectionManager.getConnection(); // Auto-fallback chainWhen receiving funds, the app generates a one-time stealth address instead of exposing the main wallet. Incoming funds are automatically detected and shielded into the privacy pool — the main wallet is never visible to senders.
Key Features
- Receive screen generates fresh stealth addresses (HMAC-derived from viewing secret key)
- Autonomous runner polls every 5 minutes for incoming funds on stealth addresses
- When balance detected (>0.05 SOL), auto-shields to the best matching denomination pool
- Main wallet NEVER appears on-chain for incoming transfers
- Stealth receive addresses tracked in SecureStore with cleanup after 7 days
- Settings toggle in Privacy Settings to enable/disable auto-shielding
- Compatible with any Solana wallet sender — no Protocol 01 required on sender side
Code Example
// Auto-Shield flow (autonomous runner)
// 1. User opens Receive → stealth address generated
const seed = hmac(sha256, viewingSecretKey, "p01_auto_receive_42");
const keypair = Keypair.fromSeed(seed);
// Display keypair.publicKey as QR code
// 2. Sender sends SOL to the stealth address (any wallet)
// 3. Runner detects funds → auto-shields
const balance = await connection.getBalance(stealthAddress);
if (balance > MIN_THRESHOLD) {
await shield(pool, progressCb, undefined, keypair);
// Main wallet never visible on-chain
}All RPC calls from the mobile app are routed through a 3-tier privacy relay. The relay strips identifying headers, adds timing jitter, and routes through Tor — upstream RPC providers never see the user's real IP address.
Key Features
- Tier 1 (Client): fetchMiddleware strips User-Agent, Origin, Referer + adds 30-120ms jitter
- Tier 2 (Relay): Express server with HMAC rate limiter (zero IP storage), security headers, metadata stripping
- Tier 3 (Tor): SOCKS5 proxy with circuit rotation every 10 minutes via random authentication
- Deployed on Railway — single container (Node 22 Alpine + Tor sidecar)
- Supports batch JSON-RPC forwarding for getParsedTransactions
- Helius RPC upstream via Tor — API key hidden, IP anonymized
- Fallback: app works without relay (Tier 1 client-side protection always active)
- 13K+ requests tested with 100% Tor routing and 0 errors
Code Example
// 3-tier privacy architecture
// Tier 1: Client-side (always active)
const connection = new Connection(relayUrl, {
fetchMiddleware: privacyFetchMiddleware, // Strip headers + jitter
});
// Tier 2: Relay server (Railway)
app.use(stripMetadata); // 20+ headers removed
app.use(securityHeaders); // HSTS, CSP, no-referrer
app.use(rateLimiter); // HMAC-hashed IP (zero storage)
// Tier 3: Tor SOCKS5
const agent = new SocksProxyAgent("socks5h://tor:9050");
// Circuit rotates every 10min via random SOCKS authFor P01-to-P01 transfers, users share a persistent stealth meta-address (st:01...). The sender's Private Send auto-derives a fresh one-time stealth destination — both sender AND receiver are fully hidden on-chain.
Key Features
- Meta-address format: st:01<base58(spending_ed25519_pub + viewing_x25519_pub)>
- v2 hybrid: st:02<base58(spending + viewing + ML-KEM-768 pub)> — quantum-resistant
- Persistent stealth keys (Ed25519 + X25519) stored in SecureStore
- Private Send detects meta-addresses and auto-derives stealth destination
- QR scanner auto-detects st:01/st:02 and routes to Private Send
- On-chain trail: stealth_sender → pool → stealth_receiver (no real wallet visible)
- Receive screen shows compact 'Copy P01 ID' for easy sharing
Code Example
// Receiver: share meta-address
const keys = await getOrCreateStealthKeys();
const metaAddress = createMetaAddress(keys);
// → "st:012u2trSt1XytE271..."
// Sender: Private Send auto-derives stealth destination
if (isMetaAddress(destination)) {
const stealth = deriveStealthForRecipient(destination);
finalDestination = stealth.address;
// Both sender + receiver hidden on-chain
}Split a high-denomination note into multiple lower-denomination notes across pools. Enables the Privacy Router to break large amounts into smaller, harder-to-trace pieces with a single ZK proof.
Key Features
- On-chain instruction: split_note in zk_shielded program (deployed on devnet)
- Circuit: note_split.circom (~10K constraints, max 20 outputs)
- Denomination conservation enforced: source = numOutputs × target
- Same nullifier PDA pattern as unshield (atomic double-spend prevention)
- Protocol fee: 0.3% of source denomination
- Groth16 proof verifies ownership + output commitment correctness
- Mobile SDK: splitNote() function with proofGenerator callback
Code Example
// Split 1 SOL into 10 × 0.1 SOL const result = await splitNote( sourcePool, // 1 SOL pool targetPool, // 0.1 SOL pool receipt, // Source note receipt 10, // Number of outputs outputSecrets, proofGenerator, ); // → 10 new notes in 0.1 SOL pool
The Privacy Router plans and executes multi-hop routes through the privacy pool system. Routes include shield, unshield, reshield, and split operations with configurable timing delays to maximize anonymity.
Key Features
- 5 privacy levels: Minimal (1 hop) → Paranoid (14+ hops, 20 splits)
- Autonomous runner executes hops in background (60s polling, Android foreground service)
- Timing jitter: random delays between hops (hours) prevent correlation
- Note locking: notes in active routes are locked (cannot withdraw or re-send)
- Consent popup: irreversibility warning before route starts
- Route progress: locked notes show hop X/Y, progress bar, next hop ETA
- Routes encrypted in SecureStore, survive app restarts
- In-app notification on each hop completion
Code Example
// Start a Paranoid-level private send
const route = await startPrivateRoute({
amount: 0.1,
destination: "7gWpzSZA...",
privacyLevel: 5, // Paranoid
spendingKeyHash,
});
// → 14 hops over ~2 days
// → Shield → Unshield → Reshield → ... → Final delivery
// → Each hop uses a different stealth addressOn-device AI agent with 56 tools covering wallet operations, privacy actions, Solana network queries, DeFi analytics, and device features. Runs locally (Gemma 3 via llama.rn) — no data leaves the device.
Key Features
- Wallet (6): balance, address, send, history, airdrop, stealth receive
- Privacy (5): shield, notes list, private send, route status, privacy level
- Solana (6): slot, epoch, TPS, tx lookup, account info, rent calculator
- Token/DeFi (6): token balance, swap quote, swap execute, TVL, lending rates, portfolio
- Analytics (3): gas tracker, whale watch, market dominance
- Staking (3): stake info, APY, validators
- NFT (2): list NFTs, floor price
- Social (2): protocol info, trending tokens
- Conversion (3): SOL/USD, SOL/lamports, epoch/date
- Device (3): share, haptic, notification
- Alerts (3): set price alert, list alerts, clear alerts
- Utility (4): calculate, validate address, base58 encode, generate keypair
- Memory (3): save, read, list persistent agent memory
- Tool-use loop: up to 3 rounds of tool execution per message
Code Example
// User: "What's my balance and shield 0.1 SOL"
// Agent calls tools:
const balance = await executeTool("wallet_balance", {});
// → { sol: "3.69", usd: "$520.13" }
// Agent responds and calls shield tool:
await executeTool("privacy_shield", { amount: 0.1 });
// → Redirects to Privacy → Shield screenSecurity Model
Threat Model
- Blockchain observers cannot link senders and recipients
- Transaction amounts are hidden in shielded transfers
- Spending patterns cannot be analyzed
- Balance tracking is impossible for third parties
Guarantees
- Sound: Invalid proofs cannot be generated
- Complete: Valid spends always produce valid proofs
- Zero-knowledge: Proofs reveal nothing beyond validity
- No double-spending: Nullifiers are unique per commitment
- MPC threshold: 1-of-N honest node via Arcium Cerberus protocol
Security Hardening (Mobile)
- Spending key never leaves device — no remote prover fallback
- PIN: SHA-256 hashed with per-device salt, constant-time compare
- Progressive lockout: 5→30s, 8→60s, 10→300s
- All secrets in hardware-backed SecureStore (not AsyncStorage)
- Clipboard auto-clear after 60s on all sensitive copies
- App switcher blur prevents screenshot leaks
- android:allowBackup="false" (prevents adb backup)
- Biometric auth: device fallback when hardware unavailable
- Lock screen enforced even when security_method="none"
Privacy: With & Without MPC
Protocol 01 is private by default — ZK proofs hide amounts and break the sender-receiver link. Arcium MPC is an optional upgrade that eliminates the remaining metadata leaks. Toggle it on in the app for maximum privacy, or leave it off for fast, already-private transactions.
| Operation | Without MPC | With MPC (Arcium) |
|---|---|---|
| Amounts | Hidden by ZK proof | Hidden by ZK proof |
| Sender → Receiver link | Broken by stealth addresses | Broken by stealth addresses |
| Nullifier | Posted in the clear on-chain | MPC nodes compute SHA3 jointly — only hash on-chain |
| Relay | On-chain relayer sees TX content | TX split & encrypted — no single node sees plaintext |
| Registry lookup | RPC query reveals search target | Query goes through MPC — target stays anonymous |
| Balance audit | — Not available | Prove solvency without revealing individual balances |
| Governance vote | — Not available | Encrypted ballots — only final tally revealed |
| Trust assumption | Relayer is honest (can't steal, can observe) | 1-of-N honest node (Cerberus protocol) |
MPC Off — Already Private
- STARK & Groth16 proofs hide amounts and ownership
- Stealth addresses make every payment unlinkable
- Denominated pools prevent amount-based correlation
- Some metadata visible: nullifiers, relay content, lookup targets
MPC On — Maximum Privacy
- Everything above, plus all metadata leaks eliminated
- Nullifiers encrypted — only SHA3 hash reaches the chain
- Relay is threshold-decrypted — no single point of observation
- Unlocks balance audits, private voting, threshold stealth scan
MPC adds ~1-2s per operation · Zero overhead when disabled · Toggle on/off in Privacy Zone
PROGRESSIVELY UPDATED · LAST REVISION MARCH 2026