Jump to content

Вычисление проверок циклическим избыточным кодом

Вычисление проверки циклическим избыточным кодом основано на математическом делении полинома по модулю два . На практике это похоже на длинное деление строки двоичного сообщения с добавленным фиксированным количеством нулей на строку «полинома генератора», за исключением того, что исключающие операции или операции заменяют вычитания. Деление этого типа эффективно реализуется аппаратно с помощью модифицированного сдвигового регистра . [1] и в программном обеспечении с помощью ряда эквивалентных алгоритмов , начиная с простого кода, близкого к математике, и становясь более быстрым (и, возможно, более запутанным). [2] ) посредством побайтового компромисса между пространством и параллелизма и временем .

Пример генерации 8-битной CRC . Генератор представляет собой сдвиговый регистр типа Галуа с логическими элементами XOR, расположенными в соответствии со степенями (белыми числами) x в полиноме генератора. Поток сообщений может быть любой длины. После того, как он был пропущен через регистр, за которым следуют 8 нулей, результатом в регистре является контрольная сумма.
Проверка полученных данных по контрольной сумме. Полученное сообщение сдвигается через тот же регистр, который используется в генераторе, но к нему вместо нулей присоединяется полученная контрольная сумма. Правильные данные дают результат, состоящий из всех нулей; поврежденный бит в сообщении или контрольной сумме даст другой результат, предупреждая о том, что произошла ошибка.

Различные стандарты CRC расширяют алгоритм полиномиального деления, определяя начальное значение регистра сдвига, последний шаг «исключающее ИЛИ» и, что наиболее важно, порядок битов ( порядок байтов ). В результате код, видимый на практике, отклоняется от «чистого» деления. [2] и регистр может сдвигаться влево или вправо.

В качестве примера аппаратной реализации полиномиального деления предположим, что мы пытаемся вычислить 8-битную CRC 8-битного сообщения, состоящего из символа ASCII «W», который является двоичным 01010111 2 , десятичным 87 10 или шестнадцатеричным 57. 16 . Для иллюстрации мы будем использовать полином CRC-8-ATM ( HEC ). . Запись первого переданного бита (коэффициент старшей степени ) слева это соответствует 9-битной строке «100000111».

Значение байта 57 16 может передаваться в двух разных порядках, в зависимости от используемого соглашения о порядке битов. Каждый из них генерирует свой полином сообщения. . Msbit-во-первых, это = 01010111, а lsbit-first, это = 11101010. Затем их можно умножить на создать два 16-битных полинома сообщения .

Тогда вычисление остатка состоит из вычитания кратных полинома генератора. . Это похоже на деление десятичной дроби, но даже проще, поскольку на каждом шаге единственными возможными кратными являются 0 и 1, а вычитания заимствуются «из бесконечности», а не уменьшают старшие цифры. Поскольку нас не волнует частное, нет необходимости его записывать.

Самый значимый бит первый Младший бит первым
0 1 0 1 0 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
= 0 1 0 1 0 1 1 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
= 0 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 0 0 0 0 1 1 0 1 0 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0
= 0 0 0 0 0 1 1 0 1 0 1 1 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 0 0 0 0 0 1 0 1 0 1 0 1 1 0 0
1 0 0 0 0 0 1 1 1
= 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0
0 0 0 0 0 0 0 0 0
= 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0
1 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 1 1 0 1 0 0 1 1 0 0 0 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0
= 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0
1 0 0 0 0 0 1 1 1
= 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0
= 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0
= 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0
= 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0

Обратите внимание, что после каждого вычитания биты делятся на три группы: вначале группа, состоящая только из нулей; в конце группа, не отличающаяся от оригинала; и группа с синей заливкой посередине, что «интересно». «Интересная» группа имеет длину 8 бит, что соответствует степени полинома. На каждом шаге соответствующее кратное многочлена вычитается, чтобы сделать нулевую группу на один бит длиннее, а неизмененная группа становится на один бит короче, пока не останется только последний остаток.

В примере msbit-first полином остатка равен . Преобразование в шестнадцатеричное число с использованием соглашения, согласно которому наивысшая степень x равна мсбиту; это А2 16 . В lsbit-first остаток равен . Преобразование в шестнадцатеричный формат с использованием соглашения о том, что наивысшая степень x — это lsbit, это 19 16 .

Выполнение

[ редактировать ]

Записывать полное сообщение на каждом этапе, как это сделано в примере выше, очень утомительно. Эффективные реализациииспользовать -битовый сдвиговый регистр для хранения только интересных битов. Умножив полином на эквивалентно сдвигу регистра на одну позицию, поскольку коэффициенты не изменяются по значению, а лишь перемещаются к следующему члену многочлена.

Вот первый вариант псевдокода для вычисления n -битной CRC. Он использует надуманный составной тип данных для полиномов, где x — это не целочисленная переменная, а конструктор, генерирующий полиномиальный объект , который можно складывать, умножать и возводить в степень. К xor двух многочленов – это сложить их по модулю два; то есть исключающее ИЛИ коэффициенты каждого совпадающего термина из обоих полиномов.

function crc(bit array bitString[1..len], int len) {    remainderPolynomial := polynomialForm(bitString[1..n])   // First n bits of the message    // A popular variant complements remainderPolynomial here; see § Preset to −1 below    for i from 1 to len {        remainderPolynomial := remainderPolynomial * x + bitString[i+n] * x0   // Define bitString[k]=0 for k>len        if coefficient of xn of remainderPolynomial = 1 {            remainderPolynomial := remainderPolynomial xor generatorPolynomial        }    }    // A popular variant complements remainderPolynomial here; see § Post-invert below    return remainderPolynomial}
Фрагмент кода 1: Простое полиномиальное деление

Обратите внимание, что в этом примере кода не требуется указывать соглашение о порядке битов, поскольку не используются байты; вход bitString уже находится в виде битового массива, а remainderPolynomial манипулируется с помощью полиномиальных операций; умножение на может быть сдвигом влево или вправо, а также добавлением bitString[i+n] делается для коэффициент, который может быть правым или левым концом регистра.

Этот код имеет два недостатка. Во-первых, на самом деле требуется n +1-битный регистр для хранения remainderPolynomial так что коэффициент можно проверить. Что еще более важно, это требует bitString быть дополнено n нулевыми битами.

Первую проблему можно решить, протестировав коэффициент remainderPolynomial прежде чем оно будет умножено на .

Вторую проблему можно было бы решить, выполнив последние n итераций иначе, но существует более тонкая оптимизация, которая используется повсеместно как в аппаратных, так и в программных реализациях.

Поскольку операция XOR, используемая для вычитания полинома генератора из сообщения, является коммутативной и ассоциативной , не имеет значения, в каком порядке различные входные данные объединяются в remainderPolynomial. И, в частности, определенный фрагмент bitString не нужно добавлять в remainderPolynomial до самого последнего момента, когда он проверяется, стоит ли xor с generatorPolynomial.

Это устраняет необходимость предварительной загрузки remainderPolynomial также с первыми n битами сообщения:

function crc(bit array bitString[1..len], int len) {    remainderPolynomial := 0    // A popular variant complements remainderPolynomial here; see § Preset to −1 below    for i from 1 to len {        remainderPolynomial := remainderPolynomial xor (bitstring[i] * xn−1)        if (coefficient of xn−1 of remainderPolynomial) = 1 {            remainderPolynomial := (remainderPolynomial * x) xor generatorPolynomial        } else {            remainderPolynomial := (remainderPolynomial * x)        }    }    // A popular variant complements remainderPolynomial here; see § Post-invert below    return remainderPolynomial}
Фрагмент кода 2: Полиномиальное деление с отложенным XOR-сообщением

Это стандартная побитовая аппаратная реализация CRC, достойная изучения; как только вы поймете, почему это вычисляет точно такой же результат, как и первая версия, остальные оптимизации станут довольно простыми. Если remainderPolynomial имеет длину всего n бит, то коэффициенты его и generatorPolynomial просто отбрасываются. По этой причине вы обычно увидите полиномы CRC, записанные в двоичном формате с опущенным старшим коэффициентом.

В программном обеспечении удобно отметить, что, хотя можно и отложить xor каждого бита до самого последнего момента, можно сделать это и раньше. Обычно удобно выполнять xor побайтно : , даже в такой побитовой реализации

function crc(byte array string[1..len], int len) {    remainderPolynomial := 0    // A popular variant complements remainderPolynomial here; see § Preset to −1 below    for i from 1 to len {        remainderPolynomial := remainderPolynomial xor polynomialForm(string[i]) * xn−8        for j from 1 to 8 {    // Assuming 8 bits per byte            if coefficient of xn−1 of remainderPolynomial = 1 {                remainderPolynomial := (remainderPolynomial * x) xor generatorPolynomial            } else {                remainderPolynomial := (remainderPolynomial * x)            }        }    }    // A popular variant complements remainderPolynomial here; see § Post-invert below    return remainderPolynomial}
Фрагмент кода 3: Полиномиальное деление с побайтовым исключающим ИЛИ сообщений

Обычно это самая компактная программная реализация, используемая в микроконтроллерах , когда пространство важнее скорости.

Порядок битов (endianness)

[ редактировать ]

При реализации в с последовательным битом аппаратном обеспечении полином генератора однозначно описывает назначение битов; первый передаваемый бит всегда является коэффициентом высшей степени и последний передаваемые биты представляют собой остаток CRC , начиная с коэффициента и заканчивая коэффициентом , он же коэффициент 1.

Однако, когда биты обрабатываются побайтно , например, при использовании параллельной передачи , кадрировании байтов, как при кодировании 8B/10B или RS-232 в стиле асинхронной последовательной связи , или при реализации CRC в программном обеспечении , необходимо указать порядок битов (порядок байтов) данных; какой бит в каждом байте считается «первым» и будет коэффициентом высшей степени .

Если данные предназначены для последовательной связи , лучше всего использовать порядок битов, в котором данные будут в конечном итоге отправлены. Это связано с тем, что способность CRC обнаруживать пакетные ошибки основана на близости полинома сообщения. ; если соседние полиномиальные члены не передаются последовательно, пакет физических ошибок одной длины может рассматриваться как более длинный пакет из-за перестановки битов.

Например, стандарты IEEE 802 ( Ethernet ) и RS-232 ( последовательный порт ) определяют передачу сначала младшего значащего бита (с прямым порядком байтов), поэтому программная реализация CRC для защиты данных, передаваемых по такому каналу, должна отображать младшие биты. в каждом байте к коэффициентам высших степеней . С другой стороны, дискеты и большинство жестких дисков сначала записывают старший бит каждого байта.

CRC lsbit-first немного проще реализовать в программном обеспечении, поэтому он встречается несколько чаще, но многие программисты находят, что порядок битов msbit-first легче соблюдать. Так, например, расширение XMODEM -CRC, раннее использование CRC в программном обеспечении, использует CRC с приоритетом мсбита.

До сих пор псевдокод избегал указания порядка битов внутри байтов, описывая сдвиги в псевдокоде как умножения на и написание явных преобразований из двоичной формы в полиномиальную. На практике CRC хранится в стандартном двоичном регистре с использованием определенного соглашения о порядке битов. В форме «сначала msbit» наиболее значимые двоичные биты будут отправлены первыми и, таким образом, содержат полиномиальные коэффициенты более высокого порядка, тогда как в форме «сначала lsbit» младшие двоичные биты содержат коэффициенты более высокого порядка. Приведенный выше псевдокод можно записать в обеих формах. Для конкретности здесь используется 16-битный CRC-16- CCITT. полином :

// Most significant bit first (big-endian)// (x16)+x12+x5+1 = (1) 0001 0000 0010 0001 = 0x1021function crc(byte array string[1..len], int len) {    rem := 0    // A popular variant complements rem here    for i from 1 to len {        rem  := rem xor (string[i] leftShift (n-8))   // n = 16 in this example        for j from 1 to 8 {       // Assuming 8 bits per byte            if rem and 0x8000 {   // Test x15 coefficient                rem  := (rem leftShift 1) xor 0x1021            } else {                rem  := rem leftShift 1            }            rem  := rem and 0xffff      // Trim remainder to 16 bits        }    }    // A popular variant complements rem here    return rem}
Фрагмент кода 4: Деление на основе сдвигового регистра, сначала старший бит.
// Least significant bit first (little-endian)// 1+x5+x12+(x16) = 1000 0100 0000 1000 (1) = 0x8408function crc(byte array string[1..len], int len) {    rem  := 0    // A popular variant complements rem here    for i from 1 to len {        rem  := rem xor string[i]        for j from 1 to 8 {       // Assuming 8 bits per byte            if rem and 0x0001 {   // Test x15 coefficient                rem  := (rem rightShift 1) xor 0x8408            } else {                rem  := rem rightShift 1            }        }    }    // A popular variant complements rem here    return rem}
Фрагмент кода 5: Деление на основе сдвигового регистра, сначала младший бит.

Обратите внимание, что форма lsbit-first позволяет избежать необходимости сдвига string[i] перед xor. В любом случае обязательно передавайте байты CRC в том порядке, который соответствует выбранному вами соглашению о порядке битов.

Многобитные вычисления

[ редактировать ]

Алгоритм Сарвате (одна таблица поиска)

[ редактировать ]

Другая распространенная оптимизация использует справочную таблицу, индексированную коэффициентами высшего порядка rem обрабатывать более одного бита дивиденда за итерацию. [3] Чаще всего используется таблица поиска из 256 записей, заменяющая тело внешнего цикла (через i) с:

// Msbit-firstrem = (rem leftShift 8) xor big_endian_table[string[i] xor ((leftmost 8 bits of rem) rightShift (n-8))]// Lsbit-firstrem = (rem rightShift 8) xor little_endian_table[string[i] xor (rightmost 8 bits of rem)]
Фрагмент кода 6: Ядра табличного деления

Один из наиболее часто встречающихся алгоритмов CRC известен как CRC-32 , используемый (среди прочих) Ethernet , FDDI , ZIP и другими форматами архивов , а также PNG форматом изображений . Его полином может быть записан с приоритетом msbit как 0x04C11DB7 или lsbit-first как 0xEDB88320. Веб-страница W3C в формате PNG включает приложение с короткой и простой табличной реализацией CRC-32 на языке C. [4] Вы заметите, что код соответствует представленному здесь псевдокоду lsbit-first побайтно, а таблица генерируется с использованием побитового кода.

Использование таблицы на 256 записей обычно наиболее удобно, но можно использовать и другие размеры. В небольших микроконтроллерах использование таблицы из 16 записей для одновременной обработки четырех бит дает существенное повышение скорости, сохраняя при этом размер таблицы. На компьютерах с достаточным объемом памяти таблица из 65 536 записей может использоваться для обработки 16 бит за раз.

Создание таблиц

[ редактировать ]

Программное обеспечение для создания таблиц настолько маленькое и быстрое, что обычно быстрее вычислить их при запуске программы, чем загружать предварительно рассчитанные таблицы из хранилища. Одним из популярных методов является использование побитового кода 256 раз для генерации CRC 256 возможных 8-битных байтов. Однако это можно существенно оптимизировать, воспользовавшись свойством, которое table[i xor j] == table[i] xor table[j]. Непосредственно вычисляются только записи таблицы, соответствующие степеням двойки.

В следующем примере кода crc имеет значение table[i]:

big_endian_table[0] := 0crc := 0x8000 // Assuming a 16-bit polynomiali := 1do {    if crc and 0x8000 {        crc := (crc leftShift 1) xor 0x1021 // The CRC polynomial    } else {        crc := crc leftShift 1    }    // crc is the value of big_endian_table[i]; let j iterate over the already-initialized entries    for j from 0 to i−1 {        big_endian_table[i + j] := crc xor big_endian_table[j];    }    i := i leftshift 1} while i < 256
Фрагмент кода 7: Побайтовая генерация таблицы CRC, сначала старший бит.
little_endian_table[0] := 0crc := 1;i := 128do {    if crc and 1 {        crc := (crc rightShift 1) xor 0x8408 // The CRC polynomial    } else {        crc := crc rightShift 1    }    // crc is the value of little_endian_table[i]; let j iterate over the already-initialized entries    for j from 0 to 255 by 2 × i {        little_endian_table[i + j] := crc xor little_endian_table[j];    }    i := i rightshift 1} while i > 0
Фрагмент кода 8: Побайтовая генерация таблицы CRC, сначала младший бит.

В этих примерах кода индекс таблицы i + j эквивалентно i xor j; вы можете использовать любую форму, которая вам удобнее.

Алгоритм CRC-32

[ редактировать ]

Это практический алгоритм для варианта CRC-32. [5] CRCTable — это мемоизация вычислений, которые необходимо будет повторять для каждого байта сообщения ( Вычисление проверок циклическим избыточным кодом § Многобитовые вычисления ).

Function CRC32   Input:      data:  Bytes     // Array of bytes   Output:      crc32: UInt32    // 32-bit unsigned CRC-32 value
// Initialize CRC-32 to starting valuecrc32 ← 0xFFFFFFFF
for each byte in data do nLookupIndex ← (crc32 xor byte) and 0xFF crc32 ← (crc32 shr 8) xor CRCTable[nLookupIndex] // CRCTable is an array of 256 32-bit constants
// Finalize the CRC-32 value by inverting all the bitscrc32 ← crc32 xor 0xFFFFFFFFreturn crc32


В C алгоритм выглядит так:

#include <inttypes.h> // uint32_t, uint8_tuint32_t CRC32(const uint8_t data[], size_t data_length) {	uint32_t crc32 = 0xFFFFFFFFu;		for (size_t i = 0; i < data_length; i++) {		const uint32_t lookupIndex = (crc32 ^ data[i]) & 0xff;		crc32 = (crc32 >> 8) ^ CRCTable[lookupIndex];  // CRCTable is an array of 256 32-bit constants	}		// Finalize the CRC-32 value by inverting all the bits	crc32 ^= 0xFFFFFFFFu;	return crc32;}

Нарезка байтов с использованием нескольких таблиц

[ редактировать ]

Существует алгоритм среза на n (обычно срез на 8 для CRC32), который обычно удваивает или утраивает производительность по сравнению с алгоритмом Сарвате. Вместо чтения по 8 бит за раз алгоритм читает 8 n бит за раз. Это максимизирует производительность суперскалярных процессоров. [6] [7] [8] [9]

Неясно, кто на самом деле изобрел алгоритм. [10]

Чтобы понять преимущества, начните со случая среза на 2. Мы хотим вычислить CRC по 2 байта (16 бит) за раз, но стандартный табличный подход потребует неудобно большой таблицы из 65536 записей. Как упоминалось в разделе «Генерация таблиц» , таблицы CRC обладают свойством, которое table[i xor j] = table[i] xor table[j]. Мы можем использовать этот идентификатор, чтобы заменить большую таблицу двумя таблицами по 256 записей: table[i + 256×j] = table_low[i] xor table_high[j].

Таким образом, большая таблица не сохраняется явно, но на каждой итерации вычисляется значение CRC, которое будет там, путем объединения значений в двух меньших таблицах. То есть 16-битный индекс «разрезается» на два 8-битных индекса. На первый взгляд это кажется бессмысленным; зачем выполнять два поиска в отдельных таблицах, если стандартный побайтовый алгоритм выполняет два поиска в одной и той же таблице?

Разница заключается в параллелизме на уровне инструкций . В стандартном алгоритме индекс для каждого поиска зависит от значения, полученного в предыдущем. Таким образом, второй поиск не может начаться, пока не завершится первый поиск.

При использовании срезированных таблиц оба поиска могут начинаться одновременно. Если процессор сможет выполнять две нагрузки параллельно (микропроцессоры 2020-х годов могут отслеживать более 100 выполняемых загрузок), то это потенциально может удвоить скорость внутреннего цикла.

Очевидно, что этот метод можно распространить на столько срезов, сколько процессор может извлечь из этого выгоду.

Когда ширина среза равна размеру CRC, происходит незначительное ускорение. В той части базового алгоритма Сарвате, где предыдущее значение CRC сдвигается на размер поиска в таблице, предыдущее значение CRC полностью смещается (все, что остается, — это ноль), поэтому XOR можно исключить из критического пути.

Результирующий внутренний цикл среза на n состоит из:

  1. XOR текущая CRC со следующими n байтами сообщения,
  2. найдите каждый байт результирующего значения в n таблицах срезов, затем
  3. XOR n результатов, чтобы получить следующий CRC.

Это по-прежнему имеет то свойство, что все загрузки на втором этапе должны быть завершены до начала следующей итерации, что приводит к регулярным паузам, во время которых подсистема памяти процессора (в частности, кэш данных) не используется. Однако когда ширина среза превышает размер CRC, появляется значительное второе ускорение.

Это связано с тем, что часть результатов первого шага больше не зависит от какой-либо предыдущей итерации. При выполнении XOR 32-битной CRC с 64-битным сообщением половина результата представляет собой просто копию сообщения. При тщательном кодировании (во избежание создания ложной зависимости данных ) половина загрузки таблицы срезов может начаться до завершения предыдущей итерации цикла. занятость подсистемы памяти процессора В результате получается достаточно работы, чтобы поддерживать постоянную , что обеспечивает максимальную производительность. Как уже упоминалось, в микропроцессорах, выпущенных после 2000 года, для достижения этого уровня обычно достаточно среза на 8.

Нет особой необходимости в том, чтобы срезы имели ширину 8 бит. Например, было бы вполне возможно вычислить CRC по 64 бита за раз, используя алгоритм среза по 9, используя 9 справочных таблиц по 128 записей для обработки 63 битов, а 64-й бит обрабатывается побитовым алгоритмом. -временной алгоритм (который фактически представляет собой 1-битную справочную таблицу с 2 записями). Это почти вдвое уменьшит размер таблицы (с 8×256 = 2048 записей до 9×128 = 1152) за счет еще одной загрузки, зависящей от данных, на итерацию.

Параллельные вычисления без таблицы

[ редактировать ]

Параллельное обновление побайта или слова также можно выполнить явно, без таблицы. [11] Обычно это используется в высокоскоростных аппаратных реализациях. Для каждого бита уравнение решается после сдвига 8 бит. В следующих таблицах перечислены уравнения для некоторых часто используемых полиномов с использованием следующих символов:

cТам Бит CRC 7…0 (или 15…0) перед обновлением
р я Бит CRC 7…0 (или 15…0) после обновления
dИз бит входных данных 7…0
и я = d я + c я e p = e 7 + e 6 + … + e 1 + e 0 (parity bit)
s я = d я + c я+8 s p = s 7 + s 6 + … + s 1 + s 0 (бит четности)
Уравнения побитового обновления для некоторых полиномов CRC-8 после сдвига 8 бит
Полином: ( х 7 + х 3 + 1) × x (CRC-7-CCITT со сдвигом влево) х 8 + х 5 + х 4 + 1 (CRC-8-Даллас/Максим)
Коэффициенты: 0x12 = (0x09 << 1) ( MSBF /нормальный) 0x8c ( LSBF /обратный)
r0  ←r1  ←r2  ←r3  ←r4  ←r5  ←r6  ←r7 
0e0 + e4 + e7e1 + e5e2 + e6e3 + e7      + e0 + e4 + e7e4           + e1 + e5e5           + e2 + e6e6           + e3 + e7
e0           + e4 + e1 + e0        + e5 + e2 + e1e1           + e5 + e2 + e1        + e6 + e3 + e2 + e0e2           + e6 + e3 + e2 + e0   + e7 + e4 + e3 + e1e3 + e0      + e7 + e4 + e3 + e1e4 + e1 + e0e5 + e2 + e1e6 + e3 + e2 + e0e7 + e4 + e3 + e1
C-код
фрагменты:
 uint8_t c, d, e, f, r;  e = c ^ d; f = e ^ (e >> 4) ^ (e >> 7); r =     (f << 1) ^ (f << 4);
 uint8_t c, d, e, f, r;  e = c ^ d; f = e ^ (e << 3) ^ (e << 4) ^ (e << 6); r = f ^ (f >> 4) ^ (f >> 5);
Уравнения побитового обновления для некоторых полиномов CRC-16 после сдвига 8 бит
Полином: х 16 + х 12 + х 5 + 1 (CRC-16-CCITT) х 16 + х 15 + х 2 +1 (CRC-16-ANSI)
Коэффициенты: 0x1021 (MSBF/нормальный) 0x8408 (LSBF/реверс) 0x8005 (MSBF/нормальный) 0xa001 (LSBF/реверс)
r0  ←r1  ←r2  ←r3  ←r4  ←r5  ←r6  ←r7  ←r8  ←r9  ←r10 ←r11 ←r12 ←r13 ←r14 ←r15
s4 + s0s5 + s1s6 + s2s7 + s3     s4     s5  + s4 + s0     s6  + s5 + s1     s7  + s6 + s2c0       + s7 + s3c1            + s4c2            + s5c3            + s6c4            + s7  + s4 + s0c5                  + s5 + s1c6                  + s6 + s2c7                  + s7 + s3
c8             + e4 + e0c9             + e5 + e1c10            + e6 + e2c11      + e0  + e7 + e3c12      + e1c13      + e2c14      + e3c15      + e4 + e0     e0  + e5 + e1     e1  + e6 + e2     e2  + e7 + e3     e3     e4 + e0     e5 + e1     e6 + e2     e7 + e3
          sp          s0 + sp          s1 + s0          s2 + s1          s3 + s2          s4 + s3          s5 + s4          s6 + s5c0      + s7 + s6c1           + s7c2c3c4c5c6c7 + sp
c8            + epc9 c10c11c12c13c14 + e0c15 + e1 + e0      e2 + e1      e3 + e2      e4 + e3      e5 + e4      e6 + e5      e7 + e6      ep + e7           ep
C-код
фрагменты:
 uint8_t  d, s, t; uint16_t c, r;  s = d ^ (c >> 8); t = s ^ (s >> 4); r = (c << 8) ^      t       ^     (t << 5) ^     (t << 12);
 uint8_t  d, e, f; uint16_t c, r;  e = c ^ d; f = e ^ (e << 4); r = (c >> 8) ^     (f << 8) ^     (f << 3) ^     (f >> 4);
 uint8_t  d, s, p; uint16_t c, r, t;  s = d ^ (c >> 8); p = s ^ (s >> 4); p = p ^ (p >> 2); p = p ^ (p >> 1); p = p & 1; t = p | (s << 1); r = (c << 8)  ^     (t << 15) ^      t        ^     (t << 1);
 uint8_t  d, e, p; uint16_t c, r, f;  e = c ^ d; p = e ^ (e >> 4); p = p ^ (p >> 2); p = p ^ (p >> 1); p = p & 1; f = e | (p << 8); r = (c >> 8) ^     (f << 6) ^     (f << 7) ^     (f >> 8);

Двухэтапное вычисление

[ редактировать ]

Поскольку полином CRC-32 имеет большое количество членов, при вычислении остатка побайтно каждый бит зависит от 8 бит предыдущей итерации. В аппаратных реализациях с байтовым параллелизмом это требует использования либо 8-входовых, либо каскадных вентилей XOR, что увеличивает задержку распространения .

Чтобы максимизировать скорость вычислений, промежуточный остаток можно вычислить, сначала вычислив CRC сообщения по модулю x. 123 + х 111 + х 92 + х 84 + х 64 + х 46 + х 23 + 1. Это тщательно выбранное кратное полиному CRC-32, такое, что члены (отводы обратной связи) находятся на расстоянии не менее 8 позиций друг от друга. Таким образом, 123-битный сдвиговый регистр можно расширить на 8 бит за итерацию, используя только двухвходовые логические элементы XOR, что является максимально быстрым. Наконец, промежуточный остаток можно уменьшить по модулю стандартного полинома во втором сдвиговом регистре, чтобы получить остаток CRC-32. [12]

Если разрешены вентили XOR с 3 или 4 входами, можно использовать более короткие промежуточные полиномы степени 71 или 53 соответственно.

Блочные вычисления

[ редактировать ]

Блочное вычисление остатка может быть выполнено аппаратно для любого полинома CRC путем факторизации матрицы преобразования пространства состояний, необходимой для вычисления остатка, на две более простые матрицы Теплица. [13]

Однопроходная проверка

[ редактировать ]

При добавлении CRC к сообщению можно отделить переданный CRC, пересчитать его и сверить перевычисленное значение с переданным. Однако обычно используется более простой метод.используется в аппаратном обеспечении.

Когда CRC передается с правильным порядком байтов (соответствующим выбранному соглашению о порядке битов), получатель может вычислить общий CRC для сообщения и CRC, и если они верны, результат будет нулевым. [14] Эта возможность является причиной того, что большинство сетевых протоколов, включающих CRC, делают это перед конечным разделителем; для проверки CRC не обязательно знать, близок ли конец пакета.

Фактически, некоторые протоколы используют CRC в качестве разделителя сообщений — метод, называемый кадрированием на основе CRC . (Для этого требуется несколько кадров для обнаружения захвата или потери кадра, поэтому он ограничен приложениями, в которых кадры имеют известную длину, а содержимое кадра достаточно случайно, поэтому действительные CRC в невыровненных данных встречаются редко.)

Варианты CRC

[ редактировать ]

На практике большинство стандартов предписывают установку регистра на все единицы и инвертирование CRC перед передачей. Это не влияет на способность CRC обнаруживать измененные биты, но дает возможность замечать биты, добавленные к сообщению.

Предустановлено на −1

[ редактировать ]

Базовая математика CRC принимает (считает правильно переданными) сообщения, которые при интерпретации как полином кратны полиному CRC. Если к такому сообщению добавляются несколько ведущих нулевых битов, они не изменят его интерпретацию как полинома. Это эквивалентно тому, что 0001 и 1 — одно и то же число.

Но если передаваемое сообщение заботится о ведущих нулевых битах, неспособность базового алгоритма CRC обнаружить такое изменение нежелательна. Если возможно, что ошибка передачи может добавить такие биты, простым решением будет начать с rem регистр сдвига установлен на некоторое ненулевое значение; для удобства обычно используется значение «все единицы». Это математически эквивалентно дополнению (двоичное НЕ) первых n бит сообщения, где n — количество битов в регистре CRC.

Это никак не влияет на генерацию и проверку CRC, если и генератор, и программа проверки используют одно и то же начальное значение. Подойдет любое ненулевое начальное значение, а в некоторых стандартах указаны необычные значения. [15] но значение «все единицы» (-1 в двоичном дополнении) является, безусловно, наиболее распространенным. Обратите внимание, что однопроходная генерация/проверка CRC по-прежнему будет давать нулевой результат, если сообщение правильное, независимо от заданного значения.

Пост-инверт

[ редактировать ]

Такая же ошибка может возникнуть в конце сообщения, хотя и с более ограниченным набором сообщений. Добавление 0 битов к сообщению эквивалентно умножению его полинома на x , и если ранее он был кратен полиному CRC, результат этого умножения также будет кратным. Это эквивалентно тому, что, поскольку 726 кратно 11, то и 7260 кратно.

Аналогичное решение можно применить в конце сообщения, инвертируя регистр CRC перед его добавлением к сообщению. Опять же, подойдет любое ненулевое изменение; инвертирование всех битов (исключающее ИЛИ с шаблоном «все единицы») является наиболее распространенным.

Это влияет на однопроходную проверку CRC: вместо нулевого результата, когда сообщение корректно, он выдает фиксированный ненулевой результат. (Если быть точным, результатом является CRC с нулевой предустановкой, но с пост-инвертированием шаблона инверсии.) Как только эта константа получена (например, путем выполнения однопроходной генерации/проверки CRC для произвольного сообщения), его можно использовать непосредственно для проверки правильности любого другого сообщения, проверенного с использованием того же алгоритма CRC.

См. также

[ редактировать ]

Общая категория

Контрольные суммы без CRC

  1. ^ Дуброва, Елена; Мансури, Шоре Шариф (май 2012 г.). «Подход на основе BDD к построению LFSRS для параллельного кодирования CRC» . 42-й международный симпозиум IEEE по многозначной логике , 2012 г. стр. 128–133. дои : 10.1109/ISMVL.2012.20 . ISBN  978-0-7695-4673-5 . S2CID   27306826 .
  2. ^ Перейти обратно: а б Уильямс, Росс Н. (24 сентября 1996 г.). «Безболезненное руководство по алгоритмам обнаружения ошибок CRC V3.00» . Архивировано из оригинала 27 сентября 2006 г. Проверено 16 февраля 2016 г.
  3. ^ Сарвате, Дилип В. (август 1998 г.). «Вычисление проверок циклическим избыточным кодом посредством поиска в таблице» . Коммуникации АКМ . 31 (8): 1008–1013. дои : 10.1145/63030.63037 . S2CID   5363350 .
  4. ^ «Спецификация портативной сетевой графики (PNG) (второе издание): Приложение D, Пример реализации кода циклической избыточности» . W3C . 10 ноября 2003 г. Проверено 16 февраля 2016 г.
  5. ^ «[MS-ABS]: 32-битный алгоритм CRC» . msdn.microsoft.com . Архивировано из оригинала 7 ноября 2017 года . Проверено 4 ноября 2017 г.
  6. ^ Кунавис, Мэн; Берри, Флорида (2005). «Систематический подход к созданию высокопроизводительных программных генераторов CRC». 10-й симпозиум IEEE по компьютерам и коммуникациям (ISCC'05) (PDF) . стр. 855–862. дои : 10.1109/ISCC.2005.18 . ISBN  0-7695-2373-0 . S2CID   10308354 .
  7. ^ Берри, Фрэнк Л.; Кунавис, Майкл Э. (ноябрь 2008 г.). «Новые алгоритмы поиска по таблицам для высокопроизводительной генерации CRC». Транзакции IEEE на компьютерах . 57 (11): 1550–1560. дои : 10.1109/TC.2008.85 . S2CID   206624854 .
  8. ^ Генерация высокооктанового CRC с помощью алгоритма Intel Slicing-by-8 (PDF) (Технический отчет). Интел . Архивировано из оригинала (PDF) 22 июля 2012 г.
  9. ^ «Краткое руководство по вычислению CRC» . Архивы ядра Linux .
  10. ^ Менон-Сен, Абхиджит (20 января 2017 г.). «Кто изобрел алгоритм нарезки по N CRC32?» .
  11. ^ Джон Буллер (15 марта 1996 г.). «Re: 8051 и CRC-CCITT» . Группа новостей : comp.arch.embedded . Usenet:   [электронная почта защищена] . Проверено 16 февраля 2016 г.
  12. ^ Глез, Рене Ж. (20 января 1997 г.). «Двухэтапное вычисление циклического избыточного кода CRC-32 для сетей ATM» . Журнал исследований и разработок IBM . 41 (6). Армонк, Нью-Йорк : IBM : 705. doi : 10.1147/rd.416.0705 . Архивировано из оригинала 30 января 2009 г. Проверено 16 февраля 2016 г.
  13. ^ Дас, Ариндам (2022). «Блочное вычисление циклического избыточного кода с использованием факторизованных матриц Теплица вместо справочной таблицы» . Транзакции IEEE на компьютерах . 72 (4): 1110–1121. дои : 10.1109/TC.2022.3189574 . ISSN   0018-9340 . S2CID   250472783 .
  14. ^ Кадач, Эндрю; Дженкинс, Боб (3 сентября 2010 г.). Все, что мы знаем о CRC, но боимся забыть (PDF) (Технический отчет). п. 4. Тот факт, что CRC сообщения, за которым следует его CRC, является постоянной величиной, которая не зависит от сообщения... хорошо известен и уже давно широко используется в телекоммуникационной отрасли. Хороший источник еще большего
  15. ^ Например, низкочастотная RFID Техническое описание TMS37157 — Пассивное низкочастотное интерфейсное устройство с EEPROM и интерфейсом транспондера 134,2 кГц (PDF) , Texas Instruments , ноябрь 2009 г., стр. 39 , получено 16 февраля 2016 г. Генератор CRC инициализируется значением 0x3791, как показано на рисунке 50.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: a43f6c215b5d926140b6506dc8fc9451__1718537760
URL1:https://arc.ask3.ru/arc/aa/a4/51/a43f6c215b5d926140b6506dc8fc9451.html
Заголовок, (Title) документа по адресу, URL1:
Computation of cyclic redundancy checks - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)