@@ -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,24 @@ 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`, as we cannot guarantee that it will change across
438
+ /// multiple splice attempts, we use the txid of the funding transaction the splice transaction is
439
+ /// spending, henceforth known as the splice's parent funding txid.
440
+ ///
441
+ /// tweak = base_funding_key + SHA256(splice_parent_funding_txid || base_funding_pubkey)
442
+ //
443
+ // TODO: Expose a helper on `FundingScope` that calls this.
444
+ pub fn compute_funding_key_tweak ( base_funding_pubkey : & PublicKey , splice_parent_funding_txid : & Txid ) -> Scalar {
445
+ let mut sha = Sha256 :: engine ( ) ;
446
+ sha. input ( splice_parent_funding_txid. as_byte_array ( ) ) ;
447
+ sha. input ( & base_funding_pubkey. serialize ( ) ) ;
448
+ Scalar :: from_be_bytes ( Sha256 :: from_engine ( sha) . to_byte_array ( ) ) . unwrap ( )
449
+ }
450
+
433
451
/// The set of public keys which are used in the creation of one commitment transaction.
434
452
/// These are derived from the channel base keys and per-commitment data.
435
453
///
@@ -470,7 +488,14 @@ impl_writeable_tlv_based!(TxCreationKeys, {
470
488
pub struct ChannelPublicKeys {
471
489
/// The public key which is used to sign all commitment transactions, as it appears in the
472
490
/// on-chain channel lock-in 2-of-2 multisig output.
473
- pub funding_pubkey : PublicKey ,
491
+ funding_pubkey : PublicKey ,
492
+ /// A scalar tweak applied to the base funding key to obtain the channel's funding key used in
493
+ /// the 2-of-2 multisig. This is used to derive additional keys from the same secret backing the
494
+ /// base `funding_pubkey`, as we have to rotate keys for each successful splice attempt.
495
+ ///
496
+ /// The tweak is computed as described in [`compute_funding_key_tweak`], and it must only be set
497
+ /// for holder public keys, never for counterparty ones.
498
+ funding_key_tweak : Option < Scalar > ,
474
499
/// The base point which is used (with [`RevocationKey::from_basepoint`]) to derive per-commitment
475
500
/// revocation keys. This is combined with the per-commitment-secret generated by the
476
501
/// counterparty to create a secret which the counterparty can reveal to revoke previous
@@ -489,12 +514,43 @@ pub struct ChannelPublicKeys {
489
514
pub htlc_basepoint : HtlcBasepoint ,
490
515
}
491
516
517
+ impl ChannelPublicKeys {
518
+ /// Constructs a new instance of [`ChannelPublicKeys`].
519
+ pub fn new (
520
+ funding_pubkey : PublicKey , funding_key_tweak : Option < Scalar > ,
521
+ revocation_basepoint : RevocationBasepoint , payment_point : PublicKey ,
522
+ delayed_payment_basepoint : DelayedPaymentBasepoint , htlc_basepoint : HtlcBasepoint ,
523
+ ) -> Self {
524
+ Self {
525
+ funding_pubkey, funding_key_tweak, revocation_basepoint, payment_point,
526
+ delayed_payment_basepoint, htlc_basepoint,
527
+ }
528
+ }
529
+
530
+ /// Returns the funding public key with the required tweak applied if one exists.
531
+ pub fn funding_pubkey < C : secp256k1:: Verification > ( & self , secp : & Secp256k1 < C > ) -> PublicKey {
532
+ self . funding_key_tweak
533
+ . map ( |tweak| {
534
+ self . funding_pubkey . add_exp_tweak ( secp, & tweak) . expect (
535
+ "Addition only fails if the tweak is the inverse of the key"
536
+ )
537
+ } )
538
+ . unwrap_or ( self . funding_pubkey )
539
+ }
540
+
541
+ /// Returns the tweak, if one exists, to apply to the funding key.
542
+ pub fn funding_key_tweak ( & self ) -> Option < Scalar > {
543
+ self . funding_key_tweak
544
+ }
545
+ }
546
+
492
547
impl_writeable_tlv_based ! ( ChannelPublicKeys , {
493
548
( 0 , funding_pubkey, required) ,
494
549
( 2 , revocation_basepoint, required) ,
495
550
( 4 , payment_point, required) ,
496
551
( 6 , delayed_payment_basepoint, required) ,
497
552
( 8 , htlc_basepoint, required) ,
553
+ ( 10 , funding_key_tweak, option) ,
498
554
} ) ;
499
555
500
556
impl TxCreationKeys {
@@ -931,10 +987,10 @@ impl ChannelTransactionParameters {
931
987
}
932
988
}
933
989
934
- pub ( crate ) fn make_funding_redeemscript ( & self ) -> ScriptBuf {
990
+ pub ( crate ) fn make_funding_redeemscript < C : Verification > ( & self , secp : & Secp256k1 < C > ) -> ScriptBuf {
935
991
make_funding_redeemscript (
936
- & self . holder_pubkeys . funding_pubkey ,
937
- & self . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys . funding_pubkey
992
+ & self . holder_pubkeys . funding_pubkey ( secp ) ,
993
+ & self . counterparty_parameters . as_ref ( ) . unwrap ( ) . pubkeys . funding_pubkey ( & secp )
938
994
)
939
995
}
940
996
@@ -945,13 +1001,13 @@ impl ChannelTransactionParameters {
945
1001
946
1002
#[ cfg( test) ]
947
1003
pub fn test_dummy ( channel_value_satoshis : u64 ) -> Self {
948
- let dummy_keys = ChannelPublicKeys {
949
- funding_pubkey : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
950
- revocation_basepoint : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
951
- payment_point : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
952
- delayed_payment_basepoint : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
953
- htlc_basepoint : PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
954
- } ;
1004
+ let dummy_keys = ChannelPublicKeys :: new (
1005
+ PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) , None ,
1006
+ PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
1007
+ PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) ,
1008
+ PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
1009
+ PublicKey :: from_slice ( & [ 2 ; 33 ] ) . unwrap ( ) . into ( ) ,
1010
+ ) ;
955
1011
Self {
956
1012
holder_pubkeys : dummy_keys. clone ( ) ,
957
1013
holder_selected_contest_delay : 42 ,
@@ -1136,13 +1192,10 @@ impl HolderCommitmentTransaction {
1136
1192
countersignatory_htlc_key : HtlcKey :: from_basepoint ( & secp_ctx, & HtlcBasepoint :: from ( dummy_key) , & dummy_key) ,
1137
1193
broadcaster_delayed_payment_key : DelayedPaymentKey :: from_basepoint ( & secp_ctx, & DelayedPaymentBasepoint :: from ( dummy_key) , & dummy_key) ,
1138
1194
} ;
1139
- let channel_pubkeys = ChannelPublicKeys {
1140
- funding_pubkey : dummy_key. clone ( ) ,
1141
- revocation_basepoint : RevocationBasepoint :: from ( dummy_key) ,
1142
- payment_point : dummy_key. clone ( ) ,
1143
- delayed_payment_basepoint : DelayedPaymentBasepoint :: from ( dummy_key. clone ( ) ) ,
1144
- htlc_basepoint : HtlcBasepoint :: from ( dummy_key. clone ( ) )
1145
- } ;
1195
+ let channel_pubkeys = ChannelPublicKeys :: new (
1196
+ dummy_key. clone ( ) , None , RevocationBasepoint :: from ( dummy_key) , dummy_key. clone ( ) ,
1197
+ DelayedPaymentBasepoint :: from ( dummy_key. clone ( ) ) , HtlcBasepoint :: from ( dummy_key. clone ( ) )
1198
+ ) ;
1146
1199
let channel_parameters = ChannelTransactionParameters {
1147
1200
holder_pubkeys : channel_pubkeys. clone ( ) ,
1148
1201
holder_selected_contest_delay : 0 ,
0 commit comments