Skip to content

Commit 5224964

Browse files
committed
feat: impl GetKey for KeyMap and DescriptorSecretKey
- add the implementation of GetKey for `KeyMap`, and also implements it for the inner type `DescriptorSecretKey` in order to make the match branching and logic clearer.
1 parent 40f1c7f commit 5224964

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

src/descriptor/key_map.rs

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
55
use core::iter;
66

7+
use bitcoin::psbt::{GetKey, GetKeyError, KeyRequest};
78
use bitcoin::secp256k1::{Secp256k1, Signing};
9+
use bitcoin::PrivateKey;
810

911
#[cfg(doc)]
1012
use super::Descriptor;
@@ -75,3 +77,258 @@ impl iter::Extend<(DescriptorPublicKey, DescriptorSecretKey)> for KeyMap {
7577
self.map.extend(iter)
7678
}
7779
}
80+
81+
impl GetKey for KeyMap {
82+
type Error = GetKeyError;
83+
84+
fn get_key<C: Signing>(
85+
&self,
86+
key_request: KeyRequest,
87+
secp: &Secp256k1<C>,
88+
) -> Result<Option<bitcoin::PrivateKey>, Self::Error> {
89+
Ok(self
90+
.map
91+
.iter()
92+
.find_map(|(_desc_pk, desc_sk)| -> Option<PrivateKey> {
93+
match desc_sk.get_key(key_request.clone(), secp) {
94+
Ok(Some(pk)) => Some(pk),
95+
Ok(None) | Err(_) => None,
96+
}
97+
}))
98+
}
99+
}
100+
101+
impl GetKey for DescriptorSecretKey {
102+
type Error = GetKeyError;
103+
104+
fn get_key<C: Signing>(
105+
&self,
106+
key_request: KeyRequest,
107+
secp: &Secp256k1<C>,
108+
) -> Result<Option<PrivateKey>, Self::Error> {
109+
match (self, key_request) {
110+
(DescriptorSecretKey::Single(single_priv), key_request) => {
111+
let sk = single_priv.key;
112+
let pk = sk.public_key(secp);
113+
let pubkey_map = BTreeMap::from([(pk, sk)]);
114+
pubkey_map.get_key(key_request, secp)
115+
}
116+
(DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Pubkey(public_key)) => {
117+
let xpriv = descriptor_xkey
118+
.xkey
119+
.derive_priv(secp, &descriptor_xkey.derivation_path)
120+
.map_err(GetKeyError::Bip32)?;
121+
let pk = xpriv.private_key.public_key(secp);
122+
123+
if public_key.inner.eq(&pk) {
124+
Ok(Some(xpriv.to_priv()))
125+
} else {
126+
Ok(None)
127+
}
128+
}
129+
(
130+
DescriptorSecretKey::XPrv(descriptor_xkey),
131+
ref key_request @ KeyRequest::Bip32(ref key_source),
132+
) => {
133+
if let Some(key) = descriptor_xkey.xkey.get_key(key_request.clone(), secp)? {
134+
return Ok(Some(key));
135+
}
136+
137+
if let Some(_) = descriptor_xkey.matches(key_source, secp) {
138+
let (_, derivation_path) = key_source;
139+
return Ok(Some(
140+
descriptor_xkey
141+
.xkey
142+
.derive_priv(secp, &derivation_path)
143+
.map_err(GetKeyError::Bip32)?
144+
.to_priv(),
145+
));
146+
}
147+
148+
Ok(None)
149+
}
150+
(DescriptorSecretKey::XPrv(_), KeyRequest::XOnlyPubkey(_)) => {
151+
Err(GetKeyError::NotSupported)
152+
}
153+
(
154+
desc_multi_sk @ DescriptorSecretKey::MultiXPrv(_descriptor_multi_xkey),
155+
key_request,
156+
) => Ok(desc_multi_sk.clone().into_single_keys().iter().find_map(
157+
|desc_sk| match desc_sk.get_key(key_request.clone(), secp) {
158+
Ok(Some(pk)) => Some(pk),
159+
Ok(None) | Err(_) => None,
160+
},
161+
)),
162+
_ => unreachable!(),
163+
}
164+
}
165+
}
166+
167+
#[cfg(test)]
168+
mod tests {
169+
use core::str::FromStr;
170+
171+
use bitcoin::bip32::{ChildNumber, DerivationPath, IntoDerivationPath, Xpriv};
172+
173+
use super::*;
174+
use crate::Descriptor;
175+
176+
#[test]
177+
fn get_key_single_key() {
178+
let secp = Secp256k1::new();
179+
180+
let descriptor_sk_s =
181+
"[90b6a706/44'/0'/0'/0/0]cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij";
182+
183+
let single = match descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap() {
184+
DescriptorSecretKey::Single(single) => single,
185+
_ => panic!("unexpected DescriptorSecretKey variant"),
186+
};
187+
188+
let want_sk = single.key;
189+
let descriptor_s = format!("wpkh({})", descriptor_sk_s);
190+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
191+
192+
let pk = want_sk.public_key(&secp);
193+
let request = KeyRequest::Pubkey(pk);
194+
let got_sk = keymap
195+
.get_key(request, &secp)
196+
.expect("get_key call errored")
197+
.expect("failed to find the key");
198+
assert_eq!(got_sk, want_sk)
199+
}
200+
201+
#[test]
202+
fn get_key_xpriv_single_key_xpriv() {
203+
let secp = Secp256k1::new();
204+
205+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
206+
207+
let xpriv = s.parse::<Xpriv>().unwrap();
208+
let xpriv_fingerprint = xpriv.fingerprint(&secp);
209+
210+
// Sanity check.
211+
{
212+
let descriptor_sk_s = format!("[{}]{}", xpriv_fingerprint, xpriv);
213+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
214+
let got = match descriptor_sk {
215+
DescriptorSecretKey::XPrv(x) => x.xkey,
216+
_ => panic!("unexpected DescriptorSecretKey variant"),
217+
};
218+
assert_eq!(got, xpriv);
219+
}
220+
221+
let want_sk = xpriv.to_priv();
222+
let descriptor_s = format!("wpkh([{}]{})", xpriv_fingerprint, xpriv);
223+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
224+
225+
let pk = want_sk.public_key(&secp);
226+
let request = KeyRequest::Pubkey(pk);
227+
let got_sk = keymap
228+
.get_key(request, &secp)
229+
.expect("get_key call errored")
230+
.expect("failed to find the key");
231+
assert_eq!(got_sk, want_sk)
232+
}
233+
234+
#[test]
235+
fn get_key_xpriv_child_depth_one() {
236+
let secp = Secp256k1::new();
237+
238+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
239+
let master = s.parse::<Xpriv>().unwrap();
240+
let master_fingerprint = master.fingerprint(&secp);
241+
242+
let child_number = ChildNumber::from_hardened_idx(44).unwrap();
243+
let child = master.derive_priv(&secp, &[child_number]).unwrap();
244+
245+
// Sanity check.
246+
{
247+
let descriptor_sk_s = format!("[{}/44']{}", master_fingerprint, child);
248+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
249+
let got = match descriptor_sk {
250+
DescriptorSecretKey::XPrv(ref x) => x.xkey,
251+
_ => panic!("unexpected DescriptorSecretKey variant"),
252+
};
253+
assert_eq!(got, child);
254+
}
255+
256+
let want_sk = child.to_priv();
257+
let descriptor_s = format!("wpkh({}/44')", s);
258+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
259+
260+
let pk = want_sk.public_key(&secp);
261+
let request = KeyRequest::Pubkey(pk);
262+
let got_sk = keymap
263+
.get_key(request, &secp)
264+
.expect("get_key call errored")
265+
.expect("failed to find the key");
266+
assert_eq!(got_sk, want_sk)
267+
}
268+
269+
#[test]
270+
fn get_key_xpriv_with_path() {
271+
let secp = Secp256k1::new();
272+
273+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
274+
let master = s.parse::<Xpriv>().unwrap();
275+
let master_fingerprint = master.fingerprint(&secp);
276+
277+
let first_external_child = "44'/0'/0'/0/0";
278+
let derivation_path = first_external_child.into_derivation_path().unwrap();
279+
280+
let child = master.derive_priv(&secp, &derivation_path).unwrap();
281+
282+
// Sanity check.
283+
{
284+
let descriptor_sk_s =
285+
format!("[{}/{}]{}", master_fingerprint, first_external_child, child);
286+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
287+
let got = match descriptor_sk {
288+
DescriptorSecretKey::XPrv(ref x) => x.xkey,
289+
_ => panic!("unexpected DescriptorSecretKey variant"),
290+
};
291+
assert_eq!(got, child);
292+
}
293+
294+
let want_sk = child.to_priv();
295+
let descriptor_s = format!("wpkh({}/44'/0'/0'/0/*)", s);
296+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
297+
298+
let key_source = (master_fingerprint, derivation_path);
299+
let request = KeyRequest::Bip32(key_source);
300+
let got_sk = keymap
301+
.get_key(request, &secp)
302+
.expect("get_key call errored")
303+
.expect("failed to find the key");
304+
305+
assert_eq!(got_sk, want_sk)
306+
}
307+
308+
#[test]
309+
fn get_key_xpriv_with_key_origin() {
310+
let secp = Secp256k1::new();
311+
312+
let descriptor_str = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)";
313+
let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(&secp, descriptor_str).unwrap();
314+
315+
let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*").unwrap();
316+
let xpriv = match descriptor_sk {
317+
DescriptorSecretKey::XPrv(descriptor_xkey) => descriptor_xkey,
318+
_ => unreachable!(),
319+
};
320+
321+
let path = DerivationPath::from_str("84'/1'/0'/0").unwrap();
322+
let expected_pk = xpriv.xkey.derive_priv(&secp, &path).unwrap().to_priv();
323+
324+
let (fp, _) = xpriv.origin.unwrap();
325+
let key_request = KeyRequest::Bip32((fp, path));
326+
327+
let pk = keymap
328+
.get_key(key_request, &secp)
329+
.expect("get_key should not fail")
330+
.expect("get_key should return a `PrivateKey`");
331+
332+
assert_eq!(pk, expected_pk);
333+
}
334+
}

0 commit comments

Comments
 (0)