@@ -215,13 +215,19 @@ pub enum PsbtError {
215
215
enum OurKey {
216
216
Segwit ( bitcoin:: secp256k1:: PublicKey , Keypath ) ,
217
217
TaprootInternal ( Keypath ) ,
218
+ TaprootScript (
219
+ bitcoin:: secp256k1:: XOnlyPublicKey ,
220
+ bitcoin:: taproot:: TapLeafHash ,
221
+ Keypath ,
222
+ ) ,
218
223
}
219
224
220
225
impl OurKey {
221
226
fn keypath ( & self ) -> Keypath {
222
227
match self {
223
228
OurKey :: Segwit ( _, kp) => kp. clone ( ) ,
224
229
OurKey :: TaprootInternal ( kp) => kp. clone ( ) ,
230
+ OurKey :: TaprootScript ( _, _, kp) => kp. clone ( ) ,
225
231
}
226
232
}
227
233
}
@@ -295,19 +301,34 @@ fn find_our_key<T: PsbtOutputInfo>(
295
301
our_root_fingerprint : & [ u8 ] ,
296
302
output_info : T ,
297
303
) -> 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
+ {
306
307
if & fingerprint[ ..] == our_root_fingerprint {
307
308
// 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
+ ) ) ;
309
331
}
310
- return Err ( PsbtError :: KeyNotFound ) ;
311
332
}
312
333
for ( pubkey, ( fingerprint, derivation_path) ) in output_info. get_bip32_derivation ( ) . iter ( ) {
313
334
if & fingerprint[ ..] == our_root_fingerprint {
@@ -516,15 +537,26 @@ pub fn make_script_config_policy(policy: &str, keys: &[KeyOriginInfo]) -> pb::Bt
516
537
}
517
538
}
518
539
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)
528
560
}
529
561
530
562
impl < R : Runtime > PairedBitBox < R > {
@@ -621,7 +653,7 @@ impl<R: Runtime> PairedBitBox<R> {
621
653
format_unit : pb:: btc_sign_init_request:: FormatUnit ,
622
654
) -> Result < Vec < Vec < u8 > > , Error > {
623
655
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 ) {
625
657
self . validate_version ( ">=9.10.0" ) ?; // taproot since 9.10.0
626
658
}
627
659
@@ -648,7 +680,7 @@ impl<R: Runtime> PairedBitBox<R> {
648
680
let input_index: usize = next_response. index as _ ;
649
681
let tx_input: & TxInput = & transaction. inputs [ input_index] ;
650
682
651
- let input_is_schnorr = is_taproot (
683
+ let input_is_schnorr = is_schnorr (
652
684
& transaction. script_configs [ tx_input. script_config_index as usize ] ,
653
685
) ;
654
686
let perform_antiklepto = is_inputs_pass2 && !input_is_schnorr;
@@ -844,7 +876,12 @@ impl<R: Runtime> PairedBitBox<R> {
844
876
psbt_input. tap_key_sig = Some (
845
877
bitcoin:: taproot:: Signature :: from_slice ( signature)
846
878
. 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) ;
848
885
}
849
886
}
850
887
}
0 commit comments