Randomize secp contexts for marginally better sidechannel resistance
authorMatt Corallo <git@bluematt.me>
Sat, 13 Feb 2021 16:20:07 +0000 (11:20 -0500)
committerMatt Corallo <git@bluematt.me>
Sat, 27 Feb 2021 04:47:03 +0000 (23:47 -0500)
lightning/src/chain/channelmonitor.rs
lightning/src/chain/keysinterface.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/onchaintx.rs
lightning/src/util/test_utils.rs

index 71490dd6e0e1af4de7b19b71e8699da47d5c2f46..a830c8216a6a4e8fe0e631763380ea12b05836ee 100644 (file)
@@ -951,7 +951,7 @@ impl<Signer: Sign> Writeable for ChannelMonitor<Signer> {
 }
 
 impl<Signer: Sign> ChannelMonitor<Signer> {
-       pub(crate) fn new(keys: Signer, shutdown_pubkey: &PublicKey,
+       pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_pubkey: &PublicKey,
                          on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script),
                          channel_parameters: &ChannelTransactionParameters,
                          funding_redeemscript: Script, channel_value_satoshis: u64,
@@ -972,8 +972,6 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
                let channel_keys_id = keys.channel_keys_id();
                let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint;
 
-               let secp_ctx = Secp256k1::new();
-
                // block for Rust 1.34 compat
                let (holder_commitment_tx, current_holder_commitment_number) = {
                        let trusted_tx = initial_holder_commitment_tx.trust();
@@ -994,7 +992,8 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
                };
 
                let onchain_tx_handler =
-                       OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone(), initial_holder_commitment_tx);
+                       OnchainTxHandler::new(destination_script.clone(), keys,
+                       channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx.clone());
 
                let mut outputs_to_watch = HashMap::new();
                outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]);
@@ -2558,6 +2557,9 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
                let lockdown_from_offchain = Readable::read(reader)?;
                let holder_tx_signed = Readable::read(reader)?;
 
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
+
                Ok((last_block_hash.clone(), ChannelMonitor {
                        latest_update_id,
                        commitment_transaction_number_obscure_factor,
@@ -2603,7 +2605,7 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
                        holder_tx_signed,
 
                        last_block_hash,
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
                }))
        }
 }
@@ -2718,7 +2720,7 @@ mod tests {
                };
                // Prune with one old state and a holder commitment tx holding a few overlaps with the
                // old state.
-               let mut monitor = ChannelMonitor::new(keys,
+               let mut monitor = ChannelMonitor::new(Secp256k1::new(), keys,
                                                      &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
                                                      (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
                                                      &channel_parameters,
index 9d3b955861dbfca672fabf614ab4378f58aaa6a7..26654d7a8de57fc037cf88635c0935024d0ea20b 100644 (file)
@@ -744,8 +744,10 @@ pub struct KeysManager {
        shutdown_pubkey: PublicKey,
        channel_master_key: ExtendedPrivKey,
        channel_child_index: AtomicUsize,
+
        rand_bytes_master_key: ExtendedPrivKey,
        rand_bytes_child_index: AtomicUsize,
+       rand_bytes_unique_start: Sha256State,
 
        seed: [u8; 32],
        starting_time_secs: u64,
@@ -794,31 +796,36 @@ impl KeysManager {
                                let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3).unwrap()).expect("Your RNG is busted");
                                let rand_bytes_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted");
 
-                               KeysManager {
+                               let mut rand_bytes_unique_start = Sha256::engine();
+                               rand_bytes_unique_start.input(&byte_utils::be64_to_array(starting_time_secs));
+                               rand_bytes_unique_start.input(&byte_utils::be32_to_array(starting_time_nanos));
+                               rand_bytes_unique_start.input(seed);
+
+                               let mut res = KeysManager {
                                        secp_ctx,
                                        node_secret,
+
                                        destination_script,
                                        shutdown_pubkey,
+
                                        channel_master_key,
                                        channel_child_index: AtomicUsize::new(0),
+
                                        rand_bytes_master_key,
                                        rand_bytes_child_index: AtomicUsize::new(0),
+                                       rand_bytes_unique_start,
 
                                        seed: *seed,
                                        starting_time_secs,
                                        starting_time_nanos,
-                               }
+                               };
+                               let secp_seed = res.get_secure_random_bytes();
+                               res.secp_ctx.seeded_randomize(&secp_seed);
+                               res
                        },
                        Err(_) => panic!("Your rng is busted"),
                }
        }
-       fn derive_unique_start(&self) -> Sha256State {
-               let mut unique_start = Sha256::engine();
-               unique_start.input(&byte_utils::be64_to_array(self.starting_time_secs));
-               unique_start.input(&byte_utils::be32_to_array(self.starting_time_nanos));
-               unique_start.input(&self.seed);
-               unique_start
-       }
        /// Derive an old set of Sign for per-channel secrets based on a key derivation
        /// parameters.
        /// Key derivation parameters are accessible through a per-channel secrets
@@ -1017,7 +1024,7 @@ impl KeysInterface for KeysManager {
        }
 
        fn get_secure_random_bytes(&self) -> [u8; 32] {
-               let mut sha = self.derive_unique_start();
+               let mut sha = self.rand_bytes_unique_start.clone();
 
                let child_ix = self.rand_bytes_child_index.fetch_add(1, Ordering::AcqRel);
                let child_privkey = self.rand_bytes_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted");
index 95dcde2c25c6ba1bd3210fd34a54af6a2e4cb1b6..1fc0d8b3cd6bb263b859886e1463c294495e194f 100644 (file)
@@ -521,13 +521,16 @@ impl<Signer: Sign> Channel<Signer> {
 
                let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
 
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes());
+
                Ok(Channel {
                        user_id,
                        config: config.channel_options.clone(),
 
                        channel_id: keys_provider.get_secure_random_bytes(),
                        channel_state: ChannelState::OurInitSent as u32,
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
                        channel_value_satoshis,
 
                        latest_monitor_update_id: 0,
@@ -755,13 +758,16 @@ impl<Signer: Sign> Channel<Signer> {
                        }
                } else { None };
 
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes());
+
                let chan = Channel {
                        user_id,
                        config: local_config,
 
                        channel_id: msg.temporary_channel_id,
                        channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
 
                        latest_monitor_update_id: 0,
 
@@ -1564,7 +1570,7 @@ impl<Signer: Sign> Channel<Signer> {
                let funding_redeemscript = self.get_funding_redeemscript();
                let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
                let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound());
-               let mut channel_monitor = ChannelMonitor::new(self.holder_signer.clone(),
+               let mut channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(),
                                                              &self.shutdown_pubkey, self.get_holder_selected_contest_delay(),
                                                              &self.destination_script, (funding_txo, funding_txo_script.clone()),
                                                              &self.channel_transaction_parameters,
@@ -1634,7 +1640,7 @@ impl<Signer: Sign> Channel<Signer> {
                let funding_txo = self.get_funding_txo().unwrap();
                let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
                let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound());
-               let mut channel_monitor = ChannelMonitor::new(self.holder_signer.clone(),
+               let mut channel_monitor = ChannelMonitor::new(self.secp_ctx.clone(), self.holder_signer.clone(),
                                                              &self.shutdown_pubkey, self.get_holder_selected_contest_delay(),
                                                              &self.destination_script, (funding_txo, funding_txo_script),
                                                              &self.channel_transaction_parameters,
@@ -4608,13 +4614,16 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
                let counterparty_shutdown_scriptpubkey = Readable::read(reader)?;
                let commitment_secrets = Readable::read(reader)?;
 
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&keys_source.get_secure_random_bytes());
+
                Ok(Channel {
                        user_id,
 
                        config,
                        channel_id,
                        channel_state,
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
                        channel_value_satoshis,
 
                        latest_monitor_update_id,
index 8fd243ae7720276c6025d6a0ece52509edc9e8c0..4b10340f4c37ba05683679169e9d674262485774 100644 (file)
@@ -766,7 +766,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// Users need to notify the new ChannelManager when a new block is connected or
        /// disconnected using its `block_connected` and `block_disconnected` methods.
        pub fn new(network: Network, fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, current_blockchain_height: usize) -> Self {
-               let secp_ctx = Secp256k1::new();
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
 
                ChannelManager {
                        default_configuration: config.clone(),
@@ -4129,6 +4130,9 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
 
                let last_node_announcement_serial: u32 = Readable::read(reader)?;
 
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&args.keys_manager.get_secure_random_bytes());
+
                let channel_manager = ChannelManager {
                        genesis_hash,
                        fee_estimator: args.fee_estimator,
@@ -4137,7 +4141,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
 
                        latest_block_height: AtomicUsize::new(latest_block_height as usize),
                        last_block_hash: Mutex::new(last_block_hash),
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
 
                        channel_state: Mutex::new(ChannelHolder {
                                by_id,
index 7228a687aca6eee88a670ab35a46bba3bb77443c..f3d8b2e9489d5078dc79dbc42be835fa54fe56f5 100644 (file)
@@ -406,6 +406,9 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
                }
                let latest_height = Readable::read(reader)?;
 
+               let mut secp_ctx = Secp256k1::new();
+               secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
+
                Ok(OnchainTxHandler {
                        destination_script,
                        holder_commitment,
@@ -418,13 +421,13 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::Signer> {
                        pending_claim_requests,
                        onchain_events_waiting_threshold_conf,
                        latest_height,
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
                })
        }
 }
 
 impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
-       pub(crate) fn new(destination_script: Script, signer: ChannelSigner, channel_parameters: ChannelTransactionParameters, holder_commitment: HolderCommitmentTransaction) -> Self {
+       pub(crate) fn new(destination_script: Script, signer: ChannelSigner, channel_parameters: ChannelTransactionParameters, holder_commitment: HolderCommitmentTransaction, secp_ctx: Secp256k1<secp256k1::All>) -> Self {
                OnchainTxHandler {
                        destination_script,
                        holder_commitment,
@@ -438,7 +441,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
                        onchain_events_waiting_threshold_conf: HashMap::new(),
                        latest_height: 0,
 
-                       secp_ctx: Secp256k1::new(),
+                       secp_ctx,
                }
        }
 
index fb54299fb3f73b5faadbce347f5ed0c99486ddbe..c2d22a4a060f1df23143b38863952ca5af368354 100644 (file)
@@ -69,7 +69,7 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface {
        fn get_destination_script(&self) -> Script { unreachable!(); }
        fn get_shutdown_pubkey(&self) -> PublicKey { unreachable!(); }
        fn get_channel_signer(&self, _inbound: bool, _channel_value_satoshis: u64) -> EnforcingSigner { unreachable!(); }
-       fn get_secure_random_bytes(&self) -> [u8; 32] { unreachable!(); }
+       fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }
 
        fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, msgs::DecodeError> {
                EnforcingSigner::read(&mut std::io::Cursor::new(reader))