比特币地址
我们都知道如果想要给某个人转帐比特币的话需要知道他的钱包地址,事实上,地址是将公钥表示称人类可读性的形式,原生的公钥是很难阅读的。在比特币系统中,每个人的身份就是一对公钥跟私钥。
公钥加密算法使用的是非对称加密算法,包含了公钥跟私钥,公钥可以公开,私钥不能够公开,只有所有者菜能够知道私钥,私钥是用来识别,鉴定和证明钱包所有者的身份。在加密货币系统当中,私钥就代表着一个个体。比特币是使用椭圆曲线来产生私钥的。
我们可以来尝试生成比特币钱包地址
- 首先我们来定义钱包类
type Wallet struct {
//1.私钥
PrivateKey ecdsa.PrivateKey// 椭圆曲线加密
//2.公钥
PublicKey []byte
}
- 其次,我们定义功能用于生成一对公钥和私钥
func newKeyPair()(ecdsa.PrivateKey,[]byte) {
// 椭圆曲线对象
curve := elliptic.P256()
// 通过椭圆曲线随机产生私钥
privateKey,err := ecdsa.GenerateKey(curve,rand2.Reader)
if err != nil {
log.Panic(err)
}
// 通过私钥产生公钥
publicKey := append(privateKey.PublicKey.X.Bytes(),privateKey.PublicKey.Y.Bytes()...)
return *privateKey,publicKey
}
- 通过构造方法来产生一个钱包对象
func NewWallet() *Wallet {
privateKey,publicKey := newKeyPair()
return &Wallet{PrivateKey:privateKey,PublicKey:publicKey}
}
- 最后我们在main方法当中调用
func main() {
wallet := NewWallet()
fmt.Printf("Private:%s\n",wallet.PrivateKey)
fmt.Println("-------------")
fmt.Printf("PublickKey : %x\n",wallet.PublicKey)
}
在控制台中我们可以看到打印结果:8f7c29391ac172923a6f675c42c4a69e0f345ee8fe4d732d4e5fb7511cfe6331905bca3bdbf6e4ad94e579c7d5e3667402b8dd92fb6e358ff9373dffa4994ec0
在打印台中我们可以看到公钥是一串难以阅读的十六进制数字。所以如果我们要想让公钥变成方便人们阅读的话还需要将公钥进行处理得到所谓的地址。
比特币的地址生成如下图所示:

由上图我们可以得知比特币地址由三部分组成,分别是Version+Public key hash + Checksum,最后进行Base58编码得到的字符串就是我们想要的地址。由上面的图片我们可以写出以下代码:
1.对公钥进行两次Hash,分别是256Hash和Ripemd160Hash得到Public key hash
func Ripemd160HashAnd256Hash(publicKey []byte) []byte {
//1.hash256
hash256 := sha256.New()
hash256.Write(publicKey)
hash := hash256.Sum(nil)
//2.Ripemd160Hash
ripemd160 := ripemd1602.New()
ripemd160.Write(hash[:])
return ripemd160.Sum(nil)
}
2.得到Public key hash后需要加上生成算法版本的前缀Version
const Version = byte(0x00)
Version_Ripemd160Hash = append([]byte{Version},ripemd160hash)
3.对第二步得到的结果我们进行两次256Hash,计算出校验和,校验和是结果的前四个字节
func GetCheckSum(payload []byte) []byte {
hash1 := sha256.Sum256(payload)
hash2 := sha256.Sum256(hash1[:])
return hash2[:4]
}
4.最后我们需要对Version+Public key hash + Checksum结果进行base58编码得到地址。
- base58编码
var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
func Base58Encode(input []byte) []byte {
var result []byte
x:= big.NewInt(0).SetBytes(input)
base := big.NewInt(int64(len(b58Alphabet)))
zero := big.NewInt(0)
mod := &big.Int{}
for x.Cmp(zero) != 0{
x.DivMod(x,base,mod)
result = append(result,b58Alphabet[mod.Int64()])
}
ReverseBytes(result)
for b := range input{
if b == 0x00 {
result = append([]byte{b58Alphabet[0]},result...)
}else {
break
}
}
return result
}
func Base58Decode(input []byte) []byte {
result := big.NewInt(0)
zeroBytes := 0
for b := range input{
if b == 0x00 {
zeroBytes ++;
}
}
payload := input[zeroBytes:]
for _,b := range payload{
charIndex := bytes.IndexByte(b58Alphabet,b)
result.Mul(result,big.NewInt(58))
result.Add(result,big.NewInt(int64(charIndex)))
}
decoded := result.Bytes()
decoded = append(bytes.Repeat([]byte{byte(0x00)},zeroBytes),decoded...)
return decoded
}
func ReverseBytes(data []byte) {
for i,j := 0,len(data) - 1;i < j;i,j = i+1,j-1 {
data[i],data[j] = data[j],data[i]
}
}
给Wallet添加方法用于获取钱包对象的地址
func (wallet *Wallet)GetWalletAddress() []byte {
ripemd160Hash := Ripemd160HashAnd256Hash(wallet.PublicKey)
version_ripemd160Hash := append([]byte{byte(0x00)},ripemd160Hash...)
checkSumBytes := GetCheckSum(version_ripemd160Hash)
addressData := append(version_ripemd160Hash,checkSumBytes...)
address := Base58Encode(addressData)
return address
}
5.最后再main函数中进行调用
address := wallet.GetWalletAddress()
fmt.Printf("address : %s\n",address)
控制台输出:
1KcXhEhFJPtcpHRhHtdX3JA6xeksxf1eTK
至此我们完成了比特币地址的生成,我们可以使用该地址到blockchain.info中查询它的余额,如果这是一个正确的比特币地址,会显示目前其中余额为0,如下图:

