1use crate::collections::HashSet;
15use alloc::string::{String, ToString};
16use alloc::vec::Vec;
17use core::any::TypeId;
18use core::fmt;
19use core::marker::PhantomData;
20use core::ops::Deref;
21use core::str::FromStr;
22
23use rand_core::{CryptoRng, RngCore};
24
25use bitcoin::secp256k1::{self, Secp256k1, Signing};
26
27use bitcoin::bip32;
28use bitcoin::{key::XOnlyPublicKey, Network, PrivateKey, PublicKey};
29
30use miniscript::descriptor::{Descriptor, DescriptorMultiXKey, DescriptorXKey, Wildcard};
31pub use miniscript::descriptor::{
32 DescriptorPublicKey, DescriptorSecretKey, KeyMap, SinglePriv, SinglePub, SinglePubKey,
33 SortedMultiVec,
34};
35pub use miniscript::ScriptContext;
36use miniscript::{Miniscript, Terminal};
37
38use crate::descriptor::{CheckMiniscript, DescriptorError};
39use crate::wallet::utils::SecpCtx;
40
41#[cfg(feature = "keys-bip39")]
42#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
43pub mod bip39;
44
45pub type ValidNetworks = HashSet<Network>;
47
48pub fn any_network() -> ValidNetworks {
50 vec![
51 Network::Bitcoin,
52 Network::Testnet,
53 Network::Testnet4,
54 Network::Regtest,
55 Network::Signet,
56 ]
57 .into_iter()
58 .collect()
59}
60pub fn mainnet_network() -> ValidNetworks {
62 vec![Network::Bitcoin].into_iter().collect()
63}
64pub fn test_networks() -> ValidNetworks {
66 vec![
67 Network::Testnet,
68 Network::Testnet4,
69 Network::Regtest,
70 Network::Signet,
71 ]
72 .into_iter()
73 .collect()
74}
75pub fn merge_networks(a: &ValidNetworks, b: &ValidNetworks) -> ValidNetworks {
77 a.intersection(b).cloned().collect()
78}
79
80#[derive(Debug)]
82pub enum DescriptorKey<Ctx: ScriptContext> {
83 #[doc(hidden)]
84 Public(DescriptorPublicKey, ValidNetworks, PhantomData<Ctx>),
85 #[doc(hidden)]
86 Secret(DescriptorSecretKey, ValidNetworks, PhantomData<Ctx>),
87}
88
89impl<Ctx: ScriptContext> DescriptorKey<Ctx> {
90 pub fn from_public(public: DescriptorPublicKey, networks: ValidNetworks) -> Self {
92 DescriptorKey::Public(public, networks, PhantomData)
93 }
94
95 pub fn from_secret(secret: DescriptorSecretKey, networks: ValidNetworks) -> Self {
97 DescriptorKey::Secret(secret, networks, PhantomData)
98 }
99
100 pub fn override_valid_networks(self, networks: ValidNetworks) -> Self {
102 match self {
103 DescriptorKey::Public(key, _, _) => DescriptorKey::Public(key, networks, PhantomData),
104 DescriptorKey::Secret(key, _, _) => DescriptorKey::Secret(key, networks, PhantomData),
105 }
106 }
107
108 #[doc(hidden)]
113 pub fn extract(
114 self,
115 secp: &SecpCtx,
116 ) -> Result<(DescriptorPublicKey, KeyMap, ValidNetworks), KeyError> {
117 match self {
118 DescriptorKey::Public(public, valid_networks, _) => {
119 Ok((public, KeyMap::default(), valid_networks))
120 }
121 DescriptorKey::Secret(secret, valid_networks, _) => {
122 let mut key_map = KeyMap::new();
123
124 let public = secret
125 .to_public(secp)
126 .map_err(|e| miniscript::Error::Unexpected(e.to_string()))?;
127 key_map.insert(public.clone(), secret);
128
129 Ok((public, key_map, valid_networks))
130 }
131 }
132 }
133}
134
135#[derive(Debug, Eq, PartialEq, Copy, Clone)]
137pub enum ScriptContextEnum {
138 Legacy,
140 Segwitv0,
142 Tap,
144}
145
146impl ScriptContextEnum {
147 pub fn is_legacy(&self) -> bool {
149 self == &ScriptContextEnum::Legacy
150 }
151
152 pub fn is_segwit_v0(&self) -> bool {
154 self == &ScriptContextEnum::Segwitv0
155 }
156
157 pub fn is_taproot(&self) -> bool {
159 self == &ScriptContextEnum::Tap
160 }
161}
162
163pub trait ExtScriptContext: ScriptContext {
165 fn as_enum() -> ScriptContextEnum;
167
168 fn is_legacy() -> bool {
170 Self::as_enum().is_legacy()
171 }
172
173 fn is_segwit_v0() -> bool {
175 Self::as_enum().is_segwit_v0()
176 }
177
178 fn is_taproot() -> bool {
180 Self::as_enum().is_taproot()
181 }
182}
183
184impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
185 fn as_enum() -> ScriptContextEnum {
186 match TypeId::of::<Ctx>() {
187 t if t == TypeId::of::<miniscript::Legacy>() => ScriptContextEnum::Legacy,
188 t if t == TypeId::of::<miniscript::Segwitv0>() => ScriptContextEnum::Segwitv0,
189 t if t == TypeId::of::<miniscript::Tap>() => ScriptContextEnum::Tap,
190 _ => unimplemented!("Unknown ScriptContext type"),
191 }
192 }
193}
194
195pub trait IntoDescriptorKey<Ctx: ScriptContext>: Sized {
317 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
319}
320
321pub enum ExtendedKey<Ctx: ScriptContext = miniscript::Legacy> {
328 Private((bip32::Xpriv, PhantomData<Ctx>)),
330 Public((bip32::Xpub, PhantomData<Ctx>)),
332}
333
334impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
335 pub fn has_secret(&self) -> bool {
337 match self {
338 ExtendedKey::Private(_) => true,
339 ExtendedKey::Public(_) => false,
340 }
341 }
342
343 pub fn into_xprv(self, network: Network) -> Option<bip32::Xpriv> {
346 match self {
347 ExtendedKey::Private((mut xprv, _)) => {
348 xprv.network = network.into();
349 Some(xprv)
350 }
351 ExtendedKey::Public(_) => None,
352 }
353 }
354
355 pub fn into_xpub<C: Signing>(
358 self,
359 network: bitcoin::Network,
360 secp: &Secp256k1<C>,
361 ) -> bip32::Xpub {
362 let mut xpub = match self {
363 ExtendedKey::Private((xprv, _)) => bip32::Xpub::from_priv(secp, &xprv),
364 ExtendedKey::Public((xpub, _)) => xpub,
365 };
366
367 xpub.network = network.into();
368 xpub
369 }
370}
371
372impl<Ctx: ScriptContext> From<bip32::Xpub> for ExtendedKey<Ctx> {
373 fn from(xpub: bip32::Xpub) -> Self {
374 ExtendedKey::Public((xpub, PhantomData))
375 }
376}
377
378impl<Ctx: ScriptContext> From<bip32::Xpriv> for ExtendedKey<Ctx> {
379 fn from(xprv: bip32::Xpriv) -> Self {
380 ExtendedKey::Private((xprv, PhantomData))
381 }
382}
383
384pub trait DerivableKey<Ctx: ScriptContext = miniscript::Legacy>: Sized {
476 #[cfg_attr(
478 feature = "keys-bip39",
479 doc = r##"
480This can be used to get direct access to `xprv`s and `xpub`s for types that implement this trait,
481like [`Mnemonic`](bip39::Mnemonic) when the `keys-bip39` feature is enabled.
482```rust
483use bdk_wallet::bitcoin::Network;
484use bdk_wallet::keys::{DerivableKey, ExtendedKey};
485use bdk_wallet::keys::bip39::{Mnemonic, Language};
486
487# fn main() -> Result<(), Box<dyn std::error::Error>> {
488let xkey: ExtendedKey =
489 Mnemonic::parse_in(
490 Language::English,
491 "jelly crash boy whisper mouse ecology tuna soccer memory million news short",
492 )?
493 .into_extended_key()?;
494let xprv = xkey.into_xprv(Network::Bitcoin).unwrap();
495# Ok(()) }
496```
497"##
498 )]
499 fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError>;
500
501 fn into_descriptor_key(
504 self,
505 origin: Option<bip32::KeySource>,
506 derivation_path: bip32::DerivationPath,
507 ) -> Result<DescriptorKey<Ctx>, KeyError> {
508 match self.into_extended_key()? {
509 ExtendedKey::Private((xprv, _)) => DescriptorSecretKey::XPrv(DescriptorXKey {
510 origin,
511 xkey: xprv,
512 derivation_path,
513 wildcard: Wildcard::Unhardened,
514 })
515 .into_descriptor_key(),
516 ExtendedKey::Public((xpub, _)) => DescriptorPublicKey::XPub(DescriptorXKey {
517 origin,
518 xkey: xpub,
519 derivation_path,
520 wildcard: Wildcard::Unhardened,
521 })
522 .into_descriptor_key(),
523 }
524 }
525}
526
527impl<Ctx: ScriptContext> DerivableKey<Ctx> for ExtendedKey<Ctx> {
529 fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
530 Ok(self)
531 }
532}
533
534impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpub {
535 fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
536 Ok(self.into())
537 }
538}
539
540impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpriv {
541 fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
542 Ok(self.into())
543 }
544}
545
546pub struct GeneratedKey<K, Ctx: ScriptContext> {
548 key: K,
549 valid_networks: ValidNetworks,
550 phantom: PhantomData<Ctx>,
551}
552
553impl<K, Ctx: ScriptContext> GeneratedKey<K, Ctx> {
554 fn new(key: K, valid_networks: ValidNetworks) -> Self {
555 GeneratedKey {
556 key,
557 valid_networks,
558 phantom: PhantomData,
559 }
560 }
561
562 pub fn into_key(self) -> K {
564 self.key
565 }
566}
567
568impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx> {
569 type Target = K;
570
571 fn deref(&self) -> &Self::Target {
572 &self.key
573 }
574}
575
576impl<K: Clone, Ctx: ScriptContext> Clone for GeneratedKey<K, Ctx> {
577 fn clone(&self) -> GeneratedKey<K, Ctx> {
578 GeneratedKey {
579 key: self.key.clone(),
580 valid_networks: self.valid_networks.clone(),
581 phantom: self.phantom,
582 }
583 }
584}
585
586impl<Ctx, K> DerivableKey<Ctx> for GeneratedKey<K, Ctx>
589where
590 Ctx: ScriptContext,
591 K: DerivableKey<Ctx>,
592{
593 fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
594 self.key.into_extended_key()
595 }
596
597 fn into_descriptor_key(
598 self,
599 origin: Option<bip32::KeySource>,
600 derivation_path: bip32::DerivationPath,
601 ) -> Result<DescriptorKey<Ctx>, KeyError> {
602 let descriptor_key = self.key.into_descriptor_key(origin, derivation_path)?;
603 Ok(descriptor_key.override_valid_networks(self.valid_networks))
604 }
605}
606
607impl<Ctx, K> IntoDescriptorKey<Ctx> for GeneratedKey<K, Ctx>
610where
611 Ctx: ScriptContext,
612 K: IntoDescriptorKey<Ctx>,
613{
614 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
615 let desc_key = self.key.into_descriptor_key()?;
616 Ok(desc_key.override_valid_networks(self.valid_networks))
617 }
618}
619
620pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
629 type Entropy: AsMut<[u8]> + Default;
631
632 type Options;
634 type Error: core::fmt::Debug;
636
637 fn generate_with_entropy(
639 options: Self::Options,
640 entropy: Self::Entropy,
641 ) -> Result<GeneratedKey<Self, Ctx>, Self::Error>;
642
643 #[cfg(feature = "std")]
647 fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
648 Self::generate_with_aux_rand(options, &mut bitcoin::key::rand::thread_rng())
649 }
650
651 fn generate_with_aux_rand(
655 options: Self::Options,
656 rng: &mut (impl CryptoRng + RngCore),
657 ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
658 let mut entropy = Self::Entropy::default();
659 rng.fill_bytes(entropy.as_mut());
660 Self::generate_with_entropy(options, entropy)
661 }
662}
663
664pub trait GeneratableDefaultOptions<Ctx>: GeneratableKey<Ctx>
669where
670 Ctx: ScriptContext,
671 <Self as GeneratableKey<Ctx>>::Options: Default,
672{
673 fn generate_with_entropy_default(
675 entropy: Self::Entropy,
676 ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
677 Self::generate_with_entropy(Default::default(), entropy)
678 }
679
680 #[cfg(feature = "std")]
684 fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
685 Self::generate_with_aux_rand(Default::default(), &mut bitcoin::key::rand::thread_rng())
686 }
687
688 fn generate_default_with_aux_rand(
692 rng: &mut (impl CryptoRng + RngCore),
693 ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
694 Self::generate_with_aux_rand(Default::default(), rng)
695 }
696}
697
698impl<Ctx, K> GeneratableDefaultOptions<Ctx> for K
701where
702 Ctx: ScriptContext,
703 K: GeneratableKey<Ctx>,
704 <K as GeneratableKey<Ctx>>::Options: Default,
705{
706}
707
708impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
709 type Entropy = [u8; 32];
710
711 type Options = ();
712 type Error = bip32::Error;
713
714 fn generate_with_entropy(
715 _: Self::Options,
716 entropy: Self::Entropy,
717 ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
718 let xprv = bip32::Xpriv::new_master(Network::Bitcoin, entropy.as_ref())?;
720 Ok(GeneratedKey::new(xprv, any_network()))
721 }
722}
723
724#[derive(Debug, Copy, Clone)]
728pub struct PrivateKeyGenerateOptions {
729 pub compressed: bool,
731}
732
733impl Default for PrivateKeyGenerateOptions {
734 fn default() -> Self {
735 PrivateKeyGenerateOptions { compressed: true }
736 }
737}
738
739impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
740 type Entropy = [u8; secp256k1::constants::SECRET_KEY_SIZE];
741
742 type Options = PrivateKeyGenerateOptions;
743 type Error = bip32::Error;
744
745 fn generate_with_entropy(
746 options: Self::Options,
747 entropy: Self::Entropy,
748 ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
749 let inner = secp256k1::SecretKey::from_slice(&entropy)?;
751 let private_key = PrivateKey {
752 compressed: options.compressed,
753 network: Network::Bitcoin.into(),
754 inner,
755 };
756
757 Ok(GeneratedKey::new(private_key, any_network()))
758 }
759}
760
761impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
762 for (T, bip32::DerivationPath)
763{
764 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
765 self.0.into_descriptor_key(None, self.1)
766 }
767}
768
769impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
770 for (T, bip32::KeySource, bip32::DerivationPath)
771{
772 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
773 self.0.into_descriptor_key(Some(self.1), self.2)
774 }
775}
776
777fn expand_multi_keys<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
778 pks: Vec<Pk>,
779 secp: &SecpCtx,
780) -> Result<(Vec<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError> {
781 let (pks, key_maps_networks): (Vec<_>, Vec<_>) = pks
782 .into_iter()
783 .map(|key| key.into_descriptor_key()?.extract(secp))
784 .collect::<Result<Vec<_>, _>>()?
785 .into_iter()
786 .map(|(a, b, c)| (a, (b, c)))
787 .unzip();
788
789 let (key_map, valid_networks) = key_maps_networks.into_iter().fold(
790 (KeyMap::default(), any_network()),
791 |(mut keys_acc, net_acc), (key, net)| {
792 keys_acc.extend(key);
793 let net_acc = merge_networks(&net_acc, &net);
794
795 (keys_acc, net_acc)
796 },
797 );
798
799 Ok((pks, key_map, valid_networks))
800}
801
802#[doc(hidden)]
804pub fn make_pk<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
805 descriptor_key: Pk,
806 secp: &SecpCtx,
807) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
808 let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?;
809 let minisc = Miniscript::from_ast(Terminal::PkK(key))?;
810
811 minisc.check_miniscript()?;
812
813 Ok((minisc, key_map, valid_networks))
814}
815
816#[doc(hidden)]
818pub fn make_pkh<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
819 descriptor_key: Pk,
820 secp: &SecpCtx,
821) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
822 let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?;
823 let minisc = Miniscript::from_ast(Terminal::PkH(key))?;
824
825 minisc.check_miniscript()?;
826
827 Ok((minisc, key_map, valid_networks))
828}
829
830#[doc(hidden)]
832pub fn make_multi<
833 Pk: IntoDescriptorKey<Ctx>,
834 Ctx: ScriptContext,
835 V: Fn(usize, Vec<DescriptorPublicKey>) -> Terminal<DescriptorPublicKey, Ctx>,
836>(
837 thresh: usize,
838 variant: V,
839 pks: Vec<Pk>,
840 secp: &SecpCtx,
841) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
842 let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
843 let minisc = Miniscript::from_ast(variant(thresh, pks))?;
844
845 minisc.check_miniscript()?;
846
847 Ok((minisc, key_map, valid_networks))
848}
849
850#[doc(hidden)]
852pub fn make_sortedmulti<Pk, Ctx, F>(
853 thresh: usize,
854 pks: Vec<Pk>,
855 build_desc: F,
856 secp: &SecpCtx,
857) -> Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>
858where
859 Pk: IntoDescriptorKey<Ctx>,
860 Ctx: ScriptContext,
861 F: Fn(
862 usize,
863 Vec<DescriptorPublicKey>,
864 ) -> Result<(Descriptor<DescriptorPublicKey>, PhantomData<Ctx>), DescriptorError>,
865{
866 let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
867 let descriptor = build_desc(thresh, pks)?.0;
868
869 Ok((descriptor, key_map, valid_networks))
870}
871
872impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorKey<Ctx> {
874 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
875 Ok(self)
876 }
877}
878
879impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorPublicKey {
880 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
881 let networks = match self {
882 DescriptorPublicKey::Single(_) => any_network(),
883 DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) => {
884 if xkey.network.is_mainnet() {
885 mainnet_network()
886 } else {
887 test_networks()
888 }
889 }
890 DescriptorPublicKey::MultiXPub(DescriptorMultiXKey { xkey, .. }) => {
891 if xkey.network.is_mainnet() {
892 mainnet_network()
893 } else {
894 test_networks()
895 }
896 }
897 };
898
899 Ok(DescriptorKey::from_public(self, networks))
900 }
901}
902
903impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PublicKey {
904 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
905 DescriptorPublicKey::Single(SinglePub {
906 key: SinglePubKey::FullKey(self),
907 origin: None,
908 })
909 .into_descriptor_key()
910 }
911}
912
913impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for XOnlyPublicKey {
914 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
915 DescriptorPublicKey::Single(SinglePub {
916 key: SinglePubKey::XOnly(self),
917 origin: None,
918 })
919 .into_descriptor_key()
920 }
921}
922
923impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorSecretKey {
924 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
925 let networks = match &self {
926 DescriptorSecretKey::Single(sk) if sk.key.network.is_mainnet() => mainnet_network(),
927 DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. }) if xkey.network.is_mainnet() => {
928 mainnet_network()
929 }
930 _ => test_networks(),
931 };
932
933 Ok(DescriptorKey::from_secret(self, networks))
934 }
935}
936
937impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for &'_ str {
938 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
939 DescriptorSecretKey::from_str(self)
940 .map_err(|e| KeyError::Message(e.to_string()))?
941 .into_descriptor_key()
942 }
943}
944
945impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PrivateKey {
946 fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
947 DescriptorSecretKey::Single(SinglePriv {
948 key: self,
949 origin: None,
950 })
951 .into_descriptor_key()
952 }
953}
954
955#[derive(Debug, PartialEq)]
957pub enum KeyError {
958 InvalidScriptContext,
960 InvalidNetwork,
962 InvalidChecksum,
964
965 Message(String),
967
968 Bip32(bitcoin::bip32::Error),
970 Miniscript(miniscript::Error),
972}
973
974impl From<miniscript::Error> for KeyError {
975 fn from(err: miniscript::Error) -> Self {
976 KeyError::Miniscript(err)
977 }
978}
979
980impl From<bip32::Error> for KeyError {
981 fn from(err: bip32::Error) -> Self {
982 KeyError::Bip32(err)
983 }
984}
985
986impl fmt::Display for KeyError {
987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988 match self {
989 Self::InvalidScriptContext => write!(f, "Invalid script context"),
990 Self::InvalidNetwork => write!(f, "Invalid network"),
991 Self::InvalidChecksum => write!(f, "Invalid checksum"),
992 Self::Message(err) => write!(f, "{err}"),
993 Self::Bip32(err) => write!(f, "BIP32 error: {err}"),
994 Self::Miniscript(err) => write!(f, "Miniscript error: {err}"),
995 }
996 }
997}
998
999#[cfg(feature = "std")]
1000impl std::error::Error for KeyError {}
1001
1002#[cfg(test)]
1003mod test {
1004 use bitcoin::bip32;
1005
1006 use super::*;
1007
1008 pub const TEST_ENTROPY: [u8; 32] = [0xAA; 32];
1009
1010 #[test]
1011 fn test_keys_generate_xprv() {
1012 let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
1013 bip32::Xpriv::generate_with_entropy_default(TEST_ENTROPY).unwrap();
1014
1015 assert_eq!(generated_xprv.valid_networks, any_network());
1016 assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");
1017 }
1018
1019 #[test]
1020 fn test_keys_generate_wif() {
1021 let generated_wif: GeneratedKey<_, miniscript::Segwitv0> =
1022 bitcoin::PrivateKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
1023
1024 assert_eq!(generated_wif.valid_networks, any_network());
1025 assert_eq!(
1026 generated_wif.to_string(),
1027 "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"
1028 );
1029 }
1030
1031 #[cfg(feature = "keys-bip39")]
1032 #[test]
1033 fn test_keys_wif_network_bip39() {
1034 let xkey: ExtendedKey = bip39::Mnemonic::parse_in(
1035 bip39::Language::English,
1036 "jelly crash boy whisper mouse ecology tuna soccer memory million news short",
1037 )
1038 .unwrap()
1039 .into_extended_key()
1040 .unwrap();
1041 let xprv = xkey.into_xprv(Network::Testnet).unwrap();
1042
1043 assert_eq!(xprv.network, Network::Testnet.into());
1044 }
1045}