Implement address generation and wallets

This commit is contained in:
Ivan Kuznetsov 2017-09-07 14:18:12 +07:00
parent 373a09b2bc
commit 70c04fa8ce
4 changed files with 123 additions and 0 deletions

66
address.go Normal file
View File

@ -0,0 +1,66 @@
package main
import (
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"log"
"golang.org/x/crypto/ripemd160"
)
const version = byte(0x00)
// Wallet ...
type Wallet struct {
PrivateKey []byte
PublicKey []byte
}
// GetAddress returns wallet address
func (w Wallet) GetAddress() []byte {
publicSHA256 := sha256.Sum256(w.PublicKey)
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
}
// NewWallet ...
func NewWallet() *Wallet {
private, public := newKeyPair()
wallet := Wallet{private, public}
return &wallet
}
func newKeyPair() ([]byte, []byte) {
curve := elliptic.P256()
private, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
log.Panic(err)
}
public := append(x.Bytes(), y.Bytes()...)
return private, public
}
// Checksum ...
func checksum(payload []byte) []byte {
firstSHA := sha256.Sum256(payload)
secondSHA := sha256.Sum256(firstSHA[:])
return secondSHA[:4]
}

35
base58.go Normal file
View File

@ -0,0 +1,35 @@
package main
import (
"math/big"
)
var alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
// Base58Encode encodes a byte array to Base58
func Base58Encode(input []byte) []byte {
var result []byte
x := big.NewInt(0)
x.SetBytes(input)
base := big.NewInt(int64(len(alphabet)))
zero := big.NewInt(0)
mod := &big.Int{}
for x.Cmp(zero) != 0 {
x.DivMod(x, base, mod)
result = append(result, alphabet[mod.Int64()])
}
ReverseBytes(result)
for c := range input {
if c == 0x00 {
result = append([]byte{alphabet[0]}, result...)
} else {
break
}
}
return result
}

15
cli.go
View File

@ -17,6 +17,11 @@ func (cli *CLI) createBlockchain(address string) {
fmt.Println("Done!") fmt.Println("Done!")
} }
func (cli *CLI) createWallet() {
wallet := NewWallet()
fmt.Printf("Your address: %s\n", wallet.GetAddress())
}
func (cli *CLI) getBalance(address string) { func (cli *CLI) getBalance(address string) {
bc := NewBlockchain(address) bc := NewBlockchain(address)
defer bc.db.Close() defer bc.db.Close()
@ -83,6 +88,7 @@ func (cli *CLI) Run() {
getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError)
createBlockchainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) createBlockchainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError)
createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError)
sendCmd := flag.NewFlagSet("send", flag.ExitOnError) sendCmd := flag.NewFlagSet("send", flag.ExitOnError)
printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError)
@ -103,6 +109,11 @@ func (cli *CLI) Run() {
if err != nil { if err != nil {
log.Panic(err) log.Panic(err)
} }
case "createwallet":
err := createWalletCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "printchain": case "printchain":
err := printChainCmd.Parse(os.Args[2:]) err := printChainCmd.Parse(os.Args[2:])
if err != nil { if err != nil {
@ -134,6 +145,10 @@ func (cli *CLI) Run() {
cli.createBlockchain(*createBlockchainAddress) cli.createBlockchain(*createBlockchainAddress)
} }
if createWalletCmd.Parsed() {
cli.createWallet()
}
if printChainCmd.Parsed() { if printChainCmd.Parsed() {
cli.printChain() cli.printChain()
} }

View File

@ -16,3 +16,10 @@ func IntToHex(num int64) []byte {
return buff.Bytes() return buff.Bytes()
} }
// ReverseBytes reverses a byte array
func ReverseBytes(data []byte) {
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
}