@@ -35,7 +35,7 @@ use crate::util::transaction_utils;
3535
3636use bitcoin:: locktime:: absolute:: LockTime ;
3737use bitcoin:: ecdsa:: Signature as BitcoinSignature ;
38- use bitcoin:: secp256k1:: { SecretKey , PublicKey , Scalar } ;
38+ use bitcoin:: secp256k1:: { SecretKey , PublicKey , Scalar , Verification } ;
3939use bitcoin:: secp256k1:: { Secp256k1 , ecdsa:: Signature , Message } ;
4040use bitcoin:: { secp256k1, Sequence , Witness } ;
4141
@@ -430,6 +430,26 @@ pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1
430430 . expect ( "Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak commits to the key." )
431431}
432432
433+ /// Computes the tweak to apply to the base funding key of a channel.
434+ ///
435+ /// The tweak is computed similar to existing tweaks used in
436+ /// [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation), but
437+ /// rather than using the `per_commitment_point`, we use the txid of the funding transaction the
438+ /// splice transaction is spending to guarantee uniqueness, and the `revocation_basepoint` to
439+ /// guarantee only the channel participants can re-derive the new funding key.
440+ ///
441+ /// tweak = SHA256(splice_parent_funding_txid || revocation_basepoint || base_funding_pubkey)
442+ /// tweaked_funding_key = base_funding_key + tweak
443+ //
444+ // TODO: Expose a helper on `FundingScope` that calls this.
445+ pub fn compute_funding_key_tweak ( base_funding_pubkey : & PublicKey , revocation_basepoint : & PublicKey , splice_parent_funding_txid : & Txid ) -> Scalar {
446+ let mut sha = Sha256 :: engine ( ) ;
447+ sha. input ( splice_parent_funding_txid. as_byte_array ( ) ) ;
448+ sha. input ( & revocation_basepoint. serialize ( ) ) ;
449+ sha. input ( & base_funding_pubkey. serialize ( ) ) ;
450+ Scalar :: from_be_bytes ( Sha256 :: from_engine ( sha) . to_byte_array ( ) ) . unwrap ( )
451+ }
452+
433453/// The set of public keys which are used in the creation of one commitment transaction.
434454/// These are derived from the channel base keys and per-commitment data.
435455///
@@ -470,6 +490,9 @@ impl_writeable_tlv_based!(TxCreationKeys, {
470490pub struct ChannelPublicKeys {
471491 /// The public key which is used to sign all commitment transactions, as it appears in the
472492 /// on-chain channel lock-in 2-of-2 multisig output.
493+ ///
494+ /// NOTE: This key will already have the [`HolderChannelPublicKeys::funding_key_tweak`] applied
495+ /// if one existed.
473496 pub funding_pubkey : PublicKey ,
474497 /// The base point which is used (with [`RevocationKey::from_basepoint`]) to derive per-commitment
475498 /// revocation keys. This is combined with the per-commitment-secret generated by the
@@ -497,6 +520,113 @@ impl_writeable_tlv_based!(ChannelPublicKeys, {
497520 ( 8 , htlc_basepoint, required) ,
498521} ) ;
499522
523+ /// The holder's public keys which do not change over the life of a channel, except for the
524+ /// `funding_pubkey`, which may rotate after each successful splice attempt via the
525+ /// `funding_key_tweak`.
526+ #[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
527+ pub struct HolderChannelPublicKeys {
528+ keys : ChannelPublicKeys ,
529+ /// A optional scalar tweak applied to the base funding key to obtain the channel's funding key
530+ /// used in the 2-of-2 multisig. This is used to derive additional keys from the same secret
531+ /// backing the base `funding_pubkey`, as we have to rotate keys for each successful splice
532+ /// attempt. The tweak is computed as described in [`compute_funding_key_tweak`].
533+ //
534+ // TODO: Expose `splice_parent_funding_txid` instead so the signer can re-derive the tweak?
535+ // There's no harm in the signer trusting the tweak as long as its funding secret has not
536+ // been leaked.
537+ pub funding_key_tweak : Option < Scalar > ,
538+ }
539+
540+ // `HolderChannelPublicKeys` may have been previously written as `ChannelPublicKeys` so we have to
541+ // mimic its serialization.
542+ impl Writeable for HolderChannelPublicKeys {
543+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
544+ write_tlv_fields ! ( writer, {
545+ ( 0 , self . keys. funding_pubkey, required) ,
546+ ( 2 , self . keys. revocation_basepoint, required) ,
547+ ( 4 , self . keys. payment_point, required) ,
548+ ( 6 , self . keys. delayed_payment_basepoint, required) ,
549+ ( 8 , self . keys. htlc_basepoint, required) ,
550+ ( 10 , self . funding_key_tweak, option) ,
551+ } ) ;
552+ Ok ( ( ) )
553+ }
554+ }
555+
556+ impl Readable for HolderChannelPublicKeys {
557+ fn read < R : io:: Read > ( reader : & mut R ) -> Result < Self , DecodeError > {
558+ let mut funding_pubkey = RequiredWrapper ( None ) ;
559+ let mut revocation_basepoint = RequiredWrapper ( None ) ;
560+ let mut payment_point = RequiredWrapper ( None ) ;
561+ let mut delayed_payment_basepoint = RequiredWrapper ( None ) ;
562+ let mut htlc_basepoint = RequiredWrapper ( None ) ;
563+ let mut funding_key_tweak: Option < Scalar > = None ;
564+
565+ read_tlv_fields ! ( reader, {
566+ ( 0 , funding_pubkey, required) ,
567+ ( 2 , revocation_basepoint, required) ,
568+ ( 4 , payment_point, required) ,
569+ ( 6 , delayed_payment_basepoint, required) ,
570+ ( 8 , htlc_basepoint, required) ,
571+ ( 10 , funding_key_tweak, option) ,
572+ } ) ;
573+
574+ Ok ( Self {
575+ keys : ChannelPublicKeys {
576+ funding_pubkey : funding_pubkey. 0 . unwrap ( ) ,
577+ revocation_basepoint : revocation_basepoint. 0 . unwrap ( ) ,
578+ payment_point : payment_point. 0 . unwrap ( ) ,
579+ delayed_payment_basepoint : delayed_payment_basepoint. 0 . unwrap ( ) ,
580+ htlc_basepoint : htlc_basepoint. 0 . unwrap ( ) ,
581+ } ,
582+ funding_key_tweak,
583+ } )
584+ }
585+ }
586+
587+ impl AsRef < ChannelPublicKeys > for HolderChannelPublicKeys {
588+ fn as_ref ( & self ) -> & ChannelPublicKeys {
589+ & self . keys
590+ }
591+ }
592+
593+ impl From < ChannelPublicKeys > for HolderChannelPublicKeys {
594+ fn from ( value : ChannelPublicKeys ) -> Self {
595+ Self {
596+ keys : value,
597+ funding_key_tweak : None ,
598+ }
599+ }
600+ }
601+
602+ impl HolderChannelPublicKeys {
603+ /// Constructs a new instance of [`HolderChannelPublicKeys`].
604+ pub fn new < C : Verification > (
605+ funding_pubkey : PublicKey , revocation_basepoint : RevocationBasepoint ,
606+ payment_point : PublicKey , delayed_payment_basepoint : DelayedPaymentBasepoint ,
607+ htlc_basepoint : HtlcBasepoint , funding_key_tweak : Option < Scalar > , secp : & Secp256k1 < C > ,
608+ ) -> Self {
609+ let funding_pubkey = funding_key_tweak
610+ . map ( |tweak| {
611+ funding_pubkey
612+ . add_exp_tweak ( secp, & tweak)
613+ . expect ( "Addition only fails if the tweak is the inverse of the key" )
614+ } )
615+ . unwrap_or ( funding_pubkey) ;
616+
617+ Self {
618+ keys : ChannelPublicKeys {
619+ funding_pubkey,
620+ revocation_basepoint,
621+ payment_point,
622+ delayed_payment_basepoint,
623+ htlc_basepoint,
624+ } ,
625+ funding_key_tweak,
626+ }
627+ }
628+ }
629+
500630impl TxCreationKeys {
501631 /// Create per-state keys from channel base points and the per-commitment point.
502632 /// Key set is asymmetric and can't be used as part of counter-signatory set of transactions.
@@ -869,7 +999,7 @@ pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signatu
869999#[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
8701000pub struct ChannelTransactionParameters {
8711001 /// Holder public keys
872- pub holder_pubkeys : ChannelPublicKeys ,
1002+ pub holder_pubkeys : HolderChannelPublicKeys ,
8731003 /// The contest delay selected by the holder, which applies to counterparty-broadcast transactions
8741004 pub holder_selected_contest_delay : u16 ,
8751005 /// Whether the holder is the initiator of this channel.
@@ -933,7 +1063,7 @@ impl ChannelTransactionParameters {
9331063
9341064 pub ( crate ) fn make_funding_redeemscript ( & self ) -> ScriptBuf {
9351065 make_funding_redeemscript (
936- & self . holder_pubkeys . funding_pubkey ,
1066+ & self . holder_pubkeys . as_ref ( ) . funding_pubkey ,
9371067 & self . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys . funding_pubkey
9381068 )
9391069 }
@@ -953,7 +1083,10 @@ impl ChannelTransactionParameters {
9531083 htlc_basepoint : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
9541084 } ;
9551085 Self {
956- holder_pubkeys : dummy_keys. clone ( ) ,
1086+ holder_pubkeys : HolderChannelPublicKeys {
1087+ keys : dummy_keys. clone ( ) ,
1088+ funding_key_tweak : None ,
1089+ } ,
9571090 holder_selected_contest_delay : 42 ,
9581091 is_outbound_from_holder : true ,
9591092 counterparty_parameters : Some ( CounterpartyChannelTransactionParameters {
@@ -1050,7 +1183,7 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
10501183 /// Get the channel pubkeys for the broadcaster
10511184 pub fn broadcaster_pubkeys ( & self ) -> & ' a ChannelPublicKeys {
10521185 if self . holder_is_broadcaster {
1053- & self . inner . holder_pubkeys
1186+ self . inner . holder_pubkeys . as_ref ( )
10541187 } else {
10551188 & self . inner . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys
10561189 }
@@ -1061,7 +1194,7 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
10611194 if self . holder_is_broadcaster {
10621195 & self . inner . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys
10631196 } else {
1064- & self . inner . holder_pubkeys
1197+ self . inner . holder_pubkeys . as_ref ( )
10651198 }
10661199 }
10671200
@@ -1149,7 +1282,10 @@ impl HolderCommitmentTransaction {
11491282 htlc_basepoint : HtlcBasepoint :: from ( dummy_key. clone ( ) )
11501283 } ;
11511284 let channel_parameters = ChannelTransactionParameters {
1152- holder_pubkeys : channel_pubkeys. clone ( ) ,
1285+ holder_pubkeys : HolderChannelPublicKeys {
1286+ keys : channel_pubkeys. clone ( ) ,
1287+ funding_key_tweak : None ,
1288+ } ,
11531289 holder_selected_contest_delay : 0 ,
11541290 is_outbound_from_holder : false ,
11551291 counterparty_parameters : Some ( CounterpartyChannelTransactionParameters { pubkeys : channel_pubkeys. clone ( ) , selected_contest_delay : 0 } ) ,
@@ -1918,7 +2054,7 @@ pub fn get_commitment_transaction_number_obscure_factor(
19182054
19192055#[ cfg( test) ]
19202056mod tests {
1921- use super :: { CounterpartyCommitmentSecrets , ChannelPublicKeys } ;
2057+ use super :: { CounterpartyCommitmentSecrets , ChannelPublicKeys , HolderChannelPublicKeys } ;
19222058 use crate :: chain;
19232059 use crate :: ln:: chan_utils:: { get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction , TxCreationKeys , ChannelTransactionParameters , CounterpartyChannelTransactionParameters , HTLCOutputInCommitment } ;
19242060 use bitcoin:: secp256k1:: { PublicKey , SecretKey , Secp256k1 } ;
@@ -1961,7 +2097,7 @@ mod tests {
19612097 let counterparty_pubkeys = counterparty_signer. pubkeys ( ) . clone ( ) ;
19622098 let keys = TxCreationKeys :: derive_new ( & secp_ctx, & per_commitment_point, delayed_payment_base, htlc_basepoint, & counterparty_pubkeys. revocation_basepoint , & counterparty_pubkeys. htlc_basepoint ) ;
19632099 let channel_parameters = ChannelTransactionParameters {
1964- holder_pubkeys : holder_pubkeys. clone ( ) ,
2100+ holder_pubkeys : HolderChannelPublicKeys :: from ( holder_pubkeys. clone ( ) ) ,
19652101 holder_selected_contest_delay : 0 ,
19662102 is_outbound_from_holder : false ,
19672103 counterparty_parameters : Some ( CounterpartyChannelTransactionParameters { pubkeys : counterparty_pubkeys. clone ( ) , selected_contest_delay : 0 } ) ,
0 commit comments