GO语言-生成区块链账户地址

711 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

生成区块链账户地址

为了收款方便,用户需要对外公布一个地址,这个地址其实是公钥经过一系列变化得来的。比如:比特币公钥到地址的变化过程,一个公钥经过SHA256+RIPEMD160两次叠加运算得到公钥hash,在公钥hash前防止版本号0x00,在经过SHA256后取前四个字节得到校验和checksum,将版本号+公钥+校验连接在一起,再经过base58编码,最终得到比特币地址。

// Base58Decode decodes Base58-encoded data
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
}

在main函数中调用它

func main1() {
	val := Base58Decode([]byte("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"))
	fmt.Printf("%x,%d\n", val, len(val))
	fmt.Printf("%x, %x\n", val[1:21], val[21:])
	hash1 := sha256.Sum256(val[:21])
	hash2 := sha256.Sum256(hash1[:])
	fmt.Printf("%x\n", hash2[:4])
}

将私钥生成和地址生成结合起来实现比特币地址的生成。

1、构造钱包结构

我们先构造一个钱包结构,钱包包含用户的公钥和私钥。

// 钱包结构
type Wallet struct {
	PrivateKey ecdsa.PrivateKey //私钥
	PublicKey  []byte           //公钥
}

// 创建钱包
func NewWallet() *Wallet {
	//随机生成秘钥对
	private, public := newKeyPair()
	wallet := Wallet{private, public}
	return &wallet
}

2、计算hash和ripemd160

为了获得地址,首先要对公钥进行hash运算,之后计算ripemd160

//计算公钥hash
func HashPubKey(pubKey []byte) []byte {
	//1. 先hash一次
	publicSHA256 := sha256.Sum256(pubKey)
	//2. 计算ripemd160
	RIPEMD160Hasher := ripemd160.New()
	RIPEMD160Hasher.Write(publicSHA256[:])

	publicRIPEMD160 := RIPEMD160Hasher.Sum(nil) //导包就行

	return publicRIPEMD160
}

3、计算校验和

获得hash后,就可以计算校验和了,实现一个checksum函数,计算两次hash。 //计算校验和,输入为0x00+公钥hash

const version = byte(0x00)

const ChecksumLen = 4
func checksum(payload []byte) []byte {

	firstSHA := sha256.Sum256(payload)
	secondSHA := sha256.Sum256(firstSHA[:])

	return secondSHA[:ChecksumLen]
}

4、生成地址

生成地址就是把步骤2和3的功能加上base58编码,就可以获得地址了。

//生成地址
func (w Wallet) GetAddress() []byte {
	//1. 计算公钥hash
	pubKeyHash := HashPubKey(w.PublicKey)
	//2. 计算校验和
	versionedPayload := append([]byte{version}, pubKeyHash...)
	checksum := checksum(versionedPayload)
	//3. 计算base58编码
	fullPayload := append(versionedPayload, checksum...)
	address := Base58Encode(fullPayload)

	return address
}

5、地址生成测试

func main() {
	//1. 构造钱包
	wallet := NewWallet()
	//2. 生成地址
	address := wallet.GetAddress()
	fmt.Printf("%s\n", address)
}