@@ -22,26 +22,30 @@ pub mod slip77;
22
22
23
23
use std:: fmt;
24
24
25
+ use bitcoin:: bip32;
25
26
use elements:: secp256k1_zkp;
26
27
27
28
use 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
+ } ;
29
33
use crate :: expression:: FromTree ;
30
34
use crate :: extensions:: { CovExtArgs , CovenantExt , Extension , ParseableExt } ;
31
35
use crate :: { expression, Error , MiniscriptKey , ToPublicKey } ;
32
36
33
37
/// A description of a blinding key
34
38
#[ derive( Clone , PartialEq , Eq , Debug ) ]
35
- pub enum Key < Pk : MiniscriptKey > {
39
+ pub enum Key {
36
40
/// Blinding key is computed using SLIP77 with the given master key
37
41
Slip77 ( slip77:: MasterBlindingKey ) ,
38
42
/// Blinding key is given directly
39
- Bare ( Pk ) ,
43
+ Bare ( DescriptorPublicKey ) ,
40
44
/// Blinding key is given directly, as a secret key
41
45
View ( DescriptorSecretKey ) ,
42
46
}
43
47
44
- impl < Pk : MiniscriptKey > fmt:: Display for Key < Pk > {
48
+ impl fmt:: Display for Key {
45
49
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
46
50
match self {
47
51
Key :: Slip77 ( data) => write ! ( f, "slip77({})" , data) ,
@@ -51,16 +55,40 @@ impl<Pk: MiniscriptKey> fmt::Display for Key<Pk> {
51
55
}
52
56
}
53
57
54
- impl < Pk : MiniscriptKey + ToPublicKey > Key < Pk > {
58
+ impl Key {
55
59
fn to_public_key < C : secp256k1_zkp:: Signing + secp256k1_zkp:: Verification > (
56
60
& self ,
57
61
secp : & secp256k1_zkp:: Secp256k1 < C > ,
58
62
spk : & elements:: Script ,
59
- ) -> secp256k1_zkp:: PublicKey {
63
+ ) -> Result < secp256k1_zkp:: PublicKey , Error > {
60
64
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
+ } ,
64
92
}
65
93
}
66
94
}
@@ -69,7 +97,7 @@ impl<Pk: MiniscriptKey + ToPublicKey> Key<Pk> {
69
97
#[ derive( Clone , PartialEq , Eq , Debug ) ]
70
98
pub struct Descriptor < Pk : MiniscriptKey , T : Extension = CovenantExt < CovExtArgs > > {
71
99
/// The blinding key
72
- pub key : Key < Pk > ,
100
+ pub key : Key ,
73
101
/// The script descriptor
74
102
pub descriptor : crate :: Descriptor < Pk , T > ,
75
103
}
@@ -82,6 +110,51 @@ impl<Pk: MiniscriptKey, T: Extension> Descriptor<Pk, T> {
82
110
}
83
111
}
84
112
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
+
85
158
impl < Pk : MiniscriptKey + ToPublicKey , T : Extension + ParseableExt > Descriptor < Pk , T > {
86
159
/// Obtains the unblinded address for this descriptor.
87
160
pub fn unconfidential_address (
@@ -99,7 +172,7 @@ impl<Pk: MiniscriptKey + ToPublicKey, T: Extension + ParseableExt> Descriptor<Pk
99
172
) -> Result < elements:: Address , Error > {
100
173
let spk = self . descriptor . script_pubkey ( ) ;
101
174
self . descriptor
102
- . blinded_address ( self . key . to_public_key ( secp, & spk) , params)
175
+ . blinded_address ( self . key . to_public_key ( secp, & spk) ? , params)
103
176
}
104
177
}
105
178
@@ -137,7 +210,7 @@ impl_from_str!(
137
210
( "slip77" , _) => return Err ( Error :: BadDescriptor (
138
211
"slip77() must have exactly one argument" . to_owned( )
139
212
) ) ,
140
- _ => expression:: terminal( keyexpr, Pk :: from_str) . map( Key :: Bare )
213
+ _ => expression:: terminal( keyexpr, DescriptorPublicKey :: from_str) . map( Key :: Bare )
141
214
. or_else( |_| expression:: terminal( keyexpr, DescriptorSecretKey :: from_str) . map( Key :: View ) ) ?,
142
215
} ,
143
216
descriptor: crate :: Descriptor :: from_tree( & top. args[ 1 ] ) ?,
@@ -161,20 +234,20 @@ mod tests {
161
234
// taken from libwally src/test/test_confidential_addr.py
162
235
let mut addr = Address :: from_str ( "Q7qcjTLsYGoMA7TjUp97R6E6AM5VKqBik6" ) . unwrap ( ) ;
163
236
let key = Key :: Bare (
164
- bitcoin :: PublicKey :: from_str (
237
+ DescriptorPublicKey :: from_str (
165
238
"02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623" ,
166
239
)
167
240
. unwrap ( ) ,
168
241
) ;
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 ( ) ) ;
170
243
assert_eq ! (
171
244
addr. to_string( ) ,
172
245
"VTpt7krqRQPJwqe3XQXPg2cVdEKYVFbuprTr7es7pNRMe8mndnq2iYWddxJWYowhLAwoDF8QrZ1v2EXv"
173
246
) ;
174
247
}
175
248
176
249
struct ConfidentialTest {
177
- key : Key < DefiniteDescriptorKey > ,
250
+ key : Key ,
178
251
descriptor : crate :: Descriptor < DefiniteDescriptorKey , NoExt > ,
179
252
descriptor_str : String ,
180
253
conf_addr : & ' static str ,
@@ -231,7 +304,7 @@ mod tests {
231
304
let secp = secp256k1_zkp:: Secp256k1 :: new ( ) ;
232
305
233
306
// CT key used for bare keys
234
- let ct_key = DefiniteDescriptorKey :: from_str (
307
+ let ct_key = DescriptorPublicKey :: from_str (
235
308
"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" ,
236
309
)
237
310
. unwrap ( ) ;
@@ -370,7 +443,7 @@ mod tests {
370
443
let view_key = DescriptorSecretKey :: from_str (
371
444
"xprv9s21ZrQH143K28NgQ7bHCF61hy9VzwquBZvpzTwXLsbmQLRJ6iV9k2hUBRt5qzmBaSpeMj5LdcsHaXJvM7iFEivPryRcL8irN7Na9p65UUb" ,
372
445
) . 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 ( ) ;
374
447
let spk_key = DefiniteDescriptorKey :: from_str (
375
448
"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" ,
376
449
)
@@ -396,4 +469,38 @@ mod tests {
396
469
} ;
397
470
test. check ( & secp) ;
398
471
}
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
+ }
399
506
}
0 commit comments