1

使用SecureRandom是否可以保证2 个连续调用不会返回相同的数字?
如果这是客户端 API 端的严格要求,那么代码中的以下循环是否多余?

Random random = SecureRandom.getInstance("SHA1PRNG");  
long value1 = (long)(r.nextDouble() * LIMIT) + 1;  
long value2 = (long)(r.nextDouble() * LIMIT);  

while(value1 == value2) {  
   value2 = (long)(r.nextDouble() * LIMIT);  
}
4

3 回答 3

4

我没想到会有。每个调用都应该是独立的——要求下一个调用不能给出与前一个相同的结果,这意味着它不是随机的,IMO。

举一个更小的例子,假设我们没有nextDouble一个方法,它返回一个 1 到 3 范围内的值(包括 1 到 3)。通过消除两次返回相同值的可能性,您有效地将每次调用限制为 50/50 的选择,没有明显的原因。您将向任何可以观察“此”呼叫的人提供有关下一次呼叫的额外信息。

现在显然double有一个更大的范围 - 所以两个真正随机选择的值是相同的。不完全是 2 64中的 1 ,但相当大。

当然,您已经通过算术减少了这一点 - 即使nextDouble() 确实保证始终返回不同的值,两个double值完全有可能在乘以LIMIT然后转换为long. 想象一下LIMIT,例如,如果是 2……您希望看到多少个可能的值?

所以不,如果您有严格的客户要求,我认为您拥有的代码不是多余的。

于 2015-07-15T20:10:30.003 回答
3

不可以。不能保证会降低安全性,因为攻击者可能会利用您在连续呼叫中永远不会获得相同号码的知识。随机数字序列完全有可能包含数字的“运行”。如果您有一个数字列表,从中您有相同的机会选择任何数字,那么您很有可能可以选择两次相同的数字。当然,发生这种情况的概率低于得到两个不同数字的序列的概率,但它不是零。

此外,CSPRNG 的要求之一是给定一个状态,您不应该能够预测下一个状态(即,您范围内的所有数字都有相同的出现概率)。但是根据您的要求,您可以预测,如果您的随机数生成x范围0为的数字n,那么在下一次调用中您将获得除 之外 x的任何数字。

虽然 CSPRNG 内部可能有某种状态机,但每个调用本质上独立于先前的调用,不应受它们的影响。

如果您要追求独特性,则应使用 UUID 之类的东西。这些可以随机生成,具有获得唯一性的优势(如果您使用的是 CSPRNG 并且种子源具有足够的熵)。

如果要求客户端没有得到两个相同的随机数,那么代码不是多余的。但这会违反“随机性”属性;这有多重要,取决于您的具体情况。

于 2015-07-15T20:10:57.553 回答
2

通过调用nextDouble(),您实际上是在调用Random.nextDouble()-SecureRandom扩展Random并且不覆盖nextDouble()

根据nextDouble()的文档- 不能保证2 个连续调用不会返回相同的数字 - 也就是说,它发生的可能性非常低。

于 2015-07-15T20:10:30.623 回答