比特币 BTC 地址生成算法 go语言版

比特币地址的组成: 【版本 + 公钥哈希 + 校验和】,长度为26位到34位。

  • 版本:默认0x00, 即可空白的一字节。
  • 公钥哈希:就是给公钥做哈希算法得出的结果。
  • 校验和:将 [版本 + 公钥哈希] sha256两次,取头 4 个字符作为校验和。

1. 比特币地址生成步骤

  • 通过椭圆曲线算法生成私钥和公钥
  • 对公钥进行 sha256 散列和 ripemd160 散列,获得 pubKeyHash;
  • 在 pubKeyHash 前面加上 version(版本)字节数组,获得 walletVersionedPayload;
  • 对 walletVersionedPayload 进行两次 sha256 散列并取前4位字节,获得 checksum;
  • 将 checksum 拼接到 walletVersionedPayload 后面,获得公钥的最终 Hash 即 fullPayload;
  • 最后将 ç=fullPayload 进行 Base58 编码,得到比特币地址。

2. 比特币地址生成流程

3. 比特币地址生成源码

package main

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"log"
	"fmt"

	"golang.org/x/crypto/ripemd160"
	"github.com/btcsuite/btcutil/base58"
)

const walletVersion = byte(0x00) // 钱包版本
const addressChecksumLen = 4 // 验证码长度

// 钱包
type Wallet struct {
	PrivateKey ecdsa.PrivateKey
	PublicKey  []byte
}

// 初始化钱包
func NewWallet() *Wallet {
	private, public := newKeyPair()
	wallet := Wallet{private, public}

	return &wallet
}

// 得到比特币地址
func (w Wallet) GetAddress() string {
	// ripemd160(sha256(publickey))
	pubKeyHash := HashPubKey(w.PublicKey)

	// 最前面添加一个字节的版本信息
	walletVersionedPayload := append([]byte{walletVersion}, pubKeyHash...)

	// 获得 sha256(sha256(versionPublickeyHash)) 四个字节
	checksum := checksum(walletVersionedPayload)

	// 拼接 walletVersionedPayload + checksumHash
	fullPayload := append(walletVersionedPayload, checksum...)

	// 进行 base58 编码,生成可视化地址
	address := base58.Encode(fullPayload)

	// 比特币地址格式:【钱包版本 + 公钥哈希 + 验证码】
	return address
}

// 得到公钥哈希
func HashPubKey(pubKey []byte) []byte {
	publicSHA256 := sha256.Sum256(pubKey)

	RIPEMD160Hasher := ripemd160.New()
	_, err := RIPEMD160Hasher.Write(publicSHA256[:])
	if err != nil {
		log.Panic(err)
	}
	publicRIPEMD160 := RIPEMD160Hasher.Sum(nil)

	return publicRIPEMD160
}

// 通过【钱包版本+公钥哈希】生成验证码
func checksum(payload []byte) []byte {
	firstSHA := sha256.Sum256(payload)
	secondSHA := sha256.Sum256(firstSHA[:])

	return secondSHA[:addressChecksumLen]
}

// 创建新的私钥、公钥
func newKeyPair() (ecdsa.PrivateKey, []byte) {
	curve := elliptic.P256()
	private, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		log.Panic(err)
	}
	pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...)

	return *private, pubKey
}

// 验证比特币地址
func ValidateAddress(address string) bool {
	pubKeyHash := base58.Decode(address)
	actualChecksum := pubKeyHash[len(pubKeyHash)-addressChecksumLen:]
	version := pubKeyHash[0]
	pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-addressChecksumLen]
	targetChecksum := checksum(append([]byte{version}, pubKeyHash...))

	return bytes.Compare(actualChecksum, targetChecksum) == 0
}


func main() {
	wallet := NewWallet()
	bitcoinAddress := wallet.GetAddress()
	fmt.Println("比特币地址:", string(bitcoinAddress))
	fmt.Printf("比特币地址是否有效:%v\n:", ValidateAddress(string(bitcoinAddress)))
}

下一章:ECC 椭圆曲线加密算法

椭圆曲线加密算法(Elliptic Curve Cryptography),简称 ECC,是基于椭圆曲线数学理论实现的一种非对称加密算法。ECC 相比 RSA,ECC 优势是可以使用更短的密钥,来实现与 RSA 相 ...