DRY up EntropySource implementation
authorJeffrey Czyz <jkczyz@gmail.com>
Wed, 3 Jan 2024 21:41:00 +0000 (15:41 -0600)
committerJeffrey Czyz <jkczyz@gmail.com>
Tue, 16 Jan 2024 02:12:37 +0000 (20:12 -0600)
The ChaCha20-based EntropySource implementation is duplicated within the
sign module. Refactor those into a RandomBytes implementation so that it
may be reused both there. Also useful as a standalone EntropySource
implementation for tests where an independent EntropySource is needed to
ensure that backwards-compatibility testing is not broken.

lightning/src/sign/mod.rs

index 4e418f049bbc9867a7a2a7920706e17c135ed23e..31220879416f2837fd6af0c73e118fccb2bf6e4c 100644 (file)
@@ -822,11 +822,8 @@ 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,
+       /// A source of random bytes.
+       entropy_source: RandomBytes,
 }
 
 impl PartialEq for InMemorySigner {
@@ -857,8 +854,7 @@ impl Clone for InMemorySigner {
                        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(),
+                       entropy_source: RandomBytes::new(self.get_secure_random_bytes()),
                }
        }
 }
@@ -892,8 +888,7 @@ impl InMemorySigner {
                        holder_channel_pubkeys,
                        channel_parameters: None,
                        channel_keys_id,
-                       rand_bytes_unique_start,
-                       rand_bytes_index: AtomicCounter::new(),
+                       entropy_source: RandomBytes::new(rand_bytes_unique_start),
                }
        }
 
@@ -1069,10 +1064,7 @@ 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)
+               self.entropy_source.get_secure_random_bytes()
        }
 }
 
@@ -1350,8 +1342,7 @@ impl<ES: Deref> ReadableArgs<ES> for InMemorySigner where ES::Target: EntropySou
                        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(),
+                       entropy_source: RandomBytes::new(entropy_source.get_secure_random_bytes()),
                })
        }
 }
@@ -1379,8 +1370,7 @@ pub struct KeysManager {
        channel_master_key: ExtendedPrivKey,
        channel_child_index: AtomicUsize,
 
-       rand_bytes_unique_start: [u8; 32],
-       rand_bytes_index: AtomicCounter,
+       entropy_source: RandomBytes,
 
        seed: [u8; 32],
        starting_time_secs: u64,
@@ -1449,8 +1439,7 @@ impl KeysManager {
                                        channel_master_key,
                                        channel_child_index: AtomicUsize::new(0),
 
-                                       rand_bytes_unique_start,
-                                       rand_bytes_index: AtomicCounter::new(),
+                                       entropy_source: RandomBytes::new(rand_bytes_unique_start),
 
                                        seed: *seed,
                                        starting_time_secs,
@@ -1631,10 +1620,7 @@ impl KeysManager {
 
 impl EntropySource for KeysManager {
        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)
+               self.entropy_source.get_secure_random_bytes()
        }
 }
 
@@ -1888,6 +1874,35 @@ impl PhantomKeysManager {
        }
 }
 
+/// An implementation of [`EntropySource`] using [`ChaCha20`].
+#[derive(Debug)]
+struct RandomBytes {
+       /// Seed from which all randomness produced is derived from.
+       seed: [u8; 32],
+       /// Tracks the number of times we've produced randomness to ensure we don't return the same
+       /// bytes twice.
+       index: AtomicCounter,
+}
+
+impl RandomBytes {
+       /// Creates a new instance using the given seed.
+       pub fn new(seed: [u8; 32]) -> Self {
+               Self {
+                       seed,
+                       index: AtomicCounter::new(),
+               }
+       }
+}
+
+impl EntropySource for RandomBytes {
+       fn get_secure_random_bytes(&self) -> [u8; 32] {
+               let index = self.index.get_increment();
+               let mut nonce = [0u8; 16];
+               nonce[..8].copy_from_slice(&index.to_be_bytes());
+               ChaCha20::get_single_block(&self.seed, &nonce)
+       }
+}
+
 // Ensure that EcdsaChannelSigner can have a vtable
 #[test]
 pub fn dyn_sign() {