@@ -427,6 +427,8 @@ impl Psbt {
427427 k. get_key ( & KeyRequest :: Bip32 ( key_source. clone ( ) ) , secp)
428428 {
429429 secret_key
430+ } else if let Ok ( Some ( sk) ) = k. get_key ( & KeyRequest :: XOnlyPubkey ( xonly) , secp) {
431+ sk
430432 } else {
431433 continue ;
432434 } ;
@@ -737,6 +739,8 @@ pub enum KeyRequest {
737739 Pubkey ( PublicKey ) ,
738740 /// Request a private key using BIP-32 fingerprint and derivation path.
739741 Bip32 ( KeySource ) ,
742+ /// Request a private key using the associated x-only public key.
743+ XOnlyPubkey ( XOnlyPublicKey ) ,
740744}
741745
742746/// Trait to get a private key from a key request, key is then used to sign an input.
@@ -768,6 +772,7 @@ impl GetKey for Xpriv {
768772 ) -> Result < Option < PrivateKey > , Self :: Error > {
769773 match key_request {
770774 KeyRequest :: Pubkey ( _) => Err ( GetKeyError :: NotSupported ) ,
775+ KeyRequest :: XOnlyPubkey ( _) => Err ( GetKeyError :: NotSupported ) ,
771776 KeyRequest :: Bip32 ( ( fingerprint, path) ) => {
772777 let key = if self . fingerprint ( secp) == * fingerprint {
773778 let k = self . derive_xpriv ( secp, & path) ;
@@ -831,7 +836,7 @@ impl_get_key_for_set!(BTreeSet);
831836impl_get_key_for_set ! ( HashSet ) ;
832837
833838#[ rustfmt:: skip]
834- macro_rules! impl_get_key_for_map {
839+ macro_rules! impl_get_key_for_pubkey_map {
835840 ( $map: ident) => {
836841
837842impl GetKey for $map<PublicKey , PrivateKey > {
@@ -844,13 +849,67 @@ impl GetKey for $map<PublicKey, PrivateKey> {
844849 ) -> Result <Option <PrivateKey >, Self :: Error > {
845850 match key_request {
846851 KeyRequest :: Pubkey ( pk) => Ok ( self . get( & pk) . cloned( ) ) ,
852+ KeyRequest :: XOnlyPubkey ( xonly) => {
853+ let pubkey_even = PublicKey :: new( xonly. public_key( secp256k1:: Parity :: Even ) ) ;
854+ let key = self . get( & pubkey_even) . cloned( ) ;
855+
856+ if key. is_some( ) {
857+ return Ok ( key) ;
858+ }
859+
860+ let pubkey_odd = PublicKey :: new( xonly. public_key( secp256k1:: Parity :: Odd ) ) ;
861+ if let Some ( priv_key) = self . get( & pubkey_odd) . copied( ) {
862+ let negated_priv_key = priv_key. negate( ) ;
863+ return Ok ( Some ( negated_priv_key) ) ;
864+ }
865+
866+ Ok ( None )
867+ } ,
868+ KeyRequest :: Bip32 ( _) => Err ( GetKeyError :: NotSupported ) ,
869+ }
870+ }
871+ } } }
872+ impl_get_key_for_pubkey_map ! ( BTreeMap ) ;
873+ #[ cfg( feature = "std" ) ]
874+ impl_get_key_for_pubkey_map ! ( HashMap ) ;
875+
876+ #[ rustfmt:: skip]
877+ macro_rules! impl_get_key_for_xonly_map {
878+ ( $map: ident) => {
879+
880+ impl GetKey for $map<XOnlyPublicKey , PrivateKey > {
881+ type Error = GetKeyError ;
882+
883+ fn get_key<C : Signing >(
884+ & self ,
885+ key_request: & KeyRequest ,
886+ secp: & Secp256k1 <C >,
887+ ) -> Result <Option <PrivateKey >, Self :: Error > {
888+ match key_request {
889+ KeyRequest :: XOnlyPubkey ( xonly) => Ok ( self . get( xonly) . cloned( ) ) ,
890+ KeyRequest :: Pubkey ( pk) => {
891+ let ( xonly, parity) = pk. inner. x_only_public_key( ) ;
892+
893+ if let Some ( mut priv_key) = self . get( & XOnlyPublicKey :: from( xonly) ) . cloned( ) {
894+ let computed_pk = priv_key. public_key( & secp) ;
895+ let ( _, computed_parity) = computed_pk. inner. x_only_public_key( ) ;
896+
897+ if computed_parity != parity {
898+ priv_key = priv_key. negate( ) ;
899+ }
900+
901+ return Ok ( Some ( priv_key) ) ;
902+ }
903+
904+ Ok ( None )
905+ } ,
847906 KeyRequest :: Bip32 ( _) => Err ( GetKeyError :: NotSupported ) ,
848907 }
849908 }
850909} } }
851- impl_get_key_for_map ! ( BTreeMap ) ;
910+ impl_get_key_for_xonly_map ! ( BTreeMap ) ;
852911#[ cfg( feature = "std" ) ]
853- impl_get_key_for_map ! ( HashMap ) ;
912+ impl_get_key_for_xonly_map ! ( HashMap ) ;
854913
855914/// Errors when getting a key.
856915#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -1228,7 +1287,14 @@ mod tests {
12281287 use hashes:: { hash160, ripemd160, sha256} ;
12291288 use hex:: { test_hex_unwrap as hex, FromHex } ;
12301289 #[ cfg( feature = "rand-std" ) ]
1231- use secp256k1:: { All , SecretKey } ;
1290+ use {
1291+ crate :: address:: script_pubkey:: ScriptBufExt as _,
1292+ crate :: bip32:: { DerivationPath , Fingerprint } ,
1293+ crate :: locktime,
1294+ crate :: witness_version:: WitnessVersion ,
1295+ crate :: WitnessProgram ,
1296+ secp256k1:: { All , SecretKey } ,
1297+ } ;
12321298
12331299 use super :: * ;
12341300 use crate :: address:: script_pubkey:: ScriptExt as _;
@@ -2169,6 +2235,42 @@ mod tests {
21692235 assert_eq ! ( got. unwrap( ) , priv_key)
21702236 }
21712237
2238+ #[ test]
2239+ #[ cfg( feature = "rand-std" ) ]
2240+ fn pubkey_map_get_key_negates_odd_parity_keys ( ) {
2241+ use crate :: psbt:: { GetKey , KeyRequest } ;
2242+
2243+ let ( mut priv_key, mut pk, secp) = gen_keys ( ) ;
2244+ let ( xonly, parity) = pk. inner . x_only_public_key ( ) ;
2245+
2246+ let mut pubkey_map: HashMap < PublicKey , PrivateKey > = HashMap :: new ( ) ;
2247+
2248+ if parity == secp256k1:: Parity :: Even {
2249+ priv_key = PrivateKey {
2250+ compressed : priv_key. compressed ,
2251+ network : priv_key. network ,
2252+ inner : priv_key. inner . negate ( ) ,
2253+ } ;
2254+ pk = priv_key. public_key ( & secp) ;
2255+ }
2256+
2257+ pubkey_map. insert ( pk, priv_key) ;
2258+
2259+ let req_result = pubkey_map. get_key ( & KeyRequest :: XOnlyPubkey ( xonly) , & secp) . unwrap ( ) ;
2260+
2261+ let retrieved_key = req_result. unwrap ( ) ;
2262+
2263+ let retrieved_pub_key = retrieved_key. public_key ( & secp) ;
2264+ let ( retrieved_xonly, retrieved_parity) = retrieved_pub_key. inner . x_only_public_key ( ) ;
2265+
2266+ assert_eq ! ( xonly, retrieved_xonly) ;
2267+ assert_eq ! (
2268+ retrieved_parity,
2269+ secp256k1:: Parity :: Even ,
2270+ "Key should be normalized to have even parity, even when original had odd parity"
2271+ ) ;
2272+ }
2273+
21722274 #[ test]
21732275 fn fee ( ) {
21742276 let output_0_val = Amount :: from_sat_u32 ( 99_999_699 ) ;
@@ -2273,12 +2375,73 @@ mod tests {
22732375
22742376 #[ test]
22752377 #[ cfg( feature = "rand-std" ) ]
2276- fn sign_psbt ( ) {
2277- use crate :: address:: script_pubkey:: ScriptBufExt as _;
2278- use crate :: bip32:: { DerivationPath , Fingerprint } ;
2279- use crate :: witness_version:: WitnessVersion ;
2280- use crate :: WitnessProgram ;
2378+ fn hashmap_can_sign_taproot ( ) {
2379+ let ( priv_key, pk, secp) = gen_keys ( ) ;
2380+ let internal_key: XOnlyPublicKey = pk. inner . into ( ) ;
2381+
2382+ let tx = Transaction {
2383+ version : transaction:: Version :: TWO ,
2384+ lock_time : locktime:: absolute:: LockTime :: ZERO ,
2385+ input : vec ! [ TxIn :: EMPTY_COINBASE ] ,
2386+ output : vec ! [ TxOut { value: Amount :: ZERO , script_pubkey: ScriptBuf :: new( ) } ] ,
2387+ } ;
22812388
2389+ let mut psbt = Psbt :: from_unsigned_tx ( tx) . unwrap ( ) ;
2390+ psbt. inputs [ 0 ] . tap_internal_key = Some ( internal_key) ;
2391+ psbt. inputs [ 0 ] . witness_utxo = Some ( transaction:: TxOut {
2392+ value : Amount :: from_sat_u32 ( 10 ) ,
2393+ script_pubkey : ScriptBuf :: new_p2tr ( & secp, internal_key, None ) ,
2394+ } ) ;
2395+
2396+ let mut key_map: HashMap < PublicKey , PrivateKey > = HashMap :: new ( ) ;
2397+ key_map. insert ( pk, priv_key) ;
2398+
2399+ let key_source = ( Fingerprint :: default ( ) , DerivationPath :: default ( ) ) ;
2400+ let mut tap_key_origins = std:: collections:: BTreeMap :: new ( ) ;
2401+ tap_key_origins. insert ( internal_key, ( vec ! [ ] , key_source) ) ;
2402+ psbt. inputs [ 0 ] . tap_key_origins = tap_key_origins;
2403+
2404+ let signing_keys = psbt. sign ( & key_map, & secp) . unwrap ( ) ;
2405+ assert_eq ! ( signing_keys. len( ) , 1 ) ;
2406+ assert_eq ! ( signing_keys[ & 0 ] , SigningKeys :: Schnorr ( vec![ internal_key] ) ) ;
2407+ }
2408+
2409+ #[ test]
2410+ #[ cfg( feature = "rand-std" ) ]
2411+ fn xonly_hashmap_can_sign_taproot ( ) {
2412+ let ( priv_key, pk, secp) = gen_keys ( ) ;
2413+ let internal_key: XOnlyPublicKey = pk. inner . into ( ) ;
2414+
2415+ let tx = Transaction {
2416+ version : transaction:: Version :: TWO ,
2417+ lock_time : locktime:: absolute:: LockTime :: ZERO ,
2418+ input : vec ! [ TxIn :: EMPTY_COINBASE ] ,
2419+ output : vec ! [ TxOut { value: Amount :: ZERO , script_pubkey: ScriptBuf :: new( ) } ] ,
2420+ } ;
2421+
2422+ let mut psbt = Psbt :: from_unsigned_tx ( tx) . unwrap ( ) ;
2423+ psbt. inputs [ 0 ] . tap_internal_key = Some ( internal_key) ;
2424+ psbt. inputs [ 0 ] . witness_utxo = Some ( transaction:: TxOut {
2425+ value : Amount :: from_sat_u32 ( 10 ) ,
2426+ script_pubkey : ScriptBuf :: new_p2tr ( & secp, internal_key, None ) ,
2427+ } ) ;
2428+
2429+ let mut xonly_key_map: HashMap < XOnlyPublicKey , PrivateKey > = HashMap :: new ( ) ;
2430+ xonly_key_map. insert ( internal_key, priv_key) ;
2431+
2432+ let key_source = ( Fingerprint :: default ( ) , DerivationPath :: default ( ) ) ;
2433+ let mut tap_key_origins = std:: collections:: BTreeMap :: new ( ) ;
2434+ tap_key_origins. insert ( internal_key, ( vec ! [ ] , key_source) ) ;
2435+ psbt. inputs [ 0 ] . tap_key_origins = tap_key_origins;
2436+
2437+ let signing_keys = psbt. sign ( & xonly_key_map, & secp) . unwrap ( ) ;
2438+ assert_eq ! ( signing_keys. len( ) , 1 ) ;
2439+ assert_eq ! ( signing_keys[ & 0 ] , SigningKeys :: Schnorr ( vec![ internal_key] ) ) ;
2440+ }
2441+
2442+ #[ test]
2443+ #[ cfg( feature = "rand-std" ) ]
2444+ fn sign_psbt ( ) {
22822445 let unsigned_tx = Transaction {
22832446 version : transaction:: Version :: TWO ,
22842447 lock_time : absolute:: LockTime :: ZERO ,
0 commit comments