diff --git a/src/toxcore/crypto_core.rs b/src/toxcore/crypto_core.rs index 2ee0cc675..8693d02a3 100644 --- a/src/toxcore/crypto_core.rs +++ b/src/toxcore/crypto_core.rs @@ -62,6 +62,19 @@ pub fn random_usize() -> usize { random_u64() as usize } +/// Return unbiased random number from `[0, limit)` interval. +pub fn random_limit_usize(limit: usize) -> usize { + // TODO: possibly migrate to rand crate, it has more performant version + // of this algorithm implemented with UniformSampler trait + let cap = usize::max_value() - usize::max_value() % limit; + loop { + let n = random_usize(); + if n < cap { + return n % limit; + } + } +} + /** Check if Tox public key `PUBLICKEYBYTES` is valid. Should be used only for input validation. @@ -310,6 +323,13 @@ pub mod tests { assert_ne!(a, b); } + #[test] + fn random_limit_usize_test() { + crypto_init().unwrap(); + let n = random_limit_usize(7); + assert!(n < 7); + } + #[test] fn public_key_valid_test() { crypto_init().unwrap(); diff --git a/src/toxcore/dht/server/mod.rs b/src/toxcore/dht/server/mod.rs index 791e5c10f..eea3c135f 100644 --- a/src/toxcore/dht/server/mod.rs +++ b/src/toxcore/dht/server/mod.rs @@ -508,10 +508,10 @@ impl Server { return Box::new(future::ok(())) } - let mut random_node_idx = random_usize() % good_nodes.len(); + let mut random_node_idx = random_limit_usize(good_nodes.len()); // Increase probability of sending packet to a close node (has lower index) if random_node_idx != 0 { - random_node_idx -= random_usize() % (random_node_idx + 1); + random_node_idx -= random_limit_usize(random_node_idx + 1); } let random_node = &good_nodes[random_node_idx];