cryptopals/src/mt19937.rs

89 lines
2.3 KiB
Rust

use std::num::Wrapping;
#[derive(Debug)]
pub struct MT19937 {
mt: Vec<u32>,
index: usize,
}
const N: usize = 624;
impl MT19937 {
pub fn new() -> MT19937 {
let mut mt = MT19937 {
mt: vec![0; N],
index: N + 1,
};
mt.seed(5489);
mt
}
pub fn splice(&mut self, state: Vec<u32>) {
self.mt = state;
self.index = 624;
}
pub fn seed(&mut self, seed: u32) {
const F: u32 = 1_812_433_253;
self.mt[0] = seed;
for i in 1..N {
self.mt[i] = (Wrapping(F) * Wrapping(self.mt[i - 1] ^ (self.mt[i - 1] >> 30))
+ Wrapping(i as u32))
.0;
}
self.twist();
}
pub fn extract_bytes(&mut self) -> [u8; 4] {
let n = self.extract_number();
n.to_ne_bytes()
}
pub fn extract_number(&mut self) -> u32 {
match self.index.cmp(&N) {
std::cmp::Ordering::Equal => self.twist(),
std::cmp::Ordering::Greater => panic!("Generator was never seeded"),
std::cmp::Ordering::Less => (),
}
const S: u32 = 7;
const T: u32 = 15;
const U: u32 = 11;
const B: u32 = 0x9D2C_5680;
const C: u32 = 0xEFC6_0000;
const D: u32 = 0xFFFF_FFFF;
const L: u32 = 18;
let mut y = self.mt[self.index];
y = y ^ ((y >> U) & D);
y = y ^ ((y << S) & B);
y = y ^ ((y << T) & C);
y = y ^ (y >> L);
self.index += 1;
y
}
fn twist(&mut self) {
const M: usize = 397;
const A: u32 = 0x9908_B0DF;
const LOWER_MASK: u32 = 0x7fff_ffff;
const UPPER_MASK: u32 = 0x8000_0000;
const FIRST_HALF: usize = N - M;
for i in 0..FIRST_HALF {
let bits = self.mt[i] & UPPER_MASK | self.mt[i + 1] & LOWER_MASK;
self.mt[i] = self.mt[i + M] ^ (bits >> 1) ^ ((bits & 1) * A);
}
for i in FIRST_HALF..(N - 1) {
let bits = self.mt[i] & UPPER_MASK | self.mt[i + 1] & LOWER_MASK;
self.mt[i] = self.mt[i - FIRST_HALF] ^ (bits >> 1) ^ ((bits & 1) * A);
}
let i = N - 1;
let bits = self.mt[i] & UPPER_MASK | self.mt[0] & LOWER_MASK;
self.mt[i] = self.mt[M - 1] ^ (bits >> 1) ^ ((bits & 1) * A);
self.index = 0;
}
}