Implement EntropySource for InMemorySigner
authorWilmer Paulino <wilmer@wilmerpaulino.com>
Wed, 19 Apr 2023 21:58:57 +0000 (14:58 -0700)
committerWilmer Paulino <wilmer@wilmerpaulino.com>
Thu, 20 Apr 2023 19:14:19 +0000 (12:14 -0700)
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.

fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning/src/chain/channelmonitor.rs
lightning/src/chain/keysinterface.rs
lightning/src/ln/channel.rs
lightning/src/util/test_utils.rs

index c10b5c0e364ae770467dd03a74e8d1d1fed01c15..a00404497fa1c4146d42abfb20a8cb2474de3220 100644 (file)
@@ -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<Self::Signer, DecodeError> {
                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 {
index 59cb41dbb451da7c666afa8e0fcb8f1461c28b00..876a412da5fef668c74dd5b215999ece3d2901d1 100644 (file)
@@ -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<EnforcingSigner, DecodeError> {
-               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(
index 82fae49f7ce5374b33f80ec9b556d99f1dcb8eb4..5ff297b1af7477c4fee3cff8d8b5db6a7f428a48 100644 (file)
@@ -4235,6 +4235,7 @@ mod tests {
                        [41; 32],
                        0,
                        [0; 32],
+                       [0; 32],
                );
 
                let counterparty_pubkeys = ChannelPublicKeys {
index 4ad15db876bb4cad83106c89ba7ba835409b1544..8d522a3b46dd80a7cfe9e83d9f211480b9d47490 100644 (file)
@@ -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<secp256k1::All>) -> 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<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+impl<ES: Deref> ReadableArgs<ES> for InMemorySigner where ES::Target: EntropySource {
+       fn read<R: io::Read>(reader: &mut R, entropy_source: ES) -> Result<Self, DecodeError> {
                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<Self::Signer, DecodeError> {
-               InMemorySigner::read(&mut io::Cursor::new(reader))
+               InMemorySigner::read(&mut io::Cursor::new(reader), self)
        }
 
        fn get_destination_script(&self) -> Script {
index c67b7f695a5f7c9fdffdb81db84a804390254174..7ba62a216e1b6097497ee26599d47254d26fb199 100644 (file)
@@ -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()[..],
index 46a7bb340070618b85e69f860148b0319f14cea4..679652b2da49402a2c76f2f0720407c0928e043b 100644 (file)
@@ -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<Self::Signer, msgs::DecodeError> {
-               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<Self::Signer, msgs::DecodeError> {
                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(