go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易比特幣系統(tǒng)錢包的原理解析
錢包基礎(chǔ)概念
- 廣義上,錢包是一個(gè)應(yīng)用程序,為用戶提供交互界面。錢包控制用戶訪問(wèn)權(quán)限、管理比特比地址及秘鑰、跟蹤余額、創(chuàng)建交易和簽名交易
- 狹義上,即從程序員角度來(lái)看,“錢包”是指用于存儲(chǔ)和管理用戶秘鑰的數(shù)據(jù)結(jié)構(gòu)
- 錢包是私鑰的容器,一般是通過(guò)結(jié)構(gòu)化文件或簡(jiǎn)單數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)的
- 錢包中并不包含比特幣。比特幣是被記錄在比特幣網(wǎng)絡(luò)的區(qū)塊鏈中,用戶通過(guò)錢包中的密鑰簽名交易,從而控制網(wǎng)絡(luò)中的比特幣,在某種意義上,比特幣錢包就是密鑰鏈
錢包結(jié)構(gòu)體
type Wallet struct {
//私鑰
Private *ecdsa.PrivateKey
//約定,這里的PubKey不存儲(chǔ)原始的公鑰,而是存儲(chǔ)X和Y拼接的字符串,在校驗(yàn)端重新拆分(參考r,s傳遞)
PubKey []byte
}
創(chuàng)建錢包
func NewWallet() *Wallet {
//創(chuàng)建曲線
curve := elliptic.P256()
//生成私鑰
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
log.Panic(err)
}
//生成公鑰
pubKeyOrig := privateKey.PublicKey
//拼接X(jué), Y
pubKey := append(pubKeyOrig.X.Bytes(), pubKeyOrig.Y.Bytes()...)
return &Wallet{Private: privateKey, PubKey: pubKey}
}
錢包集結(jié)構(gòu)體
//定一個(gè) Wallets結(jié)構(gòu),它保存所有的wallet以及它的地址
type Wallets struct {
//map[地址]錢包
WalletsMap map[string]*Wallet
}
創(chuàng)建錢包集
func NewWallets() *Wallets {
var ws Wallets
ws.WalletsMap = make(map[string]*Wallet)
//加載本地錢包,把新建的錢包保存到本地
ws.loadFile()
return &ws
}
創(chuàng)建錢包到錢包集
func (ws *Wallets) CreateWallet() string {
//創(chuàng)建一個(gè)錢包
wallet := NewWallet()
address := wallet.NewAddress()
//添加到錢包集
ws.WalletsMap[address] = wallet
//保存包本地
ws.saveToFile()
//返回創(chuàng)建錢包的地址
return address
}
保存錢包到本地
func (ws *Wallets) saveToFile() {
var buffer bytes.Buffer
gob.Register(elliptic.P256())
encoder := gob.NewEncoder(&buffer)
err := encoder.Encode(ws)
//一定要注意校驗(yàn)!?。?
if err != nil {
log.Panic(err)
}
ioutil.WriteFile(walletFile, buffer.Bytes(), 0600)
}
讀取錢包集里的錢包
func (ws *Wallets) loadFile() {
//在讀取之前,要先確認(rèn)文件是否在,如果不存在,直接退出
_, err := os.Stat(walletFile)
if os.IsNotExist(err) {
return
}
//讀取內(nèi)容
content, err := ioutil.ReadFile(walletFile)
if err != nil {
log.Panic(err)
}
//解碼
gob.Register(elliptic.P256())
decoder := gob.NewDecoder(bytes.NewReader(content))
var wsLocal Wallets
err = decoder.Decode(&wsLocal)
if err != nil {
log.Panic(err)
}
ws.WalletsMap = wsLocal.WalletsMap
}
列出所有錢包的地址
func (ws *Wallets) ListAllAddresses() []string {
var addresses []string
//遍歷錢包,將所有的key取出來(lái)返回
for address := range ws.WalletsMap {
addresses = append(addresses, address)
}
return addresses
}
生成錢包地址
- 隨機(jī)選取32byte的數(shù)字作為私鑰
- 使用橢圓曲線加密算法(ECDSA-secp256k1)計(jì)算私鑰對(duì)應(yīng)的非壓縮公鑰
- 計(jì)算公鑰的SHA-256哈希值
- 取上一步結(jié)果,計(jì)算RIPEMD-160哈希值
- 取上一步結(jié)果,前面加上版本號(hào)(比特幣主網(wǎng)版本號(hào)“0x00”)
- 取上一步結(jié)果,計(jì)算SHA-256哈希值
- 取上一步結(jié)果,計(jì)算SHA-256哈希值
- 取上一步結(jié)果的前4個(gè)字節(jié)(8位十六進(jìn)制)
- 把這4個(gè)字節(jié)加在第五步的結(jié)果后面,作為校驗(yàn)(這就是比特幣地址的十六進(jìn)制形態(tài))
- 用base58表示法變換一下地址(這就是常見(jiàn)的比特幣地址形態(tài))
//生成地址
func (w *Wallet) NewAddress() string {
//錢包公鑰
pubKey := w.PubKey
//計(jì)算公鑰哈希和ripe160
rip160HashValue := HashPubKey(pubKey)
//主網(wǎng)版本號(hào)為0x00
version := byte(00)
//拼接version
payload := append([]byte{version}, rip160HashValue...)
//校驗(yàn)碼checksum
checkCode := CheckSum(payload)
//拼接版本、哈希值、校驗(yàn)碼、25字節(jié)數(shù)據(jù)
payload = append(payload, checkCode...)
//base58編碼
address := base58.Encode(payload)
return address
}
結(jié)束
源碼:https://gitee.com/xiaoshengdada/go_bitcoin/tree/master/v5
到此這篇關(guān)于go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易比特幣系統(tǒng)錢包的原理解析的文章就介紹到這了,更多相關(guān)go實(shí)現(xiàn)比特幣錢包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于context.Context的Golang?loader緩存請(qǐng)求放大問(wèn)題解決
這篇文章主要為大家介紹了基于context.Context的Golang?loader緩存請(qǐng)求放大解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
Golang中的sync.WaitGroup用法實(shí)例
這篇文章主要介紹了Golang中的sync.WaitGroup用法實(shí)例,WaitGroup的用途,它能夠一直等到所有的goroutine執(zhí)行完成,并且阻塞主線程的執(zhí)行,直到所有的goroutine執(zhí)行完成,需要的朋友可以參考下2015-07-07
GoLang中panic與recover函數(shù)以及defer語(yǔ)句超詳細(xì)講解
這篇文章主要介紹了GoLang的panic、recover函數(shù),以及defer語(yǔ)句,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01
Go?不支持?[]T轉(zhuǎn)換為[]interface類型詳解
這篇文章主要為大家介紹了Go不支持[]T轉(zhuǎn)換為[]interface類型詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Go語(yǔ)言學(xué)習(xí)之接口類型(interface)詳解
接口是用來(lái)定義行為的類型,定義的行為不由接口直接實(shí)現(xiàn),而由通過(guò)方法由定義的類型實(shí)現(xiàn),本文就來(lái)和大家詳細(xì)講講Go語(yǔ)言中接口的使用吧2023-03-03
Go語(yǔ)言死鎖與goroutine泄露問(wèn)題的解決
最近在工作中使用golang編程,今天的文章給大家分享一下Go語(yǔ)言死鎖與goroutine泄露問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07

