【问题标题】:Why does the BigInteger.isProbablePrime() function in Java return true for negative numbers?为什么 Java 中的 BigInteger.isProbablePrime() 函数对负数返回 true?
【发布时间】:2017-05-22 12:20:57
【问题描述】:

我正在用 Java 实现 RSA 公钥加密算法。它需要生成两个随机素数。我一直在使用 SecureRandom 类来生成两个 1024 位数字来创建一个 2048 位密钥。我使用 BigInteger 类处理数字。我使用 isProbablePrime() 函数来确定它是否是素数,确定性为 100。但是,我注意到这个函数对负数返回 true,即使根据定义,素数不能是负数。

【问题讨论】:

标签: java rsa biginteger secure-random


【解决方案1】:

对于“为什么”这个问题,我们无法为您提供明确的答案。为此,您需要与设计 API 的人交谈。

我倾向于同意@weston 的猜想,即“没关系”;看到这个link。该链接的另一个要点是,它取决于素数的哪个定义被用来判断素数是否为负。 (根据最广泛使用的定义,它们不是,但是......)

但是,我可以告诉你,实施行为是经过深思熟虑的。该方法的实现如下:

public boolean isProbablePrime(int certainty) {
    if (certainty <= 0)
        return true;
    BigInteger w = this.abs();
    if (w.equals(TWO))
        return true;
    if (!w.testBit(0) || w.equals(ONE))
        return false;
    return w.primeToCertainty(certainty, null);
}

注意在测试之前它是如何取候选者的绝对值的。

这种行为已经存在很长时间了(据我所知)ZERO 记录了关于它的 Java 错误报告。这支持@weston 的猜想。


不管isProbablePrime的行为是否正确,务实的解决方案是在测试之前添加一个测试,看看你的候选人是否为阴性。

【讨论】:

  • "...在测试之前添加测试以查看您的候选人是否为负数"或不生成负数,因为这是他们将随机位取为整数时的选择,将它们视为签名或未签名。
【解决方案2】:

在素数上,我指出它可能是not matter。但是重要是在将 1024 个随机位转换为整数时,您必须考虑哪种方法是正确的;将其视为已签名(就像您一样)还是未签名?

因此,例如在 8 位中,如果我随机生成 11010011211 当被视为无符号整数时,它是一个素数。

如果我将相同的位 11010011 视为有符号整数,我会得到 -45 这不是质数,即使您接受负质数。

如果弄错了,您的代码将错误地排除有效键并错误地接受无效键。而且,如果为了安全起见,排除所有负数,那么您将只能得到 1023 位素数(二进制补码负数的最高有效位始终为 1)。

因此,您处理从位到整数的转换的方式能够避免负数并避免整个负素数问题,并且 RSA 对选择作为密钥的数字只有一种正确解释。我的猜测是解释是无符号的。

【讨论】:

  • 我遇到的问题是,我生成的被测试为可能的素数的数字不适用于 RSA 的某些部分,因为它们在签名时为负数。它涉及找到模乘逆,其中模是两个随机素数的 LCM,每个素数减一。 BigInteger 对此有一个内置函数。当模数为负值时,这不起作用。
  • 你是说你找到了一个可能的正素数,其前导位 1 后来不起作用?
  • 是的。 BigInteger 类将所有数字视为以二进制补码表示法表示。除了 BigInteger 类之外,在 Java 中实现 RSA 确实没有实用的方法。
  • 向我展示你的将比特位转换为 BigInteger 的代码,我将向你展示如何处理它无符号。
  • “除了 BigInteger 类之外,真的没有在 Java 中实现 RSA 的实用方法。”如果你想重新发明轮子,不。否则这里是一个简单的例子:stackoverflow.com/a/13501136/360211
猜你喜欢
  • 2016-06-08
  • 2018-01-28
  • 1970-01-01
  • 1970-01-01
  • 2019-03-11
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 1970-01-01
相关资源
最近更新 更多