@@ -215,13 +215,19 @@ pub enum PsbtError {
215215enum OurKey {
216216 Segwit ( bitcoin:: secp256k1:: PublicKey , Keypath ) ,
217217 TaprootInternal ( Keypath ) ,
218+ TaprootScript (
219+ bitcoin:: secp256k1:: XOnlyPublicKey ,
220+ bitcoin:: taproot:: TapLeafHash ,
221+ Keypath ,
222+ ) ,
218223}
219224
220225impl OurKey {
221226 fn keypath ( & self ) -> Keypath {
222227 match self {
223228 OurKey :: Segwit ( _, kp) => kp. clone ( ) ,
224229 OurKey :: TaprootInternal ( kp) => kp. clone ( ) ,
230+ OurKey :: TaprootScript ( _, _, kp) => kp. clone ( ) ,
225231 }
226232 }
227233}
@@ -295,19 +301,34 @@ fn find_our_key<T: PsbtOutputInfo>(
295301 our_root_fingerprint : & [ u8 ] ,
296302 output_info : T ,
297303) -> Result < OurKey , PsbtError > {
298- if let Some ( tap_internal_key) = output_info. get_tap_internal_key ( ) {
299- let ( leaf_hashes, ( fingerprint, derivation_path) ) = output_info
300- . get_tap_key_origins ( )
301- . get ( tap_internal_key)
302- . ok_or ( PsbtError :: KeyNotFound ) ?;
303- if !leaf_hashes. is_empty ( ) {
304- return Err ( PsbtError :: UnsupportedTapScript ) ;
305- }
304+ for ( xonly, ( leaf_hashes, ( fingerprint, derivation_path) ) ) in
305+ output_info. get_tap_key_origins ( ) . iter ( )
306+ {
306307 if & fingerprint[ ..] == our_root_fingerprint {
307308 // TODO: check for fingerprint collision
308- return Ok ( OurKey :: TaprootInternal ( derivation_path. into ( ) ) ) ;
309+
310+ if let Some ( tap_internal_key) = output_info. get_tap_internal_key ( ) {
311+ if tap_internal_key == xonly {
312+ if !leaf_hashes. is_empty ( ) {
313+ // TODO change err msg, we don't support the
314+ // same key as internal key and also in a leaf
315+ // script.
316+ return Err ( PsbtError :: UnsupportedTapScript ) ;
317+ }
318+ return Ok ( OurKey :: TaprootInternal ( derivation_path. into ( ) ) ) ;
319+ }
320+ }
321+ if leaf_hashes. len ( ) != 1 {
322+ // TODO change err msg, per BIP-388 all pubkeys are
323+ // unique, so it can't be in multiple leafs.
324+ return Err ( PsbtError :: UnsupportedTapScript ) ;
325+ }
326+ return Ok ( OurKey :: TaprootScript (
327+ * xonly,
328+ leaf_hashes[ 0 ] ,
329+ derivation_path. into ( ) ,
330+ ) ) ;
309331 }
310- return Err ( PsbtError :: KeyNotFound ) ;
311332 }
312333 for ( pubkey, ( fingerprint, derivation_path) ) in output_info. get_bip32_derivation ( ) . iter ( ) {
313334 if & fingerprint[ ..] == our_root_fingerprint {
@@ -516,15 +537,26 @@ pub fn make_script_config_policy(policy: &str, keys: &[KeyOriginInfo]) -> pb::Bt
516537 }
517538}
518539
519- fn is_taproot ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
520- matches ! ( script_config,
521- pb:: BtcScriptConfigWithKeypath {
522- script_config:
523- Some ( pb:: BtcScriptConfig {
524- config: Some ( pb:: btc_script_config:: Config :: SimpleType ( simple_type) ) ,
525- } ) ,
526- ..
527- } if * simple_type == pb:: btc_script_config:: SimpleType :: P2tr as i32 )
540+ fn is_taproot_simple ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
541+ matches ! (
542+ script_config. script_config. as_ref( ) ,
543+ Some ( pb:: BtcScriptConfig {
544+ config: Some ( pb:: btc_script_config:: Config :: SimpleType ( simple_type) ) ,
545+ } ) if * simple_type == pb:: btc_script_config:: SimpleType :: P2tr as i32
546+ )
547+ }
548+
549+ fn is_taproot_policy ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
550+ matches ! (
551+ script_config. script_config. as_ref( ) ,
552+ Some ( pb:: BtcScriptConfig {
553+ config: Some ( pb:: btc_script_config:: Config :: Policy ( policy) ) ,
554+ } ) if policy. policy. as_str( ) . starts_with( "tr(" ) ,
555+ )
556+ }
557+
558+ fn is_schnorr ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
559+ is_taproot_simple ( script_config) | is_taproot_policy ( script_config)
528560}
529561
530562impl < R : Runtime > PairedBitBox < R > {
@@ -621,7 +653,7 @@ impl<R: Runtime> PairedBitBox<R> {
621653 format_unit : pb:: btc_sign_init_request:: FormatUnit ,
622654 ) -> Result < Vec < Vec < u8 > > , Error > {
623655 self . validate_version ( ">=9.4.0" ) ?; // anti-klepto since 9.4.0
624- if transaction. script_configs . iter ( ) . any ( is_taproot ) {
656+ if transaction. script_configs . iter ( ) . any ( is_taproot_simple ) {
625657 self . validate_version ( ">=9.10.0" ) ?; // taproot since 9.10.0
626658 }
627659
@@ -648,7 +680,7 @@ impl<R: Runtime> PairedBitBox<R> {
648680 let input_index: usize = next_response. index as _ ;
649681 let tx_input: & TxInput = & transaction. inputs [ input_index] ;
650682
651- let input_is_schnorr = is_taproot (
683+ let input_is_schnorr = is_schnorr (
652684 & transaction. script_configs [ tx_input. script_config_index as usize ] ,
653685 ) ;
654686 let perform_antiklepto = is_inputs_pass2 && !input_is_schnorr;
@@ -844,7 +876,12 @@ impl<R: Runtime> PairedBitBox<R> {
844876 psbt_input. tap_key_sig = Some (
845877 bitcoin:: taproot:: Signature :: from_slice ( signature)
846878 . map_err ( |_| Error :: InvalidSignature ) ?,
847- )
879+ ) ;
880+ }
881+ OurKey :: TaprootScript ( xonly, leaf_hash, _) => {
882+ let sig = bitcoin:: taproot:: Signature :: from_slice ( signature)
883+ . map_err ( |_| Error :: InvalidSignature ) ?;
884+ psbt_input. tap_script_sigs . insert ( ( xonly, leaf_hash) , sig) ;
848885 }
849886 }
850887 }
0 commit comments