Skip to content

Commit

Permalink
Merge pull request #1284 from lightninglabs/ExternalKey-PubKey-unit-test
Browse files Browse the repository at this point in the history
Add unit test for method ExternalKey.PubKey
  • Loading branch information
ffranr authored Jan 16, 2025
2 parents b15fc0a + cba1ca7 commit 2e343d7
Showing 1 changed file with 215 additions and 0 deletions.
215 changes: 215 additions & 0 deletions asset/asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
Expand Down Expand Up @@ -1296,3 +1297,217 @@ func TestCopySpendTemplate(t *testing.T) {

require.True(t, newAsset.DeepEqual(spendTemplate))
}

// TestExternalKeyPubKey tests that the public key can be derived from an
// external key.
func TestExternalKeyPubKey(t *testing.T) {
t.Parallel()

dummyXPub := func() hdkeychain.ExtendedKey {
xpubStr := "xpub6BynCcnXLYNnnMUZARkHxbP9pG6h5rES8Zb8aHtGwmFX" +
"9DdjJiyT9PNwkSMZfS3CvGRpvV21SkLRM6xhtshvA3DnJbQsvjD" +
"yySWGArynQNf"
xpub, err := hdkeychain.NewKeyFromString(xpubStr)
require.NoError(t, err, "failed to create xpub from string")
return *xpub
}

dummyXPubTestnet := func() hdkeychain.ExtendedKey {
xpubStr := "tpubDDfTBtwwqxXuCej7pKYfbXeCW3inAtv1cw4knmvYTTHk" +
"w3NoKaeCNH5XdY6n6fnBPc1gWEgeurfmBVzJLfBB1hGU64LsHFz" +
"Jv4ASqaHyALH"
xpub, err := hdkeychain.NewKeyFromString(xpubStr)
require.NoError(t, err, "failed to create xpub from string")
return *xpub
}

testCases := []struct {
name string
externalKey ExternalKey
expectedPubKey string
expectError bool
expectedError string
}{
{
name: "valid BIP-86 external key",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 0, 0,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --rootkey xpub... --path "m/0/0" --neuter" command.
expectedPubKey: "02c0ca6c5d4dc4899de975f17f1023e424a" +
"93a7ba6339cbaf514689f75d51787cc",
},
{
name: "invalid derivation path length",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
},
},
expectError: true,
expectedError: "derivation path must have exactly 5 " +
"components",
},
{
name: "invalid BIP-86 derivation path",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
44 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 0, 0,
},
},
expectError: true,
expectedError: "xpub must be derived from BIP-0086 " +
"(Taproot) derivation path",
},
{
name: "valid BIP-86 external key, custom coin_type",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
42 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 0, 0,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --rootkey xpub... --path m/0/0 --neuter" command.
expectedPubKey: "02c0ca6c5d4dc4899de975f17f1023e424a" +
"93a7ba6339cbaf514689f75d51787cc",
},
{
name: "valid BIP-86 external key, custom account",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
42 + hdkeychain.HardenedKeyStart, 0, 0,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --rootkey xpub... --path m/0/0 --neuter" command.
expectedPubKey: "02c0ca6c5d4dc4899de975f17f1023e424a" +
"93a7ba6339cbaf514689f75d51787cc",
},
{
name: "valid BIP-86 external key, change output",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 1, 0,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --rootkey xpub... --path m/1/0 --neuter" command.
expectedPubKey: "02ce0e73519634aaf1a34cc17afb517a697" +
"95c063386030f1b1b724410a84aa709",
},
{
name: "valid BIP-86 external key, change=2",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 2, 0,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --rootkey xpub... --path m/2/0 --neuter" command.
expectedPubKey: "0278b9669141d21f0598cc44a427c5d03a3" +
"5d6aaed5555931a99a1659dfea4ebcf",
},
{
name: "valid BIP-86 external key, index=2",
externalKey: ExternalKey{
XPub: dummyXPub(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 0, 2,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --rootkey xpub... --path "m/0/2" --neuter" command.
expectedPubKey: "0375e49d472c25d1138a5526b9b7a0198e1" +
"d692cc3fd0133f260aca446e1244ff9",
},
{
name: "valid BIP-86 external key, testnet",
externalKey: ExternalKey{
XPub: dummyXPubTestnet(),
MasterFingerprint: 0x12345678,
DerivationPath: []uint32{
86 + hdkeychain.HardenedKeyStart,
1 + hdkeychain.HardenedKeyStart,
0 + hdkeychain.HardenedKeyStart, 0, 0,
},
},
expectError: false,

// The pubkey was generated with "chantools derivekey
// --testnet --rootkey xpub... --path "m/0/0" --neuter".
expectedPubKey: "0280a3fcbeb7f770af6dd45cb0f4d02e104" +
"4eafe0d8b05bcaec79dc0478c7fa0da",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(tt *testing.T) {
pubKey, err := tc.externalKey.PubKey()

if tc.expectError {
require.Error(tt, err, tc.name)
if tc.expectedError != "" {
require.Contains(
tt, err.Error(),
tc.expectedError,
)
}

return
}

require.NoError(tt, err)
require.IsType(tt, btcec.PublicKey{}, pubKey)
pubKeyHex := hex.EncodeToString(
pubKey.SerializeCompressed(),
)
require.Equal(tt, tc.expectedPubKey, pubKeyHex)
})
}
}

0 comments on commit 2e343d7

Please sign in to comment.