Wallet Fingerprints

On-chain transaction fingerprints across wallet implementations

// context

Every Bitcoin wallet leaves a fingerprint. When software constructs a transaction it makes dozens of small decisions — input ordering, locktime values, signature encoding, fee estimation — that vary systematically across implementations. These patterns are observable on-chain and allow an adversary to identify which wallet created a transaction, even without any off-chain data.

Fingerprints are especially damaging for collaborative transactions, where multiple parties contribute inputs to a single transaction. If the participants use different wallet software, signature and script differences can partition the inputs by owner — undoing the privacy the collaboration was meant to provide. Even when intra-transaction signals are uniform, an analyst can look backward and forward in the transaction graph where each wallet's fingerprints reappear. See how this plays out for PayJoin.

This builds on prior work by Ishaana, who catalogued wallet fingerprints through manual code inspection and hands-on interaction with each wallet. Ongoing work takes a more dynamic approach: wallets are run in containers and exercised programmatically to construct real transactions, with fingerprints extracted directly from the resulting on-chain data. This makes the comparison easier to reproduce and keep current as wallets evolve.

// clustering

Beyond collaborative transactions, fingerprints are a powerful input to wallet clustering, the process of grouping addresses and transactions that likely belong to the same entity. Standard clustering leans on heuristics like common-input-ownership and change detection. Fingerprints add another dimension: if two transactions share the same characteristic construction quirks, they were probably created by the same wallet software, which corroborates or extends a cluster that on-chain heuristics alone would leave ambiguous.

⚠ Results were captured with automated AI tooling and may contain errors. Verify against source code before relying on any value.

Loading...