Java中的真随机生成

26

我在阅读 Math.random() 的 java 文档时发现,随机数实际上只是伪随机数。

是否有一个库(特别是 Java),能够根据环境温度、CPU 温度/电压等随机变量生成随机数呢?

13个回答

29

26
也许我有点多疑,但如果我要用它进行任何安全相关的事情,我不会相信由第三方提供的随机数。最好选择一个平台解决方案——尤其是已经有一个可用的方案。 - tvanfosson
3
没有平台解决方案可以生成真正的随机数。但如果您需要安全性所需的随机性,请使用加密API。 - Greg Dean
3
大气噪声是否真正随机,还是存在可检测到的模式? - Pop Catalin
3
一个JCA提供者可以使用硬件随机数生成器(RNG)来实现SecureRandom,这在TPMs和一些Intel芯片组中越来越常见。这些使用不可预测的量子力学现象来(缓慢地)产生真正的随机位。由于速率较低,最好将其用作良好PRNG的种子。 - erickson
@PopCatalin 在这些原始测量中存在明显的模式和相关性。这就是为什么他们应用“白化阶段”的原因。(维基百科上的随机性提取器) - Mark Jeronimus

24

你的问题存在歧义,这导致答案非常分散。

如果你正在寻找一种依赖于系统随机源的随机实现(我猜你是这样的),那么java.security.SecureRandom可以达到这个目的。Sun安全提供程序在你的java.security文件中的默认配置如下:

#
# Select the source of seed data for SecureRandom. By default an
# attempt is made to use the entropy gathering device specified by
# the securerandom.source property. If an exception occurs when
# accessing the URL then the traditional system/thread activity
# algorithm is used.
#
# On Solaris and Linux systems, if file:/dev/urandom is specified and it
# exists, a special SecureRandom implementation is activated by default.
# This "NativePRNG" reads random bytes directly from /dev/urandom.
#
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom
如果你真的想要用更加随机的方式来覆盖这个值,可以通过更改此属性或使用另一个SecureRandom来完成。例如,你可以使用支持HSM模块的JCE提供者,如nCipher nShield自带的PRNG,或者在讨论中提到的其他解决方案。

10

快速而不精确:

public static int generateRandom() throws IOException
{
    int num = 0;
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    for (int i = 0 ; i < Integer.SIZE ; i++)
    {
        System.out
          .println("Flip a fair coin. Enter h for heads, anything else for tails.");

        if (br.readLine().charAt(0) == 'h')
        {
            num += Math.pow(2, i);
        }
    }

    return num;
}

2
+1 完美的算法,但你真的应该让它更面向对象。只需扩展 SecureRandom 即可。 - maaartinus

8

由于访问这些随机数据源需要某种形式的硬件访问,因此使用纯Java无法编写可移植的库。

但是,您可以尝试编写平台相关代码以读取平台的随机数据源。例如,对于Linux(以及可能也适用于其他类Unix系统),可以使用/dev/random

另外,请查看SecureRandom类,它可能已经具备您想要的功能。


硬件可以通过USB和TCP/IP访问。我相信第一种方式可以使用纯Java可移植编写,而我可以确定第二种方式可以。 - skiphoppy

7
请确保您确实需要“真正”的随机数。物理随机源必须进行测量,而测量过程会引入一些偏差。对于某些应用程序,“伪”随机数实际上比“真”随机数更可取。它们可以具有更好的统计特性,并且可以更快地生成它们。另一方面,如果你不小心,你可能会用伪随机数生成器弄出乱子。请务必参考此处

任何好的物理随机数生成器都使用测量作为起点,并运行大量的位移来消除任何偏差。 - Javier
听起来像是一个算法,有点像伪随机数生成器。 :-) - John D. Cook
正确,但使用物理种子,并检查它获取了多少位物理熵,以便不输出超过该数量的位数。 - Javier

4

Java加密架构需要具有密码学强度的随机数。其中包含@saua提到的SecureRandom类。


3

没有真正的随机数生成器,因为它们都依赖于确定性过程来计算随机数,所以无论生成的数字看起来是否遵循真正的随机分布,它们可能是隐藏的 - 并且非常复杂的 - 模式的一部分,因此它们是伪随机的。 然而,您可以实现自己的随机数生成器,有几种不错的、计算廉价的方法可以在C语言数值计算方法(第二版) - 第7章中阅读。 希望对您有所帮助


嗯,将 Geiger 计数器连接到计算机上怎么样?那不是真正的随机吗? - Tamas Czinege
1
任何自然混沌系统(包括辐射)都可以成为真正随机化的有效来源,伪随机生成器的问题在于不清楚它是否可以使用某些插值技术进行数学描述。 - Josef

3
为了澄清:在宇宙中唯一真正存在的随机生成器是“量子随机比特生成器”。没有其他机制能保证生成的比特完全随机,因为即使现在您无法预测结果,也无法保证将来不会这样做。
“量子随机比特生成器”(QRBG121)是一个快速的非确定性随机位(数)生成器,其随机性依赖于半导体中光子发射的内在随机性和随后的光电效应检测。在此过程中,光子被独立地随机检测,一个接一个。检测到的光子的时间信息用于生成随机二进制位-比特。该方法的独特之处在于它仅使用一个光子检测器产生零和一,从而导致极小的偏差和高度抗组件变化和老化。此外,单个光子的检测是由光倍增管(PMT)完成的。与固态光子探测器相比,PMT具有极大的信噪比性能和更低的出现余晖的概率,这可能是不必要关联的来源。
更多信息例如在这里:http://random.irb.hr/

无意中发现了这个。你不需要光电倍增管来获得量子不确定性。看看这里关于卑微的齐纳二极管的链接。同样地,数字相机传感器中的噪声也会产生同样程度的真随机性。那就是你派对照片上的噪音。"量子随机比特生成器"只是某些硬件制造商的营销炒作。 - Paul Uszak

2

对于大多数情况而言,伪随机数已经足够使用。如果你只需要一个简单的随机数,例如“30%的时间执行此操作”,那么使用时间戳作为种子即可。如果需要安全随机数,例如洗牌一副牌,你需要更加仔细地选择种子,存在一些良好的来源以创建安全种子。

使用种子的原因是为了能够"重现"由算法生成的相同随机数序列。非常好的应用场景就是在进行随机模拟某些实验时,你想要重复特定实验,然后你只需使用相同的种子。

如果需要比Java自带的更好的PRNG,请看一下梅森旋转算法


1
在大学时,我有一个任务是实现随机生成器。我创建了类似于这样的随机数生成器:创建桌面窗口并要求用户单击窗口上的随机位置,在每次单击后,我获取单击点的坐标。我认为这相当随机。

3
他们实际上进行了“有无限猴子打字机”的实验,这与你所描述的类似。如果我没记错的话,研究结果是通常猴子只按住“F”键(或其他方便的键)。用户行为很少是随机的。 - Jimmy
我认为如何处理原始数据非常重要。我认为将几个预测性较低的来源结合起来,并对它们进行奇怪的操作应该足够好了。据我所知,这就是/dev/random所做的事情。即使没有真正的随机数生成器,它在历史上表现得相当不错。虽然速度较慢。另一方面,与PRNG结合使用,它与/dev/urandom在历史上表现良好且速度更快。 - akostadinov
即使按住“F”键,也必须有一些随机性。例如,我打赌你不知道它被按住了多少纳秒? - ban-geoengineering

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接