bitcoin: Signmessage doesn't work with segwit addresses
Describe the issue
Signmessage doesn’t work on “segwit addresses” (what BIP141/BIP49 calls “P2WPKH-nested-in-P2SH”).
Steps to reproduce
On testnet (or on litecoin 😃):
NEW_ADDRESS=$(bitcoin-cli getnewaddress)
SEGWIT_ADDRESS=$(bitcoin-cli addwitnessaddress $NEW_ADDRESS)
bitcoin-cli signmessage $SEGWIT_ADDRESS "shiny"
Expected behaviour
Signature is printed
Actual behaviour
error code: -3
error message:
Address does not refer to key
What version of bitcoin-core are you using?
v0.14.1
self-compiled from github repo
Machine specs:
- OS: Linux
- CPU: can reproduce on x86 and x64 CPUs
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 9
- Comments: 77 (60 by maintainers)
The confusion here comes from the ambiguitiy in whether an address is an identifier of a key, or a shorthand for a script.
In the time when there was only one type of addresses, this was an innocent confusion to have: every address was indeed a shorthand for a P2PKH script, but also uniquely identified a private/public keypair. This is exploited in the
signmessage
command. It works with keys, not addresses, but uses addresses to refer to these keys.Since P2SH, and certainly now with P2WSH/P2WPKH, this no longer works. You can’t sign with an arbitrary P2SH address - even if you have the key for it - since the receiver wouldn’t have the public key to verify with.
Not sure whether to open a new issue but it probably fits in here.
Maybe some day there will be a way to sign messages again. Until then, could we at least tell users that it’s not supported? For example, changing the top text from “You can sign messages/agreements with your addresses” to “You can sign messages/agreements with your legacy (P2PKH) addresses”
And changing the error from “The entered address does not refer to a key.” (which is incorrect, as P2WPKH refers to a key just as much as P2PKH does, and I’d say P2TR refers to a key even more!) to “Message signing for segwit addresses (addresses starting with bc1/tb1) is not supported in this version of Bitcoin Core.”
It’s easy enough to change the error message while it’s unsupported.
This came to my attention as I was helping someone who was worried that they had lost their keys (a reasonable worry given the red error message!) - they were trying to use the sign message function on an offline computer to make sure their wallet & passwords still worked.
Shouldn’t this be assigned to someone? Seems pretty important not to leave those migrating to SegWit addresses at a disadvantage compared to those sticking to legacy addresses.
@luke-jr Why would we need to prove ownership of specific UTXO? Neither do I understand how you mean that signature does not prove ownership of keys. I thought the whole idea of message signing is to prove the ability to spend UTXOs associated with specific keys, therefore key hashes, therefore addresses. So why not to allow to verify message-signatures associated with those public keys if it’s possible given whatever address?
It is.
And it would in theory be possible to make
signmessage
work for a P2SH-P2WPKH address, in cases where the verifier knows the embedded pubkeyhash already. But in that case you don’t need “sign with a witness address” functionality - you could just sign with the embedded key (seevalidateaddress
), and have the verifier check that.The point is to not further the misunderstanding that
signmessage
signs with an address - it never did. It signs with a keyhash, and verify with a keyhash.When attempting to sign a message with a bech32 address, Bitcoin Core complains that the address doesn’t refer to a key. But it does. As a result I am unable to verify signatures made by users of the Electrum wallet (which can sign using bech32 addresses). I heard the Trezor also has similar functionality.
I made the following change to allow signing and verifying messages with bech32 addresses in Core. It appears to be compatible with Electrum’s signatures.
The address is a p2sh address, it doesn’t have an associated public or private key to sign and verify messages with.
@luke-jr Yes, I agree with what you’re saying; I don’t think I’m saying anything else. A signature with address A means whoever can receive on address A agrees with the message. That implies they are who will receive coins sent there, and have the ability to send them further.
It does not mean anything about transactions that look like they have “input address” A.
IMO it is intentional that the old sign/verify message does not work with P2SH/newer addresses. If someone wants to do message signing as a non-obsolete thing, I would recommend writing a BIP that specifies how to handle it for newer address formats, and fixes the confusion surrounding it (I have seen people try to use signed messages to prove they sent bitcoins, which the current stuff does NOT prove.)
In the meantime, perhaps verifymessage ought to throw an error rather than returning false?
This assumption is wrong. Third party and shared wallets are supposed to allow users to sign messages with the addresses they deposit/receive with.
It’s assumed that the private key is owned by the person who does the signing. Ownership is an important aspect of some things, private keys being one of them, as I view things. I think you meant something else, but I can’t figure out what.
That does not seem to be a particularly large concern to me. Validators can just test both the old scheme and the new. Old signatures can rather easily be accepted by future validators. -------- Original Message -------- On 28 Dec 2019, 13:17, andronoob wrote:
See #16440.
@EvilJordan we are eagerly awaiting your pull request…
@prusnak I’m totally fine with extending signmessage using just new header bytes as you’re suggesting:
As SegWit keys are always compressed you only need 4 for each, indeed.
@jakubtrnka working on what?
New dev mailinglist discussion here.
We constructed a new kind of signmessage for elements which is conceptually a lot better and supports arbitrary scripts-- but it immediately runs into a problem that softfork semantics only work within the context of a consensus network… it’s not clear how to handle them.
E.g. if a new softfork is defined on bitcoin and you make a pubkey that uses it… old verifiers need to return indeterminate-- before segwit script versioning this was intractable but it could be done now.
No, you can’t.
There is no way for the software that is verifying the signature to know whether the public key corresponds to a nested-p2wpkh address. It simply does not know what p2sh address it would correspond to since a public key can be a part of multiple p2sh addresses. The reason it works for p2pkh is because a public key can only correspond to one p2pkh address.
But you can sight with your P2SH address that you have private key to, right?
And similarly, if the receiver knows that the address is “nested witness address”, he can check whether a given public key belongs to that address.
I am not talking about arbitrary P2SH addresses, but really when the receiver knows it’s “nested witness” address.