【问题标题】:Fast CRC32 algorithm for reversed bit order用于反转位顺序的快速 CRC32 算法
【发布时间】:2018-08-15 09:08:32
【问题描述】:

我正在使用一个微控制器来计算我上传到它的闪存的数据的 CRC32 校验和。这又可以用来验证上传是否正确,方法是在上传所有数据后验证生成的校验和。

唯一的问题是微控制器在运行其他标准 crc32 计算时会反转输入字节的位顺序。这反过来意味着我需要反转编程主机上数据中的每个字节,以便计算 CRC32 和以进行验证。由于编程主机有些受限,所以速度很慢。

我认为,如果可以修改 CRC32 查找表,这样我就可以在不必颠倒位顺序的情况下进行查找,验证算法的运行速度会快很多倍。但我似乎无法找到一种方法来做到这一点。

为了澄清字节反转,我需要按照以下方式更改输入字节:

01 02 03 04 -> 80 40 C0 20

当然,在二进制表示中看到反转要容易得多:

00000001 00000010 00000011 00000100 -> 10000000 01000000 11000000 00100000

编辑 这是我用来验证 CRC32 计算正确性的 PoC Python 代码,但这会反转每个字节(即慢速方式)。

EDIT2 我还包含了我尝试生成置换查找表并使用标准 LUT CRC32 算法失败的尝试。

代码先吐出正确的参考CRC值,然后再吐出错误的LUT计算出的CRC。

import binascii

CRC32_POLY = 0xEDB88320

def reverse_byte_bits(x):
    '''
    Reverses the bit order of the giveb byte 'x' and returns the result
    '''
    x = ((x<<4) & 0xF0)|((x>>4) & 0x0F)
    x = ((x<<2) & 0xCC)|((x>>2) & 0x33)
    x = ((x<<1) & 0xAA)|((x>>1) & 0x55)
    return x

def reverse_bits(ba, blen):
    '''
    Reverses all bytes in the given array of bytes
    '''
    bar = bytearray()
    for i in range(0, blen):
        bar.append(reverse_byte_bits(ba[i]))
    return bar

def crc32_reverse(ba):
    # Reverse all bits in the
    bar = reverse_bits(ba, len(ba))

    # Calculate the CRC value
    return binascii.crc32(bar)

def gen_crc_table_msb():
    crctable = [0] * 256

    for i in range(0, 256):
        remainder = i
        for bit in range(0, 8):
            if remainder & 0x1:
                remainder = (remainder >> 1) ^ CRC32_POLY
            else:
                remainder = (remainder >> 1)

        # The correct index for the calculated value is the reverse of the index
        ix = reverse_byte_bits(i)
        crctable[ix] = remainder

    return crctable

def crc32_revlut(ba, lut):
    crc = 0xFFFFFFFF
    for x in ba:
        crc = lut[x ^ (crc & 0xFF)] ^ (crc >> 8)
    return ~crc

# Reference test which gives the correct CRC
test = bytearray([1, 2, 3, 4, 5, 6, 7, 8])
crcrev = crc32_reverse(test)
print("0x%08X" % (crcrev & 0xFFFFFFFF))

# Test using permutated lookup table, but standard CRC32 LUT algorithm
lut = gen_crc_table_msb()
crctst = crc32_revlut(test, lut)
print("0x%08X" % (crctst & 0xFFFFFFFF))

有人对如何做到这一点有任何提示吗?

【问题讨论】:

  • 以相反的顺序循环输入字节,并将每个字节作为索引进入一个 256 元素的查找表?
  • 由“非反转”字节索引的表是同一个表,但根据位反转排列进行排列
  • 发布您的代码。这将记录您的问题并帮助我们理解它。
  • 字节以正确的顺序发送到MCU,但计算CRC时需要将每个字节中的位取反。如果可以进一步说明问题,我可以附加“慢代码”。
  • harold:这也是我最初的想法。正常计算 CRC32 查找表,但使用位反转索引对表进行置换。但是,生成的校验和不正确。

标签: algorithm crc32


【解决方案1】:

通过反转crc“流”的逻辑,可以避免主计算中的反转。所以不是crc &gt;&gt; 8,而是crc &lt;&lt; 8,而不是与LUT索引的CRC的底部字节进行异或,我们取顶部。像这样:

def reverse_dword_bits(x):
    '''
    Reverses the bit order of the given dword 'x' and returns the result
    '''
    x = ((x<<16) & 0xFFFF0000)|((x>>16) & 0x0000FFFF)
    x = ((x<<8) & 0xFF00FF00)|((x>>8) & 0x00FF00FF)
    x = ((x<<4) & 0xF0F0F0F0)|((x>>4) & 0x0F0F0F0F)
    x = ((x<<2) & 0xCCCCCCCC)|((x>>2) & 0x33333333)
    x = ((x<<1) & 0xAAAAAAAA)|((x>>1) & 0x55555555)
    return x

def gen_crc_table_msb():
    crctable = [0] * 256

    for i in range(0, 256):
        remainder = i
        for bit in range(0, 8):
            if remainder & 0x1:
                remainder = (remainder >> 1) ^ CRC32_POLY
            else:
                remainder = (remainder >> 1)

        # The correct index for the calculated value is the reverse of the index
        ix = reverse_byte_bits(i)
        crctable[ix] = reverse_dword_bits(remainder)

    return crctable

def crc32_revlut(ba, lut):
    crc = 0xFFFFFFFF
    for x in ba:
        crc = lut[x ^ (crc >> 24)] ^ ((crc << 8) & 0xFFFFFFFF)
    return reverse_dword_bits(~crc)

【讨论】:

  • 哇,好快 :-) 效果很好,非常感谢 :-)
猜你喜欢
  • 2010-12-23
  • 2014-01-28
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 2010-10-06
相关资源
最近更新 更多