From: Wilmer Paulino Date: Wed, 19 Apr 2023 21:58:57 +0000 (-0700) Subject: Implement EntropySource for InMemorySigner X-Git-Tag: v0.0.115~10^2~3 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=2c5bd1c56fd5aeb7cf9b049584cf24bd1852c15d;p=rust-lightning Implement EntropySource for InMemorySigner This allows the `InMemorySigner` to produce its own randomness, which we plan to use when generating signatures in future work. We can no longer derive `Clone` due to the `AtomicCounter`, so we opt to implement it manually. --- diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index c10b5c0e..a0040449 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -240,6 +240,7 @@ impl SignerProvider for KeyProvider { [id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_secret[31]], channel_value_satoshis, channel_keys_id, + channel_keys_id, ); let revoked_commitment = self.make_enforcement_state_cell(keys.commitment_seed); EnforcingSigner::new_with_revoked(keys, revoked_commitment, false) @@ -248,7 +249,7 @@ impl SignerProvider for KeyProvider { fn read_chan_signer(&self, buffer: &[u8]) -> Result { let mut reader = std::io::Cursor::new(buffer); - let inner: InMemorySigner = Readable::read(&mut reader)?; + let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; let state = self.make_enforcement_state_cell(inner.commitment_seed); Ok(EnforcingSigner { diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 59cb41db..876a412d 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -48,7 +48,7 @@ use lightning::util::config::UserConfig; use lightning::util::errors::APIError; use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState}; use lightning::util::logger::Logger; -use lightning::util::ser::{Readable, Writeable}; +use lightning::util::ser::{Readable, ReadableArgs, Writeable}; use crate::utils::test_logger; use crate::utils::test_persister::TestPersister; @@ -347,6 +347,7 @@ impl SignerProvider for KeyProvider { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr], channel_value_satoshis, channel_keys_id, + channel_keys_id, ) } else { InMemorySigner::new( @@ -359,12 +360,13 @@ impl SignerProvider for KeyProvider { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, ctr], channel_value_satoshis, channel_keys_id, + channel_keys_id, ) }, state, false) } fn read_chan_signer(&self, mut data: &[u8]) -> Result { - let inner: InMemorySigner = Readable::read(&mut data)?; + let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?; let state = Arc::new(Mutex::new(EnforcementState::new())); Ok(EnforcingSigner::new_with_revoked( diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 82fae49f..5ff297b1 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -4235,6 +4235,7 @@ mod tests { [41; 32], 0, [0; 32], + [0; 32], ); let counterparty_pubkeys = ChannelPublicKeys { diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 4ad15db8..8d522a3b 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -33,7 +33,7 @@ use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; use crate::util::transaction_utils; use crate::util::crypto::{hkdf_extract_expand_twice, sign}; -use crate::util::ser::{Writeable, Writer, Readable}; +use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs}; use crate::chain::transaction::OutPoint; #[cfg(anchors)] use crate::events::bump_transaction::HTLCDescriptor; @@ -45,6 +45,7 @@ use crate::ln::script::ShutdownScript; use crate::prelude::*; use core::convert::TryInto; +use core::ops::Deref; use core::sync::atomic::{AtomicUsize, Ordering}; use crate::io::{self, Error}; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; @@ -553,7 +554,6 @@ pub trait SignerProvider { fn get_shutdown_scriptpubkey(&self) -> ShutdownScript; } -#[derive(Clone)] /// A simple implementation of [`WriteableEcdsaChannelSigner`] that just keeps the private keys in memory. /// /// This implementation performs no policy checks and is insufficient by itself as @@ -580,6 +580,30 @@ pub struct InMemorySigner { channel_value_satoshis: u64, /// Key derivation parameters. channel_keys_id: [u8; 32], + /// Seed from which all randomness produced is derived from. + rand_bytes_unique_start: [u8; 32], + /// Tracks the number of times we've produced randomness to ensure we don't return the same + /// bytes twice. + rand_bytes_index: AtomicCounter, +} + +impl Clone for InMemorySigner { + fn clone(&self) -> Self { + Self { + funding_key: self.funding_key.clone(), + revocation_base_key: self.revocation_base_key.clone(), + payment_key: self.payment_key.clone(), + delayed_payment_base_key: self.delayed_payment_base_key.clone(), + htlc_base_key: self.htlc_base_key.clone(), + commitment_seed: self.commitment_seed.clone(), + holder_channel_pubkeys: self.holder_channel_pubkeys.clone(), + channel_parameters: self.channel_parameters.clone(), + channel_value_satoshis: self.channel_value_satoshis, + channel_keys_id: self.channel_keys_id, + rand_bytes_unique_start: self.get_secure_random_bytes(), + rand_bytes_index: AtomicCounter::new(), + } + } } impl InMemorySigner { @@ -594,6 +618,7 @@ impl InMemorySigner { commitment_seed: [u8; 32], channel_value_satoshis: u64, channel_keys_id: [u8; 32], + rand_bytes_unique_start: [u8; 32], ) -> InMemorySigner { let holder_channel_pubkeys = InMemorySigner::make_holder_keys(secp_ctx, &funding_key, &revocation_base_key, @@ -610,6 +635,8 @@ impl InMemorySigner { holder_channel_pubkeys, channel_parameters: None, channel_keys_id, + rand_bytes_unique_start, + rand_bytes_index: AtomicCounter::new(), } } @@ -736,6 +763,15 @@ impl InMemorySigner { } } +impl EntropySource for InMemorySigner { + fn get_secure_random_bytes(&self) -> [u8; 32] { + let index = self.rand_bytes_index.get_increment(); + let mut nonce = [0u8; 16]; + nonce[..8].copy_from_slice(&index.to_be_bytes()); + ChaCha20::get_single_block(&self.rand_bytes_unique_start, &nonce) + } +} + impl ChannelSigner for InMemorySigner { fn get_per_commitment_point(&self, idx: u64, secp_ctx: &Secp256k1) -> PublicKey { let commitment_secret = SecretKey::from_slice(&chan_utils::build_commitment_secret(&self.commitment_seed, idx)).unwrap(); @@ -922,8 +958,8 @@ impl Writeable for InMemorySigner { } } -impl Readable for InMemorySigner { - fn read(reader: &mut R) -> Result { +impl ReadableArgs for InMemorySigner where ES::Target: EntropySource { + fn read(reader: &mut R, entropy_source: ES) -> Result { let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); let funding_key = Readable::read(reader)?; @@ -953,6 +989,8 @@ impl Readable for InMemorySigner { holder_channel_pubkeys, channel_parameters: counterparty_channel_data, channel_keys_id: keys_id, + rand_bytes_unique_start: entropy_source.get_secure_random_bytes(), + rand_bytes_index: AtomicCounter::new(), }) } } @@ -1107,6 +1145,7 @@ impl KeysManager { let payment_key = key_step!(b"payment key", revocation_base_key); let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_key); let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key); + let prng_seed = self.get_secure_random_bytes(); InMemorySigner::new( &self.secp_ctx, @@ -1118,6 +1157,7 @@ impl KeysManager { commitment_seed, channel_value_satoshis, params.clone(), + prng_seed, ) } @@ -1323,7 +1363,7 @@ impl SignerProvider for KeysManager { } fn read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader)) + InMemorySigner::read(&mut io::Cursor::new(reader), self) } fn get_destination_script(&self) -> Script { diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index c67b7f69..7ba62a21 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -7549,6 +7549,7 @@ mod tests { [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 10_000_000, [0; 32], + [0; 32], ); assert_eq!(signer.pubkeys().funding_pubkey.serialize()[..], diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 46a7bb34..679652b2 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -161,7 +161,7 @@ impl SignerProvider for OnlyReadsKeysInterface { fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::Signer { unreachable!(); } fn read_chan_signer(&self, mut reader: &[u8]) -> Result { - let inner: InMemorySigner = Readable::read(&mut reader)?; + let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; let state = Arc::new(Mutex::new(EnforcementState::new())); Ok(EnforcingSigner::new_with_revoked( @@ -783,7 +783,7 @@ impl SignerProvider for TestKeysInterface { fn read_chan_signer(&self, buffer: &[u8]) -> Result { let mut reader = io::Cursor::new(buffer); - let inner: InMemorySigner = Readable::read(&mut reader)?; + let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; let state = self.make_enforcement_state_cell(inner.commitment_seed); Ok(EnforcingSigner::new_with_revoked(