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