Skip to content

Commit b8cc17a

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 4deb263 commit b8cc17a

File tree

2 files changed

+83
-11
lines changed

2 files changed

+83
-11
lines changed

lightning/src/ln/channel_keys.rs

+13-1
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,7 +239,6 @@ impl RevocationKey {
226239
key_read_write!(RevocationKey);
227240

228241

229-
230242
#[cfg(test)]
231243
mod test {
232244
use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey};

lightning/src/sign/mod.rs

+70-10
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,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};
46-
use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
47-
use crate::ln::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint};
46+
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, PaymentBasepoint};
4848
use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage};
4949
#[cfg(taproot)]
5050
use crate::ln::msgs::PartialSignatureWithNonce;
@@ -104,6 +104,7 @@ pub struct DelayedPaymentOutputDescriptor {
104104
/// The value of the channel which this output originated from, possibly indirectly.
105105
pub channel_value_satoshis: u64,
106106
}
107+
107108
impl DelayedPaymentOutputDescriptor {
108109
/// The maximum length a well-formed witness spending one of these should have.
109110
/// Note: If you have the grind_signatures feature enabled, this will be at least 1 byte
@@ -149,6 +150,7 @@ pub struct StaticPaymentOutputDescriptor {
149150
/// Added as optional, but always `Some` if the descriptor was produced in v0.0.117 or later.
150151
pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
151152
}
153+
152154
impl StaticPaymentOutputDescriptor {
153155
/// Returns the `witness_script` of the spendable output.
154156
///
@@ -304,7 +306,7 @@ impl SpendableOutputDescriptor {
304306
///
305307
/// This is not exported to bindings users as there is no standard serialization for an input.
306308
/// See [`Self::create_spendable_outputs_psbt`] instead.
307-
pub fn to_psbt_input(&self) -> 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 {
308310
match self {
309311
SpendableOutputDescriptor::StaticOutput { output, .. } => {
310312
// Is a standard P2WPKH, no need for witness script
@@ -314,16 +316,72 @@ impl SpendableOutputDescriptor {
314316
}
315317
},
316318
SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
317-
// TODO we could add the witness script as well
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() {
324+
let payment_key = DelayedPaymentKey::from_basepoint(
325+
secp_ctx,
326+
basepoint,
327+
&descriptor.per_commitment_point,
328+
);
329+
// Required to derive signing key: privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
330+
let add_tweak = basepoint.derive_add_tweak(&descriptor.per_commitment_point);
331+
(Some(get_revokeable_redeemscript(
332+
&descriptor.revocation_pubkey,
333+
descriptor.to_self_delay,
334+
&payment_key,
335+
)), Some(add_tweak))
336+
} else {
337+
(None, None)
338+
};
339+
318340
bitcoin::psbt::Input {
319341
witness_utxo: Some(descriptor.output.clone()),
342+
witness_script,
343+
proprietary: add_tweak.map(|add_tweak| {vec![(
344+
raw::ProprietaryKey {
345+
prefix: "LDK_spendable_output".as_bytes().to_vec(),
346+
subtype: 0,
347+
key: "add_tweak".as_bytes().to_vec(),
348+
},
349+
add_tweak.to_vec(),
350+
)].into_iter().collect()}).unwrap_or_default(),
320351
..Default::default()
321352
}
322353
},
323354
SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
324-
// 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 as Payment 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+
325382
bitcoin::psbt::Input {
326383
witness_utxo: Some(descriptor.output.clone()),
384+
witness_script,
327385
..Default::default()
328386
}
329387
},
@@ -346,7 +404,8 @@ impl SpendableOutputDescriptor {
346404
/// does not match the one we can spend.
347405
///
348406
/// We do not enforce that outputs meet the dust limit or that any output scripts are standard.
349-
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), ()> {
407+
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), ()> {
408+
let secp_ctx = Secp256k1::new();
350409
let mut input = Vec::with_capacity(descriptors.len());
351410
let mut input_value = 0;
352411
let mut witness_weight = 0;
@@ -413,7 +472,7 @@ impl SpendableOutputDescriptor {
413472
let expected_max_weight =
414473
transaction_utils::maybe_add_change_output(&mut tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?;
415474

416-
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input()).collect::<Vec<_>>();
475+
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx, channel_public_keys)).collect::<Vec<_>>();
417476
let psbt = PartiallySignedTransaction {
418477
inputs: psbt_inputs,
419478
outputs: vec![Default::default(); tx.output.len()],
@@ -1615,7 +1674,8 @@ impl KeysManager {
16151674
/// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
16161675
/// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
16171676
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, ()> {
1618-
let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime)?;
1677+
// TODO: provide channel keys to construct witness script
1678+
let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime, None)?;
16191679
psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?;
16201680

16211681
let spend_tx = psbt.extract_tx();

0 commit comments

Comments
 (0)