blockchain_go/wallet.go

156 lines
3.0 KiB
Go
Raw Normal View History

package main
import (
2017-09-07 04:42:38 -05:00
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
2017-09-07 04:42:38 -05:00
"encoding/gob"
2017-09-07 21:46:06 -05:00
"fmt"
2017-09-07 04:42:38 -05:00
"io/ioutil"
"log"
"os"
"golang.org/x/crypto/ripemd160"
)
const version = byte(0x00)
2017-09-07 04:42:38 -05:00
const walletFile = "wallet.dat"
2017-09-07 21:46:06 -05:00
// Wallet stores private and public keys
type Wallet struct {
PrivateKey ecdsa.PrivateKey
PublicKey ecdsa.PublicKey
}
2017-09-07 21:46:06 -05:00
// Wallets stores a collection of wallets
type Wallets struct {
Wallets map[string]*Wallet
}
// GetAddress returns wallet address
func (w Wallet) GetAddress() []byte {
public := append(w.PublicKey.X.Bytes(), w.PublicKey.Y.Bytes()...)
publicSHA256 := sha256.Sum256(public)
RIPEMD160Hasher := ripemd160.New()
_, err := RIPEMD160Hasher.Write(publicSHA256[:])
if err != nil {
log.Panic(err)
}
publicRIPEMD160 := RIPEMD160Hasher.Sum(nil)
versionedPayload := append([]byte{version}, publicRIPEMD160...)
checksum := checksum(versionedPayload)
fullPayload := append(versionedPayload, checksum...)
address := Base58Encode(fullPayload)
return address
}
2017-09-07 21:46:06 -05:00
// NewWallet creates and returns a Wallet
func NewWallet() *Wallet {
private, public := newKeyPair()
wallet := Wallet{private, public}
return &wallet
}
func newKeyPair() (ecdsa.PrivateKey, ecdsa.PublicKey) {
curve := elliptic.P256()
private, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
log.Panic(err)
}
return *private, private.PublicKey
}
// CreateWallet adds a Wallet to Wallets
func (ws *Wallets) CreateWallet() string {
wallet := NewWallet()
address := fmt.Sprintf("%s", wallet.GetAddress())
ws.Wallets[address] = wallet
return address
}
// SaveToFile saves wallets to a file
func (ws Wallets) SaveToFile() {
2017-09-07 04:42:38 -05:00
var content bytes.Buffer
2017-09-07 04:33:17 -05:00
2017-09-07 21:46:06 -05:00
gob.Register(elliptic.P256())
2017-09-07 04:42:38 -05:00
encoder := gob.NewEncoder(&content)
2017-09-07 21:46:06 -05:00
err := encoder.Encode(ws)
2017-09-07 04:42:38 -05:00
if err != nil {
log.Panic(err)
}
err = ioutil.WriteFile(walletFile, content.Bytes(), 0644)
if err != nil {
log.Panic(err)
}
2017-09-07 04:33:17 -05:00
}
2017-09-07 21:46:06 -05:00
// LoadFromFile loads wallets from the file
func (ws *Wallets) LoadFromFile() error {
if _, err := os.Stat(walletFile); os.IsNotExist(err) {
return err
}
2017-09-07 21:46:06 -05:00
fileContent, err := ioutil.ReadFile(walletFile)
if err != nil {
log.Panic(err)
}
2017-09-07 21:46:06 -05:00
var wallets Wallets
gob.Register(elliptic.P256())
decoder := gob.NewDecoder(bytes.NewReader(fileContent))
err = decoder.Decode(&wallets)
if err != nil {
log.Panic(err)
}
2017-09-07 21:46:06 -05:00
ws.Wallets = wallets.Wallets
return nil
}
2017-09-07 21:51:44 -05:00
// GetAddresses returns an array of addresses stored in the wallet file
func (ws *Wallets) GetAddresses() []string {
var addresses []string
for address := range ws.Wallets {
addresses = append(addresses, address)
}
return addresses
}
2017-09-07 21:46:06 -05:00
// NewWallets ...
func NewWallets() *Wallets {
wallets := Wallets{}
wallets.Wallets = make(map[string]*Wallet)
err := wallets.LoadFromFile()
if err != nil {
fmt.Println("Wallets file doesn't exist")
// wallets.CreateWallet()
// wallets.SaveToFile()
}
return &wallets
}
// Checksum ...
func checksum(payload []byte) []byte {
firstSHA := sha256.Sum256(payload)
secondSHA := sha256.Sum256(firstSHA[:])
return secondSHA[:4]
}