@@ -22,26 +22,30 @@ pub mod slip77;
2222
2323use std:: fmt;
2424
25+ use bitcoin:: bip32;
2526use elements:: secp256k1_zkp;
2627
2728use crate :: descriptor:: checksum:: { desc_checksum, verify_checksum} ;
28- use crate :: descriptor:: DescriptorSecretKey ;
29+ use crate :: descriptor:: {
30+ ConversionError , DefiniteDescriptorKey , DescriptorSecretKey , DescriptorPublicKey ,
31+ DescriptorXKey , Wildcard
32+ } ;
2933use crate :: expression:: FromTree ;
3034use crate :: extensions:: { CovExtArgs , CovenantExt , Extension , ParseableExt } ;
3135use crate :: { expression, Error , MiniscriptKey , ToPublicKey } ;
3236
3337/// A description of a blinding key
3438#[ derive( Clone , PartialEq , Eq , Debug ) ]
35- pub enum Key < Pk : MiniscriptKey > {
39+ pub enum Key {
3640 /// Blinding key is computed using SLIP77 with the given master key
3741 Slip77 ( slip77:: MasterBlindingKey ) ,
3842 /// Blinding key is given directly
39- Bare ( Pk ) ,
43+ Bare ( DescriptorPublicKey ) ,
4044 /// Blinding key is given directly, as a secret key
4145 View ( DescriptorSecretKey ) ,
4246}
4347
44- impl < Pk : MiniscriptKey > fmt:: Display for Key < Pk > {
48+ impl fmt:: Display for Key {
4549 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
4650 match self {
4751 Key :: Slip77 ( data) => write ! ( f, "slip77({})" , data) ,
@@ -51,16 +55,40 @@ impl<Pk: MiniscriptKey> fmt::Display for Key<Pk> {
5155 }
5256}
5357
54- impl < Pk : MiniscriptKey + ToPublicKey > Key < Pk > {
58+ impl Key {
5559 fn to_public_key < C : secp256k1_zkp:: Signing + secp256k1_zkp:: Verification > (
5660 & self ,
5761 secp : & secp256k1_zkp:: Secp256k1 < C > ,
5862 spk : & elements:: Script ,
59- ) -> secp256k1_zkp:: PublicKey {
63+ ) -> Result < secp256k1_zkp:: PublicKey , Error > {
6064 match * self {
61- Key :: Slip77 ( ref mbk) => mbk. blinding_key ( secp, spk) ,
62- Key :: Bare ( ref pk) => bare:: tweak_key ( secp, spk, pk) ,
63- Key :: View ( ref sk) => bare:: tweak_key ( secp, spk, & sk. to_public ( secp) . expect ( "view keys cannot be multipath keys" ) . at_derivation_index ( 0 ) . expect ( "FIXME deal with derivation paths properly" ) ) ,
65+ Key :: Slip77 ( ref mbk) => Ok ( mbk. blinding_key ( secp, spk) ) ,
66+ Key :: Bare ( ref pk) => {
67+ if pk. is_multipath ( ) {
68+ Err ( Error :: Unexpected ( "multipath blinding key" . into ( ) ) )
69+ } else if pk. has_wildcard ( ) {
70+ Err ( Error :: Unexpected ( "wildcard blinding key" . into ( ) ) )
71+ } else {
72+ // Convert into a DefiniteDescriptorKey, note that we are deriving the xpub
73+ // since there is not wildcard.
74+ // Consider adding DescriptorPublicKey::to_definite_descriptor
75+ let pk = pk. clone ( ) . at_derivation_index ( 0 ) . expect ( "single or xpub without wildcards" ) ;
76+ Ok ( bare:: tweak_key ( secp, spk, & pk) )
77+ }
78+ } ,
79+ Key :: View ( ref sk) => {
80+ if sk. is_multipath ( ) {
81+ Err ( Error :: Unexpected ( "multipath blinding key" . into ( ) ) )
82+ } else {
83+ let pk = sk. to_public ( secp) . expect ( "single or xprv" ) ;
84+ if pk. has_wildcard ( ) {
85+ Err ( Error :: Unexpected ( "wildcard blinding key" . into ( ) ) )
86+ } else {
87+ let pk = pk. at_derivation_index ( 0 ) . expect ( "single or xprv without wildcards" ) ;
88+ Ok ( bare:: tweak_key ( secp, spk, & pk) )
89+ }
90+ }
91+ } ,
6492 }
6593 }
6694}
@@ -69,7 +97,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Key<Pk> {
6997#[ derive( Clone , PartialEq , Eq , Debug ) ]
7098pub struct Descriptor < Pk : MiniscriptKey , T : Extension = CovenantExt < CovExtArgs > > {
7199 /// The blinding key
72- pub key : Key < Pk > ,
100+ pub key : Key ,
73101 /// The script descriptor
74102 pub descriptor : crate :: Descriptor < Pk , T > ,
75103}
@@ -82,6 +110,51 @@ impl<Pk: MiniscriptKey, T: Extension> Descriptor<Pk, T> {
82110 }
83111}
84112
113+ impl < T : Extension + ParseableExt > Descriptor < DescriptorPublicKey , T > {
114+ /// Replaces all wildcards (i.e. `/*`) in the descriptor and the descriptor blinding key
115+ /// with a particular derivation index, turning it into a *definite* descriptor.
116+ ///
117+ /// # Errors
118+ /// - If index ≥ 2^31
119+ pub fn at_derivation_index ( & self , index : u32 ) -> Result < Descriptor < DefiniteDescriptorKey , T > , ConversionError > {
120+ let definite_key = match self . key . clone ( ) {
121+ Key :: Slip77 ( k) => Key :: Slip77 ( k) ,
122+ Key :: Bare ( k) => Key :: Bare ( k. at_derivation_index ( index) ?. into_descriptor_public_key ( ) ) ,
123+ Key :: View ( k) => Key :: View ( match k {
124+ // Consider implementing DescriptorSecretKey::at_derivation_index
125+ DescriptorSecretKey :: Single ( _) => k,
126+ DescriptorSecretKey :: XPrv ( xprv) => {
127+ let derivation_path = match xprv. wildcard {
128+ Wildcard :: None => xprv. derivation_path ,
129+ Wildcard :: Unhardened => xprv. derivation_path . into_child (
130+ bip32:: ChildNumber :: from_normal_idx ( index)
131+ . ok ( )
132+ . ok_or ( ConversionError :: HardenedChild ) ?,
133+ ) ,
134+ Wildcard :: Hardened => xprv. derivation_path . into_child (
135+ bip32:: ChildNumber :: from_hardened_idx ( index)
136+ . ok ( )
137+ . ok_or ( ConversionError :: HardenedChild ) ?,
138+ ) ,
139+ } ;
140+ DescriptorSecretKey :: XPrv ( DescriptorXKey {
141+ origin : xprv. origin ,
142+ xkey : xprv. xkey ,
143+ derivation_path,
144+ wildcard : Wildcard :: None ,
145+ } )
146+ } ,
147+ DescriptorSecretKey :: MultiXPrv ( _) => return Err ( ConversionError :: MultiKey ) ,
148+ } ) ,
149+ } ;
150+ let definite_descriptor = self . descriptor . at_derivation_index ( index) ?;
151+ Ok ( Descriptor {
152+ key : definite_key,
153+ descriptor : definite_descriptor,
154+ } )
155+ }
156+ }
157+
85158impl < Pk : MiniscriptKey + ToPublicKey , T : Extension + ParseableExt > Descriptor < Pk , T > {
86159 /// Obtains the unblinded address for this descriptor.
87160 pub fn unconfidential_address (
@@ -99,7 +172,7 @@ impl<Pk: MiniscriptKey + ToPublicKey, T: Extension + ParseableExt> Descriptor<Pk
99172 ) -> Result < elements:: Address , Error > {
100173 let spk = self . descriptor . script_pubkey ( ) ;
101174 self . descriptor
102- . blinded_address ( self . key . to_public_key ( secp, & spk) , params)
175+ . blinded_address ( self . key . to_public_key ( secp, & spk) ? , params)
103176 }
104177}
105178
@@ -137,7 +210,7 @@ impl_from_str!(
137210 ( "slip77" , _) => return Err ( Error :: BadDescriptor (
138211 "slip77() must have exactly one argument" . to_owned( )
139212 ) ) ,
140- _ => expression:: terminal( keyexpr, Pk :: from_str) . map( Key :: Bare )
213+ _ => expression:: terminal( keyexpr, DescriptorPublicKey :: from_str) . map( Key :: Bare )
141214 . or_else( |_| expression:: terminal( keyexpr, DescriptorSecretKey :: from_str) . map( Key :: View ) ) ?,
142215 } ,
143216 descriptor: crate :: Descriptor :: from_tree( & top. args[ 1 ] ) ?,
@@ -161,20 +234,20 @@ mod tests {
161234 // taken from libwally src/test/test_confidential_addr.py
162235 let mut addr = Address :: from_str ( "Q7qcjTLsYGoMA7TjUp97R6E6AM5VKqBik6" ) . unwrap ( ) ;
163236 let key = Key :: Bare (
164- bitcoin :: PublicKey :: from_str (
237+ DescriptorPublicKey :: from_str (
165238 "02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623" ,
166239 )
167240 . unwrap ( ) ,
168241 ) ;
169- addr. blinding_pubkey = Some ( key. to_public_key ( & secp, & addr. script_pubkey ( ) ) ) ;
242+ addr. blinding_pubkey = Some ( key. to_public_key ( & secp, & addr. script_pubkey ( ) ) . unwrap ( ) ) ;
170243 assert_eq ! (
171244 addr. to_string( ) ,
172245 "VTpt7krqRQPJwqe3XQXPg2cVdEKYVFbuprTr7es7pNRMe8mndnq2iYWddxJWYowhLAwoDF8QrZ1v2EXv"
173246 ) ;
174247 }
175248
176249 struct ConfidentialTest {
177- key : Key < DefiniteDescriptorKey > ,
250+ key : Key ,
178251 descriptor : crate :: Descriptor < DefiniteDescriptorKey , NoExt > ,
179252 descriptor_str : String ,
180253 conf_addr : & ' static str ,
@@ -231,7 +304,7 @@ mod tests {
231304 let secp = secp256k1_zkp:: Secp256k1 :: new ( ) ;
232305
233306 // CT key used for bare keys
234- let ct_key = DefiniteDescriptorKey :: from_str (
307+ let ct_key = DescriptorPublicKey :: from_str (
235308 "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" ,
236309 )
237310 . unwrap ( ) ;
@@ -370,7 +443,7 @@ mod tests {
370443 let view_key = DescriptorSecretKey :: from_str (
371444 "xprv9s21ZrQH143K28NgQ7bHCF61hy9VzwquBZvpzTwXLsbmQLRJ6iV9k2hUBRt5qzmBaSpeMj5LdcsHaXJvM7iFEivPryRcL8irN7Na9p65UUb" ,
372445 ) . unwrap ( ) ;
373- let ct_key = view_key. to_public ( & secp) . unwrap ( ) . at_derivation_index ( 0 ) . unwrap ( ) ; // FIXME figure out derivation
446+ let ct_key = view_key. to_public ( & secp) . unwrap ( ) ;
374447 let spk_key = DefiniteDescriptorKey :: from_str (
375448 "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" ,
376449 )
@@ -396,4 +469,38 @@ mod tests {
396469 } ;
397470 test. check ( & secp) ;
398471 }
472+
473+ #[ test]
474+ fn descriptor_wildcard ( ) {
475+ let secp = secp256k1_zkp:: Secp256k1 :: new ( ) ;
476+ let params = & elements:: AddressParams :: ELEMENTS ;
477+
478+ let xprv = "xprv9s21ZrQH143K28NgQ7bHCF61hy9VzwquBZvpzTwXLsbmQLRJ6iV9k2hUBRt5qzmBaSpeMj5LdcsHaXJvM7iFEivPryRcL8irN7Na9p65UUb" ;
479+ let xpub = "xpub661MyMwAqRbcEcT9W98HZP2kFzyzQQZkYnrRnrM8uD8kH8kSeFoQHq1x2iihLgC6PXGy5LrjCL66uSNhJ8pwjfx2rMUTLWuRMns2EG9xnjs" ;
480+ let desc_view_str = format ! ( "ct({}/*,elwpkh({}/*))#wk8ltq6h" , xprv, xpub) ;
481+ let desc_bare_str = format ! ( "ct({}/*,elwpkh({}/*))#zzac2dpf" , xpub, xpub) ;
482+ let index = 1 ;
483+ let conf_addr = "el1qqf6690fpw2y00hv5a84zsydjgztg2089d5xnll4k4cstzn63uvgudd907qpvlvvwd5ym9gx7j0v46elf23kfxunucm6ejjyk0" ;
484+ let unconf_addr = "ert1qkjhlqqk0kx8x6zdj5r0f8k2avl54gmyn7qjk2k" ;
485+
486+ let desc_view = Descriptor :: < DescriptorPublicKey > :: from_str ( & desc_view_str) . unwrap ( ) ;
487+ let desc_bare = Descriptor :: < DescriptorPublicKey > :: from_str ( & desc_bare_str) . unwrap ( ) ;
488+ let definite_desc_view = desc_view. at_derivation_index ( index) . unwrap ( ) ;
489+ let definite_desc_bare = desc_bare. at_derivation_index ( index) . unwrap ( ) ;
490+ assert_eq ! ( definite_desc_view. address( & secp, params) . unwrap( ) . to_string( ) , conf_addr. to_string( ) ) ;
491+ assert_eq ! ( definite_desc_bare. address( & secp, params) . unwrap( ) . to_string( ) , conf_addr. to_string( ) ) ;
492+ assert_eq ! ( definite_desc_view. unconfidential_address( params) . unwrap( ) . to_string( ) , unconf_addr. to_string( ) ) ;
493+ assert_eq ! ( definite_desc_bare. unconfidential_address( params) . unwrap( ) . to_string( ) , unconf_addr. to_string( ) ) ;
494+
495+ // It's not possible to get an address if the blinding key has a wildcard,
496+ // because the descriptor blinding key is not *definite*,
497+ // but we can't enforce this with the Descriptor generic.
498+ let desc_view_str = format ! ( "ct({}/*,elwpkh({}))#ls6mx2ac" , xprv, xpub) ;
499+ let desc_view = Descriptor :: < DefiniteDescriptorKey > :: from_str ( & desc_view_str) . unwrap ( ) ;
500+ assert_eq ! ( desc_view. address( & secp, params) . unwrap_err( ) , Error :: Unexpected ( "wildcard blinding key" . into( ) ) ) ;
501+
502+ let desc_bare_str = format ! ( "ct({}/*,elwpkh({}))#czkz0hwn" , xpub, xpub) ;
503+ let desc_bare = Descriptor :: < DefiniteDescriptorKey > :: from_str ( & desc_bare_str) . unwrap ( ) ;
504+ assert_eq ! ( desc_bare. address( & secp, params) . unwrap_err( ) , Error :: Unexpected ( "wildcard blinding key" . into( ) ) ) ;
505+ }
399506}
0 commit comments