Skip to content

Commit 093fcab

Browse files
authored
Merge pull request #664 from lightning-signer/tx-creation-keys
Wrap transaction creation keys
2 parents 99eef23 + 8058202 commit 093fcab

File tree

5 files changed

+62
-20
lines changed

5 files changed

+62
-20
lines changed

lightning/src/chain/keysinterface.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use util::byte_utils;
2323
use util::ser::{Writeable, Writer, Readable};
2424

2525
use ln::chan_utils;
26-
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, LocalCommitmentTransaction};
26+
use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, LocalCommitmentTransaction, PreCalculatedTxCreationKeys};
2727
use ln::msgs;
2828

2929
use std::sync::atomic::{AtomicUsize, Ordering};
@@ -223,7 +223,7 @@ pub trait ChannelKeys : Send+Clone {
223223
// TODO: Document the things someone using this interface should enforce before signing.
224224
// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
225225
// making the callee generate it via some util function we expose)!
226-
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u32, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
226+
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u32, commitment_tx: &Transaction, keys: &PreCalculatedTxCreationKeys, htlcs: &[&HTLCOutputInCommitment], secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
227227

228228
/// Create a signature for a local commitment transaction. This will only ever be called with
229229
/// the same local_commitment_tx (or a copy thereof), though there are currently no guarantees
@@ -461,8 +461,9 @@ impl ChannelKeys for InMemoryChannelKeys {
461461
fn pubkeys(&self) -> &ChannelPublicKeys { &self.local_channel_pubkeys }
462462
fn key_derivation_params(&self) -> (u64, u64) { self.key_derivation_params }
463463

464-
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u32, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
464+
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u32, commitment_tx: &Transaction, pre_keys: &PreCalculatedTxCreationKeys, htlcs: &[&HTLCOutputInCommitment], secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
465465
if commitment_tx.input.len() != 1 { return Err(()); }
466+
let keys = pre_keys.trust_key_derivation();
466467

467468
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
468469
let accepted_data = self.accepted_channel_data.as_ref().expect("must accept before signing");

lightning/src/ln/chan_utils.rs

+42-7
Original file line numberDiff line numberDiff line change
@@ -267,23 +267,52 @@ pub fn derive_public_revocation_key<T: secp256k1::Verification>(secp_ctx: &Secp2
267267

268268
/// The set of public keys which are used in the creation of one commitment transaction.
269269
/// These are derived from the channel base keys and per-commitment data.
270+
///
271+
/// These keys are assumed to be good, either because the code derived them from
272+
/// channel basepoints via the new function, or they were obtained via
273+
/// PreCalculatedTxCreationKeys.trust_key_derivation because we trusted the source of the
274+
/// pre-calculated keys.
270275
#[derive(PartialEq, Clone)]
271276
pub struct TxCreationKeys {
272277
/// The per-commitment public key which was used to derive the other keys.
273278
pub per_commitment_point: PublicKey,
274279
/// The revocation key which is used to allow the owner of the commitment transaction to
275280
/// provide their counterparty the ability to punish them if they broadcast an old state.
276-
pub(crate) revocation_key: PublicKey,
281+
pub revocation_key: PublicKey,
277282
/// A's HTLC Key
278-
pub(crate) a_htlc_key: PublicKey,
283+
pub a_htlc_key: PublicKey,
279284
/// B's HTLC Key
280-
pub(crate) b_htlc_key: PublicKey,
285+
pub b_htlc_key: PublicKey,
281286
/// A's Payment Key (which isn't allowed to be spent from for some delay)
282-
pub(crate) a_delayed_payment_key: PublicKey,
287+
pub a_delayed_payment_key: PublicKey,
283288
}
284289
impl_writeable!(TxCreationKeys, 33*6,
285290
{ per_commitment_point, revocation_key, a_htlc_key, b_htlc_key, a_delayed_payment_key });
286291

292+
/// The per-commitment point and a set of pre-calculated public keys used for transaction creation
293+
/// in the signer.
294+
/// The pre-calculated keys are an optimization, because ChannelKeys has enough
295+
/// information to re-derive them.
296+
pub struct PreCalculatedTxCreationKeys(TxCreationKeys);
297+
298+
impl PreCalculatedTxCreationKeys {
299+
/// Create a new PreCalculatedTxCreationKeys from TxCreationKeys
300+
pub fn new(keys: TxCreationKeys) -> Self {
301+
PreCalculatedTxCreationKeys(keys)
302+
}
303+
304+
/// The pre-calculated transaction creation public keys.
305+
/// An external validating signer should not trust these keys.
306+
pub fn trust_key_derivation(&self) -> &TxCreationKeys {
307+
&self.0
308+
}
309+
310+
/// The transaction per-commitment point
311+
pub fn per_comitment_point(&self) -> &PublicKey {
312+
&self.0.per_commitment_point
313+
}
314+
}
315+
287316
/// One counterparty's public keys which do not change over the life of a channel.
288317
#[derive(Clone, PartialEq)]
289318
pub struct ChannelPublicKeys {
@@ -318,7 +347,8 @@ impl_writeable!(ChannelPublicKeys, 33*5, {
318347

319348

320349
impl TxCreationKeys {
321-
pub(crate) fn new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_htlc_base: &PublicKey) -> Result<TxCreationKeys, secp256k1::Error> {
350+
/// Create a new TxCreationKeys from channel base points and the per-commitment point
351+
pub fn new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_htlc_base: &PublicKey) -> Result<TxCreationKeys, secp256k1::Error> {
322352
Ok(TxCreationKeys {
323353
per_commitment_point: per_commitment_point.clone(),
324354
revocation_key: derive_public_revocation_key(&secp_ctx, &per_commitment_point, &b_revocation_base)?,
@@ -510,8 +540,7 @@ pub struct LocalCommitmentTransaction {
510540
// Which order the signatures should go in when constructing the final commitment tx witness.
511541
// The user should be able to reconstruc this themselves, so we don't bother to expose it.
512542
our_sig_first: bool,
513-
/// The key derivation parameters for this commitment transaction
514-
pub local_keys: TxCreationKeys,
543+
pub(crate) local_keys: TxCreationKeys,
515544
/// The feerate paid per 1000-weight-unit in this commitment transaction. This value is
516545
/// controlled by the channel initiator.
517546
pub feerate_per_kw: u32,
@@ -576,6 +605,12 @@ impl LocalCommitmentTransaction {
576605
}
577606
}
578607

608+
/// The pre-calculated transaction creation public keys.
609+
/// An external validating signer should not trust these keys.
610+
pub fn trust_key_derivation(&self) -> &TxCreationKeys {
611+
&self.local_keys
612+
}
613+
579614
/// Get the txid of the local commitment transaction contained in this
580615
/// LocalCommitmentTransaction
581616
pub fn txid(&self) -> Txid {

lightning/src/ln/channel.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ln::msgs;
1919
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
2020
use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER};
2121
use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
22-
use ln::chan_utils::{CounterpartyCommitmentSecrets, LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys};
22+
use ln::chan_utils::{CounterpartyCommitmentSecrets, LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, PreCalculatedTxCreationKeys};
2323
use ln::chan_utils;
2424
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
2525
use chain::transaction::OutPoint;
@@ -1484,7 +1484,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14841484

14851485
let remote_keys = self.build_remote_transaction_keys()?;
14861486
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw, logger).0;
1487-
let remote_signature = self.local_keys.sign_remote_commitment(self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), &self.secp_ctx)
1487+
let pre_remote_keys = PreCalculatedTxCreationKeys::new(remote_keys);
1488+
let remote_signature = self.local_keys.sign_remote_commitment(self.feerate_per_kw, &remote_initial_commitment_tx, &pre_remote_keys, &Vec::new(), &self.secp_ctx)
14881489
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0;
14891490

14901491
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
@@ -3532,7 +3533,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
35323533
fn get_outbound_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ChannelError> where L::Target: Logger {
35333534
let remote_keys = self.build_remote_transaction_keys()?;
35343535
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw, logger).0;
3535-
Ok(self.local_keys.sign_remote_commitment(self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), &self.secp_ctx)
3536+
let pre_remote_keys = PreCalculatedTxCreationKeys::new(remote_keys);
3537+
Ok(self.local_keys.sign_remote_commitment(self.feerate_per_kw, &remote_initial_commitment_tx, &pre_remote_keys, &Vec::new(), &self.secp_ctx)
35363538
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0)
35373539
}
35383540

@@ -3885,10 +3887,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
38853887
htlcs.push(htlc);
38863888
}
38873889

3888-
let res = self.local_keys.sign_remote_commitment(feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, &self.secp_ctx)
3890+
let pre_remote_keys = PreCalculatedTxCreationKeys::new(remote_keys);
3891+
let res = self.local_keys.sign_remote_commitment(feerate_per_kw, &remote_commitment_tx.0, &pre_remote_keys, &htlcs, &self.secp_ctx)
38893892
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?;
38903893
signature = res.0;
38913894
htlc_signatures = res.1;
3895+
let remote_keys = pre_remote_keys.trust_key_derivation();
38923896

38933897
log_trace!(logger, "Signed remote commitment tx {} with redeemscript {} -> {}",
38943898
encode::serialize_hex(&remote_commitment_tx.0),
@@ -3898,7 +3902,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
38983902
for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
38993903
log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {}",
39003904
encode::serialize_hex(&chan_utils::build_htlc_transaction(&remote_commitment_tx.0.txid(), feerate_per_kw, self.our_to_self_delay, htlc, &remote_keys.a_delayed_payment_key, &remote_keys.revocation_key)),
3901-
encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &remote_keys)),
3905+
encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, remote_keys)),
39023906
log_bytes!(remote_keys.a_htlc_key.serialize()),
39033907
log_bytes!(htlc_sig.serialize_compact()[..]));
39043908
}

lightning/src/ln/functional_tests.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use std::sync::atomic::Ordering;
5252
use std::{mem, io};
5353

5454
use ln::functional_test_utils::*;
55+
use ln::chan_utils::PreCalculatedTxCreationKeys;
5556

5657
#[test]
5758
fn test_insane_channel_opens() {
@@ -1694,7 +1695,8 @@ fn test_fee_spike_violation_fails_htlc() {
16941695
let local_chan_lock = nodes[0].node.channel_state.lock().unwrap();
16951696
let local_chan = local_chan_lock.by_id.get(&chan.2).unwrap();
16961697
let local_chan_keys = local_chan.get_local_keys();
1697-
local_chan_keys.sign_remote_commitment(feerate_per_kw, &commit_tx, &commit_tx_keys, &[&accepted_htlc_info], &secp_ctx).unwrap()
1698+
let pre_commit_tx_keys = PreCalculatedTxCreationKeys::new(commit_tx_keys);
1699+
local_chan_keys.sign_remote_commitment(feerate_per_kw, &commit_tx, &pre_commit_tx_keys, &[&accepted_htlc_info], &secp_ctx).unwrap()
16981700
};
16991701

17001702
let commit_signed_msg = msgs::CommitmentSigned {

lightning/src/util/enforcing_trait_impls.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys, ChannelPublicKeys, LocalCommitmentTransaction};
1+
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys, ChannelPublicKeys, LocalCommitmentTransaction, PreCalculatedTxCreationKeys};
22
use ln::{chan_utils, msgs};
33
use chain::keysinterface::{ChannelKeys, InMemoryChannelKeys};
44

@@ -60,9 +60,9 @@ impl ChannelKeys for EnforcingChannelKeys {
6060
fn pubkeys(&self) -> &ChannelPublicKeys { self.inner.pubkeys() }
6161
fn key_derivation_params(&self) -> (u64, u64) { self.inner.key_derivation_params() }
6262

63-
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u32, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
63+
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u32, commitment_tx: &Transaction, pre_keys: &PreCalculatedTxCreationKeys, htlcs: &[&HTLCOutputInCommitment], secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
6464
if commitment_tx.input.len() != 1 { panic!("lightning commitment transactions have a single input"); }
65-
self.check_keys(secp_ctx, keys);
65+
self.check_keys(secp_ctx, pre_keys.trust_key_derivation());
6666
let obscured_commitment_transaction_number = (commitment_tx.lock_time & 0xffffff) as u64 | ((commitment_tx.input[0].sequence as u64 & 0xffffff) << 3*8);
6767

6868
{
@@ -75,7 +75,7 @@ impl ChannelKeys for EnforcingChannelKeys {
7575
commitment_data.1 = cmp::max(commitment_number, commitment_data.1)
7676
}
7777

78-
Ok(self.inner.sign_remote_commitment(feerate_per_kw, commitment_tx, keys, htlcs, secp_ctx).unwrap())
78+
Ok(self.inner.sign_remote_commitment(feerate_per_kw, commitment_tx, pre_keys, htlcs, secp_ctx).unwrap())
7979
}
8080

8181
fn sign_local_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &LocalCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {

0 commit comments

Comments
 (0)