use crate::hash256::HASH256;
const RAND_NK: usize = 21;
const RAND_NJ: usize = 6;
const RAND_NV: usize = 8;
pub struct RAND {
ira: [u32; RAND_NK],
rndptr: usize,
borrow: u32,
pool_ptr: usize,
pool: [u8; 32],
}
impl RAND {
pub fn new() -> RAND {
RAND {
ira: [0; RAND_NK],
rndptr: 0,
borrow: 0,
pool_ptr: 0,
pool: [0; 32],
}
}
pub fn clean(&mut self) {
self.pool_ptr = 0;
self.rndptr = 0;
for i in 0..32 {
self.pool[i] = 0
}
for i in 0..RAND_NK {
self.ira[i] = 0
}
self.borrow = 0;
}
fn sbrand(&mut self) -> u32 {
self.rndptr += 1;
if self.rndptr < RAND_NK {
return self.ira[self.rndptr];
}
self.rndptr = 0;
let mut k = RAND_NK - RAND_NJ;
for i in 0..RAND_NK {
if k == RAND_NK {
k = 0
}
let t = self.ira[k];
let pdiff = t.wrapping_sub(self.ira[i]).wrapping_sub(self.borrow);
if pdiff < t {
self.borrow = 0
}
if pdiff > t {
self.borrow = 1
}
self.ira[i] = pdiff;
k += 1;
}
return self.ira[0];
}
fn sirand(&mut self, seed: u32) {
let mut m: u32 = 1;
let mut sd = seed;
self.borrow = 0;
self.rndptr = 0;
self.ira[0] ^= sd;
for i in 1..RAND_NK {
let inn = (RAND_NV * i) % RAND_NK;
self.ira[inn] ^= m;
let t = m;
m = sd.wrapping_sub(m);
sd = t;
}
for _ in 0..10000 {
self.sbrand();
}
}
fn fill_pool(&mut self) {
let mut sh = HASH256::new();
for _ in 0..128 {
sh.process((self.sbrand() & 0xff) as u8)
}
let w = sh.hash();
for i in 0..32 {
self.pool[i] = w[i]
}
self.pool_ptr = 0;
}
fn pack(b: [u8; 4]) -> u32 {
return (((b[3] as u32) & 0xff) << 24)
| (((b[2] as u32) & 0xff) << 16)
| (((b[1] as u32) & 0xff) << 8)
| ((b[0] as u32) & 0xff);
}
pub fn seed(&mut self, rawlen: usize, raw: &[u8]) {
let mut b: [u8; 4] = [0; 4];
let mut sh = HASH256::new();
self.pool_ptr = 0;
for i in 0..RAND_NK {
self.ira[i] = 0
}
if rawlen > 0 {
for i in 0..rawlen {
sh.process(raw[i]);
}
let digest = sh.hash();
for i in 0..8 {
b[0] = digest[4 * i];
b[1] = digest[4 * i + 1];
b[2] = digest[4 * i + 2];
b[3] = digest[4 * i + 3];
self.sirand(RAND::pack(b));
}
}
self.fill_pool();
}
pub fn getbyte(&mut self) -> u8 {
let r = self.pool[self.pool_ptr];
self.pool_ptr += 1;
if self.pool_ptr >= 32 {
self.fill_pool()
}
return (r & 0xff) as u8;
}
}