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*/