一种循环冗余校验算法,它对具有特定非零值的尾随字节数不变



假设我有一个任意的字节块。该块以使用 CRC-16-CCITT 算法计算整个块的 CRC 余数终止,其中余数按大端字节顺序排列。在块和余数之后,有任意数量的零字节,一直持续到字节流的末尾。

这种安排利用了这种CRC算法的某些属性,该属性通常被认为是不受欢迎的:它不区分具有不同数量的尾随零的消息,前提是消息以其余数终止(在我的情况下(。这允许接收方断言数据的正确性,而不管流中的尾随字节数如何。

下面是一个示例:

>>> hex(crc(b'123456789'))                 # Computing the remainder
'0x29b1'
>>> hex(crc(b'123456789x29xb1'))         # Appending the remainder in the big-endian order
'0x0'                                      # If the remainder is correct, the residual value is always zero
>>> hex(crc(b'123456789x29xb1x00x00')) # ...and it is invariant to the number of trailing zeros
'0x0'
>>> hex(crc(b'123456789x29xb1x00x00x00'))
'0x0'

在我的情况下,这是所需的行为。但是,在我的应用程序中,数据是通过使用非归零 (NRZ( 编码的介质交换的:介质层在相同级别的每五个连续数据位之后注入一个填充位,其中填充位的极性与前面的位相反;例如,00000000的值作为000001000传输。位填充是非常不可取的,因为它会增加开销。

为了利用 CRC 算法对尾随数据(用于填充(的不变性,同时避免位填充,我打算在更新 CRC 余数之前用 0x55 或每个数据字节(尽管它可能是任何其他避免填充的位模式(,然后用 0x5555 或最后的余数。

作为参考,这里是标准的CRC-16-CCITT算法,朴素的实现:

def crc16(b):
crc = 0xFFFF
for byte in b:
crc ^= byte << 8
for bit in range(8):
if crc & 0x8000:
crc = ((crc << 1) ^ 0x1021) & 0xFFFF
else:
crc = (crc << 1) & 0xFFFF
return crc

这是我的修改,xors输入和输出与0x55:

def crc16_mod(b):
crc = 0xFFFF
for byte in b:
crc ^= (byte ^ 0x55) << 8
for bit in range(8):
if crc & 0x8000:
crc = ((crc << 1) ^ 0x1021) & 0xFFFF
else:
crc = (crc << 1) & 0xFFFF
return crc ^ 0x5555

一个简单的检查确认修改后的算法的行为符合预期:

>>> print(hex(crc16_mod(b'123456789')))         # New remainder
0x954f
>>> print(hex(crc16_mod(b'123456789x95x4f'))) # Appending the remainder; residual is 0x5555
0x5555
>>> print(hex(crc16_mod(b'123456789x95x4fx55x55x55'))) # Invariant to the number of trailing 0x55
0x5555
>>> print(hex(crc16_mod(b'123456789x95x4fx55x55x55x55'))) # Invariant to the number of trailing 0x55
0x5555

我的问题如下:引入此修改是否损害了算法的错误检测属性?还有其他我应该注意的缺点吗?

在标准的误差模型(以固定概率独立翻转的位(下,没有缺点。很难预见实际困难。

相关内容

  • 没有找到相关文章

最新更新