Skip to content

Commit d2e6f2a

Browse files
committed
Make TxCreationKeys public and wrap it in PreCalculatedTxCreationKeys
Allows calling of InMemoryChannelKeys methods. The wrapping makes it obvious to signer implementers that the pre-derived keys are a local cache and should not be trusted in a validating signer.
1 parent d735a24 commit d2e6f2a

File tree

5 files changed

+53
-17
lines changed

5 files changed

+53
-17
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 4 additions & 3 deletions
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

Lines changed: 35 additions & 5 deletions
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)?,

lightning/src/ln/channel.rs

Lines changed: 7 additions & 4 deletions
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.
@@ -3525,7 +3526,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
35253526
fn get_outbound_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ChannelError> where L::Target: Logger {
35263527
let remote_keys = self.build_remote_transaction_keys()?;
35273528
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;
3528-
Ok(self.local_keys.sign_remote_commitment(self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), &self.secp_ctx)
3529+
let pre_remote_keys = PreCalculatedTxCreationKeys::new(remote_keys);
3530+
Ok(self.local_keys.sign_remote_commitment(self.feerate_per_kw, &remote_initial_commitment_tx, &pre_remote_keys, &Vec::new(), &self.secp_ctx)
35293531
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0)
35303532
}
35313533

@@ -3878,7 +3880,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
38783880
htlcs.push(htlc);
38793881
}
38803882

3881-
let res = self.local_keys.sign_remote_commitment(feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, &self.secp_ctx)
3883+
let pre_remote_keys = PreCalculatedTxCreationKeys::new(remote_keys.clone());
3884+
let res = self.local_keys.sign_remote_commitment(feerate_per_kw, &remote_commitment_tx.0, &pre_remote_keys, &htlcs, &self.secp_ctx)
38823885
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?;
38833886
signature = res.0;
38843887
htlc_signatures = res.1;

lightning/src/ln/functional_tests.rs

Lines changed: 3 additions & 1 deletion
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

Lines changed: 4 additions & 4 deletions
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)