github.com/particl/partsuite_partutil@v0.0.0-20170924205752-117d65fa91c0/hdkeychain/extendedkey_test.go (about)

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