1919
2020use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d, Hash } ;
2121use std:: marker:: PhantomData ;
22+ use std:: { error, fmt} ;
2223use { bitcoin, Miniscript } ;
2324
2425use miniscript:: lex:: { Token as Tk , TokenIter } ;
@@ -34,6 +35,44 @@ fn return_none<T>(_: usize) -> Option<T> {
3435 None
3536}
3637
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+
3776#[ derive( Copy , Clone , Debug ) ]
3877enum NonTerm {
3978 Expression ,
@@ -214,11 +253,12 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> TerminalStack<Pk, Ctx> {
214253 }
215254}
216255
217- /// Parse a script fragment into an `Terminal `
256+ /// Parse a script fragment into an `Miniscript `
218257#[ 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+ {
222262 let mut non_term = Vec :: with_capacity ( tokens. len ( ) ) ;
223263 let mut term = TerminalStack ( Vec :: with_capacity ( tokens. len ( ) ) ) ;
224264
@@ -231,7 +271,23 @@ pub fn parse<Ctx: ScriptContext>(
231271 match_token ! (
232272 tokens,
233273 // 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+ } ,
235291 // checksig
236292 Tk :: CheckSig => {
237293 non_term. push( NonTerm :: Check ) ;
@@ -248,36 +304,36 @@ pub fn parse<Ctx: ScriptContext>(
248304 tokens,
249305 Tk :: Dup => {
250306 term. reduce0( Terminal :: PkH (
251- hash160:: Hash :: from_inner ( hash)
307+ hash160:: Hash :: from_slice ( hash) . expect ( "valid size" )
252308 ) ) ?
253309 } ,
254310 Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
255311 non_term. push( NonTerm :: Verify ) ;
256312 term. reduce0( Terminal :: Hash160 (
257- hash160:: Hash :: from_inner ( hash)
313+ hash160:: Hash :: from_slice ( hash) . expect ( "valid size" )
258314 ) ) ?
259315 } ,
260316 ) ,
261317 Tk :: Ripemd160 , Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
262318 non_term. push( NonTerm :: Verify ) ;
263319 term. reduce0( Terminal :: Ripemd160 (
264- ripemd160:: Hash :: from_inner ( hash)
320+ ripemd160:: Hash :: from_slice ( hash) . expect ( "valid size" )
265321 ) ) ?
266322 } ,
267323 ) ,
268324 // Tk::Hash20(hash),
269- Tk :: Hash32 ( hash) => match_token!(
325+ Tk :: Bytes32 ( hash) => match_token!(
270326 tokens,
271327 Tk :: Sha256 , Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
272328 non_term. push( NonTerm :: Verify ) ;
273329 term. reduce0( Terminal :: Sha256 (
274- sha256:: Hash :: from_inner ( hash)
330+ sha256:: Hash :: from_slice ( hash) . expect ( "valid size" )
275331 ) ) ?
276332 } ,
277333 Tk :: Hash256 , Tk :: Verify , Tk :: Equal , Tk :: Num ( 32 ) , Tk :: Size => {
278334 non_term. push( NonTerm :: Verify ) ;
279335 term. reduce0( Terminal :: Hash256 (
280- sha256d:: Hash :: from_inner ( hash)
336+ sha256d:: Hash :: from_slice ( hash) . expect ( "valid size" )
281337 ) ) ?
282338 } ,
283339 ) ,
@@ -307,21 +363,21 @@ pub fn parse<Ctx: ScriptContext>(
307363 // hashlocks
308364 Tk :: Equal => match_token!(
309365 tokens,
310- Tk :: Hash32 ( hash) => match_token!(
366+ Tk :: Bytes32 ( hash) => match_token!(
311367 tokens,
312368 Tk :: Sha256 ,
313369 Tk :: Verify ,
314370 Tk :: Equal ,
315371 Tk :: Num ( 32 ) ,
316372 Tk :: Size => term. reduce0( Terminal :: Sha256 (
317- sha256:: Hash :: from_inner ( hash)
373+ sha256:: Hash :: from_slice ( hash) . expect ( "valid size" )
318374 ) ) ?,
319375 Tk :: Hash256 ,
320376 Tk :: Verify ,
321377 Tk :: Equal ,
322378 Tk :: Num ( 32 ) ,
323379 Tk :: Size => term. reduce0( Terminal :: Hash256 (
324- sha256d:: Hash :: from_inner ( hash)
380+ sha256d:: Hash :: from_slice ( hash) . expect ( "valid size" )
325381 ) ) ?,
326382 ) ,
327383 Tk :: Hash20 ( hash) => match_token!(
@@ -331,14 +387,14 @@ pub fn parse<Ctx: ScriptContext>(
331387 Tk :: Equal ,
332388 Tk :: Num ( 32 ) ,
333389 Tk :: Size => term. reduce0( Terminal :: Ripemd160 (
334- ripemd160:: Hash :: from_inner ( hash)
390+ ripemd160:: Hash :: from_slice ( hash) . expect ( "valid size" )
335391 ) ) ?,
336392 Tk :: Hash160 ,
337393 Tk :: Verify ,
338394 Tk :: Equal ,
339395 Tk :: Num ( 32 ) ,
340396 Tk :: Size => term. reduce0( Terminal :: Hash160 (
341- hash160:: Hash :: from_inner ( hash)
397+ hash160:: Hash :: from_slice ( hash) . expect ( "valid size" )
342398 ) ) ?,
343399 ) ,
344400 // thresholds
@@ -390,7 +446,10 @@ pub fn parse<Ctx: ScriptContext>(
390446 for _ in 0 ..n {
391447 match_token!(
392448 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( ) ) ) ?) ,
394453 ) ;
395454 }
396455 let k = match_token!(
0 commit comments