功能代码:
import (
"encoding/hex"
"errors"
"github.com/btcsuite/btcutil/base58"
"github.com/decred/dcrd/dcrec/secp256k1"
)
//P2WPKH-P2SH
func NewP2SH(rawPrivKey []byte, netType string, isCompress bool) (string, error) {
//参数校验
var mapNet = map[string]byte{"main":0x05, "testnet":0x6f}
if _, ok := mapNet[netType]; !ok {
return "", errors.New("invalid net type")
}
var (
privKey *secp256k1.PrivateKey
err error
hash160 []byte
pubKey []byte
)
privKey = secp256k1.PrivKeyFromBytes(rawPrivKey)
//计算公钥
if isCompress {
pubKey, _ = hex.DecodeString(NewCompressPubKey(privKey.PubKey().X().Bytes(), privKey.PubKey().Y().Bytes()))
} else {
pubKey,_ = hex.DecodeString(NewUncompressPubKey(privKey.PubKey().X().Bytes(), privKey.PubKey().Y().Bytes()))
}
// BASE58CHECK( 0x05 HASH160( 0x00 0x14 HASH160( pubKey ) ) )
//上面的 HASH160(x) = RIPEMD160(Sha256(x)),base58check(x) = x Sha256(Sha256(x)).substring(0,4)
if hash160, err = Ripemd160AfterSha256(pubKey); err != nil {
return "", err
}
if hash160, err = Ripemd160AfterSha256(append([]byte{0x00,0x14}, hash160...)); err != nil {
return "", err
}
buf := append([]byte{mapNet[netType]}, hash160...)
checksum := Sha256AfterSha256(buf)
buf = append(buf, checksum[:4]...)
return base58.Encode(buf),nil
}
测试代码:
func TestNewP2SH(t *testing.T) {
var testcases = []struct{
originalPrivKey string
netType string
address string
} {
{"cff0fbaaae8f6ee6ebb35f98afa4036958d929ee18143b26c466251cd966b128",
"main",
"3QehmGVcZsJEVc1uPSvXwamRQn56JR7qKd",
},
}
var err error
var address string
for _, oneCase := range testcases {
privKey,_ := hex.DecodeString(oneCase.originalPrivKey)
if address,err = NewP2SH(privKey, oneCase.netType,true);err != nil {
t.Error(err)
return
}
if address != oneCase.address {
t.Error("genereate compressed address error")
t.Error("want: ", oneCase.address)
t.Error("got: ", address)
return
}
}
}
这里的测试用例可以用Electrum钱包生成的地址测试。不过Electrum钱包导出的私钥是WIF格式的,需要将它解码转成字节数组的形式填写在测试用例中。
(全文完)
参考资料:
https://learnmeabitcoin.com/guide/p2sh
https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
https://en.bitcoin.it/wiki/List_of_address_prefixes