1. 程式人生 > >幹什麼不好,非要做程式設計師,真是敗家。

幹什麼不好,非要做程式設計師,真是敗家。

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 {
	pubKeyHash := HashPubKey(w.PublicKey)


	walletVersionedPayload := append([]byte{walletVersion}, pubKeyHash...)
	checksum := checksum(walletVersionedPayload)

	fullPayload := append(walletVersionedPayload, checksum...)
	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() {
	for i:=0; i<100;i++  {
		w := NewWallet()
		fmt.Println(w.GetAddress())
	}
}