Skip to content

Bitcoin Signed Messages

Every time a wallet spends coins, it proves that it holds the right Private Key by producing a Signature over the Transaction. Sometimes we want that proof without spending anything, e.g. to show that we control an Address before someone pays to it, or to log in to a service with a key we already hold.

A Bitcoin Signed Message is exactly that: an ordinary ECDSA Signature, made with the same Private Key and the same curve as a Transaction Signature, but over a piece of text in place of a Transaction. The format comes from the original Bitcoin client, and most wallets can create and check these Signatures. In this section we will look at how a message is signed, how the Signature is checked, and what it does and doesn’t prove.

Figure 1 shows how a wallet signs the message hello, world. The values are real ones, for a testnet key used in our library examples.

The message is serialised behind the length-prefixed magic text “Bitcoin Signed Message:\n” and its own length, and hashed twice with SHA256. The hash is signed with ECDSA using the Private Key. The result is a 65-byte compact Signature: a header byte holding the recovery id, then r and s of 32 bytes each. The 65 bytes are encoded in base64.message: “hello, world”Private Key18Bitcoin Signed Message:\n0chello, worldSHA256( SHA256( … ) )ECDSA sign, find the recovery id1fr: 32 bytess: 32 bytesH2gd4ydfFx6yqKpHyTfvru+sG/Rh18ayKn91G/I2OrLbWYkJtYboGX/IlM47+uMbr0IQobpkRI1P+73Agdip98o=lengththe magic prefixlengthmessagee5189df6 … a0d7e54e27 + 4 + 0681de327 … 363ab2db598909b5 … d8a9f7ca65 bytesbase64
Figure 1: Signing a message

Referring to Figure 1, we notice a few interesting things:

  1. The message is not signed as it is. It is first placed behind a fixed magic prefix, the text Bitcoin Signed Message: followed by a newline. Both the prefix and the message are preceded by their lengths, as variable-length integers: 18 is 24, the length of the prefix, and 0c is 12, the length of hello, world.
  2. These bytes are hashed twice with SHA-256, as we do with Transactions.
  3. The hash is signed with ECDSA, using the Private Key. This gives the two numbers that make up every ECDSA Signature, r and s.
  4. The wallet also works out a recovery id, a number from 0 to 3 that we will need when we check the Signature. It goes into a header byte, as 27 + recovery id, plus 4 if the Public Key is compressed. Our header byte is 1f, or 31, i.e. a compressed key with a recovery id of 0.
  5. The header byte, r and s make up a 65-byte compact Signature, which is encoded in base64 so that it can be pasted into an email or a web form.

Why the magic prefix? A wallet that will sign any 32 bytes it is given can be tricked into signing the hash of a Transaction, and with it a payment. Because a signed message is always hashed behind the prefix, its hash can never be that of a Transaction, so signing a message can never spend coins.

To check a Signature, one needs the message, the Signature, and the Address the Signature claims to come from. Figure 2 shows how.

The message is hashed as in Figure 1. From the hash, r, s and the recovery id, the verifier recovers a Public Key, hashes and encodes it into an Address, and compares it with the claimed Address. If they are the same the Signature is valid, otherwise it is invalid.messageSignatureclaimed Addressrecover a Public Key from r, s, recovery idPublic Keyrecovered Addresscomparevalidinvalidhash, as in Figure 1header byte, r, shash and encode, as in Addressessamedifferentn1ZCYg9YXtB5XC…
Figure 2: Verifying a message against an Address

Referring to Figure 2:

  1. The verifier hashes the message exactly as the signer did, magic prefix and all.
  2. From the hash, r and s, ECDSA allows us to work backwards to the Public Key that made the Signature. In general up to four Public Keys fit, and the recovery id in the header byte tells us which one is meant. This is called Public Key recovery.
  3. The recovered Public Key is hashed and encoded into an Address, as we described in Addresses. The header byte tells us whether to use the compressed or uncompressed form of the key.
  4. If the recovered Address is the same as the claimed Address, the Signature is valid. If the message has been changed by as much as one character, a different Public Key is recovered, and the Addresses don’t match.

This is why the Signature carries a recovery id at all. The signer never has to hand over their Public Key, and an Address is all the verifier needs. Where the verifier does hold the signer’s Public Key, they can of course compare Public Keys directly, or check the Signature with ordinary ECDSA verification.

It should be noted that one Private Key can make many different, equally valid Signatures over the same message. Each ECDSA Signature uses a secret random number, so two wallets signing hello, world with the key of Figure 1 will produce two different Signatures, and both will verify. Don’t compare Signatures to decide whether two messages were signed by the same key. Verify each one.

A valid Signature proves one thing only: that whoever made it held the Private Key behind the Address at the moment they signed. It is worth being careful about what it does not prove:

  • It doesn’t prove that the signer still holds any coins. The coins at an Address may have been spent long ago.
  • It doesn’t say when, or for whom, it was made. A Signature over I own this Address can be copied and shown to anyone, at any time, by anyone who has seen it.
  • It doesn’t prove that the signer is a particular person, only that they held a particular key.

The short of it, is that a Signature should be over a message that can’t be reused. A service that asks a wallet to prove control of an Address should hand it a challenge to sign: a fresh random value, together with the name of the service and the date. A Signature over that message is no use to anyone else, and no use tomorrow.

Please note that a user should read a message before their wallet signs it. The magic prefix keeps a signed message from ever spending coins, but the words of the message can still be used against the signer, e.g. a message that says they agree to something they didn’t.

Bitcoin Signed Messages tie a Signature to an Address, and so they share the limits of Addresses: the same key keeps being used, and nothing in the Signature says who it was meant for. In the BRC-100 ecosystem, wallets sign messages with keys derived for the purpose with BRC-42, as described in BRC-77, and two parties prove their identity to each other with the mutual authentication of BRC-103 in place of signing a challenge by hand. Bitcoin Signed Messages remain the most widely understood way of proving control of an Address, and every wallet that can check one does it the same way.

Both of our libraries implement Bitcoin Signed Messages. You can see how to sign a message, and verify one against an Address or a Public Key, in DartSV and Bitcoin4J.