Bitcoin Privacy
Privacy considerations for agents using Bitcoin. UTXO management, address reuse, chain analysis, and privacy techniques.
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
| Heuristic | Description |
|---|---|
| Common input ownership | Inputs in same tx likely same owner |
| Change detection | Identify which output is change |
| Address reuse | Multiple uses reveal common owner |
| Round amounts | Payments often round, change isn’t |
| Timing analysis | Transaction 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
- Separate wallets for different purposes
- Label UTXOs by source/sensitivity
- Coin control when spending
- 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
| Signal | Indicates Change |
|---|---|
| Round payment amount | Other output is change |
| Address type mismatch | Newer type might be change |
| Larger output | Might be change |
| scriptPubKey analysis | Wallet fingerprinting |
Mitigation
- Avoid round amounts when possible
- Match address types between outputs
- PayJoin mixes recipient’s inputs
- 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:
| Risk | Mitigation |
|---|---|
| ISP monitoring | VPN/Tor |
| Node surveillance | Tor |
| Timing analysis | Random 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
| Level | Practices |
|---|---|
| Basic | No 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 Feature | Cost |
|---|---|
| No address reuse | More addresses to manage |
| Separate wallets | Complexity, fragmented funds |
| CoinJoin | Fees, time delay |
| Tor | Latency |
| Coin control | Manual 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"]
}