Bitcoin Forum
November 14, 2025, 09:14:05 AM *
News: Pumpkin contest voting
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Publishing signed bitcoin messages  (Read 88 times)
mothepro (OP)
Newbie
*
Offline Offline

Activity: 4
Merit: 19


View Profile
November 12, 2025, 04:47:23 PM
Merited by odolvlobo (10), ABCbits (5), stwenhao (1)
 #1

Just wanted to see what y'all think of this bitcoin message verifier page I put together.

https://verify-bitcoin-message.js.org

Originally, I made it to learn, but also wanted an easy way to aggregate, share and publish these types of messages...

If anyone can, translations would be an incredible contribution now Smiley
mothepro (OP)
Newbie
*
Offline Offline

Activity: 4
Merit: 19


View Profile
November 12, 2025, 05:01:32 PM
 #2

The Github bot will automatically verify and provide proof every message which gets published.

For context, a while back, someone used 100s bitcoin addresses to sign this message.

Quote
Craig Steven Wright is a liar and a fraud. He doesn't have the keys used to sign this message.

The Lightning Network is a significant achievement. However, we need to continue work on improving on-chain capacity.

Unfortunately, the solution is not to just change a constant in the code or to allow powerful participants to force out others.

We are all Satoshi
stwenhao
Hero Member
*****
Offline Offline

Activity: 550
Merit: 1227


View Profile
November 13, 2025, 08:13:13 AM
Merited by pooya87 (5), vapourminer (4), ABCbits (3)
 #3

The tool works correctly, but it says things, which can be wrong in some cases. Because the correctness of the signature doesn't prove, that the coins are spendable, if it was artificially generated, without dealing with any private keys at all.

For example:
Code:
message="Hello World"
address="1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH"
signature="GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE="

Quote
1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH digitally signed this message with their private key
Wrong, the private key is unknown. If it would be known, then secp256k1 would be broken.

Quote
Authentication The signer can spend bitcoin from the address
Wrong, the signer can only sign "Hello World" specifically, and nothing else, because the private key is unknown, and the public key was created from the signed message and signature public key.

Proof of Work puzzle in mainnet, testnet4 and signet.
ABCbits
Legendary
*
Offline Offline

Activity: 3430
Merit: 9352



View Profile
November 13, 2025, 10:47:04 AM
Merited by vapourminer (4), pooya87 (4)
 #4

For something that made for learning purpose, it's good enough. I just want to suggest to consider showing all entered data (address, signature and message) after user clicking button "Verify".

The tool works correctly, but it says things, which can be wrong in some cases. Because the correctness of the signature doesn't prove, that the coins are spendable, if it was artificially generated, without dealing with any private keys at all.
--snip--

Interesting. I tried using other website mentioned on OP's website and they have same issue. Electrum says "Invalid address" on "Sign/verify message" windows, although Electrum let me import the address on watch-only address.

mothepro (OP)
Newbie
*
Offline Offline

Activity: 4
Merit: 19


View Profile
November 13, 2025, 03:40:56 PM
Merited by vapourminer (2), stwenhao (1)
 #5

For the curious, the payload in question is: https://verify-bitcoin-message.js.org/?address=1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH&message=Hello+World&signature=GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE%3D

correctness of the signature doesn't prove, that the coins are spendable, if it was artificially generated

Are you able to explain more about how this signature was generated then?

My best guess is the message "Hello World" was chosen, then signature uses some simple points on the elliptic curve to generate a public key.

Wrong, the signer can only sign "Hello World" specifically, and nothing else, because the private key is unknown, and the public key was created from the signed message and signature public key.

But then the public key shouldn't map to a valid address?

I implemented a Base58 checksum (which shouldn't validate) AND mempool.space should throw an invalid address error.

It sounds like message signatures are only useful if you expect a specific address (or a set amount of coins in the address).

I just want to suggest to consider showing all entered data (address, signature and message) after user clicking button "Verify".


Great feedback, added a "View Details" button to see the entire payload as json. Thanks!
stwenhao
Hero Member
*****
Offline Offline

Activity: 550
Merit: 1227


View Profile
November 13, 2025, 08:11:41 PM
Merited by ABCbits (5), vapourminer (4)
 #6

Quote
Are you able to explain more about how this signature was generated then?
Sure:

https://bitcoin.stackexchange.com/questions/77324/how-are-bitcoin-signed-messages-generated
https://en.bitcoin.it/wiki/Message_signing

1. Take some public key, where you don't know the private key, and turn it into R-value. For example:
Code:
R=020000000000000000000000000000000000000000000000000000000000000001
r=0000000000000000000000000000000000000000000000000000000000000001
2. Take some signature s-value. It could be anything at all, in range from 0x1 to 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0:
Code:
s=0000000000000000000000000000000000000000000000000000000000000001
3. Encode (r,s) with base64:
Code:
1b
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000001
Here, "1b" is a simple prefix, that can tell, how the public key should be exactly recovered. But if there is any correctly implemented signature validator, then the right prefix can be simply bruteforced, because there is something like 8 combinations or so (and other ones are just to check, if the public key is compressed or not, and in which address type it should be wrapped).

4. Take any message you want, and hash it properly:
Code:
message="Hello World"
header=0x18426974636f696e205369676e6564204d6573736167653a0a
data=0x0b48656c6c6f20576f726c64
tobehashed=0x18426974636f696e205369676e6564204d6573736167653a0a0b48656c6c6f20576f726c64
SHA-256(tobehashed)=93b57da96f256f507a3e3aa2adefed75f786e7d9cd4c38aab7a3a9f5a95af7c9
SHA-256(93b57da96f256f507a3e3aa2adefed75f786e7d9cd4c38aab7a3a9f5a95af7c9)=a7af0baad5ae99b97fc69b3a0d1abcf3ef17f131cc4776e1bc11933ec8550f49
5. Use public key recovery:
Code:
z=a7af0baad5ae99b97fc69b3a0d1abcf3ef17f131cc4776e1bc11933ec8550f49
-z=5850f4552a516646803964c5f2e5430acb96ebb4e301295a03c0cb4e07e131f8
R1=020000000000000000000000000000000000000000000000000000000000000001
R2=030000000000000000000000000000000000000000000000000000000000000001
Q1=R1+z=043AB2A58097B1C47183F519513E087FB61C0CBD1E361948B3A2D85235E9C8FCC64198D3727EDD4206C4F26342993E46BA38AE4985181FF5BFDD088DBDF0254AAC
Q2=R1-z=04753402E9699F1944EB22A8133A40BC2705FFB7B4E93E2DFBF18948C2AE5227B701BBAECE9C0009BA53614C48EEB0F1E01C737CEB906432A8D204327C70018060
Q3=R2+z=04753402E9699F1944EB22A8133A40BC2705FFB7B4E93E2DFBF18948C2AE5227B7FE44513163FFF645AC9EB3B7114F0E1FE38C83146F9BCD572DFBCD828FFE7BCF
Q4=R2-z=043AB2A58097B1C47183F519513E087FB61C0CBD1E361948B3A2D85235E9C8FCC6BE672C8D8122BDF93B0D9CBD66C1B945C751B67AE7E00A4022F772410FDAB183
Q5=023AB2A58097B1C47183F519513E087FB61C0CBD1E361948B3A2D85235E9C8FCC6
Q6=02753402E9699F1944EB22A8133A40BC2705FFB7B4E93E2DFBF18948C2AE5227B7
Q7=03753402E9699F1944EB22A8133A40BC2705FFB7B4E93E2DFBF18948C2AE5227B7
Q8=033AB2A58097B1C47183F519513E087FB61C0CBD1E361948B3A2D85235E9C8FCC6
addr(Q1)=12SkaKZ7MShARBL3WAD47FP1uoh1XXRkK5
addr(Q2)=1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH
addr(Q3)=12e5ZRpFvcN7cGkNBDyycGMi6myTswbsTn
addr(Q4)=1224tarPatBJ41bEf1iSj3P8VRSsDCXEto
And now, you can easily check, that 1psPJZYEJrjPtY6kw5Tqtj4mW2yXSSDuH is not just a random address. It is generated from 04 753402E9699F1944EB22A8133A40BC2705FFB7B4E93E2DFBF18948C2AE5227B7 01BBAECE9C0009BA53614C48EEB0F1E01C737CEB906432A8D204327C70018060 public key, and it is enough to pass ECDSA validation.

However, the knowledge of this public key, does not require the knowledge of the private key. Also, it is possible to pick someone else's public key, and put it into R-value, instead of 020000000000000000000000000000000000000000000000000000000000000001. Then, a given recovered address will be spendable only by that person.

Here is another example, which will pass verification:
Code:
message="I am Saint Wenhao, and I can use public key recovery."
address="1D2w953S1GgTHa2tRA5kuFwfuUkw9jt5ip"
signature="GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE="
As you can see, the message is completely different, the signature is exactly the same, and the recovered address changed to something else. But nobody can move any coins from 1D2w953S1GgTHa2tRA5kuFwfuUkw9jt5ip, as long as the private key to 020000000000000000000000000000000000000000000000000000000000000001 remains unknown.

Link to your site: https://verify-bitcoin-message.js.org/?address=1D2w953S1GgTHa2tRA5kuFwfuUkw9jt5ip&message=I+am+Saint+Wenhao%2C+and+I+can+use+public+key+recovery.&signature=GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE%3D

As you can see, verification passed, but "The signer can spend bitcoin from the address" is a lie, because only public keys were used, to generate all of that, so private keys are unknown, even if the signature can pass verification.

Proof of Work puzzle in mainnet, testnet4 and signet.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!