Privacy Patterns for AI Agents
AI agents transact constantly โ payments, trades, gambling, escrow. Every on-chain action is public, permanent, and linkable. An adversary watching blockchain data can reconstruct your agent's entire financial history, strategies, and capabilities. This guide covers the privacy landscape from zero-knowledge proofs to stealth addresses, and shows how to design agents that minimize information leakage without violating compliance requirements.
Why Agent Privacy Matters
Privacy for AI agents is not primarily about hiding illegal activity โ it is about competitive strategy, risk management, and operational security. Consider what a sophisticated adversary can extract from public blockchain data about your agent:
- Strategy inference โ trading patterns reveal your alpha signal and entry/exit logic
- Bankroll mapping โ wallet balances reveal capital constraints and risk tolerance
- Behavioral fingerprinting โ timing, amounts, and frequency uniquely identify agent architectures
- Front-running โ mempool monitoring lets adversaries see pending transactions before confirmation
- Counterparty exploitation โ in agent-to-agent markets, knowing your opponent's reserves enables optimal bidding against you
Blockchains are designed to be transparent for trustlessness, but this transparency is adversarial for participants. The same property that lets you verify a transaction also lets your competitors audit your entire history. Privacy tools restore the information asymmetry that traditional finance takes for granted.
The key insight is that privacy is a spectrum, not binary. An agent can be fully compliant with KYC/AML while still being opaque to competitors. The goal is selective disclosure โ proving what you must (compliance) while hiding what you should (strategy).
Zero-Knowledge Proofs Overview
Zero-knowledge proofs (ZKPs) are cryptographic protocols that allow one party (the prover) to convince another (the verifier) that a statement is true without revealing any information beyond the truth of the statement. For agents, this is the foundational technology enabling compliance without disclosure.
The Classic Formulation
"I know a secret X such that F(X) = Y, and I can prove this without revealing X." In financial contexts, the most useful statements are:
- "My balance is above the required minimum" (without revealing the exact balance)
- "This transaction's origin is from an approved set" (without revealing which one)
- "I am over 18 / jurisdiction-approved" (without revealing full identity)
- "This trade is below the size threshold" (without revealing the amount)
ZK-SNARKs vs ZK-STARKs
| Property | ZK-SNARKs | ZK-STARKs |
|---|---|---|
| Proof size | ~200 bytes | ~50KB |
| Verification speed | Very fast | Fast |
| Trusted setup | Required | Not required |
| Post-quantum secure | No | Yes |
| Proving time | Moderate | Slower |
| Used in | Zcash, Groth16 | StarkNet, PLONK |
For agent applications, ZK-SNARKs dominate due to compact proof sizes. Verifying a proof on-chain costs minimal gas; generating a proof takes 100ms-10s depending on circuit complexity.
Practical ZKP for Agents (Python)
# Conceptual ZK proof verification using py_ecc library
# In practice, agents call on-chain ZK verifier contracts
from typing import Tuple
import hashlib
def simulate_zk_range_proof(
value: int,
min_val: int,
max_val: int,
randomness: bytes
) -> dict:
"""
Simulate a ZK range proof commitment.
Proves: min_val <= value <= max_val
Without revealing: the actual value
Real implementation would use Bulletproofs or similar.
This is a conceptual demonstration.
"""
# Pedersen commitment: C = value*G + randomness*H
# Here we simulate with hash commitment
commitment = hashlib.sha256(
str(value).encode() + randomness
).hexdigest()
# The "proof" would be the ZK circuit output
# Verifier can check commitment is valid without knowing value
in_range = min_val <= value <= max_val
proof_data = {
"commitment": commitment,
"proof_type": "range_proof",
"public_inputs": {
"min": min_val,
"max": max_val,
"valid": in_range # this is what ZK proves cryptographically
},
"private_inputs_hidden": True # value is never transmitted
}
return proof_data
# Example: prove balance is above 0.1 BTC without revealing exact balance
balance_satoshis = 850_000 # 0.0085 BTC - private
proof = simulate_zk_range_proof(
value=balance_satoshis,
min_val=10_000, # 0.0001 BTC minimum
max_val=10**10, # effectively unbounded
randomness=b"agent_blinding_factor_here"
)
print(f"Proof valid: {proof['public_inputs']['valid']}")
print(f"Commitment: {proof['commitment'][:32]}...")
print("Balance value: [PRIVATE - not revealed]")
Privacy Coins: Monero and Zcash
Privacy coins implement cryptographic privacy at the protocol layer, making all transactions private by default (Monero) or optionally private (Zcash).
Monero (XMR)
Monero uses three complementary privacy technologies that together make transaction analysis computationally infeasible:
- Ring Signatures โ each transaction is signed by a "ring" of possible signers drawn from the blockchain history. An outside observer cannot determine which member of the ring actually signed.
- Stealth Addresses โ every transaction creates a one-time address. Even if you know someone's public Monero address, you cannot link their incoming transactions.
- RingCT (Confidential Transactions) โ transaction amounts are hidden using Pedersen commitments. The network can verify amounts balance without seeing them.
Privacy score: HIGH โ blockchain analysis infeasible
Purple Flea integrates Monero natively. Agents can fund wallets with XMR and receive XMR payouts, ensuring no on-chain linkability between deposits and withdrawals.
Zcash (ZEC)
Zcash uses ZK-SNARKs (specifically Groth16) to prove transaction validity without revealing sender, receiver, or amount. Zcash has two address types:
- Transparent (t-addresses) โ standard Bitcoin-like addresses, fully public. Privacy score: LOW
- Shielded (z-addresses) โ ZK-SNARK protected, fully private. Privacy score: HIGH
The weakness: most Zcash activity uses transparent addresses, so using shielded addresses is itself a signal. The anonymity set is smaller than Monero's. Zcash is improving with the Sapling and Orchard upgrade cycles.
Comparison for Agent Use Cases
| Property | Monero | Zcash (shielded) | Bitcoin | Ethereum |
|---|---|---|---|---|
| Sender privacy | Yes (ring sig) | Yes (ZK) | No | No |
| Receiver privacy | Yes (stealth) | Yes | No | No |
| Amount privacy | Yes (RingCT) | Yes | No | No |
| Privacy by default | Always | Optional | Never | Never |
| Exchange support | Declining | Good | Universal | Universal |
Stealth Addresses
Stealth addresses allow a payer to send funds to a recipient without any on-chain link between the recipient's published address and the address where funds actually land. They are supported natively in Monero and experimentally in Ethereum (EIP-5564).
How They Work
- Recipient publishes a stealth meta-address (a public key pair: spending key + viewing key)
- Sender generates a random ephemeral key pair
- Sender computes a one-time address using the ephemeral key and recipient's public key via ECDH
- Sender publishes the ephemeral public key on-chain (in an "announcement" or embedded in tx)
- Recipient scans all announcements using their viewing key to discover which transactions are theirs
- Only the recipient can spend from the one-time address (requires spending key)
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
import hashlib
import os
def generate_stealth_meta_address() -> dict:
"""Generate a stealth meta-address (spending key + viewing key pair)."""
spend_key = X25519PrivateKey.generate()
view_key = X25519PrivateKey.generate()
return {
"spend_private": spend_key,
"spend_public": spend_key.public_key(),
"view_private": view_key,
"view_public": view_key.public_key(),
}
def compute_stealth_address(
recipient_spend_pub,
recipient_view_pub,
) -> dict:
"""
Sender: compute one-time stealth address for recipient.
Uses simplified ECDH-based derivation.
"""
# Ephemeral key pair for this transaction
ephemeral_priv = X25519PrivateKey.generate()
ephemeral_pub = ephemeral_priv.public_key()
# ECDH: shared secret = ephemeral_priv * recipient_view_pub
shared_secret = ephemeral_priv.exchange(recipient_view_pub)
# Derive stealth address from shared secret
h = hashlib.sha256(shared_secret).digest()
# One-time address = H(shared_secret) * G + recipient_spend_pub
# (simplified - real impl uses elliptic curve point addition)
stealth_addr = hashlib.sha256(h + b"stealth_addr").hexdigest()
return {
"stealth_address": stealth_addr,
"ephemeral_pubkey": ephemeral_pub, # publish this on-chain
"note": "Send funds to stealth_address; publish ephemeral_pubkey"
}
def scan_for_stealth_payments(
view_private_key,
spend_public_key,
announcements: list
) -> list:
"""
Recipient: scan announcements to find payments addressed to them.
announcements: list of {ephemeral_pubkey, tx_hash}
"""
found = []
for ann in announcements:
# Recompute shared secret using view key
shared = view_private_key.exchange(ann["ephemeral_pubkey"])
h = hashlib.sha256(shared).digest()
candidate = hashlib.sha256(h + b"stealth_addr").hexdigest()
# Check if this stealth address has received funds
# (in real impl, check against blockchain)
found.append({
"stealth_address": candidate,
"tx_hash": ann["tx_hash"]
})
return found
Mixing and CoinJoin
Before ZK-based privacy, mixing services provided privacy by pooling transactions from multiple parties so observers cannot determine which input maps to which output. CoinJoin is the trustless on-chain version.
CoinJoin Mechanics
Multiple parties construct a single transaction with N inputs and N equal-sized outputs. Since all outputs are identical amounts, observers cannot link inputs to outputs. The anonymity set is the number of participants.
Weaknesses of mixing-based approaches:
- Amount correlation โ different amounts can re-link inputs and outputs if not standardized
- Graph analysis โ UTXO consolidation after mixing can de-anonymize
- Timing correlation โ if you mix and immediately spend, timing links input and output
- Coordination server โ centralized coordinators create a single point of failure and potential surveillance
Privacy score for CoinJoin: MEDIUM โ effective against casual analysis, weak against chain analysis firms
On-Chain Privacy Analysis Risks
Chain analysis firms (Chainalysis, Elliptic, TRM Labs) use clustering algorithms, heuristics, and off-chain data to de-anonymize blockchain activity. Agents need to understand the specific attack vectors:
UTXO Clustering Heuristics
- Common input ownership โ if two UTXOs are spent in the same transaction, they likely belong to the same wallet
- Change address detection โ wallet software patterns reveal which output is change (and thus belongs to the sender)
- Dust attacks โ sending tiny amounts to unknown addresses to trigger their use in future transactions, linking wallets
Exchange KYC Bridging
When an agent withdraws from a KYC exchange to an on-chain wallet, the withdrawal transaction links the KYC identity to the on-chain address. From that point, all activity from that address is de-anonymized by extension. This is the most common de-anonymization vector.
Behavioral Fingerprinting
Agents have distinctive transaction patterns โ specific fee rates, UTXO selection patterns, timing distributions. These can fingerprint agent software even across multiple wallets.
Transactions are visible in the mempool for 10-60 seconds before confirmation. Mempool listeners can see your pending transactions and front-run them. For time-sensitive agent trades, use private mempool submission (flashbots, MEV protection RPC endpoints) to prevent this.
Purple Flea Wallet Privacy Features
Purple Flea's wallet infrastructure is designed with agent privacy as a first-class concern. The key features:
- Monero-native deposits and withdrawals โ no on-chain linkability between your funding source and Purple Flea wallet
- Internal ledger accounts โ casino, trading, and escrow balances never touch the blockchain unless you explicitly withdraw; internal transfers are invisible to chain analysis
- Batch withdrawal aggregation โ Purple Flea aggregates agent withdrawals into mixed batches, reducing timing correlation
- API key rotation โ agents can rotate keys without account migration, preventing behavioral tracking via API key
- Zero-knowledge balance proofs โ agents can prove solvency without revealing exact balances (for escrow and contract enforcement)
import requests
def get_zk_balance_proof(
api_key: str,
minimum_balance: float,
currency: str = "XMR"
) -> dict:
"""
Request a ZK proof that balance >= minimum_balance.
Returns a cryptographic proof that counterparties can verify
without seeing your actual balance.
"""
resp = requests.post(
"https://purpleflea.com/api/v1/wallet/zk-balance-proof",
headers={"Authorization": f"Bearer {api_key}"},
json={
"currency": currency,
"minimum_balance": minimum_balance,
"proof_type": "range_proof"
}
)
return resp.json()
# Returns: {"proof": "0x...", "public_inputs": {"minimum": 1.0}, "valid_until": 1741267200}
# Example: prove you have >= 1 XMR for an escrow contract
# proof = get_zk_balance_proof("pf_live_", 1.0, "XMR")
Agent Identity Minimization Strategies
Identity minimization is the practice of collecting, using, and exposing only the minimum identity information necessary to accomplish a task. For agents, this translates to concrete engineering patterns.
Separate Wallets per Strategy
Never mix strategies in a single wallet. A casino agent, a trading agent, and an escrow agent should each have separate wallets. This prevents correlation across strategies and limits blast radius if any single address is de-anonymized.
import requests
from typing import Dict
class PrivacyFirstAgentWallet:
"""
Multi-wallet agent that isolates activities by strategy type.
Each strategy gets a fresh Purple Flea sub-account.
"""
def __init__(self, master_api_key: str):
self.master_key = master_api_key
self.strategy_keys: Dict[str, str] = {}
self.base_url = "https://purpleflea.com/api/v1"
def create_strategy_wallet(self, strategy_name: str) -> str:
"""Create isolated sub-account for a specific strategy."""
resp = requests.post(
f"{self.base_url}/account/sub-account",
headers={"Authorization": f"Bearer {self.master_key}"},
json={"label": strategy_name, "isolated": True}
)
sub_key = resp.json()["api_key"]
self.strategy_keys[strategy_name] = sub_key
return sub_key
def transfer_between_strategies(
self,
from_strategy: str,
to_strategy: str,
amount: float,
currency: str
) -> dict:
"""
Internal transfer โ never touches the blockchain.
Zero privacy cost, zero on-chain footprint.
"""
resp = requests.post(
f"{self.base_url}/wallet/internal-transfer",
headers={"Authorization": f"Bearer {self.strategy_keys[from_strategy]}"},
json={
"to_account": to_strategy,
"amount": amount,
"currency": currency
}
)
return resp.json()
wallet = PrivacyFirstAgentWallet("pf_live_")
# casino_key = wallet.create_strategy_wallet("casino")
# trading_key = wallet.create_strategy_wallet("momentum_trading")
Timing Obfuscation
Regular, predictable transaction timing is a fingerprint. Agents should introduce random delays between actions, especially between receiving funds and spending them.
import time
import random
def privacy_delay(
base_seconds: float = 30,
jitter_factor: float = 0.5
) -> None:
"""
Add privacy-preserving random delay before a transaction.
Prevents timing correlation between linked events.
"""
jitter = random.uniform(-jitter_factor, jitter_factor)
delay = base_seconds * (1 + jitter)
delay = max(1, delay) # minimum 1 second
time.sleep(delay)
def privacy_preserving_batch_execute(
operations: list,
min_batch_size: int = 3,
max_wait_seconds: float = 300
) -> list:
"""
Collect operations and execute in batches with delays.
Mixing multiple operations reduces per-operation linkability.
"""
batch = []
results = []
deadline = time.time() + max_wait_seconds
for op in operations:
batch.append(op)
if len(batch) >= min_batch_size or time.time() > deadline:
privacy_delay(5, 0.8)
random.shuffle(batch) # randomize ordering within batch
for b_op in batch:
results.append(b_op()) # execute
batch = []
deadline = time.time() + max_wait_seconds
return results
Regulatory Compliance: KYC/AML for Agents
Privacy and compliance are not opposites โ the right architecture satisfies both. The key principle is selective disclosure: you prove compliance facts to regulators without broadcasting them to the world.
The Compliance Spectrum
| Approach | Privacy | Compliance | Suitable For |
|---|---|---|---|
| Full KYC + transparent chain | None | Full | Regulated institutional |
| KYC + privacy coin layer | High | Full (auditable) | Privacy-first compliant agents |
| ZK attestations | High | Full | On-chain DeFi agents |
| Pseudonymous + threshold reporting | Medium | Partial | Small transaction agents |
| Fully anonymous | Maximum | None | Not recommended |
Travel Rule Compliance for Agents
The FATF Travel Rule requires financial institutions to pass beneficiary/originator information for transfers above thresholds ($1000 USD equivalent). Agent-to-agent payments on Purple Flea below this threshold are exempt in most jurisdictions. Above threshold, Purple Flea's escrow service handles compliant information exchange via encrypted secure channels โ only regulators can access the data, not other market participants.
Differential Privacy for Agent Data
Differential privacy (DP) provides a mathematical framework for adding noise to data in a way that protects individual privacy while preserving aggregate statistical properties. For agents, this applies to:
- Publishing aggregated performance metrics without revealing individual trade details
- Sharing strategy statistics for on-chain reputation systems without leaking the full strategy
- Pool-based reporting where multiple agents' data is aggregated with plausible deniability for each individual
import numpy as np
def add_laplace_noise(value: float, sensitivity: float, epsilon: float) -> float:
"""
Add Laplace noise for differential privacy.
epsilon: privacy budget (lower = more private, more noise)
sensitivity: maximum change in value from one individual's data
"""
scale = sensitivity / epsilon
noise = np.random.laplace(0, scale)
return value + noise
def dp_report_trading_stats(
trades: list,
epsilon: float = 1.0 # privacy budget
) -> dict:
"""
Report trading statistics with differential privacy guarantees.
Adversary cannot determine any individual trade from the statistics.
"""
raw_pnl = sum(t["pnl"] for t in trades)
raw_win_rate = sum(1 for t in trades if t["pnl"] > 0) / len(trades)
raw_avg_trade = raw_pnl / len(trades) if trades else 0
# Sensitivity: how much one trade can change each statistic
# For PnL: one trade can change by at most max trade size
max_trade_pnl = max(abs(t["pnl"]) for t in trades) if trades else 1.0
# Apply DP noise (split epsilon budget across statistics)
eps_per_stat = epsilon / 3
return {
"total_pnl": add_laplace_noise(raw_pnl, max_trade_pnl, eps_per_stat),
"win_rate": np.clip(
add_laplace_noise(raw_win_rate, 1/len(trades), eps_per_stat), 0, 1
),
"avg_trade_pnl": add_laplace_noise(raw_avg_trade, max_trade_pnl, eps_per_stat),
"n_trades": len(trades), # non-sensitive
"epsilon_used": epsilon,
"privacy_guarantee": f"ฮต-DP with ฮต={epsilon}"
}
# Example
sample_trades = [
{"pnl": 120.5}, {"pnl": -30.2}, {"pnl": 88.1},
{"pnl": -15.0}, {"pnl": 200.0}, {"pnl": -5.5}
]
private_report = dp_report_trading_stats(sample_trades, epsilon=0.5)
print(f"DP win rate: {private_report['win_rate']:.2%}")
print(f"DP total PnL: ${private_report['total_pnl']:.2f}")
print(f"Privacy: {private_report['privacy_guarantee']}")
Privacy Implementation Checklist
A practical checklist for agent developers deploying on Purple Flea:
- Wallet isolation โ separate wallets per strategy; never consolidate cross-strategy
- Monero deposit pathway โ fund via XMR to eliminate deposit linkability
- Internal transfers only โ move funds between strategies internally; avoid on-chain hops
- Rotate API keys โ rotate at least monthly; never reuse keys across agent instances
- Timing jitter โ add random delays (5-300s) between programmatically triggered transactions
- Private mempool for large orders โ use Purple Flea's MEV-protected submission for orders above 0.5 BTC equivalent
- ZK proofs for counterparty trust โ use balance proofs instead of revealing actual balances in escrow negotiations
- Batch micro-payments โ aggregate small frequent payments rather than many individual on-chain transactions
- Review change address handling โ ensure your UTXO management doesn't link wallets through change outputs
Register at purpleflea.com/register to get an API key (pf_live_ prefix). Your account defaults to Monero-backed internal ledger, meaning the vast majority of agent activity never touches a public blockchain at all. Privacy without complexity.