extendedkey_test.go raw

   1  package hdkeychain
   2  
   3  // References:
   4  //   [BIP32]: BIP0032 - Hierarchical Deterministic Wallets https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
   5  import (
   6  	"bytes"
   7  	"errors"
   8  	"math"
   9  	"reflect"
  10  	"testing"
  11  	
  12  	"github.com/p9c/p9/pkg/chaincfg"
  13  )
  14  
  15  // // TestBIP0032Vectors tests the vectors provided by [BIP32] to ensure the derivation works as intended.
  16  // func TestBIP0032Vectors(// 	t *testing.T) {
  17  // 	// The master seeds for each of the two test vectors in [BIP32].
  18  // 	testVec1MasterHex := "000102030405060708090a0b0c0d0e0f"
  19  // 	testVec2MasterHex := "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"
  20  // 	testVec3MasterHex := "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"
  21  // 	hkStart := uint32(0x80000000)
  22  // 	tests := []struct {
  23  // 		name     string
  24  // 		master   string
  25  // 		path     []uint32
  26  // 		wantPub  string
  27  // 		wantPriv string
  28  // 		net      *chaincfg.Params
  29  // 	}{
  30  // 		// Test vector 1
  31  // 		{
  32  // 			name:     "test vector 1 chain m",
  33  // 			master:   testVec1MasterHex,
  34  // 			path:     []uint32{},
  35  // 			wantPub:  "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
  36  // 			wantPriv: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
  37  // 			net:      &chaincfg.MainNetParams,
  38  // 		},
  39  // 		{
  40  // 			name:     "test vector 1 chain m/0H",
  41  // 			master:   testVec1MasterHex,
  42  // 			path:     []uint32{hkStart},
  43  // 			wantPub:  "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
  44  // 			wantPriv: "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
  45  // 			net:      &chaincfg.MainNetParams,
  46  // 		},
  47  // 		{
  48  // 			name:     "test vector 1 chain m/0H/1",
  49  // 			master:   testVec1MasterHex,
  50  // 			path:     []uint32{hkStart, 1},
  51  // 			wantPub:  "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
  52  // 			wantPriv: "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
  53  // 			net:      &chaincfg.MainNetParams,
  54  // 		},
  55  // 		{
  56  // 			name:     "test vector 1 chain m/0H/1/2H",
  57  // 			master:   testVec1MasterHex,
  58  // 			path:     []uint32{hkStart, 1, hkStart + 2},
  59  // 			wantPub:  "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
  60  // 			wantPriv: "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
  61  // 			net:      &chaincfg.MainNetParams,
  62  // 		},
  63  // 		{
  64  // 			name:     "test vector 1 chain m/0H/1/2H/2",
  65  // 			master:   testVec1MasterHex,
  66  // 			path:     []uint32{hkStart, 1, hkStart + 2, 2},
  67  // 			wantPub:  "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
  68  // 			wantPriv: "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
  69  // 			net:      &chaincfg.MainNetParams,
  70  // 		},
  71  // 		{
  72  // 			name:     "test vector 1 chain m/0H/1/2H/2/1000000000",
  73  // 			master:   testVec1MasterHex,
  74  // 			path:     []uint32{hkStart, 1, hkStart + 2, 2, 1000000000},
  75  // 			wantPub:  "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
  76  // 			wantPriv: "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
  77  // 			net:      &chaincfg.MainNetParams,
  78  // 		},
  79  // 		// Test vector 2
  80  // 		{
  81  // 			name:     "test vector 2 chain m",
  82  // 			master:   testVec2MasterHex,
  83  // 			path:     []uint32{},
  84  // 			wantPub:  "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
  85  // 			wantPriv: "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
  86  // 			net:      &chaincfg.MainNetParams,
  87  // 		},
  88  // 		{
  89  // 			name:     "test vector 2 chain m/0",
  90  // 			master:   testVec2MasterHex,
  91  // 			path:     []uint32{0},
  92  // 			wantPub:  "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
  93  // 			wantPriv: "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
  94  // 			net:      &chaincfg.MainNetParams,
  95  // 		},
  96  // 		{
  97  // 			name:     "test vector 2 chain m/0/2147483647H",
  98  // 			master:   testVec2MasterHex,
  99  // 			path:     []uint32{0, hkStart + 2147483647},
 100  // 			wantPub:  "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
 101  // 			wantPriv: "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
 102  // 			net:      &chaincfg.MainNetParams,
 103  // 		},
 104  // 		{
 105  // 			name:     "test vector 2 chain m/0/2147483647H/1",
 106  // 			master:   testVec2MasterHex,
 107  // 			path:     []uint32{0, hkStart + 2147483647, 1},
 108  // 			wantPub:  "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
 109  // 			wantPriv: "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
 110  // 			net:      &chaincfg.MainNetParams,
 111  // 		},
 112  // 		{
 113  // 			name:     "test vector 2 chain m/0/2147483647H/1/2147483646H",
 114  // 			master:   testVec2MasterHex,
 115  // 			path:     []uint32{0, hkStart + 2147483647, 1, hkStart + 2147483646},
 116  // 			wantPub:  "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
 117  // 			wantPriv: "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
 118  // 			net:      &chaincfg.MainNetParams,
 119  // 		},
 120  // 		{
 121  // 			name:     "test vector 2 chain m/0/2147483647H/1/2147483646H/2",
 122  // 			master:   testVec2MasterHex,
 123  // 			path:     []uint32{0, hkStart + 2147483647, 1, hkStart + 2147483646, 2},
 124  // 			wantPub:  "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
 125  // 			wantPriv: "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
 126  // 			net:      &chaincfg.MainNetParams,
 127  // 		},
 128  // 		// Test vector 3
 129  // 		{
 130  // 			name:     "test vector 3 chain m",
 131  // 			master:   testVec3MasterHex,
 132  // 			path:     []uint32{},
 133  // 			wantPub:  "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13",
 134  // 			wantPriv: "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
 135  // 			net:      &chaincfg.MainNetParams,
 136  // 		},
 137  // 		{
 138  // 			name:     "test vector 3 chain m/0H",
 139  // 			master:   testVec3MasterHex,
 140  // 			path:     []uint32{hkStart},
 141  // 			wantPub:  "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y",
 142  // 			wantPriv: "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
 143  // 			net:      &chaincfg.MainNetParams,
 144  // 		},
 145  // 		// Test vector 1 - Testnet
 146  // 		{
 147  // 			name:     "test vector 1 chain m - testnet",
 148  // 			master:   testVec1MasterHex,
 149  // 			path:     []uint32{},
 150  // 			wantPub:  "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp",
 151  // 			wantPriv: "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m",
 152  // 			net:      &chaincfg.TestNet3Params,
 153  // 		},
 154  // 		{
 155  // 			name:     "test vector 1 chain m/0H - testnet",
 156  // 			master:   testVec1MasterHex,
 157  // 			path:     []uint32{hkStart},
 158  // 			wantPub:  "tpubD8eQVK4Kdxg3gHrF62jGP7dKVCoYiEB8dFSpuTawkL5YxTus5j5pf83vaKnii4bc6v2NVEy81P2gYrJczYne3QNNwMTS53p5uzDyHvnw2jm",
 159  // 			wantPriv: "tprv8bxNLu25VazNnppTCP4fyhyCvBHcYtzE3wr3cwYeL4HA7yf6TLGEUdS4QC1vLT63TkjRssqJe4CvGNEC8DzW5AoPUw56D1Ayg6HY4oy8QZ9",
 160  // 			net:      &chaincfg.TestNet3Params,
 161  // 		},
 162  // 		{
 163  // 			name:     "test vector 1 chain m/0H/1 - testnet",
 164  // 			master:   testVec1MasterHex,
 165  // 			path:     []uint32{hkStart, 1},
 166  // 			wantPub:  "tpubDApXh6cD2fZ7WjtgpHd8yrWyYaneiFuRZa7fVjMkgxsmC1QzoXW8cgx9zQFJ81Jx4deRGfRE7yXA9A3STsxXj4CKEZJHYgpMYikkas9DBTP",
 167  // 			wantPriv: "tprv8e8VYgZxtHsSdGrtvdxYaSrryZGiYviWzGWtDDKTGh5NMXAEB8gYSCLHpFCywNs5uqV7ghRjimALQJkRFZnUrLHpzi2pGkwqLtbubgWuQ8q",
 168  // 			net:      &chaincfg.TestNet3Params,
 169  // 		},
 170  // 		{
 171  // 			name:     "test vector 1 chain m/0H/1/2H - testnet",
 172  // 			master:   testVec1MasterHex,
 173  // 			path:     []uint32{hkStart, 1, hkStart + 2},
 174  // 			wantPub:  "tpubDDRojdS4jYQXNugn4t2WLrZ7mjfAyoVQu7MLk4eurqFCbrc7cHLZX8W5YRS8ZskGR9k9t3PqVv68bVBjAyW4nWM9pTGRddt3GQftg6MVQsm",
 175  // 			wantPriv: "tprv8gjmbDPpbAirVSezBEMuwSu1Ci9EpUJWKokZTYccSZSomNMLytWyLdtDNHRbucNaRJWWHANf9AzEdWVAqahfyRjVMKbNRhBmxAM8EJr7R15",
 176  // 			net:      &chaincfg.TestNet3Params,
 177  // 		},
 178  // 		{
 179  // 			name:     "test vector 1 chain m/0H/1/2H/2 - testnet",
 180  // 			master:   testVec1MasterHex,
 181  // 			path:     []uint32{hkStart, 1, hkStart + 2, 2},
 182  // 			wantPub:  "tpubDFfCa4Z1v25WTPAVm9EbEMiRrYwucPocLbEe12BPBGooxxEUg42vihy1DkRWyftztTsL23snYezF9uXjGGwGW6pQjEpcTpmsH6ajpf4CVPn",
 183  // 			wantPriv: "tprv8iyAReWmmePqZv8hsVZzpx4KHXRyT4chmHdriW95m11R8Tyi3fDLYDM93bq4NGn1V6eCu5cE3zSQ6hPd31F2ApKXkZgTyn1V78pHjkq1V2v",
 184  // 			net:      &chaincfg.TestNet3Params,
 185  // 		},
 186  // 		{
 187  // 			name:     "test vector 1 chain m/0H/1/2H/2/1000000000 - testnet",
 188  // 			master:   testVec1MasterHex,
 189  // 			path:     []uint32{hkStart, 1, hkStart + 2, 2, 1000000000},
 190  // 			wantPub:  "tpubDHNy3kAG39ThyiwwsgoKY4iRenXDRtce8qdCFJZXPMCJg5dsCUHayp84raLTpvyiNA9sXPob5rgqkKvkN8S7MMyXbnEhGJMW64Cf4vFAoaF",
 191  // 			wantPriv: "tprv8kgvuL81tmn36Fv9z38j8f4K5m1HGZRjZY2QxnXDy5PuqbP6a5TzoKWCgTcGHBu66W3TgSbAu2yX6sPza5FkHmy564Sh6gmCPUNeUt4yj2x",
 192  // 			net:      &chaincfg.TestNet3Params,
 193  // 		},
 194  // 	}
 195  // tests:
 196  // 	for i, test := range tests {
 197  // 		masterSeed, e := hex.DecodeString(test.master)
 198  // 		if e != nil  {
 199  // 			t.Errorf("DecodeString #%d (%s): unexpected error: %v",
 200  // 				i, test.name, e)
 201  // 			continue
 202  // 		}
 203  // 		extKey, e := NewMaster(masterSeed, test.net)
 204  // 		if e != nil  {
 205  // 			t.Errorf("NewMaster #%d (%s): unexpected error when "+
 206  // 				"creating new master key: %v", i, test.name,
 207  // 				e)
 208  // 			continue
 209  // 		}
 210  // 		for _, childNum := range test.path {
 211  // 			var e error
 212  // 			extKey, e = extKey.Child(childNum)
 213  // 			if e != nil  {
 214  // 				t.Errorf("e: %v", e)
 215  // 				continue tests
 216  // 			}
 217  // 		}
 218  // 		if extKey.Depth() != uint8(len(test.path)) {
 219  // 			t.Errorf("Depth of key %d should match fixture path: %v",
 220  // 				extKey.Depth(), len(test.path))
 221  // 			continue
 222  // 		}
 223  // 		privStr := extKey.String()
 224  // 		if privStr != test.wantPriv {
 225  // 			t.Errorf("Serialize #%d (%s): mismatched serialized "+
 226  // 				"private extended key -- got: %s, want: %s", i,
 227  // 				test.name, privStr, test.wantPriv)
 228  // 			continue
 229  // 		}
 230  // 		pubKey, e := extKey.Neuter()
 231  // 		if e != nil  {
 232  // 			t.Errorf("Neuter #%d (%s): unexpected error: %v ", i,
 233  // 				test.name, e)
 234  // 			continue
 235  // 		}
 236  // 		// Neutering a second time should have no effect.
 237  // 		pubKey, e = pubKey.Neuter()
 238  // 		if e != nil  {
 239  // 			t.Errorf("Neuter #%d (%s): unexpected error: %v", i,
 240  // 				test.name, e)
 241  // 			return
 242  // 		}
 243  // 		pubStr := pubKey.String()
 244  // 		if pubStr != test.wantPub {
 245  // 			t.Errorf("Neuter #%d (%s): mismatched serialized "+
 246  // 				"public extended key -- got: %s, want: %s", i,
 247  // 				test.name, pubStr, test.wantPub)
 248  // 			continue
 249  // 		}
 250  // 	}
 251  // }
 252  
 253  // TestPrivateDerivation tests several vectors which derive private keys from other private keys works as intended.
 254  func TestPrivateDerivation(t *testing.T) {
 255  	// The private extended keys for test vectors in [BIP32].
 256  	testVec1MasterPrivKey := "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
 257  	testVec2MasterPrivKey := "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"
 258  	tests := []struct {
 259  		name     string
 260  		master   string
 261  		path     []uint32
 262  		wantPriv string
 263  	}{
 264  		// Test vector 1
 265  		{
 266  			name:     "test vector 1 chain m",
 267  			master:   testVec1MasterPrivKey,
 268  			path:     []uint32{},
 269  			wantPriv: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 270  		},
 271  		{
 272  			name:     "test vector 1 chain m/0",
 273  			master:   testVec1MasterPrivKey,
 274  			path:     []uint32{0},
 275  			wantPriv: "xprv9uHRZZhbkedL37eZEnyrNsQPFZYRAvjy5rt6M1nbEkLSo378x1CQQLo2xxBvREwiK6kqf7GRNvsNEchwibzXaV6i5GcsgyjBeRguXhKsi4R",
 276  		},
 277  		{
 278  			name:     "test vector 1 chain m/0/1",
 279  			master:   testVec1MasterPrivKey,
 280  			path:     []uint32{0, 1},
 281  			wantPriv: "xprv9ww7sMFLzJMzy7bV1qs7nGBxgKYrgcm3HcJvGb4yvNhT9vxXC7eX7WVULzCfxucFEn2TsVvJw25hH9d4mchywguGQCZvRgsiRaTY1HCqN8G",
 282  		},
 283  		{
 284  			name:     "test vector 1 chain m/0/1/2",
 285  			master:   testVec1MasterPrivKey,
 286  			path:     []uint32{0, 1, 2},
 287  			wantPriv: "xprv9xrdP7iD2L1YZCgR9AecDgpDMZSTzP5KCfUykGXgjBxLgp1VFHsEeL3conzGAkbc1MigG1o8YqmfEA2jtkPdf4vwMaGJC2YSDbBTPAjfRUi",
 288  		},
 289  		{
 290  			name:     "test vector 1 chain m/0/1/2/2",
 291  			master:   testVec1MasterPrivKey,
 292  			path:     []uint32{0, 1, 2, 2},
 293  			wantPriv: "xprvA2J8Hq4eiP7xCEBP7gzRJGJnd9CHTkEU6eTNMrZ6YR7H5boik8daFtDZxmJDfdMSKHwroCfAfsBKWWidRfBQjpegy6kzXSkQGGoMdWKz5Xh",
 294  		},
 295  		{
 296  			name:     "test vector 1 chain m/0/1/2/2/1000000000",
 297  			master:   testVec1MasterPrivKey,
 298  			path:     []uint32{0, 1, 2, 2, 1000000000},
 299  			wantPriv: "xprvA3XhazxncJqJsQcG85Gg61qwPQKiobAnWjuPpjKhExprZjfse6nErRwTMwGe6uGWXPSykZSTiYb2TXAm7Qhwj8KgRd2XaD21Styu6h6AwFz",
 300  		},
 301  		// Test vector 2
 302  		{
 303  			name:     "test vector 2 chain m",
 304  			master:   testVec2MasterPrivKey,
 305  			path:     []uint32{},
 306  			wantPriv: "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
 307  		},
 308  		{
 309  			name:     "test vector 2 chain m/0",
 310  			master:   testVec2MasterPrivKey,
 311  			path:     []uint32{0},
 312  			wantPriv: "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
 313  		},
 314  		{
 315  			name:     "test vector 2 chain m/0/2147483647",
 316  			master:   testVec2MasterPrivKey,
 317  			path:     []uint32{0, 2147483647},
 318  			wantPriv: "xprv9wSp6B7cXJWXZRpDbxkFg3ry2fuSyUfvboJ5Yi6YNw7i1bXmq9QwQ7EwMpeG4cK2pnMqEx1cLYD7cSGSCtruGSXC6ZSVDHugMsZgbuY62m6",
 319  		},
 320  		{
 321  			name:     "test vector 2 chain m/0/2147483647/1",
 322  			master:   testVec2MasterPrivKey,
 323  			path:     []uint32{0, 2147483647, 1},
 324  			wantPriv: "xprv9ysS5br6UbWCRCJcggvpUNMyhVWgD7NypY9gsVTMYmuRtZg8izyYC5Ey4T931WgWbfJwRDwfVFqV3b29gqHDbuEpGcbzf16pdomk54NXkSm",
 325  		},
 326  		{
 327  			name:     "test vector 2 chain m/0/2147483647/1/2147483646",
 328  			master:   testVec2MasterPrivKey,
 329  			path:     []uint32{0, 2147483647, 1, 2147483646},
 330  			wantPriv: "xprvA2LfeWWwRCxh4iqigcDMnUf2E3nVUFkntc93nmUYBtb9rpSPYWa8MY3x9ZHSLZkg4G84UefrDruVK3FhMLSJsGtBx883iddHNuH1LNpRrEp",
 331  		},
 332  		{
 333  			name:     "test vector 2 chain m/0/2147483647/1/2147483646/2",
 334  			master:   testVec2MasterPrivKey,
 335  			path:     []uint32{0, 2147483647, 1, 2147483646, 2},
 336  			wantPriv: "xprvA48ALo8BDjcRET68R5RsPzF3H7WeyYYtHcyUeLRGBPHXu6CJSGjwW7dWoeUWTEzT7LG3qk6Eg6x2ZoqD8gtyEFZecpAyvchksfLyg3Zbqam",
 337  		},
 338  		// Custom tests to trigger specific conditions.
 339  		{
 340  			// Seed 000000000000000000000000000000da.
 341  			name:     "Derived privkey with zero high byte m/0",
 342  			master:   "xprv9s21ZrQH143K4FR6rNeqEK4EBhRgLjWLWhA3pw8iqgAKk82ypz58PXbrzU19opYcxw8JDJQF4id55PwTsN1Zv8Xt6SKvbr2KNU5y8jN8djz",
 343  			path:     []uint32{0},
 344  			wantPriv: "xprv9uC5JqtViMmgcAMUxcsBCBFA7oYCNs4bozPbyvLfddjHou4rMiGEHipz94xNaPb1e4f18TRoPXfiXx4C3cDAcADqxCSRSSWLvMBRWPctSN9",
 345  		},
 346  	}
 347  tests:
 348  	for i, test := range tests {
 349  		extKey, e := NewKeyFromString(test.master)
 350  		if e != nil {
 351  			t.Errorf(
 352  				"NewKeyFromString #%d (%s): unexpected error "+
 353  					"creating extended key: %v", i, test.name,
 354  				e,
 355  			)
 356  			continue
 357  		}
 358  		for _, childNum := range test.path {
 359  			var e error
 360  			extKey, e = extKey.Child(childNum)
 361  			if e != nil {
 362  				t.Errorf("e: %v", e)
 363  				continue tests
 364  			}
 365  		}
 366  		privStr := extKey.String()
 367  		if privStr != test.wantPriv {
 368  			t.Errorf(
 369  				"Child #%d (%s): mismatched serialized "+
 370  					"private extended key -- got: %s, want: %s", i,
 371  				test.name, privStr, test.wantPriv,
 372  			)
 373  			continue
 374  		}
 375  	}
 376  }
 377  
 378  // TestPublicDerivation tests several vectors which derive public keys from other public keys works as intended.
 379  func TestPublicDerivation(t *testing.T) {
 380  	// The public extended keys for test vectors in [BIP32].
 381  	testVec1MasterPubKey := "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
 382  	testVec2MasterPubKey := "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"
 383  	tests := []struct {
 384  		name    string
 385  		master  string
 386  		path    []uint32
 387  		wantPub string
 388  	}{
 389  		// Test vector 1
 390  		{
 391  			name:    "test vector 1 chain m",
 392  			master:  testVec1MasterPubKey,
 393  			path:    []uint32{},
 394  			wantPub: "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 395  		},
 396  		{
 397  			name:    "test vector 1 chain m/0",
 398  			master:  testVec1MasterPubKey,
 399  			path:    []uint32{0},
 400  			wantPub: "xpub68Gmy5EVb2BdFbj2LpWrk1M7obNuaPTpT5oh9QCCo5sRfqSHVYWex97WpDZzszdzHzxXDAzPLVSwybe4uPYkSk4G3gnrPqqkV9RyNzAcNJ1",
 401  		},
 402  		{
 403  			name:    "test vector 1 chain m/0/1",
 404  			master:  testVec1MasterPubKey,
 405  			path:    []uint32{0, 1},
 406  			wantPub: "xpub6AvUGrnEpfvJBbfx7sQ89Q8hEMPM65UteqEX4yUbUiES2jHfjexmfJoxCGSwFMZiPBaKQT1RiKWrKfuDV4vpgVs4Xn8PpPTR2i79rwHd4Zr",
 407  		},
 408  		{
 409  			name:    "test vector 1 chain m/0/1/2",
 410  			master:  testVec1MasterPubKey,
 411  			path:    []uint32{0, 1, 2},
 412  			wantPub: "xpub6BqyndF6rhZqmgktFCBcapkwubGxPqoAZtQaYewJHXVKZcLdnqBVC8N6f6FSHWUghjuTLeubWyQWfJdk2G3tGgvgj3qngo4vLTnnSjAZckv",
 413  		},
 414  		{
 415  			name:    "test vector 1 chain m/0/1/2/2",
 416  			master:  testVec1MasterPubKey,
 417  			path:    []uint32{0, 1, 2, 2},
 418  			wantPub: "xpub6FHUhLbYYkgFQiFrDiXRfQFXBB2msCxKTsNyAExi6keFxQ8sHfwpogY3p3s1ePSpUqLNYks5T6a3JqpCGszt4kxbyq7tUoFP5c8KWyiDtPp",
 419  		},
 420  		{
 421  			name:    "test vector 1 chain m/0/1/2/2/1000000000",
 422  			master:  testVec1MasterPubKey,
 423  			path:    []uint32{0, 1, 2, 2, 1000000000},
 424  			wantPub: "xpub6GX3zWVgSgPc5tgjE6ogT9nfwSADD3tdsxpzd7jJoJMqSY12Be6VQEFwDCp6wAQoZsH2iq5nNocHEaVDxBcobPrkZCjYW3QUmoDYzMFBDu9",
 425  		},
 426  		// Test vector 2
 427  		{
 428  			name:    "test vector 2 chain m",
 429  			master:  testVec2MasterPubKey,
 430  			path:    []uint32{},
 431  			wantPub: "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
 432  		},
 433  		{
 434  			name:    "test vector 2 chain m/0",
 435  			master:  testVec2MasterPubKey,
 436  			path:    []uint32{0},
 437  			wantPub: "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
 438  		},
 439  		{
 440  			name:    "test vector 2 chain m/0/2147483647",
 441  			master:  testVec2MasterPubKey,
 442  			path:    []uint32{0, 2147483647},
 443  			wantPub: "xpub6ASAVgeWMg4pmutghzHG3BohahjwNwPmy2DgM6W9wGegtPrvNgjBwuZRD7hSDFhYfunq8vDgwG4ah1gVzZysgp3UsKz7VNjCnSUJJ5T4fdD",
 444  		},
 445  		{
 446  			name:    "test vector 2 chain m/0/2147483647/1",
 447  			master:  testVec2MasterPubKey,
 448  			path:    []uint32{0, 2147483647, 1},
 449  			wantPub: "xpub6CrnV7NzJy4VdgP5niTpqWJiFXMAca6qBm5Hfsry77SQmN1HGYHnjsZSujoHzdxf7ZNK5UVrmDXFPiEW2ecwHGWMFGUxPC9ARipss9rXd4b",
 450  		},
 451  		{
 452  			name:    "test vector 2 chain m/0/2147483647/1/2147483646",
 453  			master:  testVec2MasterPubKey,
 454  			path:    []uint32{0, 2147483647, 1, 2147483646},
 455  			wantPub: "xpub6FL2423qFaWzHCvBndkN9cbkn5cysiUeFq4eb9t9kE88jcmY63tNuLNRzpHPdAM4dUpLhZ7aUm2cJ5zF7KYonf4jAPfRqTMTRBNkQL3Tfta",
 456  		},
 457  		{
 458  			name:    "test vector 2 chain m/0/2147483647/1/2147483646/2",
 459  			master:  testVec2MasterPubKey,
 460  			path:    []uint32{0, 2147483647, 1, 2147483646, 2},
 461  			wantPub: "xpub6H7WkJf547AiSwAbX6xsm8Bmq9M9P1Gjequ5SipsjipWmtXSyp4C3uwzewedGEgAMsDy4jEvNTWtxLyqqHY9C12gaBmgUdk2CGmwachwnWK",
 462  		},
 463  	}
 464  tests:
 465  	for i, test := range tests {
 466  		extKey, e := NewKeyFromString(test.master)
 467  		if e != nil {
 468  			t.Errorf(
 469  				"NewKeyFromString #%d (%s): unexpected error "+
 470  					"creating extended key: %v", i, test.name,
 471  				e,
 472  			)
 473  			continue
 474  		}
 475  		for _, childNum := range test.path {
 476  			var e error
 477  			extKey, e = extKey.Child(childNum)
 478  			if e != nil {
 479  				t.Errorf("e: %v", e)
 480  				continue tests
 481  			}
 482  		}
 483  		pubStr := extKey.String()
 484  		if pubStr != test.wantPub {
 485  			t.Errorf(
 486  				"Child #%d (%s): mismatched serialized "+
 487  					"public extended key -- got: %s, want: %s", i,
 488  				test.name, pubStr, test.wantPub,
 489  			)
 490  			continue
 491  		}
 492  	}
 493  }
 494  
 495  // TestGenenerateSeed ensures the GenerateSeed function works as intended.
 496  func TestGenenerateSeed(t *testing.T) {
 497  	wantErr := errors.New("seed length must be between 128 and 512 bits")
 498  	tests := []struct {
 499  		name   string
 500  		length uint8
 501  		e      error
 502  	}{
 503  		// Test various valid lengths.
 504  		{name: "16 bytes", length: 16},
 505  		{name: "17 bytes", length: 17},
 506  		{name: "20 bytes", length: 20},
 507  		{name: "32 bytes", length: 32},
 508  		{name: "64 bytes", length: 64},
 509  		// Test invalid lengths.
 510  		{name: "15 bytes", length: 15, e: wantErr},
 511  		{name: "65 bytes", length: 65, e: wantErr},
 512  	}
 513  	for i, test := range tests {
 514  		seed, e := GenerateSeed(test.length)
 515  		if !reflect.DeepEqual(e, test.e) {
 516  			t.Errorf(
 517  				"GenerateSeed #%d (%s): unexpected error -- "+
 518  					"want %v, got %v", i, test.name, test.e, e,
 519  			)
 520  			continue
 521  		}
 522  		if test.e == nil && len(seed) != int(test.length) {
 523  			t.Errorf(
 524  				"GenerateSeed #%d (%s): length mismatch -- "+
 525  					"got %d, want %d", i, test.name, len(seed),
 526  				test.length,
 527  			)
 528  			continue
 529  		}
 530  	}
 531  }
 532  
 533  // // TestExtendedKeyAPI ensures the API on the ExtendedKey type works as intended.
 534  // func TestExtendedKeyAPI(// 	t *testing.T) {
 535  // 	tests := []struct {
 536  // 		name       string
 537  // 		extKey     string
 538  // 		isPrivate  bool
 539  // 		parentFP   uint32
 540  // 		privKey    string
 541  // 		privKeyErr error
 542  // 		pubKey     string
 543  // 		address    string
 544  // 	}{
 545  // 		{
 546  // 			name:      "test vector 1 master node private",
 547  // 			extKey:    "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 548  // 			isPrivate: true,
 549  // 			parentFP:  0,
 550  // 			privKey:   "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35",
 551  // 			pubKey:    "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
 552  // 			address:   "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma",
 553  // 		},
 554  // 		{
 555  // 			name:       "test vector 1 chain m/0H/1/2H public",
 556  // 			extKey:     "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
 557  // 			isPrivate:  false,
 558  // 			parentFP:   3203769081,
 559  // 			privKeyErr: ErrNotPrivExtKey,
 560  // 			pubKey:     "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
 561  // 			address:    "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x",
 562  // 		},
 563  // 	}
 564  // 	for i, test := range tests {
 565  // 		key, e := NewKeyFromString(test.extKey)
 566  // 		if e != nil  {
 567  // 			t.Errorf("NewKeyFromString #%d (%s): unexpected "+
 568  // 				"error: %v", i, test.name, e)
 569  // 			continue
 570  // 		}
 571  // 		if key.IsPrivate() != test.isPrivate {
 572  // 			t.Errorf("IsPrivate #%d (%s): mismatched key type -- "+
 573  // 				"want private %v, got private %v", i, test.name,
 574  // 				test.isPrivate, key.IsPrivate())
 575  // 			continue
 576  // 		}
 577  // 		parentFP := key.ParentFingerprint()
 578  // 		if parentFP != test.parentFP {
 579  // 			t.Errorf("ParentFingerprint #%d (%s): mismatched "+
 580  // 				"parent fingerprint -- want %d, got %d", i,
 581  // 				test.name, test.parentFP, parentFP)
 582  // 			continue
 583  // 		}
 584  // 		serializedKey := key.String()
 585  // 		if serializedKey != test.extKey {
 586  // 			t.Errorf("String #%d (%s): mismatched serialized key "+
 587  // 				"-- want %s, got %s", i, test.name, test.extKey,
 588  // 				serializedKey)
 589  // 			continue
 590  // 		}
 591  // 		privKey, e := key.ECPrivKey()
 592  // 		if !reflect.DeepEqual(e, test.privKeyErr) {
 593  // 			t.Errorf("ECPrivKey #%d (%s): mismatched error: want "+
 594  // 				"%v, got %v", i, test.name, test.privKeyErr, e)
 595  // 			continue
 596  // 		}
 597  // 		if test.privKeyErr == nil {
 598  // 			privKeyStr := hex.EncodeToString(privKey.Serialize())
 599  // 			if privKeyStr != test.privKey {
 600  // 				t.Errorf("ECPrivKey #%d (%s): mismatched "+
 601  // 					"private key -- want %s, got %s", i,
 602  // 					test.name, test.privKey, privKeyStr)
 603  // 				continue
 604  // 			}
 605  // 		}
 606  // 		pubKey, e := key.ECPubKey()
 607  // 		if e != nil  {
 608  // 			t.Errorf("ECPubKey #%d (%s): unexpected error: %v", i,
 609  // 				test.name, e)
 610  // 			continue
 611  // 		}
 612  // 		pubKeyStr := hex.EncodeToString(pubKey.SerializeCompressed())
 613  // 		if pubKeyStr != test.pubKey {
 614  // 			t.Errorf("ECPubKey #%d (%s): mismatched public key -- "+
 615  // 				"want %s, got %s", i, test.name, test.pubKey,
 616  // 				pubKeyStr)
 617  // 			continue
 618  // 		}
 619  // 		addr, e := key.Address(&chaincfg.MainNetParams)
 620  // 		if e != nil  {
 621  // 			t.Errorf("Address #%d (%s): unexpected error: %v", i,
 622  // 				test.name, e)
 623  // 			continue
 624  // 		}
 625  // 		if addr.EncodeAddress() != test.address {
 626  // 			t.Errorf("Address #%d (%s): mismatched address -- want "+
 627  // 				"%s, got %s", i, test.name, test.address,
 628  // 				addr.EncodeAddress())
 629  // 			continue
 630  // 		}
 631  // 	}
 632  // }
 633  
 634  // TestNet ensures the network related APIs work as intended.
 635  func TestNet(t *testing.T) {
 636  	tests := []struct {
 637  		name      string
 638  		key       string
 639  		origNet   *chaincfg.Params
 640  		newNet    *chaincfg.Params
 641  		newPriv   string
 642  		newPub    string
 643  		isPrivate bool
 644  	}{
 645  		// Private extended keys.
 646  		{
 647  			name:      "mainnet -> simnet",
 648  			key:       "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 649  			origNet:   &chaincfg.MainNetParams,
 650  			newNet:    &chaincfg.SimNetParams,
 651  			newPriv:   "sprv8Erh3X3hFeKunvVdAGQQtambRPapECWiTDtvsTGdyrhzhbYgnSZajRRWbihzvq4AM4ivm6uso31VfKaukwJJUs3GYihXP8ebhMb3F2AHu3P",
 652  			newPub:    "spub4Tr3T2ab61tD1Qa6GHwRFiiKyRRJdfEZpSpXfqgFYCEyaPsqKysqHDjzSzMJSiUEGbcsG3w2SLMoTqn44B8x6u3MLRRkYfACTUBnHK79THk",
 653  			isPrivate: true,
 654  		},
 655  		{
 656  			name:      "simnet -> mainnet",
 657  			key:       "sprv8Erh3X3hFeKunvVdAGQQtambRPapECWiTDtvsTGdyrhzhbYgnSZajRRWbihzvq4AM4ivm6uso31VfKaukwJJUs3GYihXP8ebhMb3F2AHu3P",
 658  			origNet:   &chaincfg.SimNetParams,
 659  			newNet:    &chaincfg.MainNetParams,
 660  			newPriv:   "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 661  			newPub:    "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 662  			isPrivate: true,
 663  		},
 664  		{
 665  			name:      "mainnet -> regtest",
 666  			key:       "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 667  			origNet:   &chaincfg.MainNetParams,
 668  			newNet:    &chaincfg.RegressionTestParams,
 669  			newPriv:   "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m",
 670  			newPub:    "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp",
 671  			isPrivate: true,
 672  		},
 673  		{
 674  			name:      "regtest -> mainnet",
 675  			key:       "tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m",
 676  			origNet:   &chaincfg.RegressionTestParams,
 677  			newNet:    &chaincfg.MainNetParams,
 678  			newPriv:   "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 679  			newPub:    "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 680  			isPrivate: true,
 681  		},
 682  		// Public extended keys.
 683  		{
 684  			name:      "mainnet -> simnet",
 685  			key:       "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 686  			origNet:   &chaincfg.MainNetParams,
 687  			newNet:    &chaincfg.SimNetParams,
 688  			newPub:    "spub4Tr3T2ab61tD1Qa6GHwRFiiKyRRJdfEZpSpXfqgFYCEyaPsqKysqHDjzSzMJSiUEGbcsG3w2SLMoTqn44B8x6u3MLRRkYfACTUBnHK79THk",
 689  			isPrivate: false,
 690  		},
 691  		{
 692  			name:      "simnet -> mainnet",
 693  			key:       "spub4Tr3T2ab61tD1Qa6GHwRFiiKyRRJdfEZpSpXfqgFYCEyaPsqKysqHDjzSzMJSiUEGbcsG3w2SLMoTqn44B8x6u3MLRRkYfACTUBnHK79THk",
 694  			origNet:   &chaincfg.SimNetParams,
 695  			newNet:    &chaincfg.MainNetParams,
 696  			newPub:    "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 697  			isPrivate: false,
 698  		},
 699  		{
 700  			name:      "mainnet -> regtest",
 701  			key:       "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 702  			origNet:   &chaincfg.MainNetParams,
 703  			newNet:    &chaincfg.RegressionTestParams,
 704  			newPub:    "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp",
 705  			isPrivate: false,
 706  		},
 707  		{
 708  			name:      "regtest -> mainnet",
 709  			key:       "tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp",
 710  			origNet:   &chaincfg.RegressionTestParams,
 711  			newNet:    &chaincfg.MainNetParams,
 712  			newPub:    "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
 713  			isPrivate: false,
 714  		},
 715  	}
 716  	for i, test := range tests {
 717  		extKey, e := NewKeyFromString(test.key)
 718  		if e != nil {
 719  			t.Errorf(
 720  				"NewKeyFromString #%d (%s): unexpected error "+
 721  					"creating extended key: %v", i, test.name,
 722  				e,
 723  			)
 724  			continue
 725  		}
 726  		if !extKey.IsForNet(test.origNet) {
 727  			t.Errorf(
 728  				"IsForNet #%d (%s): key is not for expected "+
 729  					"network %v", i, test.name, test.origNet.Name,
 730  			)
 731  			continue
 732  		}
 733  		extKey.SetNet(test.newNet)
 734  		if !extKey.IsForNet(test.newNet) {
 735  			t.Errorf(
 736  				"SetNet/IsForNet #%d (%s): key is not for "+
 737  					"expected network %v", i, test.name,
 738  				test.newNet.Name,
 739  			)
 740  			continue
 741  		}
 742  		if test.isPrivate {
 743  			privStr := extKey.String()
 744  			if privStr != test.newPriv {
 745  				t.Errorf(
 746  					"Serialize #%d (%s): mismatched serialized "+
 747  						"private extended key -- got: %s, want: %s", i,
 748  					test.name, privStr, test.newPriv,
 749  				)
 750  				continue
 751  			}
 752  			extKey, e = extKey.Neuter()
 753  			if e != nil {
 754  				t.Errorf(
 755  					"Neuter #%d (%s): unexpected error: %v ", i,
 756  					test.name, e,
 757  				)
 758  				continue
 759  			}
 760  		}
 761  		pubStr := extKey.String()
 762  		if pubStr != test.newPub {
 763  			t.Errorf(
 764  				"Neuter #%d (%s): mismatched serialized "+
 765  					"public extended key -- got: %s, want: %s", i,
 766  				test.name, pubStr, test.newPub,
 767  			)
 768  			continue
 769  		}
 770  	}
 771  }
 772  
 773  // TestErrors performs some negative tests for various invalid cases to ensure the errors are handled properly.
 774  func TestErrors(t *testing.T) {
 775  	// Should get an error when seed has too few bytes.
 776  	net := &chaincfg.MainNetParams
 777  	_, e := NewMaster(bytes.Repeat([]byte{0x00}, 15), net)
 778  	if e != ErrInvalidSeedLen {
 779  		t.Fatalf(
 780  			"NewMaster: mismatched error -- got: %v, want: %v",
 781  			e, ErrInvalidSeedLen,
 782  		)
 783  	}
 784  	// Should get an error when seed has too many bytes.
 785  	_, e = NewMaster(bytes.Repeat([]byte{0x00}, 65), net)
 786  	if e != ErrInvalidSeedLen {
 787  		t.Fatalf(
 788  			"NewMaster: mismatched error -- got: %v, want: %v",
 789  			e, ErrInvalidSeedLen,
 790  		)
 791  	}
 792  	// Generate a new key and neuter it to a public extended key.
 793  	seed, e := GenerateSeed(RecommendedSeedLen)
 794  	if e != nil {
 795  		t.Fatalf("GenerateSeed: unexpected error: %v", e)
 796  	}
 797  	extKey, e := NewMaster(seed, net)
 798  	if e != nil {
 799  		t.Fatalf("NewMaster: unexpected error: %v", e)
 800  	}
 801  	pubKey, e := extKey.Neuter()
 802  	if e != nil {
 803  		t.Fatalf("Neuter: unexpected error: %v", e)
 804  	}
 805  	// Deriving a hardened child extended key should fail from a public key.
 806  	_, e = pubKey.Child(HardenedKeyStart)
 807  	if e != ErrDeriveHardFromPublic {
 808  		t.Fatalf(
 809  			"Child: mismatched error -- got: %v, want: %v",
 810  			e, ErrDeriveHardFromPublic,
 811  		)
 812  	}
 813  	// NewKeyFromString failure tests.
 814  	tests := []struct {
 815  		name      string
 816  		key       string
 817  		e         error
 818  		neuter    bool
 819  		neuterErr error
 820  	}{
 821  		{
 822  			name: "invalid key length",
 823  			key:  "xpub1234",
 824  			e:    ErrInvalidKeyLen,
 825  		},
 826  		{
 827  			name: "bad checksum",
 828  			key:  "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EBygr15",
 829  			e:    ErrBadChecksum,
 830  		},
 831  		{
 832  			name: "pubkey not on curve",
 833  			key:  "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ1hr9Rwbk95YadvBkQXxzHBSngB8ndpW6QH7zhhsXZ2jHyZqPjk",
 834  			e:    errors.New("invalid square root"),
 835  		},
 836  		{
 837  			name:      "unsupported version",
 838  			key:       "xbad4LfUL9eKmA66w2GJdVMqhvDmYGJpTGjWRAtjHqoUY17sGaymoMV9Cm3ocn9Ud6Hh2vLFVC7KSKCRVVrqc6dsEdsTjRV1WUmkK85YEUujAPX",
 839  			e:         nil,
 840  			neuter:    true,
 841  			neuterErr: chaincfg.ErrUnknownHDKeyID,
 842  		},
 843  	}
 844  	for i, test := range tests {
 845  		extKey, e := NewKeyFromString(test.key)
 846  		if !reflect.DeepEqual(e, test.e) {
 847  			t.Errorf(
 848  				"NewKeyFromString #%d (%s): mismatched error "+
 849  					"-- got: %v, want: %v", i, test.name, e,
 850  				test.e,
 851  			)
 852  			continue
 853  		}
 854  		if test.neuter {
 855  			_, e := extKey.Neuter()
 856  			if !reflect.DeepEqual(e, test.neuterErr) {
 857  				t.Errorf(
 858  					"Neuter #%d (%s): mismatched error "+
 859  						"-- got: %v, want: %v", i, test.name,
 860  					e, test.neuterErr,
 861  				)
 862  				continue
 863  			}
 864  		}
 865  	}
 866  }
 867  
 868  // // TestZero ensures that zeroing an extended key works as intended.
 869  // func TestZero(// 	t *testing.T) {
 870  // 	tests := []struct {
 871  // 		name   string
 872  // 		master string
 873  // 		extKey string
 874  // 		net    *chaincfg.Params
 875  // 	}{
 876  // 		// Test vector 1
 877  // 		{
 878  // 			name:   "test vector 1 chain m",
 879  // 			master: "000102030405060708090a0b0c0d0e0f",
 880  // 			extKey: "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
 881  // 			net:    &chaincfg.MainNetParams,
 882  // 		},
 883  // 		// Test vector 2
 884  // 		{
 885  // 			name:   "test vector 2 chain m",
 886  // 			master: "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542",
 887  // 			extKey: "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
 888  // 			net:    &chaincfg.MainNetParams,
 889  // 		},
 890  // 	}
 891  // 	// Use a closure to test that a key is zeroed since the tests create
 892  // 	// keys in different ways and need to test the same things multiple
 893  // 	// times.
 894  // 	testZeroed := func(i int, testName string, key *ExtendedKey) bool {
 895  // 		// Zeroing a key should result in it no longer being private
 896  // 		if key.IsPrivate() {
 897  // 			t.Errorf("IsPrivate #%d (%s): mismatched key type -- "+
 898  // 				"want private %v, got private %v", i, testName,
 899  // 				false, key.IsPrivate())
 900  // 			return false
 901  // 		}
 902  // 		parentFP := key.ParentFingerprint()
 903  // 		if parentFP != 0 {
 904  // 			t.Errorf("ParentFingerprint #%d (%s): mismatched "+
 905  // 				"parent fingerprint -- want %d, got %d", i,
 906  // 				testName, 0, parentFP)
 907  // 			return false
 908  // 		}
 909  // 		wantKey := "zeroed extended key"
 910  // 		serializedKey := key.String()
 911  // 		if serializedKey != wantKey {
 912  // 			t.Errorf("String #%d (%s): mismatched serialized key "+
 913  // 				"-- want %s, got %s", i, testName, wantKey,
 914  // 				serializedKey)
 915  // 			return false
 916  // 		}
 917  // 		wantErr := ErrNotPrivExtKey
 918  // 		_, e := key.ECPrivKey()
 919  // 		if !reflect.DeepEqual(e, wantErr) {
 920  // 			t.Errorf("ECPrivKey #%d (%s): mismatched error: want "+
 921  // 				"%v, got %v", i, testName, wantErr, e)
 922  // 			return false
 923  // 		}
 924  // 		wantErr = errors.New("pubkey string is empty")
 925  // 		_, e = key.ECPubKey()
 926  // 		if !reflect.DeepEqual(e, wantErr) {
 927  // 			t.Errorf("ECPubKey #%d (%s): mismatched error: want "+
 928  // 				"%v, got %v", i, testName, wantErr, e)
 929  // 			return false
 930  // 		}
 931  // 		wantAddr := "1HT7xU2Ngenf7D4yocz2SAcnNLW7rK8d4E"
 932  // 		addr, e := key.Address(&chaincfg.MainNetParams)
 933  // 		if e != nil  {
 934  // 			t.Errorf("Addres s #%d (%s): unexpected error: %v", i,
 935  // 				testName, e)
 936  // 			return false
 937  // 		}
 938  // 		if addr.EncodeAddress() != wantAddr {
 939  // 			t.Errorf("Address #%d (%s): mismatched address -- want "+
 940  // 				"%s, got %s", i, testName, wantAddr,
 941  // 				addr.EncodeAddress())
 942  // 			return false
 943  // 		}
 944  // 		return true
 945  // 	}
 946  // 	for i, test := range tests {
 947  // 		// Create new key from seed and get the neutered version.
 948  // 		masterSeed, e := hex.DecodeString(test.master)
 949  // 		if e != nil  {
 950  // 			t.Errorf("DecodeString #%d (%s): unexpected error: %v",
 951  // 				i, test.name, e)
 952  // 			continue
 953  // 		}
 954  // 		key, e := NewMaster(masterSeed, test.net)
 955  // 		if e != nil  {
 956  // 			t.Errorf("NewMaster #%d (%s): unexpected error when "+
 957  // 				"creating new master key: %v", i, test.name,
 958  // 				e)
 959  // 			continue
 960  // 		}
 961  // 		neuteredKey, e := key.Neuter()
 962  // 		if e != nil  {
 963  // 			t.Errorf("Neuter #%d (%s): unexpected error: %v", i,
 964  // 				test.name, e)
 965  // 			continue
 966  // 		}
 967  // 		// Ensure both non-neutered and neutered keys are zeroed properly.
 968  // 		key.Zero()
 969  // 		if !testZeroed(i, test.name+" from seed not neutered", key) {
 970  // 			continue
 971  // 		}
 972  // 		neuteredKey.Zero()
 973  // 		if !testZeroed(i, test.name+" from seed neutered", key) {
 974  // 			continue
 975  // 		}
 976  // 		// Deserialize key and get the neutered version.
 977  // 		key, e = NewKeyFromString(test.extKey)
 978  // 		if e != nil  {
 979  // 			t.Errorf("NewKeyFromString #%d (%s): unexpected "+
 980  // 				"error: %v", i, test.name, e)
 981  // 			continue
 982  // 		}
 983  // 		neuteredKey, e = key.Neuter()
 984  // 		if e != nil  {
 985  // 			t.Errorf("Neuter #%d (%s): unexpected error: %v", i,
 986  // 				test.name, e)
 987  // 			continue
 988  // 		}
 989  // 		// Ensure both non-neutered and neutered keys are zeroed properly.
 990  // 		key.Zero()
 991  // 		if !testZeroed(i, test.name+" deserialized not neutered", key) {
 992  // 			continue
 993  // 		}
 994  // 		neuteredKey.Zero()
 995  // 		if !testZeroed(i, test.name+" deserialized neutered", key) {
 996  // 			continue
 997  // 		}
 998  // 	}
 999  // }
1000  
1001  // TestMaximumDepth ensures that attempting to retrieve a child key when already at the maximum depth is not allowed.  The serialization of a BIP32 key uses uint8 to encode the depth.  This implicitly bounds the depth of the tree to 255 derivations.  Here we test that an error is returned after 'max uint8'.
1002  func TestMaximumDepth(t *testing.T) {
1003  	net := &chaincfg.MainNetParams
1004  	extKey, e := NewMaster([]byte(`abcd1234abcd1234abcd1234abcd1234`), net)
1005  	if e != nil {
1006  		t.Fatalf("NewMaster: unexpected error: %v", e)
1007  	}
1008  	for i := uint8(0); i < math.MaxUint8; i++ {
1009  		if extKey.Depth() != i {
1010  			t.Fatalf(
1011  				"extendedkey depth %d should match expected value %d",
1012  				extKey.Depth(), i,
1013  			)
1014  		}
1015  		var newKey *ExtendedKey
1016  		newKey, e = extKey.Child(1)
1017  		if e != nil {
1018  			t.Fatalf("Child: unexpected error: %v", e)
1019  		}
1020  		extKey = newKey
1021  	}
1022  	noKey, e := extKey.Child(1)
1023  	if e != ErrDeriveBeyondMaxDepth {
1024  		t.Fatalf(
1025  			"Child: mismatched error: want %v, got %v",
1026  			ErrDeriveBeyondMaxDepth, e,
1027  		)
1028  	}
1029  	if noKey != nil {
1030  		t.Fatal("Child: deriving 256th key should not succeed")
1031  	}
1032  }
1033