Расчет CRC32 в Python без использования библиотек
Я пытался разобраться в расчетах CRC32 без особого успеха, значения, которые я, похоже, получаю, не соответствуют тому, что я должен получить.
Я знаю, что Python имеет библиотеки, которые способны генерировать эти контрольные суммы (а именно zlib и binascii), но у меня нет роскоши иметь возможность использовать их, поскольку функциональность CRC не существует на micropython.
пока у меня есть следующий код:
import binascii
import zlib
from array import array
poly = 0xEDB88320
table = array('L')
for byte in range(256):
crc = 0
for bit in range(8):
if (byte ^ crc) & 1:
crc = (crc >> 1) ^ poly
else:
crc >>= 1
byte >>= 1
table.append(crc)
def crc32(string):
value = 0xffffffffL
for ch in string:
value = table[(ord(ch) ^ value) & 0x000000ffL] ^ (value >> 8)
return value
teststring = "test"
print "binascii calc: 0x%08x" % (binascii.crc32(teststring) & 0xffffffff)
print "zlib calc: 0x%08x" % (zlib.crc32(teststring) & 0xffffffff)
print "my calc: 0x%08x" % (crc32(teststring))
тогда я получаю следующий вывод:
binascii calc: 0xd87f7e0c
zlib calc: 0xd87f7e0c
my calc: 0x2780810c
вычисления binascii и zlib согласуются с тем, где мой нет. Я считаю, что вычисленная таблица байтов верна, поскольку я сравнил ее с примерами, доступными в сети. Таким образом, проблема должна быть рутиной, где каждый байт вычисляется, может ли кто-нибудь указать мне в правильном направлении?
спасибо заранее!
1 ответов
Я не внимательно посмотрел на ваш код, поэтому я не могу точно определить источник ошибки, но вы можете легко настроить его, чтобы получить желаемый результат:
import binascii
from array import array
poly = 0xEDB88320
table = array('L')
for byte in range(256):
crc = 0
for bit in range(8):
if (byte ^ crc) & 1:
crc = (crc >> 1) ^ poly
else:
crc >>= 1
byte >>= 1
table.append(crc)
def crc32(string):
value = 0xffffffffL
for ch in string:
value = table[(ord(ch) ^ value) & 0xff] ^ (value >> 8)
return -1 - value
# test
data = (
'',
'test',
'hello world',
'1234',
'A long string to test CRC32 functions',
)
for s in data:
print repr(s)
a = binascii.crc32(s)
print '%08x' % (a & 0xffffffffL)
b = crc32(s)
print '%08x' % (b & 0xffffffffL)
print
выход
''
00000000
00000000
'test'
d87f7e0c
d87f7e0c
'hello world'
0d4a1185
0d4a1185
'1234'
9be3e0a3
9be3e0a3
'A long string to test CRC32 functions'
d2d10e28
d2d10e28
вот еще несколько тестов, которые подтверждают, что tweaked crc32
дает тот же результат, что и binascii.crc32
.
from random import seed, randrange
print 'Single byte tests...',
for i in range(256):
s = chr(i)
a = binascii.crc32(s) & 0xffffffffL
b = crc32(s) & 0xffffffffL
assert a == b, (repr(s), a, b)
print('ok')
seed(42)
print 'Multi-byte tests...'
for width in range(2, 20):
print 'Width', width
r = range(width)
for n in range(1000):
s = ''.join([chr(randrange(256)) for i in r])
a = binascii.crc32(s) & 0xffffffffL
b = crc32(s) & 0xffffffffL
assert a == b, (repr(s), a, b)
print('ok')
выход
Single byte tests... ok
Multi-byte tests...
Width 2
Width 3
Width 4
Width 5
Width 6
Width 7
Width 8
Width 9
Width 10
Width 11
Width 12
Width 13
Width 14
Width 15
Width 16
Width 17
Width 18
Width 19
ok
как описано в комментариях, источник ошибки в исходном коде этот алгоритм CRC-32 инвертирует исходный буфер crc, а затем инвертирует конечное содержимое буфера. Так что value
инициализируется к 0xffffffff
вместо нуля, и нам нужно вернуться value ^ 0xffffffff
, который также может быть записан как ~value & 0xffffffff
, т. е. инвертировать value
и затем выберите 32 бита низкого порядка результата.