2014-07-19 09:13:00 +02:00
|
|
|
// 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"
|
|
|
|
|
2015-01-15 22:13:38 +01:00
|
|
|
"github.com/btcsuite/btcutil/hdkeychain"
|
2014-07-19 09:13:00 +02:00
|
|
|
"github.com/conformal/btcnet"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|