<p><code>bitcoinjs-message</code> uses traditional signing process which simply sign message with prefix(if not given) <code>\x18Bitcoin Signed Message:\n</code>. This kind of signing schema has been common but has limitation as it only supports p2pkh. There are implementations which support other type of address with this schema(<code>bitcoinjs-message</code> also supports p2wpkh and p2sh-p2wpkh, but not p2tr), but there's no strict standard for it.</p>
<p><a href="https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki" rel="nofollow noreferrer">BIP322</a> suggests a new way of signing schema, in which virtual transaction is required to sign and verify all types of addresses while p2pkh uses traditional signing process. However, it's still in development and not yet implemented in bitcoin-core as I know.</p>
<p>I was also looking for bip322 message signing library, and just end up implementing it by myself. If you need you can use it. My open source <a href="https://github.com/ChrisCho-H/bitcoin-sdk-js" rel="nofollow noreferrer"><code>bitcoin-sdk-js</code></a> has a feature of bip322 signing and verifying message with javascript, which support p2pkh, p2wpkh and p2tr. It's verified with bip322 test vector so you can use it. I would try to follow development of bitcoin-core. Be careful as BIP322 itself is in transition.</p>
<p>Below is how to implement.</p>
<pre class="lang-javascript prettyprint-override"><code>import * as bitcoin from 'bitcoin-sdk-js'

const keyPair = await bitcoin.wallet.generateKeyPair();
const privkey = keyPair.privateKey;
const pubkey = keyPair.publicKey;
const legacyAddress = await bitcoin.address.generateAddress(
  pubkey,
  'legacy',
);
const segwitAddress = await bitcoin.address.generateAddress(
  pubkey,
  'segwit',
);
const tapAddress = await bitcoin.address.generateAddress(
  (
    await bitcoin.tapscript.getTapTweakedPubkey(
      pubkey.slice(2),
      await bitcoin.tapscript.getTapTweak(pubkey.slice(2)),
    )
  ).tweakedPubKey,
  'taproot',
);
const msg = 'message you want to sign';
// When
const sigLegacy = await bitcoin.crypto.signMessage(
   msg,
   privkey,
   legacyAddress,
);
const sigSegwit = await bitcoin.crypto.signMessage(
  msg,
  privkey,
  segwitAddress,
);
const sigTap = await bitcoin.crypto.signMessage(msg, privkey, tapAddress);
// Then
assert.strictEqual(
  await bitcoin.crypto.verifyMessage(msg, sigLegacy, legacyAddress),
  true,
);
assert.strictEqual(
  await bitcoin.crypto.verifyMessage(msg, sigSegwit, segwitAddress),
  true,
);
assert.strictEqual(
  await bitcoin.crypto.verifyMessage(msg, sigTap, tapAddress),
  true,
);
</code></pre>
<p>p.s. I think the website you refer might have an issue with non-ASCII encoding, I recommend <a href="https://bluewallet.github.io/VerifySignature" rel="nofollow noreferrer">this website</a> to test traditional message signing.</p>

CC BY-SA 4.0
2024-05-18T11:51:25.443Z
2024-08-05T07:53:23.280Z
2024-08-05T07:53:23.280Z
Hyunhum Cho
<p>I'm trying to verify ownership of a Bitcoin address using the public key, signature, and the address (P2PKH, P2SH, P2WPKH, P2WSH, P2TR) as input. However, the code below does not work for Bech32 addresses.</p>
<pre><code>import BitCoinLib from 'bitcoinjs-lib';
import BitCoinMessage from 'bitcoinjs-message';

BitCoinMessage.verify(message, address, signature);
</code></pre>
<p>As another attempt, I tried using bitcore-lib, but it doesn't support address verification. It only accepts public key and signature as inputs.</p>
<pre><code>import bitcore from 'bitcore-lib';

export function verifyMessage(publicKey, sig, text) {
    const message = new bitcore.Message(text);
  
    var signature = bitcore.crypto.Signature.fromCompact(
      Buffer.from(sig, &quot;base64&quot;)
    );
    var hash = message.magicHash();
  
    // recover the public key
    var ecdsa = new bitcore.crypto.ECDSA();
    ecdsa.hashbuf = hash;
    ecdsa.sig = signature;
  
    const pubkeyInSig = ecdsa.toPublicKey();
  
    const pubkeyInSigString = new bitcore.PublicKey(
      Object.assign({}, pubkeyInSig.toObject(), { compressed: true })
    ).toString();
    if (pubkeyInSigString != publicKey) {
      return false;
    }
  
    return bitcore.crypto.ECDSA.verify(hash, signature, pubkeyInSig);
  }
</code></pre>
<p>What I want to achieve is similar to <a href="https://www.verifybitcoinmessage.com/" rel="nofollow noreferrer">https://www.verifybitcoinmessage.com/</a>, but that site also has limitations as it cannot verify P2WPKH addresses.</p>
<p>Is it possible to verify all types of addresses? If so, please provide guidance on how to do it.</p>

<signature><message>
Verifying the address and the message using the public key, address, and signature!
0xB17C014
# Verifying the address and the message using the public key, address, and signature!

(Asked by: username_0 on 2024-04-29)

I'm trying to verify ownership of a Bitcoin address using the public key, signature, and the address (P2PKH, P2SH, P2WPKH, P2WSH, P2TR) as input. However, the code below does not work for Bech32 addresses.

```
import BitCoinLib from 'bitcoinjs-lib';
import BitCoinMessage from 'bitcoinjs-message';

BitCoinMessage.verify(message, address, signature);

```

As another attempt, I tried using bitcore-lib, but it doesn't support address verification. It only accepts public key and signature as inputs.

```
import bitcore from 'bitcore-lib';

export function verifyMessage(publicKey, sig, text) {
    const message = new bitcore.Message(text);
  
    var signature = bitcore.crypto.Signature.fromCompact(
      Buffer.from(sig, "base64")
    );
    var hash = message.magicHash();
  
    // recover the public key
    var ecdsa = new bitcore.crypto.ECDSA();
    ecdsa.hashbuf = hash;
    ecdsa.sig = signature;
  
    const pubkeyInSig = ecdsa.toPublicKey();
  
    const pubkeyInSigString = new bitcore.PublicKey(
      Object.assign({}, pubkeyInSig.toObject(), { compressed: true })
    ).toString();
    if (pubkeyInSigString != publicKey) {
      return false;
    }
  
    return bitcore.crypto.ECDSA.verify(hash, signature, pubkeyInSig);
  }

```

What I want to achieve is similar to <https://www.verifybitcoinmessage.com/>, but that site also has limitations as it cannot verify P2WPKH addresses.

Is it possible to verify all types of addresses? If so, please provide guidance on how to do it.

**Tags:** signature, message


---

## 1 answers

### Answer by username_1 on 2024-05-18. Score: 0

`bitcoinjs-message` uses traditional signing process which simply sign message with prefix(if not given) `\x18Bitcoin Signed Message:\n`. This kind of signing schema has been common but has limitation as it only supports p2pkh. There are implementations which support other type of address with this schema(`bitcoinjs-message` also supports p2wpkh and p2sh-p2wpkh, but not p2tr), but there's no strict standard for it.

[BIP322](https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki) suggests a new way of signing schema, in which virtual transaction is required to sign and verify all types of addresses while p2pkh uses traditional signing process. However, it's still in development and not yet implemented in bitcoin-core as I know.

I was also looking for bip322 message signing library, and just end up implementing it by myself. If you need you can use it. My open source [`bitcoin-sdk-js`](https://github.com/ChrisCho-H/bitcoin-sdk-js) has a feature of bip322 signing and verifying message with javascript, which support p2pkh, p2wpkh and p2tr. It's verified with bip322 test vector so you can use it. I would try to follow development of bitcoin-core. Be careful as BIP322 itself is in transition.

Below is how to implement.

```javascript
import * as bitcoin from 'bitcoin-sdk-js'

const keyPair = await bitcoin.wallet.generateKeyPair();
const privkey = keyPair.privateKey;
const pubkey = keyPair.publicKey;
const legacyAddress = await bitcoin.address.generateAddress(
  pubkey,
  'legacy',
);
const segwitAddress = await bitcoin.address.generateAddress(
  pubkey,
  'segwit',
);
const tapAddress = await bitcoin.address.generateAddress(
  (
    await bitcoin.tapscript.getTapTweakedPubkey(
      pubkey.slice(2),
      await bitcoin.tapscript.getTapTweak(pubkey.slice(2)),
    )
  ).tweakedPubKey,
  'taproot',
);
const msg = 'message you want to sign';
// When
const sigLegacy = await bitcoin.crypto.signMessage(
   msg,
   privkey,
   legacyAddress,
);
const sigSegwit = await bitcoin.crypto.signMessage(
  msg,
  privkey,
  segwitAddress,
);
const sigTap = await bitcoin.crypto.signMessage(msg, privkey, tapAddress);
// Then
assert.strictEqual(
  await bitcoin.crypto.verifyMessage(msg, sigLegacy, legacyAddress),
  true,
);
assert.strictEqual(
  await bitcoin.crypto.verifyMessage(msg, sigSegwit, segwitAddress),
  true,
);
assert.strictEqual(
  await bitcoin.crypto.verifyMessage(msg, sigTap, tapAddress),
  true,
);

```

p.s. I think the website you refer might have an issue with non-ASCII encoding, I recommend [this website](https://bluewallet.github.io/VerifySignature) to test traditional message signing.


---

