What are stealth addresses?

Stealth addresses solve a basic problem: publishing a static Bitcoin address is convenient for receiving payments but has privacy leaks, because now your adversary can look up all the payments you received in the block chain.

One simple solution is to have a server that just iterates a BIP32 HD wallet branch you give it and vends the resulting addresses. By keeping the chain code hidden behind the server, we get unlinkability. But this is inconvenient for a few reasons:

You need a server that understands how to do this.

If the chain code ever leaks then all your payments become linkable.

More problematically, it doesn’t play well with signing in BIP70. To know who you are paying you want a signature from them, but then the server would have to be able to sign as you, which reduces security.

Why can’t you just publish the chain code and let the sender iterate the keys? Because the receipient of the money has to be able to find the payments, and that means they have to be able to enumerate all possible payment addresses. If the genuine recipient can enumerate them all, so can the adversary who wants to learn your income.

What’s needed is a way for a sender of money to generate a public key that they don’t own the private key for, such that the receiver can calculate the private key, and it’s impossible to link the payments together. This is what stealth addresses do.

How they work

The exact mechanism is well explained in this writeup by Peter Todd, although it’s worth noting the original idea of doing elliptic curve Diffie-Hellman is from ByteCoin in 2011. But at a very high level, the sender selects a large random number. This number is fed into a bunch of equations along with the published key and out pops what we need: a new public key (read: address) for which only the recipient can calculate the private part, and which can’t be linked to the original published key.

So far so good. Unfortunately it’s the conversion of this scheme into “stealth addresses” that is where the problems start. Let’s put aside the questionable name choice and look at the technology — to redeem the payment, the recipient needs the big random number. It can be public without causing problems, so the current stealth address scheme tags it onto the transaction using a new output.

First problem: stealth address usage bloats the block chain.

Second problem: stealth payments look different to regular payments.

Once such a tagged transaction is made, the recipient has to be able to find it. Normally a wallet does this by scanning the block chain looking for payments to addresses it generated. But in this case the address is brand new, and the tag is a random number. So the only way to find payments to your stealth address is to try all of them and see if any match. This scales very badly. There are attempts to hack around this problem in the original proposal, but they all assume big changes to the P2P protocol that nobody is implementing, and they work by simply sharding the anonymity set: you try some fraction of all possible payments, and the payer tries to make their payment fit by brute forcing the randomness to fit the requested fraction.

Third problem: stealth addresses and phones don’t mix

Of course by “phone” what I really mean is any CPU or battery constrained device, which these days is most of them.

Finally, the whole notion of an address is one we’re trying to get away from. Addresses can’t be easily extended with new features because it’s not backwards compatible. Wallets that don’t know about stealth addresses will just reject them, instead of successfully making a payment but with worse privacy — probably a popular option for deployment in the real world.

Fourth problem: stealth addresses are not backwards compatible.

There’s also a final issue that is is inherited from the notion of an address:

Fifth problem: you have no idea who sent you money or why.

Luckily there is an alternative design that fixes all these problems. It’s the one I plan to pursue long term.