Skip to content

Commit d4de913

Browse files
authored
Merge pull request #1974 from danielgranhao/speed-up-secure-random-byte-gen
2 parents 801d297 + f19821d commit d4de913

File tree

2 files changed

+72
-21
lines changed

2 files changed

+72
-21
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use bitcoin::util::sighash;
2121

2222
use bitcoin::bech32::u5;
2323
use bitcoin::hashes::{Hash, HashEngine};
24-
use bitcoin::hashes::sha256::HashEngine as Sha256State;
2524
use bitcoin::hashes::sha256::Hash as Sha256;
2625
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
2726
use bitcoin::hash_types::WPubkeyHash;
@@ -49,6 +48,8 @@ use core::convert::TryInto;
4948
use core::sync::atomic::{AtomicUsize, Ordering};
5049
use crate::io::{self, Error};
5150
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
51+
use crate::util::atomic_counter::AtomicCounter;
52+
use crate::util::chacha20::ChaCha20;
5253
use crate::util::invoice::construct_invoice_preimage;
5354

5455
/// Used as initial key material, to be expanded into multiple secret keys (but not to be used
@@ -979,9 +980,8 @@ pub struct KeysManager {
979980
channel_master_key: ExtendedPrivKey,
980981
channel_child_index: AtomicUsize,
981982

982-
rand_bytes_master_key: ExtendedPrivKey,
983-
rand_bytes_child_index: AtomicUsize,
984-
rand_bytes_unique_start: Sha256State,
983+
rand_bytes_unique_start: [u8; 32],
984+
rand_bytes_index: AtomicCounter,
985985

986986
seed: [u8; 32],
987987
starting_time_secs: u64,
@@ -1027,15 +1027,16 @@ impl KeysManager {
10271027
Err(_) => panic!("Your RNG is busted"),
10281028
};
10291029
let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3).unwrap()).expect("Your RNG is busted");
1030-
let rand_bytes_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted");
10311030
let inbound_payment_key: SecretKey = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted").private_key;
10321031
let mut inbound_pmt_key_bytes = [0; 32];
10331032
inbound_pmt_key_bytes.copy_from_slice(&inbound_payment_key[..]);
10341033

1035-
let mut rand_bytes_unique_start = Sha256::engine();
1036-
rand_bytes_unique_start.input(&starting_time_secs.to_be_bytes());
1037-
rand_bytes_unique_start.input(&starting_time_nanos.to_be_bytes());
1038-
rand_bytes_unique_start.input(seed);
1034+
let mut rand_bytes_engine = Sha256::engine();
1035+
rand_bytes_engine.input(&starting_time_secs.to_be_bytes());
1036+
rand_bytes_engine.input(&starting_time_nanos.to_be_bytes());
1037+
rand_bytes_engine.input(seed);
1038+
rand_bytes_engine.input(b"LDK PRNG Seed");
1039+
let rand_bytes_unique_start = Sha256::from_engine(rand_bytes_engine).into_inner();
10391040

10401041
let mut res = KeysManager {
10411042
secp_ctx,
@@ -1049,9 +1050,8 @@ impl KeysManager {
10491050
channel_master_key,
10501051
channel_child_index: AtomicUsize::new(0),
10511052

1052-
rand_bytes_master_key,
1053-
rand_bytes_child_index: AtomicUsize::new(0),
10541053
rand_bytes_unique_start,
1054+
rand_bytes_index: AtomicCounter::new(),
10551055

10561056
seed: *seed,
10571057
starting_time_secs,
@@ -1248,14 +1248,10 @@ impl KeysManager {
12481248

12491249
impl EntropySource for KeysManager {
12501250
fn get_secure_random_bytes(&self) -> [u8; 32] {
1251-
let mut sha = self.rand_bytes_unique_start.clone();
1252-
1253-
let child_ix = self.rand_bytes_child_index.fetch_add(1, Ordering::AcqRel);
1254-
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");
1255-
sha.input(&child_privkey.private_key[..]);
1256-
1257-
sha.input(b"Unique Secure Random Bytes Salt");
1258-
Sha256::from_engine(sha).into_inner()
1251+
let index = self.rand_bytes_index.get_increment();
1252+
let mut nonce = [0u8; 16];
1253+
nonce[..8].copy_from_slice(&index.to_be_bytes());
1254+
ChaCha20::get_single_block(&self.rand_bytes_unique_start, &nonce)
12591255
}
12601256
}
12611257

@@ -1469,3 +1465,58 @@ impl PhantomKeysManager {
14691465
pub fn dyn_sign() {
14701466
let _signer: Box<dyn EcdsaChannelSigner>;
14711467
}
1468+
1469+
#[cfg(all(test, feature = "_bench_unstable", not(feature = "no-std")))]
1470+
mod benches {
1471+
use std::sync::{Arc, mpsc};
1472+
use std::sync::mpsc::TryRecvError;
1473+
use std::thread;
1474+
use std::time::Duration;
1475+
use bitcoin::blockdata::constants::genesis_block;
1476+
use bitcoin::Network;
1477+
use crate::chain::keysinterface::{EntropySource, KeysManager};
1478+
1479+
use test::Bencher;
1480+
1481+
#[bench]
1482+
fn bench_get_secure_random_bytes(bench: &mut Bencher) {
1483+
let seed = [0u8; 32];
1484+
let now = Duration::from_secs(genesis_block(Network::Testnet).header.time as u64);
1485+
let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_micros()));
1486+
1487+
let mut handles = Vec::new();
1488+
let mut stops = Vec::new();
1489+
for _ in 1..5 {
1490+
let keys_manager_clone = Arc::clone(&keys_manager);
1491+
let (stop_sender, stop_receiver) = mpsc::channel();
1492+
let handle = thread::spawn(move || {
1493+
loop {
1494+
keys_manager_clone.get_secure_random_bytes();
1495+
match stop_receiver.try_recv() {
1496+
Ok(_) | Err(TryRecvError::Disconnected) => {
1497+
println!("Terminating.");
1498+
break;
1499+
}
1500+
Err(TryRecvError::Empty) => {}
1501+
}
1502+
}
1503+
});
1504+
handles.push(handle);
1505+
stops.push(stop_sender);
1506+
}
1507+
1508+
bench.iter(|| {
1509+
for _ in 1..100 {
1510+
keys_manager.get_secure_random_bytes();
1511+
}
1512+
});
1513+
1514+
for stop in stops {
1515+
let _ = stop.send(());
1516+
}
1517+
for handle in handles {
1518+
handle.join().unwrap();
1519+
}
1520+
}
1521+
1522+
}

lightning/src/ln/functional_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7250,8 +7250,8 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
72507250
assert_ne!(node_txn[0].input[0].previous_output, node_txn[2].input[0].previous_output);
72517251
assert_ne!(node_txn[1].input[0].previous_output, node_txn[2].input[0].previous_output);
72527252

7253-
assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
7254-
assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output);
7253+
assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output);
7254+
assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
72557255

72567256
// node_txn[3] spends the revoked outputs from the revoked_htlc_txn (which only have one
72577257
// output, checked above).

0 commit comments

Comments
 (0)