go語言實現簡易比特幣系統錢包的原理解析
錢包基礎概念
- 廣義上,錢包是一個應用程序,為用戶提供交互界面。錢包控制用戶訪問權限、管理比特比地址及秘鑰、跟蹤餘額、創建交易和簽名交易
- 狹義上,即從程序員角度來看,“錢包”是指用於存儲和管理用戶秘鑰的數據結構
- 錢包是私鑰的容器,一般是通過結構化文件或簡單數據庫來實現的
- 錢包中並不包含比特幣。比特幣是被記錄在比特幣網絡的區塊鏈中,用戶通過錢包中的密鑰簽名交易,從而控制網絡中的比特幣,在某種意義上,比特幣錢包就是密鑰鏈
錢包結構體
type Wallet struct { //私鑰 Private *ecdsa.PrivateKey //約定,這裡的PubKey不存儲原始的公鑰,而是存儲X和Y拼接的字符串,在校驗端重新拆分(參考r,s傳遞) PubKey []byte }
創建錢包
func NewWallet() *Wallet { //創建曲線 curve := elliptic.P256() //生成私鑰 privateKey, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { log.Panic(err) } //生成公鑰 pubKeyOrig := privateKey.PublicKey //拼接X, Y pubKey := append(pubKeyOrig.X.Bytes(), pubKeyOrig.Y.Bytes()...) return &Wallet{Private: privateKey, PubKey: pubKey} }
錢包集結構體
//定一個 Wallets結構,它保存所有的wallet以及它的地址 type Wallets struct { //map[地址]錢包 WalletsMap map[string]*Wallet }
創建錢包集
func NewWallets() *Wallets { var ws Wallets ws.WalletsMap = make(map[string]*Wallet) //加載本地錢包,把新建的錢包保存到本地 ws.loadFile() return &ws }
創建錢包到錢包集
func (ws *Wallets) CreateWallet() string { //創建一個錢包 wallet := NewWallet() address := wallet.NewAddress() //添加到錢包集 ws.WalletsMap[address] = wallet //保存包本地 ws.saveToFile() //返回創建錢包的地址 return address }
保存錢包到本地
func (ws *Wallets) saveToFile() { var buffer bytes.Buffer gob.Register(elliptic.P256()) encoder := gob.NewEncoder(&buffer) err := encoder.Encode(ws) //一定要註意校驗!!! if err != nil { log.Panic(err) } ioutil.WriteFile(walletFile, buffer.Bytes(), 0600) }
讀取錢包集裡的錢包
func (ws *Wallets) loadFile() { //在讀取之前,要先確認文件是否在,如果不存在,直接退出 _, err := os.Stat(walletFile) if os.IsNotExist(err) { return } //讀取內容 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取出來返回 for address := range ws.WalletsMap { addresses = append(addresses, address) } return addresses }
生成錢包地址
- 隨機選取32byte的數字作為私鑰
- 使用橢圓曲線加密算法(ECDSA-secp256k1)計算私鑰對應的非壓縮公鑰
- 計算公鑰的SHA-256哈希值
- 取上一步結果,計算RIPEMD-160哈希值
- 取上一步結果,前面加上版本號(比特幣主網版本號“0x00”)
- 取上一步結果,計算SHA-256哈希值
- 取上一步結果,計算SHA-256哈希值
- 取上一步結果的前4個字節(8位十六進制)
- 把這4個字節加在第五步的結果後面,作為校驗(這就是比特幣地址的十六進制形態)
- 用base58表示法變換一下地址(這就是常見的比特幣地址形態)
//生成地址 func (w *Wallet) NewAddress() string { //錢包公鑰 pubKey := w.PubKey //計算公鑰哈希和ripe160 rip160HashValue := HashPubKey(pubKey) //主網版本號為0x00 version := byte(00) //拼接version payload := append([]byte{version}, rip160HashValue...) //校驗碼checksum checkCode := CheckSum(payload) //拼接版本、哈希值、校驗碼、25字節數據 payload = append(payload, checkCode...) //base58編碼 address := base58.Encode(payload) return address }
結束
源碼:https://gitee.com/xiaoshengdada/go_bitcoin/tree/master/v5
到此這篇關於go語言實現簡易比特幣系統錢包的原理解析的文章就介紹到這瞭,更多相關go實現比特幣錢包內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- None Found