@@ -13,6 +13,7 @@ use core::fmt;
1313use core:: iter:: FusedIterator ;
1414
1515use hashes:: { hash_newtype, sha256t, sha256t_tag, HashEngine } ;
16+ use hex:: { FromHex , HexToBytesError } ;
1617use internals:: array:: ArrayExt ;
1718#[ allow( unused) ] // MSRV polyfill
1819use internals:: slice:: SliceExt ;
@@ -1198,6 +1199,12 @@ impl ControlBlock {
11981199
11991200 Ok ( ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch } )
12001201 }
1202+
1203+ /// Constructs a new [`ControlBlock`] from a hex string.
1204+ pub fn from_hex ( hex : & str ) -> Result < Self , TaprootError > {
1205+ let vec = Vec :: from_hex ( hex) . map_err ( TaprootError :: InvalidControlBlockHex ) ?;
1206+ ControlBlock :: decode ( vec. as_slice ( ) )
1207+ }
12011208}
12021209
12031210impl < B , K > ControlBlock < B , K > {
@@ -1514,6 +1521,8 @@ pub enum TaprootError {
15141521 InvalidControlBlockSize ( InvalidControlBlockSizeError ) ,
15151522 /// Invalid Taproot internal key.
15161523 InvalidInternalKey ( secp256k1:: Error ) ,
1524+ /// Invalid control block hex
1525+ InvalidControlBlockHex ( HexToBytesError ) ,
15171526 /// Empty Taproot tree.
15181527 EmptyTree ,
15191528}
@@ -1531,6 +1540,7 @@ impl fmt::Display for TaprootError {
15311540 InvalidMerkleTreeDepth ( ref e) => write_err ! ( f, "invalid Merkle tree depth" ; e) ,
15321541 InvalidTaprootLeafVersion ( ref e) => write_err ! ( f, "invalid Taproot leaf version" ; e) ,
15331542 InvalidControlBlockSize ( ref e) => write_err ! ( f, "invalid control block size" ; e) ,
1543+ InvalidControlBlockHex ( ref e) => write_err ! ( f, "invalid control block hex" ; e) ,
15341544 InvalidInternalKey ( ref e) => write_err ! ( f, "invalid internal x-only key" ; e) ,
15351545 EmptyTree => write ! ( f, "Taproot tree must contain at least one script" ) ,
15361546 }
@@ -1546,6 +1556,7 @@ impl std::error::Error for TaprootError {
15461556 InvalidInternalKey ( e) => Some ( e) ,
15471557 InvalidTaprootLeafVersion ( ref e) => Some ( e) ,
15481558 InvalidMerkleTreeDepth ( ref e) => Some ( e) ,
1559+ InvalidControlBlockHex ( ref e) => Some ( e) ,
15491560 InvalidMerkleBranchSize ( _) | InvalidControlBlockSize ( _) | EmptyTree => None ,
15501561 }
15511562 }
@@ -1670,7 +1681,7 @@ impl std::error::Error for InvalidControlBlockSizeError {}
16701681#[ cfg( test) ]
16711682mod test {
16721683 use hashes:: sha256;
1673- use hex:: { DisplayHex , FromHex } ;
1684+ use hex:: DisplayHex ;
16741685 use secp256k1:: VerifyOnly ;
16751686
16761687 use super :: * ;
@@ -1771,8 +1782,7 @@ mod test {
17711782 let out_pk = out_spk_hex[ 4 ..] . parse :: < XOnlyPublicKey > ( ) . unwrap ( ) ;
17721783 let out_pk = TweakedPublicKey :: dangerous_assume_tweaked ( out_pk) ;
17731784 let script = ScriptBuf :: from_hex ( script_hex) . unwrap ( ) ;
1774- let control_block =
1775- ControlBlock :: decode ( & Vec :: < u8 > :: from_hex ( control_block_hex) . unwrap ( ) ) . unwrap ( ) ;
1785+ let control_block = ControlBlock :: from_hex ( control_block_hex) . unwrap ( ) ;
17761786 assert_eq ! ( control_block_hex, control_block. serialize( ) . to_lower_hex_string( ) ) ;
17771787 assert ! ( control_block. verify_taproot_commitment( secp, out_pk. to_inner( ) , & script) ) ;
17781788 }
@@ -2053,10 +2063,8 @@ mod test {
20532063 let spend_info = builder. finalize ( secp, internal_key) . unwrap ( ) ;
20542064 for ( i, script_ver) in leaves. iter ( ) . enumerate ( ) {
20552065 let expected_leaf_hash = leaf_hashes[ i] . as_str ( ) . unwrap ( ) ;
2056- let expected_ctrl_blk = ControlBlock :: decode (
2057- & Vec :: < u8 > :: from_hex ( ctrl_blks[ i] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ,
2058- )
2059- . unwrap ( ) ;
2066+ let expected_ctrl_blk =
2067+ ControlBlock :: from_hex ( ctrl_blks[ i] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ;
20602068
20612069 let leaf_hash = TapLeafHash :: from_script ( & script_ver. 0 , script_ver. 1 ) ;
20622070 let ctrl_blk = spend_info. control_block ( script_ver) . unwrap ( ) ;
0 commit comments