15
15
//!
16
16
//! This module provides support for taproot tagged hashes.
17
17
//!
18
+
18
19
use prelude:: * ;
19
20
use io;
20
21
use secp256k1:: { self , Secp256k1 } ;
@@ -120,7 +121,7 @@ impl TapLeafHash {
120
121
/// function to compute leaf hash from components
121
122
pub fn from_script ( script : & Script , ver : LeafVersion ) -> TapLeafHash {
122
123
let mut eng = TapLeafHash :: engine ( ) ;
123
- ver. as_u8 ( )
124
+ ver. into_consensus ( )
124
125
. consensus_encode ( & mut eng)
125
126
. expect ( "engines don't error" ) ;
126
127
script
@@ -142,6 +143,8 @@ pub const TAPROOT_LEAF_MASK: u8 = 0xfe;
142
143
/// Tapscript leaf version
143
144
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L226
144
145
pub const TAPROOT_LEAF_TAPSCRIPT : u8 = 0xc0 ;
146
+ /// Taproot annex prefix
147
+ pub const TAPROOT_ANNEX_PREFIX : u8 = 0x50 ;
145
148
/// Tapscript control base size
146
149
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L227
147
150
pub const TAPROOT_CONTROL_BASE_SIZE : usize = 33 ;
@@ -152,6 +155,7 @@ pub const TAPROOT_CONTROL_MAX_SIZE: usize =
152
155
153
156
// type alias for versioned tap script corresponding merkle proof
154
157
type ScriptMerkleProofMap = BTreeMap < ( Script , LeafVersion ) , BTreeSet < TaprootMerkleBranch > > ;
158
+
155
159
/// Data structure for representing Taproot spending information.
156
160
/// Taproot output corresponds to a combination of a
157
161
/// single public key condition (known the internal key), and zero or more
@@ -216,7 +220,7 @@ impl TaprootSpendInfo {
216
220
{
217
221
let mut node_weights = BinaryHeap :: < ( Reverse < u64 > , NodeInfo ) > :: new ( ) ;
218
222
for ( p, leaf) in script_weights {
219
- node_weights. push ( ( Reverse ( p as u64 ) , NodeInfo :: new_leaf_with_ver ( leaf, LeafVersion :: default ( ) ) ) ) ;
223
+ node_weights. push ( ( Reverse ( p as u64 ) , NodeInfo :: new_leaf_with_ver ( leaf, LeafVersion :: TapScript ) ) ) ;
220
224
}
221
225
if node_weights. is_empty ( ) {
222
226
return Err ( TaprootBuilderError :: IncompleteTree ) ;
@@ -409,7 +413,7 @@ impl TaprootBuilder {
409
413
/// See [`TaprootBuilder::add_leaf_with_ver`] for adding a leaf with specific version
410
414
/// See [Uncyclopedia](https://en.wikipedia.org/wiki/Depth-first_search) for more details
411
415
pub fn add_leaf ( self , depth : usize , script : Script ) -> Result < Self , TaprootBuilderError > {
412
- self . add_leaf_with_ver ( depth, script, LeafVersion :: default ( ) )
416
+ self . add_leaf_with_ver ( depth, script, LeafVersion :: TapScript )
413
417
}
414
418
415
419
/// Add a hidden/omitted node at a depth `depth` to the builder.
@@ -680,7 +684,7 @@ impl ControlBlock {
680
684
return Err ( TaprootError :: InvalidControlBlockSize ( sl. len ( ) ) ) ;
681
685
}
682
686
let output_key_parity = secp256k1:: Parity :: from ( ( sl[ 0 ] & 1 ) as i32 ) ;
683
- let leaf_version = LeafVersion :: from_u8 ( sl[ 0 ] & TAPROOT_LEAF_MASK ) ?;
687
+ let leaf_version = LeafVersion :: from_consensus ( sl[ 0 ] & TAPROOT_LEAF_MASK ) ?;
684
688
let internal_key = UntweakedPublicKey :: from_slice ( & sl[ 1 ..TAPROOT_CONTROL_BASE_SIZE ] )
685
689
. map_err ( TaprootError :: InvalidInternalKey ) ?;
686
690
let merkle_branch = TaprootMerkleBranch :: from_slice ( & sl[ TAPROOT_CONTROL_BASE_SIZE ..] ) ?;
@@ -700,7 +704,7 @@ impl ControlBlock {
700
704
701
705
/// Serialize to a writer. Returns the number of bytes written
702
706
pub fn encode < Write : io:: Write > ( & self , mut writer : Write ) -> io:: Result < usize > {
703
- let first_byte: u8 = i32:: from ( self . output_key_parity ) as u8 | self . leaf_version . as_u8 ( ) ;
707
+ let first_byte: u8 = i32:: from ( self . output_key_parity ) as u8 | self . leaf_version . into_consensus ( ) ;
704
708
let mut bytes_written = 0 ;
705
709
bytes_written += writer. write ( & [ first_byte] ) ?;
706
710
bytes_written += writer. write ( & self . internal_key . serialize ( ) ) ?;
@@ -756,20 +760,54 @@ impl ControlBlock {
756
760
}
757
761
}
758
762
763
+ /// Inner type representing future (non-tapscript) leaf versions. See [`LeafVersion::Future`].
764
+ ///
765
+ /// NB: NO PUBLIC CONSTRUCTOR!
766
+ /// The only way to construct this is by converting u8 to LeafVersion and then extracting it.
767
+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , Hash , Ord , PartialOrd ) ]
768
+ pub struct FutureLeafVersion ( u8 ) ;
769
+
770
+ impl FutureLeafVersion {
771
+ pub ( self ) fn from_consensus ( version : u8 ) -> Result < FutureLeafVersion , TaprootError > {
772
+ match version {
773
+ TAPROOT_LEAF_TAPSCRIPT => unreachable ! ( "FutureLeafVersion::from_consensus should be never called for 0xC0 value" ) ,
774
+ TAPROOT_ANNEX_PREFIX => Err ( TaprootError :: InvalidTaprootLeafVersion ( TAPROOT_ANNEX_PREFIX ) ) ,
775
+ odd if odd & 0xFE != odd => Err ( TaprootError :: InvalidTaprootLeafVersion ( odd) ) ,
776
+ even => Ok ( FutureLeafVersion ( even) )
777
+ }
778
+ }
779
+
780
+ /// Get consensus representation of the future leaf version.
781
+ #[ inline]
782
+ pub fn into_consensus ( self ) -> u8 {
783
+ self . 0
784
+ }
785
+ }
786
+
787
+ impl fmt:: Display for FutureLeafVersion {
788
+ #[ inline]
789
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
790
+ fmt:: Display :: fmt ( & self . 0 , f)
791
+ }
792
+ }
793
+
759
794
/// The leaf version for tapleafs
760
795
#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
761
- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
762
- pub struct LeafVersion ( u8 ) ;
796
+ pub enum LeafVersion {
797
+ /// BIP-342 tapscript
798
+ TapScript ,
763
799
764
- impl Default for LeafVersion {
765
- fn default ( ) -> Self {
766
- LeafVersion ( TAPROOT_LEAF_TAPSCRIPT )
767
- }
800
+ /// Future leaf version
801
+ Future ( FutureLeafVersion )
768
802
}
769
803
770
804
impl LeafVersion {
771
- /// Obtain LeafVersion from u8, will error when last bit of ver is even or
772
- /// when ver is 0x50 (ANNEX_TAG)
805
+ /// Obtain LeafVersion from consensus byte representation.
806
+ ///
807
+ /// # Errors
808
+ /// - If the last bit of the `version` is odd.
809
+ /// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]).
810
+ /// - If the `version` is not a valid [`LeafVersion`] byte.
773
811
// Text from BIP341:
774
812
// In order to support some forms of static analysis that rely on
775
813
// being able to identify script spends without access to the output being
@@ -779,23 +817,68 @@ impl LeafVersion {
779
817
// or an opcode that is not valid as the first opcode).
780
818
// The values that comply to this rule are the 32 even values between
781
819
// 0xc0 and 0xfe and also 0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba, 0xbc, 0xbe
782
- pub fn from_u8 ( ver : u8 ) -> Result < Self , TaprootError > {
783
- if ver & TAPROOT_LEAF_MASK == ver && ver != 0x50 {
784
- Ok ( LeafVersion ( ver ) )
785
- } else {
786
- Err ( TaprootError :: InvalidTaprootLeafVersion ( ver ) )
820
+ pub fn from_consensus ( version : u8 ) -> Result < Self , TaprootError > {
821
+ match version {
822
+ TAPROOT_LEAF_TAPSCRIPT => Ok ( LeafVersion :: TapScript ) ,
823
+ TAPROOT_ANNEX_PREFIX => Err ( TaprootError :: InvalidTaprootLeafVersion ( TAPROOT_ANNEX_PREFIX ) ) ,
824
+ future => FutureLeafVersion :: from_consensus ( future ) . map ( LeafVersion :: Future ) ,
787
825
}
788
826
}
789
827
790
- /// Get the inner version from LeafVersion
791
- pub fn as_u8 ( & self ) -> u8 {
792
- self . 0
828
+ /// Get consensus representation of the [`LeafVersion`].
829
+ pub fn into_consensus ( self ) -> u8 {
830
+ match self {
831
+ LeafVersion :: TapScript => TAPROOT_LEAF_TAPSCRIPT ,
832
+ LeafVersion :: Future ( version) => version. into_consensus ( ) ,
833
+ }
793
834
}
794
835
}
795
836
796
- impl Into < u8 > for LeafVersion {
797
- fn into ( self ) -> u8 {
798
- self . 0
837
+ impl fmt:: Display for LeafVersion {
838
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
839
+ match ( self , f. alternate ( ) ) {
840
+ ( LeafVersion :: TapScript , false ) => f. write_str ( "tapscript" ) ,
841
+ ( LeafVersion :: TapScript , true ) => fmt:: Display :: fmt ( & TAPROOT_LEAF_TAPSCRIPT , f) ,
842
+ ( LeafVersion :: Future ( version) , false ) => write ! ( f, "future_script_{:#02x}" , version. 0 ) ,
843
+ ( LeafVersion :: Future ( version) , true ) => fmt:: Display :: fmt ( version, f) ,
844
+ }
845
+ }
846
+ }
847
+
848
+ #[ cfg( feature = "serde" ) ]
849
+ #[ cfg_attr( docsrs, doc( cfg( feature = "serde" ) ) ) ]
850
+ impl :: serde:: Serialize for LeafVersion {
851
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
852
+ where
853
+ S : :: serde:: Serializer ,
854
+ {
855
+ serializer. serialize_u8 ( self . into_consensus ( ) )
856
+ }
857
+ }
858
+
859
+ #[ cfg( feature = "serde" ) ]
860
+ #[ cfg_attr( docsrs, doc( cfg( feature = "serde" ) ) ) ]
861
+ impl < ' de > :: serde:: Deserialize < ' de > for LeafVersion {
862
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error > where D : :: serde:: Deserializer < ' de > {
863
+ struct U8Visitor ;
864
+ impl < ' de > :: serde:: de:: Visitor < ' de > for U8Visitor {
865
+ type Value = LeafVersion ;
866
+
867
+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
868
+ formatter. write_str ( "a valid consensus-encoded taproot leaf version" )
869
+ }
870
+
871
+ fn visit_u8 < E > ( self , value : u8 ) -> Result < Self :: Value , E >
872
+ where
873
+ E : :: serde:: de:: Error ,
874
+ {
875
+ LeafVersion :: from_consensus ( value) . map_err ( |_| {
876
+ E :: invalid_value ( :: serde:: de:: Unexpected :: Unsigned ( value as u64 ) , & "consensus-encoded leaf version as u8" )
877
+ } )
878
+ }
879
+ }
880
+
881
+ deserializer. deserialize_u8 ( U8Visitor )
799
882
}
800
883
}
801
884
@@ -1063,7 +1146,7 @@ mod test {
1063
1146
length,
1064
1147
tree_info
1065
1148
. script_map
1066
- . get( & ( Script :: from_hex( script) . unwrap( ) , LeafVersion :: default ( ) ) )
1149
+ . get( & ( Script :: from_hex( script) . unwrap( ) , LeafVersion :: TapScript ) )
1067
1150
. expect( "Present Key" )
1068
1151
. iter( )
1069
1152
. next( )
@@ -1078,7 +1161,7 @@ mod test {
1078
1161
1079
1162
// Try to create and verify a control block from each path
1080
1163
for ( _weights, script) in script_weights {
1081
- let ver_script = ( script, LeafVersion :: default ( ) ) ;
1164
+ let ver_script = ( script, LeafVersion :: TapScript ) ;
1082
1165
let ctrl_block = tree_info. control_block ( & ver_script) . unwrap ( ) ;
1083
1166
assert ! ( ctrl_block. verify_taproot_commitment( & secp, & output_key, & ver_script. 0 ) )
1084
1167
}
@@ -1114,7 +1197,7 @@ mod test {
1114
1197
let output_key = tree_info. output_key ( ) ;
1115
1198
1116
1199
for script in vec ! [ a, b, c, d, e] {
1117
- let ver_script = ( script, LeafVersion :: default ( ) ) ;
1200
+ let ver_script = ( script, LeafVersion :: TapScript ) ;
1118
1201
let ctrl_block = tree_info. control_block ( & ver_script) . unwrap ( ) ;
1119
1202
assert ! ( ctrl_block. verify_taproot_commitment( & secp, & output_key, & ver_script. 0 ) )
1120
1203
}
@@ -1137,7 +1220,7 @@ mod test {
1137
1220
}
1138
1221
} else {
1139
1222
let script = Script :: from_str ( v[ "script" ] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ;
1140
- let ver = LeafVersion :: from_u8 ( v[ "leafVersion" ] . as_u64 ( ) . unwrap ( ) as u8 ) . unwrap ( ) ;
1223
+ let ver = LeafVersion :: from_consensus ( v[ "leafVersion" ] . as_u64 ( ) . unwrap ( ) as u8 ) . unwrap ( ) ;
1141
1224
leaves. push ( ( script. clone ( ) , ver) ) ;
1142
1225
builder = builder. add_leaf_with_ver ( depth, script, ver) . unwrap ( ) ;
1143
1226
}
0 commit comments