01Why Privacy Matters for AI Agents
A blockchain is a public ledger. Every transaction your agent sends is recorded permanently, visible to anyone with an internet connection and a block explorer. For human traders, this exposure is inconvenient. For AI agents operating at scale, it is strategically catastrophic.
The On-Chain Intelligence Problem
When your agent's wallet address is known — or can be inferred from transaction patterns — adversaries can extract detailed intelligence about your strategy:
- Position timing: Observing when your agent deposits to a DEX reveals when it enters positions. Front-running becomes trivial.
- Strategy fingerprinting: Transaction frequency, sizes, and counterparties reveal whether you are market-making, trend-following, or arbitraging.
- Capital exposure: Your total portfolio size is visible. Competitors can gauge whether to fight you for liquidity.
- Funding sources: If your funding wallet traces back to an exchange withdrawal that traces back to an identity, your pseudonymity collapses.
MEV and Sandwiching: On Ethereum mainnet, MEV bots monitor the mempool in real-time. An agent broadcasting a large swap has, on average, 1-3 blocks (12-36 seconds) before a sandwich bot sees the transaction, inserts buys before it, and sells after. In 2025, sandwich bots extracted over $400M from mempool-visible swaps. Privacy is not a luxury for large agents — it is a necessity.
Transparency vs Privacy Spectrum
Bitcoin / Ethereum
Every address, balance, and transaction is permanently public. Heuristics link addresses into clusters with 70-90% accuracy.
Zcash / ZK-Rollups
Optional shielded pools. Selective disclosure via viewing keys. Privacy requires opt-in — most users stay transparent.
Monero (XMR)
Ring signatures, stealth addresses, and RingCT make all transactions private by default. Sender, receiver, and amount are hidden.
02ZK-SNARK Fundamentals
A Zero-Knowledge Succinct Non-Interactive Argument of Knowledge (ZK-SNARK) is a cryptographic proof system with a remarkable property: it allows a prover to convince a verifier that a statement is true without revealing any information about why it is true.
The Core Idea
Imagine an agent that has executed a trade and earned a profit. It wants to prove to a counterparty that it is solvent (has at least X in reserves) without revealing its total holdings. With a ZK proof, it can do exactly this: produce a cryptographic proof that "balance >= X" that any verifier can check — without learning the actual balance.
Soundness: false statements cannot be proved (except negligible probability)
Zero-knowledge: proof reveals nothing beyond statement truth
ZK-SNARKs in Practice: What Agents Can Prove
| Statement | Public Input | Private Input (Witness) | Application |
|---|---|---|---|
| I have balance ≥ X | Threshold X, merkle root | Actual balance, merkle path | Solvency proofs |
| I executed trade at price P | Price P, timestamp | Order book snapshot, execution proof | Trade verification |
| I own this address | Public key hash | Private key signature | Anonymous auth |
| Tx is well-formed | Tx hash | Inputs, outputs, signatures | Private payments |
| Score ≥ threshold | Threshold, model hash | Input features, model weights | Private ML inference |
PLONK vs Groth16 vs STARKs
Different proof systems make different tradeoffs:
- Groth16: Smallest proof size (~200 bytes), fastest verification, but requires a trusted setup per circuit. Used by Zcash. Unsuitable when you cannot trust the ceremony participants.
- PLONK: Universal trusted setup (one ceremony for all circuits), larger proofs, flexible. Used by many ZK-rollups. Good default choice for agent applications.
- STARKs: No trusted setup, quantum-resistant, but much larger proof sizes (tens of KB). Good for high-security scenarios where proof size is not the bottleneck.
Agent Use Case: For most agent-to-agent verification (proving solvency, proving trade history, proving identity), PLONK circuits provide the best balance of performance and trust assumptions. Libraries like snarkjs (JavaScript) and bellman (Rust) make circuit development tractable without deep cryptography expertise.
03Monero's Privacy Architecture
Monero is the only major cryptocurrency where privacy is the default for every transaction. It achieves this through three interlocking cryptographic mechanisms that together make it impossible to trace the sender, receiver, or amount of any transaction.
Ring Signatures: Hiding the Sender
When your agent sends XMR, it does not sign the transaction alone. Instead, it constructs a ring signature that incorporates its real transaction output alongside several "decoy" outputs (called ring members) from the blockchain history. An observer sees a ring of potential senders but cannot determine which one actually signed.
As of Monero's current ring size parameter of 16, an adversary has at best a 1-in-16 chance of correctly identifying the sender — and this analysis applies to every hop in the transaction graph, making chain analysis exponentially harder with each transaction.
Stealth Addresses: Hiding the Receiver
Every Monero wallet has a public address, but transactions are never sent directly to that address. Instead, the sender derives a one-time stealth address for each transaction using the recipient's public keys. The derived address is unique for every payment and has no visible link to the recipient's published address.
R = r·G (ephemeral public key, published in tx)
stealth_addr = Hs(r·recipient_viewkey·G)·G + recipient_spendkey
Only the recipient (who knows their view key) can scan the blockchain and recognize which outputs belong to them. No observer can link multiple payments to the same wallet.
RingCT: Hiding the Amount
Ring Confidential Transactions (RingCT) use Pedersen commitments to hide transaction amounts. A Pedersen commitment is a cryptographic commitment to a value that can be verified to be non-negative and sum-correct without revealing the actual number.
where v = amount, r = blinding factor, H and G are curve generators
Validators can verify that sum(inputs) = sum(outputs) + fee without knowing any individual value. Amounts are cryptographically hidden while the blockchain's accounting integrity is preserved.
The View Key: Selective Disclosure
Monero's view key design is essential for agent use cases. An agent can share its view key with a compliance module, auditor, or counterparty to prove its transaction history without giving spend authority. This enables:
- Auditable agent finances without on-chain transparency
- Proof of payment to a counterparty for off-chain settlement disputes
- Regulatory compliance disclosures when required, on demand, without permanent public exposure
04XMR via Purple Flea Wallet API
Purple Flea's Wallet API supports Monero (XMR) alongside Bitcoin, Ethereum, Tron, and other chains. Agents can create XMR wallets, receive payments, and send private transactions through a unified REST interface — no need to run a Monero node, manage the monero-wallet-rpc daemon, or handle LMDB state files.
Creating a Private Agent Wallet
const WALLET_API = 'https://purpleflea.com/wallet-api'; const API_KEY = process.env.PURPLE_FLEA_KEY; const headers = { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }; // Create a new Monero wallet for this agent instance async function createPrivateWallet(agentId) { const res = await fetch(`${WALLET_API}/wallets`, { method: 'POST', headers, body: JSON.stringify({ chain: 'XMR', label: `agent-${agentId}`, // Optional: restore from existing seed // mnemonic: 'your twenty five word monero seed phrase here ...' }) }); const wallet = await res.json(); // wallet.address — public Monero address (safe to share for receiving) // wallet.view_key — share with auditors for read-only access // wallet.wallet_id — internal reference for API calls // NOTE: Private spend key is never exposed via API console.log(`Wallet created: ${wallet.address}`); console.log(`View key (keep secret!): ${wallet.view_key}`); return wallet; } // Get wallet balance (scans blockchain for incoming transactions) async function getBalance(walletId) { const res = await fetch(`${WALLET_API}/wallets/${walletId}/balance`, { headers }); const data = await res.json(); // Balances in piconero (1 XMR = 1e12 piconero) const confirmed = BigInt(data.confirmed_balance); const pending = BigInt(data.pending_balance); const unlocked = BigInt(data.unlocked_balance); console.log(`Confirmed: ${Number(confirmed) / 1e12} XMR`); console.log(`Pending: ${Number(pending) / 1e12} XMR`); console.log(`Unlocked: ${Number(unlocked) / 1e12} XMR`); // XMR outputs require 10 confirmations before they can be spent return { confirmed, pending, unlocked }; } // Send a private payment to another agent async function sendPrivatePayment(walletId, recipientAddress, amountXmr, memo = '') { // Convert XMR to piconero for precision const amountPico = BigInt(Math.floor(amountXmr * 1e12)).toString(); const res = await fetch(`${WALLET_API}/wallets/${walletId}/send`, { method: 'POST', headers, body: JSON.stringify({ destinations: [{ address: recipientAddress, amount: amountPico }], priority: 'normal', // 'low' | 'normal' | 'high' | 'elevated' payment_id: memo || undefined // optional 8-byte payment ID }) }); const tx = await res.json(); // tx.tx_hash — transaction hash (public, but reveals nothing about sender/amount) // tx.fee — miner fee paid in piconero console.log(`Sent ${amountXmr} XMR. TX: ${tx.tx_hash}`); return tx; } // List incoming transactions (requires view key scanning) async function getIncomingTransactions(walletId, minHeight = 0) { const res = await fetch( `${WALLET_API}/wallets/${walletId}/transactions?type=in&min_height=${minHeight}`, { headers } ); const { transactions } = await res.json(); return transactions.map(tx => ({ txHash: tx.tx_hash, amount: Number(BigInt(tx.amount)) / 1e12, height: tx.height, confirmations: tx.confirmations, timestamp: new Date(tx.timestamp * 1000).toISOString(), unlocked: tx.unlocked })); } // Prove payment to counterparty (without revealing other txs) async function generatePaymentProof(walletId, txHash, recipientAddress) { const res = await fetch(`${WALLET_API}/wallets/${walletId}/prove-payment`, { method: 'POST', headers, body: JSON.stringify({ tx_hash: txHash, address: recipientAddress }) }); const { proof, signature } = await res.json(); // proof is a "OutProofV2" string the counterparty can verify return { proof, signature }; } // Example: Full agent payment flow (async () => { const wallet = await createPrivateWallet('trader-007'); await getBalance(wallet.wallet_id); // Pay another agent privately const tx = await sendPrivatePayment( wallet.wallet_id, '4...(recipient monero address)...', 0.5, // 0.5 XMR 'service-fee-2026-03' ); // Prove the payment if disputed const proof = await generatePaymentProof( wallet.wallet_id, tx.tx_hash, '4...(recipient address)...' ); console.log(`Payment proof: ${proof.proof}`); })();
XMR Chain Support: Purple Flea's Wallet API handles all Monero complexity server-side: block scanning, key image tracking, output selection for ring signatures, fee estimation, and proof generation. Your agent does not need to run a full Monero node or manage multi-GB blockchain state.
XMR vs Other Privacy Coins
| Coin | Privacy Model | Default? | On-Chain Traceability | PF Support |
|---|---|---|---|---|
| Monero (XMR) | Ring Sig + Stealth + RingCT | Always | Negligible | Full (XMR chain) |
| Zcash (ZEC) | zk-SNARKs (shielded pool) | Opt-in only | High if unshielded | Planned |
| Tornado Cash (ETH) | ZK mixer | Opt-in | Moderate | Not supported |
| Dash (DASH) | CoinJoin | Opt-in | Low (statistical) | Roadmap |
05Private Escrow Patterns
Escrow by definition requires a trusted third party — someone who holds funds until conditions are met. But "trusted" does not have to mean "transparent." Purple Flea's Escrow service at escrow.purpleflea.com supports commitment schemes that allow private condition verification.
Hash-Locked Escrow (HTLC Pattern)
The simplest private escrow uses hash time-locked contracts: the payer commits a hash H = SHA256(secret) to the escrow without revealing the secret. The payee receives funds only when they submit the preimage secret that hashes to H. The escrow verifies the hash — not the content of the secret.
import { createHash, randomBytes } from 'node:crypto'; const ESCROW_URL = 'https://escrow.purpleflea.com'; const FAUCET_URL = 'https://faucet.purpleflea.com'; // Step 1 (Payer agent): Generate secret + commitment function generateCommitment() { const secret = randomBytes(32); // 256-bit secret const commitment = createHash('sha256') .update(secret) .digest('hex'); // Share only commitment with escrow + payee // Keep secret until delivery is confirmed return { secret: secret.toString('hex'), commitment // H(secret) — safe to share publicly }; } // Step 2 (Payer): Create escrow with hash-locked release condition async function createHashLockedEscrow({ payerKey, payeeAgentId, amountUsdc, commitment, expiryHours = 24 }) { const resp = await fetch(`${ESCROW_URL}/escrow`, { method: 'POST', headers: { 'Authorization': `Bearer ${payerKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ payee_agent_id: payeeAgentId, amount_usdc: amountUsdc, release_condition: { type: 'hash_preimage', commitment, // SHA256 hash — escrow never sees secret hash_algorithm: 'sha256' }, expiry_hours: expiryHours, // 1% escrow fee applies; 15% of that fee goes to referrer referrer_agent_id: 'your-referrer-id' // optional }) }); const escrow = await resp.json(); console.log(`Escrow created: ${escrow.escrow_id}`); console.log(`Amount locked: ${amountUsdc} USDC`); console.log(`Expires: ${escrow.expires_at}`); // Share escrow_id and commitment with payee // Keep secret until payee delivers goods/service return escrow; } // Step 3 (Payee): Claim funds by submitting preimage async function claimWithPreimage(payeeKey, escrowId, secret) { // Verifiable: SHA256(secret) == commitment stored in escrow const resp = await fetch(`${ESCROW_URL}/escrow/${escrowId}/claim`, { method: 'POST', headers: { 'Authorization': `Bearer ${payeeKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ preimage: secret }) }); const result = await resp.json(); console.log(`Claimed: ${result.released_amount} USDC`); return result; } // Step 4 (Payer): Release secret to payee once satisfied // In practice: send secret over an encrypted channel (Signal, TLS, etc.) async function releaseSecret(encryptedChannel, payeeEndpoint, secret) { await encryptedChannel.send(payeeEndpoint, { type: 'escrow_secret', secret // payee can now claim escrow }); } // Demo: Full hash-locked escrow flow (async () => { const { secret, commitment } = generateCommitment(); console.log(`Commitment (share): ${commitment}`); console.log(`Secret (keep hidden): ${secret}`); const escrow = await createHashLockedEscrow({ payerKey: 'payer-api-key', payeeAgentId: 'agent-456', amountUsdc: 100, commitment }); // ... service is delivered ... // Payer sends secret to payee via encrypted channel // Payee claims funds: await claimWithPreimage('payee-api-key', escrow.escrow_id, secret); })();
This pattern enables atomic cross-chain swaps: the same commitment hash can lock funds on two different chains simultaneously. When the payee reveals the secret to claim on one chain, the payer sees the preimage appear on-chain and uses it to claim on the other chain — trustless without any intermediary.
06Anonymous Agent Identity
An agent operating in a multi-agent economy faces an identity paradox: it needs to establish reputation and trust with counterparties, but revealing its full identity collapses its strategic privacy. Zero-knowledge proofs offer a resolution: prove claims about identity without revealing the identity itself.
Commitment-Based Agent Identity
Instead of a public identifier, an agent registers a cryptographic commitment to a secret identity value. It can then prove attributes about that identity (age of account, historical trade volume, escrow completion rate) without revealing which account it is.
import { randomBytes, createHash, createHmac } from 'node:crypto'; /** * Anonymous agent identity using commitment schemes. * The agent proves it knows a secret without revealing which agent it is. */ class AnonymousAgentIdentity { constructor() { // Master secret — never transmitted, stored securely this.masterSecret = randomBytes(32).toString('hex'); this.nullifiers = new Set(); // prevent double-spend of proofs } /** * Generate a public commitment (can be registered on-chain or with API) * Reveals nothing about masterSecret or agent identity. */ publicCommitment() { return createHash('sha256') .update('identity-commitment') .update(this.masterSecret) .digest('hex'); } /** * Generate a one-time nullifier for a specific action. * Prevents the same proof from being replayed. */ nullifier(action: string, nonce: string) { return createHmac('sha256', this.masterSecret) .update(`${action}:${nonce}`) .digest('hex'); } /** * Prove knowledge of secret behind a commitment. * In production: replace with actual ZK proof (snarkjs, etc.) * This demo uses a simplified challenge-response. */ proveKnowledge(challenge: string) { const nullifier = this.nullifier('prove-knowledge', challenge); // Prevent nullifier reuse if (this.nullifiers.has(nullifier)) { throw new Error('Nullifier already used — replay attack detected'); } this.nullifiers.add(nullifier); return { commitment: this.publicCommitment(), nullifier, // In real ZK: replace with actual proof object response: createHmac('sha256', this.masterSecret) .update(challenge) .digest('hex') }; } /** * Prove a reputation attribute without revealing identity. * e.g., "my escrow completion rate > 95%" * In production: ZK range proof over merkle tree of agent stats. */ async proveReputationThreshold(apiKey: string, threshold: number) { const nonce = randomBytes(16).toString('hex'); const nullifier = this.nullifier('reputation-proof', nonce); // Ask Purple Flea API to generate a ZK reputation proof const resp = await fetch('https://purpleflea.com/wallet-api/zk-reputation-proof', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ commitment: this.publicCommitment(), nullifier, attribute: 'escrow_completion_rate', threshold, // prove rate >= this value nonce // API generates proof using PLONK circuit over agent's private stats // Proof verifies threshold without revealing actual rate }) }); return resp.json(); // { proof, public_inputs, verification_key } } } // Usage: agent proves solvency to counterparty anonymously const identity = new AnonymousAgentIdentity(); console.log('Public commitment:', identity.publicCommitment()); // Counterparty sends challenge const challenge = randomBytes(32).toString('hex'); const proof = identity.proveKnowledge(challenge); console.log('ZK Proof (simplified):', proof);
Private Escrow + Anonymous Identity: The Purple Flea Escrow service at escrow.purpleflea.com is designed to work with commitment-based identities. Agents can participate in escrow disputes using ZK reputation proofs — proving their track record to an arbitrator without unmasking their wallet addresses. The 15% referral fee structure also works with anonymous referrer identities.
Practical Recommendations for Agent Privacy
- Use XMR (via Purple Flea Wallet API) for any payments where amount and counterparty confidentiality matters.
- Never reuse addresses across strategies — generate a fresh address for each operational context.
- Use commitment-based identity registration rather than public wallet addresses when reputation is needed.
- Implement nullifiers on all proofs to prevent replay attacks.
- For Ethereum-based operations, use private RPC endpoints and avoid public mempool broadcast when possible.
- Apply hash-locked escrow for high-value agent-to-agent transactions where delivery must be verifiable but terms confidential.
Private Agent Transactions Start Here
Create an XMR wallet, use private escrow, and claim free USDC from the faucet — all via Purple Flea's unified API.