@@ -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 ;
@@ -1180,6 +1181,12 @@ impl ControlBlock {
11801181
11811182 Ok ( ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch } )
11821183 }
1184+
1185+ /// Constructs a new [`ControlBlock`] from a hex string.
1186+ pub fn from_hex ( hex : & str ) -> Result < Self , TaprootError > {
1187+ let vec = Vec :: from_hex ( hex) . map_err ( TaprootError :: InvalidControlBlockHex ) ?;
1188+ ControlBlock :: decode ( vec. as_slice ( ) )
1189+ }
11831190}
11841191
11851192impl < B , K > ControlBlock < B , K > {
@@ -1496,6 +1503,8 @@ pub enum TaprootError {
14961503 InvalidControlBlockSize ( InvalidControlBlockSizeError ) ,
14971504 /// Invalid Taproot internal key.
14981505 InvalidInternalKey ( secp256k1:: Error ) ,
1506+ /// Invalid control block hex
1507+ InvalidControlBlockHex ( HexToBytesError ) ,
14991508 /// Empty Taproot tree.
15001509 EmptyTree ,
15011510}
@@ -1513,6 +1522,7 @@ impl fmt::Display for TaprootError {
15131522 InvalidMerkleTreeDepth ( ref e) => write_err ! ( f, "invalid Merkle tree depth" ; e) ,
15141523 InvalidTaprootLeafVersion ( ref e) => write_err ! ( f, "invalid Taproot leaf version" ; e) ,
15151524 InvalidControlBlockSize ( ref e) => write_err ! ( f, "invalid control block size" ; e) ,
1525+ InvalidControlBlockHex ( ref e) => write_err ! ( f, "invalid control block hex" ; e) ,
15161526 InvalidInternalKey ( ref e) => write_err ! ( f, "invalid internal x-only key" ; e) ,
15171527 EmptyTree => write ! ( f, "Taproot tree must contain at least one script" ) ,
15181528 }
@@ -1528,6 +1538,7 @@ impl std::error::Error for TaprootError {
15281538 InvalidInternalKey ( e) => Some ( e) ,
15291539 InvalidTaprootLeafVersion ( ref e) => Some ( e) ,
15301540 InvalidMerkleTreeDepth ( ref e) => Some ( e) ,
1541+ InvalidControlBlockHex ( ref e) => Some ( e) ,
15311542 InvalidMerkleBranchSize ( _) | InvalidControlBlockSize ( _) | EmptyTree => None ,
15321543 }
15331544 }
@@ -1652,7 +1663,7 @@ impl std::error::Error for InvalidControlBlockSizeError {}
16521663#[ cfg( test) ]
16531664mod test {
16541665 use hashes:: sha256;
1655- use hex:: { DisplayHex , FromHex } ;
1666+ use hex:: DisplayHex ;
16561667 use secp256k1:: VerifyOnly ;
16571668
16581669 use super :: * ;
@@ -1753,8 +1764,7 @@ mod test {
17531764 let out_pk = out_spk_hex[ 4 ..] . parse :: < XOnlyPublicKey > ( ) . unwrap ( ) ;
17541765 let out_pk = TweakedPublicKey :: dangerous_assume_tweaked ( out_pk) ;
17551766 let script = ScriptBuf :: from_hex ( script_hex) . unwrap ( ) ;
1756- let control_block =
1757- ControlBlock :: decode ( & Vec :: < u8 > :: from_hex ( control_block_hex) . unwrap ( ) ) . unwrap ( ) ;
1767+ let control_block = ControlBlock :: from_hex ( control_block_hex) . unwrap ( ) ;
17581768 assert_eq ! ( control_block_hex, control_block. serialize( ) . to_lower_hex_string( ) ) ;
17591769 assert ! ( control_block. verify_taproot_commitment( secp, out_pk. to_inner( ) , & script) ) ;
17601770 }
@@ -2035,10 +2045,8 @@ mod test {
20352045 let spend_info = builder. finalize ( secp, internal_key) . unwrap ( ) ;
20362046 for ( i, script_ver) in leaves. iter ( ) . enumerate ( ) {
20372047 let expected_leaf_hash = leaf_hashes[ i] . as_str ( ) . unwrap ( ) ;
2038- let expected_ctrl_blk = ControlBlock :: decode (
2039- & Vec :: < u8 > :: from_hex ( ctrl_blks[ i] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ,
2040- )
2041- . unwrap ( ) ;
2048+ let expected_ctrl_blk =
2049+ ControlBlock :: from_hex ( ctrl_blks[ i] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ;
20422050
20432051 let leaf_hash = TapLeafHash :: from_script ( & script_ver. 0 , script_ver. 1 ) ;
20442052 let ctrl_blk = spend_info. control_block ( script_ver) . unwrap ( ) ;
0 commit comments