Skip to content

Instantly share code, notes, and snippets.

@ryanxcharles
Last active June 14, 2023 13:35
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ryanxcharles/1c0f95d0892b4a92d70a to your computer and use it in GitHub Desktop.
Save ryanxcharles/1c0f95d0892b4a92d70a to your computer and use it in GitHub Desktop.
Stealth Addresses, Transactions and Messages

Stealth Addresses, Transactions and Messages

Normal bitcoin addresses cannot be published in public without losing all privacy, since all transactions to that address can be seen by anybody. Stealth addresses let us publish an address in public which can be used by payers to derive a new address that the payee has access to, but no one else knows is associated with the stealth address. The trick is that the payer must use a nonce to derive the address paid to, and this nonce must be delivered to the payee so they know how to recover the funds. This nonce can be delivered in the transaction, so that no separate channel is required to communicate the nonce.

The same technology can also be used to construct new public keys to send encrypted messages to.

We will discuss four methods:

  1. The simplest form of stealth addresses, which has some drawbacks that can improved upon.

  2. Stealth addresses for maximum public privacy.

  3. Stealth addresses for maximum privacy of payer from payee.

  4. Stealth addresses for general, off-blockchain messaging.

Simple Stealth Addresses

The payee has keypair A=aG. The payee makes the public key public to everyone (that is the stealth address).

The payer has keypair B=bG. B is the nonce.

They have a shared secret S=bA=baG=abG=aB, although the payee does not yet know how to calculate this since they do not have B yet.

The payer constructs kdf(S)=d and D=dG and E=A+D=aG+dG=(a+d)G=eG.

The payer constructs a transaction paying to E containing B in an OP_RETURN and broadcasts it and it is included in a block.

The payee scans the blockchain for OP_RETURN statements. For all OP_RETURN statements containing a possible public key, they calculate S=aB, then calculate kdf(S)=d and D=dG and E=A+D, and see if the same transaction containing the OP_RETURN also pays to E. If so, the payee has the private key for that output, e, which can be used to spend the money.

This method has some drawbacks:

  1. The private key of the payee, a, must be online on the computer that is scanning the blockchain, increasing the probability of compromised security.

  2. Anybody can see the OP_RETURN statement contains a possible public key and is likely a stealth transaction, thus increasing the probability of compromised privacy.

Both of these drawbacks are addressed in the next method.

Stealth Addresses for Maximum Public Privacy

The payee has two keypairs, A=aG, for receiving payments, and A'=a'G, for calculating the shared secret. Both public keys are made public (the pair A, A' is the stealth address).

The payer has keypair B=bG. They have previously received payments at this address, so the hash of the public key is public.

They have a shared secret S=bA'=ba'G=a'bG=a'B, although the payee does not yet know how to calculate this since they do not have B yet.

The payer constructs kdf(S)=d and D=dG and E=A+D=aG+dG=(a+d)G=eG.

The payer constructs a transaction paying to E where B is a public key in one of the inputs and broadcasts it and it is included in a block.

The payee scans every transaction in the blockchain. For every public key in an input, they calculate S=a'B, then calculate kdf(S)=d and D=dG and E=A+D, and see if the same transaction containing B also pays to E. If so, they can spend that money with keypair A=aG. Note that main private key, a, does not have to be online when scanning the blockchain, only a'. Also note that since no OP_RETURN is used, this transaction is indistinguishable from most normal pubkeyhash transactions on the blockchain.

Since this method produces transactions that do not look different than other transactions, it has maximum public privacy. However, it is slow, because every transaction in the blockchain must be scanned with computational difficulty O(nm) where n is the number of inputs and m is the number of outputs, which is somewhat slow. This can be overcome by always putting B in the first input, and also only scanning the blockchain during a time window when a payment is expected.

One final problem is that the payee can see the input used by the payer, i.e. it is not compatible with CoinJoin, i.e. the payer cannot have privacy from the payee. This can be addressed by reverting to an OP_RETURN, explained in the next section, albeit with the consequence that the public privacy is lessened.

Stealth Addresses for Maximum Privacy of Payer from Payee

This is the same as above, where the payee has two keypairs A=aG and A'=a'G, and the payer has keypair B=bG, except B is put in an OP_RETURN statement rather than an input, thus making these transactions compatible with CoinJoin so the payer can have privacy from the payee.

The consequence is that because B is contained in an OP_RETURN, this stands out to anybody analyzing the blockchain, so public privacy is lessened.

Stealth Addresses for Off-Blockchain Messaging

Stealth addresses can also be used for messaging.

The receiver has keypairs A=aG and A'=a'G. The public keys are made public.

The sender has keypairs B=bG and B'=b'G. The former public key is public and reused, the latter public key is private, and is only used one time to send a hint message to the receiver.

They have a shared secret S=bA'=ba'G=a'bG=a'B, although the receiver does not yet know how to calculate this since they do not have B yet.

The sender constructs kdf(S)=d and D=dG and E=A+D=aG+dG=(a+d)G=eG, and then encrypts a message using public key E with the ECIES algorithm.

The sender posts B, E (or a hash of E), and the encrypted message in public. The receiver searches the public place for all potential encrypted messages. Any potential B is checked against E, or its hash, since the receiver can calculate S=a'B and d=kdf(s) and E=A+D=A+dG=aG+d=(a+d)G=eG. The receiver can decrypt the message with private key e (which only the receiver, and not sender, has).

The receiver's second private key a' needs to be "online" in order to find the message, but their private key a only needs to be used to actually decrypt the encrypted message.

This messaging method has the property that even though the message is posted in a public place, no one except the sender and receiver knows who sent the message or who received it, only that a message exists, when it was posted, and roughly what its size is. Even the size could be concealed by posting many small messages, and the time could be blurred by posting the pieces at random times.

@justusranvier
Copy link

I'd like to see Bitcoin, Namecoin, and Bitmessage turn into a standard stack that all Bitcoin clients are assumed to be capable of accessing.

If everybody had an identity in the Namecoin blockchain, and those identities included both stealth addresses and Bitmessage addresses, then you could do several things:

  • Anyone can immediately send any payment to any identity they want without any interactive payment detail negotiation.
  • For maximum privacy, the stealth address nonce could be delivered over Bitmessage with OP_RETURN used as a fallback method.
  • If two users are going to have a durable economic relationship, their clients could automatically use Bitmessage to exchange BIP32 xpubs so that they can send each other money without the overhead of stealth addresses. This would be the ideal way for businesses to accept payment from customers.

@yuelipeng
Copy link

great

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment