-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRandX.hpp
More file actions
3280 lines (2947 loc) · 113 KB
/
Copy pathRandX.hpp
File metadata and controls
3280 lines (2947 loc) · 113 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//----------------------------------------------------------------------------------------
//
// RandX.hpp — 基于 Xoshiro 的伪随机数生成器封装库(C++23)
//
// 原始算法:David Blackman & Sebastiano Vigna (http://prng.di.unimi.it/)
// 原始 C++ 封装:Ryo Suzuki (https://github.com/Reputeless/Xoshiro-cpp)
//
//========================================================================================
//
// 快速上手
//
// #include "RandX.hpp"
//
// // 最简用法:直接调用便捷函数(内部使用线程局部 Xoshiro256StarStar)
// int dice = RandX::RandInt(1, 6); // [1, 6] 闭区间整数
// double coin = RandX::RandReal(); // [0.0, 1.0) 浮点数
// bool flag = RandX::RandBool(0.3); // 30% 概率为 true
//
// std::vector<int> v = {10, 20, 30, 40};
// auto& elem = RandX::RandElement(v); // 随机取一个元素
//
// 扩展 API
//
// auto sample = RandX::RandSample(v, 2); // 无放回抽样 2 个
// auto perm = RandX::RandPermutation(10); // [0,10) 随机排列
// auto token = RandX::RandString(16); // 16 位随机字符串
// auto uuid = RandX::RandUUID(); // UUID v4
// auto byte = RandX::RandBits<8>(); // [0, 256) 随机整数
// auto exp = RandX::RandExp(2.0); // 指数分布 λ=2
// auto poi = RandX::RandPoisson(5.0); // 泊松分布 μ=5
//
// 手动管理引擎
//
// // 用真随机种子创建引擎
// RandX::Xoshiro256StarStar rng{ RandX::RandomSeed() };
//
// // 指定引擎的便捷函数重载
// int val = RandX::RandInt(rng, 0, 99);
//
// // 配合标准库 distribution 使用(满足 UniformRandomBitGenerator)
// std::normal_distribution<double> norm(0.0, 1.0);
// double sample = norm(rng);
//
// 多流并行
//
// auto s0 = RandX::MakeStreamEngine<RandX::Xoshiro256StarStar>(0);
// auto s1 = RandX::MakeStreamEngine<RandX::Xoshiro256StarStar>(1);
// // 各流间隔 2^128 步,互不重叠
//
// 编译期随机(constexpr)
//
// constexpr int v = RandX::RandIntCE(0, 100);
// constexpr auto shuffled = RandX::ShuffledArray<int, 5>({1,2,3,4,5});
//
// 序列化 / 反序列化(保存和恢复状态)
//
// auto state = rng.serialize();
// rng.deserialize(state);
//
// 跳跃(并行计算中生成不重叠子序列)
//
// rng.jump(); // 等价于前进 2^128 步(xoshiro256 系列)
// rng.longJump(); // 等价于前进 2^192 步
//
// 跳过指定次数
//
// rng.discard(1000); // 跳过 1000 个输出
//
// 引擎选择指南
//
// 引擎 输出 周期 状态 适用场景
// ─────────────────────────────────────────────────────────────
// Xoshiro256StarStar 64-bit 2^256-1 32B 通用首选,统计质量最优
// Xoroshiro128StarStar 64-bit 2^128-1 16B 内存受限,统计更优
// Xoshiro128StarStar 32-bit 2^128-1 16B 32 位平台,统计更优
// Xoroshiro64StarStar 32-bit 2^64-1 8B 极端内存受限
// SplitMix64 64-bit 2^64 8B 种子扩展 / 哈希,非通用 PRNG
// SFC64 64-bit >= 2^64 32B 速度极快,通过 PractRand
// RomuDuoJr 64-bit >= 2^51 16B 极简极快,非关键模拟
// ChaCha20 64-bit 无周期 48B+ 密码学安全 CSPRNG(RFC 8439)
//
// ⚠️ 安全声明
// 本库的 xoshiro/xoroshiro/SFC64/RomuDuoJr 引擎均非 CSPRNG。
// 状态可从输出逆推,不可用于密码/密钥/会话 token 等安全场景。
// 此类场景请使用 ChaCha20 引擎或 SecureRandomBytes()。
//
//----------------------------------------------------------------------------------------
# pragma once
# include <cmath>
# include <cstdint>
# include <array>
# include <limits>
# include <concepts>
# include <random>
# include <algorithm>
# include <bit>
# include <cassert>
# include <type_traits>
# include <ranges>
# include <string>
# include <string_view>
# include <unordered_set>
# include <vector>
# include <stdexcept>
# include <chrono> // std::chrono(RandomSeed 时间戳兜底用)
# include <atomic> // std::atomic(RandomSeed 兜底计数)
# include <functional>// std::hash(RandomSeed 线程 Hash)
# include <thread> // std::this_thread(RandomSeed 线程 ID)
# include <ios> // std::ios_base::failbit(流状态标志完整定义)
# include <istream> // std::basic_istream(operator>> 所需完整类型)
# include <ostream> // std::basic_ostream(operator<< 所需完整类型)
# if defined(_MSC_VER) && (defined(__x86_64__) || defined(_M_X64))
# include <immintrin.h>
# include <intrin.h>
# endif
// ── A3 跨平台 OS 熵源头文件(条件包含) ──
# if defined(_WIN32) && __has_include(<bcrypt.h>)
// bcrypt.h 依赖 <windows.h> 提供的 ULONG/NTSTATUS 等类型(MSVC 和 MinGW 均需)
// NOMINMAX 阻止 <windows.h> 定义 min/max 宏(与引擎的 min()/max() 方法冲突)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
# include <bcrypt.h>
# pragma comment(lib, "bcrypt.lib") // 仅 MSVC 生效
// MinGW 不支持 #pragma comment(lib),须手动添加 -lbcrypt 链接选项
# if(defined(__MINGW32__) || defined(__MINGW64__)) && !defined(RANDX_SUPPRESS_LINK_HINT)
# pragma message("RandX: MinGW 需手动链接 bcrypt(编译命令添加 -lbcrypt)")
# endif
# elif defined(__linux__) && __has_include(<sys/random.h>)
# include <sys/random.h>
# include <cerrno>
# elif defined(__APPLE__)
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# if __has_include(<Security/SecRandom.h>)
# include <Security/SecRandom.h>
# endif
# elif __has_include(<Security/Security.h>)
# include <Security/Security.h>
# endif
# endif
# include <cstring> // std::memcpy(std::random_device 回退路径用)
namespace RandX
{
// 生成器的默认种子值
inline constexpr std::uint64_t DefaultSeed = 1234567890ULL;
// 将给定的 uint32 值 `i` 转换为 [0.0f, 1.0f) 范围内的 32 位浮点数
template <std::same_as<std::uint32_t> Uint32>
[[nodiscard]]
inline constexpr float FloatFromBits(Uint32 i) noexcept;
// 将给定的 uint64 值 `i` 转换为 [0.0, 1.0) 范围内的 64 位浮点数
template <std::same_as<std::uint64_t> Uint64>
[[nodiscard]]
inline constexpr double DoubleFromBits(Uint64 i) noexcept;
// ── 引擎基础设施(提前定义,供 EngineBase CRTP 基类使用) ──
namespace detail
{
[[nodiscard]]
inline constexpr std::uint64_t RotL(const std::uint64_t x, const int s) noexcept
{
return std::rotl(x, s);
}
[[nodiscard]]
inline constexpr std::uint32_t RotL(const std::uint32_t x, const int s) noexcept
{
return std::rotl(x, s);
}
// 检测状态数组是否全零(全零是 xoshiro/xoroshiro 的吸收态)
template <std::size_t N>
[[nodiscard]]
inline constexpr bool IsAllZero(const std::array<std::uint64_t, N>& state) noexcept
{
for (const auto& s : state) { if (s != 0) return false; }
return true;
}
template <std::size_t N>
[[nodiscard]]
inline constexpr bool IsAllZero(const std::array<std::uint32_t, N>& state) noexcept
{
for (const auto& s : state) { if (s != 0) return false; }
return true;
}
template <typename State>
[[nodiscard]]
inline constexpr bool IsValidState(const State& state) noexcept
{
return !IsAllZero(state);
}
}
/// @defgroup engines 引擎
/// @brief 8 个伪随机数生成引擎(7 非 CSPRNG + 1 ChaCha20 CSPRNG)
/// @{
/// @brief SplitMix64 伪随机数生成器,64 位输出,周期 2^64。
///
/// @details 状态 8 字节(1×uint64)。主要用于种子扩展与哈希,
/// 可将单个 64 位种子展开为高质量的状态序列。
/// 原始实现:http://prng.di.unimi.it/splitmix64.c
///
/// @note 非通用 PRNG,无 jump 方法。
/// @sa Xoshiro256StarStar, Xoroshiro128StarStar
class SplitMix64
{
public:
using state_type = std::uint64_t; ///< 状态类型(1×uint64)
using result_type = std::uint64_t; ///< 输出类型
/// @brief 以指定状态构造引擎
/// @param state 64 位初始状态值
[[nodiscard]]
explicit constexpr SplitMix64(state_type state = DefaultSeed) noexcept;
/// @brief 从 std::seed_seq 播种
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, SplitMix64>)
[[nodiscard]]
explicit constexpr SplitMix64(SeedSeq& seq);
/// @brief 生成下一个 64 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
/// @brief 跳过 n 个输出
/// @param n 跳过次数
constexpr void discard(unsigned long long n) noexcept;
/// @brief 生成 N 个高质量的 64 位种子序列
/// @tparam N 生成的种子数量
/// @return 包含 N 个 uint64 的数组,可用于播种其他引擎
template <std::size_t N>
[[nodiscard]]
constexpr std::array<std::uint64_t, N> generateSeedSequence() noexcept;
/// @brief 输出范围下界
/// @return 0
[[nodiscard]]
static constexpr result_type min() noexcept;
/// @brief 输出范围上界
/// @return 2^64 - 1
[[nodiscard]]
static constexpr result_type max() noexcept;
/// @brief 序列化引擎状态
/// @return 当前状态值
/// @sa deserialize()
[[nodiscard]]
constexpr state_type serialize() const noexcept;
/// @brief 从状态恢复引擎
/// @param state serialize() 返回的状态
/// @sa serialize()
constexpr void deserialize(state_type state) noexcept;
friend auto operator <=>(const SplitMix64&, const SplitMix64&) = default;
private:
state_type m_state;
};
// ── EngineBase CRTP 基类 ──
// 为数组状态引擎提供公共接口:min/max/discard/serialize/比较/构造/jumpPoly
// SplitMix64(标量状态)和 ChaCha20(CSPRNG)不继承此基类
namespace detail
{
template <class Derived, class ResultType, std::size_t N>
struct EngineBase
{
using result_type = ResultType;
using state_type = std::array<ResultType, N>;
// --- 公共接口 ---
[[nodiscard]]
static constexpr result_type min() noexcept
{
return std::numeric_limits<result_type>::lowest();
}
[[nodiscard]]
static constexpr result_type max() noexcept
{
return std::numeric_limits<result_type>::max();
}
constexpr void discard(unsigned long long z) noexcept
{
for (unsigned long long i = 0; i < z; ++i)
static_cast<Derived*>(this)->operator()();
}
[[nodiscard]]
constexpr state_type serialize() const noexcept
{
return s_;
}
constexpr void deserialize(const state_type& s) noexcept
{
s_ = s;
if (IsAllZero(s_))
{
s_[0] = static_cast<ResultType>(1);
}
assert(!IsAllZero(s_) && "absorbing all-zero state");
}
// C++23: defaulted 三路比较(保留 ==, !=, <, >, <=, >= 全套)
friend auto operator<=>(const EngineBase&, const EngineBase&) = default;
protected:
static constexpr int Bits = static_cast<int>(sizeof(ResultType) * 8);
EngineBase() = default;
// State 构造(用户直接传入,包含 Release/Debug 全零状态静默修正)
explicit constexpr EngineBase(const state_type& state) noexcept
: s_(state)
{
if (IsAllZero(s_))
{
s_[0] = static_cast<ResultType>(1);
}
assert(!IsAllZero(s_) && "absorbing all-zero state");
}
// SeedSeq 构造(零状态修正,Release 安全)
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, state_type>
&& !std::same_as<std::remove_cvref_t<SeedSeq>, Derived>)
explicit constexpr EngineBase(SeedSeq& seq)
{
if constexpr (sizeof(result_type) == 8)
{
std::array<std::uint32_t, N * 2> raw;
seq.generate(raw.begin(), raw.end());
for (std::size_t i = 0; i < N; ++i)
s_[i] = (static_cast<result_type>(raw[2 * i]) << 32) | raw[2 * i + 1];
}
else
{
std::array<std::uint32_t, N> raw;
seq.generate(raw.begin(), raw.end());
for (std::size_t i = 0; i < N; ++i)
s_[i] = static_cast<result_type>(raw[i]);
}
if (IsAllZero(s_)) s_[0] = 1;
}
// 单值播种(SplitMix64 扩展,等价于 generateSeedSequence<N>)
explicit constexpr EngineBase(std::uint64_t seed) noexcept
{
SplitMix64 sm{ seed };
for (std::size_t i = 0; i < N; ++i)
s_[i] = static_cast<result_type>(sm());
if (IsAllZero(s_)) s_[0] = 1;
}
// jump 多项式通用实现(constexpr,供 MakeStreamEngine 编译期调用)
template <std::size_t K>
constexpr void jumpPoly(const ResultType (&poly)[K]) noexcept
{
std::array<ResultType, N> acc{};
for (std::size_t i = 0; i < K; ++i)
for (int b = 0; b < Bits; ++b)
{
if (poly[i] & (ResultType{ 1 } << b))
for (std::size_t j = 0; j < N; ++j)
acc[j] ^= s_[j];
static_cast<Derived*>(this)->operator()();
}
s_ = acc;
}
state_type s_{};
};
}
/// @brief Xoshiro256** 伪随机数生成器,64 位输出,周期 2^256-1。
///
/// @details 通用首选引擎,统计质量最优。状态 32 字节(4×uint64)。
/// 满足 `std::uniform_random_bit_generator` 概念。
/// 原始实现:http://prng.di.unimi.it/xoshiro256starstar.c(版本 1.0)
///
/// @note 非 CSPRNG,不可用于密码学场景。安全场景请使用 ChaCha20。
/// @sa Xoroshiro128StarStar, SFC64, ChaCha20
class Xoshiro256StarStar
: public detail::EngineBase<Xoshiro256StarStar, std::uint64_t, 4>
{
using Base = detail::EngineBase<Xoshiro256StarStar, std::uint64_t, 4>;
public:
using typename Base::result_type; ///< 输出类型
using typename Base::state_type; ///< 状态类型(4×uint64)
/// @brief 默认构造(使用 DefaultSeed)
constexpr Xoshiro256StarStar() noexcept : Base(DefaultSeed) {}
/// @brief 以指定种子构造引擎
/// @param seed 64 位种子值
[[nodiscard]]
explicit constexpr Xoshiro256StarStar(std::uint64_t seed) noexcept
: Base(seed) {}
/// @brief 从 std::seed_seq 播种
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, Xoshiro256StarStar>)
[[nodiscard]]
explicit constexpr Xoshiro256StarStar(SeedSeq& seq)
: Base(seq) {}
/// @brief 从状态数组直接构造
/// @param state serialize() 返回的状态
[[nodiscard]]
explicit constexpr Xoshiro256StarStar(state_type state) noexcept
: Base(state) {}
/// @brief 生成下一个 64 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
/// @brief 前进 2^128 步,用于创建并行子序列
/// @note 等价于调用 2^128 次 operator()
/// @sa longJump(), MakeStreamEngine()
constexpr void jump() noexcept;
/// @brief 前进 2^192 步,用于创建更稀疏的并行子序列
/// @note 等价于调用 2^192 次 operator()
/// @sa jump(), MakeStreamEngine()
constexpr void longJump() noexcept;
};
/// @brief Xoroshiro128** 伪随机数生成器,64 位输出,周期 2^128-1。
///
/// @details 状态 16 字节(2×uint64),内存占用更小,统计质量更优,
/// 适合内存受限场景。满足 `std::uniform_random_bit_generator` 概念。
/// 原始实现:http://prng.di.unimi.it/xoroshiro128starstar.c(版本 1.0)
///
/// @note 非 CSPRNG,不可用于密码学场景。安全场景请使用 ChaCha20。
/// @sa Xoshiro256StarStar, Xoroshiro64StarStar, ChaCha20
class Xoroshiro128StarStar
: public detail::EngineBase<Xoroshiro128StarStar, std::uint64_t, 2>
{
using Base = detail::EngineBase<Xoroshiro128StarStar, std::uint64_t, 2>;
public:
using typename Base::result_type; ///< 输出类型
using typename Base::state_type; ///< 状态类型(2×uint64)
/// @brief 默认构造(使用 DefaultSeed)
constexpr Xoroshiro128StarStar() noexcept : Base(DefaultSeed) {}
/// @brief 以指定种子构造引擎
/// @param seed 64 位种子值
[[nodiscard]]
explicit constexpr Xoroshiro128StarStar(std::uint64_t seed) noexcept
: Base(seed) {}
/// @brief 从 std::seed_seq 播种
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, Xoroshiro128StarStar>)
[[nodiscard]]
explicit constexpr Xoroshiro128StarStar(SeedSeq& seq)
: Base(seq) {}
/// @brief 从状态数组直接构造
/// @param state serialize() 返回的状态
[[nodiscard]]
explicit constexpr Xoroshiro128StarStar(state_type state) noexcept
: Base(state) {}
/// @brief 生成下一个 64 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
/// @brief 前进 2^64 步,用于创建并行子序列
/// @note 等价于调用 2^64 次 operator()
/// @sa longJump(), MakeStreamEngine()
constexpr void jump() noexcept;
/// @brief 前进 2^96 步,用于创建更稀疏的并行子序列
/// @note 等价于调用 2^96 次 operator()
/// @sa jump(), MakeStreamEngine()
constexpr void longJump() noexcept;
};
/// @brief Xoshiro128** 伪随机数生成器,32 位输出,周期 2^128-1。
///
/// @details 状态 16 字节(4×uint32),32 位平台优先选择。
/// 满足 `std::uniform_random_bit_generator` 概念。
/// 原始实现:http://prng.di.unimi.it/xoshiro128starstar.c(版本 1.1)
///
/// @note 非 CSPRNG,不可用于密码学场景。安全场景请使用 ChaCha20。
/// @sa Xoshiro256StarStar, Xoroshiro64StarStar, ChaCha20
class Xoshiro128StarStar
: public detail::EngineBase<Xoshiro128StarStar, std::uint32_t, 4>
{
using Base = detail::EngineBase<Xoshiro128StarStar, std::uint32_t, 4>;
public:
using typename Base::result_type; ///< 输出类型
using typename Base::state_type; ///< 状态类型(4×uint32)
/// @brief 默认构造(使用 DefaultSeed)
constexpr Xoshiro128StarStar() noexcept : Base(DefaultSeed) {}
/// @brief 以指定种子构造引擎
/// @param seed 64 位种子值
[[nodiscard]]
explicit constexpr Xoshiro128StarStar(std::uint64_t seed) noexcept
: Base(seed) {}
/// @brief 从 std::seed_seq 播种
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, Xoshiro128StarStar>)
[[nodiscard]]
explicit constexpr Xoshiro128StarStar(SeedSeq& seq)
: Base(seq) {}
/// @brief 从状态数组直接构造
/// @param state serialize() 返回的状态
[[nodiscard]]
explicit constexpr Xoshiro128StarStar(state_type state) noexcept
: Base(state) {}
/// @brief 生成下一个 32 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
/// @brief 前进 2^64 步,用于创建并行子序列
/// @note 等价于调用 2^64 次 operator()
/// @sa longJump(), MakeStreamEngine()
constexpr void jump() noexcept;
/// @brief 前进 2^96 步,用于创建更稀疏的并行子序列
/// @note 等价于调用 2^96 次 operator()
/// @sa jump(), MakeStreamEngine()
constexpr void longJump() noexcept;
};
/// @brief Xoroshiro64** 伪随机数生成器,32 位输出,周期 2^64-1。
///
/// @details 状态 8 字节(2×uint32),适合极端内存受限场景。
/// 满足 `std::uniform_random_bit_generator` 概念。
/// 原始实现:http://prng.di.unimi.it/xoroshiro64starstar.c
///
/// @note 无 jump 方法。非 CSPRNG,不可用于密码学场景。安全场景请使用 ChaCha20。
/// @sa Xoshiro128StarStar, Xoroshiro128StarStar, ChaCha20
class Xoroshiro64StarStar
: public detail::EngineBase<Xoroshiro64StarStar, std::uint32_t, 2>
{
using Base = detail::EngineBase<Xoroshiro64StarStar, std::uint32_t, 2>;
public:
using typename Base::result_type; ///< 输出类型
using typename Base::state_type; ///< 状态类型(2×uint32)
/// @brief 默认构造(使用 DefaultSeed)
constexpr Xoroshiro64StarStar() noexcept : Base(DefaultSeed) {}
/// @brief 以指定种子构造引擎
/// @param seed 64 位种子值
[[nodiscard]]
explicit constexpr Xoroshiro64StarStar(std::uint64_t seed) noexcept
: Base(seed) {}
/// @brief 从 std::seed_seq 播种
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, Xoroshiro64StarStar>)
[[nodiscard]]
explicit constexpr Xoroshiro64StarStar(SeedSeq& seq)
: Base(seq) {}
/// @brief 从状态数组直接构造
/// @param state serialize() 返回的状态
[[nodiscard]]
explicit constexpr Xoroshiro64StarStar(state_type state) noexcept
: Base(state) {}
/// @brief 生成下一个 32 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
};
/// @brief SFC64(Small Fast Counter)伪随机数生成器,64 位输出,周期 >= 2^64。
///
/// @details 状态 32 字节(4×uint64)。由 Chris Doty-Humphrey(PractRand)设计,
/// 速度极快,通过 PractRand 全部统计测试。满足 `std::uniform_random_bit_generator` 概念。
///
/// @note 周期由 counter 保证 >= 2^64。无 jump 方法。
/// 非 CSPRNG,不可用于密码学场景。安全场景请使用 ChaCha20。
/// @sa Xoshiro256StarStar, RomuDuoJr, ChaCha20
class SFC64
: public detail::EngineBase<SFC64, std::uint64_t, 4>
{
using Base = detail::EngineBase<SFC64, std::uint64_t, 4>;
public:
using typename Base::result_type; ///< 输出类型
using typename Base::state_type; ///< 状态类型(4×uint64)
/// @brief 默认构造(使用 DefaultSeed)
constexpr SFC64() noexcept : SFC64(DefaultSeed) {}
/// @brief 以指定种子构造引擎(SplitMix64 填充 3 状态字 + counter=1 + 12 轮预热)
/// @param seed 64 位种子值
[[nodiscard]]
explicit constexpr SFC64(std::uint64_t seed) noexcept;
/// @brief 从 std::seed_seq 播种(填充 3 状态字 + counter=1 + 12 轮预热)
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, SFC64>)
[[nodiscard]]
explicit constexpr SFC64(SeedSeq& seq);
/// @brief 从状态数组直接构造
/// @param state serialize() 返回的状态
[[nodiscard]]
explicit constexpr SFC64(state_type state) noexcept
: Base(state) {}
/// @brief 生成下一个 64 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
};
/// @brief RomuDuoJr 伪随机数生成器,64 位输出,周期估计 >= 2^51。
///
/// @details 状态 16 字节(2×uint64)。由 Mark Overton 设计,
/// 极简极快,适合非关键模拟场景。满足 `std::uniform_random_bit_generator` 概念。
///
/// @note 周期无严格证明(估计 >= 2^51)。无 jump 方法。
/// 非 CSPRNG,不可用于密码学场景。安全场景请使用 ChaCha20。
/// @sa SFC64, Xoshiro256StarStar, ChaCha20
class RomuDuoJr
: public detail::EngineBase<RomuDuoJr, std::uint64_t, 2>
{
using Base = detail::EngineBase<RomuDuoJr, std::uint64_t, 2>;
public:
using typename Base::result_type; ///< 输出类型
using typename Base::state_type; ///< 状态类型(2×uint64)
/// @brief 默认构造(使用 DefaultSeed)
constexpr RomuDuoJr() noexcept : Base(DefaultSeed) {}
/// @brief 以指定种子构造引擎
/// @param seed 64 位种子值
[[nodiscard]]
explicit constexpr RomuDuoJr(std::uint64_t seed) noexcept
: Base(seed) {}
/// @brief 从 std::seed_seq 播种
/// @param seq 种子序列对象
template <class SeedSeq>
requires (!std::same_as<std::remove_cvref_t<SeedSeq>, RomuDuoJr>)
[[nodiscard]]
explicit constexpr RomuDuoJr(SeedSeq& seq)
: Base(seq) {}
/// @brief 从状态数组直接构造
/// @param state serialize() 返回的状态
[[nodiscard]]
explicit constexpr RomuDuoJr(state_type state) noexcept
: Base(state) {}
/// @brief 生成下一个 64 位随机数
/// @return [min(), max()] 区间内的伪随机数
constexpr result_type operator()() noexcept;
};
// ── 全 PRNG 引擎 TLS 可平凡析构(Trivially Destructible)编译期静态断言 ──
static_assert(std::is_trivially_destructible_v<Xoshiro256StarStar>, "Xoshiro256StarStar must be trivially destructible for safe TLS.");
static_assert(std::is_trivially_destructible_v<Xoroshiro128StarStar>, "Xoroshiro128StarStar must be trivially destructible for safe TLS.");
static_assert(std::is_trivially_destructible_v<Xoshiro128StarStar>, "Xoshiro128StarStar must be trivially destructible for safe TLS.");
static_assert(std::is_trivially_destructible_v<Xoroshiro64StarStar>, "Xoroshiro64StarStar must be trivially destructible for safe TLS.");
static_assert(std::is_trivially_destructible_v<SplitMix64>, "SplitMix64 must be trivially destructible for safe TLS.");
static_assert(std::is_trivially_destructible_v<SFC64>, "SFC64 must be trivially destructible for safe TLS.");
static_assert(std::is_trivially_destructible_v<RomuDuoJr>, "RomuDuoJr must be trivially destructible for safe TLS.");
/// @brief ChaCha20 密码学安全伪随机数生成器(CSPRNG),64 位输出,符合 RFC 8439。
///
/// @details 状态为 key(256-bit) + counter(32-bit) + nonce(96-bit)。
/// 每次 operator() 返回 8 字节,一个 block 服务 8 次调用。
/// 默认从 OS 熵自动播种,并在输出 2^20 字节后自动 reseed 以提供前向安全。
/// 满足 `std::uniform_random_bit_generator` 概念。
///
/// @note CSPRNG 安全约束:不提供 serialize/deserialize、operator<</>>、
/// jump/longJump(状态导出违背 CSPRNG 安全模型)。
/// 非线程安全,每线程应持有独立实例。
/// @sa SecureRandomBytes, SecureSeed, IsOsCryptoEntropyAvailable, Xoshiro256StarStar
class ChaCha20
{
public:
using result_type = std::uint64_t; ///< 输出类型
ChaCha20(const ChaCha20&) = delete;
ChaCha20& operator=(const ChaCha20&) = delete;
ChaCha20(ChaCha20&& other) noexcept;
ChaCha20& operator=(ChaCha20&& other) noexcept;
~ChaCha20() noexcept;
/// @brief 构造方式 1:从 OS 熵自动播种(密码学安全,默认)
/// @note 推荐用于生产环境的密码学安全场景
ChaCha20();
/// @brief 构造方式 2:以显式 64 位种子构造
/// @param seed 64 位种子值
/// @note 仅用于测试/复现,非密码学安全(种子空间仅 64-bit)
[[nodiscard]]
explicit ChaCha20(std::uint64_t seed);
/// @brief 构造方式 3:直接指定 key + nonce + counter(高级用法/测试复现)
/// @param key 密钥指针,须为 32 字节
/// @param keyLen 密钥长度(字节),须为 32,否则抛出 std::invalid_argument
/// @param nonce 随机数指针,须为 12 字节
/// @param nonceLen 随机数长度(字节),须为 12,否则抛出 std::invalid_argument
/// @param counter 32-bit block 计数器初值(默认 0;KAT 测试时显式传 1)
/// @note 此构造路径不调用 SecureRandomBytes,调用方须自行保证 key/nonce 的熵源
ChaCha20(const std::uint8_t* key, std::size_t keyLen,
const std::uint8_t* nonce, std::size_t nonceLen,
std::uint32_t counter = 0);
/// @brief 生成下一个 64 位随机数
/// @return [min(), max()] 区间内的密码学安全伪随机数
result_type operator()();
/// @brief 跳过 n 个输出
/// @param n 跳过次数
void discard(unsigned long long n);
/// @brief 从 OS 熵重新播种
/// @note 手动触发,重置 counter 与字节缓存
void reseed();
/// @brief 输出范围下界
/// @return 0
[[nodiscard]]
static constexpr result_type min() noexcept { return 0; }
/// @brief 输出范围上界
/// @return 2^64 - 1
[[nodiscard]]
static constexpr result_type max() noexcept { return UINT64_MAX; }
// 不提供:serialize/deserialize, operator<</>>, jump/longJump(CSPRNG 安全约束)
private:
std::array<std::uint32_t, 12> m_state; // key(8) + counter(1) + nonce(3),常数省略(generateBlock 时补齐)
std::array<std::uint8_t, 64> m_buffer; // 当前 block 的字节缓存
std::size_t m_bufferPos; // 缓存消费位置 [0, 64),==64 时触发新 block
std::uint64_t m_bytesSinceReseed; // 自上次 reseed 以来输出的字节数
bool m_autoReseed{ false }; // 是否在满 1MB 后自动从 OS 熵重新播种(仅默认无参构造函数启用)
void generateBlock(); // 跑一次 ChaCha20 block 函数填充 m_buffer
void reseedIfNecessary(); // m_bytesSinceReseed >= 阈值时自动 reseed
};
// ── sizeof 守卫:防止引擎 ABI 意外变化 ──
static_assert(sizeof(Xoshiro256StarStar) == 32);
static_assert(sizeof(Xoroshiro128StarStar) == 16);
static_assert(sizeof(Xoshiro128StarStar) == 16);
static_assert(sizeof(Xoroshiro64StarStar) == 8);
static_assert(sizeof(SFC64) == 32);
static_assert(sizeof(RomuDuoJr) == 16);
static_assert(sizeof(SplitMix64) == 8);
}
////////////////////////////////////////////////////////////////
namespace RandX
{
template <std::same_as<std::uint32_t> Uint32>
inline constexpr float FloatFromBits(const Uint32 i) noexcept
{
return (i >> 8) * 0x1.0p-24f;
}
template <std::same_as<std::uint64_t> Uint64>
inline constexpr double DoubleFromBits(const Uint64 i) noexcept
{
return (i >> 11) * 0x1.0p-53;
}
namespace detail
{
// 安全擦除内存(volatile 防止编译器死存储消除)
static void SecureWipe(void* ptr, std::size_t len) noexcept
{
volatile auto* p = static_cast<volatile std::uint8_t*>(ptr);
while (len--) *p++ = 0;
}
// 尝试使用 RDRAND 获取 64 位硬件随机数
[[nodiscard]]
inline bool HardwareRand64(std::uint64_t& out) noexcept
{
#if defined(__x86_64__) || defined(_M_X64)
#if defined(__RDRND__)
unsigned long long result;
if (__builtin_ia32_rdrand64_step(&result))
{
out = result;
return true;
}
#elif defined(_MSC_VER)
int cpuInfo[4] = {0};
__cpuid(cpuInfo, 1);
if ((cpuInfo[2] & (1 << 30)) != 0)
{
unsigned long long result = 0;
if (_rdrand64_step(&result))
{
out = result;
return true;
}
}
#endif
#endif
(void)out;
return false;
}
// ── A3 跨平台 OS 密码学熵源 ──
// 用 OS 密码学 API 填充 [buf, buf+n) 字节;成功返回 true。
// 平台优先级:Windows BCryptGenRandom → Linux getrandom → macOS SecRandomCopyBytes → std::random_device 兜底
// 注:getrandom 可能短读,内部循环直至填满;BCryptGenRandom/SecRandomCopyBytes 一次填满
[[nodiscard]]
inline bool GetOsEntropyBytes(void* buf, std::size_t n) noexcept
{
if (n == 0) return true;
auto* p = static_cast<std::uint8_t*>(buf);
# if defined(_WIN32) && __has_include(<bcrypt.h>)
// Windows: BCryptGenRandom(分块处理 >4GB 时的 ULONG 截断)
// NTSTATUS >= 0 即 NT_SUCCESS(不能 == 0,正向 informational code 也属成功)
std::size_t filled = 0;
while (filled < n)
{
const ULONG chunkSize = static_cast<ULONG>((std::min)(n - filled, static_cast<std::size_t>((std::numeric_limits<ULONG>::max)())));
if (::BCryptGenRandom(nullptr, p + filled, chunkSize, BCRYPT_USE_SYSTEM_PREFERRED_RNG) < 0)
{
return false;
}
filled += chunkSize;
}
return true;
# elif defined(__linux__) && __has_include(<sys/random.h>)
// Linux: getrandom(循环处理短读与 EINTR)
std::size_t filled = 0;
while (filled < n)
{
const ssize_t ret = ::getrandom(p + filled, n - filled, 0);
if (ret < 0)
{
if (errno == EINTR) continue; // 被信号打断,重试
return false; // ENOSYS/EFAULT 等不可恢复错误
}
if (ret == 0) return false;
filled += static_cast<std::size_t>(ret);
}
return true;
# elif defined(__APPLE__) && __has_include(<Security/Security.h>)
// macOS: SecRandomCopyBytes(一次调用填满)
return (::SecRandomCopyBytes(kSecRandomDefault, n, p) == errSecSuccess);
# else
// 无可用 OS 密码学熵源 → 返回 false,SecureRandomBytes 将抛出异常
// 非安全场景的播种请使用 RandomSeed()(含 random_device → 时间戳回退链)
(void)p; (void)n;
return false;
# endif
}
// 返回 true 当且仅当编译期检测到 OS 密码学熵源 API(BCryptGenRandom/getrandom/SecRandomCopyBytes)
// 返回 false 表示当前运行在 std::random_device 兜底路径,ChaCha20() 默认构造不保证密码学安全
[[nodiscard]]
inline bool HasCryptoGradeOsEntropy() noexcept
{
# if (defined(_WIN32) && __has_include(<bcrypt.h>)) || (defined(__linux__) && __has_include(<sys/random.h>)) || (defined(__APPLE__) && __has_include(<Security/Security.h>))
return true;
# else
return false;
# endif
}
// ── A4 ChaCha20 常数与辅助 ──
// ChaCha20 常数 "expand 32-byte k"(RFC 8439 §2.3)
inline constexpr std::uint32_t ChaCha20Constants[4] = {
0x61707865u, 0x3320646eu, 0x79622d32u, 0x6b206574u
};
// 参考 NIST SP 800-90A reseed_interval 概念(SP 800-90A 涵盖 Hash/HMAC/CTR_DRBG,不含 ChaCha20;
// 此处借用其"周期性强制 reseed 提供前向安全"思想,取保守阈值)
inline constexpr std::uint64_t ChaCha20ReseedThreshold = 1ULL << 20; // 1 MB
// ChaCha20 quarter-round(仅 add/xor/rotl,常时间友好)
static void ChaCha20QuarterRound(std::uint32_t& a, std::uint32_t& b,
std::uint32_t& c, std::uint32_t& d) noexcept
{
a += b; d ^= a; d = RotL(d, 16);
c += d; b ^= c; b = RotL(b, 12);
a += b; d ^= a; d = RotL(d, 8);
c += d; b ^= c; b = RotL(b, 7);
}
template <class Engine>
[[nodiscard]]
inline std::uint64_t Generate64Bits(Engine& engine)
{
if constexpr (sizeof(typename Engine::result_type) >= 8)
{
return static_cast<std::uint64_t>(engine());
}
else
{
const std::uint64_t lo = static_cast<std::uint64_t>(engine());
const std::uint64_t hi = static_cast<std::uint64_t>(engine());
return (hi << 32) | lo;
}
}
// 字符类型 concept(char/wchar_t/char8_t/char16_t/char32_t)
// char8_t 仅在 C++20+ 编译器下为基本类型,用特性检测宏条件启用
template <class T>
concept Character =
std::same_as<T, char> ||
std::same_as<T, wchar_t> ||
std::same_as<T, char16_t> ||
std::same_as<T, char32_t>
#if defined(__cpp_char8_t) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|| std::same_as<T, char8_t>
#endif
;
// 检测 state_type 是否为可索引容器(排除标量如 SplitMix64 的 uint64_t)
template <class S>
concept IndexableState = requires(const S& cs, S& s) {
{ cs.size() } -> std::same_as<std::size_t>;
{ s[std::size_t{}] } -> std::same_as<typename S::value_type&>;
};
// 可序列化引擎 concept(仅对 state_type 为容器类的引擎生效)
template <class E>
concept SerializableEngine = requires(const E& ce, E& e) {
{ ce.serialize() } -> std::same_as<typename E::state_type>;
{ e.deserialize(std::declval<typename E::state_type>()) } -> std::same_as<void>;
typename E::state_type;
requires IndexableState<typename E::state_type>;
};
/// @brief 可跳跃引擎概念:支持 jump() 前进 2^N 步
///
/// @details 满足此概念的引擎可通过 jump() 创建并行不重叠子序列。
/// 当前满足:Xoshiro256StarStar, Xoroshiro128StarStar, Xoshiro128StarStar。
/// 不满足:SplitMix64, SFC64, RomuDuoJr, Xoroshiro64StarStar, ChaCha20。
///
/// @note ChaCha20 不提供 jump(CSPRNG 安全约束,状态导出违背前向安全模型)。
/// @sa StreamEngine, MakeStreamEngine
template <class E>
concept JumpableEngine = requires(E& e) {
{ e.jump() } -> std::same_as<void>;
};
/// @brief 流式引擎概念:可通过 MakeStreamEngine 创建互不重叠的子序列流
///
/// @details 当前等价于 JumpableEngine(jump-based 流)。
/// JumpableEngine 描述能力(能 jump),StreamEngine 描述用途(能创建流)。
/// 未来 counter-based 引擎(如 Philox)可通过 counter 偏移创建流,
/// 届时此概念可扩展为 JumpableEngine<E> || CounterBasedEngine<E>。
///
/// @warning 当前约束与 JumpableEngine 完全相同,仅为语义区分与 Philox 预留。
/// 不要假设两者约束不同,等 Philox 落地时再引入 CounterBasedEngine。
/// @sa MakeStreamEngine, JumpableEngine