Checksum 和 CRC 的位置不同。为什么?
The difference of location of Checksum and CRC. WHY?
我在研究CRC和校验和的时候遇到了一个问题
CRC位于尾部,校验和位于头部。
我认为是因为 CRC 和校验和的复杂性。
CRC比较复杂,所以定位在header,checksum比较简单,所以定位在tail。
对吗?
这是为什么?
在传输或接收数据的情况下,硬件实现通常在传输数据时生成 CRC 或校验和,然后传输 CRC 或校验和(因此 CRC 或校验和将在数据末尾)。这消除了缓冲比保存 CRC 或校验和和传输单位(例如字节)所需的更多内容的需要。
对于内存中的消息,CRC 奇偶校验字节或校验和可以位于消息中的任何位置。对于校验和,这是直截了当的,但对于 CRC,CRC 必须正常生成,然后向后循环并存储到它在消息中的位置。可以按照我的回答的第二部分所示优化向后循环。
校验和可以在消息中的任何位置,因为计算起来很容易。
Intel hex 格式is/was 一种相当常见的格式,用于在文本文件中存储二进制数据,并且在文本文件的每一行数据结束后都有校验和:
https://en.wikipedia.org/wiki/Intel_HEX#Record_structure
IPv4 header 将校验和放在 message_word[5]:
https://en.wikipedia.org/wiki/IPv4_header_checksum#Calculating_the_IPv4_header_checksum
消息中的任何位置都可以有 CRC 奇偶校验。奇偶校验字节归零,计算正常的 CRC,然后 CRC "reverse cycled" 到将要存储的位置。可以使用无进位乘法而不是实际反转 CRC:
parity = (crc · (pow(2,-1-reverse_distance)%poly))%poly
-1 表示 CRC 的循环周期。对于 CRC32,周期为 2^32-1 = 0xffffffff
具有 14 个数据字节、4 个奇偶校验字节、14 个数据字节的 32 字节消息的示例代码。在消息中存储奇偶校验字节后,对消息进行正常的 CRC 计算将为零。
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
static uint32_t crctbl[256];
void GenTbl(void) /* generate crc table */
{
uint32_t crc;
uint32_t c;
uint32_t i;
for(c = 0; c < 0x100; c++){
crc = c<<24;
for(i = 0; i < 8; i++)
crc = (crc<<1)^((0-(crc>>31))&0x04c11db7);
crctbl[c] = crc;
}
}
uint32_t GenCrc(uint8_t * bfr, size_t size) /* generate crc */
{
uint32_t crc = 0u;
while(size--)
crc = (crc<<8)^crctbl[(crc>>24)^*bfr++];
return(crc);
}
/* carryless multiply modulo crc */
uint32_t MpyModCrc(uint32_t a, uint32_t b) /* (a*b)%crc */
{
uint32_t pd = 0;
uint32_t i;
for(i = 0; i < 32; i++){
pd = (pd<<1)^((0-(pd>>31))&0x04c11db7u);
pd ^= (0-(b>>31))&a;
b <<= 1;
}
return pd;
}
/* exponentiate by repeated squaring modulo crc */
uint32_t PowModCrc(uint32_t p) /* pow(2,p)%crc */
{
uint32_t prd = 0x1u; /* current product */
uint32_t sqr = 0x2u; /* current square */
while(p){
if(p&1)
prd = MpyModCrc(prd, sqr);
sqr = MpyModCrc(sqr, sqr);
p >>= 1;
}
return prd;
}
/* message 14 data, 4 parities, 14 data */
/* parities = crc cycled backwards 18 bytes */
int main()
{
uint32_t pmr;
uint32_t crc;
uint32_t par;
uint8_t msg[32] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x00,0x00,
0x00,0x00,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20};
GenTbl(); /* generate crc table */
pmr = PowModCrc(-1-(18*8)); /* pmr = pow(2,-1-18*8)%crc */
crc = GenCrc(msg, 32); /* generate crc */
par = MpyModCrc(crc, pmr); /* par = (crc*pmr)%crc */
msg[14] = (uint8_t)(par>>24); /* store parities in msg */
msg[15] = (uint8_t)(par>>16);
msg[16] = (uint8_t)(par>> 8);
msg[17] = (uint8_t)(par>> 0);
crc = GenCrc(msg, 32); /* crc == 0 */
printf("%08x\n", crc);
return 0;
}
我在研究CRC和校验和的时候遇到了一个问题
CRC位于尾部,校验和位于头部。 我认为是因为 CRC 和校验和的复杂性。 CRC比较复杂,所以定位在header,checksum比较简单,所以定位在tail。 对吗?
这是为什么?
在传输或接收数据的情况下,硬件实现通常在传输数据时生成 CRC 或校验和,然后传输 CRC 或校验和(因此 CRC 或校验和将在数据末尾)。这消除了缓冲比保存 CRC 或校验和和传输单位(例如字节)所需的更多内容的需要。
对于内存中的消息,CRC 奇偶校验字节或校验和可以位于消息中的任何位置。对于校验和,这是直截了当的,但对于 CRC,CRC 必须正常生成,然后向后循环并存储到它在消息中的位置。可以按照我的回答的第二部分所示优化向后循环。
校验和可以在消息中的任何位置,因为计算起来很容易。
Intel hex 格式is/was 一种相当常见的格式,用于在文本文件中存储二进制数据,并且在文本文件的每一行数据结束后都有校验和:
https://en.wikipedia.org/wiki/Intel_HEX#Record_structure
IPv4 header 将校验和放在 message_word[5]:
https://en.wikipedia.org/wiki/IPv4_header_checksum#Calculating_the_IPv4_header_checksum
消息中的任何位置都可以有 CRC 奇偶校验。奇偶校验字节归零,计算正常的 CRC,然后 CRC "reverse cycled" 到将要存储的位置。可以使用无进位乘法而不是实际反转 CRC:
parity = (crc · (pow(2,-1-reverse_distance)%poly))%poly
-1 表示 CRC 的循环周期。对于 CRC32,周期为 2^32-1 = 0xffffffff
具有 14 个数据字节、4 个奇偶校验字节、14 个数据字节的 32 字节消息的示例代码。在消息中存储奇偶校验字节后,对消息进行正常的 CRC 计算将为零。
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
static uint32_t crctbl[256];
void GenTbl(void) /* generate crc table */
{
uint32_t crc;
uint32_t c;
uint32_t i;
for(c = 0; c < 0x100; c++){
crc = c<<24;
for(i = 0; i < 8; i++)
crc = (crc<<1)^((0-(crc>>31))&0x04c11db7);
crctbl[c] = crc;
}
}
uint32_t GenCrc(uint8_t * bfr, size_t size) /* generate crc */
{
uint32_t crc = 0u;
while(size--)
crc = (crc<<8)^crctbl[(crc>>24)^*bfr++];
return(crc);
}
/* carryless multiply modulo crc */
uint32_t MpyModCrc(uint32_t a, uint32_t b) /* (a*b)%crc */
{
uint32_t pd = 0;
uint32_t i;
for(i = 0; i < 32; i++){
pd = (pd<<1)^((0-(pd>>31))&0x04c11db7u);
pd ^= (0-(b>>31))&a;
b <<= 1;
}
return pd;
}
/* exponentiate by repeated squaring modulo crc */
uint32_t PowModCrc(uint32_t p) /* pow(2,p)%crc */
{
uint32_t prd = 0x1u; /* current product */
uint32_t sqr = 0x2u; /* current square */
while(p){
if(p&1)
prd = MpyModCrc(prd, sqr);
sqr = MpyModCrc(sqr, sqr);
p >>= 1;
}
return prd;
}
/* message 14 data, 4 parities, 14 data */
/* parities = crc cycled backwards 18 bytes */
int main()
{
uint32_t pmr;
uint32_t crc;
uint32_t par;
uint8_t msg[32] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x00,0x00,
0x00,0x00,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20};
GenTbl(); /* generate crc table */
pmr = PowModCrc(-1-(18*8)); /* pmr = pow(2,-1-18*8)%crc */
crc = GenCrc(msg, 32); /* generate crc */
par = MpyModCrc(crc, pmr); /* par = (crc*pmr)%crc */
msg[14] = (uint8_t)(par>>24); /* store parities in msg */
msg[15] = (uint8_t)(par>>16);
msg[16] = (uint8_t)(par>> 8);
msg[17] = (uint8_t)(par>> 0);
crc = GenCrc(msg, 32); /* crc == 0 */
printf("%08x\n", crc);
return 0;
}