Reducing the on-chain fingerprintability of different wallet software

Right now every wallet software does slightly different things with transaction preparation, which makes it possible for chain analysis to fingerprint transaction and detect which wallet is being used. It would be nice if at least we could have all P2PKH transactions look ‘the same’ so this isn’t possible.

I’m aware of the following variations:

  • Tx version:
    • Tx version=1 is the classic choice.
    • Tx version=2 adds BIP68 support (inputs can define their own relative locktimes). Note though that this BIP68 capability is generally unused, and if it is used then the transaction will stick out.
  • Signatures may be ECDSA or Schnorr
    • ECDSA is the classic. HW wallets currently only support ECDSA.
    • Schnorr is the up-and-comer. It adds efficiency that might one day be important in scaling. If widely used then it fancier things (multisigs, hidden smart contracts) to have a large anonymity set.
    • Mixtures of ECDSA and Schnorr signed inputs are possible, but rare.
  • Locktimes:
  • Sequence numbers:
    • 0 is a valid choice, and works fine even with tx version 2, but nobody uses it AFAIK.
    • 0xFFFFFFFD (two-before-final) might appear in wallets forked from BTC, since it indicates RBF capability.
    • 0xFFFFFFFE (one-before-final) is a common choice, which means ‘do not ignore the locktime’.
    • 0xFFFFFFFF is a special case that marks a tx as final, meaning that the locktime is disregarded.
  • Fees selection, especially when all txes are on the “1 sat/byte” floor.
    • Wallets using Schnorr may try to save a slight amount on fees by allocating for these smaller signatures, but they face an issue with partially signed txes that might end up having ECDSA.
    • Wallets may round off output amounts, resulting in random values being discarded as fees.
  • Transaction input/output ordering: in normal txes the ordering doesn’t have any significance.
    • Random shuffling is a good choice.
    • BIP69 is an alternative that uses a deterministic sorting order.
    • Other options besides these will inevitably leak unnecessary information about change addresses, coin selection strategies and such.

TODO:

  • Make a table of what various wallet softwares do.
  • Scan the recent chain and observe the frequency of modern fingerprints. Observe mempool admittance to check for locktime settings.

The goal is to start converging on a standard form of transaction. If one form (or a few forms) gain significant dominance, then other minority wallets will feel compelled to follow for privacy reasons.

13 Likes

Great overview and I agree this is the full list if we asssume P2PKH outputs and no fancy SigHash.

This value means that you turn on relative lock time, but set it to zero.
Kind of like turning on an amplifier but turning the volume to zero.
I’d argue its better to keep it turned off (final) and avoid code-paths that check stuff on mempool entry.

1 Like

Hmm, it seems editing is restricted after a certain time. Anyway, another privacy factor:

  • Does the wallet sometimes only partially spend from an address (only spending some coins) or does it do the private thing and always spend all available coins on a given address at the same time.

Ha, so that is the reason for this weird behavior in EC :smiley:

In my imported read.cash wallet (so exactly one address) it always joins all outputs, behavior I personally call a bug (yes the change goes back to the same address).

(copy-pasted from BCHN Slack discussion)

This is a good point to bring up, but when choosing the common standard it is important to do so in line with the overall direction we should be moving in. Specifically:

  • Everybody on Schnorr is better than everybody on ECDSA. (Schnorr has better performance/functionality.)
  • Everybody on BIP69 is better than everybody on random order. (BIP69 makes the privacy auditable.)

So while we can tweak the timing of when we toggle the default settings, this is the direction we should be transitioning in.

2 Likes

Nikita Zhavoronkov (lead dev Blockchair) has done an analysis of how different transaction types on BTC damage privacy. I sent him a link to this discussion.

2 Likes

This is a great initiative!

Here is a complete list (with example transactions!) of heuristics analysts can use when looking at a single transaction we’ve come up with at Blockchair: https://blockchair.com/api/docs#link_M6

Some of them allow to distinguish the recipient’s address from the change address, some allow to fingerprint the wallet the sender uses, some are applicable to fingerprinting exchanges (ordering of inputs/outputs in mass payouts, etc.)

Right now our Privacy-o-meter works for Bitcoin only, but it’s on our to-do list to enable it for other cryptos, including Bitcoin Cash (it has some unique indicators).

Right now we’re also working on making our address clusterizer (that uses these heuristics) results public.

4 Likes

Created the following BCHN issues for this topic:

2 Likes

BCHN MR to change locktime from option 3 to option 2: Wallet: Remove random component of locktime (!1063) · Merge Requests · Bitcoin Cash Node / Bitcoin Cash Node · GitLab

BCH Unlimited has also ported removing the random component of locktime:

Both BCHN and BCH Unlimited merged it.

Is this still being worked on?

Flowee Pay has implemented all those suggestions and they are on by default.

BCHN still has those issues open.

Selene uses locktime=0, I will create an issue to change this to current blockheight (as we do test against Electron Cash for parity).

Selene also has yet to implement BIP-69 but there is an issue open for this as well.

We are using Schnorr signatures on all transactions, fees default to 1 sat/B, and tx version=2.

1 Like

I would argue that zero is the thing to use on BCH. There is no benefit to pick something else.

Rationale for actually using zero is that non-online wallets (which could be Pay or maybe Selene when the user doesn’t have 4G) can create anonymous transactions. Using BIP70 or similar to send the tx to the merchant via bluetooth.

Also transactions that are created at Burning Man and only broadcast the week after are then not standing out like a sore thumb.

Zero seems to be the most logical choice to me.

I interpreted this thread as suggestion locktime=blockheight, but the rationale is “to prevent ‘fee sniping’” and “because Electron Cash does it.”

So, your arguments here are definitely more practical… are there any other considerations to be aware of regarding locktime?

Best to make sure that reducing the on-chain fingerprint-ability is a consensus hard code change so that no one can implement a bad wallet to expose privacy of others

That’s a nice wish but it would come with ugly trade-offs and require a full protocol overhaul, and it would ruin a lot of other use-cases we like, so we’re not going in that direction. You have XMR for that.