- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我似乎看到很多答案有人建议使用 <random>
生成随机数,通常伴随着这样的代码:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);
通常这会取代某种“邪恶的可憎之物”,例如:
srand(time(NULL));
rand()%6;
我们可能 criticize争论的老方法 time(NULL)
提供低熵,time(NULL)
是可预测的,最终结果是不均匀的。
但所有这些都适用于新方法:它只是有一个更 Shiny 的表面。
rd()
返回单个 unsigned int
.这至少有 16 位,可能有 32 位。这不足以播种 MT 的 19937 位状态。
使用 std::mt19937 gen(rd());gen()
(用 32 位播种并查看第一个输出)没有提供良好的输出分布。 7 和 13 永远不可能是第一个输出。两个种子产生 0。十二个种子产生 1226181350。( Link )
std::random_device
可以,有时是,实现为具有固定种子的简单 PRNG。因此,它可能会在每次运行时产生相同的序列。 ( Link ) 这比 time(NULL)
还要糟糕.
更糟糕的是,复制和粘贴上述代码片段非常容易,尽管它们包含问题。一些解决方案需要获取 largish libraries这可能并不适合所有人。
鉴于此,我的问题是如何在 C++ 中简洁、可移植和彻底地播种 mt19937 PRNG?
鉴于上述问题,一个很好的答案:
std::random_device
或 time(NULL)
作为熵的来源。想法
我目前的想法是 std::random_device
的输出可以与 time(NULL)
混合(可能通过 XOR) , 来自 address space randomization 的值,以及一个硬编码常量(可以在分发期间设置)以获得熵的最大努力。
std::random_device::entropy()
does not很好地说明什么 std::random_device
可能会也可能不会。
最佳答案
我认为 std::random_device
的最大缺陷是,如果没有可用的 CSPRNG,则允许确定性回退。这本身就是不使用 std::random_device
为 PRNG 播种的一个很好的理由,因为产生的字节可能是确定性的。不幸的是,它没有提供 API 来查明这种情况何时发生,或者请求失败而不是低质量的随机数。
也就是说,没有完全可移植的解决方案:但是,有一个体面的、最小的方法。您可以使用围绕 CSPRNG 的最小包装器(定义为下面的 sysrandom
)来播种 PRNG。
您可以依赖 CryptGenRandom
,一个 CSPRNG。例如,您可以使用以下代码:
bool acquire_context(HCRYPTPROV *ctx)
{
if (!CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, 0)) {
return CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET);
}
return true;
}
size_t sysrandom(void* dst, size_t dstlen)
{
HCRYPTPROV ctx;
if (!acquire_context(&ctx)) {
throw std::runtime_error("Unable to initialize Win32 crypt library.");
}
BYTE* buffer = reinterpret_cast<BYTE*>(dst);
if(!CryptGenRandom(ctx, dstlen, buffer)) {
throw std::runtime_error("Unable to generate random bytes.");
}
if (!CryptReleaseContext(ctx, 0)) {
throw std::runtime_error("Unable to release Win32 crypt library.");
}
return dstlen;
}
在许多类 Unix 系统上,您应该使用 /dev/urandom可能时(尽管不能保证在符合 POSIX 的系统上存在)。
size_t sysrandom(void* dst, size_t dstlen)
{
char* buffer = reinterpret_cast<char*>(dst);
std::ifstream stream("/dev/urandom", std::ios_base::binary | std::ios_base::in);
stream.read(buffer, dstlen);
return dstlen;
}
如果没有可用的 CSPRNG,您可以选择依赖 std::random_device
。但是,如果可能的话,我会避免这种情况,因为各种编译器(最著名的是 MinGW)将其实现为 PRNG。 (事实上 ,每次都产生相同的序列以提醒人们它不是随机的)。
现在我们的部分开销最小,我们可以生成所需的随机熵位来为我们的 PRNG 播种。该示例使用(显然不够)32 位作为 PRNG 的种子,您应该增加此值(这取决于您的 CSPRNG)。
std::uint_least32_t seed;
sysrandom(&seed, sizeof(seed));
std::mt19937 gen(seed);
在快速查看 source code 之后,我们可以看到与 boost::random_device(一个真正的 CSPRNG)的相似之处. Boost 在 Windows 上使用 MS_DEF_PROV
,这是 PROV_RSA_FULL
的提供程序类型。唯一缺少的是验证加密上下文,这可以通过 CRYPT_VERIFYCONTEXT
完成。在 *Nix 上,Boost 使用 /dev/urandom
。 IE,此解决方案便携、经过充分测试且易于使用。
如果您愿意为了安全而牺牲简洁性,getrandom
在 Linux 3.17 及更高版本以及最近的 Solaris 上是一个很好的选择。 getrandom
的行为与 /dev/urandom
相同,除了它会在内核启动后尚未初始化其 CSPRNG 时阻塞。以下代码片段检测 Linux getrandom
是否可用,如果不可用则返回到 /dev/urandom
。
#if defined(__linux__) || defined(linux) || defined(__linux)
# // Check the kernel version. `getrandom` is only Linux 3.17 and above.
# include <linux/version.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
# define HAVE_GETRANDOM
# endif
#endif
// also requires glibc 2.25 for the libc wrapper
#if defined(HAVE_GETRANDOM)
# include <sys/syscall.h>
# include <linux/random.h>
size_t sysrandom(void* dst, size_t dstlen)
{
int bytes = syscall(SYS_getrandom, dst, dstlen, 0);
if (bytes != dstlen) {
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}
return dstlen;
}
#elif defined(_WIN32)
// Windows sysrandom here.
#else
// POSIX sysrandom here.
#endif
最后一个警告:现代 OpenBSD 没有 /dev/urandom
。你应该使用 getentropy相反。
#if defined(__OpenBSD__)
# define HAVE_GETENTROPY
#endif
#if defined(HAVE_GETENTROPY)
# include <unistd.h>
size_t sysrandom(void* dst, size_t dstlen)
{
int bytes = getentropy(dst, dstlen);
if (bytes != dstlen) {
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}
return dstlen;
}
#endif
如果您需要加密安全的随机字节,您应该用 POSIX 的无缓冲打开/读取/关闭替换 fstream。这是因为 basic_filebuf
和 FILE
都包含一个内部缓冲区,它将通过标准分配器分配(因此不会从内存中删除)。
这可以很容易地通过将 sysrandom
更改为:
size_t sysrandom(void* dst, size_t dstlen)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1) {
throw std::runtime_error("Unable to open /dev/urandom.");
}
if (read(fd, dst, dstlen) != dstlen) {
close(fd);
throw std::runtime_error("Unable to read N bytes from CSPRNG.");
}
close(fd);
return dstlen;
}
特别感谢 Ben Voigt 指出 FILE
使用缓冲读取,因此不应使用。
我还要感谢 Peter Cordes 提到 getrandom
,以及 OpenBSD 缺少 /dev/urandom
。
关于c++ - 如何简洁、便携、彻底地播种mt19937 PRNG?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46595287/
从 PHP7 开始,为 PRNG 引入了一个新函数:random_int ( http://php.net/manual/en/function.random-int.php ) PHP 手册中没有与
在 .net 核心项目中,我像这样在 Program.cs 文件中播种: var host = BuildWebHost(args); using (var scope = host.Services
我有一张谷歌地图,上面有大约 200 个标记。使用谷歌距离矩阵服务,我可以找到从一个地址到 map 上所有标记的行驶距离。由于 API 限制,我每次调用只能提交 25 个目的地,因此我必须将操作分解为
下面的脚本抛出错误(自定义字段未定义)。我需要以不同的方式传递元素 ID 吗? 我正在尝试使用我要计算的表单字段来为数组播种。它应该迭代数组中的每个表单字段,并用表单元素的值递增 sum 变量。 jQ
我正在学习“Laravel 5 Essentials”中的教程。当我尝试使用命令为我的数据库播种时 php artisan db:seed 我收到错误 [ReflectionException]
我正在关注 docs为 users 表设置种子,该表显示正在使用 User::create class UserTableSeeder extends Seeder { public func
让我首先说明我要完成的任务: 我需要在一定范围内随机生成一组数字 我希望这些数字稍微均匀分布 我需要能够为随机数生成播种,这样,给定一个种子,生成的随机数将始终相同。 在对 drand48()、ran
这个问题在这里已经有了答案: Recommended way to initialize srand? (15 个答案) 关闭 9 年前。 我学习的方法是最初使用 srand(time(NULL))
SQLite 是否支持播种 RANDOM() 的功能与 MySQL 对 RAND() 的处理方式相同? $query = "SELECT * FROM table ORDER BY RAND(" .
我正在使用不支持的 Visual Studio 2010 ,所以我必须播种 default_random_engine .因此,我决定用 rand 播种它如下 srand((unsigned int
在 google OR-tools 库中,“原始”CP-Solver(此处讨论: https://developers.google.com/optimization/cp/original_cp_s
我正在尝试为 AspNetRole 表设置初始系统角色。 播种扩展: public static void EnsureRolesAreCreated(this IApplicationBuilder
我似乎无法弄清楚如何使用 Sequelize 为 ARRAY(ENUM) 播种。当我通过我的应用程序注册用户时,我可以很好地创建一个新用户,但是当我在种子文件中使用 queryInterface.bu
以下代码应创建两个具有相同种子的 Random 对象: System.out.println("System time before: " + System.currentTimeMillis());
尝试从集合中选择伪随机元素时,我看到了非确定性行为,即使 RNG 已播种(示例代码如下所示)。为什么会发生这种情况,我是否应该期望其他 Python 数据类型表现出类似的行为? 注意:我只在 Pyth
关于在 openssl/bn.h 中使用 BN_generate_prime 生成质数的内容,我无法找到答案。另外,我将如何播种此函数使用的任何 PRNG? 单独的问题但与我的代码相关(我正在编写一个
所以,我是 MEAN 堆栈的新手,我在尝试播种 MongoDB 时碰壁了。我正在使用 Mongoose 与数据库进行通信,并且有一堆文档建议我应该能够使用填充的 JSON 文件进行播种。 我尝试过的:
我有一个非常简单的情况:我想使用 testcontainers 测试 AWS 中现有的 mysql 数据库。 我遵循了官方指南( https://www.testcontainers.org/modu
我有一个很长(500K+ 行)的两列电子表格,如下所示: Name Code 1234 A 1234 B 1456 C 4556 A 4556 B 4556
我有一个要播种的数据透视表。除了 PK 和 FK,该表还包含另外两列:Arrival & Departure(类型:时间戳)。我正在使用 Carbon 随机填充前面的列。这是我的代码: $faker
我是一名优秀的程序员,十分优秀!