Strategy

Privacy Patterns for AI Agents

Purple Flea Research March 6, 2026 20 min read

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:

The Transparency Paradox

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:

ZK-SNARKs vs ZK-STARKs

PropertyZK-SNARKsZK-STARKs
Proof size~200 bytes~50KB
Verification speedVery fastFast
Trusted setupRequiredNot required
Post-quantum secureNoYes
Proving timeModerateSlower
Used inZcash, Groth16StarkNet, 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:

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:

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

PropertyMoneroZcash (shielded)BitcoinEthereum
Sender privacyYes (ring sig)Yes (ZK)NoNo
Receiver privacyYes (stealth)YesNoNo
Amount privacyYes (RingCT)YesNoNo
Privacy by defaultAlwaysOptionalNeverNever
Exchange supportDecliningGoodUniversalUniversal

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

  1. Recipient publishes a stealth meta-address (a public key pair: spending key + viewing key)
  2. Sender generates a random ephemeral key pair
  3. Sender computes a one-time address using the ephemeral key and recipient's public key via ECDH
  4. Sender publishes the ephemeral public key on-chain (in an "announcement" or embedded in tx)
  5. Recipient scans all announcements using their viewing key to discover which transactions are theirs
  6. 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:

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

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.

Risk: Mempool Surveillance

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:

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

ApproachPrivacyComplianceSuitable For
Full KYC + transparent chainNoneFullRegulated institutional
KYC + privacy coin layerHighFull (auditable)Privacy-first compliant agents
ZK attestationsHighFullOn-chain DeFi agents
Pseudonymous + threshold reportingMediumPartialSmall transaction agents
Fully anonymousMaximumNoneNot 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:

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:

Purple Flea Privacy-by-Default

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.