| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| //mod hash256; |
| |
| use hash256::HASH256; |
| |
| const RAND_NK: usize=21; |
| const RAND_NJ: usize=6; |
| const RAND_NV: usize=8; |
| |
| pub struct RAND { |
| ira: [u32;RAND_NK], /* random number... */ |
| 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 { /* Marsaglia & Zaman random number generator */ |
| 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 { /* calculate next NK values */ |
| 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 { /* fill initialisation vector */ |
| let inn=(RAND_NV*i)%RAND_NK; |
| self.ira[inn]^=m; /* note XOR */ |
| let t=m; |
| m=sd.wrapping_sub(m); |
| sd=t; |
| } |
| for _ in 0..10000 {self.sbrand();} /* "warm-up" & stir the generator */ |
| } |
| |
| 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 { /* pack 4 bytes into a 32-bit Word */ |
| return ((((b[3] as u32))&0xff)<<24)|(((b[2] as u32)&0xff)<<16)|(((b[1] as u32)&0xff)<<8)|((b[0] as u32)&0xff); |
| } |
| |
| /* Initialize RNG with some real entropy from some external source */ |
| pub fn seed(&mut self,rawlen: usize,raw: &[u8]) { /* initialise from at least 128 byte string of raw random entropy */ |
| 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(); |
| |
| /* initialise PRNG from distilled randomness */ |
| |
| 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(); |
| } |
| |
| /* get random byte */ |
| 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; |
| } |
| } |
| |
| /* test main program */ |
| /* |
| fn main() { |
| let mut raw : [u8;100]=[0;100]; |
| let mut rng=RAND::new(); |
| |
| rng.clean(); |
| for i in 0..100 {raw[i]=i as u8} |
| |
| rng.seed(100,&raw); |
| |
| for _ in 0..1000 { |
| print!("{:03} ",rng.getbyte()); |
| } |
| } |
| */ |