如何匹配适用于不同数据大小的CRC32算法

huangapple go评论60阅读模式
英文:

How to match CRC32 algorithms working on various data sizes

问题

我有一个设备,它向发送的数据添加CRC32校验和。它是使用查找表计算的,如下所示:

uint32_t CrcFromBuffer(uint8_t* buffer, uint16_t length) {
    uint32_t crc32 = 0xffffffff;

    if (buffer == NULL) {
        return 0;
    } else {
        while (length != 0) {
            uint8_t crc32_table_index = ((uint8_t)(crc32) ^ (*buffer));
            crc32 = crc32 >> 8;
            crc32 = crc32_table[crc32_table_index] ^ crc32;
            buffer++;
            length--;
        }
    }

    return ~crc32;
}

我正在使用STM32F401微控制器,它具有硬件支持,可以使用相同的多项式计算CRC,但只能处理32位输入数据大小。如果数据长度是4字节的倍数,它可以正常工作。这是一个示例:

bool eight_bytes_random_crc() {
    uint8_t array8[8] = {0xAB, 0x21, 0x32, 0x47, 0x01, 0xFF, 0x00, 0x99};
    uint32_t array32[2] = {__RBIT(0x473221AB), __RBIT(0x9900FF01)}; // 需要反转位顺序
    uint32_t hard_crc = __RBIT(~HAL_CRC_Calculate(&hcrc, array32, 2)); // 再次反转位并取反结果
    uint32_t soft_crc = CrcFromBuffer(array8, 8); 
    return hard_crc == soft_crc; 
}

如何使用STM32硬件CRC支持非4字节倍数长度的数据数组?

我尝试通过蛮力搜索一个值,该值会为单字节产生相同的CRC,但在给定0xAB输入的情况下,找不到明显的方法来获得该值:

uint32_t one_byte_crc() {
    uint8_t array8[1] = {0xAB};
    uint32_t soft_crc = CrcFromBuffer(array8, 1); 
    for (uint32_t i = 0; i <= 0xFFFFFFFF; i++ ) {
        uint32_t array32[1] = {__RBIT(i)};
        uint32_t hard_crc = __RBIT(~HAL_CRC_Calculate(&amp;hcrc, array32, 1));
        if (hard_crc == soft_crc) {
            return i; // 得到0xF7D1D97E
        }
    }    
} 

如何在数据数组的长度不是4字节倍数的情况下使用STM32硬件CRC?

英文:

I have a device that adds a CRC32 checksum to data it sends. It is calculated using a lookup table as follows:

uint32_t CrcFromBuffer(uint8_t* buffer, uint16_t lenght) {
	uint32_t crc32 = 0xffffffff;

	if (buffer == NULL) {
		return 0;
	} else {
		while (lenght != 0) {
			uint8_t crc32_table_index = ((uint8_t)(crc32) ^ (*buffer));
			crc32 = crc32 &gt;&gt; 8;
			crc32 = crc32_table[crc32_table_index] ^ crc32;
			buffer++;
			lenght--;
		}
	}

	return ~crc32;
}

I'm using an STM32F401 microcontroller, which has hardware support for calculating CRC with the same polynomial but only with a 32-bit input data size. It works fine if the data length is a multiple of 4 bytes. Here's an example:

bool eight_bytes_random_crc() {
  uint8_t array8[8] = {0xAB, 0x21, 0x32, 0x47, 0x01, 0xFF, 0x00, 0x99};
  uint32_t array32[2] = {__RBIT(0x473221AB), __RBIT(0x9900FF01)}; // need to reverse bit order
  uint32_t hard_crc = __RBIT(~HAL_CRC_Calculate(&amp;hcrc, array32, 2)); // again reverse bits and negate the result
  uint32_t soft_crc = CrcFromBuffer(array8, 8); 
  return hard_crc == soft_crc; 
}

How can I use the STM32 hardware CRC support for data arrays with a length that is not a multiple of 4 bytes?

I tried a brute-force search for a value that would produce the same CRC for a single byte but couldn't find an obvious way to get that value, given only the 0xAB input:

uint32_t one_byte_crc() {
  uint8_t array8[1] = {0xAB};
  uint32_t soft_crc = CrcFromBuffer(array8, 1); 
  for (uint32_t i = 0; i &lt;= 0xFFFFFFFF; i++ ) {
      uint32_t array32[1] = {__RBIT(i)};
      uint32_t hard_crc = __RBIT(~HAL_CRC_Calculate(&amp;hcrc, array32, 1));
      if (hard_crc == soft_crc) {
        return i; // gives 0xF7D1D97E
      }
  }    
} 

Any suggestions on how to use STM32 hardware CRC for non-multiple of 4 byte length data arrays?

答案1

得分: 4

你唯一能做的就是要么a)使用硬件来计算你的数据的CRC直到四字节的倍数,然后使用软件来完成CRC,处理剩下的0到3字节,或者b)使用硬件来计算所有数据的CRC,用零填充到四字节的倍数,然后使用逆CRC表来取消CRC中的最后0到3个零。最高效的可能是如果剩下0或1个字节,就选择a),如果剩下3个字节,就选择b),这样可以取消1个字节的计算。如果剩下2个字节,你会选择更快的方法,但我不确定哪种方法更快。可能两种方法都可以。

英文:

The only thing you can do is either a) use the hardware to calculate the CRC up to a multiple of four bytes of your data, and then use software to finish up the CRC with the last 0 to 3 bytes, or b) use the hardware to calculate the CRC of all of your data padded out to a multiple of four with zeros, and then use a reverse CRC table to un-calculate the last 0 to 3 zeros from the CRC.

The most efficient might be to use a) if there are 0 or 1 bytes left, and b) if there are 3 bytes left, so un-calculating 1 byte. For 2 bytes left, you'd pick the faster one, but I'm not sure which one that would be. Could go either way.

huangapple
  • 本文由 发表于 2023年4月17日 06:11:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76030571.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定