@@ -137,6 +137,10 @@ pub enum SpendableOutputDescriptor {
137
137
outpoint : OutPoint ,
138
138
/// The output which is referenced by the given outpoint.
139
139
output : TxOut ,
140
+ /// Arbitrary identification information returned by a call to
141
+ /// `Sign::channel_keys_id()`. This may be useful in re-deriving keys used in
142
+ /// the channel to spend the output.
143
+ channel_keys_id : Option < [ u8 ; 32 ] >
140
144
} ,
141
145
/// An output to a P2WSH script which can be spent with a single signature after a CSV delay.
142
146
///
@@ -181,6 +185,7 @@ impl_writeable_tlv_based_enum!(SpendableOutputDescriptor,
181
185
( 0 , StaticOutput ) => {
182
186
( 0 , outpoint, required) ,
183
187
( 2 , output, required) ,
188
+ ( 3 , channel_keys_id, option) ,
184
189
} ,
185
190
;
186
191
( 1 , DelayedPaymentOutput ) ,
@@ -406,7 +411,7 @@ pub trait KeysInterface {
406
411
///
407
412
/// This method should return a different value each time it is called, to avoid linking
408
413
/// on-chain funds across channels as controlled to the same user.
409
- fn get_destination_script ( & self ) -> Script ;
414
+ fn get_destination_script ( & self , channel_keys_id : [ u8 ; 32 ] ) -> Script ;
410
415
/// Get a script pubkey which we will send funds to when closing a channel.
411
416
///
412
417
/// This method should return a different value each time it is called, to avoid linking
@@ -846,7 +851,7 @@ pub struct KeysManager {
846
851
node_secret : SecretKey ,
847
852
inbound_payment_key : KeyMaterial ,
848
853
destination_script : Script ,
849
- shutdown_pubkey : PublicKey ,
854
+ shutdown_pubkey : ExtendedPubKey ,
850
855
channel_master_key : ExtendedPrivKey ,
851
856
channel_child_index : AtomicUsize ,
852
857
@@ -857,6 +862,7 @@ pub struct KeysManager {
857
862
seed : [ u8 ; 32 ] ,
858
863
starting_time_secs : u64 ,
859
864
starting_time_nanos : u32 ,
865
+ new_style_derivation : bool ,
860
866
}
861
867
862
868
impl KeysManager {
@@ -895,7 +901,7 @@ impl KeysManager {
895
901
Err ( _) => panic ! ( "Your RNG is busted" ) ,
896
902
} ;
897
903
let shutdown_pubkey = match master_key. ckd_priv ( & secp_ctx, ChildNumber :: from_hardened_idx ( 2 ) . unwrap ( ) ) {
898
- Ok ( shutdown_key) => ExtendedPubKey :: from_private ( & secp_ctx, & shutdown_key) . public_key . key ,
904
+ Ok ( shutdown_key) => ExtendedPubKey :: from_private ( & secp_ctx, & shutdown_key) ,
899
905
Err ( _) => panic ! ( "Your RNG is busted" ) ,
900
906
} ;
901
907
let channel_master_key = master_key. ckd_priv ( & secp_ctx, ChildNumber :: from_hardened_idx ( 3 ) . unwrap ( ) ) . expect ( "Your RNG is busted" ) ;
@@ -913,7 +919,6 @@ impl KeysManager {
913
919
secp_ctx,
914
920
node_secret,
915
921
inbound_payment_key : KeyMaterial ( inbound_pmt_key_bytes) ,
916
-
917
922
destination_script,
918
923
shutdown_pubkey,
919
924
@@ -927,6 +932,7 @@ impl KeysManager {
927
932
seed : * seed,
928
933
starting_time_secs,
929
934
starting_time_nanos,
935
+ new_style_derivation : true ,
930
936
} ;
931
937
let secp_seed = res. get_secure_random_bytes ( ) ;
932
938
res. secp_ctx . seeded_randomize ( & secp_seed) ;
@@ -1031,7 +1037,7 @@ impl KeysManager {
1031
1037
input_value += descriptor. output . value ;
1032
1038
if !output_set. insert ( descriptor. outpoint ) { return Err ( ( ) ) ; }
1033
1039
} ,
1034
- SpendableOutputDescriptor :: StaticOutput { ref outpoint, ref output } => {
1040
+ SpendableOutputDescriptor :: StaticOutput { ref outpoint, ref output, .. } => {
1035
1041
input. push ( TxIn {
1036
1042
previous_output : outpoint. into_bitcoin_outpoint ( ) ,
1037
1043
script_sig : Script :: new ( ) ,
@@ -1074,12 +1080,17 @@ impl KeysManager {
1074
1080
}
1075
1081
spend_tx. input [ input_idx] . witness = keys_cache. as_ref ( ) . unwrap ( ) . 0 . sign_dynamic_p2wsh_input ( & spend_tx, input_idx, & descriptor, & secp_ctx) ?;
1076
1082
} ,
1077
- SpendableOutputDescriptor :: StaticOutput { ref output, .. } => {
1083
+ SpendableOutputDescriptor :: StaticOutput { ref output, channel_keys_id, .. } => {
1084
+
1085
+ let destination_script = channel_keys_id. map_or_else ( || self . destination_script . clone ( ) , |s| self . get_destination_script ( s) ) ;
1078
1086
let derivation_idx = if output. script_pubkey == self . destination_script {
1079
1087
1
1088
+ } else if output. script_pubkey == destination_script && channel_keys_id. is_some ( ) {
1089
+ byte_utils:: slice_to_be64 ( & channel_keys_id. unwrap ( ) [ 0 ..8 ] ) as u32
1080
1090
} else {
1081
1091
2
1082
1092
} ;
1093
+
1083
1094
let secret = {
1084
1095
// Note that when we aren't serializing the key, network doesn't matter
1085
1096
match ExtendedPrivKey :: new_master ( Network :: Testnet , & self . seed ) {
@@ -1094,7 +1105,7 @@ impl KeysManager {
1094
1105
} ;
1095
1106
let pubkey = ExtendedPubKey :: from_private ( & secp_ctx, & secret) . public_key ;
1096
1107
if derivation_idx == 2 {
1097
- assert_eq ! ( pubkey. key, self . shutdown_pubkey) ;
1108
+ assert_eq ! ( pubkey. key, self . shutdown_pubkey. public_key . key ) ;
1098
1109
}
1099
1110
let witness_script = bitcoin:: Address :: p2pkh ( & pubkey, Network :: Testnet ) . script_pubkey ( ) ;
1100
1111
let payment_script = bitcoin:: Address :: p2wpkh ( & pubkey, Network :: Testnet ) . expect ( "uncompressed key found" ) . script_pubkey ( ) ;
@@ -1134,12 +1145,30 @@ impl KeysInterface for KeysManager {
1134
1145
self . inbound_payment_key . clone ( )
1135
1146
}
1136
1147
1137
- fn get_destination_script ( & self ) -> Script {
1138
- self . destination_script . clone ( )
1148
+ fn get_destination_script ( & self , channel_keys_id : [ u8 ; 32 ] ) -> Script {
1149
+ let derivation_idx = if self . new_style_derivation {
1150
+ byte_utils:: slice_to_be64 ( & channel_keys_id[ 0 ..8 ] )
1151
+ } else {
1152
+ 3
1153
+ } ;
1154
+ match ExtendedPrivKey :: new_master ( Network :: Testnet , & self . seed ) {
1155
+ Ok ( master_key) => {
1156
+ match master_key. ckd_priv ( & self . secp_ctx , ChildNumber :: from_hardened_idx ( derivation_idx as u32 ) . expect ( "key space exhausted" ) ) {
1157
+ Ok ( destination_key) => {
1158
+ let wpubkey_hash = WPubkeyHash :: hash ( & ExtendedPubKey :: from_private ( & self . secp_ctx , & destination_key) . public_key . to_bytes ( ) ) ;
1159
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_PUSHBYTES_0 )
1160
+ . push_slice ( & wpubkey_hash. into_inner ( ) )
1161
+ . into_script ( )
1162
+ } ,
1163
+ Err ( _) => panic ! ( "Your RNG is busted" ) ,
1164
+ }
1165
+ }
1166
+ Err ( _) => panic ! ( "Your RNG is busted" )
1167
+ }
1139
1168
}
1140
1169
1141
1170
fn get_shutdown_scriptpubkey ( & self ) -> ShutdownScript {
1142
- ShutdownScript :: new_p2wpkh_from_pubkey ( self . shutdown_pubkey . clone ( ) )
1171
+ ShutdownScript :: new_p2wpkh_from_pubkey ( self . shutdown_pubkey . public_key . key . clone ( ) )
1143
1172
}
1144
1173
1145
1174
fn get_channel_signer ( & self , _inbound : bool , channel_value_satoshis : u64 ) -> Self :: Signer {
@@ -1218,8 +1247,8 @@ impl KeysInterface for PhantomKeysManager {
1218
1247
self . inbound_payment_key . clone ( )
1219
1248
}
1220
1249
1221
- fn get_destination_script ( & self ) -> Script {
1222
- self . inner . get_destination_script ( )
1250
+ fn get_destination_script ( & self , channel_keys_id : [ u8 ; 32 ] ) -> Script {
1251
+ self . inner . get_destination_script ( channel_keys_id )
1223
1252
}
1224
1253
1225
1254
fn get_shutdown_scriptpubkey ( & self ) -> ShutdownScript {
0 commit comments