Skip to main content

amcl/
rand.rs

1/*
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements.  See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership.  The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"); you may not use this file except in compliance
8with the License.  You may obtain a copy of the License at
9
10  http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied.  See the License for the
16specific language governing permissions and limitations
17under the License.
18*/
19
20//mod hash256;
21
22use crate::hash256::HASH256;
23
24const RAND_NK: usize = 21;
25const RAND_NJ: usize = 6;
26const RAND_NV: usize = 8;
27
28pub struct RAND {
29    ira: [u32; RAND_NK], /* random number...   */
30    rndptr: usize,
31    borrow: u32,
32    pool_ptr: usize,
33    pool: [u8; 32],
34}
35
36impl RAND {
37    pub fn new() -> RAND {
38        RAND {
39            ira: [0; RAND_NK],
40            rndptr: 0,
41            borrow: 0,
42            pool_ptr: 0,
43            pool: [0; 32],
44        }
45    }
46
47    pub fn clean(&mut self) {
48        self.pool_ptr = 0;
49        self.rndptr = 0;
50        for i in 0..32 {
51            self.pool[i] = 0
52        }
53        for i in 0..RAND_NK {
54            self.ira[i] = 0
55        }
56        self.borrow = 0;
57    }
58
59    fn sbrand(&mut self) -> u32 {
60        /* Marsaglia & Zaman random number generator */
61        self.rndptr += 1;
62        if self.rndptr < RAND_NK {
63            return self.ira[self.rndptr];
64        }
65        self.rndptr = 0;
66        let mut k = RAND_NK - RAND_NJ;
67        for i in 0..RAND_NK {
68            /* calculate next NK values */
69            if k == RAND_NK {
70                k = 0
71            }
72            let t = self.ira[k];
73            let pdiff = t.wrapping_sub(self.ira[i]).wrapping_sub(self.borrow);
74            if pdiff < t {
75                self.borrow = 0
76            }
77            if pdiff > t {
78                self.borrow = 1
79            }
80            self.ira[i] = pdiff;
81            k += 1;
82        }
83        return self.ira[0];
84    }
85
86    fn sirand(&mut self, seed: u32) {
87        let mut m: u32 = 1;
88        let mut sd = seed;
89        self.borrow = 0;
90        self.rndptr = 0;
91        self.ira[0] ^= sd;
92        for i in 1..RAND_NK {
93            /* fill initialisation vector */
94            let inn = (RAND_NV * i) % RAND_NK;
95            self.ira[inn] ^= m; /* note XOR */
96            let t = m;
97            m = sd.wrapping_sub(m);
98            sd = t;
99        }
100        for _ in 0..10000 {
101            self.sbrand();
102        } /* "warm-up" & stir the generator */
103    }
104
105    fn fill_pool(&mut self) {
106        let mut sh = HASH256::new();
107        for _ in 0..128 {
108            sh.process((self.sbrand() & 0xff) as u8)
109        }
110        let w = sh.hash();
111        for i in 0..32 {
112            self.pool[i] = w[i]
113        }
114        self.pool_ptr = 0;
115    }
116
117    fn pack(b: [u8; 4]) -> u32 {
118        /* pack 4 bytes into a 32-bit Word */
119        return (((b[3] as u32) & 0xff) << 24)
120            | (((b[2] as u32) & 0xff) << 16)
121            | (((b[1] as u32) & 0xff) << 8)
122            | ((b[0] as u32) & 0xff);
123    }
124
125    /* Initialize RNG with some real entropy from some external source */
126    pub fn seed(&mut self, rawlen: usize, raw: &[u8]) {
127        /* initialise from at least 128 byte string of raw random entropy */
128        let mut b: [u8; 4] = [0; 4];
129        let mut sh = HASH256::new();
130        self.pool_ptr = 0;
131
132        for i in 0..RAND_NK {
133            self.ira[i] = 0
134        }
135        if rawlen > 0 {
136            for i in 0..rawlen {
137                sh.process(raw[i]);
138            }
139            let digest = sh.hash();
140
141            /* initialise PRNG from distilled randomness */
142
143            for i in 0..8 {
144                b[0] = digest[4 * i];
145                b[1] = digest[4 * i + 1];
146                b[2] = digest[4 * i + 2];
147                b[3] = digest[4 * i + 3];
148                self.sirand(RAND::pack(b));
149            }
150        }
151        self.fill_pool();
152    }
153
154    /* get random byte */
155    pub fn getbyte(&mut self) -> u8 {
156        let r = self.pool[self.pool_ptr];
157        self.pool_ptr += 1;
158        if self.pool_ptr >= 32 {
159            self.fill_pool()
160        }
161        return (r & 0xff) as u8;
162    }
163}
164
165/* test main program */
166/*
167fn main() {
168    let mut raw : [u8;100]=[0;100];
169    let mut rng=RAND::new();
170
171    rng.clean();
172    for i in 0..100 {raw[i]=i as u8}
173
174    rng.seed(100,&raw);
175
176    for _ in 0..1000 {
177        print!("{:03} ",rng.getbyte());
178    }
179}
180*/