Skip to content

Commit

Permalink
Version 0.20.
Browse files Browse the repository at this point in the history
  • Loading branch information
aiportal committed Aug 7, 2017
1 parent 6a0cf5a commit 2ff824f
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 114 deletions.
34 changes: 27 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,36 @@

A console bitcoin wallet application written in golang.

![GoWallet Account View](https://raw.githubusercontent.com/aiportal/gowallet/master/_doc/account.png)

**GoWallet uses a secret phrase and a salt phrase to generate your safe wallets.**
Project location: https://github.com/aiportal/gowallet

Secret at least 16 characters, containing uppercase letters, lowercase letters, numbers, and special characters.
salt at least 6 characters.
Secret and salt allow the use of hexadecimal notation similar to '\xff' or '\xFF' to represent a character.
**GoWallet is a safe brain wallet for bitcoin.**
Secret phrase at least 16 characters.
Salt phrase at least 6 characters.

Secret phrases should contain uppercase letters, lowercase letters, numbers, and special characters.
Both secret phrases and salt phrases can use hexadecimal notation such as \xff or \xFF to represent a character.

**It is recommended that use a more complex secret and put it on paper.**
**It's also recommended that keep your salt in mind.**

Donations are welcome at <code>[<b>1BTC</b>zvzTn7QYBwFkRRkXGcVPodwrYoQyAq](https://blockchain.info/address/1BTCzvzTn7QYBwFkRRkXGcVPodwrYoQyAq)</code>

![GoWallet Encryption Process](https://raw.githubusercontent.com/aiportal/gowallet/master/_doc/encryption.png)


**It is advisable to use more complex secret and to write secret on paper.**
**It is also recommended that salt be memorized in the brain.**
#### Advanced usage

Donations are welcome at <code>1Brn37oiWcDoTVqeP1EzbVtCz3dJ7W1Z57</code>
You can export bulk wallets using the command line.

![GoWallet Encryption Process](https://raw.githubusercontent.com/aiportal/gowallet/master/GoWallet.png)
-n or -number uint
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Number of wallets to generate.
-v or -vanity string
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Find vanity wallet address matching. (prefix)
-e or -export string
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Export wallets(child number, private key and address) in WIF format.
215 changes: 108 additions & 107 deletions gowallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,124 +4,93 @@ import (
"flag"
"fmt"
"os"
"gowallet/address"
"gowallet/view"
"gowallet/wallet"
)

const goWalletTip = `
GoWallet uses a secret phrase and a salt phrase to generate your safe wallets.
Project location: https://github.com/aiportal/gowallet
Secret at least 16 characters, containing uppercase letters, lowercase letters, numbers, and special characters.
salt at least 6 characters.
Secret and salt allow the use of hexadecimal notation similar to '\xff' or '\xFF' to represent a character.
It is advisable to use more complex secret and to write secret on paper.
It is also recommended that salt be memorized in the brain.`

const debug = true
const trace = false


func main() {
vanity, number, export := parseParams()

var passPhrase string
if _, err := os.Stat("./gowallet.wlt"); os.IsNotExist(err) {
// New wallets.
var seed []byte
if !debug {
secret, salt, err := address.InputBrainWalletSecret(goWalletTip)
if err != nil {
println(err.Error())
return
}
if trace {
println("your secret is: " + secret)
println("your salt is: " + salt)
}
passPhrase = salt
seed, err = address.GenerateBrainWalletSeed(secret, salt)
if err != nil {
println(err.Error())
return
}
} else {
seed, err = address.GenerateBrainWalletSeed("https://github.com/aiportal", "gowallet")
if err != nil {
println(err.Error())
return
}
passPhrase = "gowallet"
}

accountKey, accountPub, err := address.GenerateAccount(seed[:], 0)
number, vanity, export := parseParams()
if number > 0 {
err := generateWallets(uint32(number), vanity, export)
if err != nil {
println(err.Error())
return
}
fmt.Println("")
fmt.Println("Main account: ")
// fmt.Printf(" key: %s\n", accountKey)
fmt.Printf(" pub: %s\n", accountPub)
} else {
view.ShowSplashView(view.SplashStartView)

if vanity == "" {
wallets, err := address.GenerateWallets(accountKey, uint32(number))
var ws []*wallet.Wallet
if !wallet.IsFileExists() {
var err error
ws, err = createWallets(1, 10)
if err != nil {
println(err.Error())
fmt.Println(err.Error())
return
}
for i, w := range wallets {
encrypt, err := address.EncryptKey(w[0], passPhrase)
if err != nil {
println(err.Error())
encrypt = w[0]
}
fmt.Printf("wallet(%d): \n", i)
fmt.Printf(" private: %s\n", encrypt)
fmt.Printf(" address: %s\n", w[1])
}
if export != "" {
err := exportWallets(export, wallets)
if err != nil {
println(err.Error())
return
}
}
// save wallets
wf := wallet.NewWalletFile(ws)
wf.Save()
} else {
wallets, err := address.SearchVanities(accountKey, vanity, uint32(number),
func(i uint32, count uint32, n uint32) {
fmt.Printf("processed:%d / %d, found: %d \n", i, count, n)
})
wf, err := wallet.LoadWalletFile()
if err != nil {
println(err.Error())
fmt.Println(err.Error())
return
}
for _, w := range wallets {
fmt.Printf("wallet(%s): \n", w[2])
fmt.Printf(" private: %s\n", w[0])
fmt.Printf(" address: %s\n", w[1])
}
if export != "" {
err := exportWallets(export, wallets)
if err != nil {
println(err.Error())
return
}
}
ws = wf.Wallets
}
} else {
// Open wallets file.

showUI(ws)
}
}

func showUI(ws []*wallet.Wallet) {

accountView := view.NewAccountView(ws)
accountView.Show()

for accountView.Data != nil {
cmd := accountView.Data.(string)
if cmd == "quit" {
break
}
tipView := view.NewTipView(cmd)
if tipView != nil {
tipView.Show()
}
accountView.Show()
}
}

// create wallets by secret and salt
func createWallets(start, count uint32) (ws []*wallet.Wallet, err error) {
view.ShowSplashView(view.SplashCreateView)

// create wallets
wp, err := view.InputNewParameters(3)
if err != nil {
return
}
//wp := view.WalletParam{Secret:"https://github.com/aiportal", Salt:"gowallet"}

wa, err := wallet.NewWalletAccount(wp.SecretBytes(), wp.SaltBytes())
if err != nil {
return
}
ws, err = wa.GenerateWallets(start, count)
if err != nil {
return
}
return
}

//Parse command line parameters
func parseParams() (vanity string, number uint, export string) {
func parseParams() (number uint, vanity, export string) {

flag.StringVar(&vanity, "vanity", "", "Find vanity wallet address matching. (prefix or regular)")
flag.StringVar(&vanity, "v", "", "Find vanity wallet address matching. (prefix or regular)")
flag.UintVar(&number, "number", 0, "Number of wallets to generate.")
flag.UintVar(&number, "n", 0, "Number of wallets to generate.")

flag.UintVar(&number, "number", 1, "Number of wallets to generate. (default 1)")
flag.UintVar(&number, "n", 1, "Number of wallets to generate. (default 1)")
flag.StringVar(&vanity, "vanity", "", "Find vanity wallet address matching. (prefix)")
flag.StringVar(&vanity, "v", "", "Find vanity wallet address matching. (prefix)")

flag.StringVar(&export, "export", "", "Export wallets in WIF format.")
flag.StringVar(&export, "e", "", "Export wallets in WIF format.")
Expand All @@ -130,21 +99,53 @@ func parseParams() (vanity string, number uint, export string) {
return
}

// Export wallets
func exportWallets(filename string, wallets [][]string) (err error) {
f, err := os.Create(filename)
func generateWallets(number uint32, vanity, export string) (err error) {

view.ShowSplashView(view.SplashStartView)
view.ShowSplashView(view.SplashCreateView)
wp, err := view.InputNewParameters(3)
if err != nil {
return
}
defer f.Close()
for i, w := range wallets {
if len(w) > 2 {
f.WriteString(fmt.Sprintf("wallet(%s): \n", w[2]))
} else {
f.WriteString(fmt.Sprintf("wallet(%d): \n", i))
wa, err := wallet.NewWalletAccount(wp.SecretBytes(), wp.SaltBytes())
if err != nil {
return
}
var ws []*wallet.Wallet
if vanity == "" {
ws, err = wa.GenerateWallets(0, uint32(number))
if err != nil {
return
}
} else {
var patterns []string
patterns, err = wa.NormalizeVanities([]string{vanity})
if err != nil {
return
}
ws, err = wa.FindVanities(patterns, func(i, c, n uint32) bool {
fmt.Printf("progress: %d, %d, %d\n", i, c, n)
return (n >= number)
})
}
if export == "" {
for _, w := range ws {
fmt.Printf("wallet (%d): \n", w.No)
fmt.Println(" " + w.Private)
fmt.Println(" " + w.Address)
}
} else {
var f *os.File
f, err = os.Create(export)
if err != nil {
return
}
defer f.Close()
for _, w := range ws {
f.WriteString(fmt.Sprintf("wallet(%d): \r\n", w.No))
f.WriteString(fmt.Sprintf(" private: %s\r\n", w.Private))
f.WriteString(fmt.Sprintf(" address: %s\r\n", w.Address))
}
f.WriteString(fmt.Sprintf(" private: %s\n", w[0]))
f.WriteString(fmt.Sprintf(" address: %s\n", w[1]))
}
return
}
90 changes: 90 additions & 0 deletions wallet/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package wallet

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/user"
)

const WalletFileName = ".gowallet.w02" // version 0.2

// check if user wallet file exists
func IsFileExists() bool {
u, err := user.Current()
if err != nil {
return false
}
filename := fmt.Sprintf("%s/%s", u.HomeDir, WalletFileName)
f, err := os.Stat(filename)
if err != nil {
return false
}
if f.IsDir() {
return false
}
return true
}

type WalletFile struct {
Wallets []*Wallet
}

func NewWalletFile(ws []*Wallet) *WalletFile {
wf := new(WalletFile)
wf.Wallets = make([]*Wallet, len(ws))
for i, v := range ws {
w := NewWallet(v.No, "", v.Address)
wf.Wallets[i] = w
}
return wf
}

func LoadWalletFile() (wf *WalletFile, err error) {
u, err := user.Current()
if err != nil {
return
}
path := fmt.Sprintf("%s/%s", u.HomeDir, WalletFileName)
_, err = os.Stat(path)
if err != nil {
return
}
bs, err := ioutil.ReadFile(path)
if err != nil {
return
}
wf = new(WalletFile)
err = json.Unmarshal(bs, wf)
if err != nil {
return
}
return
}

func (wf *WalletFile) Save() (err error) {
u, err := user.Current()
if err != nil {
return
}
path := fmt.Sprintf("%s/%s", u.HomeDir, WalletFileName)

bs, err := json.Marshal(wf)
if err != nil {
return
}
err = ioutil.WriteFile(path, bs, os.ModeExclusive)
if err != nil {
return
}
return
}
//
//func (wf *WalletFile) Wallets() (ws []*Wallet) {
// ws = make([]*Wallet, len(wf.wallets))
// for i, v := range wf.wallets {
// ws[i] = v
// }
// return
//}

0 comments on commit 2ff824f

Please sign in to comment.