lib_unknown/rand.rs
1//! 硬件熵随机数:时间戳熵源(`probe`)、重播种(`seed`)与热路径输出(`next`),另含区间采样与 `fill_bytes`(`rand-expand`)。
2//!
3//! 需要启用 `"rand"` 特性。
4#![allow(unused)]
5
6use crate::crypto::base::{mix64, shuffle_with};
7use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
8// /dev/urandom参考
9// ❯ head -c 10M /dev/urandom > small_samples.bin
10// ❯ /home/zz/Documents/git/SP800-90B_EntropyAssessment/cpp/ea_non_iid -i -v -a small_samples.bin 8
11// Opening file: 'small_samples.bin' (SHA-256 hash 4466b8477a570ab30889532da827030cc389125bd484d43f8339cf00a23c90bd)
12// Loaded 10485760 samples of 256 distinct 8-bit-wide symbols
13// Number of Binary Symbols: 83886080
14//
15// Running non-IID tests...
16//
17// Running Most Common Value Estimate...
18// Bitstring MCV Estimate: mode = 41944627, p-hat = 0.50001891851425173, p_u = 0.50015953690906079
19// Most Common Value Estimate (bit string) = 0.999540 / 1 bit(s)
20// Literal MCV Estimate: mode = 41721, p-hat = 0.003978824615478516, p_u = 0.0040289005228594642
21// Most Common Value Estimate = 7.955398 / 8 bit(s)
22//
23// Running Entropic Statistic Estimates (bit strings only)...
24// Bitstring Collision Estimate: X-bar = 2.500075193522735, sigma-hat = 0.50000000179673953, p = 0.50857750043554861
25// Collision Test Estimate (bit string) = 0.975460 / 1 bit(s)
26// Bitstring Markov Estimate: P_0 = 0.49998108148574827, P_1 = 0.50001891851425173, P_0,0 = 0.49996292450723928, P_0,1 = 0.50003707549276077, P_1,0 = 0.49999924900989107, P_1,1 = 0.50000075099010899, p_max = 2.952323724507251e-39
27// Markov Test Estimate (bit string) = 0.999948 / 1 bit(s)
28// Bitstring Compression Estimate: X-bar = 5.2173562024019668, sigma-hat = 1.0155761472136569, p = 0.020720381304131674
29// Compression Test Estimate (bit string) = 0.932134 / 1 bit(s)
30//
31// Running Tuple Estimates...
32// Bitstring t-Tuple Estimate: t = 22, p-hat_max = 0.519800544732285640763, p_u = 0.5199410528217940434775
33// Bitstring LRS Estimate: u = 23, v = 49, p-hat = 0.50048298953775729, p_u = 0.50062360786706038
34// T-Tuple Test Estimate (bit string) = 0.943580 / 1 bit(s)
35// Literal t-Tuple Estimate: t = 2, p-hat_max = 0.004590882747638149776254, p_u = 0.004644655968621724387299
36// Literal LRS Estimate: u = 3, v = 5, p-hat = 0.0039149192648118801, p_u = 0.0039645929941324926
37// T-Tuple Test Estimate = 7.750213 / 8 bit(s)
38// LRS Test Estimate (bit string) = 0.998202 / 1 bit(s)
39// LRS Test Estimate = 7.978612 / 8 bit(s)
40//
41// Running Predictor Estimates...
42// Bitstring MultiMCW Prediction Estimate: N = 83886017, Pglobal' = 0.50016892471455032 (C = 41945383) Plocal can't affect result (r = 26)
43// Multi Most Common in Window (MultiMCW) Prediction Test Estimate (bit string) = 0.999513 / 1 bit(s)
44// Literal MultiMCW Prediction Estimate: N = 10485697, Pglobal' = 0.0039368902123073065 (C = 40762) Plocal = 0.0055718895656600631 (r = 4)
45// Multi Most Common in Window (MultiMCW) Prediction Test Estimate = 7.487618 / 8 bit(s)
46// Bitstring Lag Prediction Estimate: N = 83886079, Pglobal' = 0.50024399072940884 (C = 41951711) Plocal can't affect result (r = 28)
47// Lag Prediction Test Estimate (bit string) = 0.999296 / 1 bit(s)
48// Literal Lag Prediction Estimate: N = 10485759, Pglobal' = 0.003972280184949272 (C = 41131) Plocal = 0.0055718813178256762 (r = 4)
49// Lag Prediction Test Estimate = 7.487620 / 8 bit(s)
50// Bitstring MultiMMC Prediction Estimate: N = 83886078, Pglobal' = 0.50009155185115994 (C = 41938923) Plocal can't affect result (r = 24)
51// Multi Markov Model with Counting (MultiMMC) Prediction Test Estimate (bit string) = 0.999736 / 1 bit(s)
52// Literal MultiMMC Prediction Estimate: N = 10485758, Pglobal' = 0.0039454088113584813 (C = 40851) Plocal = 0.0055718814508428282 (r = 4)
53// Multi Markov Model with Counting (MultiMMC) Prediction Test Estimate = 7.487620 / 8 bit(s)
54// Bitstring LZ78Y Prediction Estimate: N = 83886063, Pglobal' = 0.5000796607255481 (C = 41937918) Plocal can't affect result (r = 25)
55// LZ78Y Prediction Test Estimate (bit string) = 0.999770 / 1 bit(s)
56// Literal LZ78Y Prediction Estimate: N = 10485743, Pglobal' = 0.0039455104269033141 (C = 40852) Plocal = 0.0055718834462567543 (r = 4)
57// LZ78Y Prediction Test Estimate = 7.487619 / 8 bit(s)
58//
59// H_original: 7.487618
60// H_bitstring: 0.932134
61// min(H_original, 8 X H_bitstring): 7.457074
62
63// 主要熵源
64/// 采集硬件时间戳并归一化到 1GHz 的原始熵源。
65///
66/// 读取 x86(`RDTSC`)/aarch64(`CNTVCT_EL0`)/RISC-V(`rdtime`) 等计数器,
67/// 用 Q48 定点乘子换算为纳秒级单调时钟。
68///
69/// # Feature Requirement
70///
71/// 需要启用 `"rand"` 特性。
72///
73/// # Examples
74///
75/// ```rust
76/// use lib_unknown::rand::probe;
77///
78/// let t1 = probe();
79/// let t2 = probe();
80/// assert!(t2 >= t1 || t2.wrapping_sub(t1) < u64::MAX);
81/// ```
82#[inline(always)]
83pub fn probe() -> u64 {
84 const SHIFT: u8 = 48;
85 const TARGET_FREQ: u128 = 1_000_000_000; // 目标 1GHz (1 tick = 1 ns)
86 static MULTIPLIER_Q48: AtomicU64 = AtomicU64::new(0);
87 #[inline(always)]
88 fn raw_probe() -> u64 {
89 #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
90 {
91 #[cfg(target_arch = "x86_64")]
92 unsafe {
93 core::arch::x86_64::_rdtsc()
94 }
95 #[cfg(target_arch = "x86")]
96 unsafe {
97 core::arch::x86::_rdtsc()
98 }
99 }
100
101 #[cfg(target_arch = "aarch64")]
102 {
103 let tsc: u64;
104 unsafe {
105 core::arch::asm!("mrs {}, cntvct_el0", out(reg) tsc, options(nomem, nostack))
106 };
107 tsc
108 }
109
110 #[cfg(target_arch = "arm")]
111 {
112 let mut lo: u32;
113 let mut hi: u32;
114 unsafe {
115 core::arch::asm!("mrrc p15, 1, {}, {}, c14", out(reg) lo, out(reg) hi, options(nomem, nostack))
116 };
117 ((hi as u64) << 32) | (lo as u64)
118 }
119
120 #[cfg(target_arch = "riscv64")]
121 {
122 let tsc: u64;
123 unsafe { core::arch::asm!("rdtime {}", out(reg) tsc, options(nomem, nostack)) };
124 tsc
125 }
126
127 #[cfg(target_arch = "riscv32")]
128 {
129 let mut hi: u32;
130 let mut lo: u32;
131 let mut hi2: u32;
132 unsafe {
133 core::arch::asm!(
134 "2:", "rdtimeh {hi}", "rdtime {lo}", "rdtimeh {hi2}", "bne {hi}, {hi2}, 2b",
135 hi = out(reg) hi, lo = out(reg) lo, hi2 = out(reg) hi2, options(nomem, nostack, preserves_flags)
136 );
137 }
138 ((hi as u64) << 32) | (lo as u64)
139 }
140
141 #[cfg(target_arch = "loongarch64")]
142 {
143 let tsc: u64;
144 unsafe { core::arch::asm!("rdtime.d {}, $r0", out(reg) tsc, options(nomem, nostack)) };
145 tsc
146 }
147
148 #[cfg(target_arch = "powerpc")]
149 {
150 let tsc: u64;
151 unsafe { core::arch::asm!("mftb {}", out(reg) tsc, options(nomem, nostack)) };
152 tsc
153 }
154
155 #[cfg(target_arch = "wasm32")]
156 {
157 #[cfg(target_os = "wasi")]
158 {
159 let mut timespec = core::mem::MaybeUninit::uninit();
160 unsafe {
161 let _ = wasi::clock_time_get(wasi::CLOCKID_MONOTONIC, 1, timespec.as_mut_ptr());
162 timespec.assume_init()
163 }
164 }
165 #[cfg(not(target_os = "wasi"))]
166 {
167 // Web 环境下,即使 no_std 也需要通过 ffi 引入 JS 运行时 API
168 #[wasm_bindgen::prelude::wasm_bindgen]
169 extern "C" {
170 #[wasm_bindgen::prelude::wasm_bindgen(js_namespace = performance)]
171 fn now() -> f64;
172 }
173 (now() * 1_000_000.0) as u64
174 }
175 }
176 }
177
178 fn autodetect_hardware_freq() -> u64 {
179 #[cfg(target_arch = "aarch64")]
180 {
181 let freq: u64;
182 unsafe {
183 core::arch::asm!("mrs {}, cntfrq_el0", out(reg) freq, options(nomem, nostack))
184 };
185 return freq;
186 }
187
188 #[cfg(target_arch = "loongarch64")]
189 {
190 let freq: u32;
191 // 龙芯 CPUCFG 指令索引 4,直接返回 CPU 定时器频率
192 unsafe {
193 core::arch::asm!("cpucfg {}, {}", out(reg) freq, in(reg) 4, options(nomem, nostack))
194 };
195 return freq as u64;
196 }
197
198 #[cfg(target_arch = "wasm32")]
199 {
200 return 1_000_000_000; // Web/WASI 已被我们在 raw_probe 中转为 1GHz
201 }
202
203 #[cfg(not(any(
204 target_arch = "aarch64",
205 target_arch = "loongarch64",
206 target_arch = "wasm32"
207 )))]
208 {
209 2_500_000_000
210 }
211 }
212
213 let raw = raw_probe();
214 let mut mult = MULTIPLIER_Q48.load(Ordering::Relaxed);
215
216 if mult == 0 {
217 let hz = autodetect_hardware_freq();
218 let final_mult = if hz == 0 {
219 1u64 << SHIFT
220 } else {
221 ((TARGET_FREQ << SHIFT) / hz as u128) as u64
222 };
223 mult = match MULTIPLIER_Q48.compare_exchange(
224 0,
225 final_mult,
226 Ordering::SeqCst,
227 Ordering::Relaxed,
228 ) {
229 Ok(_) => final_mult,
230 Err(existing) => existing,
231 };
232 }
233
234 ((raw as u128 * mult as u128) >> SHIFT) as u64
235}
236
237// 较低的熵源
238#[inline(never)]
239fn reg_sig() -> u64 {
240 let state: u64;
241 let gpr1: u64;
242 let gpr2: u64;
243 let gpr3: u64;
244 let code: u64;
245 let stack: u64;
246
247 // ==========================================
248 // 64位架构支持
249 // ==========================================
250 #[cfg(target_arch = "x86_64")]
251 unsafe {
252 core::arch::asm!(
253 "pushfq",
254 "pop {0}",
255 "lea {1}, [rip]",
256 "mov {2}, rsp",
257 out(reg) state, out(reg) code, out(reg) stack,
258 out("rcx") gpr1, out("r10") gpr2, out("r11") gpr3,
259 );
260 }
261
262 #[cfg(target_arch = "aarch64")]
263 unsafe {
264 core::arch::asm!(
265 "mrs {0}, nzcv",
266 "adr {1}, .",
267 "mov {2}, sp",
268 out(reg) state, out(reg) code, out(reg) stack,
269 out("x1") gpr1, out("x2") gpr2, out("x3") gpr3,
270 options(nomem, nostack)
271 );
272 }
273
274 #[cfg(target_arch = "riscv64")]
275 unsafe {
276 core::arch::asm!(
277 "rdinstret {0}",
278 "auipc {1}, 0",
279 "mv {2}, sp",
280 out(reg) state, out(reg) code, out(reg) stack,
281 out("t0") gpr1, out("t1") gpr2, out("t2") gpr3,
282 options(nomem, nostack)
283 );
284 }
285
286 #[cfg(target_arch = "x86")]
287 unsafe {
288 let (s32, c32, sp32, g1, g2, g3): (u32, u32, u32, u32, u32, u32);
289 core::arch::asm!(
290 "pushfd",
291 "pop {0}",
292 "call 2f",
293 "2:",
294 "pop {1}",
295 "mov {2}, esp",
296 out(reg) s32, out(reg) c32, out(reg) sp32,
297 out("ecx") g1, out("edx") g2, out("edi") g3,
298 );
299 state = s32 as u64;
300 code = c32 as u64;
301 stack = sp32 as u64;
302 gpr1 = g1 as u64;
303 gpr2 = g2 as u64;
304 gpr3 = g3 as u64;
305 }
306
307 #[cfg(target_arch = "arm")]
308 unsafe {
309 let (s32, c32, sp32, g1, g2, g3): (u32, u32, u32, u32, u32, u32);
310 core::arch::asm!(
311 "mrs {0}, CPSR", // 读取当前程序状态寄存器
312 "mov {1}, pc", // 32位ARM允许直接读取PC寄存器
313 "mov {2}, sp",
314 out(reg) s32, out(reg) c32, out(reg) sp32,
315 out("r1") g1, out("r2") g2, out("r3") g3,
316 options(nomem, nostack)
317 );
318 state = s32 as u64;
319 code = c32 as u64;
320 stack = sp32 as u64;
321 gpr1 = g1 as u64;
322 gpr2 = g2 as u64;
323 gpr3 = g3 as u64;
324 }
325
326 #[cfg(target_arch = "riscv32")]
327 unsafe {
328 let (s32, c32, sp32, g1, g2, g3): (u32, u32, u32, u32, u32, u32);
329 core::arch::asm!(
330 "rdinstret {0}", // RISC-V 32同样支持退休指令计数器
331 "auipc {1}, 0",
332 "mv {2}, sp",
333 out(reg) s32, out(reg) c32, out(reg) sp32,
334 out("t0") g1, out("t1") g2, out("t2") g3,
335 options(nomem, nostack)
336 );
337 state = s32 as u64;
338 code = c32 as u64;
339 stack = sp32 as u64;
340 gpr1 = g1 as u64;
341 gpr2 = g2 as u64;
342 gpr3 = g3 as u64;
343 }
344
345 #[cfg(not(any(
346 target_arch = "x86_64",
347 target_arch = "aarch64",
348 target_arch = "riscv64",
349 target_arch = "x86",
350 target_arch = "arm",
351 target_arch = "riscv32"
352 )))]
353 {
354 state = 0;
355 gpr1 = 0;
356 gpr2 = 0;
357 gpr3 = 0;
358 code = 0;
359 stack = 0;
360 }
361
362 let mut s = state.rotate_left(13);
363 s ^= gpr1.rotate_right(17);
364 s ^= gpr2.rotate_left(11);
365 s ^= gpr3.rotate_right(3);
366 s ^= code.rotate_left(17);
367 s ^= stack.rotate_right(5);
368 mix64(s)
369}
370
371// 10MB seed()产出测试
372// Loaded 10485760 samples of 256 distinct 8-bit-wide symbols
373// Number of Binary Symbols: 83886080
374//
375// Running non-IID tests...
376//
377// Running Most Common Value Estimate...
378// Bitstring MCV Estimate: mode = 41952873, p-hat = 0.50011721849441526, p_u = 0.50025783688546077
379// Most Common Value Estimate (bit string) = 0.999256 / 1 bit(s)
380// Literal MCV Estimate: mode = 41493, p-hat = 0.0039570808410644533, p_u = 0.004007020276832818
381// Most Common Value Estimate = 7.963254 / 8 bit(s)
382//
383// Running Entropic Statistic Estimates (bit strings only)...
384// Bitstring Collision Estimate: X-bar = 2.4998640044984755, sigma-hat = 0.4999999889553986, p = 0.51338519057718568
385// Collision Test Estimate (bit string) = 0.961886 / 1 bit(s)
386// Bitstring Markov Estimate: P_0 = 0.49988278150558474, P_1 = 0.50011721849441526, P_0,0 = 0.49999291730758672, P_0,1 = 0.50000708269241323, P_1,0 = 0.49977268541298708, P_1,1 = 0.50022731458701286, p_max = 3.1140954007368964e-39
387// Markov Test Estimate (bit string) = 0.999347 / 1 bit(s)
388// Bitstring Compression Estimate: X-bar = 5.2179921089068255, sigma-hat = 1.0151616484856194, p = 0.018763160395471878
389// Compression Test Estimate (bit string) = 0.955992 / 1 bit(s)
390//
391// Running Tuple Estimates...
392// Bitstring t-Tuple Estimate: t = 22, p-hat_max = 0.5192926595069563040102, p_u = 0.5194331731846545434296
393// Bitstring LRS Estimate: u = 23, v = 50, p-hat = 0.50285994550643263, p_u = 0.50300056160100674
394// T-Tuple Test Estimate (bit string) = 0.944990 / 1 bit(s)
395// Literal t-Tuple Estimate: t = 2, p-hat_max = 0.004528134246922033372418, p_u = 0.004581540398724434760821
396// Literal LRS Estimate: u = 3, v = 5, p-hat = 0.0039059863557037059, p_u = 0.0039556036033593406
397// T-Tuple Test Estimate = 7.769952 / 8 bit(s)
398// LRS Test Estimate (bit string) = 0.991368 / 1 bit(s)
399// LRS Test Estimate = 7.981886 / 8 bit(s)
400//
401// Running Predictor Estimates...
402// Bitstring MultiMCW Prediction Estimate: N = 83886017, Pglobal' = 0.50017991581909249 (C = 41946305) Plocal can't affect result (r = 27)
403// Multi Most Common in Window (MultiMCW) Prediction Test Estimate (bit string) = 0.999481 / 1 bit(s)
404// Literal MultiMCW Prediction Estimate: N = 10485697, Pglobal' = 0.0039609791527534998 (C = 41013) Plocal can't affect result (r = 3)
405// Multi Most Common in Window (MultiMCW) Prediction Test Estimate = 7.979927 / 8 bit(s)
406// Bitstring Lag Prediction Estimate: N = 83886079, Pglobal' = 0.50005931169698126 (C = 41936219) Plocal can't affect result (r = 29)
407// Lag Prediction Test Estimate (bit string) = 0.999829 / 1 bit(s)
408// Literal Lag Prediction Estimate: N = 10485759, Pglobal' = 0.0039561572050945742 (C = 40963) Plocal = 0.0055718813178256762 (r = 4)
409// Lag Prediction Test Estimate = 7.487620 / 8 bit(s)
410// Bitstring MultiMMC Prediction Estimate: N = 83886078, Pglobal' = 0.50020497949238396 (C = 41948438) Plocal can't affect result (r = 26)
411// Multi Markov Model with Counting (MultiMMC) Prediction Test Estimate (bit string) = 0.999409 / 1 bit(s)
412// Literal MultiMMC Prediction Estimate: N = 10485758, Pglobal' = 0.0039504952950308991 (C = 40904) Plocal = 0.0055718814508428282 (r = 4)
413// Multi Markov Model with Counting (MultiMMC) Prediction Test Estimate = 7.487620 / 8 bit(s)
414// Bitstring LZ78Y Prediction Estimate: N = 83886063, Pglobal' = 0.5002201250591588 (C = 41949701) Plocal can't affect result (r = 28)
415// LZ78Y Prediction Test Estimate (bit string) = 0.999365 / 1 bit(s)
416// Literal LZ78Y Prediction Estimate: N = 10485743, Pglobal' = 0.0039507888600843859 (C = 40907) Plocal = 0.0055718834462567543 (r = 4)
417// LZ78Y Prediction Test Estimate = 7.487619 / 8 bit(s)
418//
419// H_original: 7.487619
420// H_bitstring: 0.944990
421// min(H_original, 8 X H_bitstring): 7.487619
422
423// RNG = RNG_stdin, seed = unknown
424// test set = core, folding = standard(unknown format)
425//
426// rng=RNG_stdin, seed=unknown
427// length= 32 megabytes (2^25 bytes), time= 2.6 seconds
428// no anomalies in 163 test result(s)
429//
430// rng=RNG_stdin, seed=unknown
431// length= 64 megabytes (2^26 bytes), time= 5.5 seconds
432// no anomalies in 174 test result(s)
433//
434// rng=RNG_stdin, seed=unknown
435// length= 128 megabytes (2^27 bytes), time= 11.1 seconds
436// no anomalies in 187 test result(s)
437//
438// rng=RNG_stdin, seed=unknown
439// length= 256 megabytes (2^28 bytes), time= 21.8 seconds
440// no anomalies in 201 test result(s)
441//
442// rng=RNG_stdin, seed=unknown
443// length= 512 megabytes (2^29 bytes), time= 43.1 seconds
444// no anomalies in 216 test result(s)
445/// 混合多熵源生成 64 位种子。
446///
447/// 将 `probe` 时间戳、`reg_sig` 寄存器指纹与栈内存抖动混合搅拌,
448/// 适用于 `next` 的定期重播种。开销高于 `next`,勿用于热路径。
449///
450/// # Feature Requirement
451///
452/// 需要启用 `"rand"` 特性。
453///
454/// # Examples
455///
456/// ```rust
457/// use lib_unknown::rand::seed;
458///
459/// let s1 = seed();
460/// let s2 = seed();
461/// assert_ne!(s1, s2);
462/// ```
463pub fn seed() -> u64 {
464 use core::hint::black_box;
465
466 static COUNTER: AtomicUsize = AtomicUsize::new(0);
467 const STACK_MASK: usize = 767;
468 static CONFIG: (u8, u8, u8) = (32, 16, 8);
469
470 let c = COUNTER.fetch_add(1, Ordering::Relaxed) as u8;
471 let x = probe();
472 let y = reg_sig();
473 #[cfg(feature = "rand-safe-stack")]
474 let stack: core::mem::MaybeUninit<[u8; STACK_MASK]> = core::mem::MaybeUninit::uninit();
475 let sp = unsafe {
476 #[cfg(feature = "rand-safe-stack")]
477 {
478 black_box(stack.as_ptr() as *const u8)
479 }
480 #[cfg(not(feature = "rand-safe-stack"))]
481 {
482 black_box(&c as *const u8) // 大多数情况下rust程序使用的栈大于767字节
483 }
484 };
485 let rs = |idx| unsafe { black_box(core::ptr::read_volatile(sp.add(idx))).saturating_add(2) };
486 let t2s = |t: u64, mut s: u64, i: u8| {
487 if t.rotate_left(i as u32) as u8 & 1 == 0 {
488 let idx = ((t as u16) & (STACK_MASK as u16)) as usize;
489 s = s.rotate_left(rs(idx) as u32);
490 let idx2 = (((s >> 16) as u16) & (STACK_MASK as u16)) as usize;
491 s = s.wrapping_mul(rs(idx2) as u64);
492 } else {
493 let idx = (((t >> 16) as u16) & (STACK_MASK as u16)) as usize;
494 s = s.rotate_right(rs(idx) as u32);
495 let idx2 = ((s as u16) & (STACK_MASK as u16)) as usize;
496 s = s.wrapping_mul(rs(idx2) as u64);
497 }
498
499 s = match s.rotate_left(i as u32) as u8 {
500 0 => s ^ 0x9e3779b97f4a7c15,
501 255 => s.wrapping_mul(probe().saturating_add(2)),
502 127 => s.rotate_right(7),
503 3 => s.wrapping_mul(STACK_MASK as u64),
504 7 => s.wrapping_add(0x9e3779b97f4a7c15),
505 32 => s.wrapping_mul(0x94d049bb133111eb),
506 _ => s,
507 };
508 s
509 };
510
511 let mut s = (x ^ y).rotate_right(c as u32);
512
513 for i in 0..black_box(CONFIG.0) {
514 if (s >> 8) as u8 > 127 {
515 continue;
516 }
517 let t1 = probe().wrapping_mul((i as u64 ^ s).wrapping_mul(0x9e3779b97f4a7c15));
518 s ^= t1;
519 s = t2s(t1, s, i);
520
521 for j in 0..black_box(CONFIG.1) {
522 if (s >> 16) as u8 <= 127 {
523 continue;
524 }
525 let t2 = probe().wrapping_mul(((i ^ j) as u64 ^ s).wrapping_mul(0x9e3779b97f4a7c15));
526 s ^= t2;
527 s = t2s(t2, s, i ^ j);
528
529 for k in 0..black_box(CONFIG.2) {
530 if (s >> 32) as u8 > 127 {
531 continue;
532 }
533 let t3 =
534 probe().wrapping_mul(((i ^ j ^ k) as u64 ^ s).wrapping_mul(0x9e3779b97f4a7c15));
535 s ^= t3;
536 s = t2s(t3, s, i ^ j ^ k);
537 }
538 }
539 }
540 mix64(s)
541}
542
543/// 使用系统熵原地打乱可变序列。
544///
545/// # Feature Requirement
546///
547/// 需要启用 `"rand"` 特性。
548///
549/// # Examples
550///
551/// ```rust
552/// use lib_unknown::rand::shuffle;
553///
554/// let v = shuffle([0, 1, 2, 3, 4, 5, 6, 7]);
555/// assert_eq!(v.len(), 8);
556/// ```
557pub fn shuffle<T, U>(mut table: U) -> U
558where
559 U: AsMut<[T]>,
560{
561 shuffle_with(table, next())
562}
563
564// RNG = RNG_stdin, seed = unknown
565// test set = core, folding = standard(unknown format)
566//
567// rng=RNG_stdin, seed=unknown
568// length= 256 megabytes (2^28 bytes), time= 3.6 seconds
569// no anomalies in 201 test result(s)
570//
571// rng=RNG_stdin, seed=unknown
572// length= 512 megabytes (2^29 bytes), time= 7.4 seconds
573// Test Name Raw Processed Evaluation
574// [Low1/32]BCFN(2+1,13-5U) R= -7.0 p =1-1.8e-4 unusual
575// ...and 215 test result(s) without anomalies
576//
577// rng=RNG_stdin, seed=unknown
578// length= 1 gigabyte (2^30 bytes), time= 14.7 seconds
579// no anomalies in 231 test result(s)
580//
581// rng=RNG_stdin, seed=unknown
582// length= 2 gigabytes (2^31 bytes), time= 29.0 seconds
583// no anomalies in 246 test result(s)
584//
585// rng=RNG_stdin, seed=unknown
586// length= 4 gigabytes (2^32 bytes), time= 57.4 seconds
587// no anomalies in 261 test result(s)
588//
589// rng=RNG_stdin, seed=unknown
590// length= 8 gigabytes (2^33 bytes), time= 115 seconds
591// no anomalies in 274 test result(s)
592//
593// rng=RNG_stdin, seed=unknown
594// length= 16 gigabytes (2^34 bytes), time= 234 seconds
595// no anomalies in 287 test result(s)
596//
597// rng=RNG_stdin, seed=unknown
598// length= 32 gigabytes (2^35 bytes), time= 506 seconds
599// no anomalies in 299 test result(s)
600/// 生成下一个 64 位随机数(热路径)。
601///
602/// 快路径为 `mix64` 搅拌计数器,每 1024 次调用或首次调用时用 `seed` 重播种。
603/// 线程安全,可在 `no_std` 下使用。
604///
605/// # Feature Requirement
606///
607/// 需要启用 `"rand"` 特性。
608///
609/// # Examples
610///
611/// ```rust
612/// use lib_unknown::rand::next;
613///
614/// let a = next();
615/// let b = next();
616/// assert_ne!(a, b);
617/// ```
618pub fn next() -> u64 {
619 static SEED: AtomicU64 = AtomicU64::new(0);
620 static COUNTER: AtomicUsize = AtomicUsize::new(0);
621 let c = COUNTER.fetch_add(1, Ordering::Relaxed);
622 let mut s = SEED.fetch_add(0x9e3779b97f4a7c15, Ordering::Relaxed);
623 if s == 0 || s == 0x9e3779b97f4a7c15 || c.is_multiple_of(1024) {
624 s ^= seed();
625 SEED.store(s, Ordering::Relaxed);
626 s
627 } else {
628 mix64(s)
629 }
630}
631
632// // 热路径开销与seed相当
633// // RNG = RNG_stdin, seed = unknown
634// // test set = core, folding = standard(unknown format)
635// //
636// // rng=RNG_stdin, seed=unknown
637// // length= 32 megabytes (2^25 bytes), time= 2.1 seconds
638// // no anomalies in 163 test result(s)
639// //
640// // rng=RNG_stdin, seed=unknown
641// // length= 64 megabytes (2^26 bytes), time= 4.1 seconds
642// // no anomalies in 174 test result(s)
643// //
644// // rng=RNG_stdin, seed=unknown
645// // length= 128 megabytes (2^27 bytes), time= 7.6 seconds
646// // no anomalies in 187 test result(s)
647// //
648// // rng=RNG_stdin, seed=unknown
649// // length= 256 megabytes (2^28 bytes), time= 14.7 seconds
650// // no anomalies in 201 test result(s)
651// //
652// // rng=RNG_stdin, seed=unknown
653// // length= 512 megabytes (2^29 bytes), time= 28.5 seconds
654// // no anomalies in 216 test result(s)
655// //
656// // rng=RNG_stdin, seed=unknown
657// // length= 1 gigabyte (2^30 bytes), time= 55.7 seconds
658// // no anomalies in 231 test result(s)
659// //
660// // rng=RNG_stdin, seed=unknown
661// // length= 2 gigabytes (2^31 bytes), time= 110 seconds
662// // no anomalies in 246 test result(s)
663// pub fn next() -> u64 {
664// static IV: u64 = 0x00001000808c0001;
665//
666// // 全局密钥
667// static K1: AtomicU64 = AtomicU64::new(0);
668// static K2: AtomicU64 = AtomicU64::new(0);
669// static INIT_STATE: AtomicUsize = AtomicUsize::new(0);
670//
671// // 动态状态源
672// static SEED1: AtomicU64 = AtomicU64::new(0);
673// static SEED2: AtomicU64 = AtomicU64::new(0);
674// static COUNTER: AtomicUsize = AtomicUsize::new(0);
675//
676// #[inline]
677// const fn round(x: [u64; 5], c: u64) -> [u64; 5] {
678// let x0 = x[0] ^ x[4];
679// let x2 = x[2] ^ x[1] ^ c;
680// let x4 = x[4] ^ x[3];
681// let tx0 = x0 ^ (!x[1] & x2);
682// let tx1 = x[1] ^ (!x2 & x[3]);
683// let tx2 = x2 ^ (!x[3] & x4);
684// let tx3 = x[3] ^ (!x4 & x0);
685// let tx4 = x4 ^ (!x0 & x[1]);
686// let tx1 = tx1 ^ tx0;
687// let tx3 = tx3 ^ tx2;
688// let tx0 = tx0 ^ tx4;
689// let x0 = tx0 ^ tx0.rotate_right(9);
690// let x1 = tx1 ^ tx1.rotate_right(22);
691// let x2 = tx2 ^ tx2.rotate_right(5);
692// let x3 = tx3 ^ tx3.rotate_right(7);
693// let x4 = tx4 ^ tx4.rotate_right(34);
694// [
695// tx0 ^ x0.rotate_right(19),
696// tx1 ^ x1.rotate_right(39),
697// !(tx2 ^ x2.rotate_right(1)),
698// tx3 ^ x3.rotate_right(10),
699// tx4 ^ x4.rotate_right(7),
700// ]
701// }
702//
703// let c = COUNTER.fetch_add(1, Ordering::Relaxed) as u64;
704//
705// let mut s1 = SEED1.fetch_add(0x9e3779b97f4a7c15, Ordering::Relaxed);
706// let mut s2 = SEED2.fetch_add(0xbf58476d1ce4e5b9, Ordering::Relaxed);
707//
708// if c == 0 || c & 1023 == 0 {
709// let new_entropy = seed();
710// SEED1.fetch_xor(new_entropy, Ordering::Relaxed);
711// s1 ^= new_entropy;
712// } else {
713// s1 = mix64(s1);
714// s2 = mix64(s2);
715// }
716//
717// let mut k1 = K1.load(Ordering::Acquire);
718// let mut k2 = K2.load(Ordering::Acquire);
719//
720// if k1 == 0 || k2 == 0 {
721// match INIT_STATE.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed) {
722// Ok(_) => {
723// k1 = seed();
724// k2 = seed();
725//
726// if k1 == 0 { k1 = 1; }
727// if k2 == 0 { k2 = 1; }
728//
729// K1.store(k1, Ordering::Release);
730// K2.store(k2, Ordering::Release);
731// INIT_STATE.store(2, Ordering::Release);
732// }
733// Err(_) => {
734// let mut spins = 0;
735// while INIT_STATE.load(Ordering::Acquire) != 2 {
736// core::hint::spin_loop();
737// spins += 1;
738// if spins > 10_000 { break; }
739// }
740//
741// k1 = K1.load(Ordering::Acquire);
742// k2 = K2.load(Ordering::Acquire);
743// if k1 == 0 { k1 = c ^ 0xDEADBEEF; }
744// if k2 == 0 { k2 = s1 ^ 0xCAFEBABE; }
745// }
746// }
747// }
748//
749// let mut state = [IV, k1, k2, s1 ^ c, s2];
750//
751// let constants = [
752// 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b,
753// ];
754// for &cst in &constants {
755// state = round(state, cst);
756// }
757//
758// state[0]
759// }
760
761#[cfg(feature = "rand-expand")]
762/// 可随机生成的类型。
763///
764/// # Feature Requirement
765///
766/// 需要启用 `"rand-expand"` 特性。
767///
768/// # Examples
769///
770/// ```rust
771/// use lib_unknown::rand::{Random, random};
772///
773/// let v: u64 = random();
774/// let _ = v;
775/// ```
776pub trait Random {
777 fn random() -> Self;
778}
779#[cfg(feature = "rand-expand")]
780/// 生成指定类型的随机值。
781///
782/// # Feature Requirement
783///
784/// 需要启用 `"rand-expand"` 特性.
785///
786/// # Examples
787///
788/// ```rust
789/// use lib_unknown::rand::random;
790///
791/// let v: u32 = random();
792/// let _ = v;
793/// ```
794#[inline(always)]
795pub fn random<T: Random>() -> T {
796 T::random()
797}
798macro_rules! impl_random_int {
799 ($($t:ty),*) => {
800 $(
801 #[cfg(feature = "rand-expand")]
802 impl Random for $t {
803 #[inline(always)]
804 fn random() -> Self {
805 next() as Self
806 }
807 }
808 )*
809 };
810}
811impl_random_int!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
812#[cfg(feature = "rand-expand")]
813impl Random for bool {
814 #[inline(always)]
815 fn random() -> Self {
816 (next() & 1) == 1
817 }
818}
819#[cfg(feature = "rand-expand")]
820impl Random for f64 {
821 #[inline(always)]
822 fn random() -> Self {
823 let fraction = next() >> 11;
824 fraction as f64 / (1u64 << 53) as f64
825 }
826}
827#[cfg(feature = "rand-expand")]
828impl Random for f32 {
829 #[inline(always)]
830 fn random() -> Self {
831 let fraction = (next() as u32) >> 8;
832 fraction as f32 / (1u32 << 24) as f32
833 }
834}
835
836#[cfg(feature = "rand-expand")]
837/// 用随机字节填充切片。
838///
839/// # Feature Requirement
840///
841/// 需要启用 `"rand-expand"` 特性。
842///
843/// # Examples
844///
845/// ```rust
846/// use lib_unknown::rand::fill_bytes;
847///
848/// let mut buf = [0u8; 16];
849/// fill_bytes(&mut buf);
850/// assert_eq!(buf.len(), 16);
851/// ```
852pub fn fill_bytes(dest: &mut [u8]) {
853 let (chunks, remainder) = dest.as_chunks_mut::<8>();
854 for chunk in chunks {
855 *chunk = next().to_le_bytes();
856 }
857 if !remainder.is_empty() {
858 let bytes = next().to_le_bytes();
859 remainder.copy_from_slice(&bytes[..remainder.len()]);
860 }
861}
862
863#[cfg(feature = "rand-expand")]
864/// 可从区间采样的类型。
865///
866/// # Feature Requirement
867///
868/// 需要启用 `"rand-expand"` 特性。
869pub trait SampleRange {
870 type Output;
871 fn sample(self) -> Self::Output;
872}
873
874#[cfg(feature = "rand-expand")]
875/// 从区间中均匀采样一个随机值,整数用无偏取模实现。
876///
877/// # Feature Requirement
878///
879/// 需要启用 `"rand-expand"` 特性。
880///
881/// # Examples
882///
883/// ```rust
884/// use lib_unknown::rand::random_range;
885///
886/// let v = random_range(0..100u32);
887/// assert!(v < 100);
888/// ```
889///
890/// # Panics
891///
892/// - 当区间为空(`start >= end`,闭区间为 `start > end`)时发生 panic。
893#[inline(always)]
894pub fn random_range<R: SampleRange>(range: R) -> R::Output {
895 range.sample()
896}
897macro_rules! impl_sample_range_int {
898 ($($t:ty, $u:ty),*) => {
899 $(
900 // 支持半开区间 Range (..)
901 #[cfg(feature = "rand-expand")]
902 impl SampleRange for core::ops::Range<$t> {
903 type Output = $t;
904
905 #[inline]
906 fn sample(self) -> $t {
907 assert!(self.start < self.end, "Invalid range: start must be less than end");
908
909 let start = self.start as $u;
910 let end = self.end as $u;
911 let span = end.wrapping_sub(start);
912
913 let threshold = span.wrapping_neg() % span;
914
915 loop {
916 let r = next() as $u;
917 if r >= threshold {
918 let offset = r % span;
919 return start.wrapping_add(offset) as $t;
920 }
921 }
922 }
923 }
924
925 // 支持闭区间 RangeInclusive (..=)
926 #[cfg(feature = "rand-expand")]
927 impl SampleRange for core::ops::RangeInclusive<$t> {
928 type Output = $t;
929
930 #[inline]
931 fn sample(self) -> $t {
932 let (start_val, end_val) = (*self.start(), *self.end());
933 assert!(start_val <= end_val, "Invalid range: start must be less than or equal to end");
934
935 if start_val == <$t>::MIN && end_val == <$t>::MAX {
936 return next() as $t;
937 }
938
939 let start = start_val as $u;
940 let end = end_val as $u;
941 let span = end.wrapping_sub(start).wrapping_add(1);
942
943 let threshold = span.wrapping_neg() % span;
944
945 loop {
946 let r = next() as $u;
947 if r >= threshold {
948 let offset = r % span;
949 return start.wrapping_add(offset) as $t;
950 }
951 }
952 }
953 }
954 )*
955 };
956}
957
958impl_sample_range_int!(
959 u8, u8, u16, u16, u32, u32, u64, u64, usize, usize, i8, u8, i16, u16, i32, u32, i64, u64,
960 isize, usize
961);
962macro_rules! impl_sample_range_float {
963 ($($t:ty),*) => {
964 $(
965 #[cfg(feature = "rand-expand")]
966 impl SampleRange for core::ops::Range<$t> {
967 type Output = $t;
968 #[inline]
969 fn sample(self) -> $t {
970 assert!(self.start < self.end, "Invalid range: start must be less than end");
971 self.start + random::<$t>() * (self.end - self.start)
972 }
973 }
974
975 #[cfg(feature = "rand-expand")]
976 impl SampleRange for core::ops::RangeInclusive<$t> {
977 type Output = $t;
978 #[inline]
979 fn sample(self) -> $t {
980 let (start, end) = (*self.start(), *self.end());
981 assert!(start <= end, "Invalid range: start must be less than or equal to end");
982 if start == end {
983 return start;
984 }
985 start + random::<$t>() * (end - start)
986 }
987 }
988 )*
989 };
990}
991
992impl_sample_range_float!(f32, f64);
993
994#[cfg(test)]
995#[allow(clippy::unwrap_used, clippy::expect_used)]
996mod tests {
997 use super::*;
998
999 #[cfg(feature = "std")]
1000 #[test]
1001 fn test() {
1002 for _ in 0..1024 {
1003 let a = std::time::Instant::now();
1004 let s = next();
1005 println!("{:<30}{:?}", s, a.elapsed());
1006 }
1007 }
1008}