Skip to content

Commit 1e5c85c

Browse files
committed
Implement Script for Witness and Add Tweak in Partially Signed Bitcoin Transaction to make it a single data source needed for a Signer to produce valid signatures.
1 parent c2bbfff commit 1e5c85c

File tree

1 file changed

+50
-8
lines changed

1 file changed

+50
-8
lines changed

lightning/src/sign/mod.rs

+50-8
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;
@@ -43,7 +43,7 @@ use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs};
4343
use crate::chain::transaction::OutPoint;
4444
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)]
@@ -149,6 +149,7 @@ pub struct StaticPaymentOutputDescriptor {
149149
/// Added as optional, but always `Some` if the descriptor was produced in v0.0.117 or later.
150150
pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
151151
}
152+
152153
impl StaticPaymentOutputDescriptor {
153154
/// Returns the `witness_script` of the spendable output.
154155
///
@@ -304,7 +305,7 @@ impl SpendableOutputDescriptor {
304305
///
305306
/// This is not exported to bindings users as there is no standard serialization for an input.
306307
/// See [`Self::create_spendable_outputs_psbt`] instead.
307-
pub fn to_psbt_input(&self) -> bitcoin::psbt::Input {
308+
pub fn to_psbt_input<T: secp256k1::Signing>(&self, secp_ctx: &Secp256k1<T>, delayed_payment_basepoint: Option<&DelayedPaymentBasepoint>) -> bitcoin::psbt::Input {
308309
match self {
309310
SpendableOutputDescriptor::StaticOutput { output, .. } => {
310311
// Is a standard P2WPKH, no need for witness script
@@ -314,9 +315,21 @@ impl SpendableOutputDescriptor {
314315
}
315316
},
316317
SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) => {
317-
// TODO we could add the witness script as well
318+
let witness_script = delayed_payment_basepoint.map(|basepoint| {
319+
let payment_key = DelayedPaymentKey::from_basepoint(
320+
secp_ctx,
321+
basepoint,
322+
&descriptor.per_commitment_point,
323+
);
324+
get_revokeable_redeemscript(
325+
&descriptor.revocation_pubkey,
326+
descriptor.to_self_delay,
327+
&payment_key,
328+
)
329+
});
318330
bitcoin::psbt::Input {
319331
witness_utxo: Some(descriptor.output.clone()),
332+
witness_script: witness_script,
320333
..Default::default()
321334
}
322335
},
@@ -330,6 +343,7 @@ impl SpendableOutputDescriptor {
330343
}
331344
}
332345

346+
333347
/// Creates an unsigned [`PartiallySignedTransaction`] which spends the given descriptors to
334348
/// the given outputs, plus an output to the given change destination (if sufficient
335349
/// change value remains). The PSBT will have a feerate, at least, of the given value.
@@ -346,11 +360,14 @@ impl SpendableOutputDescriptor {
346360
/// does not match the one we can spend.
347361
///
348362
/// 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), ()> {
363+
pub fn create_spendable_outputs_psbt(descriptors: &[&SpendableOutputDescriptor], outputs: Vec<TxOut>, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, locktime: Option<LockTime>, delayed_payment_basepoint: Option<&DelayedPaymentBasepoint>) -> Result<(PartiallySignedTransaction, u64), ()> {
364+
let secp_ctx = Secp256k1::new();
350365
let mut input = Vec::with_capacity(descriptors.len());
351366
let mut input_value = 0;
352367
let mut witness_weight = 0;
353368
let mut output_set = HashSet::with_capacity(descriptors.len());
369+
// Required to derive signing key: privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)
370+
let mut add_tweak: Option<Vec<u8>> = None;
354371
for outp in descriptors {
355372
match outp {
356373
SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
@@ -387,6 +404,8 @@ impl SpendableOutputDescriptor {
387404
#[cfg(feature = "grind_signatures")]
388405
{ witness_weight -= 1; } // Guarantees a low R signature
389406
input_value += descriptor.output.value;
407+
408+
add_tweak = delayed_payment_basepoint.and_then(|basepoint| Some(derive_add_tweak(&descriptor.per_commitment_point, &basepoint)));
390409
},
391410
SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output, .. } => {
392411
if !output_set.insert(*outpoint) { return Err(()); }
@@ -413,20 +432,43 @@ impl SpendableOutputDescriptor {
413432
let expected_max_weight =
414433
transaction_utils::maybe_add_change_output(&mut tx, input_value, witness_weight, feerate_sat_per_1000_weight, change_destination_script)?;
415434

416-
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input()).collect::<Vec<_>>();
435+
let psbt_inputs = descriptors.iter().map(|d| d.to_psbt_input(&secp_ctx, delayed_payment_basepoint)).collect::<Vec<_>>();
417436
let psbt = PartiallySignedTransaction {
418437
inputs: psbt_inputs,
419438
outputs: vec![Default::default(); tx.output.len()],
420439
unsigned_tx: tx,
421440
xpub: Default::default(),
422441
version: 0,
423-
proprietary: Default::default(),
442+
proprietary: add_tweak.map(|add_tweak| {vec![(
443+
raw::ProprietaryKey {
444+
prefix: "spendable_output".as_bytes().to_vec(),
445+
subtype: 0,
446+
key: "add_tweak".as_bytes().to_vec(),
447+
},
448+
add_tweak,
449+
)].into_iter().collect()}).unwrap_or_default(),
424450
unknown: Default::default(),
425451
};
426452
Ok((psbt, expected_max_weight))
427453
}
428454
}
429455

456+
/// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak
457+
/// from a delayed payment basepoint and a per_commitment_point:
458+
/// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)`
459+
/// TODO(oleg): refactor after migration to LDK v119
460+
pub fn derive_add_tweak(
461+
per_commitment_point: &PublicKey,
462+
basepoint: &DelayedPaymentBasepoint,
463+
) -> Vec<u8> {
464+
let mut sha = Sha256::engine();
465+
sha.input(&per_commitment_point.serialize());
466+
sha.input(&basepoint.to_public_key().serialize());
467+
let res = Sha256::from_engine(sha).to_byte_array();
468+
res.to_vec()
469+
}
470+
471+
430472
/// The parameters required to derive a channel signer via [`SignerProvider`].
431473
#[derive(Clone, Debug, PartialEq, Eq)]
432474
pub struct ChannelDerivationParameters {
@@ -1615,7 +1657,7 @@ impl KeysManager {
16151657
/// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used
16161658
/// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`].
16171659
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)?;
1660+
let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt(descriptors, outputs, change_destination_script, feerate_sat_per_1000_weight, locktime, None)?;
16191661
psbt = self.sign_spendable_outputs_psbt(descriptors, psbt, secp_ctx)?;
16201662

16211663
let spend_tx = psbt.extract_tx();

0 commit comments

Comments
 (0)