Bitcoin
Message signing – How to check if a signature is signed by Pubkey? Taproot and BIP0322
Wallets like XVerse allow users to sign messages using an ordinal BTC address (let’s say bc1XXX), and the messages are hashed based on BIP0322.
So I have:
- User Wallet: bc1XXX
- Message hash: YYY
- Signed by bc1XXX: ZZZ
So this data is sent to my backend server, and I want to check that ZZZ is actually signed by bc1XXX (and contains YYY as the message).
I’m using this so far:
const msgHash = bip0322Hash(message);
const signatureBuffer = Buffer.from(signatureStr, 'base64');
const decodedSignature = signatureBuffer.slice(2, 66);
const recoveryId = signatureBuffer(0);
// Extract public key from the signature
const recoveredPublicKeyBuffer = secp.recoverPublicKey(
msgHash,
decodedSignature,
recoveryId, // Recovery ID (0 or 1)
false
);
console.log(publicKeyToTaprootAddress(recoveredPublicKeyBuffer)); //no match with my original pubkey that signed the message
But it’s difficult to get the exact address. recoveredPublicKeyBuffer
It cannot match the public key address in my test set.
I’m trying to use this function, but the output doesn’t match my public key.
function publicKeyToTaprootAddress(publicKey: Uint8Array)
// Compute the SHA-256 hash of the public key
const hash = sha256(Buffer.from(publicKey));
// Construct the human-readable part and the data part of the Bech32m string
const hrp = 'bc';
const data = sha256(Buffer.from((0x01).concat(Array.from(hash))));
const data2 = bech32m.toWords(Buffer.from(data));
// Encode the Bech32m string
return bech32m.encode(hrp, data2);