Skip to content

Commit bbd89a2

Browse files
committed
Support holder funding key rotation during splicing
We introduce a scalar tweak that can be applied to the base funding key to obtain the channel's funding key used in the 2-of-2 multisig. This is used to derive additional keys from the same secret backing the base funding_pubkey, as we have to rotate keys for each successful splice attempt. The tweak is computed similar to existing tweaks used in [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation): 1. We use the txid of the funding transaction the splice transaction is spending instead of the `per_commitment_point` to guarantee uniqueness. 2. We include the private key instead of the public key to guarantee only those with knowledge of it can re-derive the new funding key. tweak = SHA256(splice_parent_funding_txid || base_funding_secret_key) tweaked_funding_key = base_funding_key + tweak While the use of this tweak is not required (signers may choose to compute a tweak of their choice), signers must ensure their tweak guarantees the two properties mentioned above: uniqueness and derivable only by one or both of the channel participants.
1 parent 7188d5b commit bbd89a2

File tree

11 files changed

+241
-63
lines changed

11 files changed

+241
-63
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,8 +1359,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
13591359
) -> ChannelMonitor<Signer> {
13601360

13611361
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
1362+
let holder_pubkeys = &channel_parameters.holder_pubkeys;
13621363
let counterparty_payment_script = chan_utils::get_counterparty_payment_script(
1363-
&channel_parameters.channel_type_features, &keys.pubkeys().payment_point
1364+
&channel_parameters.channel_type_features, &holder_pubkeys.payment_point
13641365
);
13651366

13661367
let counterparty_channel_parameters = channel_parameters.counterparty_parameters.as_ref().unwrap();
@@ -1369,7 +1370,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
13691370
let counterparty_commitment_params = CounterpartyCommitmentParameters { counterparty_delayed_payment_base_key, counterparty_htlc_base_key, on_counterparty_tx_csv };
13701371

13711372
let channel_keys_id = keys.channel_keys_id();
1372-
let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint;
1373+
let holder_revocation_basepoint = holder_pubkeys.revocation_basepoint;
13731374

13741375
// block for Rust 1.34 compat
13751376
let (holder_commitment_tx, current_holder_commitment_number) = {
@@ -5417,6 +5418,7 @@ mod tests {
54175418
selected_contest_delay: 67,
54185419
}),
54195420
funding_outpoint: Some(funding_outpoint),
5421+
splice_parent_funding_txid: None,
54205422
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
54215423
channel_value_satoshis: 0,
54225424
};
@@ -5669,6 +5671,7 @@ mod tests {
56695671
selected_contest_delay: 67,
56705672
}),
56715673
funding_outpoint: Some(funding_outpoint),
5674+
splice_parent_funding_txid: None,
56725675
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
56735676
channel_value_satoshis: 0,
56745677
};

lightning/src/chain/onchaintx.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,7 @@ mod tests {
13521352
selected_contest_delay: 67,
13531353
}),
13541354
funding_outpoint: Some(funding_outpoint),
1355+
splice_parent_funding_txid: None,
13551356
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
13561357
channel_value_satoshis: 0,
13571358
};

lightning/src/chain/package.rs

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,20 @@ impl PackageSolvingData {
605605
let channel_parameters = &onchain_handler.channel_transaction_parameters;
606606
match self {
607607
PackageSolvingData::RevokedOutput(ref outp) => {
608-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
608+
let directed_parameters =
609+
&onchain_handler.channel_transaction_parameters.as_counterparty_broadcastable();
610+
debug_assert_eq!(
611+
directed_parameters.broadcaster_pubkeys().delayed_payment_basepoint,
612+
outp.counterparty_delayed_payment_base_key,
613+
);
614+
debug_assert_eq!(
615+
directed_parameters.broadcaster_pubkeys().htlc_basepoint,
616+
outp.counterparty_htlc_base_key,
617+
);
618+
let chan_keys = TxCreationKeys::from_channel_static_keys(
619+
&outp.per_commitment_point, directed_parameters.broadcaster_pubkeys(),
620+
directed_parameters.countersignatory_pubkeys(), &onchain_handler.secp_ctx,
621+
);
609622
let witness_script = chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, outp.on_counterparty_tx_csv, &chan_keys.broadcaster_delayed_payment_key);
610623
//TODO: should we panic on signer failure ?
611624
if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_output(channel_parameters, &bumped_tx, i, outp.amount.to_sat(), &outp.per_commitment_key, &onchain_handler.secp_ctx) {
@@ -617,7 +630,20 @@ impl PackageSolvingData {
617630
} else { return false; }
618631
},
619632
PackageSolvingData::RevokedHTLCOutput(ref outp) => {
620-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
633+
let directed_parameters =
634+
&onchain_handler.channel_transaction_parameters.as_counterparty_broadcastable();
635+
debug_assert_eq!(
636+
directed_parameters.broadcaster_pubkeys().delayed_payment_basepoint,
637+
outp.counterparty_delayed_payment_base_key,
638+
);
639+
debug_assert_eq!(
640+
directed_parameters.broadcaster_pubkeys().htlc_basepoint,
641+
outp.counterparty_htlc_base_key,
642+
);
643+
let chan_keys = TxCreationKeys::from_channel_static_keys(
644+
&outp.per_commitment_point, directed_parameters.broadcaster_pubkeys(),
645+
directed_parameters.countersignatory_pubkeys(), &onchain_handler.secp_ctx,
646+
);
621647
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
622648
//TODO: should we panic on signer failure ?
623649
if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(channel_parameters, &bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) {
@@ -629,7 +655,20 @@ impl PackageSolvingData {
629655
} else { return false; }
630656
},
631657
PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => {
632-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
658+
let directed_parameters =
659+
&onchain_handler.channel_transaction_parameters.as_counterparty_broadcastable();
660+
debug_assert_eq!(
661+
directed_parameters.broadcaster_pubkeys().delayed_payment_basepoint,
662+
outp.counterparty_delayed_payment_base_key,
663+
);
664+
debug_assert_eq!(
665+
directed_parameters.broadcaster_pubkeys().htlc_basepoint,
666+
outp.counterparty_htlc_base_key,
667+
);
668+
let chan_keys = TxCreationKeys::from_channel_static_keys(
669+
&outp.per_commitment_point, directed_parameters.broadcaster_pubkeys(),
670+
directed_parameters.countersignatory_pubkeys(), &onchain_handler.secp_ctx,
671+
);
633672
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
634673

635674
if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(channel_parameters, &bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {
@@ -641,7 +680,20 @@ impl PackageSolvingData {
641680
}
642681
},
643682
PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => {
644-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
683+
let directed_parameters =
684+
&onchain_handler.channel_transaction_parameters.as_counterparty_broadcastable();
685+
debug_assert_eq!(
686+
directed_parameters.broadcaster_pubkeys().delayed_payment_basepoint,
687+
outp.counterparty_delayed_payment_base_key,
688+
);
689+
debug_assert_eq!(
690+
directed_parameters.broadcaster_pubkeys().htlc_basepoint,
691+
outp.counterparty_htlc_base_key,
692+
);
693+
let chan_keys = TxCreationKeys::from_channel_static_keys(
694+
&outp.per_commitment_point, directed_parameters.broadcaster_pubkeys(),
695+
directed_parameters.countersignatory_pubkeys(), &onchain_handler.secp_ctx,
696+
);
645697
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
646698

647699
if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(channel_parameters, &bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {

lightning/src/ln/chan_utils.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,17 @@ pub struct ChannelTransactionParameters {
880880
pub counterparty_parameters: Option<CounterpartyChannelTransactionParameters>,
881881
/// The late-bound funding outpoint
882882
pub funding_outpoint: Option<chain::transaction::OutPoint>,
883+
/// The parent funding txid for a channel that has been spliced.
884+
///
885+
/// If a channel was funded with transaction A, and later spliced with transaction B, this field
886+
/// tracks the txid of transaction A.
887+
///
888+
/// See [`compute_funding_key_tweak`] and [`ChannelSigner::pubkeys`] for more context on how
889+
/// this may be used.
890+
///
891+
/// [`compute_funding_key_tweak`]: crate::sign::compute_funding_key_tweak
892+
/// [`ChannelSigner::pubkeys`]: crate::sign::ChannelSigner::pubkeys
893+
pub splice_parent_funding_txid: Option<Txid>,
883894
/// This channel's type, as negotiated during channel open. For old objects where this field
884895
/// wasn't serialized, it will default to static_remote_key at deserialization.
885896
pub channel_type_features: ChannelTypeFeatures,
@@ -963,6 +974,7 @@ impl ChannelTransactionParameters {
963974
funding_outpoint: Some(chain::transaction::OutPoint {
964975
txid: Txid::from_byte_array([42; 32]), index: 0
965976
}),
977+
splice_parent_funding_txid: None,
966978
channel_type_features: ChannelTypeFeatures::empty(),
967979
channel_value_satoshis,
968980
}
@@ -985,6 +997,7 @@ impl Writeable for ChannelTransactionParameters {
985997
(8, self.funding_outpoint, option),
986998
(10, legacy_deserialization_prevention_marker, option),
987999
(11, self.channel_type_features, required),
1000+
(12, self.splice_parent_funding_txid, option),
9881001
(13, self.channel_value_satoshis, required),
9891002
});
9901003
Ok(())
@@ -998,6 +1011,7 @@ impl ReadableArgs<u64> for ChannelTransactionParameters {
9981011
let mut is_outbound_from_holder = RequiredWrapper(None);
9991012
let mut counterparty_parameters = None;
10001013
let mut funding_outpoint = None;
1014+
let mut splice_parent_funding_txid = None;
10011015
let mut _legacy_deserialization_prevention_marker: Option<()> = None;
10021016
let mut channel_type_features = None;
10031017
let mut channel_value_satoshis = None;
@@ -1010,6 +1024,7 @@ impl ReadableArgs<u64> for ChannelTransactionParameters {
10101024
(8, funding_outpoint, option),
10111025
(10, _legacy_deserialization_prevention_marker, option),
10121026
(11, channel_type_features, option),
1027+
(12, splice_parent_funding_txid, option),
10131028
(13, channel_value_satoshis, option),
10141029
});
10151030

@@ -1028,6 +1043,7 @@ impl ReadableArgs<u64> for ChannelTransactionParameters {
10281043
is_outbound_from_holder: is_outbound_from_holder.0.unwrap(),
10291044
counterparty_parameters,
10301045
funding_outpoint,
1046+
splice_parent_funding_txid,
10311047
channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()),
10321048
channel_value_satoshis,
10331049
})
@@ -1154,6 +1170,7 @@ impl HolderCommitmentTransaction {
11541170
is_outbound_from_holder: false,
11551171
counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }),
11561172
funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
1173+
splice_parent_funding_txid: None,
11571174
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
11581175
channel_value_satoshis,
11591176
};
@@ -1953,22 +1970,25 @@ mod tests {
19531970
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
19541971
let signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(false, 0));
19551972
let counterparty_signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(true, 1));
1956-
let delayed_payment_base = &signer.pubkeys().delayed_payment_basepoint;
19571973
let per_commitment_secret = SecretKey::from_slice(&<Vec<u8>>::from_hex("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
19581974
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
1959-
let htlc_basepoint = &signer.pubkeys().htlc_basepoint;
1960-
let holder_pubkeys = signer.pubkeys();
1961-
let counterparty_pubkeys = counterparty_signer.pubkeys().clone();
1962-
let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint);
1975+
let holder_pubkeys = signer.pubkeys(None, &secp_ctx);
1976+
let counterparty_pubkeys = counterparty_signer.pubkeys(None, &secp_ctx).clone();
19631977
let channel_parameters = ChannelTransactionParameters {
19641978
holder_pubkeys: holder_pubkeys.clone(),
19651979
holder_selected_contest_delay: 0,
19661980
is_outbound_from_holder: false,
19671981
counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }),
19681982
funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
1983+
splice_parent_funding_txid: None,
19691984
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
19701985
channel_value_satoshis: 3000,
19711986
};
1987+
let directed_parameters = channel_parameters.as_holder_broadcastable();
1988+
let keys = TxCreationKeys::from_channel_static_keys(
1989+
&per_commitment_point, directed_parameters.broadcaster_pubkeys(),
1990+
directed_parameters.countersignatory_pubkeys(), &secp_ctx,
1991+
);
19721992
let htlcs_with_aux = Vec::new();
19731993

19741994
Self {

0 commit comments

Comments
 (0)