Skip to content

Commit 51df447

Browse files
committed
fix(get_key): for Xprv with key origin info
- fixes the implementation of `GetKey` for `Xprv` with `KeyRequest::Bip32` and a key_origin information. - adds a new test for a scenario where no wildcard is used, and an specific derivation index is used.
1 parent 10fd701 commit 51df447

File tree

1 file changed

+54
-11
lines changed

1 file changed

+54
-11
lines changed

src/descriptor/key_map.rs

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,28 @@ impl GetKey for DescriptorSecretKey {
7373
return Ok(Some(key));
7474
}
7575

76-
if let Some(matched_path) = descriptor_xkey.matches(key_source, secp) {
76+
if descriptor_xkey.matches(key_source, secp).is_some() {
7777
let (_, full_path) = key_source;
7878

79-
let derivation_path = &full_path[matched_path.len()..];
80-
81-
return Ok(Some(
82-
descriptor_xkey
83-
.xkey
84-
.derive_priv(secp, &derivation_path)
85-
.map_err(GetKeyError::Bip32)?
86-
.to_priv(),
87-
));
79+
match &descriptor_xkey.origin {
80+
Some((_, origin_path)) => {
81+
let derivation_path = &full_path[origin_path.len()..];
82+
return Ok(Some(
83+
descriptor_xkey
84+
.xkey
85+
.derive_priv(secp, &derivation_path)?
86+
.to_priv(),
87+
));
88+
}
89+
None => {
90+
return Ok(Some(
91+
descriptor_xkey
92+
.xkey
93+
.derive_priv(secp, &full_path)?
94+
.to_priv(),
95+
))
96+
}
97+
};
8898
}
8999

90100
Ok(None)
@@ -255,7 +265,7 @@ mod tests {
255265
}
256266

257267
#[test]
258-
fn get_key_xpriv_with_key_origin() {
268+
fn get_key_xpriv_with_key_origin_and_wildcard() {
259269
let secp = Secp256k1::new();
260270

261271
let descriptor_str = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)";
@@ -287,6 +297,39 @@ mod tests {
287297
assert_eq!(pk, expected_pk);
288298
}
289299

300+
#[test]
301+
fn get_key_xpriv_with_key_origin_and_no_wildcard() {
302+
let secp = Secp256k1::new();
303+
304+
let descriptor_str = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/0)";
305+
let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(&secp, descriptor_str).unwrap();
306+
let keymap_wrapper = KeyMapWrapper::from(keymap);
307+
308+
let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/0").unwrap();
309+
let xpriv = match descriptor_sk {
310+
DescriptorSecretKey::XPrv(descriptor_xkey) => descriptor_xkey,
311+
_ => unreachable!(),
312+
};
313+
314+
let expected_deriv_path: DerivationPath = (&[ChildNumber::Normal { index: 0 }][..]).into();
315+
let expected_pk = xpriv
316+
.xkey
317+
.derive_priv(&secp, &expected_deriv_path)
318+
.unwrap()
319+
.to_priv();
320+
321+
let derivation_path = DerivationPath::from_str("84'/1'/0'/0").unwrap();
322+
let (fp, _) = xpriv.origin.unwrap();
323+
let key_request = KeyRequest::Bip32((fp, derivation_path));
324+
325+
let pk = keymap_wrapper
326+
.get_key(key_request, &secp)
327+
.expect("get_key should not fail")
328+
.expect("get_key should return a `PrivateKey`");
329+
330+
assert_eq!(pk, expected_pk);
331+
}
332+
290333
#[test]
291334
fn get_key_keymap_no_match() {
292335
let secp = Secp256k1::new();

0 commit comments

Comments
 (0)