1

当我使用 JavaMessageDigest计算BigInteger. 看起来有时哈希值有 256 位,但有时它只有 255 位。这是我用来测试 BigInteger 散列的代码:

@Test
public void testSHA256LengthConsistent() {
    MessageDigest sha256 = null;
    try {
        sha256 = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e) {
        Assert.fail("NoSuchAlgorithmException. Can't construct the MessageDigest.");
    }
    BigInteger[] tests = {new BigInteger("15902493"), new BigInteger("5189087324092341824"), new BigInteger("7153293421609183203421127438153268")};
    for(BigInteger testNum : tests) {
        byte[] hash = sha256.digest(testNum.toByteArray());
        Assert.assertEquals(32, hash.length); //256 bits is 32 bytes
        BigInteger hashedInt = new BigInteger(1, hash);
        Assert.assertEquals(256, hashedInt.bitLength());
    }
}

(是的,我使用的是 JUnit 4)。此测试在第三个测试编号上失败,其中第二个断言失败并显示“预期为 256,但为 255”。

我将 BigIntegers 与字节数组转换的方式有问题吗?我可以为 Java 的 MessageDigest 找到的所有示例都使用它来散列字符串,而不是 BigInteger,所以我不知道是否有“标准”方式将 BigInteger 与 MessageDigest 一起使用。或者,这是 Java 处理 SHA-256 方式中的错误或边缘情况,并且 7153293421609183203421127438153268 (我随机生成的一个数字)会导致哈希中的一个错误?

顺便说一句,我已经尝试将哈希转换为负 BigInteger(使用new BigInteger(-1, hash))以查看符号位是否有问题,但我得到了完全相同的结果。

4

2 回答 2

7

前导零被忽略

byte[] bytes = {0x0, 0x1};
System.out.println(new BigInteger(1, bytes).bitLength());

印刷

1

不是您预期的 16 岁。


我应该阅读 Javadoc,因为它在BigInteger.bitLength()中声明

此 BigInteger 的最小二进制补码表示中的位数,不包括符号位。

于 2012-10-16T22:12:15.953 回答
0

如果您要运行足够数量的随机测试,您会看到大约一半的结果是 256 位长,四分之一是 255 位长,八分之一是 254 位长等等。原因是每个位的哈希实际上是随机的,因此高位(或者,准确地说,您关心的任何其他特定位)有 50% 的概率为 1,50% 的概率为 0,25% 的概率为两个高阶位(或您要查看的任何其他两个特定位)是 00(或您要测试的任何其他值)等等。

 public static void main(final String[] args) throws Exception {
    final Random random = new Random();
    final int[] bits = new int[257];
    for (int i = 0; i < 10000; i++) {
        final MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        final BigInteger testNum = new BigInteger(100, random);
        final byte[] hash = sha256.digest(testNum.toByteArray());
        final BigInteger hashedInt = new BigInteger(1, hash);
        bits[hashedInt.bitLength()]++;
    }

    for (int i = 0; i < bits.length; i++) {
        if (bits[i] > 0) {
            System.out.println(i + " / " + bits[i]);
        }
    }        
}

制作:

位:244 计数:2 0.02% 位:245 计数:3 0.03% 位:246 计数:4 0.04% 位:247 计数:7 0.07% 位:248 计数:20 0.2% 位:249 计数:33 0.33% 位: 250 计数:70 0.7% 位数:251 计数:168 1.68% 位数:252 计数:296 2.96% 位数:253 计数:657 6.57% 位数:254 计数:1238 12.38% 位数:255 计数:2510 25.1% 位数:256 位数: 4992 49.92%

于 2017-09-22T20:58:09.173 回答