Java 在包 java.secure.random 中提供了一个加密安全的随机数生成器。
如果我考虑像 RNG 的播种和循环重新实例化这样的事情,是否可以使用这个数字生成器?或者我可以“按原样”使用数字生成器吗?
有人用过这个发电机吗?
编辑:要求是:
a) 具有统计独立性
b) 在其范围内公平分布(在统计预期范围内)
c) 通过各种公认的统计测试
d) 具有密码强度。
有关 SecureRandom的文档说它可能会阻止等待系统生成更多熵(例如,在 Linux 中,它从 /dev/random 获取随机数),所以如果你要使用它,也许你需要硬件的帮助:安装随机数生成器卡(一种生成真实随机数,而不是伪随机数的硬件设备),这样您的系统将以足够的速度生成随机数,因此您的程序不会被阻塞。
正如其他人所说,安全 RNG 的吞吐量可能有限。为了缓解这种情况,您可以通过播种 CPRNG 来扩展安全随机性,或者您可以尝试优化比特流的使用。
例如,要洗一包纸牌,您只需要 226 位,但一个简单的算法(调用nextInt(n)
每张牌)可能会使用 1600 或 3200 位,浪费了 85% 的熵,并使您更容易受到延迟的影响 7 倍。
对于这种情况,我认为雅克医生的方法是合适的。
为此,这里有一些针对越来越昂贵的熵源的性能分析(也包含代码):
我会倾向于有效使用而不是拉伸,因为我认为证明可靠熵流的有效消费者的公平性要比用种子良好的 PRNG 证明任何绘图方法的公平性要容易得多。
编辑2: 我真的不知道Java,但我把它放在一起:
public class MySecureRandom extends java.security.SecureRandom {
private long m = 1;
private long r = 0;
@Override
public final int nextInt(int n) {
while (true) {
if (m < 0x80000000L) {
m <<= 32;
r <<= 32;
r += (long)next(32) - Integer.MIN_VALUE;
}
long q = m / n;
if (r < n * q) {
int x = (int)(r % n);
m = q;
r /= n;
return x;
}
m -= n * q;
r -= n * q;
}
}
}
这取消了贪婪的默认统一 [0,n-1] 生成器,并将其替换为修改后的雅克博士版本。对洗牌范围的值进行计时显示几乎比SecureRandom.nextInt(n)
.
我之前版本的这段代码(只有 2 倍加速)假设这SecureRandom.next(b)
是有效的,但事实证明调用是丢弃熵并将整个循环拖下来。这个版本管理自己的分块。
你可以使用java.security.SecureRandom
,因为你可以使用java.util.Random
这些东西。
请注意,这java.security.SecureRandom
可能取决于运行程序的计算机的一些熵。如果您从中获得许多随机值,那么它可能会阻塞,直到计算机生成足够的熵(例如,在 linuxjava.security.SecureRandom
上使用/dev/urandom
)。
因此,如果您想生成许多随机值并且可以使用 PRNG,请使用java.util.Random
.