Skip to content

Commit 2e343d7

Browse files
author
ffranr
authored
Merge pull request #1284 from lightninglabs/ExternalKey-PubKey-unit-test
Add unit test for method ExternalKey.PubKey
2 parents b15fc0a + cba1ca7 commit 2e343d7

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed

asset/asset_test.go

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/btcsuite/btcd/blockchain"
1111
"github.com/btcsuite/btcd/btcec/v2"
1212
"github.com/btcsuite/btcd/btcec/v2/schnorr"
13+
"github.com/btcsuite/btcd/btcutil/hdkeychain"
1314
"github.com/btcsuite/btcd/chaincfg/chainhash"
1415
"github.com/btcsuite/btcd/txscript"
1516
"github.com/btcsuite/btcd/wire"
@@ -1296,3 +1297,217 @@ func TestCopySpendTemplate(t *testing.T) {
12961297

12971298
require.True(t, newAsset.DeepEqual(spendTemplate))
12981299
}
1300+
1301+
// TestExternalKeyPubKey tests that the public key can be derived from an
1302+
// external key.
1303+
func TestExternalKeyPubKey(t *testing.T) {
1304+
t.Parallel()
1305+
1306+
dummyXPub := func() hdkeychain.ExtendedKey {
1307+
xpubStr := "xpub6BynCcnXLYNnnMUZARkHxbP9pG6h5rES8Zb8aHtGwmFX" +
1308+
"9DdjJiyT9PNwkSMZfS3CvGRpvV21SkLRM6xhtshvA3DnJbQsvjD" +
1309+
"yySWGArynQNf"
1310+
xpub, err := hdkeychain.NewKeyFromString(xpubStr)
1311+
require.NoError(t, err, "failed to create xpub from string")
1312+
return *xpub
1313+
}
1314+
1315+
dummyXPubTestnet := func() hdkeychain.ExtendedKey {
1316+
xpubStr := "tpubDDfTBtwwqxXuCej7pKYfbXeCW3inAtv1cw4knmvYTTHk" +
1317+
"w3NoKaeCNH5XdY6n6fnBPc1gWEgeurfmBVzJLfBB1hGU64LsHFz" +
1318+
"Jv4ASqaHyALH"
1319+
xpub, err := hdkeychain.NewKeyFromString(xpubStr)
1320+
require.NoError(t, err, "failed to create xpub from string")
1321+
return *xpub
1322+
}
1323+
1324+
testCases := []struct {
1325+
name string
1326+
externalKey ExternalKey
1327+
expectedPubKey string
1328+
expectError bool
1329+
expectedError string
1330+
}{
1331+
{
1332+
name: "valid BIP-86 external key",
1333+
externalKey: ExternalKey{
1334+
XPub: dummyXPub(),
1335+
MasterFingerprint: 0x12345678,
1336+
DerivationPath: []uint32{
1337+
86 + hdkeychain.HardenedKeyStart,
1338+
0 + hdkeychain.HardenedKeyStart,
1339+
0 + hdkeychain.HardenedKeyStart, 0, 0,
1340+
},
1341+
},
1342+
expectError: false,
1343+
1344+
// The pubkey was generated with "chantools derivekey
1345+
// --rootkey xpub... --path "m/0/0" --neuter" command.
1346+
expectedPubKey: "02c0ca6c5d4dc4899de975f17f1023e424a" +
1347+
"93a7ba6339cbaf514689f75d51787cc",
1348+
},
1349+
{
1350+
name: "invalid derivation path length",
1351+
externalKey: ExternalKey{
1352+
XPub: dummyXPub(),
1353+
MasterFingerprint: 0x12345678,
1354+
DerivationPath: []uint32{
1355+
86 + hdkeychain.HardenedKeyStart,
1356+
0 + hdkeychain.HardenedKeyStart,
1357+
0 + hdkeychain.HardenedKeyStart,
1358+
},
1359+
},
1360+
expectError: true,
1361+
expectedError: "derivation path must have exactly 5 " +
1362+
"components",
1363+
},
1364+
{
1365+
name: "invalid BIP-86 derivation path",
1366+
externalKey: ExternalKey{
1367+
XPub: dummyXPub(),
1368+
MasterFingerprint: 0x12345678,
1369+
DerivationPath: []uint32{
1370+
44 + hdkeychain.HardenedKeyStart,
1371+
0 + hdkeychain.HardenedKeyStart,
1372+
0 + hdkeychain.HardenedKeyStart, 0, 0,
1373+
},
1374+
},
1375+
expectError: true,
1376+
expectedError: "xpub must be derived from BIP-0086 " +
1377+
"(Taproot) derivation path",
1378+
},
1379+
{
1380+
name: "valid BIP-86 external key, custom coin_type",
1381+
externalKey: ExternalKey{
1382+
XPub: dummyXPub(),
1383+
MasterFingerprint: 0x12345678,
1384+
DerivationPath: []uint32{
1385+
86 + hdkeychain.HardenedKeyStart,
1386+
42 + hdkeychain.HardenedKeyStart,
1387+
0 + hdkeychain.HardenedKeyStart, 0, 0,
1388+
},
1389+
},
1390+
expectError: false,
1391+
1392+
// The pubkey was generated with "chantools derivekey
1393+
// --rootkey xpub... --path m/0/0 --neuter" command.
1394+
expectedPubKey: "02c0ca6c5d4dc4899de975f17f1023e424a" +
1395+
"93a7ba6339cbaf514689f75d51787cc",
1396+
},
1397+
{
1398+
name: "valid BIP-86 external key, custom account",
1399+
externalKey: ExternalKey{
1400+
XPub: dummyXPub(),
1401+
MasterFingerprint: 0x12345678,
1402+
DerivationPath: []uint32{
1403+
86 + hdkeychain.HardenedKeyStart,
1404+
0 + hdkeychain.HardenedKeyStart,
1405+
42 + hdkeychain.HardenedKeyStart, 0, 0,
1406+
},
1407+
},
1408+
expectError: false,
1409+
1410+
// The pubkey was generated with "chantools derivekey
1411+
// --rootkey xpub... --path m/0/0 --neuter" command.
1412+
expectedPubKey: "02c0ca6c5d4dc4899de975f17f1023e424a" +
1413+
"93a7ba6339cbaf514689f75d51787cc",
1414+
},
1415+
{
1416+
name: "valid BIP-86 external key, change output",
1417+
externalKey: ExternalKey{
1418+
XPub: dummyXPub(),
1419+
MasterFingerprint: 0x12345678,
1420+
DerivationPath: []uint32{
1421+
86 + hdkeychain.HardenedKeyStart,
1422+
0 + hdkeychain.HardenedKeyStart,
1423+
0 + hdkeychain.HardenedKeyStart, 1, 0,
1424+
},
1425+
},
1426+
expectError: false,
1427+
1428+
// The pubkey was generated with "chantools derivekey
1429+
// --rootkey xpub... --path m/1/0 --neuter" command.
1430+
expectedPubKey: "02ce0e73519634aaf1a34cc17afb517a697" +
1431+
"95c063386030f1b1b724410a84aa709",
1432+
},
1433+
{
1434+
name: "valid BIP-86 external key, change=2",
1435+
externalKey: ExternalKey{
1436+
XPub: dummyXPub(),
1437+
MasterFingerprint: 0x12345678,
1438+
DerivationPath: []uint32{
1439+
86 + hdkeychain.HardenedKeyStart,
1440+
0 + hdkeychain.HardenedKeyStart,
1441+
0 + hdkeychain.HardenedKeyStart, 2, 0,
1442+
},
1443+
},
1444+
expectError: false,
1445+
1446+
// The pubkey was generated with "chantools derivekey
1447+
// --rootkey xpub... --path m/2/0 --neuter" command.
1448+
expectedPubKey: "0278b9669141d21f0598cc44a427c5d03a3" +
1449+
"5d6aaed5555931a99a1659dfea4ebcf",
1450+
},
1451+
{
1452+
name: "valid BIP-86 external key, index=2",
1453+
externalKey: ExternalKey{
1454+
XPub: dummyXPub(),
1455+
MasterFingerprint: 0x12345678,
1456+
DerivationPath: []uint32{
1457+
86 + hdkeychain.HardenedKeyStart,
1458+
0 + hdkeychain.HardenedKeyStart,
1459+
0 + hdkeychain.HardenedKeyStart, 0, 2,
1460+
},
1461+
},
1462+
expectError: false,
1463+
1464+
// The pubkey was generated with "chantools derivekey
1465+
// --rootkey xpub... --path "m/0/2" --neuter" command.
1466+
expectedPubKey: "0375e49d472c25d1138a5526b9b7a0198e1" +
1467+
"d692cc3fd0133f260aca446e1244ff9",
1468+
},
1469+
{
1470+
name: "valid BIP-86 external key, testnet",
1471+
externalKey: ExternalKey{
1472+
XPub: dummyXPubTestnet(),
1473+
MasterFingerprint: 0x12345678,
1474+
DerivationPath: []uint32{
1475+
86 + hdkeychain.HardenedKeyStart,
1476+
1 + hdkeychain.HardenedKeyStart,
1477+
0 + hdkeychain.HardenedKeyStart, 0, 0,
1478+
},
1479+
},
1480+
expectError: false,
1481+
1482+
// The pubkey was generated with "chantools derivekey
1483+
// --testnet --rootkey xpub... --path "m/0/0" --neuter".
1484+
expectedPubKey: "0280a3fcbeb7f770af6dd45cb0f4d02e104" +
1485+
"4eafe0d8b05bcaec79dc0478c7fa0da",
1486+
},
1487+
}
1488+
1489+
for _, tc := range testCases {
1490+
t.Run(tc.name, func(tt *testing.T) {
1491+
pubKey, err := tc.externalKey.PubKey()
1492+
1493+
if tc.expectError {
1494+
require.Error(tt, err, tc.name)
1495+
if tc.expectedError != "" {
1496+
require.Contains(
1497+
tt, err.Error(),
1498+
tc.expectedError,
1499+
)
1500+
}
1501+
1502+
return
1503+
}
1504+
1505+
require.NoError(tt, err)
1506+
require.IsType(tt, btcec.PublicKey{}, pubKey)
1507+
pubKeyHex := hex.EncodeToString(
1508+
pubKey.SerializeCompressed(),
1509+
)
1510+
require.Equal(tt, tc.expectedPubKey, pubKeyHex)
1511+
})
1512+
}
1513+
}

0 commit comments

Comments
 (0)