diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 6b9ae0f2311..bcc324a5582 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -4255,7 +4255,6 @@ impl ChannelMonitorImpl { revocation_pubkey: broadcasted_holder_revokable_script.2, channel_keys_id: self.channel_keys_id, channel_value_satoshis: self.channel_value_satoshis, - delayed_payment_basepoint: Some(self.onchain_tx_handler.signer.pubkeys().delayed_payment_basepoint), })); } } diff --git a/lightning/src/ln/channel_keys.rs b/lightning/src/ln/channel_keys.rs index 99cd0896a4b..1d122beb75d 100644 --- a/lightning/src/ln/channel_keys.rs +++ b/lightning/src/ln/channel_keys.rs @@ -37,6 +37,19 @@ macro_rules! basepoint_impl { pub fn to_public_key(&self) -> PublicKey { self.0 } + + /// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak + /// from a basepoint and a per_commitment_point: + /// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)` + pub fn derive_add_tweak( + &self, + per_commitment_point: &PublicKey, + ) -> [u8; 32] { + let mut sha = Sha256::engine(); + sha.input(&per_commitment_point.serialize()); + sha.input(&self.to_public_key().serialize()); + Sha256::from_engine(sha).to_byte_array() + } } impl From for $BasepointT { @@ -226,22 +239,6 @@ impl RevocationKey { key_read_write!(RevocationKey); -/// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak -/// from a delayed payment basepoint and a per_commitment_point: -/// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)` -/// TODO(oleg): refactor after migration to LDK v119 -pub fn derive_add_tweak( - per_commitment_point: &PublicKey, - basepoint: &DelayedPaymentBasepoint, -) -> Vec { - let mut sha = Sha256::engine(); - sha.input(&per_commitment_point.serialize()); - sha.input(&basepoint.to_public_key().serialize()); - let res = Sha256::from_engine(sha).to_byte_array(); - res.to_vec() -} - - #[cfg(test)] mod test { use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey}; diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index fa91571dc58..df8f39cd0b5 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -37,14 +37,14 @@ use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use bitcoin::secp256k1::schnorr; use bitcoin::{secp256k1, Sequence, Witness, Txid}; +use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; use crate::util::transaction_utils; use crate::util::crypto::{hkdf_extract_expand_twice, sign, sign_with_aux_rand}; use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs}; use crate::chain::transaction::OutPoint; -use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; use crate::ln::{chan_utils, PaymentPreimage}; use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction, get_revokeable_redeemscript}; -use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint, derive_add_tweak}; +use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint, PaymentBasepoint}; use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; #[cfg(taproot)] use crate::ln::msgs::PartialSignatureWithNonce; @@ -103,8 +103,6 @@ pub struct DelayedPaymentOutputDescriptor { pub channel_keys_id: [u8; 32], /// The value of the channel which this output originated from, possibly indirectly. pub channel_value_satoshis: u64, - /// Channel base key used to generate a witness data to spend this output. - pub delayed_payment_basepoint: Option } impl DelayedPaymentOutputDescriptor { @@ -124,7 +122,6 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, { (8, revocation_pubkey, required), (10, channel_keys_id, required), (12, channel_value_satoshis, required), - (14, delayed_payment_basepoint, option), }); pub(crate) const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ + @@ -309,7 +306,7 @@ impl SpendableOutputDescriptor { /// /// This is not exported to bindings users as there is no standard serialization for an input. /// See [`Self::create_spendable_outputs_psbt`] instead. - pub fn to_psbt_input(&self, secp_ctx: &Secp256k1) -> bitcoin::psbt::Input { + pub fn to_psbt_input(&self, secp_ctx: &Secp256k1, channel_public_keys: Option<&ChannelPublicKeys>) -> bitcoin::psbt::Input { match self { SpendableOutputDescriptor::StaticOutput { output, .. } => { // Is a standard P2WPKH, no need for witness script @@ -319,14 +316,18 @@ impl SpendableOutputDescriptor { } }, SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => { - let (witness_script, add_tweak) = if let Some(basepoint) = descriptor.delayed_payment_basepoint.as_ref() { + let delayed_payment_basepoint = channel_public_keys.map(|keys| DelayedPaymentBasepoint::from( + keys.delayed_payment_basepoint, + )); + + let (witness_script, add_tweak) = if let Some(basepoint) = delayed_payment_basepoint.as_ref() { let payment_key = DelayedPaymentKey::from_basepoint( secp_ctx, basepoint, &descriptor.per_commitment_point, ); // Required to derive signing key: privkey = basepoint_secret + SHA256(per_commitment_point || basepoint) - let add_tweak = derive_add_tweak(&descriptor.per_commitment_point, basepoint); + let add_tweak = basepoint.derive_add_tweak(&descriptor.per_commitment_point); (Some(get_revokeable_redeemscript( &descriptor.revocation_pubkey, descriptor.to_self_delay, @@ -336,7 +337,6 @@ impl SpendableOutputDescriptor { (None, None) }; - bitcoin::psbt::Input { witness_utxo: Some(descriptor.output.clone()), witness_script, @@ -346,15 +346,43 @@ impl SpendableOutputDescriptor { subtype: 0, key: "add_tweak".as_bytes().to_vec(), }, - add_tweak, + add_tweak.to_vec(), )].into_iter().collect()}).unwrap_or_default(), ..Default::default() } }, SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => { - // TODO we could add the witness script as well + // Use simplified derivation, assuming `option_static_remotekey` or `option_anchors` is negotiated. + // `remote_payment_basepoint` is used to produce add tweak which is needed in order to produce the signing key. + let remote_payment_basepoint = channel_public_keys.map(|keys| + PaymentBasepoint::from(keys.payment_point) + ); + + let witness_script = match remote_payment_basepoint { + Some(ref basepoint) => { + // We cannot always assume that `channel_parameters` is set, so can't just call + // `self.channel_parameters()` or anything that relies on it + let supports_anchors_zero_fee_htlc_tx = descriptor.channel_transaction_parameters.as_ref() + .map(|features| features.channel_type_features.supports_anchors_zero_fee_htlc_tx()) + .unwrap_or(false); + + let witness_script = if supports_anchors_zero_fee_htlc_tx { + chan_utils::get_to_countersignatory_with_anchors_redeemscript(&basepoint.to_public_key()) + } else { + ScriptBuf::new_p2pkh(&bitcoin::PublicKey::new(basepoint.to_public_key()).pubkey_hash()) + }; + + // With simplified derivation, the private payment key is equal to private payment basepoint, + // so add tweak is not needed. + Some(witness_script) + }, + _ => None, + }; + + bitcoin::psbt::Input { witness_utxo: Some(descriptor.output.clone()), + witness_script, ..Default::default() } }, @@ -378,7 +406,7 @@ impl SpendableOutputDescriptor { /// does not match the one we can spend. /// /// We do not enforce that outputs meet the dust limit or that any output scripts are standard. - pub fn create_spendable_outputs_psbt(descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option) -> Result<(PartiallySignedTransaction, u64), ()> { + pub fn create_spendable_outputs_psbt(descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option, channel_public_keys: Option<&ChannelPublicKeys>) -> Result<(PartiallySignedTransaction, u64), ()> { let secp_ctx = Secp256k1::new(); let mut input = Vec::with_capacity(descriptors.len()); let mut input_value = 0; @@ -446,7 +474,7 @@ impl SpendableOutputDescriptor { let expected_max_weight = transaction_utils::maybe_add_change_output(&mut tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?; - let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx)).collect::>(); + let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx, channel_public_keys)).collect::>(); let psbt = PartiallySignedTransaction { inputs: psbt_inputs, outputs: vec![Default::default(); tx.output.len()], @@ -1649,7 +1677,8 @@ impl KeysManager { /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`]. pub fn spend_spendable_outputs(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option, secp_ctx: &Secp256k1) -> Result { - let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime)?; + // TODO: provide channel keys to construct witness script + let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime, None)?; psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?; let spend_tx = psbt.extract_tx();