Skip to content

Commit 0a2d69d

Browse files
committed
Merge #99: Add translate_pk method for ConfidentialDescriptor
d12cf6c Add translate_pk method to confidential descriptors (Velnbur) Pull request description: The reasoning behind this PR is a small enhancement in developer experience. `miniscript::Descriptor` has [`translate_pk`](https://docs.rs/miniscript/latest/miniscript/descriptor/enum.Descriptor.html#method.translate_pk) method, but [`ConfidentialDescriptor`](https://docs.rs/elements-miniscript/latest/elements_miniscript/confidential/struct.Descriptor.html) does not. Because of this, to translate the inner descriptor, the user needs to extract it and then move the key: ```rust let conf_descriptor = ConfidentialDescriptor::<DescriptorPublicKey>::from_str(&descriptor_str).unwrap(); let definite_desc = conf_descriptor .descriptor .translate_pk(&mut translator) .unwrap(); let definite_conf_descriptor = ConfidentialDescriptor { descriptor: definite_desc, key: conf_descriptor.key, }; definite_conf_descriptor.address(SECP256K1, &AddressParams::LIQUID) ``` When in `miniscript`, this can be done with method chain calls: ```rust let descriptor = Descriptor::<DescriptorPublicKey>::from_str(&wallet.descriptor).unwrap(); descriptor .translate_pk(&mut translator) .unwrap() .address(Network::Bitcoin) ``` ACKs for top commit: apoelstra: ACK d12cf6c; successfully ran local tests; yeah, this seems useful, though I wish we had a more elegant way to treat blinding keys like descriptor keys Tree-SHA512: eba5e5219332b2faf55acfe3eb774ea280234ec842c1abdac2b417d264363710fd79ddbb8b6b863cce4e576067f005a1eaf39edc8102c9f33d8d7ee94d228d2b
2 parents 8a1ccd9 + d12cf6c commit 0a2d69d

2 files changed

Lines changed: 68 additions & 2 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Example: using translate_pk on a confidential descriptor to go from wildcard
2+
// DescriptorPublicKey keys to concrete DefiniteDescriptorKey keys at a given
3+
// derivation index, then derive a confidential address.
4+
5+
extern crate elements_miniscript as miniscript;
6+
7+
use std::str::FromStr;
8+
9+
use miniscript::{
10+
confidential, translate_hash_clone, DefiniteDescriptorKey, DescriptorPublicKey, NoExt,
11+
Translator,
12+
};
13+
14+
struct IndexTranslator(u32);
15+
16+
impl Translator<DescriptorPublicKey, DefiniteDescriptorKey, ()> for IndexTranslator {
17+
fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<DefiniteDescriptorKey, ()> {
18+
pk.clone().at_derivation_index(self.0).map_err(|_| ())
19+
}
20+
21+
translate_hash_clone!(DescriptorPublicKey, DefiniteDescriptorKey, ());
22+
}
23+
24+
fn main() {
25+
let secp = elements::secp256k1_zkp::Secp256k1::new();
26+
27+
// Confidential descriptor: SLIP77 blinding key + wildcard P2WPKH spend key.
28+
let desc_str = "ct(\
29+
slip77(b2396b3ee20509cdb64fe24180a14a72dbd671728eaa49bac69d2bdecb5f5a04),\
30+
elwpkh(xpub661MyMwAqRbcEcT9W98HZP2kFzyzQQZkYnrRnrM8uD8kH8kSeFoQHq1x2iihLg\
31+
C6PXGy5LrjCL66uSNhJ8pwjfx2rMUTLWuRMns2EG9xnjs/*))";
32+
33+
let desc = confidential::Descriptor::<DescriptorPublicKey, NoExt>::from_str(desc_str).unwrap();
34+
35+
for index in 0..3 {
36+
let definite: confidential::Descriptor<DefiniteDescriptorKey, NoExt> =
37+
desc.translate_pk(&mut IndexTranslator(index)).unwrap();
38+
39+
let conf_addr = definite
40+
.address(&secp, &elements::AddressParams::LIQUID)
41+
.unwrap();
42+
let unconf_addr = definite
43+
.unconfidential_address(&elements::AddressParams::LIQUID)
44+
.unwrap();
45+
46+
println!("index {index}:");
47+
println!(" confidential: {conf_addr}");
48+
println!(" unconfidential: {unconf_addr}");
49+
}
50+
}

src/confidential/mod.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::descriptor::{
3333
};
3434
use crate::expression::FromTree;
3535
use crate::extensions::{CovExtArgs, CovenantExt, Extension, ParseableExt};
36-
use crate::{expression, Error, MiniscriptKey, ToPublicKey};
36+
use crate::{expression, Error, MiniscriptKey, ToPublicKey, TranslatePk, Translator};
3737

3838
/// A description of a blinding key
3939
#[derive(Clone, PartialEq, Eq, Debug)]
@@ -166,6 +166,23 @@ impl<T: Extension + ParseableExt> Descriptor<DescriptorPublicKey, T> {
166166
}
167167
}
168168

169+
impl<Pk: MiniscriptKey, Ext: Extension> Descriptor<Pk, Ext> {
170+
/// Converts a descriptor using one kind of keys to another kind of key.
171+
///
172+
/// The blinding [`Key`] is preserved as-is; only the inner script descriptor's
173+
/// keys are translated via the supplied [`Translator`].
174+
pub fn translate_pk<Q, E, Tr>(&self, t: &mut Tr) -> Result<Descriptor<Q, Ext>, E>
175+
where
176+
Q: MiniscriptKey,
177+
Tr: Translator<Pk, Q, E>,
178+
{
179+
Ok(Descriptor {
180+
key: self.key.clone(),
181+
descriptor: self.descriptor.translate_pk(t)?,
182+
})
183+
}
184+
}
185+
169186
impl<Pk: MiniscriptKey + ToPublicKey, T: Extension + ParseableExt> Descriptor<Pk, T> {
170187
/// Obtains the unblinded address for this descriptor.
171188
pub fn unconfidential_address(
@@ -330,7 +347,6 @@ mod tests {
330347
)
331348
.unwrap();
332349

333-
334350
let single_ct_key = DescriptorPublicKey::from_str(
335351
"02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623",
336352
)

0 commit comments

Comments
 (0)