From: Matt Corallo Date: Sat, 13 Feb 2021 16:20:07 +0000 (-0500) Subject: Randomize secp contexts for marginally better sidechannel resistance X-Git-Tag: v0.0.13~18^2~2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=1521633ca235449130d5fdea1382627c26c5544b;p=rust-lightning Randomize secp contexts for marginally better sidechannel resistance --- diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 71490dd6e..a830c8216 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -951,7 +951,7 @@ impl Writeable for ChannelMonitor { } impl ChannelMonitor { - pub(crate) fn new(keys: Signer, shutdown_pubkey: &PublicKey, + pub(crate) fn new(secp_ctx: Secp256k1, 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 ChannelMonitor { 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 ChannelMonitor { }; 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> 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> 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, diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 9d3b95586..26654d7a8 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -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"); diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 95dcde2c2..1fc0d8b3c 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -521,13 +521,16 @@ impl Channel { 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 Channel { } } 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 Channel { 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 Channel { 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 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, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 8fd243ae7..4b10340f4 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -766,7 +766,8 @@ impl 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, diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 7228a687a..f3d8b2e94 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -406,6 +406,9 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler { } 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 { pending_claim_requests, onchain_events_waiting_threshold_conf, latest_height, - secp_ctx: Secp256k1::new(), + secp_ctx, }) } } impl OnchainTxHandler { - 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) -> Self { OnchainTxHandler { destination_script, holder_commitment, @@ -438,7 +441,7 @@ impl OnchainTxHandler { onchain_events_waiting_threshold_conf: HashMap::new(), latest_height: 0, - secp_ctx: Secp256k1::new(), + secp_ctx, } } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index fb54299fb..c2d22a4a0 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -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 { EnforcingSigner::read(&mut std::io::Cursor::new(reader))