Skip to content

Commit 24da1b6

Browse files
ValuedMammalluisschwab
authored andcommitted
fix: GeneratableKey options for PrivateKey, Xpriv
..to require the NetworkKind when generating the key. This fixes an issue where keys generated for mainnet were incorrectly marked valid for any network. test(keys): Add `test_xpriv_generate_options` fixes #22
1 parent a04fa29 commit 24da1b6

File tree

1 file changed

+67
-13
lines changed

1 file changed

+67
-13
lines changed

src/keys/mod.rs

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use bitcoin::{
2727
bip32,
2828
key::XOnlyPublicKey,
2929
secp256k1::{self, Secp256k1, Signing},
30-
Network, NetworkKind, PrivateKey, PublicKey,
30+
NetworkKind, PrivateKey, PublicKey,
3131
};
3232
use miniscript::{
3333
descriptor::{Descriptor, DescriptorMultiXKey, DescriptorXKey, Wildcard},
@@ -618,7 +618,7 @@ pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
618618
/// Type specifying the amount of entropy required e.g. `[u8;32]`
619619
type Entropy: AsMut<[u8]> + Default;
620620

621-
/// Extra options required by the `generate_with_entropy`
621+
/// Extra options required to generate the key.
622622
type Options;
623623
/// Returned error in case of failure
624624
type Error: core::fmt::Debug;
@@ -697,16 +697,35 @@ where
697697
impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
698698
type Entropy = [u8; 32];
699699

700-
type Options = ();
700+
type Options = XprivGenerateOptions;
701701
type Error = bip32::Error;
702702

703703
fn generate_with_entropy(
704-
_: Self::Options,
704+
options: Self::Options,
705705
entropy: Self::Entropy,
706706
) -> 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+
}
710729
}
711730
}
712731

@@ -717,11 +736,16 @@ impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
717736
pub struct PrivateKeyGenerateOptions {
718737
/// Whether the generated key should be "compressed" or not.
719738
pub compressed: bool,
739+
/// The kind of network to be used, defaults to `NetworkKind::Main`.
740+
pub network: NetworkKind,
720741
}
721742

722743
impl Default for PrivateKeyGenerateOptions {
723744
fn default() -> Self {
724-
PrivateKeyGenerateOptions { compressed: true }
745+
PrivateKeyGenerateOptions {
746+
compressed: true,
747+
network: NetworkKind::Main,
748+
}
725749
}
726750
}
727751

@@ -735,15 +759,19 @@ impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
735759
options: Self::Options,
736760
entropy: Self::Entropy,
737761
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
738-
// pick a arbitrary network here, but say that we support all of them
739762
let inner = secp256k1::SecretKey::from_slice(&entropy)?;
740763
let private_key = PrivateKey {
741764
compressed: options.compressed,
742-
network: Network::Bitcoin.into(),
765+
network: options.network,
743766
inner,
744767
};
768+
let valid_networks = if private_key.network.is_mainnet() {
769+
mainnet_network_kind()
770+
} else {
771+
test_network_kind()
772+
};
745773

746-
Ok(GeneratedKey::new(private_key, any_network_kind()))
774+
Ok(GeneratedKey::new(private_key, valid_networks))
747775
}
748776
}
749777

@@ -1021,12 +1049,38 @@ mod test {
10211049

10221050
pub const TEST_ENTROPY: [u8; 32] = [0xAA; 32];
10231051

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+
10241078
#[test]
10251079
fn test_keys_generate_xprv() {
10261080
let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
10271081
bip32::Xpriv::generate_with_entropy_default(TEST_ENTROPY).unwrap();
10281082

1029-
assert_eq!(generated_xprv.valid_network_kinds, any_network_kind());
1083+
assert_eq!(generated_xprv.valid_network_kinds, mainnet_network_kind());
10301084
assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");
10311085
}
10321086

@@ -1035,7 +1089,7 @@ mod test {
10351089
let generated_wif: GeneratedKey<_, miniscript::Segwitv0> =
10361090
bitcoin::PrivateKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
10371091

1038-
assert_eq!(generated_wif.valid_network_kinds, any_network_kind());
1092+
assert_eq!(generated_wif.valid_network_kinds, mainnet_network_kind());
10391093
assert_eq!(
10401094
generated_wif.to_string(),
10411095
"L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"

0 commit comments

Comments
 (0)