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