Skip to content

Commit 3b73b43

Browse files
committed
Use ChannelPublicKeys in create_spendable_outputs_psbt to derive the basepoint and the key tweak.
Implement StaticPaymentOutput to PSBT input conversion.
1 parent 9a9d8ff commit 3b73b43

File tree

3 files changed

+56
-31
lines changed

3 files changed

+56
-31
lines changed

lightning/src/chain/channelmonitor.rs

-1
Original file line numberDiff line numberDiff line change
@@ -4255,7 +4255,6 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
42554255
revocation_pubkey: broadcasted_holder_revokable_script.2,
42564256
channel_keys_id: self.channel_keys_id,
42574257
channel_value_satoshis: self.channel_value_satoshis,
4258-
delayed_payment_basepoint: Some(self.onchain_tx_handler.signer.pubkeys().delayed_payment_basepoint),
42594258
}));
42604259
}
42614260
}

lightning/src/ln/channel_keys.rs

+13-16
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ macro_rules! basepoint_impl {
3737
pub fn to_public_key(&self) -> PublicKey {
3838
self.0
3939
}
40+
41+
/// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak
42+
/// from a basepoint and a per_commitment_point:
43+
/// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)`
44+
pub fn derive_add_tweak(
45+
&self,
46+
per_commitment_point: &PublicKey,
47+
) -> [u8; 32] {
48+
let mut sha = Sha256::engine();
49+
sha.input(&per_commitment_point.serialize());
50+
sha.input(&self.to_public_key().serialize());
51+
Sha256::from_engine(sha).to_byte_array()
52+
}
4053
}
4154

4255
impl From<PublicKey> for $BasepointT {
@@ -226,22 +239,6 @@ impl RevocationKey {
226239
key_read_write!(RevocationKey);
227240

228241

229-
/// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak
230-
/// from a delayed payment basepoint and a per_commitment_point:
231-
/// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)`
232-
/// TODO(oleg): refactor after migration to LDK v119
233-
pub fn derive_add_tweak(
234-
per_commitment_point: &PublicKey,
235-
basepoint: &DelayedPaymentBasepoint,
236-
) -> Vec<u8> {
237-
let mut sha = Sha256::engine();
238-
sha.input(&per_commitment_point.serialize());
239-
sha.input(&basepoint.to_public_key().serialize());
240-
let res = Sha256::from_engine(sha).to_byte_array();
241-
res.to_vec()
242-
}
243-
244-
245242
#[cfg(test)]
246243
mod test {
247244
use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey};

lightning/src/sign/mod.rs

+43-14
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
3737
use bitcoin::secp256k1::schnorr;
3838
use bitcoin::{secp256k1, Sequence, Witness, Txid};
3939

40+
use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
4041
use crate::util::transaction_utils;
4142
use crate::util::crypto::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
4243
use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs};
4344
use crate::chain::transaction::OutPoint;
44-
use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
4545
use crate::ln::{chan_utils, PaymentPreimage};
4646
use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction, get_revokeable_redeemscript};
47-
use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint, derive_add_tweak};
47+
use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint, PaymentBasepoint};
4848
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
4949
#[cfg(taproot)]
5050
use crate::ln::msgs::PartialSignatureWithNonce;
@@ -103,8 +103,6 @@ pub struct DelayedPaymentOutputDescriptor {
103103
pub channel_keys_id: [u8; 32],
104104
/// The value of the channel which this output originated from, possibly indirectly.
105105
pub channel_value_satoshis: u64,
106-
/// Channel base key used to generate a witness data to spend this output.
107-
pub delayed_payment_basepoint: Option<DelayedPaymentBasepoint>
108106
}
109107

110108
impl DelayedPaymentOutputDescriptor {
@@ -124,7 +122,6 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, {
124122
(8, revocation_pubkey, required),
125123
(10, channel_keys_id, required),
126124
(12, channel_value_satoshis, required),
127-
(14, delayed_payment_basepoint, option),
128125
});
129126

130127
pub(crate) const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ +
@@ -309,7 +306,7 @@ impl SpendableOutputDescriptor {
309306
///
310307
/// This is not exported to bindings users as there is no standard serialization for an input.
311308
/// See [`Self::create_spendable_outputs_psbt`] instead.
312-
pub fn to_psbt_input<T: secp256k1::Signing>(&self, secp_ctx: &Secp256k1<T>) -> bitcoin::psbt::Input {
309+
pub fn to_psbt_input<T: secp256k1::Signing>(&self, secp_ctx: &Secp256k1<T>, channel_public_keys: Option<&ChannelPublicKeys>) -> bitcoin::psbt::Input {
313310
match self {
314311
SpendableOutputDescriptor::StaticOutput { output, .. } => {
315312
// Is a standard P2WPKH, no need for witness script
@@ -319,14 +316,18 @@ impl SpendableOutputDescriptor {
319316
}
320317
},
321318
SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
322-
let (witness_script, add_tweak) = if let Some(basepoint) = descriptor.delayed_payment_basepoint.as_ref() {
319+
let delayed_payment_basepoint = channel_public_keys.map(|keys| DelayedPaymentBasepoint::from(
320+
keys.delayed_payment_basepoint,
321+
));
322+
323+
let (witness_script, add_tweak) = if let Some(basepoint) = delayed_payment_basepoint.as_ref() {
323324
let payment_key = DelayedPaymentKey::from_basepoint(
324325
secp_ctx,
325326
basepoint,
326327
&descriptor.per_commitment_point,
327328
);
328329
// Required to derive signing key: privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
329-
let add_tweak = derive_add_tweak(&descriptor.per_commitment_point, basepoint);
330+
let add_tweak = basepoint.derive_add_tweak(&descriptor.per_commitment_point);
330331
(Some(get_revokeable_redeemscript(
331332
&descriptor.revocation_pubkey,
332333
descriptor.to_self_delay,
@@ -336,7 +337,6 @@ impl SpendableOutputDescriptor {
336337
(None, None)
337338
};
338339

339-
340340
bitcoin::psbt::Input {
341341
witness_utxo: Some(descriptor.output.clone()),
342342
witness_script,
@@ -346,15 +346,43 @@ impl SpendableOutputDescriptor {
346346
subtype: 0,
347347
key: "add_tweak".as_bytes().to_vec(),
348348
},
349-
add_tweak,
349+
add_tweak.to_vec(),
350350
)].into_iter().collect()}).unwrap_or_default(),
351351
..Default::default()
352352
}
353353
},
354354
SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
355-
// TODO we could add the witness script as well
355+
// Use simplified derivation, assuming `option_static_remotekey` or `option_anchors` is negotiated.
356+
// `remote_payment_basepoint` is used to produce add tweak which is needed in order to produce the signing key.
357+
let remote_payment_basepoint = channel_public_keys.map(|keys|
358+
PaymentBasepoint::from(keys.payment_point)
359+
);
360+
361+
let witness_script = match remote_payment_basepoint {
362+
Some(ref basepoint) => {
363+
// We cannot always assume that `channel_parameters` is set, so can't just call
364+
// `self.channel_parameters()` or anything that relies on it
365+
let supports_anchors_zero_fee_htlc_tx = descriptor.channel_transaction_parameters.as_ref()
366+
.map(|features| features.channel_type_features.supports_anchors_zero_fee_htlc_tx())
367+
.unwrap_or(false);
368+
369+
let witness_script = if supports_anchors_zero_fee_htlc_tx {
370+
chan_utils::get_to_countersignatory_with_anchors_redeemscript(&basepoint.to_public_key())
371+
} else {
372+
ScriptBuf::new_p2pkh(&bitcoin::PublicKey::new(basepoint.to_public_key()).pubkey_hash())
373+
};
374+
375+
// With simplified derivation, the private payment key is equal to private payment basepoint,
376+
// so add tweak is not needed.
377+
Some(witness_script)
378+
},
379+
_ => None,
380+
};
381+
382+
356383
bitcoin::psbt::Input {
357384
witness_utxo: Some(descriptor.output.clone()),
385+
witness_script,
358386
..Default::default()
359387
}
360388
},
@@ -378,7 +406,7 @@ impl SpendableOutputDescriptor {
378406
/// does not match the one we can spend.
379407
///
380408
/// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
381-
pub fn create_spendable_outputs_psbt(descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option<LockTime>) -> Result<(PartiallySignedTransaction, u64), ()> {
409+
pub fn create_spendable_outputs_psbt(descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option<LockTime>, channel_public_keys: Option<&ChannelPublicKeys>) -> Result<(PartiallySignedTransaction, u64), ()> {
382410
let secp_ctx = Secp256k1::new();
383411
let mut input = Vec::with_capacity(descriptors.len());
384412
let mut input_value = 0;
@@ -446,7 +474,7 @@ impl SpendableOutputDescriptor {
446474
let expected_max_weight =
447475
transaction_utils::maybe_add_change_output(&mut tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?;
448476

449-
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx)).collect::<Vec<_>>();
477+
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx, channel_public_keys)).collect::<Vec<_>>();
450478
let psbt = PartiallySignedTransaction {
451479
inputs: psbt_inputs,
452480
outputs: vec![Default::default(); tx.output.len()],
@@ -1649,7 +1677,8 @@ impl KeysManager {
16491677
/// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
16501678
/// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
16511679
pub fn spend_spendable_outputs<C: Signing>(&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option<LockTime>, secp_ctx: &Secp256k1<C>) -> Result<Transaction, ()> {
1652-
let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime)?;
1680+
// TODO: provide channel keys to construct witness script
1681+
let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime, None)?;
16531682
psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?;
16541683

16551684
let spend_tx = psbt.extract_tx();

0 commit comments

Comments
 (0)