Skip to content

Commit 6ebf48a

Browse files
committed
Implement Script for Witness and Add Tweak in PSBT.
Adding Witness Script and key tweaks makes a Partially Signed Bitcoin Transaction the 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 6264a44 commit 6ebf48a

File tree

3 files changed

+186
-11
lines changed

3 files changed

+186
-11
lines changed

lightning/src/chain/channelmonitor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4330,6 +4330,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
43304330
revocation_pubkey: broadcasted_holder_revokable_script.2,
43314331
channel_keys_id: self.channel_keys_id,
43324332
channel_value_satoshis: self.channel_value_satoshis,
4333+
channel_transaction_parameters: Some(self.onchain_tx_handler.channel_transaction_parameters.clone()),
43334334
}));
43344335
}
43354336
}

lightning/src/ln/channel_keys.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,30 @@ 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+
/// This calculates the hash part in the tweak derivation process, which is used to ensure
45+
/// that each key is unique and cannot be guessed by an external party. It is equivalent
46+
/// to the `from_basepoint` method, but without the addition operation, providing just the
47+
/// tweak from the hash of the per_commitment_point and the basepoint.
48+
pub fn derive_add_tweak(
49+
&self,
50+
per_commitment_point: &PublicKey,
51+
) -> [u8; 32] {
52+
let mut sha = Sha256::engine();
53+
sha.input(&per_commitment_point.serialize());
54+
sha.input(&self.to_public_key().serialize());
55+
Sha256::from_engine(sha).to_byte_array()
56+
}
4057
}
4158

4259
impl From<PublicKey> for $BasepointT {
4360
fn from(value: PublicKey) -> Self {
4461
Self(value)
4562
}
4663
}
47-
4864
}
4965
}
5066
macro_rules! key_impl {

lightning/src/sign/mod.rs

+168-10
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ use bitcoin::{secp256k1, Sequence, Txid, Witness};
4040
use crate::chain::transaction::OutPoint;
4141
use crate::crypto::utils::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
4242
use crate::ln::chan_utils::{
43-
make_funding_redeemscript, ChannelPublicKeys, ChannelTransactionParameters, ClosingTransaction,
44-
CommitmentTransaction, HTLCOutputInCommitment, HolderCommitmentTransaction,
43+
get_revokeable_redeemscript, make_funding_redeemscript, ChannelPublicKeys,
44+
ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction,
45+
HTLCOutputInCommitment, HolderCommitmentTransaction,
4546
};
4647
use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
4748
use crate::ln::channel_keys::{
@@ -68,6 +69,7 @@ use crate::sign::ecdsa::{EcdsaChannelSigner, WriteableEcdsaChannelSigner};
6869
use crate::sign::taproot::TaprootChannelSigner;
6970
use crate::util::atomic_counter::AtomicCounter;
7071
use crate::util::invoice::construct_invoice_preimage;
72+
use core::convert::TryInto;
7173
use core::ops::Deref;
7274
use core::sync::atomic::{AtomicUsize, Ordering};
7375
#[cfg(taproot)]
@@ -108,7 +110,13 @@ pub struct DelayedPaymentOutputDescriptor {
108110
pub channel_keys_id: [u8; 32],
109111
/// The value of the channel which this output originated from, possibly indirectly.
110112
pub channel_value_satoshis: u64,
113+
/// The channel public keys and other parameters needed to generate a spending transaction or to provide to a re-derived signer through
114+
/// [`ChannelSigner::provide_channel_parameters`].
115+
///
116+
/// Added as optional, but always `Some` if the descriptor was produced in v0.0.122 or later.
117+
pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
111118
}
119+
112120
impl DelayedPaymentOutputDescriptor {
113121
/// The maximum length a well-formed witness spending one of these should have.
114122
/// Note: If you have the grind_signatures feature enabled, this will be at least 1 byte
@@ -127,6 +135,7 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, {
127135
(8, revocation_pubkey, required),
128136
(10, channel_keys_id, required),
129137
(12, channel_value_satoshis, required),
138+
(13, channel_transaction_parameters, option),
130139
});
131140

132141
pub(crate) const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ +
@@ -155,6 +164,7 @@ pub struct StaticPaymentOutputDescriptor {
155164
/// Added as optional, but always `Some` if the descriptor was produced in v0.0.117 or later.
156165
pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
157166
}
167+
158168
impl StaticPaymentOutputDescriptor {
159169
/// Returns the `witness_script` of the spendable output.
160170
///
@@ -306,23 +316,124 @@ impl SpendableOutputDescriptor {
306316
///
307317
/// This is not exported to bindings users as there is no standard serialization for an input.
308318
/// See [`Self::create_spendable_outputs_psbt`] instead.
309-
pub fn to_psbt_input(&self) -> bitcoin::psbt::Input {
319+
///
320+
/// The proprietary field is used to store add tweak for the signing key of this transaction.
321+
/// See the [DelayedPaymentBasepoint::derive_add_tweak] docs for more info on add tweak and how to use it.
322+
///
323+
/// To get the proprietary field use:
324+
/// ```
325+
/// use bitcoin::psbt::{PartiallySignedTransaction};
326+
/// use bitcoin::hashes::hex::FromHex;
327+
///
328+
/// # let s = "70736274ff0100520200000001dee978529ab3e61a2987bea5183713d0e6d5ceb5ac81100fdb54a1a2\
329+
/// # 69cef505000000000090000000011f26000000000000160014abb3ab63280d4ccc5c11d6b50fd427a8\
330+
/// # e19d6470000000000001012b10270000000000002200200afe4736760d814a2651bae63b572d935d9a\
331+
/// # b74a1a16c01774e341a32afa763601054d63210394a27a700617f5b7aee72bd4f8076b5770a582b7fb\
332+
/// # d1d4ee2ea3802cd3cfbe2067029000b27521034629b1c8fdebfaeb58a74cd181f485e2c462e594cb30\
333+
/// # 34dee655875f69f6c7c968ac20fc144c444b5f7370656e6461626c655f6f7574707574006164645f74\
334+
/// # 7765616b20a86534f38ad61dc580ef41c3886204adf0911b81619c1ad7a2f5b5de39a2ba600000";
335+
/// # let psbt = PartiallySignedTransaction::deserialize(<Vec<u8> as FromHex>::from_hex(s).unwrap().as_slice()).unwrap();
336+
/// let key = bitcoin::psbt::raw::ProprietaryKey {
337+
/// prefix: "LDK_spendable_output".as_bytes().to_vec(),
338+
/// subtype: 0,
339+
/// key: "add_tweak".as_bytes().to_vec(),
340+
/// };
341+
/// let value = psbt
342+
/// .inputs
343+
/// .first()
344+
/// .expect("Unable to get add tweak as there are no inputs")
345+
/// .proprietary
346+
/// .get(&key)
347+
/// .map(|x| x.to_owned());
348+
/// ```
349+
pub fn to_psbt_input<T: secp256k1::Signing>(
350+
&self, secp_ctx: &Secp256k1<T>,
351+
) -> bitcoin::psbt::Input {
310352
match self {
311353
SpendableOutputDescriptor::StaticOutput { output, .. } => {
312354
// Is a standard P2WPKH, no need for witness script
313355
bitcoin::psbt::Input { witness_utxo: Some(output.clone()), ..Default::default() }
314356
},
315-
SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
316-
// TODO we could add the witness script as well
357+
SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
358+
channel_transaction_parameters,
359+
per_commitment_point,
360+
revocation_pubkey,
361+
to_self_delay,
362+
output,
363+
..
364+
}) => {
365+
let delayed_payment_basepoint = channel_transaction_parameters
366+
.as_ref()
367+
.map(|params| params.holder_pubkeys.delayed_payment_basepoint);
368+
369+
let (witness_script, add_tweak) =
370+
if let Some(basepoint) = delayed_payment_basepoint.as_ref() {
371+
let payment_key = DelayedPaymentKey::from_basepoint(
372+
secp_ctx,
373+
basepoint,
374+
&per_commitment_point,
375+
);
376+
// Required to derive signing key: privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
377+
let add_tweak = basepoint.derive_add_tweak(&per_commitment_point);
378+
(
379+
Some(get_revokeable_redeemscript(
380+
&revocation_pubkey,
381+
*to_self_delay,
382+
&payment_key,
383+
)),
384+
Some(add_tweak),
385+
)
386+
} else {
387+
(None, None)
388+
};
389+
317390
bitcoin::psbt::Input {
318-
witness_utxo: Some(descriptor.output.clone()),
391+
witness_utxo: Some(output.clone()),
392+
witness_script,
393+
proprietary: add_tweak
394+
.map(|add_tweak| {
395+
vec![(
396+
bitcoin::psbt::raw::ProprietaryKey {
397+
// A non standard namespace for spendable outputs, used to store the tweak needed
398+
// to derive the private key
399+
prefix: "LDK_spendable_output".as_bytes().to_vec(),
400+
subtype: 0,
401+
key: "add_tweak".as_bytes().to_vec(),
402+
},
403+
add_tweak.to_vec(),
404+
)]
405+
.into_iter()
406+
.collect()
407+
})
408+
.unwrap_or_default(),
319409
..Default::default()
320410
}
321411
},
322412
SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
323-
// TODO we could add the witness script as well
413+
let witness_script = if let Some(true) =
414+
descriptor.channel_transaction_parameters.as_ref().and_then(|channel_params| {
415+
Some(
416+
channel_params
417+
.channel_type_features
418+
.supports_anchors_zero_fee_htlc_tx(),
419+
)
420+
}) {
421+
descriptor.witness_script()
422+
} else {
423+
descriptor.channel_transaction_parameters.as_ref().and_then(|channel_params| {
424+
// Use simplified derivation, assuming `option_static_remotekey` is negotiated.
425+
// `remote_payment_basepoint` is used as Payment Key.
426+
let payment_point = channel_params.holder_pubkeys.payment_point;
427+
Some(ScriptBuf::new_p2pkh(
428+
&bitcoin::PublicKey::new(payment_point).pubkey_hash(),
429+
))
430+
})
431+
};
432+
// With simplified derivation, the private payment key is equal to private payment basepoint,
433+
// so add tweak is not needed.
324434
bitcoin::psbt::Input {
325435
witness_utxo: Some(descriptor.output.clone()),
436+
witness_script,
326437
..Default::default()
327438
}
328439
},
@@ -345,8 +456,8 @@ impl SpendableOutputDescriptor {
345456
/// does not match the one we can spend.
346457
///
347458
/// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
348-
pub fn create_spendable_outputs_psbt(
349-
descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>,
459+
pub fn create_spendable_outputs_psbt<T: secp256k1::Signing>(
460+
secp_ctx: &Secp256k1<T>, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>,
350461
change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32,
351462
locktime: Option<LockTime>,
352463
) -> Result<(PartiallySignedTransaction, u64), ()> {
@@ -438,7 +549,8 @@ impl SpendableOutputDescriptor {
438549
change_destination_script,
439550
)?;
440551

441-
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input()).collect::<Vec<_>>();
552+
let psbt_inputs =
553+
descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx)).collect::<Vec<_>>();
442554
let psbt = PartiallySignedTransaction {
443555
inputs: psbt_inputs,
444556
outputs: vec![Default::default(); tx.output.len()],
@@ -2024,6 +2136,51 @@ impl KeysManager {
20242136

20252137
Ok(psbt)
20262138
}
2139+
2140+
/// Creates a [`Transaction`] which spends the given descriptors to the given outputs, plus an
2141+
/// output to the given change destination (if sufficient change value remains). The
2142+
/// transaction will have a feerate, at least, of the given value.
2143+
///
2144+
/// The `locktime` argument is used to set the transaction's locktime. If `None`, the
2145+
/// transaction will have a locktime of 0. It it recommended to set this to the current block
2146+
/// height to avoid fee sniping, unless you have some specific reason to use a different
2147+
/// locktime.
2148+
///
2149+
/// Returns `Err(())` if the output value is greater than the input value minus required fee,
2150+
/// if a descriptor was duplicated, or if an output descriptor `script_pubkey`
2151+
/// does not match the one we can spend.
2152+
///
2153+
/// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
2154+
///
2155+
/// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
2156+
/// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
2157+
pub fn spend_spendable_outputs<C: Signing>(
2158+
&self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>,
2159+
change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32,
2160+
locktime: Option<LockTime>, secp_ctx: &Secp256k1<C>,
2161+
) -> Result<Transaction, ()> {
2162+
let (mut psbt, expected_max_weight) =
2163+
SpendableOutputDescriptor::create_spendable_outputs_psbt(
2164+
&self.secp_ctx,
2165+
descriptors,
2166+
outputs,
2167+
change_destination_script,
2168+
feerate_sat_per_1000_weight,
2169+
locktime,
2170+
)?;
2171+
psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?;
2172+
2173+
let spend_tx = psbt.extract_tx();
2174+
2175+
debug_assert!(expected_max_weight >= spend_tx.weight().to_wu());
2176+
// Note that witnesses with a signature vary somewhat in size, so allow
2177+
// `expected_max_weight` to overshoot by up to 3 bytes per input.
2178+
debug_assert!(
2179+
expected_max_weight <= spend_tx.weight().to_wu() + descriptors.len() as u64 * 3
2180+
);
2181+
2182+
Ok(spend_tx)
2183+
}
20272184
}
20282185

20292186
impl EntropySource for KeysManager {
@@ -2112,6 +2269,7 @@ impl OutputSpender for KeysManager {
21122269
) -> Result<Transaction, ()> {
21132270
let (mut psbt, expected_max_weight) =
21142271
SpendableOutputDescriptor::create_spendable_outputs_psbt(
2272+
secp_ctx,
21152273
descriptors,
21162274
outputs,
21172275
change_destination_script,

0 commit comments

Comments
 (0)