Skip to content

Commit e20cce3

Browse files
committed
Extend BaseSign with HTLC output signing support for external claims
1 parent f0775f8 commit e20cce3

File tree

3 files changed

+68
-21
lines changed

3 files changed

+68
-21
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,14 @@ pub trait BaseSign {
324324
/// (which is committed to in the BIP 143 signatures).
325325
fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
326326

327+
#[cfg(anchors)]
328+
/// Computes the signature for a commitment transaction's HTLC output used as an input within
329+
/// `htlc_tx`, which spends the commitment transaction, at index `input`.
330+
fn sign_holder_htlc_transaction(
331+
&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_number: u64,
332+
witness_script: &Script, secp_ctx: &Secp256k1<secp256k1::All>
333+
) -> Result<Signature, ()>;
334+
327335
/// Create a signature for a claiming transaction for a HTLC output on a counterparty's commitment
328336
/// transaction, either offered or received.
329337
///
@@ -671,7 +679,6 @@ impl InMemorySigner {
671679
witness.push(witness_script.clone().into_bytes());
672680
Ok(witness)
673681
}
674-
675682
}
676683

677684
impl BaseSign for InMemorySigner {
@@ -767,6 +774,21 @@ impl BaseSign for InMemorySigner {
767774
return Ok(sign(secp_ctx, &sighash, &revocation_key))
768775
}
769776

777+
#[cfg(anchors)]
778+
fn sign_holder_htlc_transaction(
779+
&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_number: u64,
780+
witness_script: &Script, secp_ctx: &Secp256k1<secp256k1::All>
781+
) -> Result<Signature, ()> {
782+
let per_commitment_point = self.get_per_commitment_point(per_commitment_number, &secp_ctx);
783+
let our_htlc_key = chan_utils::derive_private_key(
784+
&secp_ctx, &per_commitment_point, &self.htlc_base_key
785+
).map_err(|_| ())?;
786+
let sighash = &sighash::SighashCache::new(&*htlc_tx).segwit_signature_hash(
787+
input, witness_script, amount, EcdsaSighashType::All
788+
).map_err(|_| ())?;
789+
Ok(sign(&secp_ctx, &hash_to_message!(sighash), &our_htlc_key))
790+
}
791+
770792
fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
771793
if let Ok(htlc_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key) {
772794
let witness_script = if let Ok(revocation_pubkey) = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint) {

lightning/src/ln/chan_utils.rs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,36 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte
698698
}
699699
}
700700

701+
pub fn build_htlc_input_witness(
702+
local_sig: &Signature, remote_sig: &Signature, preimage: &Option<PaymentPreimage>, redeem_script: &Script,
703+
opt_anchors: bool,
704+
) -> Witness {
705+
let remote_sighash_type = if opt_anchors {
706+
EcdsaSighashType::SinglePlusAnyoneCanPay
707+
} else {
708+
EcdsaSighashType::All
709+
};
710+
let mut remote_sig = remote_sig.serialize_der().to_vec();
711+
remote_sig.push(remote_sighash_type as u8);
712+
713+
let mut local_sig = local_sig.serialize_der().to_vec();
714+
local_sig.push(EcdsaSighashType::All as u8);
715+
716+
let mut witness_vec = Vec::with_capacity(5);
717+
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
718+
witness_vec.push(vec![]);
719+
witness_vec.push(remote_sig);
720+
witness_vec.push(local_sig);
721+
if let Some(preimage) = preimage {
722+
witness_vec.push(preimage.0.to_vec());
723+
} else {
724+
// Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
725+
witness_vec.push(vec![]);
726+
}
727+
witness_vec.push(redeem_script.to_bytes());
728+
Witness::from_vec(witness_vec)
729+
}
730+
701731
/// Gets the witnessScript for the to_remote output when anchors are enabled.
702732
#[inline]
703733
pub(crate) fn get_to_countersignatory_with_anchors_redeemscript(payment_point: &PublicKey) -> Script {
@@ -1518,26 +1548,9 @@ impl<'a> TrustedCommitmentTransaction<'a> {
15181548

15191549
let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
15201550

1521-
let sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
1522-
1523-
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
1524-
htlc_tx.input[0].witness.push(Vec::new());
1525-
1526-
let mut cp_sig_ser = counterparty_signature.serialize_der().to_vec();
1527-
cp_sig_ser.push(sighashtype as u8);
1528-
htlc_tx.input[0].witness.push(cp_sig_ser);
1529-
let mut holder_sig_ser = signature.serialize_der().to_vec();
1530-
holder_sig_ser.push(EcdsaSighashType::All as u8);
1531-
htlc_tx.input[0].witness.push(holder_sig_ser);
1532-
1533-
if this_htlc.offered {
1534-
// Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
1535-
htlc_tx.input[0].witness.push(Vec::new());
1536-
} else {
1537-
htlc_tx.input[0].witness.push(preimage.unwrap().0.to_vec());
1538-
}
1539-
1540-
htlc_tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec());
1551+
htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness(
1552+
signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(),
1553+
);
15411554
htlc_tx
15421555
}
15431556
}

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use core::cmp;
1717
use crate::sync::{Mutex, Arc};
1818
#[cfg(test)] use crate::sync::MutexGuard;
1919

20+
#[cfg(anchors)]
21+
use bitcoin::Script;
2022
use bitcoin::blockdata::transaction::{Transaction, EcdsaSighashType};
2123
use bitcoin::util::sighash;
2224

@@ -190,6 +192,16 @@ impl BaseSign for EnforcingSigner {
190192
Ok(self.inner.sign_justice_revoked_htlc(justice_tx, input, amount, per_commitment_key, htlc, secp_ctx).unwrap())
191193
}
192194

195+
#[cfg(anchors)]
196+
fn sign_holder_htlc_transaction(
197+
&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_number: u64,
198+
witness_script: &Script, secp_ctx: &Secp256k1<secp256k1::All>
199+
) -> Result<Signature, ()> {
200+
Ok(self.inner.sign_holder_htlc_transaction(
201+
htlc_tx, input, amount, per_commitment_number, witness_script, secp_ctx
202+
).unwrap())
203+
}
204+
193205
fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
194206
Ok(self.inner.sign_counterparty_htlc_transaction(htlc_tx, input, amount, per_commitment_point, htlc, secp_ctx).unwrap())
195207
}

0 commit comments

Comments
 (0)