web-dev-qa-db-ja.com

ライブラリを使用せずにPython)でのCRC32計算

私は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の計算は一致しますが、私の計算は一致しません。ネット上で入手可能な例と比較したので、計算されたバイト表は正しいと思います。したがって、問題は各バイトが計算されるルーチンである必要があります。誰かが私を正しい方向に向けることができますか?

前もって感謝します!

10
Cooper

私はあなたのコードを詳しく調べていないので、エラーの正確な原因を特定することはできませんが、簡単に微調整して目的の出力を得ることができます。

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

微調整されたcrc32binascii.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ビットを選択します。

8
PM 2Ring