@@ -27,7 +27,7 @@ use bitcoin::{
27
27
bip32,
28
28
key:: XOnlyPublicKey ,
29
29
secp256k1:: { self , Secp256k1 , Signing } ,
30
- Network , NetworkKind , PrivateKey , PublicKey ,
30
+ NetworkKind , PrivateKey , PublicKey ,
31
31
} ;
32
32
use miniscript:: {
33
33
descriptor:: { Descriptor , DescriptorMultiXKey , DescriptorXKey , Wildcard } ,
@@ -618,7 +618,7 @@ pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
618
618
/// Type specifying the amount of entropy required e.g. `[u8;32]`
619
619
type Entropy : AsMut < [ u8 ] > + Default ;
620
620
621
- /// Extra options required by the `generate_with_entropy`
621
+ /// Extra options required to generate the key.
622
622
type Options ;
623
623
/// Returned error in case of failure
624
624
type Error : core:: fmt:: Debug ;
@@ -697,16 +697,35 @@ where
697
697
impl < Ctx : ScriptContext > GeneratableKey < Ctx > for bip32:: Xpriv {
698
698
type Entropy = [ u8 ; 32 ] ;
699
699
700
- type Options = ( ) ;
700
+ type Options = XprivGenerateOptions ;
701
701
type Error = bip32:: Error ;
702
702
703
703
fn generate_with_entropy (
704
- _ : Self :: Options ,
704
+ options : Self :: Options ,
705
705
entropy : Self :: Entropy ,
706
706
) -> Result < GeneratedKey < Self , Ctx > , Self :: Error > {
707
- // Pick an arbitrary network kind here, but say that we support all of them.
708
- let xprv = bip32:: Xpriv :: new_master ( NetworkKind :: Main , entropy. as_ref ( ) ) ?;
709
- Ok ( GeneratedKey :: new ( xprv, any_network_kind ( ) ) )
707
+ let ( kind, valid_networks) = if options. network . is_mainnet ( ) {
708
+ ( NetworkKind :: Main , mainnet_network_kind ( ) )
709
+ } else {
710
+ ( NetworkKind :: Test , test_network_kind ( ) )
711
+ } ;
712
+ let xprv = bip32:: Xpriv :: new_master ( kind, entropy. as_ref ( ) ) ?;
713
+ Ok ( GeneratedKey :: new ( xprv, valid_networks) )
714
+ }
715
+ }
716
+
717
+ /// Options for generating a [`bip32::Xpriv`].
718
+ #[ derive( Debug , Copy , Clone ) ]
719
+ pub struct XprivGenerateOptions {
720
+ /// The network to be used when generating the xprv, default to `NetworkKind::Main`
721
+ pub network : NetworkKind ,
722
+ }
723
+
724
+ impl Default for XprivGenerateOptions {
725
+ fn default ( ) -> Self {
726
+ XprivGenerateOptions {
727
+ network : NetworkKind :: Main ,
728
+ }
710
729
}
711
730
}
712
731
@@ -717,11 +736,16 @@ impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
717
736
pub struct PrivateKeyGenerateOptions {
718
737
/// Whether the generated key should be "compressed" or not.
719
738
pub compressed : bool ,
739
+ /// The kind of network to be used, defaults to `NetworkKind::Main`.
740
+ pub network : NetworkKind ,
720
741
}
721
742
722
743
impl Default for PrivateKeyGenerateOptions {
723
744
fn default ( ) -> Self {
724
- PrivateKeyGenerateOptions { compressed : true }
745
+ PrivateKeyGenerateOptions {
746
+ compressed : true ,
747
+ network : NetworkKind :: Main ,
748
+ }
725
749
}
726
750
}
727
751
@@ -735,15 +759,19 @@ impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
735
759
options : Self :: Options ,
736
760
entropy : Self :: Entropy ,
737
761
) -> Result < GeneratedKey < Self , Ctx > , Self :: Error > {
738
- // pick a arbitrary network here, but say that we support all of them
739
762
let inner = secp256k1:: SecretKey :: from_slice ( & entropy) ?;
740
763
let private_key = PrivateKey {
741
764
compressed : options. compressed ,
742
- network : Network :: Bitcoin . into ( ) ,
765
+ network : options . network ,
743
766
inner,
744
767
} ;
768
+ let valid_networks = if private_key. network . is_mainnet ( ) {
769
+ mainnet_network_kind ( )
770
+ } else {
771
+ test_network_kind ( )
772
+ } ;
745
773
746
- Ok ( GeneratedKey :: new ( private_key, any_network_kind ( ) ) )
774
+ Ok ( GeneratedKey :: new ( private_key, valid_networks ) )
747
775
}
748
776
}
749
777
@@ -1021,12 +1049,38 @@ mod test {
1021
1049
1022
1050
pub const TEST_ENTROPY : [ u8 ; 32 ] = [ 0xAA ; 32 ] ;
1023
1051
1052
+ #[ test]
1053
+ fn test_xpriv_generate_options ( ) {
1054
+ use bitcoin:: bip32:: Xpriv ;
1055
+ let secp = SecpCtx :: new ( ) ;
1056
+ // Test
1057
+ let options = XprivGenerateOptions {
1058
+ network : NetworkKind :: Test ,
1059
+ } ;
1060
+ let xpriv: GeneratedKey < Xpriv , miniscript:: Segwitv0 > = Xpriv :: generate ( options) . unwrap ( ) ;
1061
+ let desc_key = xpriv
1062
+ . into_descriptor_key ( None , "m/84h/1h/0h" . parse ( ) . unwrap ( ) )
1063
+ . unwrap ( ) ;
1064
+ let desc_pk = desc_key. extract ( & secp) . unwrap ( ) . 0 ;
1065
+ assert ! ( desc_pk. to_string( ) . contains( "tpub" ) ) ;
1066
+ // Main
1067
+ let options = XprivGenerateOptions {
1068
+ network : NetworkKind :: Main ,
1069
+ } ;
1070
+ let xpriv: GeneratedKey < Xpriv , miniscript:: Segwitv0 > = Xpriv :: generate ( options) . unwrap ( ) ;
1071
+ let desc_key = xpriv
1072
+ . into_descriptor_key ( None , "m/84h/1h/0h" . parse ( ) . unwrap ( ) )
1073
+ . unwrap ( ) ;
1074
+ let desc_pk = desc_key. extract ( & secp) . unwrap ( ) . 0 ;
1075
+ assert ! ( desc_pk. to_string( ) . contains( "xpub" ) ) ;
1076
+ }
1077
+
1024
1078
#[ test]
1025
1079
fn test_keys_generate_xprv ( ) {
1026
1080
let generated_xprv: GeneratedKey < _ , miniscript:: Segwitv0 > =
1027
1081
bip32:: Xpriv :: generate_with_entropy_default ( TEST_ENTROPY ) . unwrap ( ) ;
1028
1082
1029
- assert_eq ! ( generated_xprv. valid_network_kinds, any_network_kind ( ) ) ;
1083
+ assert_eq ! ( generated_xprv. valid_network_kinds, mainnet_network_kind ( ) ) ;
1030
1084
assert_eq ! ( generated_xprv. to_string( ) , "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q" ) ;
1031
1085
}
1032
1086
@@ -1035,7 +1089,7 @@ mod test {
1035
1089
let generated_wif: GeneratedKey < _ , miniscript:: Segwitv0 > =
1036
1090
bitcoin:: PrivateKey :: generate_with_entropy_default ( TEST_ENTROPY ) . unwrap ( ) ;
1037
1091
1038
- assert_eq ! ( generated_wif. valid_network_kinds, any_network_kind ( ) ) ;
1092
+ assert_eq ! ( generated_wif. valid_network_kinds, mainnet_network_kind ( ) ) ;
1039
1093
assert_eq ! (
1040
1094
generated_wif. to_string( ) ,
1041
1095
"L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"
0 commit comments