1 package hdkeychain_test
2 3 import (
4 "fmt"
5 6 "github.com/p9c/p9/pkg/chaincfg"
7 "github.com/p9c/p9/pkg/util/hdkeychain"
8 )
9 10 // This example demonstrates how to generate a cryptographically random seed then use it to create a new master node
11 // (extended key).
12 func ExampleNewMaster() {
13 // Generate a random seed at the recommended length.
14 seed, e := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen)
15 if e != nil {
16 return
17 }
18 // Generate a new master node using the seed.
19 key, e := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
20 if e != nil {
21 return
22 }
23 // Show that the generated master node extended key is private.
24 fmt.Println("Private Extended Key?:", key.IsPrivate())
25 // Output:
26 // Private Extended Key?: true
27 }
28 29 // This example demonstrates the default hierarchical deterministic wallet layout as described in BIP0032.
30 func Example_defaultWalletLayout() {
31 // The default wallet layout described in BIP0032 is:
32 //
33 // Each account is composed of two keypair chains: an internal and an external one. The external keychain is used to
34 // generate new public addresses, while the internal keychain is used for all other operations (change addresses,
35 // generation addresses, ..., anything that doesn't need to be communicated).
36 //
37 // * m/iH/0/k
38 //
39 // corresponds to the k'th keypair of the external chain of account number i of the HDW derived from master m.
40 //
41 // * m/iH/1/k
42 //
43 // corresponds to the k'th keypair of the internal chain of account number i of the HDW derived from master m.
44 //
45 // Ordinarily this would either be read from some encrypted source and be decrypted or generated as the NewMaster
46 // example shows, but for the purposes of this example, the private extended key for the master node is being hard
47 // coded here.
48 master := "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
49 // Start by getting an extended key instance for the master node. This gives the path: m
50 masterKey, e := hdkeychain.NewKeyFromString(master)
51 if e != nil {
52 return
53 }
54 // Derive the extended key for account 0. This gives the path: m/0H
55 acct0, e := masterKey.Child(hdkeychain.HardenedKeyStart + 0)
56 if e != nil {
57 return
58 }
59 // Derive the extended key for the account 0 external chain. This gives the path: m/0H/0
60 acct0Ext, e := acct0.Child(0)
61 if e != nil {
62 return
63 }
64 // Derive the extended key for the account 0 internal chain. This gives the path: m/0H/1
65 acct0Int, e := acct0.Child(1)
66 if e != nil {
67 return
68 }
69 // At this point, acct0Ext and acct0Int are ready to derive the keys for the external and internal wallet chains.
70 // Derive the 10th extended key for the account 0 external chain. This gives the path: m/0H/0/10
71 acct0Ext10, e := acct0Ext.Child(10)
72 if e != nil {
73 return
74 }
75 // Derive the 1st extended key for the account 0 internal chain. This gives the path: m/0H/1/0
76 acct0Int0, e := acct0Int.Child(0)
77 if e != nil {
78 return
79 }
80 // Get and show the address associated with the extended keys for the main bitcoin network.
81 acct0ExtAddr, e := acct0Ext10.Address(&chaincfg.MainNetParams)
82 if e != nil {
83 return
84 }
85 acct0IntAddr, e := acct0Int0.Address(&chaincfg.MainNetParams)
86 if e != nil {
87 return
88 }
89 fmt.Println("Account 0 External Address 10:", acct0ExtAddr)
90 fmt.Println("Account 0 Internal Address 0:", acct0IntAddr)
91 // Output:
92 // Account 0 External Address 10: aV29NZpQZkh7ByDPhP4NR7nzx56crLAvTF
93 // Account 0 Internal Address 0: aUWmaTQVFwTV6wwQYvyyQRAvWeQmAorqAV
94 }
95 96 // This example demonstrates the audits use case in BIP0032.
97 func Example_audits() {
98 // The audits use case described in BIP0032 is://
99 //
100 // In case an auditor needs full access to the list of incoming and outgoing payments, one can share all account
101 // public extended keys. This will allow the auditor to see all transactions from and to the wallet, in all
102 // accounts, but not a single secret key.
103 //
104 // * N(m/*)
105 //
106 // corresponds to the neutered master extended key (also called the master public extended key) Ordinarily this
107 // would either be read from some encrypted source and be decrypted or generated as the NewMaster example shows, but
108 // for the purposes of this example, the private extended key for the master node is being hard coded here.
109 master := "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
110 // Start by getting an extended key instance for the master node. This gives the path:
111 //
112 // m
113 masterKey, e := hdkeychain.NewKeyFromString(master)
114 if e != nil {
115 return
116 }
117 // Neuter the master key to generate a master public extended key. This gives the path: N(m/*)
118 masterPubKey, e := masterKey.Neuter()
119 if e != nil {
120 return
121 }
122 // Share the master public extended key with the auditor.
123 fmt.Println("Audit key N(m/*):", masterPubKey)
124 // Output:
125 // Audit key N(m/*): xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8
126 }
127