Skip to content

Commit

Permalink
address v0.12: Modify import packages.
Browse files Browse the repository at this point in the history
  • Loading branch information
ultragis committed Jul 17, 2017
1 parent 14e8f10 commit cd70417
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 946 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*.dll
*.so
*.dylib
*.idea

# Test binary, build with `go test -c`
*.test
Expand All @@ -13,3 +12,5 @@

# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

.idea/
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,36 @@
# gowallet
A bitcoin wallet application written in golang.

A bitcoin wallet application written in golang.
Supports random wallet and brain wallet.

<b>The brain wallet uses a secret phrase and a salt phrase</b> to generate the private key.<br/>

<b>Secret phrase at least 16 characters</b>, containing uppercase letters, lowercase letters, numbers, and special characters.<br/>
<b>Salt phrase at least 6 characters.</b><br/>

The secret phrase and the salt phrase support a hex notation similar to '\xFF' or '\xff' to represent a character.</br>

It is advisable to use more complex secret phrases and to write secret phrases on paper.<br/>
It is also recommended that salt phrases be memorized in the brain.<br/>


Usage of address:<br/>
 -b  Brain wallet mode.<br/>
 -brain<br/>
    Brain wallet mode.<br/>
 -o string<br/>
    Output file name.<br/>
 -output string<br/>
    Output file name.<br/>


# go钱包
go钱包是用GO语言编写的比特币钱包软件。支持随机钱包和脑钱包。</br>

**脑钱包使用一个秘密短语和一个盐短语生成私钥。**</br>
秘密短语至少16个字符,包含大写字母,小写字母,数字和特殊字符。</br>
盐短语至少6个字符。</br>
秘密短语和盐短语允许使用类似于'\xFF'这样的十六进制表示法表示一个字符</br>

建议使用较为复杂的秘密短语并将秘密短语记在纸上。</br>
同时建议将盐短语记在脑中。
180 changes: 87 additions & 93 deletions address.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,137 +2,115 @@ package main

import (
"bytes"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"errors"
"flag"
"fmt"
"io/ioutil"
"crypto/rand"
"os"
"regexp"
"syscall"
"./secp256k1/bitecdsa"
"./secp256k1/bitelliptic"
"github.com/btcsuite/btcutil/base58"
"github.com/fatih/color"
"github.com/njones/bitcoin-crypto/bitelliptic"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/ripemd160"
"golang.org/x/crypto/scrypt"
"golang.org/x/crypto/ssh/terminal"
)

// WarpWallet encryption:
// 1. s1 ← scrypt(key=passphrase||0x1, salt=salt||0x1, N=218, r=8, p=1, dkLen=32)
// 2. s2 ← PBKDF2(key=passphrase||0x2, salt=salt||0x2, c=216, dkLen=32)
// 3. private_key ← s1 ⊕ s2
// 4. Generate public_key from private_key using standard Bitcoin EC crypto
// 5. Output (private_key, public_key)

//脑钱包使用一个秘密短语和一个盐短语生成私钥。
//秘密短语至少16个字符,包含大写字母,小写字母,数字和特殊字符。
//盐短语至少6个字符。
//建议使用较为复杂的秘密短语并将秘密短语记在纸上。
//同时建议将盐短语记在脑中。

const brainWalletTip = `
The brain wallet uses a secret phrase and a salt phrase to generate the private key.
Secret phrase at least 16 characters, containing uppercase letters, lowercase letters, numbers, and special characters.
Salt phrase at least 6 characters.
Secret phrases and salt phrases allow the use of hexadecimal notation similar to ' \xff ' to represent a character.
It is advisable to use more complex secret phrases and to write secret phrases on paper.
It is also recommended that salt phrases be memorized in the brain.`

const debug = true
const debug = false


//Parse command line parameters
func parseCommandParams() (private string, brain bool, output string) {
flag.StringVar(&private, "private", "", "Private key wif string for test.")
func parseCommandParams() (brain bool, output string) {

flag.BoolVar(&brain, "brain", false, "Brain wallet mode.")
flag.BoolVar(&brain, "b", false, "...")
flag.BoolVar(&brain, "b", false, "Brain wallet mode.")

flag.StringVar(&output, "output", "", "Output file name. (optional)")
flag.StringVar(&output, "o", "", "...")
flag.StringVar(&output, "output", "", "Output file name.")
flag.StringVar(&output, "o", "", "Output file name.")

flag.Parse()
return
}

func main() {
private, brain, output := parseCommandParams()

var private_key [32]byte
if private == "" {
if brain == true {
// Brain wallet
secret, salt, err := inputBrainWalletSecret(brainWalletTip)
if err != nil {
println(err.Error())
return
}
//secret, salt = []byte("www.aiportal.net"), []byte("aiportal")
private_key, err = generateBrainWalletKey(secret, salt)
if err != nil {
println(err.Error())
return
}
} else {
// Random private key.
private_key_bytes, err := generateRandomBytes(32)
if err == nil {
copy(private_key[:], private_key_bytes)
} else {
println(err)
return
}
brain, output := parseCommandParams()

var seed []byte
if brain == true {
// Brain wallet
secret, salt, err := inputBrainWalletSecret(brainWalletTip)
if err != nil {
return
}
seed, err = generateBrainWalletSeed(secret, salt)
if err != nil {
println(err.Error())
return
}
} else {
// Private key from WIF string.
private_key_bytes, _, _ := base58.CheckDecode(private)
copy(private_key[:], private_key_bytes)
// Random wallet.
var err error
seed, err = generateRandomBytes(32)
if err != nil {
println(err.Error())
return
}
}

private_wif := base58.CheckEncode(private_key[:], 0x80)
private_wif, address_wif, err := GenerateWalletWif(seed)
if err != nil {
println(err.Error())
return
}
println("")
println("private: " + private_wif)

public_key := computePublicKey(private_key)
public_wif := base58.CheckEncode(public_key[:], 0x00)
println("address: " + public_wif)
println("address: " + address_wif)

if output != "" {
err := ioutil.WriteFile(output, []byte(public_wif), os.ModeAppend)
ln := fmt.Sprintf("private: %s\naddress: %s", private_wif, address_wif)
err := ioutil.WriteFile(output, []byte(ln), os.ModeAppend)
if err != nil {
fmt.Printf("Failed to write to file. %s", err)
println(err.Error())
}
}
}

// Compute the public key from private key.
func computePublicKey(privateKey [32]byte) []byte {

reader := bytes.NewReader(privateKey[:])
key, err := bitecdsa.GenerateKey(bitelliptic.S256(), reader)
// Generate wallet private key and address
func GenerateWalletWif(seed []byte) (privateWif string, addressWif string, err error) {
reader := bytes.NewReader(seed)
private_bytes, x, y, err := bitelliptic.S256().GenerateKey(reader)
if err != nil {
println(err)
return []byte{}
return
}
privateWif = base58.CheckEncode(private_bytes, 0x80)

var public_key = [65]byte{0x04}
x_bytes := key.X.Bytes()
y_bytes := key.Y.Bytes()
copy(public_key[33-len(x_bytes):], x_bytes)
copy(public_key[65-len(y_bytes):], y_bytes)
var public_bytes = [65]byte{0x04}
copy(public_bytes[33 - len(x.Bytes()):], x.Bytes())
copy(public_bytes[65 - len(y.Bytes()):], y.Bytes())

public_key_sha := sha256.Sum256(public_key[:])
public_sha := sha256.Sum256(public_bytes[:])

ripeHash := ripemd160.New()
ripeHash.Write(public_key_sha[:])
public_key_ripe := ripeHash.Sum(nil)
ripeHash.Write(public_sha[:])
public_ripe := ripeHash.Sum(nil)

return public_key_ripe[:]
addressWif = base58.CheckEncode(public_ripe, 0x00)
return
}

//Generate secure random private key seed.
Expand All @@ -154,6 +132,7 @@ func inputBrainWalletSecret(tip string) (secret []byte, salt []byte, err error)
color.Yellow(tip)
println("")

terminal.MakeRaw(int(os.Stdin.Fd()))
t := terminal.NewTerminal(os.Stdin, "")

// Secret
Expand Down Expand Up @@ -196,7 +175,7 @@ func inputBrainWalletSecret(tip string) (secret []byte, salt []byte, err error)
}
if debug { print(salt1) }
println("")
if len(salt1) < 6 {
if len(escapeHexString(salt1)) < 6 {
color.HiRed(" Salt at least 6 characters.")
err = errInput
return
Expand All @@ -217,6 +196,10 @@ func inputBrainWalletSecret(tip string) (secret []byte, salt []byte, err error)

secret = escapeHexString(secret1)
salt = escapeHexString(salt1)
if debug {
fmt.Printf("secret: %X\n", secret)
fmt.Printf("salt: %X\n", salt)
}
return
}

Expand All @@ -238,20 +221,29 @@ func escapeHexString(str string) []byte {
}

//Check secret strength
func checkSecretStrength(secret string) (valid bool) {
func checkSecretStrength(secret string) bool {
number, _ := regexp.MatchString("[0-9]+", secret)
lower, _ := regexp.MatchString("[a-z]+", secret)
upper, _ := regexp.MatchString("[A-Z]+", secret)
special, _ := regexp.MatchString("[^0-9a-zA-Z ]", secret)
valid = number && lower && upper && special
return
return number && lower && upper && special
}

// Generate private key from secret and salt
func generateBrainWalletKey(secret []byte, salt []byte) (key [32]byte, err error) {

if len(secret) == 0 || len(salt) < 0 {
err = errors.New("empty secret or salt")
// Generate wallet seed from secret and salt
func generateBrainWalletSeed(secret []byte, salt []byte) (seed []byte, err error) {
// WarpWallet encryption:
// 1. s1 ← scrypt(key=passphrase||0x1, salt=salt||0x1, N=218, r=8, p=1, dkLen=32)
// 2. s2 ← PBKDF2(key=passphrase||0x2, salt=salt||0x2, c=216, dkLen=32)
// 3. private_key ← s1 ⊕ s2
// 4. Generate public_key from private_key using standard Bitcoin EC crypto
// 5. Output (private_key, public_key)

if len(secret) == 0 {
err = errors.New("Empty secret")
return
}
if len(salt) < 0 {
err = errors.New("Empty salt")
return
}

Expand All @@ -261,32 +253,34 @@ func generateBrainWalletKey(secret []byte, salt []byte) (key [32]byte, err error
secret1[i] = v | 0x1
secret2[i] = v | 0x2
}

salt1 := make([]byte, len(salt))
salt2 := make([]byte, len(salt))
for i, v := range salt {
salt1[i] = v | 0x1
salt2[i] = v | 0x2
}
key1, err := scrypt.Key(secret1, salt1, 16384, 8, 1, 32)

s1, err := scrypt.Key(secret1, salt1, 16384, 8, 1, 32)
if err != nil {
return
}
key2 := pbkdf2.Key(secret2, salt2, 4096, 32, sha1.New)
s2 := pbkdf2.Key(secret2, salt2, 4096, 32, sha1.New)

pk1, err := bitecdsa.GenerateKey(bitelliptic.S256(), bytes.NewReader(key1))
_, x1, y1, err := bitelliptic.S256().GenerateKey(bytes.NewReader(s1))
if err != nil {
return
}
pk2, err := bitecdsa.GenerateKey(bitelliptic.S256(), bytes.NewReader(key2))
_, x2, y2, err := bitelliptic.S256().GenerateKey(bytes.NewReader(s2))
if err != nil {
return
}
x, y := bitelliptic.S256().Add(pk1.X, pk1.Y, pk2.X, pk2.Y)

key_bytes := []byte{0x04}
key_bytes = append(key_bytes, x.Bytes()...)
key_bytes = append(key_bytes, y.Bytes()...)
key = sha256.Sum256(key_bytes[:])
x, y := bitelliptic.S256().Add(x1, y1, x2, y2)

seed = []byte{0x04}
seed = append(seed, x.Bytes()...)
seed = append(seed, y.Bytes()...)

return
}
Loading

0 comments on commit cd70417

Please sign in to comment.