繁体   English   中英

当输入的比特数为奇数(而不是字节)时,生成CRC8 / 16的最佳方法? C或Python

[英]Best way to generate CRC8/16 when input is odd number of BITS (not byte)? C or Python

因此,我坚持使用一种协议,该协议会在奇数位数上添加CRC8 / CRC16。 (即,不能被8整除)在软件中为其生成CRC的最佳方法是什么?

有很多使用表的CRC算法,但是它们是按字节查找的。 当然,有一次“失败保护”的功能。 但是有更好的方法吗? 也许主要通过表查找来完成它,然后一次完成它呢?

我目前在python中使用位数组来处理此问题。 但是用C解决方案也可以。 谢谢!

编辑:请注意,我正在与计算奇数位数CRC的现有硬件接口。 (对于硬件而言,这很容易,因为它们一次只使用LFSR--1位!)因此,为了进行完整性检查而使用已知模式进行填充会起作用,但会破坏硬件兼容性。

前面加零的填充不应更改结果。 计算CRC本质上是二进制长除法。 不幸的是,这涉及拆分每个字节。 使用移位运算符和按位或很容易。

最后,零填充会容易得多,并且根据您计算CRC的原因,这是完全合理的事情。 例如,如果您使用CRC进行完整性检查。

编辑从我的评论中举我的例子。 如果您有11位11101110111并要计算CRC,请填充它们以获得00000111 01110111 = 0x777,请勿填充它们以获得0x7770,因为这将具有不同的CRC。

这样做的原因是CRC本质上是二进制长除法

                    1 0 1 = 5
            -------------
1 0 0 1 1 / 1 1 0 1 1 0 1
            1 0 0 1 1 | |
            --------- | |
              1 0 0 0 0 |
              0 0 0 0 0 |
              --------- |
              1 0 0 0 0 1
                1 0 0 1 1
                ---------
                  1 1 1 0 = 14 = remainder

结果完全相同

                      1 0 1 = 5
            ---------------
1 0 0 1 1 / 0 1 1 0 1 1 0 1
              1 0 0 1 1 | |
              --------- | |
                1 0 0 0 0 |
                0 0 0 0 0 |
                --------- |
                1 0 0 0 0 1
                  1 0 0 1 1
                  ---------
                    1 1 1 0 = 14 = remainder

同样,对于任何数量的前导零。

请注意,在这一点上,除非您是一位精神科医生,正在寻找野外工作,想成为一名,或者暗中想要见一眼,否则可能值得您跳到超级双重秘密试用编辑

进一步的修改由于问题的改变

如果您具有非平凡的初始向量,则可以执行以下操作。 假设我们要使用FFFF的初始化程序来计算上述字符串的CRC-CCITT CRC。 我们填充字符串以获取0x0FFF,并使用初始值设定项0计算CRC-CCIT以获取0x0ECE,然后使用初始值设定项0xFFFF为0x0000计算CRC-CCIT以获取0x1D0F,并对它们进行0x0ECE异或0x1D0F = 0x13C1。

如果多项式是原始的(我认为它们都是),则可以快速计算任意0字符串和非零初始化程序的CRC,但是它变得复杂并且我没有足够的时间。

该技术的本质是我们可以将移位寄存器的状态视为多项式。 如果我们使用n个值对其进行初始化,则与将初始多项式视为p(x)= x ^(n-1)+ x ^(n-2)... + x + 1相同 计算k个零的字符串的CRC等效于找到p(x)x ^ k mod CRC。 通过反复平方和归约很容易发现x ^ k mod CRC。 GF(2)上用于多项式算法的任何库都应执行此操作。

甚至进一步编辑对于非零初始值设定项,用零填充并将初始值设定为一个值,使得在读取| pad |之后,可能更有意义。 移位寄存器包含FFFF的零(或任何您想要的值。这些可以预先计算),您只需要存储16或32(即crc多项式中有多少位)。

例如,对于带有初始化程序0xFFFF和单个位0填充的CRC-CCIT,我们将要使用0xF7EF的初始化程序。 可以通过使用扩展的欧几里得算法找到x ^(-1)mod CRC,然后针对各种填充长度计算初始化器* x ^(-k)mod CRC来计算这些值。 同样,任何GF(2)polynomail软件包都应该使此操作变得容易。 我过去曾经使用过NTL ,发现它相当灵活,但在这里可能会过分杀了。 即使对于32位crcs,令人难以置信的搜索也可能会比编写代码更快地找到初始化程序。

超级双重秘密试用版

好的,事情实际上比我想象的要简单得多。 上面的一般想法是正确的,我们想在字符串的前面加上0,以根据软件实现的需要将大小扩展为8、16或32的倍数,并且我们想更改初始向量来设置声明在读取填充零之后,LFSR将被设置为我们想要的初始向量。 我们当然可以使用galois场算法来做到这一点,但是有一种更简单的方法:只需向后运行LFSR。

例如,如果我们要计算11位11位11101110111的CRC-CCITT(0xFFFF),则用5 0填充它们以得到00000111 01110111,然后将LFSR返回五个空格以得到初始矢量0xF060。 (我已经手工完成了计算,所以要当心)。 因此,如果以0xF060的IV启动LSFR(或软件实现)并在0x0fff上运行,则结果应与在原始11位上以IV 0xFFFF运行LFSR的结果相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM