如何使用Python计算CRC32以匹配在线结果?

47
我正在尝试使用Python计算/生成一些随机字符串的CRC32哈希值,但它们与我从在线来源生成的值不匹配。以下是我在我的电脑上所做的操作:
>>> import binascii
>>> binascii.crc32('hello-world')
-1311505829

另一种方法,
>>> import zlib
>>> zlib.crc32('hello-world')
-1311505829

上述结果相同表明我正确地调用了该函数。但是,如果我访问以下在线资源, 对于字符串“hello-world”,它们都给出相同的值= b1d4025b
有人知道我需要做什么才能获得匹配的结果吗?
当我输入这个问题时,我想到我可能需要将我的Python结果转换为十六进制。
>>> hex(zlib.crc32('hello-world'))
'-0x4e2bfda5'

不幸的是,那也没有帮助。:(

3个回答

56

Python 2(不同于py3)使用有符号32位CRC。

那些网站正在使用无符号32位CRC。

除此之外,这些值是相同的,正如您可以从这里看到的一样:

>>> 0x100000000 - 0xb1d4025b == 0x4e2bfda5
True

将32位有符号数转换为32位无符号数的一种快速方法是:*

>>> -1311505829 % (1<<32)
2983461467

或者,用十六进制表示:

>>> hex(-1311505829 % (1<<32))
'0xb1d4025b'

& 0xFFFFFFFF% 0x100000000& (2**32-1)% (2**32)等方式都是进行位操作的等价方式;只是取决于你认为哪种方式更易读。


* 这仅适用于支持向下整除的语言,例如Python(-3 // 2 == -2);在支持截断整数除法的语言中,例如Java(-3 / 2 == -1),你仍将得到一个负数。而在不要求除法和模运算配合得当的语言中,例如C语言,情况未知——但在C语言中,你只需将字节转换为所需类型即可……


3
Python正在执行带符号的32位CRC校验。请注意,在Python3中,这已更改为运行无符号CRC。请参阅文档 - dthor
2
这并不取决于除法的计算方式,而是取决于 % 的定义。在大多数编程语言中,它被定义为以下之一:x % y == x - floor(x / y) * y(“与除数同号”,即 Python 所做的。因此,2**32 是正数),x % y == x - truncate(x / y) * y(“与被除数同号”)或 x % y == x - round_towards_zero(x / y)(“正模”)。通常情况下,这与 / 相同,但并非总是如此。要在其他语言中始终进行正整数除法,您可以像这样做:def positive_mod(a, b): return ((a % b) + b) % b。请参见 https://en.wikipedia.org/wiki/Modulo_operation。 - Artyer

39

《zlib.crc32文档》建议使用以下方法“在所有Python版本和平台上生成相同的数值”。

import zlib
hex(zlib.crc32(b'hello-world') & 0xffffffff)

结果如预期的那样是0xb1d4025b


我很好奇这在不同的平台上会有什么不同。Python 的行为难道不应该是跨平台一致的吗?(忽略 2.x 和 3.x 的差异) - chronodekar
@chronodekar:我相信在源代码中找到它不会太难;如果你自己找不到,可以创建一个新的问题。但是从快速测试来看,在Mac 2.7和Linux 2.7上是负面的,在Windows 2.7和Mac 3.5上是正面的,所以我很确定这是一个平台问题,而不是2与3的问题。或者也许是两者的结合。 (无论如何,这并没有帮助OP,他的Python显然像我的Mac 2.7一样执行有符号crc32...) - abarnert
2
@chronodekar 我在Python文档中没有找到明确的答案,因此我已编辑我的答案,以在所有Python版本和平台上具有相同的行为。 - Aleksei Zyrianov
请注意,Python 3保证binascii.crc32返回无符号值,而2.6和2.7应该保证返回有符号值,因此平台差异不应影响此操作。 - rosuav

8

看起来Python返回了有符号整数(因此是负数),而其他语言返回的是无符号整数。

我尝试使用模运算和2^32,它给出了与这些网站相同的值。

>>> hex(zlib.crc32(b'hello-world')% 2**32)
'0xb1d4025b'

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