在 Python 中使用 zlib crc32_combine
Using zlib crc32_combine in Python
我正在尝试在 Python 中使用 zlib 中的 crc32_combine
函数。
尽管还有各种其他 zlib 函数可用,
这个不是 "batteries included" 标准库的一部分。
我尝试了两种方法:从 C 代码到 Python 的端口和
使用 ctypes 从 Python 调用 zlib。两者都给我不同的结果,
虽然不是我期待的结果。
我正在展示 ctypes 代码,因为我认为它执行得更快并且有
出现额外程序员错误的可能性较小。
算法可以combine two CRC32散列当
提供了第二个哈希的数据。 crc32_combine定义如下:
crc32(crc32(0, seq1, len1), seq2, len2) == crc32_combine(
crc32(0, seq1, len1), crc32(0, seq2, len2), len2)
这是输出:
Expected CRC: 45E57586
Combined CRC: 567EE4E4
在 win32 上 运行 和 Python 3.5.1 时,第二行总是不同的。不是 Python 2,但结果也不是我所期望的。将 zlib1.dll 放在与脚本相同的目录中进行试用。
import zlib
def crc32_combine_ctypes(crc1, crc2, len2):
import ctypes
from ctypes import util
lib = util.find_library('zlib1')
_zlib = ctypes.CDLL(lib)
assert _zlib._name, "Can't find zlib"
_zlib.crc32_combine.argtypes = [
ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong]
_zlib.crc32_combine.restype = ctypes.c_ulong
return _zlib.crc32_combine(crc1, crc2, len2)
testfile = "zlib1.dll"
with open(testfile, "rb") as tf:
data = tf.read()
print("Expected CRC: %0.8X" % (zlib.crc32(data) & 0xFFFFFFFF))
cut = len(data) // 2 - 100
p1 = data[0:cut]
p2 = data[cut:]
crc1 = zlib.crc32(p1)
crc2 = zlib.crc32(p2)
len1 = len(p1)
len2 = len(p2)
combined = crc32_combine_ctypes(crc1, crc2, len2)
print("Combined CRC: %0.8X" % (combined & 0xFFFFFFFF))
我做错了什么?
eryksun 的想法是正确的:我使用了一个又坏又旧的 DLL。
包含 32 位 dll 的最新 zlib 版本:
https://sourceforge.net/projects/libpng/files/zlib/1.2.8/
我对纯 Python 代码的移植比使用 ctypes 调用库慢几百倍。 (使用具有 1k 次迭代和 50m 作为长度参数的 timeit 的数字)
31.729 (function provided below)
0.120 (just the _zlib.crc32_combine() call: no library loading included)
纯Python代码:
def crc32_combine(crc1, crc2, len2):
"""Explanation algorithm:
crc32(crc32(0, seq1, len1), seq2, len2) == crc32_combine(
crc32(0, seq1, len1), crc32(0, seq2, len2), len2)"""
# degenerate case (also disallow negative lengths)
if len2 <= 0:
return crc1
# put operator for one zero bit in odd
# CRC-32 polynomial, 1, 2, 4, 8, ..., 1073741824
odd = [0xedb88320] + [1 << i for i in range(0, 31)]
even = [0] * 32
def matrix_times(matrix, vector):
number_sum = 0
matrix_index = 0
while vector != 0:
if vector & 1:
number_sum ^= matrix[matrix_index]
vector = vector >> 1 & 0x7FFFFFFF
matrix_index += 1
return number_sum
# put operator for two zero bits in even - gf2_matrix_square(even, odd)
even[:] = [matrix_times(odd, odd[n]) for n in range(0, 32)]
# put operator for four zero bits in odd
odd[:] = [matrix_times(even, even[n]) for n in range(0, 32)]
# apply len2 zeros to crc1 (first square will put the operator for one
# zero byte, eight zero bits, in even)
while len2 != 0:
# apply zeros operator for this bit of len2
even[:] = [matrix_times(odd, odd[n]) for n in range(0, 32)]
if len2 & 1:
crc1 = matrix_times(even, crc1)
len2 >>= 1
# if no more bits set, then done
if len2 == 0:
break
# another iteration of the loop with odd and even swapped
odd[:] = [matrix_times(even, even[n]) for n in range(0, 32)]
if len2 & 1:
crc1 = matrix_times(odd, crc1)
len2 >>= 1
# if no more bits set, then done
# return combined crc
crc1 ^= crc2
return crc1
我正在尝试在 Python 中使用 zlib 中的 crc32_combine
函数。
尽管还有各种其他 zlib 函数可用,
这个不是 "batteries included" 标准库的一部分。
我尝试了两种方法:从 C 代码到 Python 的端口和
使用 ctypes 从 Python 调用 zlib。两者都给我不同的结果,
虽然不是我期待的结果。
我正在展示 ctypes 代码,因为我认为它执行得更快并且有
出现额外程序员错误的可能性较小。
算法可以combine two CRC32散列当 提供了第二个哈希的数据。 crc32_combine定义如下:
crc32(crc32(0, seq1, len1), seq2, len2) == crc32_combine(
crc32(0, seq1, len1), crc32(0, seq2, len2), len2)
这是输出:
Expected CRC: 45E57586
Combined CRC: 567EE4E4
在 win32 上 运行 和 Python 3.5.1 时,第二行总是不同的。不是 Python 2,但结果也不是我所期望的。将 zlib1.dll 放在与脚本相同的目录中进行试用。
import zlib
def crc32_combine_ctypes(crc1, crc2, len2):
import ctypes
from ctypes import util
lib = util.find_library('zlib1')
_zlib = ctypes.CDLL(lib)
assert _zlib._name, "Can't find zlib"
_zlib.crc32_combine.argtypes = [
ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong]
_zlib.crc32_combine.restype = ctypes.c_ulong
return _zlib.crc32_combine(crc1, crc2, len2)
testfile = "zlib1.dll"
with open(testfile, "rb") as tf:
data = tf.read()
print("Expected CRC: %0.8X" % (zlib.crc32(data) & 0xFFFFFFFF))
cut = len(data) // 2 - 100
p1 = data[0:cut]
p2 = data[cut:]
crc1 = zlib.crc32(p1)
crc2 = zlib.crc32(p2)
len1 = len(p1)
len2 = len(p2)
combined = crc32_combine_ctypes(crc1, crc2, len2)
print("Combined CRC: %0.8X" % (combined & 0xFFFFFFFF))
我做错了什么?
eryksun 的想法是正确的:我使用了一个又坏又旧的 DLL。 包含 32 位 dll 的最新 zlib 版本: https://sourceforge.net/projects/libpng/files/zlib/1.2.8/
我对纯 Python 代码的移植比使用 ctypes 调用库慢几百倍。 (使用具有 1k 次迭代和 50m 作为长度参数的 timeit 的数字)
31.729 (function provided below)
0.120 (just the _zlib.crc32_combine() call: no library loading included)
纯Python代码:
def crc32_combine(crc1, crc2, len2):
"""Explanation algorithm:
crc32(crc32(0, seq1, len1), seq2, len2) == crc32_combine(
crc32(0, seq1, len1), crc32(0, seq2, len2), len2)"""
# degenerate case (also disallow negative lengths)
if len2 <= 0:
return crc1
# put operator for one zero bit in odd
# CRC-32 polynomial, 1, 2, 4, 8, ..., 1073741824
odd = [0xedb88320] + [1 << i for i in range(0, 31)]
even = [0] * 32
def matrix_times(matrix, vector):
number_sum = 0
matrix_index = 0
while vector != 0:
if vector & 1:
number_sum ^= matrix[matrix_index]
vector = vector >> 1 & 0x7FFFFFFF
matrix_index += 1
return number_sum
# put operator for two zero bits in even - gf2_matrix_square(even, odd)
even[:] = [matrix_times(odd, odd[n]) for n in range(0, 32)]
# put operator for four zero bits in odd
odd[:] = [matrix_times(even, even[n]) for n in range(0, 32)]
# apply len2 zeros to crc1 (first square will put the operator for one
# zero byte, eight zero bits, in even)
while len2 != 0:
# apply zeros operator for this bit of len2
even[:] = [matrix_times(odd, odd[n]) for n in range(0, 32)]
if len2 & 1:
crc1 = matrix_times(even, crc1)
len2 >>= 1
# if no more bits set, then done
if len2 == 0:
break
# another iteration of the loop with odd and even swapped
odd[:] = [matrix_times(even, even[n]) for n in range(0, 32)]
if len2 & 1:
crc1 = matrix_times(odd, crc1)
len2 >>= 1
# if no more bits set, then done
# return combined crc
crc1 ^= crc2
return crc1