@@ -35,7 +35,7 @@ use crate::util::transaction_utils;
35
35
36
36
use bitcoin:: locktime:: absolute:: LockTime ;
37
37
use bitcoin:: ecdsa:: Signature as BitcoinSignature ;
38
- use bitcoin:: secp256k1:: { SecretKey , PublicKey , Scalar } ;
38
+ use bitcoin:: secp256k1:: { SecretKey , PublicKey , Scalar , Verification } ;
39
39
use bitcoin:: secp256k1:: { Secp256k1 , ecdsa:: Signature , Message } ;
40
40
use bitcoin:: { secp256k1, Sequence , Witness } ;
41
41
@@ -430,6 +430,26 @@ pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1
430
430
. expect ( "Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak commits to the key." )
431
431
}
432
432
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
+
433
453
/// The set of public keys which are used in the creation of one commitment transaction.
434
454
/// These are derived from the channel base keys and per-commitment data.
435
455
///
@@ -470,6 +490,9 @@ impl_writeable_tlv_based!(TxCreationKeys, {
470
490
pub struct ChannelPublicKeys {
471
491
/// The public key which is used to sign all commitment transactions, as it appears in the
472
492
/// 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.
473
496
pub funding_pubkey : PublicKey ,
474
497
/// The base point which is used (with [`RevocationKey::from_basepoint`]) to derive per-commitment
475
498
/// revocation keys. This is combined with the per-commitment-secret generated by the
@@ -497,6 +520,102 @@ impl_writeable_tlv_based!(ChannelPublicKeys, {
497
520
( 8 , htlc_basepoint, required) ,
498
521
} ) ;
499
522
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
+
500
619
impl TxCreationKeys {
501
620
/// Create per-state keys from channel base points and the per-commitment point.
502
621
/// 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
869
988
#[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
870
989
pub struct ChannelTransactionParameters {
871
990
/// Holder public keys
872
- pub holder_pubkeys : ChannelPublicKeys ,
991
+ pub holder_pubkeys : HolderChannelPublicKeys ,
873
992
/// The contest delay selected by the holder, which applies to counterparty-broadcast transactions
874
993
pub holder_selected_contest_delay : u16 ,
875
994
/// Whether the holder is the initiator of this channel.
@@ -933,7 +1052,7 @@ impl ChannelTransactionParameters {
933
1052
934
1053
pub ( crate ) fn make_funding_redeemscript ( & self ) -> ScriptBuf {
935
1054
make_funding_redeemscript (
936
- & self . holder_pubkeys . funding_pubkey ,
1055
+ & self . holder_pubkeys . inner ( ) . funding_pubkey ,
937
1056
& self . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys . funding_pubkey
938
1057
)
939
1058
}
@@ -953,7 +1072,10 @@ impl ChannelTransactionParameters {
953
1072
htlc_basepoint : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
954
1073
} ;
955
1074
Self {
956
- holder_pubkeys : dummy_keys. clone ( ) ,
1075
+ holder_pubkeys : HolderChannelPublicKeys {
1076
+ keys : dummy_keys. clone ( ) ,
1077
+ funding_key_tweak : None ,
1078
+ } ,
957
1079
holder_selected_contest_delay : 42 ,
958
1080
is_outbound_from_holder : true ,
959
1081
counterparty_parameters : Some ( CounterpartyChannelTransactionParameters {
@@ -1050,7 +1172,7 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
1050
1172
/// Get the channel pubkeys for the broadcaster
1051
1173
pub fn broadcaster_pubkeys ( & self ) -> & ' a ChannelPublicKeys {
1052
1174
if self . holder_is_broadcaster {
1053
- & self . inner . holder_pubkeys
1175
+ self . inner . holder_pubkeys . inner ( )
1054
1176
} else {
1055
1177
& self . inner . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys
1056
1178
}
@@ -1061,7 +1183,7 @@ impl<'a> DirectedChannelTransactionParameters<'a> {
1061
1183
if self . holder_is_broadcaster {
1062
1184
& self . inner . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys
1063
1185
} else {
1064
- & self . inner . holder_pubkeys
1186
+ self . inner . holder_pubkeys . inner ( )
1065
1187
}
1066
1188
}
1067
1189
@@ -1149,7 +1271,10 @@ impl HolderCommitmentTransaction {
1149
1271
htlc_basepoint : HtlcBasepoint :: from ( dummy_key. clone ( ) )
1150
1272
} ;
1151
1273
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
+ } ,
1153
1278
holder_selected_contest_delay : 0 ,
1154
1279
is_outbound_from_holder : false ,
1155
1280
counterparty_parameters : Some ( CounterpartyChannelTransactionParameters { pubkeys : channel_pubkeys. clone ( ) , selected_contest_delay : 0 } ) ,
@@ -1918,7 +2043,7 @@ pub fn get_commitment_transaction_number_obscure_factor(
1918
2043
1919
2044
#[ cfg( test) ]
1920
2045
mod tests {
1921
- use super :: { CounterpartyCommitmentSecrets , ChannelPublicKeys } ;
2046
+ use super :: { CounterpartyCommitmentSecrets , ChannelPublicKeys , HolderChannelPublicKeys } ;
1922
2047
use crate :: chain;
1923
2048
use crate :: ln:: chan_utils:: { get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction , TxCreationKeys , ChannelTransactionParameters , CounterpartyChannelTransactionParameters , HTLCOutputInCommitment } ;
1924
2049
use bitcoin:: secp256k1:: { PublicKey , SecretKey , Secp256k1 } ;
@@ -1961,7 +2086,11 @@ mod tests {
1961
2086
let counterparty_pubkeys = counterparty_signer. pubkeys ( ) . clone ( ) ;
1962
2087
let keys = TxCreationKeys :: derive_new ( & secp_ctx, & per_commitment_point, delayed_payment_base, htlc_basepoint, & counterparty_pubkeys. revocation_basepoint , & counterparty_pubkeys. htlc_basepoint ) ;
1963
2088
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
+ ) ,
1965
2094
holder_selected_contest_delay : 0 ,
1966
2095
is_outbound_from_holder : false ,
1967
2096
counterparty_parameters : Some ( CounterpartyChannelTransactionParameters { pubkeys : counterparty_pubkeys. clone ( ) , selected_contest_delay : 0 } ) ,
0 commit comments