summaryrefslogtreecommitdiffstats
path: root/third_party/rust/neqo-transport/tests/sim/rng.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/neqo-transport/tests/sim/rng.rs')
-rw-r--r--third_party/rust/neqo-transport/tests/sim/rng.rs81
1 files changed, 81 insertions, 0 deletions
diff --git a/third_party/rust/neqo-transport/tests/sim/rng.rs b/third_party/rust/neqo-transport/tests/sim/rng.rs
new file mode 100644
index 0000000000..af4f70eb5f
--- /dev/null
+++ b/third_party/rust/neqo-transport/tests/sim/rng.rs
@@ -0,0 +1,81 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::{convert::TryFrom, ops::Range};
+
+use neqo_common::Decoder;
+
+/// An implementation of a xoshiro256** pseudorandom generator.
+pub struct Random {
+ state: [u64; 4],
+}
+
+impl Random {
+ pub fn new(seed: [u8; 32]) -> Self {
+ assert!(seed.iter().any(|&x| x != 0));
+ let mut dec = Decoder::from(&seed);
+ Self {
+ state: [
+ dec.decode_uint(8).unwrap(),
+ dec.decode_uint(8).unwrap(),
+ dec.decode_uint(8).unwrap(),
+ dec.decode_uint(8).unwrap(),
+ ],
+ }
+ }
+
+ pub fn random(&mut self) -> u64 {
+ let result = (self.state[1].overflowing_mul(5).0)
+ .rotate_right(7)
+ .overflowing_mul(9)
+ .0;
+ let t = self.state[1] << 17;
+
+ self.state[2] ^= self.state[0];
+ self.state[3] ^= self.state[1];
+ self.state[1] ^= self.state[2];
+ self.state[0] ^= self.state[3];
+
+ self.state[2] ^= t;
+ self.state[3] = self.state[3].rotate_right(45);
+
+ result
+ }
+
+ /// Generate a random value from the range.
+ /// If the range is empty or inverted (`range.start > range.end`), then
+ /// this returns the value of `range.start` without generating any random values.
+ pub fn random_from(&mut self, range: Range<u64>) -> u64 {
+ let max = range.end.saturating_sub(range.start);
+ if max == 0 {
+ return range.start;
+ }
+
+ let shift = (max - 1).leading_zeros();
+ assert_ne!(max, 0);
+ loop {
+ let r = self.random() >> shift;
+ if r < max {
+ return range.start + r;
+ }
+ }
+ }
+
+ /// Get the seed necessary to continue from this point.
+ pub fn seed_str(&self) -> String {
+ format!(
+ "{:8x}{:8x}{:8x}{:8x}",
+ self.state[0], self.state[1], self.state[2], self.state[3],
+ )
+ }
+}
+
+impl Default for Random {
+ fn default() -> Self {
+ let buf = neqo_crypto::random(32);
+ Random::new(<[u8; 32]>::try_from(&buf[..]).unwrap())
+ }
+}