功能代码如下:
import (
"encoding/hex"
"errors"
"github.com/btcsuite/btcutil/base58"
"github.com/decred/dcrd/dcrec/secp256k1"
)
func NewP2PKH(rawPrivKey []byte, netType string, isCompress bool) (string, error) {
//先检测函数参数的有效性
var mapNet = map[string]byte{"testnet":0x6F, "main":0x00}
if _, ok := mapNet[netType]; !ok {
return "",errors.New("net type invalid")
}
var (
privKey *secp256k1.PrivateKey
err error
pubKey []byte
hash160 []byte
hash160WithPrefix []byte
address []byte
hash256 [32]byte
)
//1. 用私钥生成公钥
privKey = secp256k1.PrivKeyFromBytes(rawPrivKey)
//2. 计算公钥
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()))
}
//3. 计算公钥的sha256哈希值
//4. 计算上一步结果的ripemd160哈希值
if hash160, err = Ripemd160AfterSha256(pubKey); err != nil {
return "", err
}
//5. 取上一步结果,前面加入地址网络前缀
hash160WithPrefix = append([]byte{mapNet[netType]}, hash160...)
//6. 取上一步结果,计算SHA256哈希值
//7. 取上一步结果,在计算SHA256哈希值
hash256 = Sha256AfterSha256(hash160WithPrefix)
//8. 取上一步结果的前四个字节,放在第五步结果后面,作为校验
address = append(hash160WithPrefix, hash256[0:4]...)
//9. 用base58编码上一步结果
return base58.Encode(address),nil
}
下面是测试代码:
func TestNewP2PKH(t *testing.T) {
t.Run("test compressed public key to address", func(t *testing.T) {
var testcases = []struct{
originalPrivKey string
netType string
address string
} {
{
"a4f228d49910e8ecb53ba6f23f33fbfd2bad442e902ea20b8cf89c473237bf9f",
"main",
"127NVqnjf8gB9BFAW2dnQeM6wqmy1gbGtv",
},
}
var err error
var address string
for _, oneCase := range testcases {
privKey,_ := hex.DecodeString(oneCase.originalPrivKey)
if address,err = NewP2PKH(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
}
}
})
}
工具网站:
下面这个网站可以看到一步一步怎么计算得到最终结果的。BTW,这网站要才能看。
http://gobittest.appspot.com/Address
(全文完)