19
19
20
20
use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d, Hash } ;
21
21
use std:: marker:: PhantomData ;
22
+ use std:: { error, fmt} ;
22
23
use { bitcoin, Miniscript } ;
23
24
24
25
use miniscript:: lex:: { Token as Tk , TokenIter } ;
@@ -34,6 +35,44 @@ fn return_none<T>(_: usize) -> Option<T> {
34
35
None
35
36
}
36
37
38
+ /// Trait for parsing keys from byte slices
39
+ pub trait ParseableKey : Sized {
40
+ /// Parse a key from slice
41
+ fn from_slice ( sl : & [ u8 ] ) -> Result < Self , KeyParseError > ;
42
+ }
43
+
44
+ /// Decoding error while parsing keys
45
+ #[ derive( Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
46
+ pub enum KeyParseError {
47
+ /// Bitcoin PublicKey parse error
48
+ FullKeyParseError ( bitcoin:: util:: key:: Error ) ,
49
+ /// Wrong Input Count
50
+ XonlyKeyParseError ( bitcoin:: secp256k1:: Error ) ,
51
+ }
52
+
53
+ impl ParseableKey for bitcoin:: PublicKey {
54
+ fn from_slice ( sl : & [ u8 ] ) -> Result < Self , KeyParseError > {
55
+ bitcoin:: PublicKey :: from_slice ( sl) . map_err ( KeyParseError :: FullKeyParseError )
56
+ }
57
+ }
58
+
59
+ impl ParseableKey for bitcoin:: schnorr:: PublicKey {
60
+ fn from_slice ( sl : & [ u8 ] ) -> Result < Self , KeyParseError > {
61
+ bitcoin:: schnorr:: PublicKey :: from_slice ( sl) . map_err ( KeyParseError :: XonlyKeyParseError )
62
+ }
63
+ }
64
+
65
+ impl error:: Error for KeyParseError { }
66
+
67
+ impl fmt:: Display for KeyParseError {
68
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
69
+ match self {
70
+ KeyParseError :: FullKeyParseError ( e) => write ! ( f, "FullKey Parse Error {}" , e) ,
71
+ KeyParseError :: XonlyKeyParseError ( e) => write ! ( f, "XonlyKey Parse Error {}" , e) ,
72
+ }
73
+ }
74
+ }
75
+
37
76
#[ derive( Copy , Clone , Debug ) ]
38
77
enum NonTerm {
39
78
Expression ,
@@ -214,11 +253,12 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> TerminalStack<Pk, Ctx> {
214
253
}
215
254
}
216
255
217
- /// Parse a script fragment into an `Terminal `
256
+ /// Parse a script fragment into an `Miniscript `
218
257
#[ allow( unreachable_patterns) ]
219
- pub fn parse < Ctx : ScriptContext > (
220
- tokens : & mut TokenIter ,
221
- ) -> Result < Miniscript < bitcoin:: PublicKey , Ctx > , Error > {
258
+ pub fn parse < Ctx : ScriptContext , Pk > ( tokens : & mut TokenIter ) -> Result < Miniscript < Pk , Ctx > , Error >
259
+ where
260
+ Pk : ParseableKey + MiniscriptKey < Hash = bitcoin:: hashes:: hash160:: Hash > ,
261
+ {
222
262
let mut non_term = Vec :: with_capacity ( tokens. len ( ) ) ;
223
263
let mut term = TerminalStack ( Vec :: with_capacity ( tokens. len ( ) ) ) ;
224
264
@@ -231,7 +271,23 @@ pub fn parse<Ctx: ScriptContext>(
231
271
match_token ! (
232
272
tokens,
233
273
// pubkey
234
- Tk :: Pubkey ( pk) => term. reduce0( Terminal :: PkK ( pk) ) ?,
274
+ Tk :: Bytes33 ( pk) => {
275
+ let ret = Pk :: from_slice( pk)
276
+ . map_err( |e| Error :: PubKeyCtxError ( e. to_string( ) , Ctx :: to_string( ) ) ) ?;
277
+ term. reduce0( Terminal :: PkK ( ret) ) ?
278
+ } ,
279
+ Tk :: Bytes65 ( pk) => {
280
+ let ret = Pk :: from_slice( pk)
281
+ . map_err( |e| Error :: PubKeyCtxError ( e. to_string( ) , Ctx :: to_string( ) ) ) ?;
282
+ term. reduce0( Terminal :: PkK ( ret) ) ?
283
+ } ,
284
+ // Note this does not collide with hash32 because they always followed by equal
285
+ // and would be parsed in different branch. If we get a naked Bytes32, it must be
286
+ // a x-only key
287
+ Tk :: Bytes32 ( pk) => {
288
+ let ret = Pk :: from_slice( pk) . map_err( |e| Error :: PubKeyCtxError ( e. to_string( ) , Ctx :: to_string( ) ) ) ?;
289
+ term. reduce0( Terminal :: PkK ( ret) ) ?
290
+ } ,
235
291
// checksig
236
292
Tk :: CheckSig => {
237
293
non_term. push( NonTerm :: Check ) ;
@@ -248,36 +304,36 @@ pub fn parse<Ctx: ScriptContext>(
248
304
tokens,
249
305
Tk :: Dup => {
250
306
term. reduce0( Terminal :: PkH (
251
- hash160:: Hash :: from_inner ( hash)
307
+ hash160:: Hash :: from_slice ( hash) . expect ( "valid size" )
252
308
) ) ?
253
309
} ,
254
310
Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
255
311
non_term. push( NonTerm :: Verify ) ;
256
312
term. reduce0( Terminal :: Hash160 (
257
- hash160:: Hash :: from_inner ( hash)
313
+ hash160:: Hash :: from_slice ( hash) . expect ( "valid size" )
258
314
) ) ?
259
315
} ,
260
316
) ,
261
317
Tk :: Ripemd160 , Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
262
318
non_term. push( NonTerm :: Verify ) ;
263
319
term. reduce0( Terminal :: Ripemd160 (
264
- ripemd160:: Hash :: from_inner ( hash)
320
+ ripemd160:: Hash :: from_slice ( hash) . expect ( "valid size" )
265
321
) ) ?
266
322
} ,
267
323
) ,
268
324
// Tk::Hash20(hash),
269
- Tk :: Hash32 ( hash) => match_token!(
325
+ Tk :: Bytes32 ( hash) => match_token!(
270
326
tokens,
271
327
Tk :: Sha256 , Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
272
328
non_term. push( NonTerm :: Verify ) ;
273
329
term. reduce0( Terminal :: Sha256 (
274
- sha256:: Hash :: from_inner ( hash)
330
+ sha256:: Hash :: from_slice ( hash) . expect ( "valid size" )
275
331
) ) ?
276
332
} ,
277
333
Tk :: Hash256 , Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
278
334
non_term. push( NonTerm :: Verify ) ;
279
335
term. reduce0( Terminal :: Hash256 (
280
- sha256d:: Hash :: from_inner ( hash)
336
+ sha256d:: Hash :: from_slice ( hash) . expect ( "valid size" )
281
337
) ) ?
282
338
} ,
283
339
) ,
@@ -307,21 +363,21 @@ pub fn parse<Ctx: ScriptContext>(
307
363
// hashlocks
308
364
Tk :: Equal => match_token!(
309
365
tokens,
310
- Tk :: Hash32 ( hash) => match_token!(
366
+ Tk :: Bytes32 ( hash) => match_token!(
311
367
tokens,
312
368
Tk :: Sha256 ,
313
369
Tk :: Verify ,
314
370
Tk :: Equal ,
315
371
Tk :: Num ( 32 ) ,
316
372
Tk :: Size => term. reduce0( Terminal :: Sha256 (
317
- sha256:: Hash :: from_inner ( hash)
373
+ sha256:: Hash :: from_slice ( hash) . expect ( "valid size" )
318
374
) ) ?,
319
375
Tk :: Hash256 ,
320
376
Tk :: Verify ,
321
377
Tk :: Equal ,
322
378
Tk :: Num ( 32 ) ,
323
379
Tk :: Size => term. reduce0( Terminal :: Hash256 (
324
- sha256d:: Hash :: from_inner ( hash)
380
+ sha256d:: Hash :: from_slice ( hash) . expect ( "valid size" )
325
381
) ) ?,
326
382
) ,
327
383
Tk :: Hash20 ( hash) => match_token!(
@@ -331,14 +387,14 @@ pub fn parse<Ctx: ScriptContext>(
331
387
Tk :: Equal ,
332
388
Tk :: Num ( 32 ) ,
333
389
Tk :: Size => term. reduce0( Terminal :: Ripemd160 (
334
- ripemd160:: Hash :: from_inner ( hash)
390
+ ripemd160:: Hash :: from_slice ( hash) . expect ( "valid size" )
335
391
) ) ?,
336
392
Tk :: Hash160 ,
337
393
Tk :: Verify ,
338
394
Tk :: Equal ,
339
395
Tk :: Num ( 32 ) ,
340
396
Tk :: Size => term. reduce0( Terminal :: Hash160 (
341
- hash160:: Hash :: from_inner ( hash)
397
+ hash160:: Hash :: from_slice ( hash) . expect ( "valid size" )
342
398
) ) ?,
343
399
) ,
344
400
// thresholds
@@ -390,7 +446,10 @@ pub fn parse<Ctx: ScriptContext>(
390
446
for _ in 0 ..n {
391
447
match_token!(
392
448
tokens,
393
- Tk :: Pubkey ( pk) => keys. push( pk) ,
449
+ Tk :: Bytes33 ( pk) => keys. push( <Pk >:: from_slice( pk)
450
+ . map_err( |e| Error :: PubKeyCtxError ( e. to_string( ) , Ctx :: to_string( ) ) ) ?) ,
451
+ Tk :: Bytes65 ( pk) => keys. push( <Pk >:: from_slice( pk)
452
+ . map_err( |e| Error :: PubKeyCtxError ( e. to_string( ) , Ctx :: to_string( ) ) ) ?) ,
394
453
) ;
395
454
}
396
455
let k = match_token!(
0 commit comments