lbcutil/hdkeychain/example_test.go
Dave Collins e6c5ca2a6a Implement hdkeychain BIP0032 API.
This commit adds a new sub-package named hdkeychain which can be used to
derive hierarchical deterministic key chains which form the foundation of
hd wallets.

- Support for private and public extended keys
- Convenient cryptographically secure seed generation
- Simple creation of master nodes
- Support for multi-layer derivation
- Easy serialization and deserialization for both private and public
  extended keys
- Support for custom networks by registering them with btcnet
- Obtaining the underlying EC pubkeys, EC privkeys, and associated bitcoin addresses
  ties in seamlessly with existing btcec and btcutil types which provide
  powerful tools for working with them to do things like sign transactions
  and generate payment scripts
- Makes use of the btcec package which is highly optimized for secp256k1
- Code examples including:
  - Generating a cryptographically secure random seed and deriving a
    master node from it
  - Default HD wallet layout as described by BIP0032
  - Audits use case as described by BIP0032
- Comprehensive test coverage including the BIP0032 test vectors
- Benchmarks
2014-07-22 17:11:46 -05:00

182 lines
5.4 KiB
Go

// Copyright (c) 2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package hdkeychain_test
import (
"fmt"
"github.com/conformal/btcnet"
"github.com/conformal/btcutil/hdkeychain"
)
// This example demonstrates how to generate a cryptographically random seed
// then use it to create a new master node (extended key).
func ExampleNewMaster() {
// Generate a random seed at the recommended length.
seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen)
if err != nil {
fmt.Println(err)
return
}
// Generate a new master node using the seed.
key, err := hdkeychain.NewMaster(seed)
if err != nil {
fmt.Println(err)
return
}
// Show that the generated master node extended key is private.
fmt.Println("Private Extended Key?:", key.IsPrivate())
// Output:
// Private Extended Key?: true
}
// This example demonstrates the default hierarchical deterministic wallet
// layout as described in BIP0032.
func Example_defaultWalletLayout() {
// The default wallet layout described in BIP0032 is:
//
// Each account is composed of two keypair chains: an internal and an
// external one. The external keychain is used to generate new public
// addresses, while the internal keychain is used for all other
// operations (change addresses, generation addresses, ..., anything
// that doesn't need to be communicated).
//
// * m/iH/0/k
// corresponds to the k'th keypair of the external chain of account
// number i of the HDW derived from master m.
// * m/iH/1/k
// corresponds to the k'th keypair of the internal chain of account
// number i of the HDW derived from master m.
// Ordinarily this would either be read from some encrypted source
// and be decrypted or generated as the NewMaster example shows, but
// for the purposes of this example, the private exteded key for the
// master node is being hard coded here.
master := "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jP" +
"PqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
// Start by getting an extended key instance for the master node.
// This gives the path:
// m
masterKey, err := hdkeychain.NewKeyFromString(master)
if err != nil {
fmt.Println(err)
return
}
// Derive the extended key for account 0. This gives the path:
// m/0H
acct0, err := masterKey.Child(hdkeychain.HardenedKeyStart + 0)
if err != nil {
fmt.Println(err)
return
}
// Derive the extended key for the account 0 external chain. This
// gives the path:
// m/0H/0
acct0Ext, err := acct0.Child(0)
if err != nil {
fmt.Println(err)
return
}
// Derive the extended key for the account 0 internal chain. This gives
// the path:
// m/0H/1
acct0Int, err := acct0.Child(1)
if err != nil {
fmt.Println(err)
return
}
// At this point, acct0Ext and acct0Int are ready to derive the keys for
// the external and internal wallet chains.
// Derive the 10th extended key for the account 0 external chain. This
// gives the path:
// m/0H/0/10
acct0Ext10, err := acct0Ext.Child(10)
if err != nil {
fmt.Println(err)
return
}
// Derive the 1st extended key for the account 0 internal chain. This
// gives the path:
// m/0H/1/0
acct0Int0, err := acct0Int.Child(0)
if err != nil {
fmt.Println(err)
return
}
// Get and show the address associated with the extended keys for the
// main bitcoin network.
acct0ExtAddr, err := acct0Ext10.Address(&btcnet.MainNetParams)
if err != nil {
fmt.Println(err)
return
}
acct0IntAddr, err := acct0Int0.Address(&btcnet.MainNetParams)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Account 0 External Address 10:", acct0ExtAddr)
fmt.Println("Account 0 Internal Address 0:", acct0IntAddr)
// Output:
// Account 0 External Address 10: 1HVccubUT8iKTapMJ5AnNA4sLRN27xzQ4F
// Account 0 Internal Address 0: 1J5rebbkQaunJTUoNVREDbeB49DqMNFFXk
}
// This example demonstrates the audits use case in BIP0032.
func Example_audits() {
// The audits use case described in BIP0032 is:
//
// In case an auditor needs full access to the list of incoming and
// outgoing payments, one can share all account public extended keys.
// This will allow the auditor to see all transactions from and to the
// wallet, in all accounts, but not a single secret key.
//
// * N(m/*)
// corresponds to the neutered master extended key (also called
// the master public extended key)
// Ordinarily this would either be read from some encrypted source
// and be decrypted or generated as the NewMaster example shows, but
// for the purposes of this example, the private exteded key for the
// master node is being hard coded here.
master := "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jP" +
"PqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
// Start by getting an extended key instance for the master node.
// This gives the path:
// m
masterKey, err := hdkeychain.NewKeyFromString(master)
if err != nil {
fmt.Println(err)
return
}
// Neuter the master key to generate a master public extended key. This
// gives the path:
// N(m/*)
masterPubKey, err := masterKey.Neuter()
if err != nil {
fmt.Println(err)
return
}
// Share the master public extended key with the auditor.
fmt.Println("Audit key N(m/*):", masterPubKey)
// Output:
// Audit key N(m/*): xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8
}