Skip to content

Instantly share code, notes, and snippets.

@trevormil
Created May 27, 2024 21:18
Show Gist options
  • Save trevormil/7c8c3bec3cac94a2af3c1d4edf95ac2b to your computer and use it in GitHub Desktop.
Save trevormil/7c8c3bec3cac94a2af3c1d4edf95ac2b to your computer and use it in GitHub Desktop.
BIP 322 P2WPKH BIP322 Verification in Go
package main
import (
"encoding/base64"
"log"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
bip322 "github.com/unisat-wallet/libbrc20-indexer/utils/bip322"
)
func convertAddressToScriptPubkey(address string) []byte {
btcAddress, err := btcutil.DecodeAddress(address, &chaincfg.MainNetParams)
if err != nil {
panic(err)
}
outputScript, err := txscript.PayToAddrScript(btcAddress)
if err != nil {
panic(err)
}
return outputScript
}
func main() {
//You can replace these with the actual values you want to verify
//These are in the format used by bip322-js
//This is for P2WPKH BIP322 verification
message := "Hello World"
signature := "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="
signerAddress := "bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l"
//These will be in the following format:
//[0x02 or 0x03] [LENGTH_BYTE, ...(LENGTH bytes that go into witness[0])] [0x21, ...(33 byte (len = 0x21) public key that was used to sign the message)]
//- First byte is either a 0x02 or 0x03 (not sure exactly why but apparently it is - https://github.com/ACken2/bip322-js/blob/f0f9373b3a1da19e017c518b891522eaa4bcccdd/src/helpers/Address.ts#L85)
//- Next part is the details that go into witness[0] (length of this part is determined by the second byte) - again, not exactly sure what this is
//- Last part is the public key that was used to sign the message (33 bytes) - There is a length byte 0x21 before this part to denote the length of the public key (0x21 = 33)
encodedSigBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
panic(err)
}
//Convert the address to a public key script (I believe this is the denotation for a pay-to-this-address script but not 100% sure)
pkScript := convertAddressToScriptPubkey(signerAddress)
//Decode the length of the witness[0] part
encodedSigLenByte := encodedSigBytes[1]
encodedSigLen := int(encodedSigLenByte)
//Extract witness[0] and witness[1] from the encoded signature
PUB_KEY_LEN := 33
encodedSig := encodedSigBytes[len(encodedSigBytes)-PUB_KEY_LEN-1-encodedSigLen : len(encodedSigBytes)-PUB_KEY_LEN-1]
pubKey := encodedSigBytes[len(encodedSigBytes)-33:]
//Recreate the witness to pass into the VerifySignature function
witness := wire.TxWitness{
encodedSig,
pubKey,
}
//This is the BIP322 verification function from the Unisat wallet
verified := bip322.VerifySignature(witness, pkScript, message)
log.Println("BIP 322 Verified:", verified)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment