Skip to content

Commit 6970176

Browse files
committed
Implement Script for Witness and Add Tweak in Spendable Output to Partially Signed Bitcoin Transaction Input converter.
Adding Witness Script and key tweaks makes PSBT a single data source needed for a Signer to produce valid signatures. A Signer is not required to be able to generate L2 keys, e.g delayed payment basepoint.
1 parent 5592378 commit 6970176

File tree

3 files changed

+88
-29
lines changed

3 files changed

+88
-29
lines changed

lightning/src/chain/channelmonitor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4255,6 +4255,7 @@ 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+
channel_transaction_parameters: Some(self.onchain_tx_handler.channel_transaction_parameters.clone()),
42584259
}));
42594260
}
42604261
}

lightning/src/ln/channel_keys.rs

+28-15
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,34 @@ macro_rules! doc_comment {
3131
};
3232
}
3333
macro_rules! basepoint_impl {
34-
($BasepointT:ty) => {
35-
impl $BasepointT {
36-
/// Get inner Public Key
37-
pub fn to_public_key(&self) -> PublicKey {
38-
self.0
39-
}
40-
}
41-
42-
impl From<PublicKey> for $BasepointT {
43-
fn from(value: PublicKey) -> Self {
44-
Self(value)
45-
}
46-
}
47-
48-
}
34+
($BasepointT:ty) => {
35+
impl $BasepointT {
36+
/// Get inner Public Key
37+
pub fn to_public_key(&self) -> PublicKey {
38+
self.0
39+
}
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+
}
53+
}
54+
55+
impl From<PublicKey> for $BasepointT {
56+
fn from(value: PublicKey) -> Self {
57+
Self(value)
58+
}
59+
}
60+
61+
}
4962
}
5063
macro_rules! key_impl {
5164
($BasepointT:ty, $KeyName:expr) => {

lightning/src/sign/mod.rs

+59-14
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use bitcoin::blockdata::script::{Script, ScriptBuf, Builder};
1818
use bitcoin::blockdata::opcodes;
1919
use bitcoin::ecdsa::Signature as EcdsaSignature;
2020
use bitcoin::network::constants::Network;
21-
use bitcoin::psbt::PartiallySignedTransaction;
21+
use bitcoin::psbt::{PartiallySignedTransaction, raw};
2222
use bitcoin::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
2323
use bitcoin::sighash;
2424
use bitcoin::sighash::EcdsaSighashType;
@@ -37,13 +37,13 @@ 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::crypto::utils::{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};
46-
use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
46+
use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction, get_revokeable_redeemscript};
4747
use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint};
4848
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
4949
#[cfg(taproot)]
@@ -103,7 +103,13 @@ 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+
/// The channel public keys and other parameters needed to generate a spending transaction or to provide to a re-derived signer through
107+
/// [`ChannelSigner::provide_channel_parameters`].
108+
///
109+
/// Added as optional, but always `Some` if the descriptor was produced in v0.0.120 or later.
110+
pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
106111
}
112+
107113
impl DelayedPaymentOutputDescriptor {
108114
/// The maximum length a well-formed witness spending one of these should have.
109115
/// Note: If you have the grind_signatures feature enabled, this will be at least 1 byte
@@ -121,6 +127,7 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, {
121127
(8, revocation_pubkey, required),
122128
(10, channel_keys_id, required),
123129
(12, channel_value_satoshis, required),
130+
(14, channel_transaction_parameters, option),
124131
});
125132

126133
pub(crate) const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ +
@@ -149,21 +156,24 @@ pub struct StaticPaymentOutputDescriptor {
149156
/// Added as optional, but always `Some` if the descriptor was produced in v0.0.117 or later.
150157
pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
151158
}
159+
152160
impl StaticPaymentOutputDescriptor {
153161
/// Returns the `witness_script` of the spendable output.
154162
///
155163
/// Note that this will only return `Some` for [`StaticPaymentOutputDescriptor`]s that
156164
/// originated from an anchor outputs channel, as they take the form of a P2WSH script.
157165
pub fn witness_script(&self) -> Option<ScriptBuf> {
158166
self.channel_transaction_parameters.as_ref()
159-
.and_then(|channel_params|
160-
if channel_params.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
161-
let payment_point = channel_params.holder_pubkeys.payment_point;
167+
.and_then(|channel_params| {
168+
// Use simplified derivation, assuming `option_static_remotekey` is negotiated.
169+
// `remote_payment_basepoint` is used as Payment Key.
170+
let payment_point = channel_params.holder_pubkeys.payment_point;
171+
if channel_params.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
162172
Some(chan_utils::get_to_countersignatory_with_anchors_redeemscript(&payment_point))
163-
} else {
164-
None
165-
}
166-
)
173+
} else {
174+
Some(ScriptBuf::new_p2pkh(&bitcoin::PublicKey::new(payment_point).pubkey_hash()))
175+
}
176+
})
167177
}
168178

169179
/// The maximum length a well-formed witness spending one of these should have.
@@ -304,7 +314,7 @@ impl SpendableOutputDescriptor {
304314
///
305315
/// This is not exported to bindings users as there is no standard serialization for an input.
306316
/// See [`Self::create_spendable_outputs_psbt`] instead.
307-
pub fn to_psbt_input(&self) -> bitcoin::psbt::Input {
317+
pub fn to_psbt_input<T: secp256k1::Signing>(&self, secp_ctx: &Secp256k1<T>) -> bitcoin::psbt::Input {
308318
match self {
309319
SpendableOutputDescriptor::StaticOutput { output, .. } => {
310320
// Is a standard P2WPKH, no need for witness script
@@ -314,16 +324,49 @@ impl SpendableOutputDescriptor {
314324
}
315325
},
316326
SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
317-
// TODO we could add the witness script as well
327+
let delayed_payment_basepoint = descriptor.channel_transaction_parameters.as_ref().map(|params| DelayedPaymentBasepoint::from(
328+
params.holder_pubkeys.delayed_payment_basepoint,
329+
));
330+
331+
let (witness_script, add_tweak) = if let Some(basepoint) = delayed_payment_basepoint.as_ref() {
332+
let payment_key = DelayedPaymentKey::from_basepoint(
333+
secp_ctx,
334+
basepoint,
335+
&descriptor.per_commitment_point,
336+
);
337+
// Required to derive signing key: privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
338+
let add_tweak = basepoint.derive_add_tweak(&descriptor.per_commitment_point);
339+
(Some(get_revokeable_redeemscript(
340+
&descriptor.revocation_pubkey,
341+
descriptor.to_self_delay,
342+
&payment_key,
343+
)), Some(add_tweak))
344+
} else {
345+
(None, None)
346+
};
347+
318348
bitcoin::psbt::Input {
319349
witness_utxo: Some(descriptor.output.clone()),
350+
witness_script,
351+
proprietary: add_tweak.map(|add_tweak| {vec![(
352+
raw::ProprietaryKey {
353+
prefix: "LDK_spendable_output".as_bytes().to_vec(),
354+
subtype: 0,
355+
key: "add_tweak".as_bytes().to_vec(),
356+
},
357+
add_tweak.to_vec(),
358+
)].into_iter().collect()}).unwrap_or_default(),
320359
..Default::default()
321360
}
322361
},
323362
SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
324-
// TODO we could add the witness script as well
363+
let witness_script = descriptor.witness_script();
364+
365+
// With simplified derivation, the private payment key is equal to private payment basepoint,
366+
// so add tweak is not needed.
325367
bitcoin::psbt::Input {
326368
witness_utxo: Some(descriptor.output.clone()),
369+
witness_script,
327370
..Default::default()
328371
}
329372
},
@@ -347,6 +390,7 @@ impl SpendableOutputDescriptor {
347390
///
348391
/// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
349392
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), ()> {
393+
let secp_ctx = Secp256k1::new();
350394
let mut input = Vec::with_capacity(descriptors.len());
351395
let mut input_value = 0;
352396
let mut witness_weight = 0;
@@ -413,7 +457,7 @@ impl SpendableOutputDescriptor {
413457
let expected_max_weight =
414458
transaction_utils::maybe_add_change_output(&mut tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?;
415459

416-
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input()).collect::<Vec<_>>();
460+
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx)).collect::<Vec<_>>();
417461
let psbt = PartiallySignedTransaction {
418462
inputs: psbt_inputs,
419463
outputs: vec![Default::default(); tx.output.len()],
@@ -1615,6 +1659,7 @@ impl KeysManager {
16151659
/// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
16161660
/// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
16171661
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, ()> {
1662+
// TODO: provide channel keys to construct witness script
16181663
let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime)?;
16191664
psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?;
16201665

0 commit comments

Comments
 (0)