Предположим, что многобайтовый блок данных дважды обрабатывается некоторой CRC, один раз без изменений и один раз с одним ошибочным байтом. Можно ли найти ошибочный байт исключительно на основе двух кодов? Обратите внимание, что это не означает, что точная природа ошибки должна быть идентифицирована только ее местоположением, а также ошибка байта не ограничена одним изменением бита, которое может быть исправлено любой CRC.
CRC: найти ошибочный байт
Ответы (1)
Дано: CRC для хороших данных и CRC для данных с одним плохим байтом. Предполагается, что два заданных CRC исправны, поэтому в самих CRC нет ошибок. Xor правильных данных CRC с неверными данными CRC. Рассматривайте это как xoring хороших данных + хороший CRC с неверными данными + плохой CRC, результатом являются данные, состоящие из нулей, за исключением одного плохого байта и соответствующего CRC. Xor также отменяет любое начальное значение CRC или последующее дополнение значения CRC.
Чтобы иметь возможность определить местоположение плохого байта, CRC должен быть уникальным для каждой возможной комбинации местоположения байта и значения байта.
Я обнаружил, что полином CRC32C 0x1edc6f41 создает уникальные CRC для данных от 1 до 190235 байт. Он дает сбой при 190236 байтах данных, так как буфер со всеми нулями, за исключением bfr[0] = 0xfb или bfr[190235] = 0x32, дает один и тот же (неуникальный) CRC = 0x364b1c30 .
Пример кода для определения местоположения с учетом правильной контрольной суммы и плохой контрольной суммы (один неверный байт):
static uint32_t crcrtbl[256];
void genrtbl(void)
{
uint32_t crc;
uint32_t b;
uint32_t c;
uint32_t i;
for(c = 0; c < 0x100; c++){
crc = c;
for(i = 0; i < 8; i++){
b = crc&1;
crc >>= 1;
crc ^= (0 - b) & (0x11edc6f41>>1);
}
crcrtbl[c] = crc;
}
}
size_t crc32r(uint32_t crc, size_t size)
{
while(size--){
crc = (crc >> 8) ^ crcrtbl[crc & 0xff];
if(0 == (crc & 0xffffff))
break;
}
return(size);
}
// ...
genrtbl(); // generate table
// given good_crc and bad_crc, return location
location = crc32r(good_crc ^ bad_crc, size);
код для генерации crc
uint32_t crctbl[256];
void gentbl(void)
{
uint32_t crc;
uint32_t b;
uint32_t c;
uint32_t i;
for(c = 0; c < 0x100; c++){
crc = c<<24;
for(i = 0; i < 8; i++){
b = crc>>31;
crc <<= 1;
crc ^= (0 - b) & 0x1edc6f41; // 32 bit crc
}
crctbl[c] = crc;
}
}
uint32_t crc32(uint32_t crc32, uint8_t * bfr, size_t size)
{
uint32_t crc = crc32;
while(size--)
crc = (crc << 8) ^ crctbl[(crc >> 24)^*bfr++];
return(crc);
}