@@ -77,10 +77,16 @@ pub enum Descriptor<Pk: MiniscriptKey> {
77
77
78
78
#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
79
79
pub enum DescriptorPublicKey {
80
- PukKey ( bitcoin :: PublicKey ) ,
80
+ ShortPub ( DescriptorShortPub ) ,
81
81
XPub ( DescriptorXPub ) ,
82
82
}
83
83
84
+ #[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
85
+ pub struct DescriptorShortPub {
86
+ origin : Option < ( bip32:: Fingerprint , bip32:: DerivationPath ) > ,
87
+ key : bitcoin:: PublicKey ,
88
+ }
89
+
84
90
#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Hash ) ]
85
91
pub struct DescriptorXPub {
86
92
origin : Option < ( bip32:: Fingerprint , bip32:: DerivationPath ) > ,
@@ -101,16 +107,13 @@ impl fmt::Display for DescriptorKeyParseError {
101
107
impl fmt:: Display for DescriptorPublicKey {
102
108
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
103
109
match * self {
104
- DescriptorPublicKey :: PukKey ( ref pk) => pk. fmt ( f) ,
110
+ DescriptorPublicKey :: ShortPub ( ref pk) => {
111
+ maybe_fmt_master_id ( f, & pk. origin ) ?;
112
+ pk. key . fmt ( f) ?;
113
+ Ok ( ( ) )
114
+ }
105
115
DescriptorPublicKey :: XPub ( ref xpub) => {
106
- if let Some ( ( ref master_id, ref master_deriv) ) = xpub. origin {
107
- fmt:: Formatter :: write_str ( f, "[" ) ?;
108
- for byte in master_id. into_bytes ( ) . iter ( ) {
109
- write ! ( f, "{:02x}" , byte) ?;
110
- }
111
- fmt_derivation_path ( f, master_deriv) ?;
112
- fmt:: Formatter :: write_str ( f, "]" ) ?;
113
- }
116
+ maybe_fmt_master_id ( f, & xpub. origin ) ?;
114
117
xpub. xpub . fmt ( f) ?;
115
118
fmt_derivation_path ( f, & xpub. derivation_path ) ?;
116
119
if xpub. is_wildcard {
@@ -122,6 +125,23 @@ impl fmt::Display for DescriptorPublicKey {
122
125
}
123
126
}
124
127
128
+ /// Writes the fingerprint of the origin, if there is one.
129
+ fn maybe_fmt_master_id (
130
+ f : & mut fmt:: Formatter ,
131
+ origin : & Option < ( bip32:: Fingerprint , bip32:: DerivationPath ) > ,
132
+ ) -> fmt:: Result {
133
+ if let Some ( ( ref master_id, ref master_deriv) ) = * origin {
134
+ fmt:: Formatter :: write_str ( f, "[" ) ?;
135
+ for byte in master_id. into_bytes ( ) . iter ( ) {
136
+ write ! ( f, "{:02x}" , byte) ?;
137
+ }
138
+ fmt_derivation_path ( f, master_deriv) ?;
139
+ fmt:: Formatter :: write_str ( f, "]" ) ?;
140
+ }
141
+
142
+ Ok ( ( ) )
143
+ }
144
+
125
145
/// Writes a derivation path to the formatter, no leading 'm'
126
146
fn fmt_derivation_path ( f : & mut fmt:: Formatter , path : & bip32:: DerivationPath ) -> fmt:: Result {
127
147
for child in path {
@@ -134,11 +154,16 @@ impl FromStr for DescriptorPublicKey {
134
154
type Err = DescriptorKeyParseError ;
135
155
136
156
fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
157
+ // A "raw" public key without any origin is the least we accept.
137
158
if s. len ( ) < 66 {
138
- Err ( DescriptorKeyParseError (
159
+ return Err ( DescriptorKeyParseError (
139
160
"Key too short (<66 char), doesn't match any format" ,
140
- ) )
141
- } else if s. chars ( ) . next ( ) . unwrap ( ) == '[' {
161
+ ) ) ;
162
+ }
163
+
164
+ // They may specify an origin
165
+ let mut origin = None ;
166
+ if s. chars ( ) . next ( ) . unwrap ( ) == '[' {
142
167
let mut parts = s[ 1 ..] . split ( ']' ) ;
143
168
let mut raw_origin = parts
144
169
. next ( )
@@ -165,30 +190,33 @@ impl FromStr for DescriptorPublicKey {
165
190
. map_err ( |_| {
166
191
DescriptorKeyParseError ( "Error while parsing master derivation path" )
167
192
} ) ?;
193
+ origin = Some ( ( parent_fingerprint, origin_path) ) ;
194
+ }
168
195
169
- let key_deriv = parts
170
- . next ( )
171
- . ok_or ( DescriptorKeyParseError ( "No key after origin." ) ) ?;
196
+ let key_part = if origin == None {
197
+ Ok ( s)
198
+ } else {
199
+ s. split ( ']' )
200
+ . collect :: < Vec < & str > > ( )
201
+ . pop ( )
202
+ . ok_or ( DescriptorKeyParseError ( "No key after origin." ) )
203
+ } ?;
172
204
173
- let ( xpub, derivation_path, is_wildcard) = Self :: parse_xpub_deriv ( key_deriv) ?;
205
+ if key_part. starts_with ( "xpub" ) {
206
+ let ( xpub, derivation_path, is_wildcard) = Self :: parse_xpub_deriv ( key_part) ?;
174
207
175
208
Ok ( DescriptorPublicKey :: XPub ( DescriptorXPub {
176
- origin : Some ( ( parent_fingerprint , origin_path ) ) ,
209
+ origin,
177
210
xpub,
178
211
derivation_path,
179
212
is_wildcard,
180
213
} ) )
181
- } else if s. starts_with ( "02" ) || s. starts_with ( "03" ) || s. starts_with ( "04" ) {
182
- let pk = bitcoin:: PublicKey :: from_str ( s)
183
- . map_err ( |_| DescriptorKeyParseError ( "Error while parsing simple public key" ) ) ?;
184
- Ok ( DescriptorPublicKey :: PukKey ( pk) )
185
214
} else {
186
- let ( xpub, derivation_path, is_wildcard) = Self :: parse_xpub_deriv ( s) ?;
187
- Ok ( DescriptorPublicKey :: XPub ( DescriptorXPub {
188
- origin : None ,
189
- xpub,
190
- derivation_path,
191
- is_wildcard,
215
+ let key = bitcoin:: PublicKey :: from_str ( key_part)
216
+ . map_err ( |_| DescriptorKeyParseError ( "Error while parsing simple public key" ) ) ?;
217
+ Ok ( DescriptorPublicKey :: ShortPub ( DescriptorShortPub {
218
+ key,
219
+ origin,
192
220
} ) )
193
221
}
194
222
}
@@ -238,10 +266,10 @@ impl DescriptorPublicKey {
238
266
///
239
267
/// Panics if derivation path contains a hardened child number
240
268
pub fn derive ( & self , path : & [ bip32:: ChildNumber ] ) -> DescriptorPublicKey {
241
- assert ! ( path. into_iter( ) . all( |c| c. is_normal( ) ) ) ;
269
+ debug_assert ! ( path. into_iter( ) . all( |c| c. is_normal( ) ) ) ;
242
270
243
271
match * self {
244
- DescriptorPublicKey :: PukKey ( ref pk) => DescriptorPublicKey :: PukKey ( * pk ) ,
272
+ DescriptorPublicKey :: ShortPub ( ref pk) => DescriptorPublicKey :: ShortPub ( pk . clone ( ) ) ,
245
273
DescriptorPublicKey :: XPub ( ref xpub) => {
246
274
if xpub. is_wildcard {
247
275
DescriptorPublicKey :: XPub ( DescriptorXPub {
@@ -267,7 +295,7 @@ impl MiniscriptKey for DescriptorPublicKey {
267
295
268
296
fn to_pubkeyhash ( & self ) -> Self :: Hash {
269
297
match * self {
270
- DescriptorPublicKey :: PukKey ( ref pk ) => pk . to_pubkeyhash ( ) ,
298
+ DescriptorPublicKey :: ShortPub ( ref spub ) => spub . key . to_pubkeyhash ( ) ,
271
299
DescriptorPublicKey :: XPub ( ref xpub) => {
272
300
let ctx = secp256k1:: Secp256k1 :: verification_only ( ) ;
273
301
xpub. xpub
@@ -283,7 +311,7 @@ impl MiniscriptKey for DescriptorPublicKey {
283
311
impl ToPublicKey for DescriptorPublicKey {
284
312
fn to_public_key ( & self ) -> bitcoin:: PublicKey {
285
313
match * self {
286
- DescriptorPublicKey :: PukKey ( ref pk ) => * pk ,
314
+ DescriptorPublicKey :: ShortPub ( ref spub ) => spub . key . to_public_key ( ) ,
287
315
DescriptorPublicKey :: XPub ( ref xpub) => {
288
316
let ctx = secp256k1:: Secp256k1 :: verification_only ( ) ;
289
317
xpub. xpub
@@ -804,7 +832,7 @@ mod tests {
804
832
use bitcoin:: hashes:: { hash160, sha256} ;
805
833
use bitcoin:: util:: bip32;
806
834
use bitcoin:: { self , secp256k1, PublicKey } ;
807
- use descriptor:: { DescriptorPublicKey , DescriptorXPub } ;
835
+ use descriptor:: { DescriptorPublicKey , DescriptorShortPub , DescriptorXPub } ;
808
836
use miniscript:: satisfy:: BitcoinSig ;
809
837
use policy;
810
838
use std:: collections:: HashMap ;
@@ -1368,37 +1396,52 @@ mod tests {
1368
1396
1369
1397
// Raw (compressed) pubkey
1370
1398
let key = "03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8" ;
1371
- let expected = DescriptorPublicKey :: PukKey (
1372
- bitcoin:: PublicKey :: from_str (
1399
+ let expected = DescriptorPublicKey :: ShortPub ( DescriptorShortPub {
1400
+ key : bitcoin:: PublicKey :: from_str (
1373
1401
"03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8" ,
1374
1402
)
1375
1403
. unwrap ( ) ,
1376
- ) ;
1404
+ origin : None ,
1405
+ } ) ;
1377
1406
assert_eq ! ( expected, key. parse( ) . unwrap( ) ) ;
1378
1407
assert_eq ! ( format!( "{}" , expected) , key) ;
1379
1408
1380
1409
// Raw (uncompressed) pubkey
1381
1410
let key = "04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a" ;
1382
- let expected = DescriptorPublicKey :: PukKey (
1383
- bitcoin:: PublicKey :: from_str (
1411
+ let expected = DescriptorPublicKey :: ShortPub ( DescriptorShortPub {
1412
+ key : bitcoin:: PublicKey :: from_str (
1384
1413
"04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a" ,
1385
1414
)
1386
1415
. unwrap ( ) ,
1387
- ) ;
1416
+ origin : None ,
1417
+ } ) ;
1388
1418
assert_eq ! ( expected, key. parse( ) . unwrap( ) ) ;
1389
1419
assert_eq ! ( format!( "{}" , expected) , key) ;
1420
+
1421
+ // Raw pubkey with origin
1422
+ let desc =
1423
+ "[78412e3a/0'/42/0']0231c7d3fc85c148717848033ce276ae2b464a4e2c367ed33886cc428b8af48ff8" ;
1424
+ let expected = DescriptorPublicKey :: ShortPub ( DescriptorShortPub {
1425
+ key : bitcoin:: PublicKey :: from_str (
1426
+ "0231c7d3fc85c148717848033ce276ae2b464a4e2c367ed33886cc428b8af48ff8" ,
1427
+ )
1428
+ . unwrap ( ) ,
1429
+ origin : Some ( (
1430
+ bip32:: Fingerprint :: from ( & [ 0x78 , 0x41 , 0x2e , 0x3a ] [ ..] ) ,
1431
+ ( & [
1432
+ bip32:: ChildNumber :: from_hardened_idx ( 0 ) . unwrap ( ) ,
1433
+ bip32:: ChildNumber :: from_normal_idx ( 42 ) . unwrap ( ) ,
1434
+ bip32:: ChildNumber :: from_hardened_idx ( 0 ) . unwrap ( ) ,
1435
+ ] [ ..] )
1436
+ . into ( ) ,
1437
+ ) ) ,
1438
+ } ) ;
1439
+ assert_eq ! ( expected, desc. parse( ) . expect( "Parsing desc" ) ) ;
1440
+ assert_eq ! ( format!( "{}" , expected) , desc) ;
1390
1441
}
1391
1442
1392
1443
#[ test]
1393
1444
fn parse_descriptor_key_errors ( ) {
1394
- // origin is only supported for xpubs
1395
- let desc =
1396
- "[78412e3a/0'/0'/0']0231c7d3fc85c148717848033ce276ae2b464a4e2c367ed33886cc428b8af48ff8" ;
1397
- assert_eq ! (
1398
- DescriptorPublicKey :: from_str( desc) ,
1399
- Err ( DescriptorKeyParseError ( "Error while parsing xpub." ) )
1400
- ) ;
1401
-
1402
1445
// We refuse creating descriptors which claim to be able to derive hardened childs
1403
1446
let desc = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/42'/*" ;
1404
1447
assert_eq ! (
@@ -1426,12 +1469,21 @@ mod tests {
1426
1469
) )
1427
1470
) ;
1428
1471
1429
- // And ones with invalid xpubs
1472
+ // And ones with invalid xpubs..
1430
1473
let desc = "[78412e3a]xpub1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaLcgJvLJuZZvRcEL/1/*" ;
1431
1474
assert_eq ! (
1432
1475
DescriptorPublicKey :: from_str( desc) ,
1433
1476
Err ( DescriptorKeyParseError ( "Error while parsing xpub." ) )
1434
1477
) ;
1478
+
1479
+ // ..or invalid raw keys
1480
+ let desc = "[78412e3a]0208a117f3897c3a13c9384b8695eed98dc31bc2500feb19a1af424cd47a5d83/1/*" ;
1481
+ assert_eq ! (
1482
+ DescriptorPublicKey :: from_str( desc) ,
1483
+ Err ( DescriptorKeyParseError (
1484
+ "Error while parsing simple public key"
1485
+ ) )
1486
+ ) ;
1435
1487
}
1436
1488
1437
1489
#[ test]
0 commit comments