From fbdc3e8db6978447d390471d08aa3c5eebd513a7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 16 Jul 2024 19:11:45 +0200 Subject: [PATCH] psbt: fix taproot key-only signing --- Cargo.lock | 8 ++++---- derive/src/sign.rs | 18 +++++++++++++++--- psbt/src/sign.rs | 16 ++++++++++------ src/signers.rs | 25 +++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2874598..709e2a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,7 +165,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.11.0-beta.6" -source = "git+https://github.com/BP-WG/bp-core?branch=signer#4bad1a1a46463e14c6b762384c04f1d9b8c19f5f" +source = "git+https://github.com/BP-WG/bp-core?branch=signer#ecc7f690f95ee68ab4b7926012306e1b0e89a83e" dependencies = [ "amplify", "chrono", @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.11.0-beta.6" -source = "git+https://github.com/BP-WG/bp-core?branch=signer#4bad1a1a46463e14c6b762384c04f1d9b8c19f5f" +source = "git+https://github.com/BP-WG/bp-core?branch=signer#ecc7f690f95ee68ab4b7926012306e1b0e89a83e" dependencies = [ "amplify", "bp-consensus", @@ -194,7 +194,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.11.0-beta.6" -source = "git+https://github.com/BP-WG/bp-core?branch=signer#4bad1a1a46463e14c6b762384c04f1d9b8c19f5f" +source = "git+https://github.com/BP-WG/bp-core?branch=signer#ecc7f690f95ee68ab4b7926012306e1b0e89a83e" dependencies = [ "amplify", "base85", @@ -231,7 +231,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.11.0-beta.6" -source = "git+https://github.com/BP-WG/bp-core?branch=signer#4bad1a1a46463e14c6b762384c04f1d9b8c19f5f" +source = "git+https://github.com/BP-WG/bp-core?branch=signer#ecc7f690f95ee68ab4b7926012306e1b0e89a83e" dependencies = [ "amplify", "baid64", diff --git a/derive/src/sign.rs b/derive/src/sign.rs index 2291806..23273ae 100644 --- a/derive/src/sign.rs +++ b/derive/src/sign.rs @@ -21,7 +21,9 @@ // limitations under the License. use bc::secp256k1::{ecdsa, schnorr as bip340}; -use bc::{LegacyPk, Sighash, TapLeafHash, TapMerklePath, TapSighash, XOnlyPk}; +use bc::{ + InternalPk, LegacyPk, Sighash, TapLeafHash, TapMerklePath, TapNodeHash, TapSighash, XOnlyPk, +}; use crate::KeyOrigin; @@ -36,9 +38,19 @@ pub trait Sign { origin: Option<&KeyOrigin>, ) -> Option; - /// Create signature with a given key for inputs using Schnorr signatures with BIP-340 signing + /// Create signature with a given internal key using Schnorr signatures with BIP-340 signing /// scheme (taproot). - fn sign_bip340( + fn sign_bip340_key_only( + &self, + message: TapSighash, + pk: InternalPk, + origin: Option<&KeyOrigin>, + merkle_root: Option, + ) -> Option; + + /// Create signature with a given script path and x-only public key using Schnorr signatures + /// with BIP-340 signing scheme (taproot). + fn sign_bip340_script_path( &self, message: TapSighash, pk: XOnlyPk, diff --git a/psbt/src/sign.rs b/psbt/src/sign.rs index 6c48766..ab75601 100644 --- a/psbt/src/sign.rs +++ b/psbt/src/sign.rs @@ -22,7 +22,7 @@ use std::borrow::Borrow; -use derive::{Bip340Sig, LegacySig, SighashCache, SighashError, Sign, Tx, TxOut, Txid, XOnlyPk}; +use derive::{Bip340Sig, LegacySig, SighashCache, SighashError, Sign, Tx, TxOut, Txid}; use crate::{Input, Psbt}; @@ -183,7 +183,8 @@ impl Input { if !tap.leaf_hashes.contains(&tapleaf_hash) { continue; } - let Some(sig) = signer.sign_bip340(sighash, *pk, Some(&tap.origin)) else { + let Some(sig) = signer.sign_bip340_script_path(sighash, *pk, Some(&tap.origin)) + else { continue; }; let sig = Bip340Sig { sig, sighash_type }; @@ -199,11 +200,14 @@ impl Input { let Some(internal_key) = self.tap_internal_key else { return Ok(signature_count); }; - let xonly_key = XOnlyPk::from(internal_key); - let derivation = self.tap_bip32_derivation.get(&xonly_key); + let derivation = self.tap_bip32_derivation.get(&internal_key.to_xonly_pk()); let sighash = sig_hasher.tap_sighash_key(self.index, sighash_type)?; - let Some(sig) = signer.sign_bip340(sighash, xonly_key, derivation.map(|d| &d.origin)) - else { + let Some(sig) = signer.sign_bip340_key_only( + sighash, + internal_key, + derivation.map(|d| &d.origin), + self.tap_merkle_root, + ) else { return Ok(signature_count); }; let sig = Bip340Sig { sig, sighash_type }; diff --git a/src/signers.rs b/src/signers.rs index 5d58d9b..3c8a3e4 100644 --- a/src/signers.rs +++ b/src/signers.rs @@ -24,7 +24,10 @@ use std::collections::HashMap; use amplify::Wrapper; use bc::secp256k1::{ecdsa, schnorr as bip340, SECP256K1}; -use bc::{LegacyPk, Sighash, TapLeafHash, TapMerklePath, TapSighash, XOnlyPk}; +use bc::{ + InternalKeypair, InternalPk, LegacyPk, Sighash, TapLeafHash, TapMerklePath, + TapNodeHash, TapSighash, XOnlyPk, +}; use derive::{KeyOrigin, Sign, XkeyOrigin, Xpriv, XprivAccount}; use psbt::{Psbt, Rejected, Signer}; @@ -113,7 +116,25 @@ impl<'a> Sign for TestnetRefSigner<'a> { Some(sk.sign_ecdsa(message.into())) } - fn sign_bip340( + fn sign_bip340_key_only( + &self, + message: TapSighash, + pk: InternalPk, + origin: Option<&KeyOrigin>, + merkle_root: Option, + ) -> Option { + let xpriv = self.get(origin)?; + let output_pair = + InternalKeypair::from(xpriv.to_keypair_bip340()).to_output_keypair(merkle_root).0; + if output_pair.x_only_public_key().0.serialize() + != pk.to_output_pk(merkle_root).0.to_byte_array() + { + return None; + } + Some(output_pair.sign_schnorr(message.into())) + } + + fn sign_bip340_script_path( &self, message: TapSighash, pk: XOnlyPk,