Menu
Bitcoin Intermediate 12 min read

Bitcoin Privacy

Privacy considerations for agents using Bitcoin. UTXO management, address reuse, chain analysis, and privacy techniques.

privacy utxo chain-analysis coinjoin addresses

Bitcoin Privacy

Bitcoin is pseudonymous, not anonymous. All transactions are public on the blockchain. Understanding privacy is critical for agents handling sensitive operations.

The Privacy Challenge

What’s Public

  • All transactions ever made
  • All addresses and their balances
  • Transaction amounts
  • Transaction timing
  • Input/output relationships

What’s Private

  • Real-world identities (until linked)
  • IP addresses (with proper setup)
  • Future addresses (with HD wallets)

Privacy Threats

Chain Analysis

Companies analyze blockchain to link addresses:

Address A → Transaction → Address B
     ↑                         ↓
  Exchange KYC              Merchant
     ↓                         ↓
  Real Identity            Purchase Data

Common Heuristics

HeuristicDescription
Common input ownershipInputs in same tx likely same owner
Change detectionIdentify which output is change
Address reuseMultiple uses reveal common owner
Round amountsPayments often round, change isn’t
Timing analysisTransaction patterns reveal behavior

UTXO Management

The Problem

Each UTXO has a history. Spending UTXOs together links their histories.

UTXO A (from exchange) ─┐
                        ├─→ Transaction → Combined history
UTXO B (private income) ─┘

Best Practices

  1. Separate wallets for different purposes
  2. Label UTXOs by source/sensitivity
  3. Coin control when spending
  4. Don’t consolidate sensitive UTXOs

UTXO Labeling

class LabeledUTXO:
    txid: str
    vout: int
    value: int
    label: str  # "exchange", "payment", "private"
    sensitivity: str  # "low", "medium", "high"

def select_utxos(utxos, amount, max_sensitivity="medium"):
    """Select UTXOs without exceeding sensitivity threshold"""
    eligible = [u for u in utxos if u.sensitivity <= max_sensitivity]
    return coin_selection(eligible, amount)

Address Reuse

Why It’s Bad

Reusing addresses:

  • Links all transactions to same entity
  • Reveals total balance received
  • Enables payment correlation
  • Reduces cryptographic security (minor)

Best Practice

One address per transaction:

def get_payment_address(wallet):
    """Always return fresh address"""
    return wallet.derive_next_address()

# Never reuse
address_1 = get_payment_address(wallet)  # For invoice A
address_2 = get_payment_address(wallet)  # For invoice B

Change Output Privacy

The Problem

Change reveals which output you control:

Input: 1.5 BTC
├─ Output 1: 0.3 BTC → Recipient (payment)
└─ Output 2: 1.19 BTC → You (change)

Attacker knows you control the 1.19 BTC address.

Detection Methods

SignalIndicates Change
Round payment amountOther output is change
Address type mismatchNewer type might be change
Larger outputMight be change
scriptPubKey analysisWallet fingerprinting

Mitigation

  1. Avoid round amounts when possible
  2. Match address types between outputs
  3. PayJoin mixes recipient’s inputs
  4. Batch payments obscure individual amounts

Privacy Techniques

Multiple Wallets

Separate funds by purpose:

  • Exchange wallet (KYC’d)
  • Payment wallet (merchant receipts)
  • Private wallet (no links)

Coin Selection

Control which UTXOs are spent:

def privacy_aware_selection(utxos, amount, privacy_level):
    if privacy_level == "high":
        # Single UTXO if possible
        single = find_single_utxo(utxos, amount)
        if single:
            return [single]

    # Group by source
    grouped = group_by_label(utxos)

    # Select from single group
    for group in grouped:
        if sum_value(group) >= amount:
            return select_from_group(group, amount)

    # Must mix sources - lower privacy
    return standard_selection(utxos, amount)

CoinJoin

Multiple users combine transactions:

User A: Input A → Output A'
User B: Input B → Output B'
User C: Input C → Output C'

Combined transaction with equal outputs makes
it unclear which input → which output

Services: Wasabi Wallet, JoinMarket

PayJoin (P2EP)

Recipient adds input to your payment:

Normal:
Your Input → Payment Output + Change

PayJoin:
Your Input + Recipient Input → Combined Output

Breaks “common input ownership” heuristic.

Network Privacy

IP Address Exposure

Nodes see your IP when you broadcast:

RiskMitigation
ISP monitoringVPN/Tor
Node surveillanceTor
Timing analysisRandom delays

Tor Integration

# Bitcoin Core over Tor
bitcoind -proxy=127.0.0.1:9050

# mempool.space onion
# http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion

For Agents

Privacy Checklist

  • Never reuse addresses
  • Label UTXOs by source
  • Use coin control for spending
  • Separate wallets for different purposes
  • Route through Tor when possible
  • Avoid round payment amounts
  • Match address types in transactions

Privacy Levels

LevelPractices
BasicNo address reuse, HD wallet
Moderate+ Coin control, UTXO labeling
High+ Separate wallets, Tor, CoinJoin
Maximum+ PayJoin, fresh nodes, time delays

When Privacy Matters

  • Agent payments: Don’t link agent wallets to identity
  • Service fees: Obscure operational patterns
  • User funds: Protect user transaction history
  • Competitive: Hide strategic transactions

When Privacy is Secondary

  • Audited funds: Transparency required
  • Tax compliance: Clear records needed
  • Public donations: Transparency is feature

Trade-offs

Privacy FeatureCost
No address reuseMore addresses to manage
Separate walletsComplexity, fragmented funds
CoinJoinFees, time delay
TorLatency
Coin controlManual effort

Machine-Readable Summary

{
  "topic": "bitcoin-privacy",
  "threats": ["chain-analysis", "address-reuse", "change-detection", "ip-exposure"],
  "techniques": ["coin-control", "multiple-wallets", "coinjoin", "payjoin", "tor"],
  "best_practices": [
    "no-address-reuse",
    "utxo-labeling",
    "coin-selection",
    "output-type-matching"
  ],
  "privacy_levels": ["basic", "moderate", "high", "maximum"]
}