Skip to content

Commit 61512c1

Browse files
committed
feat(descriptor): backport GetKey impl from #851
- add `KeyMapWrapper` with `GetKey` trait for PSBT signing - implement `GetKey` for `DescriptorSecretKey` - add `From<KeyMap>` conversion - export new `KeyMapWrapper` for downstream crate usage
1 parent 63a4047 commit 61512c1

File tree

2 files changed

+281
-0
lines changed

2 files changed

+281
-0
lines changed

src/descriptor/key_map.rs

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
use std::collections::BTreeMap;
2+
3+
use bitcoin::psbt::{GetKey, GetKeyError, KeyRequest};
4+
use bitcoin::secp256k1::{Secp256k1, Signing};
5+
use bitcoin::PrivateKey;
6+
7+
use crate::descriptor::{DescriptorSecretKey, KeyMap};
8+
9+
/// A wrapper around KeyMap that implements GetKey for PSBT signing.
10+
#[derive(Debug, Clone, Eq, PartialEq)]
11+
pub struct KeyMapWrapper {
12+
map: KeyMap,
13+
}
14+
15+
impl From<KeyMap> for KeyMapWrapper {
16+
fn from(map: KeyMap) -> Self {
17+
KeyMapWrapper { map }
18+
}
19+
}
20+
21+
impl GetKey for KeyMapWrapper {
22+
type Error = GetKeyError;
23+
24+
fn get_key<C: Signing>(
25+
&self,
26+
key_request: KeyRequest,
27+
secp: &Secp256k1<C>,
28+
) -> Result<Option<bitcoin::PrivateKey>, Self::Error> {
29+
Ok(self
30+
.map
31+
.iter()
32+
.find_map(|(_desc_pk, desc_sk)| -> Option<PrivateKey> {
33+
match desc_sk.get_key(key_request.clone(), secp) {
34+
Ok(Some(pk)) => Some(pk),
35+
Ok(None) | Err(_) => None,
36+
}
37+
}))
38+
}
39+
}
40+
41+
impl GetKey for DescriptorSecretKey {
42+
type Error = GetKeyError;
43+
44+
fn get_key<C: Signing>(
45+
&self,
46+
key_request: KeyRequest,
47+
secp: &Secp256k1<C>,
48+
) -> Result<Option<PrivateKey>, Self::Error> {
49+
match (self, key_request) {
50+
(DescriptorSecretKey::Single(single_priv), key_request) => {
51+
let sk = single_priv.key;
52+
let pk = sk.public_key(secp);
53+
let pubkey_map = BTreeMap::from([(pk, sk)]);
54+
pubkey_map.get_key(key_request, secp)
55+
}
56+
(DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Pubkey(public_key)) => {
57+
let xpriv = descriptor_xkey
58+
.xkey
59+
.derive_priv(secp, &descriptor_xkey.derivation_path)
60+
.map_err(GetKeyError::Bip32)?;
61+
let pk = xpriv.private_key.public_key(secp);
62+
63+
if public_key.inner.eq(&pk) {
64+
Ok(Some(xpriv.to_priv()))
65+
} else {
66+
Ok(None)
67+
}
68+
}
69+
(
70+
DescriptorSecretKey::XPrv(descriptor_xkey),
71+
ref key_request @ KeyRequest::Bip32(ref key_source),
72+
) => {
73+
if let Some(key) = descriptor_xkey.xkey.get_key(key_request.clone(), secp)? {
74+
return Ok(Some(key));
75+
}
76+
77+
if descriptor_xkey.matches(key_source, secp).is_some() {
78+
let (_, derivation_path) = key_source;
79+
return Ok(Some(
80+
descriptor_xkey
81+
.xkey
82+
.derive_priv(secp, &derivation_path)
83+
.map_err(GetKeyError::Bip32)?
84+
.to_priv(),
85+
));
86+
}
87+
88+
Ok(None)
89+
}
90+
(DescriptorSecretKey::XPrv(_), KeyRequest::XOnlyPubkey(_)) => {
91+
Err(GetKeyError::NotSupported)
92+
}
93+
(
94+
desc_multi_sk @ DescriptorSecretKey::MultiXPrv(_descriptor_multi_xkey),
95+
key_request,
96+
) => Ok(desc_multi_sk.clone().into_single_keys().iter().find_map(
97+
|desc_sk| match desc_sk.get_key(key_request.clone(), secp) {
98+
Ok(Some(pk)) => Some(pk),
99+
Ok(None) | Err(_) => None,
100+
},
101+
)),
102+
_ => Ok(None),
103+
}
104+
}
105+
}
106+
107+
#[cfg(test)]
108+
mod tests {
109+
use core::str::FromStr;
110+
111+
use bitcoin::bip32::{ChildNumber, DerivationPath, IntoDerivationPath, Xpriv};
112+
113+
use super::*;
114+
use crate::Descriptor;
115+
116+
#[test]
117+
fn get_key_single_key() {
118+
let secp = Secp256k1::new();
119+
120+
let descriptor_sk_s =
121+
"[90b6a706/44'/0'/0'/0/0]cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij";
122+
123+
let single = match descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap() {
124+
DescriptorSecretKey::Single(single) => single,
125+
_ => panic!("unexpected DescriptorSecretKey variant"),
126+
};
127+
128+
let want_sk = single.key;
129+
let descriptor_s = format!("wpkh({})", descriptor_sk_s);
130+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
131+
let keymap_wrapper = KeyMapWrapper::from(keymap);
132+
133+
let pk = want_sk.public_key(&secp);
134+
let request = KeyRequest::Pubkey(pk);
135+
let got_sk = keymap_wrapper
136+
.get_key(request, &secp)
137+
.expect("get_key call errored")
138+
.expect("failed to find the key");
139+
assert_eq!(got_sk, want_sk)
140+
}
141+
142+
#[test]
143+
fn get_key_xpriv_single_key_xpriv() {
144+
let secp = Secp256k1::new();
145+
146+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
147+
148+
let xpriv = s.parse::<Xpriv>().unwrap();
149+
let xpriv_fingerprint = xpriv.fingerprint(&secp);
150+
151+
// Sanity check.
152+
{
153+
let descriptor_sk_s = format!("[{}]{}", xpriv_fingerprint, xpriv);
154+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
155+
let got = match descriptor_sk {
156+
DescriptorSecretKey::XPrv(x) => x.xkey,
157+
_ => panic!("unexpected DescriptorSecretKey variant"),
158+
};
159+
assert_eq!(got, xpriv);
160+
}
161+
162+
let want_sk = xpriv.to_priv();
163+
let descriptor_s = format!("wpkh([{}]{})", xpriv_fingerprint, xpriv);
164+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
165+
let keymap_wrapper = KeyMapWrapper::from(keymap);
166+
167+
let pk = want_sk.public_key(&secp);
168+
let request = KeyRequest::Pubkey(pk);
169+
let got_sk = keymap_wrapper
170+
.get_key(request, &secp)
171+
.expect("get_key call errored")
172+
.expect("failed to find the key");
173+
assert_eq!(got_sk, want_sk)
174+
}
175+
176+
#[test]
177+
fn get_key_xpriv_child_depth_one() {
178+
let secp = Secp256k1::new();
179+
180+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
181+
let master = s.parse::<Xpriv>().unwrap();
182+
let master_fingerprint = master.fingerprint(&secp);
183+
184+
let child_number = ChildNumber::from_hardened_idx(44).unwrap();
185+
let child = master.derive_priv(&secp, &[child_number]).unwrap();
186+
187+
// Sanity check.
188+
{
189+
let descriptor_sk_s = format!("[{}/44']{}", master_fingerprint, child);
190+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
191+
let got = match descriptor_sk {
192+
DescriptorSecretKey::XPrv(ref x) => x.xkey,
193+
_ => panic!("unexpected DescriptorSecretKey variant"),
194+
};
195+
assert_eq!(got, child);
196+
}
197+
198+
let want_sk = child.to_priv();
199+
let descriptor_s = format!("wpkh({}/44')", s);
200+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
201+
let keymap_wrapper = KeyMapWrapper::from(keymap);
202+
203+
let pk = want_sk.public_key(&secp);
204+
let request = KeyRequest::Pubkey(pk);
205+
let got_sk = keymap_wrapper
206+
.get_key(request, &secp)
207+
.expect("get_key call errored")
208+
.expect("failed to find the key");
209+
assert_eq!(got_sk, want_sk)
210+
}
211+
212+
#[test]
213+
fn get_key_xpriv_with_path() {
214+
let secp = Secp256k1::new();
215+
216+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
217+
let master = s.parse::<Xpriv>().unwrap();
218+
let master_fingerprint = master.fingerprint(&secp);
219+
220+
let first_external_child = "44'/0'/0'/0/0";
221+
let derivation_path = first_external_child.into_derivation_path().unwrap();
222+
223+
let child = master.derive_priv(&secp, &derivation_path).unwrap();
224+
225+
// Sanity check.
226+
{
227+
let descriptor_sk_s =
228+
format!("[{}/{}]{}", master_fingerprint, first_external_child, child);
229+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
230+
let got = match descriptor_sk {
231+
DescriptorSecretKey::XPrv(ref x) => x.xkey,
232+
_ => panic!("unexpected DescriptorSecretKey variant"),
233+
};
234+
assert_eq!(got, child);
235+
}
236+
237+
let want_sk = child.to_priv();
238+
let descriptor_s = format!("wpkh({}/44'/0'/0'/0/*)", s);
239+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
240+
let keymap_wrapper = KeyMapWrapper::from(keymap);
241+
242+
let key_source = (master_fingerprint, derivation_path);
243+
let request = KeyRequest::Bip32(key_source);
244+
let got_sk = keymap_wrapper
245+
.get_key(request, &secp)
246+
.expect("get_key call errored")
247+
.expect("failed to find the key");
248+
249+
assert_eq!(got_sk, want_sk)
250+
}
251+
252+
#[test]
253+
fn get_key_xpriv_with_key_origin() {
254+
let secp = Secp256k1::new();
255+
256+
let descriptor_str = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)";
257+
let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(&secp, descriptor_str).unwrap();
258+
let keymap_wrapper = KeyMapWrapper::from(keymap);
259+
260+
let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*").unwrap();
261+
let xpriv = match descriptor_sk {
262+
DescriptorSecretKey::XPrv(descriptor_xkey) => descriptor_xkey,
263+
_ => unreachable!(),
264+
};
265+
266+
let path = DerivationPath::from_str("84'/1'/0'/0").unwrap();
267+
let expected_pk = xpriv.xkey.derive_priv(&secp, &path).unwrap().to_priv();
268+
269+
let (fp, _) = xpriv.origin.unwrap();
270+
let key_request = KeyRequest::Bip32((fp, path));
271+
272+
let pk = keymap_wrapper
273+
.get_key(key_request, &secp)
274+
.expect("get_key should not fail")
275+
.expect("get_key should return a `PrivateKey`");
276+
277+
assert_eq!(pk, expected_pk);
278+
}
279+
}

src/descriptor/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@ pub use self::tr::{TapTree, Tr};
4646

4747
pub mod checksum;
4848
mod key;
49+
mod key_map;
4950

5051
pub use self::key::{
5152
ConversionError, DefiniteDescriptorKey, DerivPaths, DescriptorKeyParseError,
5253
DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, InnerXKey,
5354
SinglePriv, SinglePub, SinglePubKey, Wildcard,
5455
};
56+
pub use self::key_map::KeyMapWrapper;
5557

5658
/// Alias type for a map of public key to secret key
5759
///

0 commit comments

Comments
 (0)