Skip to content

Commit e2e1628

Browse files
committed
Sign local HTLC transactions at broadcast-time, instead of generate
1 parent eb97a75 commit e2e1628

File tree

3 files changed

+113
-168
lines changed

3 files changed

+113
-168
lines changed

lightning/src/ln/chan_utils.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bitcoin_hashes::ripemd160::Hash as Ripemd160;
1414
use bitcoin_hashes::hash160::Hash as Hash160;
1515
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
1616

17-
use ln::channelmanager::PaymentHash;
17+
use ln::channelmanager::{PaymentHash, PaymentPreimage};
1818
use ln::msgs::DecodeError;
1919
use util::ser::{Readable, Writeable, Writer, WriterWriteAdaptor};
2020

@@ -63,7 +63,9 @@ pub(super) fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>,
6363
base_point.combine(&hashkey)
6464
}
6565

66-
/// Derives a revocation key from its constituent parts
66+
/// Derives a revocation key from its constituent parts.
67+
/// Note that this is infallible iff we trust that at least one of the two input keys are randomly
68+
/// generated (ie our own).
6769
pub(super) fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
6870
let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret);
6971
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
@@ -286,6 +288,43 @@ pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_s
286288
}
287289
}
288290

291+
/// Signs a transaction created by build_htlc_transaction. If the transaction is an
292+
/// HTLC-Success transaction (ie htlc.offered is false), preimage must be set!
293+
pub(crate) fn sign_htlc_transaction<T: secp256k1::Signing>(tx: &mut Transaction, their_sig: &Signature, preimage: &Option<PaymentPreimage>, htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey, per_commitment_point: &PublicKey, htlc_base_key: &SecretKey, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Script), ()> {
294+
if tx.input.len() != 1 { return Err(()); }
295+
if tx.input[0].witness.len() != 0 { return Err(()); }
296+
297+
let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&htlc, a_htlc_key, b_htlc_key, revocation_key);
298+
299+
let our_htlc_key = derive_private_key(secp_ctx, per_commitment_point, htlc_base_key).map_err(|_| ())?;
300+
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
301+
let local_tx = PublicKey::from_secret_key(&secp_ctx, &our_htlc_key) == *a_htlc_key;
302+
let our_sig = secp_ctx.sign(&sighash, &our_htlc_key);
303+
304+
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
305+
306+
if local_tx { // b, then a
307+
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
308+
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
309+
} else {
310+
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
311+
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
312+
}
313+
tx.input[0].witness[1].push(SigHashType::All as u8);
314+
tx.input[0].witness[2].push(SigHashType::All as u8);
315+
316+
if htlc.offered {
317+
tx.input[0].witness.push(Vec::new());
318+
assert!(preimage.is_none());
319+
} else {
320+
tx.input[0].witness.push(preimage.unwrap().0.to_vec());
321+
}
322+
323+
tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec());
324+
325+
Ok((our_sig, htlc_redeemscript))
326+
}
327+
289328
#[derive(Clone)]
290329
/// We use this to track local commitment transactions and put off signing them until we are ready
291330
/// to broadcast. Eventually this will require a signer which is possibly external, but for now we

lightning/src/ln/channel.rs

+2-53
Original file line numberDiff line numberDiff line change
@@ -1129,56 +1129,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
11291129
chan_utils::build_htlc_transaction(prev_hash, feerate_per_kw, if local { self.their_to_self_delay } else { self.our_to_self_delay }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key)
11301130
}
11311131

1132-
fn create_htlc_tx_signature(&self, tx: &Transaction, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<(Script, Signature, bool), ChannelError> {
1133-
if tx.input.len() != 1 {
1134-
panic!("Tried to sign HTLC transaction that had input count != 1!");
1135-
}
1136-
1137-
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
1138-
1139-
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, self.local_keys.htlc_base_key()), "Derived invalid key, peer is maliciously selecting parameters");
1140-
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
1141-
let is_local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key) == keys.a_htlc_key;
1142-
Ok((htlc_redeemscript, self.secp_ctx.sign(&sighash, &our_htlc_key), is_local_tx))
1143-
}
1144-
1145-
#[cfg(test)]
1146-
/// Signs a transaction created by build_htlc_transaction. If the transaction is an
1147-
/// HTLC-Success transaction (ie htlc.offered is false), preimage must be set!
1148-
/// TODO: Make this a chan_utils, use it in channelmonitor and tests, cause its unused now
1149-
fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option<PaymentPreimage>, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<Signature, ChannelError> {
1150-
if tx.input.len() != 1 {
1151-
panic!("Tried to sign HTLC transaction that had input count != 1!");
1152-
}
1153-
if tx.input[0].witness.len() != 0 {
1154-
panic!("Tried to re-sign HTLC transaction");
1155-
}
1156-
1157-
let (htlc_redeemscript, our_sig, local_tx) = self.create_htlc_tx_signature(tx, htlc, keys)?;
1158-
1159-
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
1160-
1161-
if local_tx { // b, then a
1162-
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
1163-
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
1164-
} else {
1165-
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
1166-
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
1167-
}
1168-
tx.input[0].witness[1].push(SigHashType::All as u8);
1169-
tx.input[0].witness[2].push(SigHashType::All as u8);
1170-
1171-
if htlc.offered {
1172-
tx.input[0].witness.push(Vec::new());
1173-
} else {
1174-
tx.input[0].witness.push(preimage.unwrap().0.to_vec());
1175-
}
1176-
1177-
tx.input[0].witness.push(htlc_redeemscript.into_bytes());
1178-
1179-
Ok(our_sig)
1180-
}
1181-
11821132
/// Per HTLC, only one get_update_fail_htlc or get_update_fulfill_htlc call may be made.
11831133
/// In such cases we debug_assert!(false) and return an IgnoreError. Thus, will always return
11841134
/// Ok(_) if debug assertions are turned on and preconditions are met.
@@ -1822,8 +1772,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18221772
log_trace!(self, "Checking HTLC tx signature {} by key {} against tx {} with redeemscript {}", log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(local_keys.b_htlc_key.serialize()), encode::serialize_hex(&htlc_tx), encode::serialize_hex(&htlc_redeemscript));
18231773
let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
18241774
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
1825-
let htlc_sig = self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1;
1826-
htlcs_and_sigs.push((htlc, Some((msg.htlc_signatures[idx], htlc_sig)), source));
1775+
htlcs_and_sigs.push((htlc, Some(msg.htlc_signatures[idx]), source));
18271776
} else {
18281777
htlcs_and_sigs.push((htlc, None, source));
18291778
}
@@ -4265,7 +4214,7 @@ mod tests {
42654214
assert!(preimage.is_some());
42664215
}
42674216

4268-
chan.sign_htlc_transaction(&mut htlc_tx, &remote_signature, &preimage, &htlc, &keys).unwrap();
4217+
chan_utils::sign_htlc_transaction(&mut htlc_tx, &remote_signature, &preimage, &htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key, &keys.per_commitment_point, chan.local_keys.htlc_base_key(), &chan.secp_ctx).unwrap();
42694218
assert_eq!(serialize(&htlc_tx)[..],
42704219
hex::decode($tx_hex).unwrap()[..]);
42714220
};

0 commit comments

Comments
 (0)