@@ -314,6 +314,44 @@ impl DescriptorSecretKey {
314
314
315
315
Ok ( pk)
316
316
}
317
+
318
+ /// Whether or not this key has multiple derivation paths.
319
+ pub fn is_multipath ( & self ) -> bool {
320
+ match * self {
321
+ DescriptorSecretKey :: Single ( ..) | DescriptorSecretKey :: XPrv ( ..) => false ,
322
+ DescriptorSecretKey :: MultiXPrv ( _) => true ,
323
+ }
324
+ }
325
+
326
+ /// Get as many keys as derivation paths in this key.
327
+ ///
328
+ /// For raw keys and single-path extended keys it will return the key itself.
329
+ /// For multipath extended keys it will return a single-path extended key per derivation
330
+ /// path.
331
+ pub fn into_single_keys ( self ) -> Vec < DescriptorSecretKey > {
332
+ match self {
333
+ DescriptorSecretKey :: Single ( ..) | DescriptorSecretKey :: XPrv ( ..) => vec ! [ self ] ,
334
+ DescriptorSecretKey :: MultiXPrv ( xpub) => {
335
+ let DescriptorMultiXKey {
336
+ origin,
337
+ xkey,
338
+ derivation_paths,
339
+ wildcard,
340
+ } = xpub;
341
+ derivation_paths
342
+ . into_iter ( )
343
+ . map ( |derivation_path| {
344
+ DescriptorSecretKey :: XPrv ( DescriptorXKey {
345
+ origin : origin. clone ( ) ,
346
+ xkey,
347
+ derivation_path,
348
+ wildcard,
349
+ } )
350
+ } )
351
+ . collect ( )
352
+ }
353
+ }
354
+ }
317
355
}
318
356
319
357
/// Writes the fingerprint of the origin, if there is one.
@@ -584,6 +622,44 @@ impl DescriptorPublicKey {
584
622
Ok ( DefiniteDescriptorKey :: new ( definite)
585
623
. expect ( "The key should not contain any wildcards at this point" ) )
586
624
}
625
+
626
+ /// Whether or not this key has multiple derivation paths.
627
+ pub fn is_multipath ( & self ) -> bool {
628
+ match * self {
629
+ DescriptorPublicKey :: Single ( ..) | DescriptorPublicKey :: XPub ( ..) => false ,
630
+ DescriptorPublicKey :: MultiXPub ( _) => true ,
631
+ }
632
+ }
633
+
634
+ /// Get as many keys as derivation paths in this key.
635
+ ///
636
+ /// For raw public key and single-path extended keys it will return the key itself.
637
+ /// For multipath extended keys it will return a single-path extended key per derivation
638
+ /// path.
639
+ pub fn into_single_keys ( self ) -> Vec < DescriptorPublicKey > {
640
+ match self {
641
+ DescriptorPublicKey :: Single ( ..) | DescriptorPublicKey :: XPub ( ..) => vec ! [ self ] ,
642
+ DescriptorPublicKey :: MultiXPub ( xpub) => {
643
+ let DescriptorMultiXKey {
644
+ origin,
645
+ xkey,
646
+ derivation_paths,
647
+ wildcard,
648
+ } = xpub;
649
+ derivation_paths
650
+ . into_iter ( )
651
+ . map ( |derivation_path| {
652
+ DescriptorPublicKey :: XPub ( DescriptorXKey {
653
+ origin : origin. clone ( ) ,
654
+ xkey,
655
+ derivation_path,
656
+ wildcard,
657
+ } )
658
+ } )
659
+ . collect ( )
660
+ }
661
+ }
662
+ }
587
663
}
588
664
589
665
impl FromStr for DescriptorSecretKey {
@@ -1317,6 +1393,8 @@ mod test {
1317
1393
// You can't get the "full derivation path" for a multipath extended public key.
1318
1394
let desc_key = DescriptorPublicKey :: from_str ( "[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/<0';1>/8h/*'" ) . unwrap ( ) ;
1319
1395
assert ! ( desc_key. full_derivation_path( ) . is_none( ) ) ;
1396
+ assert ! ( desc_key. is_multipath( ) ) ;
1397
+ assert_eq ! ( desc_key. into_single_keys( ) , vec![ DescriptorPublicKey :: from_str( "[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/0'/8h/*'" ) . unwrap( ) , DescriptorPublicKey :: from_str( "[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/1/8h/*'" ) . unwrap( ) ] ) ;
1320
1398
1321
1399
// All the same but with extended private keys instead of xpubs.
1322
1400
let xprv = get_multipath_xprv ( "tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/2/<0;1;42;9854>" ) ;
@@ -1388,6 +1466,8 @@ mod test {
1388
1466
) ;
1389
1467
let desc_key = DescriptorSecretKey :: from_str ( "[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1>/8h/*'" ) . unwrap ( ) ;
1390
1468
assert ! ( desc_key. to_public( & secp) . is_err( ) ) ;
1469
+ assert ! ( desc_key. is_multipath( ) ) ;
1470
+ assert_eq ! ( desc_key. into_single_keys( ) , vec![ DescriptorSecretKey :: from_str( "[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/0'/8h/*'" ) . unwrap( ) , DescriptorSecretKey :: from_str( "[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/1/8h/*'" ) . unwrap( ) ] ) ;
1391
1471
1392
1472
// It's invalid to:
1393
1473
// - Not have opening or closing brackets
0 commit comments