@@ -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,102 @@ 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 HolderChannelPublicKeys {
588+ /// Constructs a new instance of [`HolderChannelPublicKeys`].
589+ pub fn new < C : Verification > (
590+ funding_pubkey : PublicKey , revocation_basepoint : RevocationBasepoint ,
591+ payment_point : PublicKey , delayed_payment_basepoint : DelayedPaymentBasepoint ,
592+ htlc_basepoint : HtlcBasepoint , funding_key_tweak : Option < Scalar > , secp : & Secp256k1 < C > ,
593+ ) -> Self {
594+ let funding_pubkey = funding_key_tweak
595+ . map ( |tweak| {
596+ funding_pubkey
597+ . add_exp_tweak ( secp, & tweak)
598+ . expect ( "Addition only fails if the tweak is the inverse of the key" )
599+ } )
600+ . unwrap_or ( funding_pubkey) ;
601+ Self {
602+ keys : ChannelPublicKeys {
603+ funding_pubkey,
604+ revocation_basepoint,
605+ payment_point,
606+ delayed_payment_basepoint,
607+ htlc_basepoint,
608+ } ,
609+ funding_key_tweak,
610+ }
611+ }
612+
613+ /// Returns the holder's channel public keys as a [`ChannelPublicKeys`].
614+ pub fn inner ( & self ) -> & ChannelPublicKeys {
615+ & self . keys
616+ }
617+ }
618+
500619impl TxCreationKeys {
501620 /// Create per-state keys from channel base points and the per-commitment point.
502621 /// Key set is asymmetric and can't be used as part of counter-signatory set of transactions.
@@ -869,7 +988,7 @@ pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signatu
869988#[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
870989pub struct ChannelTransactionParameters {
871990 /// Holder public keys
872- pub holder_pubkeys : ChannelPublicKeys ,
991+ pub holder_pubkeys : HolderChannelPublicKeys ,
873992 /// The contest delay selected by the holder, which applies to counterparty-broadcast transactions
874993 pub holder_selected_contest_delay : u16 ,
875994 /// Whether the holder is the initiator of this channel.
@@ -933,7 +1052,7 @@ impl ChannelTransactionParameters {
9331052
9341053 pub ( crate ) fn make_funding_redeemscript ( & self ) -> ScriptBuf {
9351054 make_funding_redeemscript (
936- & self . holder_pubkeys . funding_pubkey ,
1055+ & self . holder_pubkeys . inner ( ) . funding_pubkey ,
9371056 & self . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys . funding_pubkey
9381057 )
9391058 }
@@ -953,7 +1072,10 @@ impl ChannelTransactionParameters {
9531072 htlc_basepoint : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
9541073 } ;
9551074 Self {
956- holder_pubkeys : dummy_keys. clone ( ) ,
1075+ holder_pubkeys : HolderChannelPublicKeys {
1076+ keys : dummy_keys. clone ( ) ,
1077+ funding_key_tweak : None ,
1078+ } ,
9571079 holder_selected_contest_delay : 42 ,
9581080 is_outbound_from_holder : true ,
9591081 counterparty_parameters : Some ( CounterpartyChannelTransactionParameters {
@@ -1050,7 +1172,7 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
10501172 /// Get the channel pubkeys for the broadcaster
10511173 pub fn broadcaster_pubkeys ( & self ) -> & ' a ChannelPublicKeys {
10521174 if self . holder_is_broadcaster {
1053- & self . inner . holder_pubkeys
1175+ self . inner . holder_pubkeys . inner ( )
10541176 } else {
10551177 & self . inner . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys
10561178 }
@@ -1061,7 +1183,7 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
10611183 if self . holder_is_broadcaster {
10621184 & self . inner . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys
10631185 } else {
1064- & self . inner . holder_pubkeys
1186+ self . inner . holder_pubkeys . inner ( )
10651187 }
10661188 }
10671189
@@ -1149,7 +1271,10 @@ impl HolderCommitmentTransaction {
11491271 htlc_basepoint : HtlcBasepoint :: from ( dummy_key. clone ( ) )
11501272 } ;
11511273 let channel_parameters = ChannelTransactionParameters {
1152- holder_pubkeys : channel_pubkeys. clone ( ) ,
1274+ holder_pubkeys : HolderChannelPublicKeys {
1275+ keys : channel_pubkeys. clone ( ) ,
1276+ funding_key_tweak : None ,
1277+ } ,
11531278 holder_selected_contest_delay : 0 ,
11541279 is_outbound_from_holder : false ,
11551280 counterparty_parameters : Some ( CounterpartyChannelTransactionParameters { pubkeys : channel_pubkeys. clone ( ) , selected_contest_delay : 0 } ) ,
@@ -1918,7 +2043,7 @@ pub fn get_commitment_transaction_number_obscure_factor(
19182043
19192044#[ cfg( test) ]
19202045mod tests {
1921- use super :: { CounterpartyCommitmentSecrets , ChannelPublicKeys } ;
2046+ use super :: { CounterpartyCommitmentSecrets , ChannelPublicKeys , HolderChannelPublicKeys } ;
19222047 use crate :: chain;
19232048 use crate :: ln:: chan_utils:: { get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction , TxCreationKeys , ChannelTransactionParameters , CounterpartyChannelTransactionParameters , HTLCOutputInCommitment } ;
19242049 use bitcoin:: secp256k1:: { PublicKey , SecretKey , Secp256k1 } ;
@@ -1961,7 +2086,11 @@ mod tests {
19612086 let counterparty_pubkeys = counterparty_signer. pubkeys ( ) . clone ( ) ;
19622087 let keys = TxCreationKeys :: derive_new ( & secp_ctx, & per_commitment_point, delayed_payment_base, htlc_basepoint, & counterparty_pubkeys. revocation_basepoint , & counterparty_pubkeys. htlc_basepoint ) ;
19632088 let channel_parameters = ChannelTransactionParameters {
1964- holder_pubkeys : holder_pubkeys. clone ( ) ,
2089+ holder_pubkeys : HolderChannelPublicKeys :: new (
2090+ holder_pubkeys. funding_pubkey , holder_pubkeys. revocation_basepoint ,
2091+ holder_pubkeys. payment_point , holder_pubkeys. delayed_payment_basepoint ,
2092+ holder_pubkeys. htlc_basepoint , None , & secp_ctx,
2093+ ) ,
19652094 holder_selected_contest_delay : 0 ,
19662095 is_outbound_from_holder : false ,
19672096 counterparty_parameters : Some ( CounterpartyChannelTransactionParameters { pubkeys : counterparty_pubkeys. clone ( ) , selected_contest_delay : 0 } ) ,
0 commit comments