Skip to content

Instantly share code, notes, and snippets.

@eliquious
Last active May 13, 2019 11:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eliquious/5e51207708a8c338274f5aeddc2a8a69 to your computer and use it in GitHub Desktop.
Save eliquious/5e51207708a8c338274f5aeddc2a8a69 to your computer and use it in GitHub Desktop.
Simple command line experiment with BIP32/BIP39
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/alecthomas/kingpin"
"github.com/tyler-smith/go-bip32"
"github.com/tyler-smith/go-bip39"
"golang.org/x/crypto/ripemd160"
"hash"
)
var (
bitLengthFlag = kingpin.Flag("bitlen", "Number of bits in entropy. Determines the number of words").Default("128").Int()
mnemonicCommand = kingpin.Command("words", "Generate a list of mnemonic words")
keyCommand = kingpin.Command("key", "Generate a master key")
keySecret = keyCommand.Flag("secret", "Salts the master key").Default("Secret").String()
accountNumber = keyCommand.Flag("account", "Account number").Default("0").Int()
addressIndex = keyCommand.Flag("index", "Address index").Default("0").Int()
// keyLengthFlag = keyCommand.Flag("bitlen", "Number of bits in entropy. Determines the number of words").Default("128").Int()
)
func main() {
switch kingpin.Parse() {
case "words":
// Generate a mnemonic for memorization or user-friendly seeds
entropy, err := bip39.NewEntropy(*bitLengthFlag)
if err != nil {
fmt.Println("Entropy error: ", err.Error())
return
}
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
fmt.Println("Mnemonic error: ", err.Error())
return
}
fmt.Println("Mnemonic: ", mnemonic)
case "key":
// Generate a mnemonic for memorization or user-friendly seeds
entropy, err := bip39.NewEntropy(*bitLengthFlag)
if err != nil {
fmt.Println("Entropy error: ", err.Error())
return
}
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
fmt.Println("Mnemonic error: ", err.Error())
return
}
fmt.Println("Mnemonic: ", mnemonic)
// Generate a Bip32 HD wallet for the mnemonic and a user supplied password
seed := bip39.NewSeed(mnemonic, "Secret Passphrase")
// Master key
masterKey, err := bip32.NewMasterKey(seed)
if err != nil {
fmt.Println("Key Generation error: ", err.Error())
return
}
publicKey := masterKey.PublicKey()
fmt.Println("\nMaster Address: ", hex.EncodeToString(Hash160(masterKey.PublicKey().Key)))
fmt.Println("Master private key: ", masterKey)
fmt.Println("Master public key: ", publicKey)
// BIP44 purpose
purpose, err := masterKey.NewChildKey(bip32.FirstHardenedChild + 44)
if err != nil {
fmt.Println("Purpose Generation error: ", err.Error())
return
}
accountKey, err := purpose.NewChildKey(bip32.FirstHardenedChild + uint32(*accountNumber))
if err != nil {
fmt.Println("Account Generation error: ", err.Error())
return
}
fmt.Println("\nAccount Address: ", hex.EncodeToString(Hash160(accountKey.PublicKey().Key)))
fmt.Println("Account private key: ", accountKey)
fmt.Println("Account public key: ", accountKey.PublicKey())
changeKey, err := accountKey.NewChildKey(bip32.FirstHardenedChild)
if err != nil {
fmt.Println("Change generation error: ", err.Error())
return
}
addressKey, err := changeKey.NewChildKey(bip32.FirstHardenedChild + uint32(*addressIndex))
if err != nil {
fmt.Println("Address generation error: ", err.Error())
return
}
fmt.Println("\nIndex Address: ", hex.EncodeToString(Hash160(addressKey.PublicKey().Key)))
fmt.Println("Index private key: ", addressKey)
fmt.Println("Index public key: ", addressKey.PublicKey())
}
}
// Calculate the hash of hasher over buf.
func calcHash(buf []byte, hasher hash.Hash) []byte {
hasher.Write(buf)
return hasher.Sum(nil)
}
// Hash160 calculates the hash ripemd160(sha256(b)).
func Hash160(buf []byte) []byte {
return calcHash(calcHash(buf, sha256.New()), ripemd160.New())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment