Skip to content

Commit 4a3c350

Browse files
committed
Implement GetKey for KeyMap
Create a `KeyMay` type to replace the current `BTreeMap` alias and implement `bitcoin::psbt::GetKey` for it. Close: #709
1 parent ce42c66 commit 4a3c350

File tree

3 files changed

+344
-28
lines changed

3 files changed

+344
-28
lines changed

src/descriptor/key_map.rs

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! A map of public key to secret key.
4+
5+
use core::iter;
6+
7+
use bitcoin::psbt::{GetKey, GetKeyError, KeyRequest};
8+
use bitcoin::secp256k1::{Secp256k1, Signing};
9+
10+
#[cfg(doc)]
11+
use super::Descriptor;
12+
use super::{DescriptorKeyParseError, DescriptorPublicKey, DescriptorSecretKey, SinglePubKey};
13+
use crate::prelude::{btree_map, BTreeMap};
14+
15+
/// Alias type for a map of public key to secret key.
16+
///
17+
/// This map is returned whenever a descriptor that contains secrets is parsed using
18+
/// [`Descriptor::parse_descriptor`], since the descriptor will always only contain
19+
/// public keys. This map allows looking up the corresponding secret key given a
20+
/// public key from the descriptor.
21+
#[derive(Debug, Clone, Eq, PartialEq)]
22+
pub struct KeyMap {
23+
map: BTreeMap<DescriptorPublicKey, DescriptorSecretKey>,
24+
}
25+
26+
impl KeyMap {
27+
/// Creates a new empty `KeyMap`.
28+
#[inline]
29+
pub fn new() -> Self { Self { map: BTreeMap::new() } }
30+
31+
/// Inserts secret key into key map returning the associated public key.
32+
#[inline]
33+
pub fn insert<C: Signing>(
34+
&mut self,
35+
secp: &Secp256k1<C>,
36+
sk: DescriptorSecretKey,
37+
) -> Result<DescriptorPublicKey, DescriptorKeyParseError> {
38+
let pk = sk.to_public(secp)?;
39+
if !self.map.contains_key(&pk) {
40+
self.map.insert(pk.clone(), sk);
41+
}
42+
Ok(pk)
43+
}
44+
45+
/// Gets the secret key associated with `pk` if `pk` is in the map.
46+
#[inline]
47+
pub fn get(&self, pk: &DescriptorPublicKey) -> Option<&DescriptorSecretKey> { self.map.get(pk) }
48+
49+
/// Returns the number of items in this map.
50+
#[inline]
51+
pub fn len(&self) -> usize { self.map.len() }
52+
53+
/// Returns true if the map is empty.
54+
#[inline]
55+
pub fn is_empty(&self) -> bool { self.map.is_empty() }
56+
}
57+
58+
impl Default for KeyMap {
59+
fn default() -> Self { Self::new() }
60+
}
61+
62+
impl IntoIterator for KeyMap {
63+
type Item = (DescriptorPublicKey, DescriptorSecretKey);
64+
type IntoIter = btree_map::IntoIter<DescriptorPublicKey, DescriptorSecretKey>;
65+
66+
#[inline]
67+
fn into_iter(self) -> Self::IntoIter { self.map.into_iter() }
68+
}
69+
70+
impl iter::Extend<(DescriptorPublicKey, DescriptorSecretKey)> for KeyMap {
71+
#[inline]
72+
fn extend<T>(&mut self, iter: T)
73+
where
74+
T: IntoIterator<Item = (DescriptorPublicKey, DescriptorSecretKey)>,
75+
{
76+
self.map.extend(iter)
77+
}
78+
}
79+
80+
impl GetKey for KeyMap {
81+
type Error = GetKeyError;
82+
83+
fn get_key<C: Signing>(
84+
&self,
85+
key_request: KeyRequest,
86+
secp: &Secp256k1<C>,
87+
) -> Result<Option<bitcoin::PrivateKey>, Self::Error> {
88+
Ok(self.map.iter().find_map(|(k, v)| {
89+
match k {
90+
DescriptorPublicKey::Single(ref pk) => match key_request {
91+
KeyRequest::Pubkey(ref request) => match pk.key {
92+
SinglePubKey::FullKey(ref pk) => {
93+
if pk == request {
94+
match v {
95+
DescriptorSecretKey::Single(ref sk) => Some(sk.key),
96+
_ => unreachable!("Single maps to Single"),
97+
}
98+
} else {
99+
None
100+
}
101+
}
102+
SinglePubKey::XOnly(_) => None,
103+
},
104+
_ => None,
105+
},
106+
// Performance: Might be faster to check the origin and then if it matches return
107+
// the key directly instead of calling `get_key` on the xpriv.
108+
DescriptorPublicKey::XPub(ref xpub) => {
109+
let pk = xpub.xkey.public_key;
110+
match key_request {
111+
KeyRequest::Pubkey(ref request) => {
112+
if pk == request.inner {
113+
match v {
114+
DescriptorSecretKey::XPrv(xpriv) => {
115+
let xkey = xpriv.xkey;
116+
if let Ok(child) =
117+
xkey.derive_priv(secp, &xpriv.derivation_path)
118+
{
119+
Some(bitcoin::PrivateKey::new(
120+
child.private_key,
121+
xkey.network,
122+
))
123+
} else {
124+
None
125+
}
126+
}
127+
_ => unreachable!("XPrv maps to XPrv"),
128+
}
129+
} else {
130+
None
131+
}
132+
}
133+
KeyRequest::Bip32(..) => match v {
134+
DescriptorSecretKey::XPrv(xpriv) => {
135+
// This clone goes away in next release of rust-bitcoin.
136+
if let Ok(Some(sk)) = xpriv.xkey.get_key(key_request.clone(), secp)
137+
{
138+
Some(sk)
139+
} else {
140+
None
141+
}
142+
}
143+
_ => unreachable!("XPrv maps to XPrv"),
144+
},
145+
// TODO: Add support for lookup using XOnlyPublicKey
146+
// See https://github.com/rust-bitcoin/rust-bitcoin/pull/4238
147+
_ => None,
148+
}
149+
}
150+
DescriptorPublicKey::MultiXPub(ref xpub) => {
151+
let pk = xpub.xkey.public_key;
152+
match key_request {
153+
KeyRequest::Pubkey(ref request) => {
154+
if pk == request.inner {
155+
match v {
156+
DescriptorSecretKey::MultiXPrv(xpriv) => {
157+
Some(xpriv.xkey.to_priv())
158+
}
159+
_ => unreachable!("MultiXPrv maps to MultiXPrv"),
160+
}
161+
} else {
162+
None
163+
}
164+
}
165+
KeyRequest::Bip32(..) => match v {
166+
DescriptorSecretKey::MultiXPrv(xpriv) => {
167+
// These clones goes away in next release of rust-bitcoin.
168+
if let Ok(Some(sk)) = xpriv.xkey.get_key(key_request.clone(), secp)
169+
{
170+
Some(sk)
171+
} else {
172+
None
173+
}
174+
}
175+
_ => unreachable!("MultiXPrv maps to MultiXPrv"),
176+
},
177+
_ => unreachable!("rust-bitcoin v0.32"),
178+
}
179+
}
180+
}
181+
}))
182+
}
183+
}
184+
185+
#[cfg(test)]
186+
mod tests {
187+
// use bitcoin::NetworkKind;
188+
use bitcoin::bip32::{ChildNumber, IntoDerivationPath, Xpriv};
189+
190+
use super::*;
191+
use crate::Descriptor;
192+
193+
#[test]
194+
fn get_key_single_key() {
195+
let secp = Secp256k1::new();
196+
197+
let descriptor_sk_s =
198+
"[90b6a706/44'/0'/0'/0/0]cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij";
199+
200+
let single = match descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap() {
201+
DescriptorSecretKey::Single(single) => single,
202+
_ => panic!("unexpected DescriptorSecretKey variant"),
203+
};
204+
205+
let want_sk = single.key;
206+
let descriptor_s = format!("wpkh({})", descriptor_sk_s);
207+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
208+
209+
let pk = want_sk.public_key(&secp);
210+
let request = KeyRequest::Pubkey(pk);
211+
let got_sk = keymap
212+
.get_key(request, &secp)
213+
.expect("get_key call errored")
214+
.expect("failed to find the key");
215+
assert_eq!(got_sk, want_sk)
216+
}
217+
218+
#[test]
219+
fn get_key_xpriv_single_key_xpriv() {
220+
let secp = Secp256k1::new();
221+
222+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
223+
224+
let xpriv = s.parse::<Xpriv>().unwrap();
225+
let xpriv_fingerprint = xpriv.fingerprint(&secp);
226+
227+
// Sanity check.
228+
{
229+
let descriptor_sk_s = format!("[{}]{}", xpriv_fingerprint, xpriv);
230+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
231+
let got = match descriptor_sk {
232+
DescriptorSecretKey::XPrv(x) => x.xkey,
233+
_ => panic!("unexpected DescriptorSecretKey variant"),
234+
};
235+
assert_eq!(got, xpriv);
236+
}
237+
238+
let want_sk = xpriv.to_priv();
239+
let descriptor_s = format!("wpkh([{}]{})", xpriv_fingerprint, xpriv);
240+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
241+
242+
let pk = want_sk.public_key(&secp);
243+
let request = KeyRequest::Pubkey(pk);
244+
let got_sk = keymap
245+
.get_key(request, &secp)
246+
.expect("get_key call errored")
247+
.expect("failed to find the key");
248+
assert_eq!(got_sk, want_sk)
249+
}
250+
251+
#[test]
252+
fn get_key_xpriv_child_depth_one() {
253+
let secp = Secp256k1::new();
254+
255+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
256+
let master = s.parse::<Xpriv>().unwrap();
257+
let master_fingerprint = master.fingerprint(&secp);
258+
259+
let child_number = ChildNumber::from_hardened_idx(44).unwrap();
260+
let child = master.derive_priv(&secp, &[child_number]).unwrap();
261+
262+
// Sanity check.
263+
{
264+
let descriptor_sk_s = format!("[{}/44']{}", master_fingerprint, child);
265+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
266+
let got = match descriptor_sk {
267+
DescriptorSecretKey::XPrv(ref x) => x.xkey,
268+
_ => panic!("unexpected DescriptorSecretKey variant"),
269+
};
270+
assert_eq!(got, child);
271+
}
272+
273+
let want_sk = child.to_priv();
274+
let descriptor_s = format!("wpkh({}/44')", s);
275+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
276+
277+
let pk = want_sk.public_key(&secp);
278+
let request = KeyRequest::Pubkey(pk);
279+
let got_sk = keymap
280+
.get_key(request, &secp)
281+
.expect("get_key call errored")
282+
.expect("failed to find the key");
283+
assert_eq!(got_sk, want_sk)
284+
}
285+
286+
#[test]
287+
fn get_key_xpriv_with_path() {
288+
let secp = Secp256k1::new();
289+
290+
let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi";
291+
let master = s.parse::<Xpriv>().unwrap();
292+
let master_fingerprint = master.fingerprint(&secp);
293+
294+
let first_external_child = "44'/0'/0'/0/0";
295+
let derivation_path = first_external_child.into_derivation_path().unwrap();
296+
297+
let child = master.derive_priv(&secp, &derivation_path).unwrap();
298+
299+
// Sanity check.
300+
{
301+
let descriptor_sk_s =
302+
format!("[{}/{}]{}", master_fingerprint, first_external_child, child);
303+
let descriptor_sk = descriptor_sk_s.parse::<DescriptorSecretKey>().unwrap();
304+
let got = match descriptor_sk {
305+
DescriptorSecretKey::XPrv(ref x) => x.xkey,
306+
_ => panic!("unexpected DescriptorSecretKey variant"),
307+
};
308+
assert_eq!(got, child);
309+
}
310+
311+
let want_sk = child.to_priv();
312+
let descriptor_s = format!("wpkh({}/44'/0'/0'/0/*)", s);
313+
let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap();
314+
315+
let key_source = (master_fingerprint, derivation_path);
316+
let request = KeyRequest::Bip32(key_source);
317+
let got_sk = keymap
318+
.get_key(request, &secp)
319+
.expect("get_key call errored")
320+
.expect("failed to find the key");
321+
322+
assert_eq!(got_sk, want_sk)
323+
}
324+
}

src/descriptor/mod.rs

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +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
};
55-
56-
/// Alias type for a map of public key to secret key
57-
///
58-
/// This map is returned whenever a descriptor that contains secrets is parsed using
59-
/// [`Descriptor::parse_descriptor`], since the descriptor will always only contain
60-
/// public keys. This map allows looking up the corresponding secret key given a
61-
/// public key from the descriptor.
62-
pub type KeyMap = BTreeMap<DescriptorPublicKey, DescriptorSecretKey>;
56+
pub use self::key_map::KeyMap;
6357

6458
/// Script descriptor
6559
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -708,28 +702,24 @@ impl Descriptor<DescriptorPublicKey> {
708702
key_map: &mut KeyMap,
709703
secp: &secp256k1::Secp256k1<C>,
710704
) -> Result<DescriptorPublicKey, Error> {
711-
let (public_key, secret_key) = match DescriptorSecretKey::from_str(s) {
712-
Ok(sk) => (
713-
sk.to_public(secp)
714-
.map_err(|e| Error::Unexpected(e.to_string()))?,
715-
Some(sk),
716-
),
717-
Err(_) => (
705+
match DescriptorSecretKey::from_str(s) {
706+
Ok(sk) => {
707+
let pk = key_map
708+
.insert(secp, sk)
709+
.map_err(|e| Error::Unexpected(e.to_string()))?;
710+
Ok(pk)
711+
}
712+
Err(_) => {
718713
// try to parse as a public key if parsing as a secret key failed
719-
s.parse()
720-
.map_err(|e| Error::Parse(ParseError::box_from_str(e)))?,
721-
None,
722-
),
723-
};
724-
725-
if let Some(secret_key) = secret_key {
726-
key_map.insert(public_key.clone(), secret_key);
714+
let pk = s
715+
.parse()
716+
.map_err(|e| Error::Parse(ParseError::box_from_str(e)))?;
717+
Ok(pk)
718+
}
727719
}
728-
729-
Ok(public_key)
730720
}
731721

732-
let mut keymap_pk = KeyMapWrapper(BTreeMap::new(), secp);
722+
let mut keymap_pk = KeyMapWrapper(KeyMap::new(), secp);
733723

734724
struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1<C>);
735725

0 commit comments

Comments
 (0)