Skip to content

Commit

Permalink
Stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
apottere committed Dec 31, 2022
1 parent 72e835c commit 8e27ebb
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 65 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ go run main.go 256 "m/44'/60'/0'/0"

```
go build -o ./bin/vanity-wallet
```
```

For linux:
```
GOOS=linux GOARCH=amd64 go build -o ./bin/vanity-wallet-linux-amd64
```
176 changes: 112 additions & 64 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"fmt"
"github.com/apottere/go-vanity-wallet/utils"
"github.com/dustinxie/ecc"
"github.com/wealdtech/go-merkletree/keccak256"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/sha3"
"hash"
"math/big"
"os"
"strconv"
"strings"
"sync"
)

func fatal(a ...any) {
Expand All @@ -33,13 +35,115 @@ const hardenedLimit = 0x80000000
var seedSalt = []byte("mnemonic")
var masterKeySeed = []byte("Bitcoin seed")

func loop(wg *sync.WaitGroup, entropyInt int, derivation []DerivationPart) {
defer wg.Done()
entropy := utils.NewEntropyInfo(entropyInt)

// Shared vars
var err error
var mnemonic []byte
var seed []byte
var currentHash hash.Hash
var I []byte
var chainCode []byte
var privateKeyBytes []byte
var x, y *big.Int

p256k1 := ecc.P256k1()
n := p256k1.Params().N
keccak := sha3.NewLegacyKeccak256()
zero := big.NewInt(0)
zeroByte := []byte{0}
bytePrefix := []byte{0}
privateKey := new(big.Int)
newPrivateKey := new(big.Int)
publicKey := make([]byte, 64)
publicKeyLeft := publicKey[:32]
publicKeyRight := publicKey[32:]
tempIntBytes := make([]byte, 32)
skip := false
var count uint64 = 0

for {
// Generate random mnemonic
mnemonic, err = utils.RandomMnemonic(entropy)
if err != nil {
panic(err)
}

// Create seed from mnemonic
seed = pbkdf2.Key(mnemonic, seedSalt, 2048, 64, sha512.New)
currentHash = hmac.New(sha512.New, masterKeySeed)
currentHash.Write(seed)
I = currentHash.Sum(nil)
privateKeyBytes = I[:32]
privateKey.SetBytes(privateKeyBytes)
chainCode = I[32:]

// Derive private key
skip = false
for _, part := range derivation {
currentHash = hmac.New(sha512.New, chainCode)
if part.i >= hardenedLimit {
currentHash.Write(zeroByte)
currentHash.Write(privateKeyBytes)
currentHash.Write(part.serialized)
I = currentHash.Sum(nil)
} else {
x, y := p256k1.ScalarBaseMult(privateKeyBytes)
bytePrefix[0] = 2 + byte(y.Bit(0))
currentHash.Write(bytePrefix)
currentHash.Write(x.FillBytes(tempIntBytes))
currentHash.Write(part.serialized)
I = currentHash.Sum(nil)
}

newPrivateKey.SetBytes(I[:32])
newPrivateKey.Add(newPrivateKey, privateKey)
privateKey.Mod(newPrivateKey, n)
if privateKey.Cmp(zero) == 0 || privateKey.Cmp(n) != -1 {
fmt.Println("Private key is invalid, skipping!")
skip = true
break
}

privateKeyBytes = privateKey.FillBytes(tempIntBytes)
chainCode = I[32:]
}
count += 1
if skip {
continue
}

// Derive address
x, y = p256k1.ScalarBaseMult(privateKeyBytes)
x.FillBytes(publicKeyLeft)
y.FillBytes(publicKeyRight)
keccak.Reset()
keccak.Write(publicKey)
address := keccak.Sum(nil)[12:]

if address[0] == 0x1b && address[1] == 0x0 && address[2] == 0x0 {
result := fmt.Sprintf("0x%x", address)
result += "\t" + string(mnemonic)
fmt.Println(result)
}
}
}

func main() {
args := os.Args[1:]
if len(args) == 0 {
fatal("usage: vanity-wallet <entropy> [derivation path]")
}

entropyString := args[0]
threadsString := args[0]
threads, err := strconv.Atoi(threadsString)
if err != nil || threads < 1 {
fatal("invalid thread count:", threadsString)
}

entropyString := args[1]
entropyInt, err := strconv.Atoi(entropyString)
if err != nil {
fatal("invalid entropy:", entropyString)
Expand All @@ -49,7 +153,7 @@ func main() {
fatal("entropy must be a multiple of 32 between 128 and 256 (inclusive)")
}

derivationString := args[1]
derivationString := args[2]
derivationStringArray := strings.Split(derivationString, "/")
if len(derivationStringArray) < 2 || derivationStringArray[0] != "m" {
fatal("invalid derivation path:", derivationString)
Expand Down Expand Up @@ -92,68 +196,12 @@ func main() {
derivationStringOut += fmt.Sprintf("0x%X", part.serialized)
}

entropy := utils.NewEntropyInfo(entropyInt)

fmt.Println("Mnemonic Length:", entropy.MnemonicWordCount)
fmt.Println("Derivation Path:", derivationStringOut)

p256k1 := ecc.P256k1()
n := p256k1.Params().N

// Generate random mnemonic
mnemonic, err := utils.RandomMnemonic(entropy)
if err != nil {
panic(err)
}

fmt.Println("Random Mnemonic:", string(mnemonic))

// Create seed from mnemonic
seed := pbkdf2.Key(mnemonic, seedSalt, 2048, 64, sha512.New)
hash := hmac.New(sha512.New, masterKeySeed)
hash.Write(seed)
I := hash.Sum(nil)
privateKeyBytes := I[:32]
privateKey := new(big.Int).SetBytes(privateKeyBytes)
chainCode := I[32:]

// Derive private key
for _, part := range derivation {
hash = hmac.New(sha512.New, chainCode)
if part.i >= hardenedLimit {
hash.Write([]byte{0})
hash.Write(privateKeyBytes)
hash.Write(part.serialized)
I = hash.Sum(nil)
} else {
x, y := p256k1.ScalarBaseMult(privateKeyBytes)
hash.Write([]byte{byte(2 + y.Bit(0))})
hash.Write(x.FillBytes(make([]byte, 32)))
hash.Write(part.serialized)
I = hash.Sum(nil)
}

parsedLeft := new(big.Int).SetBytes(I[:32])
newPrivateKey := new(big.Int).Add(parsedLeft, privateKey)
privateKey = new(big.Int).Mod(newPrivateKey, n)
if privateKey.Cmp(big.NewInt(0)) == 0 || privateKey.Cmp(n) != -1 {
panic("invalid private key!") // TODO: skip this mnemonic and try again
}

privateKeyBytes = privateKey.FillBytes(make([]byte, 32))
chainCode = I[32:]
var wg sync.WaitGroup
for i := 0; i < threads; i++ {
wg.Add(1)
go loop(&wg, entropyInt, derivation)
}

// Derive address
x, y := p256k1.ScalarBaseMult(privateKeyBytes)
keccak := keccak256.New()
publicKey := make([]byte, 64)
x.FillBytes(publicKey[:32])
y.FillBytes(publicKey[32:])
address := keccak.Hash(publicKey)[12:]
fmt.Printf("Address: 0x%x\n", address)

// TODO: optimize
// TODO: loop
// TODO: check public key for vanity
wg.Wait()
}

0 comments on commit 8e27ebb

Please sign in to comment.