@@ -248,13 +248,19 @@ pub enum PsbtError {
248
248
enum OurKey {
249
249
Segwit ( bitcoin:: secp256k1:: PublicKey , Keypath ) ,
250
250
TaprootInternal ( Keypath ) ,
251
+ TaprootScript (
252
+ bitcoin:: secp256k1:: XOnlyPublicKey ,
253
+ bitcoin:: taproot:: TapLeafHash ,
254
+ Keypath ,
255
+ ) ,
251
256
}
252
257
253
258
impl OurKey {
254
259
fn keypath ( & self ) -> Keypath {
255
260
match self {
256
261
OurKey :: Segwit ( _, kp) => kp. clone ( ) ,
257
262
OurKey :: TaprootInternal ( kp) => kp. clone ( ) ,
263
+ OurKey :: TaprootScript ( _, _, kp) => kp. clone ( ) ,
258
264
}
259
265
}
260
266
}
@@ -328,19 +334,34 @@ fn find_our_key<T: PsbtOutputInfo>(
328
334
our_root_fingerprint : & [ u8 ] ,
329
335
output_info : T ,
330
336
) -> Result < OurKey , PsbtError > {
331
- if let Some ( tap_internal_key) = output_info. get_tap_internal_key ( ) {
332
- let ( leaf_hashes, ( fingerprint, derivation_path) ) = output_info
333
- . get_tap_key_origins ( )
334
- . get ( tap_internal_key)
335
- . ok_or ( PsbtError :: KeyNotFound ) ?;
336
- if !leaf_hashes. is_empty ( ) {
337
- return Err ( PsbtError :: UnsupportedTapScript ) ;
338
- }
337
+ for ( xonly, ( leaf_hashes, ( fingerprint, derivation_path) ) ) in
338
+ output_info. get_tap_key_origins ( ) . iter ( )
339
+ {
339
340
if & fingerprint[ ..] == our_root_fingerprint {
340
341
// TODO: check for fingerprint collision
341
- return Ok ( OurKey :: TaprootInternal ( derivation_path. into ( ) ) ) ;
342
+
343
+ if let Some ( tap_internal_key) = output_info. get_tap_internal_key ( ) {
344
+ if tap_internal_key == xonly {
345
+ if !leaf_hashes. is_empty ( ) {
346
+ // TODO change err msg, we don't support the
347
+ // same key as internal key and also in a leaf
348
+ // script.
349
+ return Err ( PsbtError :: UnsupportedTapScript ) ;
350
+ }
351
+ return Ok ( OurKey :: TaprootInternal ( derivation_path. into ( ) ) ) ;
352
+ }
353
+ }
354
+ if leaf_hashes. len ( ) != 1 {
355
+ // TODO change err msg, per BIP-388 all pubkeys are
356
+ // unique, so it can't be in multiple leafs.
357
+ return Err ( PsbtError :: UnsupportedTapScript ) ;
358
+ }
359
+ return Ok ( OurKey :: TaprootScript (
360
+ * xonly,
361
+ leaf_hashes[ 0 ] ,
362
+ derivation_path. into ( ) ,
363
+ ) ) ;
342
364
}
343
- return Err ( PsbtError :: KeyNotFound ) ;
344
365
}
345
366
for ( pubkey, ( fingerprint, derivation_path) ) in output_info. get_bip32_derivation ( ) . iter ( ) {
346
367
if & fingerprint[ ..] == our_root_fingerprint {
@@ -568,15 +589,26 @@ pub fn make_script_config_policy(policy: &str, keys: &[KeyOriginInfo]) -> pb::Bt
568
589
}
569
590
}
570
591
571
- fn is_taproot ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
572
- matches ! ( script_config,
573
- pb:: BtcScriptConfigWithKeypath {
574
- script_config:
575
- Some ( pb:: BtcScriptConfig {
576
- config: Some ( pb:: btc_script_config:: Config :: SimpleType ( simple_type) ) ,
577
- } ) ,
578
- ..
579
- } if * simple_type == pb:: btc_script_config:: SimpleType :: P2tr as i32 )
592
+ fn is_taproot_simple ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
593
+ matches ! (
594
+ script_config. script_config. as_ref( ) ,
595
+ Some ( pb:: BtcScriptConfig {
596
+ config: Some ( pb:: btc_script_config:: Config :: SimpleType ( simple_type) ) ,
597
+ } ) if * simple_type == pb:: btc_script_config:: SimpleType :: P2tr as i32
598
+ )
599
+ }
600
+
601
+ fn is_taproot_policy ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
602
+ matches ! (
603
+ script_config. script_config. as_ref( ) ,
604
+ Some ( pb:: BtcScriptConfig {
605
+ config: Some ( pb:: btc_script_config:: Config :: Policy ( policy) ) ,
606
+ } ) if policy. policy. as_str( ) . starts_with( "tr(" ) ,
607
+ )
608
+ }
609
+
610
+ fn is_schnorr ( script_config : & pb:: BtcScriptConfigWithKeypath ) -> bool {
611
+ is_taproot_simple ( script_config) | is_taproot_policy ( script_config)
580
612
}
581
613
582
614
impl < R : Runtime > PairedBitBox < R > {
@@ -673,7 +705,7 @@ impl<R: Runtime> PairedBitBox<R> {
673
705
format_unit : pb:: btc_sign_init_request:: FormatUnit ,
674
706
) -> Result < Vec < Vec < u8 > > , Error > {
675
707
self . validate_version ( ">=9.4.0" ) ?; // anti-klepto since 9.4.0
676
- if transaction. script_configs . iter ( ) . any ( is_taproot ) {
708
+ if transaction. script_configs . iter ( ) . any ( is_taproot_simple ) {
677
709
self . validate_version ( ">=9.10.0" ) ?; // taproot since 9.10.0
678
710
}
679
711
@@ -700,7 +732,7 @@ impl<R: Runtime> PairedBitBox<R> {
700
732
let input_index: usize = next_response. index as _ ;
701
733
let tx_input: & TxInput = & transaction. inputs [ input_index] ;
702
734
703
- let input_is_schnorr = is_taproot (
735
+ let input_is_schnorr = is_schnorr (
704
736
& transaction. script_configs [ tx_input. script_config_index as usize ] ,
705
737
) ;
706
738
let perform_antiklepto = is_inputs_pass2 && !input_is_schnorr;
@@ -896,7 +928,12 @@ impl<R: Runtime> PairedBitBox<R> {
896
928
psbt_input. tap_key_sig = Some (
897
929
bitcoin:: taproot:: Signature :: from_slice ( signature)
898
930
. map_err ( |_| Error :: InvalidSignature ) ?,
899
- )
931
+ ) ;
932
+ }
933
+ OurKey :: TaprootScript ( xonly, leaf_hash, _) => {
934
+ let sig = bitcoin:: taproot:: Signature :: from_slice ( signature)
935
+ . map_err ( |_| Error :: InvalidSignature ) ?;
936
+ psbt_input. tap_script_sigs . insert ( ( xonly, leaf_hash) , sig) ;
900
937
}
901
938
}
902
939
}
0 commit comments