Skip to content

Commit e77e48c

Browse files
committed
Added tests for DescriptorSecretKey and DescriptorPublicKey
1 parent 508e15d commit e77e48c

File tree

2 files changed

+206
-66
lines changed

2 files changed

+206
-66
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
- APIs Added [#154]
9+
- `generate_mnemonic()`, returns string mnemonic
10+
- `interface DescriptorSecretKey`
11+
- `new(Network, string_mnenoinc, password)`, contructs DescriptorSecretKey
12+
- `derive(DerivationPath)`, derives and returns child DescriptorSecretKey
13+
- `extend(DerivationPath)`, extends and returns DescriptorSecretKey
14+
- `as_public()`, returns DescriptorSecretKey as DescriptorPublicKey
15+
- `as_string()`, returns DescriptorSecretKey as String
16+
- `interface DescriptorPublicKey`
17+
- `derive(DerivationPath)` derives and returns child DescriptorPublicKey
18+
- `extend(DerivationPath)` extends and returns DescriptorPublicKey
19+
- `as_string()` returns DescriptorPublicKey as String
20+
- Interfaces Added [#154]
21+
- `DescriptorSecretKey`
22+
- `DescriptorPublicKey`
23+
- `DerivationPath`
24+
- Dictionary Removed [#154]
25+
- `ExtendedKeyInfo {mnenonic, xprv, fingerprint}`
26+
- APIs Removed [#154]
27+
- `generate_extended_key`, returned ExtendedKeyInfo
28+
- `restore_extended_key`, returned ExtendedKeyInfo
29+
30+
[#154]: https://github.com/bitcoindevkit/bdk-ffi/pull/154
831

932
## [v0.8.0]
1033
- Update BDK to version 0.20.0 [#169]

src/lib.rs

Lines changed: 183 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -676,45 +676,49 @@ impl DescriptorSecretKey {
676676
let secp = Secp256k1::new();
677677
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
678678
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
679-
let descriptor_x_key = match descriptor_secret_key.deref() {
680-
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => Some(descriptor_x_key),
681-
_ => None,
679+
match descriptor_secret_key.deref() {
680+
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
681+
let derived_xprv = descriptor_x_key.xkey.derive_priv(&secp, &path)?;
682+
let key_source = match descriptor_x_key.origin.clone() {
683+
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
684+
None => (descriptor_x_key.xkey.fingerprint(&secp), path),
685+
};
686+
let derived_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
687+
origin: Some(key_source),
688+
xkey: derived_xprv,
689+
derivation_path: BdkDerivationPath::default(),
690+
wildcard: descriptor_x_key.wildcard,
691+
});
692+
Ok(Arc::new(Self {
693+
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
694+
}))
695+
}
696+
BdkDescriptorSecretKey::SinglePriv(_) => {
697+
unreachable!()
698+
}
682699
}
683-
.unwrap();
684-
let derived_xprv = descriptor_x_key.xkey.derive_priv(&secp, &path)?;
685-
let key_source = match descriptor_x_key.origin.clone() {
686-
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
687-
None => (descriptor_x_key.xkey.fingerprint(&secp), path),
688-
};
689-
let derived_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
690-
origin: Some(key_source),
691-
xkey: derived_xprv,
692-
derivation_path: BdkDerivationPath::default(),
693-
wildcard: descriptor_x_key.wildcard,
694-
});
695-
Ok(Arc::new(Self {
696-
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
697-
}))
698700
}
699701

700702
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> {
701703
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
702704
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
703-
let descriptor_x_key = match descriptor_secret_key.deref() {
704-
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => Some(descriptor_x_key),
705-
_ => None,
705+
match descriptor_secret_key.deref() {
706+
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
707+
let extended_path = descriptor_x_key.derivation_path.extend(path);
708+
let extended_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
709+
origin: descriptor_x_key.origin.clone(),
710+
xkey: descriptor_x_key.xkey,
711+
derivation_path: extended_path,
712+
wildcard: descriptor_x_key.wildcard,
713+
});
714+
Arc::new(Self {
715+
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
716+
})
717+
}
718+
BdkDescriptorSecretKey::SinglePriv(_) => {
719+
unreachable!()
720+
}
706721
}
707-
.unwrap();
708-
let extended_path = descriptor_x_key.derivation_path.extend(path);
709-
let extended_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
710-
origin: descriptor_x_key.origin.clone(),
711-
xkey: descriptor_x_key.xkey,
712-
derivation_path: extended_path,
713-
wildcard: descriptor_x_key.wildcard,
714-
});
715-
Arc::new(Self {
716-
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
717-
})
718722
}
719723

720724
fn as_public(&self) -> Arc<DescriptorPublicKey> {
@@ -744,45 +748,50 @@ impl DescriptorPublicKey {
744748
let secp = Secp256k1::new();
745749
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
746750
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
747-
let descriptor_x_key = match descriptor_public_key.deref() {
748-
BdkDescriptorPublicKey::XPub(descriptor_x_key) => Some(descriptor_x_key),
749-
_ => None,
751+
752+
match descriptor_public_key.deref() {
753+
BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
754+
let derived_xpub = descriptor_x_key.xkey.derive_pub(&secp, &path)?;
755+
let key_source = match descriptor_x_key.origin.clone() {
756+
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
757+
None => (descriptor_x_key.xkey.fingerprint(), path),
758+
};
759+
let derived_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
760+
origin: Some(key_source),
761+
xkey: derived_xpub,
762+
derivation_path: BdkDerivationPath::default(),
763+
wildcard: descriptor_x_key.wildcard,
764+
});
765+
Ok(Arc::new(Self {
766+
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
767+
}))
768+
}
769+
BdkDescriptorPublicKey::SinglePub(_) => {
770+
unreachable!()
771+
}
750772
}
751-
.unwrap();
752-
let derived_xpub = descriptor_x_key.xkey.derive_pub(&secp, &path)?;
753-
let key_source = match descriptor_x_key.origin.clone() {
754-
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
755-
None => (descriptor_x_key.xkey.fingerprint(), path),
756-
};
757-
let derived_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
758-
origin: Some(key_source),
759-
xkey: derived_xpub,
760-
derivation_path: BdkDerivationPath::default(),
761-
wildcard: descriptor_x_key.wildcard,
762-
});
763-
Ok(Arc::new(Self {
764-
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
765-
}))
766773
}
767774

768775
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> {
769-
let descriptor_secret_key = self.descriptor_public_key_mutex.lock().unwrap();
776+
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
770777
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
771-
let descriptor_x_key = match descriptor_secret_key.deref() {
772-
BdkDescriptorPublicKey::XPub(descriptor_x_key) => Some(descriptor_x_key),
773-
_ => None,
778+
match descriptor_public_key.deref() {
779+
BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
780+
let extended_path = descriptor_x_key.derivation_path.extend(path);
781+
let extended_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
782+
origin: descriptor_x_key.origin.clone(),
783+
xkey: descriptor_x_key.xkey,
784+
derivation_path: extended_path,
785+
wildcard: descriptor_x_key.wildcard,
786+
});
787+
Arc::new(Self {
788+
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
789+
})
790+
}
791+
BdkDescriptorPublicKey::SinglePub(_) => {
792+
unreachable!()
793+
}
774794
}
775-
.unwrap();
776-
let extended_path = descriptor_x_key.derivation_path.extend(path);
777-
let extended_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
778-
origin: descriptor_x_key.origin.clone(),
779-
xkey: descriptor_x_key.xkey,
780-
derivation_path: extended_path,
781-
wildcard: descriptor_x_key.wildcard,
782-
});
783-
Arc::new(Self {
784-
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
785-
})
786795
}
787796

788797
fn as_string(&self) -> String {
@@ -797,7 +806,7 @@ uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
797806
// crate.
798807
#[cfg(test)]
799808
mod test {
800-
use crate::{TxBuilder, Wallet};
809+
use crate::*;
801810
use bdk::bitcoin::Address;
802811
use bdk::bitcoin::Network::Testnet;
803812
use bdk::wallet::get_funded_wallet;
@@ -857,4 +866,112 @@ mod test {
857866
let output_value = psbt.unsigned_tx.output.get(0).cloned().unwrap().value;
858867
assert_eq!(output_value, 49_890_u64); // input - fee
859868
}
869+
870+
fn get_descriptor_secret_key() -> DescriptorSecretKey {
871+
let mnemonic =
872+
"chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string();
873+
DescriptorSecretKey::new(Network::Testnet, mnemonic, None).unwrap()
874+
}
875+
876+
fn derive_dsk(
877+
key: &DescriptorSecretKey,
878+
path: &str,
879+
) -> Result<Arc<DescriptorSecretKey>, BdkError> {
880+
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
881+
key.derive(path)
882+
}
883+
884+
fn extend_dsk(key: &DescriptorSecretKey, path: &str) -> Arc<DescriptorSecretKey> {
885+
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
886+
key.extend(path)
887+
}
888+
889+
fn derive_dpk(
890+
key: &DescriptorPublicKey,
891+
path: &str,
892+
) -> Result<Arc<DescriptorPublicKey>, BdkError> {
893+
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
894+
key.derive(path)
895+
}
896+
897+
fn extend_dpk(key: &DescriptorPublicKey, path: &str) -> Arc<DescriptorPublicKey> {
898+
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
899+
key.extend(path)
900+
}
901+
902+
#[test]
903+
fn test_generate_descriptor_secret_key() {
904+
let master_dsk = get_descriptor_secret_key();
905+
assert_eq!(master_dsk.as_string(), "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/*");
906+
assert_eq!(master_dsk.as_public().as_string(), "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/*");
907+
}
908+
909+
#[test]
910+
fn test_derive_self() {
911+
let master_dsk = get_descriptor_secret_key();
912+
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m").unwrap();
913+
assert_eq!(derived_dsk.as_string(), "[d1d04177]tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/*");
914+
915+
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
916+
let derived_dpk: &DescriptorPublicKey = &derive_dpk(master_dpk, "m").unwrap();
917+
assert_eq!(derived_dpk.as_string(), "[d1d04177]tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/*");
918+
}
919+
920+
#[test]
921+
fn test_derive_descriptors_keys() {
922+
let master_dsk = get_descriptor_secret_key();
923+
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m/0").unwrap();
924+
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
925+
926+
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
927+
let derived_dpk: &DescriptorPublicKey = &derive_dpk(master_dpk, "m/0").unwrap();
928+
assert_eq!(derived_dpk.as_string(), "[d1d04177/0]tpubD9oaCiP1MPmQdndm7DCD3D3QU34pWd6BbKSRedoZF1UJcNhEk3PJwkALNYkhxeTKL29oGNR7psqvT1KZydCGqUDEKXN6dVQJY2R8ooLPy8m/*");
929+
}
930+
931+
#[test]
932+
fn test_extend_descriptor_keys() {
933+
let master_dsk = get_descriptor_secret_key();
934+
let extended_dsk: &DescriptorSecretKey = &extend_dsk(&master_dsk, "m/0");
935+
assert_eq!(extended_dsk.as_string(), "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0/*");
936+
937+
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
938+
let extended_dpk: &DescriptorPublicKey = &extend_dpk(master_dpk, "m/0");
939+
assert_eq!(extended_dpk.as_string(), "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0/*");
940+
}
941+
942+
#[test]
943+
fn test_derive_and_extend_descriptor_secret_key() {
944+
let master_dsk = get_descriptor_secret_key();
945+
946+
// derive DescriptorSecretKey with path "m/0" from master
947+
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m/0").unwrap();
948+
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
949+
950+
// extend derived_dsk with path "m/0"
951+
let extended_dsk: &DescriptorSecretKey = &extend_dsk(derived_dsk, "m/0");
952+
assert_eq!(extended_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0/*");
953+
let extended_dsk_mutex = extended_dsk.descriptor_secret_key_mutex.lock().unwrap();
954+
955+
// checking extended derivation_path
956+
assert_eq!(
957+
match extended_dsk_mutex.deref() {
958+
BdkDescriptorSecretKey::XPrv(xkey) => {
959+
Some(xkey.derivation_path.clone())
960+
}
961+
_ => {
962+
None
963+
}
964+
}
965+
.unwrap()
966+
.to_string(),
967+
BdkDerivationPath::from_str("m/0").unwrap().to_string()
968+
);
969+
}
970+
971+
#[test]
972+
fn test_derive_hardened_path_using_public() {
973+
let master_dpk = get_descriptor_secret_key().as_public();
974+
let derived_dpk = &derive_dpk(&master_dpk, "m/84h/1h/0h");
975+
assert!(derived_dpk.is_err());
976+
}
860977
}

0 commit comments

Comments
 (0)