MSc
Bitcoin Address Clustering
Collapsing 334,177 Bitcoin addresses into 109,074 entities over the chain's first two years, using a heuristic chain tuned to avoid merging entities that are not the same one.
Bitcoin addresses are pseudonymous individually and leaky in aggregate: the way transactions are constructed reveals which addresses are controlled by the same entity. This builds the transaction graph for the chain’s first 115,000 blocks and applies a chain of ownership heuristics to it.
- Scope
- Blocks 0–115,000, January 2009 to February 2011
- Data
- blockchain.info block API
- Graph
- 559,528 nodes · 630,301 edges
- Explorer
- Streamlit + PyVis, local
- Repository
- VincenzoImp/bitcoin-address-clustering
The problem
Common-input-ownership – if two addresses fund the same transaction, one entity controls both – is the heuristic everybody quotes, and on its own it recovers very little. The rest of the signal is in change addresses: a payment usually has two outputs, one to the recipient and one back to the sender, and deciding which is which is where the real inference happens.
Every one of those inferences can be wrong, and the errors do not stay local. Merging two entities that are not the same entity does not produce one bad row; it welds two subgraphs together and corrupts every conclusion downstream.
What I built
The graph is transaction-centric: transactions are nodes, UTXOs are edges carrying the address and value, with synthetic nodes for coinbase and unspent outputs. It is assembled from the blockchain.info block API rather than from a node, with Spark handling the extraction and aggregation and the clustering itself running as a two-pass sweep in temporal order.
334,177
addresses
109,074
entities after clustering
67.4%
reduction
The heuristics are a chain, not a single rule: coinbase outputs grouped per miner, a special case for early Satoshi-era blocks, consolidation transactions, common-input-ownership on payments, and a family of five change-address tests tried in order: the same address appearing in input and output, unnecessary inputs, an output address never seen before, round-number amounts, and address reuse. Transactions that look like CoinJoins are detected and excluded from the heuristics, with a single round of taint analysis run instead.
A Streamlit app with a PyVis rendering lets you pick an entity and see its subgraph.
Hard parts
Choosing precision and paying for it. The notebook states the design position directly: the algorithm aims to reduce false positives as much as possible, avoiding the merge of two addresses belonging to different entities. The cost is written in the results: most clusters end up holding one or two addresses, which is why a second, weaker pass exists that discards singletons and takes the count from 109,074 down to 14,933. That second number is more useful and less defensible, and the notebook keeps them separate rather than reporting one.
Knowing when not to apply a heuristic. A CoinJoin deliberately violates common-input ownership. Running the heuristics over one does not fail: it confidently merges unrelated people. Detecting the pattern and stepping back from it is the only correct response, and it means accepting that those transactions stay unresolved.