Added tests for DescriptorSecretKey and DescriptorPublicKey
This commit is contained in:
parent
58fea6b205
commit
5944756b78
23
CHANGELOG.md
23
CHANGELOG.md
@ -5,6 +5,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
- APIs Added [#154]
|
||||||
|
- `generate_mnemonic()`, returns string mnemonic
|
||||||
|
- `interface DescriptorSecretKey`
|
||||||
|
- `new(Network, string_mnenoinc, password)`, contructs DescriptorSecretKey
|
||||||
|
- `derive(DerivationPath)`, derives and returns child DescriptorSecretKey
|
||||||
|
- `extend(DerivationPath)`, extends and returns DescriptorSecretKey
|
||||||
|
- `as_public()`, returns DescriptorSecretKey as DescriptorPublicKey
|
||||||
|
- `as_string()`, returns DescriptorSecretKey as String
|
||||||
|
- `interface DescriptorPublicKey`
|
||||||
|
- `derive(DerivationPath)` derives and returns child DescriptorPublicKey
|
||||||
|
- `extend(DerivationPath)` extends and returns DescriptorPublicKey
|
||||||
|
- `as_string()` returns DescriptorPublicKey as String
|
||||||
|
- Interfaces Added [#154]
|
||||||
|
- `DescriptorSecretKey`
|
||||||
|
- `DescriptorPublicKey`
|
||||||
|
- `DerivationPath`
|
||||||
|
- Dictionary Removed [#154]
|
||||||
|
- `ExtendedKeyInfo {mnenonic, xprv, fingerprint}`
|
||||||
|
- APIs Removed [#154]
|
||||||
|
- `generate_extended_key`, returned ExtendedKeyInfo
|
||||||
|
- `restore_extended_key`, returned ExtendedKeyInfo
|
||||||
|
|
||||||
|
[#154]: https://github.com/bitcoindevkit/bdk-ffi/pull/154
|
||||||
|
|
||||||
## [v0.8.0]
|
## [v0.8.0]
|
||||||
- Update BDK to version 0.20.0 [#169]
|
- Update BDK to version 0.20.0 [#169]
|
||||||
|
233
src/lib.rs
233
src/lib.rs
@ -676,45 +676,49 @@ impl DescriptorSecretKey {
|
|||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
|
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
|
||||||
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
||||||
let descriptor_x_key = match descriptor_secret_key.deref() {
|
match descriptor_secret_key.deref() {
|
||||||
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => Some(descriptor_x_key),
|
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
|
||||||
_ => None,
|
let derived_xprv = descriptor_x_key.xkey.derive_priv(&secp, &path)?;
|
||||||
|
let key_source = match descriptor_x_key.origin.clone() {
|
||||||
|
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
|
||||||
|
None => (descriptor_x_key.xkey.fingerprint(&secp), path),
|
||||||
|
};
|
||||||
|
let derived_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
|
||||||
|
origin: Some(key_source),
|
||||||
|
xkey: derived_xprv,
|
||||||
|
derivation_path: BdkDerivationPath::default(),
|
||||||
|
wildcard: descriptor_x_key.wildcard,
|
||||||
|
});
|
||||||
|
Ok(Arc::new(Self {
|
||||||
|
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
BdkDescriptorSecretKey::SinglePriv(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.unwrap();
|
|
||||||
let derived_xprv = descriptor_x_key.xkey.derive_priv(&secp, &path)?;
|
|
||||||
let key_source = match descriptor_x_key.origin.clone() {
|
|
||||||
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
|
|
||||||
None => (descriptor_x_key.xkey.fingerprint(&secp), path),
|
|
||||||
};
|
|
||||||
let derived_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
|
|
||||||
origin: Some(key_source),
|
|
||||||
xkey: derived_xprv,
|
|
||||||
derivation_path: BdkDerivationPath::default(),
|
|
||||||
wildcard: descriptor_x_key.wildcard,
|
|
||||||
});
|
|
||||||
Ok(Arc::new(Self {
|
|
||||||
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> {
|
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> {
|
||||||
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
|
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
|
||||||
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
||||||
let descriptor_x_key = match descriptor_secret_key.deref() {
|
match descriptor_secret_key.deref() {
|
||||||
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => Some(descriptor_x_key),
|
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
|
||||||
_ => None,
|
let extended_path = descriptor_x_key.derivation_path.extend(path);
|
||||||
|
let extended_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
|
||||||
|
origin: descriptor_x_key.origin.clone(),
|
||||||
|
xkey: descriptor_x_key.xkey,
|
||||||
|
derivation_path: extended_path,
|
||||||
|
wildcard: descriptor_x_key.wildcard,
|
||||||
|
});
|
||||||
|
Arc::new(Self {
|
||||||
|
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BdkDescriptorSecretKey::SinglePriv(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.unwrap();
|
|
||||||
let extended_path = descriptor_x_key.derivation_path.extend(path);
|
|
||||||
let extended_descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
|
|
||||||
origin: descriptor_x_key.origin.clone(),
|
|
||||||
xkey: descriptor_x_key.xkey,
|
|
||||||
derivation_path: extended_path,
|
|
||||||
wildcard: descriptor_x_key.wildcard,
|
|
||||||
});
|
|
||||||
Arc::new(Self {
|
|
||||||
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_public(&self) -> Arc<DescriptorPublicKey> {
|
fn as_public(&self) -> Arc<DescriptorPublicKey> {
|
||||||
@ -744,45 +748,50 @@ impl DescriptorPublicKey {
|
|||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
|
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
|
||||||
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
||||||
let descriptor_x_key = match descriptor_public_key.deref() {
|
|
||||||
BdkDescriptorPublicKey::XPub(descriptor_x_key) => Some(descriptor_x_key),
|
match descriptor_public_key.deref() {
|
||||||
_ => None,
|
BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
|
||||||
|
let derived_xpub = descriptor_x_key.xkey.derive_pub(&secp, &path)?;
|
||||||
|
let key_source = match descriptor_x_key.origin.clone() {
|
||||||
|
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
|
||||||
|
None => (descriptor_x_key.xkey.fingerprint(), path),
|
||||||
|
};
|
||||||
|
let derived_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
|
||||||
|
origin: Some(key_source),
|
||||||
|
xkey: derived_xpub,
|
||||||
|
derivation_path: BdkDerivationPath::default(),
|
||||||
|
wildcard: descriptor_x_key.wildcard,
|
||||||
|
});
|
||||||
|
Ok(Arc::new(Self {
|
||||||
|
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
BdkDescriptorPublicKey::SinglePub(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.unwrap();
|
|
||||||
let derived_xpub = descriptor_x_key.xkey.derive_pub(&secp, &path)?;
|
|
||||||
let key_source = match descriptor_x_key.origin.clone() {
|
|
||||||
Some((fingerprint, origin_path)) => (fingerprint, origin_path.extend(path)),
|
|
||||||
None => (descriptor_x_key.xkey.fingerprint(), path),
|
|
||||||
};
|
|
||||||
let derived_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
|
|
||||||
origin: Some(key_source),
|
|
||||||
xkey: derived_xpub,
|
|
||||||
derivation_path: BdkDerivationPath::default(),
|
|
||||||
wildcard: descriptor_x_key.wildcard,
|
|
||||||
});
|
|
||||||
Ok(Arc::new(Self {
|
|
||||||
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> {
|
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> {
|
||||||
let descriptor_secret_key = self.descriptor_public_key_mutex.lock().unwrap();
|
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
|
||||||
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
|
||||||
let descriptor_x_key = match descriptor_secret_key.deref() {
|
match descriptor_public_key.deref() {
|
||||||
BdkDescriptorPublicKey::XPub(descriptor_x_key) => Some(descriptor_x_key),
|
BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
|
||||||
_ => None,
|
let extended_path = descriptor_x_key.derivation_path.extend(path);
|
||||||
|
let extended_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
|
||||||
|
origin: descriptor_x_key.origin.clone(),
|
||||||
|
xkey: descriptor_x_key.xkey,
|
||||||
|
derivation_path: extended_path,
|
||||||
|
wildcard: descriptor_x_key.wildcard,
|
||||||
|
});
|
||||||
|
Arc::new(Self {
|
||||||
|
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BdkDescriptorPublicKey::SinglePub(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.unwrap();
|
|
||||||
let extended_path = descriptor_x_key.derivation_path.extend(path);
|
|
||||||
let extended_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
|
|
||||||
origin: descriptor_x_key.origin.clone(),
|
|
||||||
xkey: descriptor_x_key.xkey,
|
|
||||||
derivation_path: extended_path,
|
|
||||||
wildcard: descriptor_x_key.wildcard,
|
|
||||||
});
|
|
||||||
Arc::new(Self {
|
|
||||||
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self) -> String {
|
fn as_string(&self) -> String {
|
||||||
@ -797,7 +806,7 @@ uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
|
|||||||
// crate.
|
// crate.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{TxBuilder, Wallet};
|
use crate::*;
|
||||||
use bdk::bitcoin::Address;
|
use bdk::bitcoin::Address;
|
||||||
use bdk::bitcoin::Network::Testnet;
|
use bdk::bitcoin::Network::Testnet;
|
||||||
use bdk::wallet::get_funded_wallet;
|
use bdk::wallet::get_funded_wallet;
|
||||||
@ -857,4 +866,96 @@ mod test {
|
|||||||
let output_value = psbt.unsigned_tx.output.get(0).cloned().unwrap().value;
|
let output_value = psbt.unsigned_tx.output.get(0).cloned().unwrap().value;
|
||||||
assert_eq!(output_value, 49_890_u64); // input - fee
|
assert_eq!(output_value, 49_890_u64); // input - fee
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_descriptor_secret_key() -> DescriptorSecretKey {
|
||||||
|
let mnemonic =
|
||||||
|
"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();
|
||||||
|
DescriptorSecretKey::new(Network::Testnet, mnemonic, None).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_dsk(
|
||||||
|
key: &DescriptorSecretKey,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<Arc<DescriptorSecretKey>, BdkError> {
|
||||||
|
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
|
||||||
|
key.derive(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_dsk(key: &DescriptorSecretKey, path: &str) -> Arc<DescriptorSecretKey> {
|
||||||
|
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
|
||||||
|
key.extend(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_dpk(
|
||||||
|
key: &DescriptorPublicKey,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<Arc<DescriptorPublicKey>, BdkError> {
|
||||||
|
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
|
||||||
|
key.derive(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_dpk(key: &DescriptorPublicKey, path: &str) -> Arc<DescriptorPublicKey> {
|
||||||
|
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
|
||||||
|
key.extend(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_descriptor_secret_key() {
|
||||||
|
let master_dsk = get_descriptor_secret_key();
|
||||||
|
assert_eq!(master_dsk.as_string(), "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/*");
|
||||||
|
assert_eq!(master_dsk.as_public().as_string(), "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derive_self() {
|
||||||
|
let master_dsk = get_descriptor_secret_key();
|
||||||
|
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m").unwrap();
|
||||||
|
assert_eq!(derived_dsk.as_string(), "[d1d04177]tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/*");
|
||||||
|
|
||||||
|
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
|
||||||
|
let derived_dpk: &DescriptorPublicKey = &derive_dpk(master_dpk, "m").unwrap();
|
||||||
|
assert_eq!(derived_dpk.as_string(), "[d1d04177]tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derive_descriptors_keys() {
|
||||||
|
let master_dsk = get_descriptor_secret_key();
|
||||||
|
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m/0").unwrap();
|
||||||
|
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
|
||||||
|
|
||||||
|
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
|
||||||
|
let derived_dpk: &DescriptorPublicKey = &derive_dpk(master_dpk, "m/0").unwrap();
|
||||||
|
assert_eq!(derived_dpk.as_string(), "[d1d04177/0]tpubD9oaCiP1MPmQdndm7DCD3D3QU34pWd6BbKSRedoZF1UJcNhEk3PJwkALNYkhxeTKL29oGNR7psqvT1KZydCGqUDEKXN6dVQJY2R8ooLPy8m/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extend_descriptor_keys() {
|
||||||
|
let master_dsk = get_descriptor_secret_key();
|
||||||
|
let extended_dsk: &DescriptorSecretKey = &extend_dsk(&master_dsk, "m/0");
|
||||||
|
assert_eq!(extended_dsk.as_string(), "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0/*");
|
||||||
|
|
||||||
|
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
|
||||||
|
let extended_dpk: &DescriptorPublicKey = &extend_dpk(master_dpk, "m/0");
|
||||||
|
assert_eq!(extended_dpk.as_string(), "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derive_and_extend_descriptor_secret_key() {
|
||||||
|
let master_dsk = get_descriptor_secret_key();
|
||||||
|
|
||||||
|
// derive DescriptorSecretKey with path "m/0" from master
|
||||||
|
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m/0").unwrap();
|
||||||
|
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
|
||||||
|
|
||||||
|
// extend derived_dsk with path "m/0"
|
||||||
|
let extended_dsk: &DescriptorSecretKey = &extend_dsk(derived_dsk, "m/0");
|
||||||
|
assert_eq!(extended_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derive_hardened_path_using_public() {
|
||||||
|
let master_dpk = get_descriptor_secret_key().as_public();
|
||||||
|
let derived_dpk = &derive_dpk(&master_dpk, "m/84h/1h/0h");
|
||||||
|
assert!(derived_dpk.is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user