Skip to content

Commit 2ff824f

Browse files
committed
Version 0.20.
1 parent 6a0cf5a commit 2ff824f

File tree

3 files changed

+225
-114
lines changed

3 files changed

+225
-114
lines changed

README.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,36 @@
22

33
A console bitcoin wallet application written in golang.
44

5+
![GoWallet Account View](https://raw.githubusercontent.com/aiportal/gowallet/master/_doc/account.png)
6+
57
**GoWallet uses a secret phrase and a salt phrase to generate your safe wallets.**
68
Project location: https://github.com/aiportal/gowallet
79

8-
Secret at least 16 characters, containing uppercase letters, lowercase letters, numbers, and special characters.
9-
salt at least 6 characters.
10-
Secret and salt allow the use of hexadecimal notation similar to '\xff' or '\xFF' to represent a character.
10+
**GoWallet is a safe brain wallet for bitcoin.**
11+
Secret phrase at least 16 characters.
12+
Salt phrase at least 6 characters.
13+
14+
Secret phrases should contain uppercase letters, lowercase letters, numbers, and special characters.
15+
Both secret phrases and salt phrases can use hexadecimal notation such as \xff or \xFF to represent a character.
16+
17+
**It is recommended that use a more complex secret and put it on paper.**
18+
**It's also recommended that keep your salt in mind.**
19+
20+
Donations are welcome at <code>[<b>1BTC</b>zvzTn7QYBwFkRRkXGcVPodwrYoQyAq](https://blockchain.info/address/1BTCzvzTn7QYBwFkRRkXGcVPodwrYoQyAq)</code>
21+
22+
![GoWallet Encryption Process](https://raw.githubusercontent.com/aiportal/gowallet/master/_doc/encryption.png)
23+
1124

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

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

17-
![GoWallet Encryption Process](https://raw.githubusercontent.com/aiportal/gowallet/master/GoWallet.png)
29+
-n or -number uint
30+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
31+
Number of wallets to generate.
32+
-v or -vanity string
33+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
34+
Find vanity wallet address matching. (prefix)
35+
-e or -export string
36+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
37+
Export wallets(child number, private key and address) in WIF format.

gowallet.go

Lines changed: 108 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -4,124 +4,93 @@ import (
44
"flag"
55
"fmt"
66
"os"
7-
"gowallet/address"
7+
"gowallet/view"
8+
"gowallet/wallet"
89
)
910

10-
const goWalletTip = `
11-
GoWallet uses a secret phrase and a salt phrase to generate your safe wallets.
12-
Project location: https://github.com/aiportal/gowallet
13-
14-
Secret at least 16 characters, containing uppercase letters, lowercase letters, numbers, and special characters.
15-
salt at least 6 characters.
16-
Secret and salt allow the use of hexadecimal notation similar to '\xff' or '\xFF' to represent a character.
17-
18-
It is advisable to use more complex secret and to write secret on paper.
19-
It is also recommended that salt be memorized in the brain.`
20-
21-
const debug = true
22-
const trace = false
23-
24-
2511
func main() {
26-
vanity, number, export := parseParams()
27-
28-
var passPhrase string
29-
if _, err := os.Stat("./gowallet.wlt"); os.IsNotExist(err) {
30-
// New wallets.
31-
var seed []byte
32-
if !debug {
33-
secret, salt, err := address.InputBrainWalletSecret(goWalletTip)
34-
if err != nil {
35-
println(err.Error())
36-
return
37-
}
38-
if trace {
39-
println("your secret is: " + secret)
40-
println("your salt is: " + salt)
41-
}
42-
passPhrase = salt
43-
seed, err = address.GenerateBrainWalletSeed(secret, salt)
44-
if err != nil {
45-
println(err.Error())
46-
return
47-
}
48-
} else {
49-
seed, err = address.GenerateBrainWalletSeed("https://github.com/aiportal", "gowallet")
50-
if err != nil {
51-
println(err.Error())
52-
return
53-
}
54-
passPhrase = "gowallet"
55-
}
56-
57-
accountKey, accountPub, err := address.GenerateAccount(seed[:], 0)
12+
number, vanity, export := parseParams()
13+
if number > 0 {
14+
err := generateWallets(uint32(number), vanity, export)
5815
if err != nil {
5916
println(err.Error())
6017
return
6118
}
62-
fmt.Println("")
63-
fmt.Println("Main account: ")
64-
// fmt.Printf(" key: %s\n", accountKey)
65-
fmt.Printf(" pub: %s\n", accountPub)
19+
} else {
20+
view.ShowSplashView(view.SplashStartView)
6621

67-
if vanity == "" {
68-
wallets, err := address.GenerateWallets(accountKey, uint32(number))
22+
var ws []*wallet.Wallet
23+
if !wallet.IsFileExists() {
24+
var err error
25+
ws, err = createWallets(1, 10)
6926
if err != nil {
70-
println(err.Error())
27+
fmt.Println(err.Error())
7128
return
7229
}
73-
for i, w := range wallets {
74-
encrypt, err := address.EncryptKey(w[0], passPhrase)
75-
if err != nil {
76-
println(err.Error())
77-
encrypt = w[0]
78-
}
79-
fmt.Printf("wallet(%d): \n", i)
80-
fmt.Printf(" private: %s\n", encrypt)
81-
fmt.Printf(" address: %s\n", w[1])
82-
}
83-
if export != "" {
84-
err := exportWallets(export, wallets)
85-
if err != nil {
86-
println(err.Error())
87-
return
88-
}
89-
}
30+
// save wallets
31+
wf := wallet.NewWalletFile(ws)
32+
wf.Save()
9033
} else {
91-
wallets, err := address.SearchVanities(accountKey, vanity, uint32(number),
92-
func(i uint32, count uint32, n uint32) {
93-
fmt.Printf("processed:%d / %d, found: %d \n", i, count, n)
94-
})
34+
wf, err := wallet.LoadWalletFile()
9535
if err != nil {
96-
println(err.Error())
36+
fmt.Println(err.Error())
9737
return
9838
}
99-
for _, w := range wallets {
100-
fmt.Printf("wallet(%s): \n", w[2])
101-
fmt.Printf(" private: %s\n", w[0])
102-
fmt.Printf(" address: %s\n", w[1])
103-
}
104-
if export != "" {
105-
err := exportWallets(export, wallets)
106-
if err != nil {
107-
println(err.Error())
108-
return
109-
}
110-
}
39+
ws = wf.Wallets
11140
}
112-
} else {
113-
// Open wallets file.
41+
42+
showUI(ws)
43+
}
44+
}
45+
46+
func showUI(ws []*wallet.Wallet) {
47+
48+
accountView := view.NewAccountView(ws)
49+
accountView.Show()
50+
51+
for accountView.Data != nil {
52+
cmd := accountView.Data.(string)
53+
if cmd == "quit" {
54+
break
55+
}
56+
tipView := view.NewTipView(cmd)
57+
if tipView != nil {
58+
tipView.Show()
59+
}
60+
accountView.Show()
11461
}
11562
}
11663

64+
// create wallets by secret and salt
65+
func createWallets(start, count uint32) (ws []*wallet.Wallet, err error) {
66+
view.ShowSplashView(view.SplashCreateView)
67+
68+
// create wallets
69+
wp, err := view.InputNewParameters(3)
70+
if err != nil {
71+
return
72+
}
73+
//wp := view.WalletParam{Secret:"https://github.com/aiportal", Salt:"gowallet"}
74+
75+
wa, err := wallet.NewWalletAccount(wp.SecretBytes(), wp.SaltBytes())
76+
if err != nil {
77+
return
78+
}
79+
ws, err = wa.GenerateWallets(start, count)
80+
if err != nil {
81+
return
82+
}
83+
return
84+
}
85+
11786
//Parse command line parameters
118-
func parseParams() (vanity string, number uint, export string) {
87+
func parseParams() (number uint, vanity, export string) {
11988

120-
flag.StringVar(&vanity, "vanity", "", "Find vanity wallet address matching. (prefix or regular)")
121-
flag.StringVar(&vanity, "v", "", "Find vanity wallet address matching. (prefix or regular)")
89+
flag.UintVar(&number, "number", 0, "Number of wallets to generate.")
90+
flag.UintVar(&number, "n", 0, "Number of wallets to generate.")
12291

123-
flag.UintVar(&number, "number", 1, "Number of wallets to generate. (default 1)")
124-
flag.UintVar(&number, "n", 1, "Number of wallets to generate. (default 1)")
92+
flag.StringVar(&vanity, "vanity", "", "Find vanity wallet address matching. (prefix)")
93+
flag.StringVar(&vanity, "v", "", "Find vanity wallet address matching. (prefix)")
12594

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

133-
// Export wallets
134-
func exportWallets(filename string, wallets [][]string) (err error) {
135-
f, err := os.Create(filename)
102+
func generateWallets(number uint32, vanity, export string) (err error) {
103+
104+
view.ShowSplashView(view.SplashStartView)
105+
view.ShowSplashView(view.SplashCreateView)
106+
wp, err := view.InputNewParameters(3)
136107
if err != nil {
137108
return
138109
}
139-
defer f.Close()
140-
for i, w := range wallets {
141-
if len(w) > 2 {
142-
f.WriteString(fmt.Sprintf("wallet(%s): \n", w[2]))
143-
} else {
144-
f.WriteString(fmt.Sprintf("wallet(%d): \n", i))
110+
wa, err := wallet.NewWalletAccount(wp.SecretBytes(), wp.SaltBytes())
111+
if err != nil {
112+
return
113+
}
114+
var ws []*wallet.Wallet
115+
if vanity == "" {
116+
ws, err = wa.GenerateWallets(0, uint32(number))
117+
if err != nil {
118+
return
119+
}
120+
} else {
121+
var patterns []string
122+
patterns, err = wa.NormalizeVanities([]string{vanity})
123+
if err != nil {
124+
return
125+
}
126+
ws, err = wa.FindVanities(patterns, func(i, c, n uint32) bool {
127+
fmt.Printf("progress: %d, %d, %d\n", i, c, n)
128+
return (n >= number)
129+
})
130+
}
131+
if export == "" {
132+
for _, w := range ws {
133+
fmt.Printf("wallet (%d): \n", w.No)
134+
fmt.Println(" " + w.Private)
135+
fmt.Println(" " + w.Address)
136+
}
137+
} else {
138+
var f *os.File
139+
f, err = os.Create(export)
140+
if err != nil {
141+
return
142+
}
143+
defer f.Close()
144+
for _, w := range ws {
145+
f.WriteString(fmt.Sprintf("wallet(%d): \r\n", w.No))
146+
f.WriteString(fmt.Sprintf(" private: %s\r\n", w.Private))
147+
f.WriteString(fmt.Sprintf(" address: %s\r\n", w.Address))
145148
}
146-
f.WriteString(fmt.Sprintf(" private: %s\n", w[0]))
147-
f.WriteString(fmt.Sprintf(" address: %s\n", w[1]))
148149
}
149150
return
150151
}

wallet/file.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package wallet
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
"os/user"
9+
)
10+
11+
const WalletFileName = ".gowallet.w02" // version 0.2
12+
13+
// check if user wallet file exists
14+
func IsFileExists() bool {
15+
u, err := user.Current()
16+
if err != nil {
17+
return false
18+
}
19+
filename := fmt.Sprintf("%s/%s", u.HomeDir, WalletFileName)
20+
f, err := os.Stat(filename)
21+
if err != nil {
22+
return false
23+
}
24+
if f.IsDir() {
25+
return false
26+
}
27+
return true
28+
}
29+
30+
type WalletFile struct {
31+
Wallets []*Wallet
32+
}
33+
34+
func NewWalletFile(ws []*Wallet) *WalletFile {
35+
wf := new(WalletFile)
36+
wf.Wallets = make([]*Wallet, len(ws))
37+
for i, v := range ws {
38+
w := NewWallet(v.No, "", v.Address)
39+
wf.Wallets[i] = w
40+
}
41+
return wf
42+
}
43+
44+
func LoadWalletFile() (wf *WalletFile, err error) {
45+
u, err := user.Current()
46+
if err != nil {
47+
return
48+
}
49+
path := fmt.Sprintf("%s/%s", u.HomeDir, WalletFileName)
50+
_, err = os.Stat(path)
51+
if err != nil {
52+
return
53+
}
54+
bs, err := ioutil.ReadFile(path)
55+
if err != nil {
56+
return
57+
}
58+
wf = new(WalletFile)
59+
err = json.Unmarshal(bs, wf)
60+
if err != nil {
61+
return
62+
}
63+
return
64+
}
65+
66+
func (wf *WalletFile) Save() (err error) {
67+
u, err := user.Current()
68+
if err != nil {
69+
return
70+
}
71+
path := fmt.Sprintf("%s/%s", u.HomeDir, WalletFileName)
72+
73+
bs, err := json.Marshal(wf)
74+
if err != nil {
75+
return
76+
}
77+
err = ioutil.WriteFile(path, bs, os.ModeExclusive)
78+
if err != nil {
79+
return
80+
}
81+
return
82+
}
83+
//
84+
//func (wf *WalletFile) Wallets() (ws []*Wallet) {
85+
// ws = make([]*Wallet, len(wf.wallets))
86+
// for i, v := range wf.wallets {
87+
// ws[i] = v
88+
// }
89+
// return
90+
//}

0 commit comments

Comments
 (0)