순환 중복 검사

순환 중복 검사(巡環重復檢査), CRC(cyclic redundancy check)는 네트워크 등을 통하여 데이터를 전송할 때 전송된 데이터에 오류가 있는지를 확인하기 위한 체크값을 결정하는 방식을 말한다. 데이터를 전송하기 전에 주어진 데이터의 값에 따라 CRC 값을 계산하여 데이터에 붙여 전송하고, 데이터 전송이 끝난 후 받은 데이터의 값으로 다시 CRC 값을 계산하게 된다. 이어서 두 값을 비교하고, 이 두 값이 다르면 데이터 전송 과정에서 잡음 등에 의해 오류가 덧붙여 전송된 것임을 알 수 있다. CRC는 이진법 기반의 하드웨어에서 구현하기 쉽고, 데이터 전송 과정에서 발생하는 흔한 오류들을 검출하는 데 탁월하다. 하지만 CRC의 구조 때문에 의도적으로 주어진 CRC 값을 갖는 다른 데이터를 만들기가 쉽고, 따라서 데이터 무결성을 검사하는 데는 사용될 수 없다. 이런 용도로는 MD5 등의 함수들이 사용된다. 순환 중복 검사를 계산하는 과정은 하드웨어적 방식과 소프트웨어적 방식을 생각할 수 있다. 하드웨어적 방식을 말할 때, 직렬데이터를 계산하는 것이 단순하다. 통신시스템에서 프로토콜 계층에서 물리층에 가까울수록 하드웨어 접근을 그리고 상위계층에 가까울수록 소프트웨어적인 방식이 적용된다. 통신시스템에서 물리계층에 가까울수록 직렬데이터를 사용하는 경향이 있다. 따라서 하드웨어적 계산방식을 사용한다. 전송라인은 거의 직렬 데이터이기 때문이다. 이런 경우 순환 중복 검사는 비트단위의 입력에 대한 출력을 얻는다. 논리 회로를 만들면 간단해진다. 그러나 높은 계층으로 갈수록 병렬데이터(octet 단위, 8비트)를 사용한다. 이런 경우는 소프트웨어적 접근으로 주로 바이트 단위로 계산한다. 순환 중복 검사는 결국 비트단위 입력에 대한 각 비트별 XOR 연산이므로 한 바이트 계산도 소프트웨어적 고속계산에 한계가 있다. 이런 경우 주로 미리 계산을 한 테이블 형태를 사용한다. CRC는 가환환(commutative ring)의 나눗셈(사칙연산의 나눗셈이 아니다. 그냥 Modulo-2의 덧셈-XOR-이다.)에 기반한다. 여기서 쓰이는 환은 법 2 (modulo 2) 정수에서 정의된 다항식의 환이다. 쉽게 말하면, 이는 한 비트의 계수를 갖는 다항식의 집합이고, 이 다항식들간의 사칙연산은 다시 계수들을 가장 아래 비트만 따도록 정의하여 한 비트 계수의 다항식으로 표현하도록 정의된다. 예를 들면: ( x 3 + x ) + ( x + 1 ) = x 3 + 2 x + 1 = x 3 + 1 {\displaystyle (x^{3}+x)+(x+1)=x^{3}+2x+1=x^{3}+1} 위 식에서 2는 이진수로 10이고, 따라서 정의에 의해서 가장 아랫자리 수(또는, 가장 아래 비트)인 0을 취하고 그 이상의 자리수는 버린다. 다음은 곱셈의 예이다: ( x 2 + x ) ( x + 1 ) = x 3 + 2 x 2 + x = x 3 + x {\displaystyle (x^{2}+x)(x+1)=x^{3}+2x^{2}+x=x^{3}+x} 더하기와 곱하기 말고 나누기도 정의할 수 있다. 예를 들어, x3 + x2 + x를 x + 1 로 나눈다고 해 보자. x 3 + x 2 + x = ( x + 1 ) ( x 2 + 1 ) − 1 = ( x + 1 ) ( x 2 + 1 ) + 1. {\displaystyle x^{3}+x^{2}+x=(x+1)(x^{2}+1)-1=(x+1)(x^{2}+1)+1.} 으로 정리할 수 있다. 다시 말하면, 나눗셈의 몫은 x2 + 1 이고 나머지는 -1 이고, -1은 홀수이기 때문에 1이 된다. 모든 데이터 비트 스트림은 이러한 다항식의 계수로 상상할 수 있다. 즉, 101 은 0번자리가 1, 1번자리가 0, 2번자리가 1이므로, 다항식 x 2 + 1 {\displaystyle x^{2}+1} 에 해당한다고 볼 수 있다. CRC 값은, 정해진 특정 다항식으로 데이터 스트링으로 주어진 다항식을 나누어 그 나머지를 나타내는 특정 길이의 비트 스트링이 된다. 이 나머지를 구하는 간단하고 빠른 알고리즘은 잘 알려져 있다. CRC는 종종 체크섬(checksum)으로 불리는데, 엄밀히 말하면 나눗셈을 통해 얻어지는 CRC 값에는 옳지 않은 이름이다. CRC의 중심을 이루는 알고리즘은 의사코드로 다음과 같이 쓸 수 있다: function crc(bit array bitString[1..len], int polynomial) { shiftRegister := initial value // 보통 00000000 또는 11111111 for i from 1 to len { if (shiftRegister의 최상위 비트) xor bitString[i] = 1 shiftRegister := (shiftRegister left shift 1) xor polynomial else shiftRegister := shiftRegister left shift 1 } return shiftRegister } (참고: 실제로는 여러 개의 최상위 비트들에 해당하는 shiftRegister의 표를 만들어서 한꺼번에 여러 비트를 처리해 속도를 높이는 방법을 쓰며, 특히 8비트 단위로 처리하는 방법이 많이 사용된다.) 위의 구현은 다음과 같은 두 가지 방법으로 고칠 수 있으며, 따라서 둘 중 하나를 적용하거나 둘 다 적용할 경우 CRC 값을 계산하는 네 가지 동등한 방법이 존재한다: shiftRegister를 비트 단위로 뒤집고, 각 단계에서 최하위 비트를 테스트한 뒤 오른쪽으로 1비트 쉬프트한다. 이 경우 polynomial의 값을 비트 단위로 뒤집어야 하고, 결과물 역시 비트 단위로 뒤집어진다. shiftRegister의 한 비트와 bitString의 한 비트를 xor하는 대신에, shiftRegister와 bitString에서 polynomial에 설정된 비트에 해당하는 모든 비트들을 xor한 1비트 결과를 shiftRegister에 더한다. polynomial을 적당히 고치면 같은 나머지를 얻을 수 있다. 이 방법은 소프트웨어에서 구현하기는 힘들지만 하드웨어 구현에서는 종종 사용되며, CRC와 깊은 관련이 있는 선형 되먹임 시프트 레지스터를 설명하는 데 자주 사용된다. 특정한 CRC는 사용되는 다항식으로 정의한다. n비트 CRC를 만드는 데는 x n + . . . + 1 {\displaystyle x^{n}+...+1} 꼴의 n차 다항식이 필요하다. 이 다항식은 기본적으로 (n+1)비트 문자열로 나타낼 수 있지만, 차수가 가장 높은 xn 항의 계수는 항상 1이기 때문에 이 항을 빼고 n비트 문자열로 나타낼 수 있다. 예를 들어 CRC-16 표준에 사용되는 다항식인 x 15 + x 2 + 1 {\displaystyle x^{15}+x^{2}+1} 은 비트 순서에 따라서 16진수 숫자 0x8005나 0xa001로 나타낼 수 있으며, 이더넷, FDDI, PKZIP, WinZip, PNG 등에서 널리 사용되는 CRC-32의 경우 0x04C11DB7 또는 0xEDB88320으로 쓸 수 있다. 여기에 표시하지는 않았지만 더 많은 CRC 종류들이 있다. 적어도 다섯 종류의 서로 다른 CRC-16, CRC-32, CRC-64가 존재하고 널리 사용된다. CRC-128, CRC-256도 존재하고 표준화되어 있지만 널리 사용되지는 않는다. 다항식의 표현은 일반적으로 다음과 같이 표현한다. 다항식의 예 : x 4 + x + 1 {\displaystyle x^{4}+x+1} 이 다항식은 다음과 같이 3가지 방법의 숫자로 표현할 수 있다: 0x3 = 0b0011 : x 4 + {\displaystyle x^{4}+} 0 x 3 + 0 x 2 + 1 x 1 + 1 x 0 {\displaystyle 0x^{3}+0x^{2}+1x^{1}+1x^{0}} (MSB-우선 코드) 0xC = 0b1100 : 1 x 0 + 1 x 1 + 0 x 2 + 0 x 3 {\displaystyle 1x^{0}+1x^{1}+0x^{2}+0x^{3}} + x 4 {\displaystyle +x^{4}} (LSB-우선 코드) 0x9 = 0b1001 : 1 x 4 + 0 x 3 + 0 x 2 + 1 x 1 {\displaystyle 1x^{4}+0x^{3}+0x^{2}+1x^{1}} + x 0 {\displaystyle +x^{0}} (Koopman 표시) 이 가지를 표로 나타내면: CRC값을 계산하려면 비트수와 다항식을 결정해야 한다. 따라서 정해진 비트수와 함께 다항식을 정하면 입력된 메시지는 오류가 없는 경우 같은 CRC 값이 나온다. 다음은 사용하고 있는 다양한 다항식들이다: n-bit 이진 CRC 계산을 위해서는 다항식(polynomial) (n+1)-비트 패턴의 제수(divisor)를 만든다. 다항식의 각 자릿수 별로 표현하면: 1 x 3 + 0 x 2 + 1 x + 1 => 1011 {\displaystyle 1x^{3}+0x^{2}+1x+1=>1011} 메시지 데이터는: 11010011101100 3비트 CRC를 계산하기 첫 번째로 나누면 : 1 --------------------- 1011 ) 11010011101100 000 <--- 오른쪽으로 3비트 후부터 1011 <--- 제수(divisor) 4비트 <= x³+x+1 ------------------ 01100011101100 000 <--- 결과 나누는 과정에서 각 비트별로 XOR로 행한다. 일반적인 나누기에서의 뺄셈과는 다르다. 연산결과 첫 번째 비트가 0으로 소거되도록 몫의 비트를 정한다. 메시지 첫 번째 비트가 1이므로 몫의 1로 하여 XOR-나누기를 한다. 이렇게 되면 첫 번째 비트가 0으로 된다. 1101 XOR 1011 => 0 110 이제 전체를 계산하며: 11110001111 100 <--- 몫은 별로 의미가 없는 중간 과정이다. ------------------- 11010011101100 000 <--- 오른쪽으로 3비트 후부터 1011 <--- 제수 01100011101100 000 <--- 결과 1011 <--- 제수 ... 00111011101100 000 1011 00010111101100 000 1011 00000001101100 000 0000 <--- 0인 경우 위의 계산결과가 바뀌지 않는다. 그대로 넘겨도 된다. 00000001101100 000 0000 00000001101100 000 0000 00000001101100 000 1011 00000000110100 000 1011 00000000011000 000 1011 00000000001110 000 1011 00000000000101 000 101 1 00000000000000 100 <--- 왼쪽이 모두 0이면 여기서 끝내도 된다. 뒤에 오는 것은 0은 계산에 영향이 없다. 00 00 00000000000000 100 0 000 ----------------- 00000000000000 100 <--- 나머지(remainder) 3비트, 앞에는 모두 0이 되고 뒤에 3비트가 최종 결론이다. 왼쪽의 나머지가 모두 0이 되도록 계속 나눈다. 최대로 입력 비트수 만큼 나누면 모두 0이 된다. 이제 위의 계산결과로부터 검증을 하면 입력 메시지 다음에 CRC 결과를 붙여 나누면 나머지가 0이 된다.: 11010011101100 100 <--- 입력과 CRC 체크값을 붙이고 1011 <--- 나누고 01100011101100 100 <--- 결과 1011 <--- 나누고 ... 00111011101100 100 ...... 00000000001110 100 1011 00000000000101 100 101 1 ------------------ 0 <--- 나머지 구현은 하드웨어적 방법과 소프트웨어적 방법이 있다. 보통 CRC가 통신시스템등에 많이 사용되는데, 하드웨어적인 접근방법도 많이 사용한다. 위의 예: x 3 + x + 1 {\displaystyle x^{3}+x+1} 는 다음과 같은 구성으로 표현할 수 있다. 직렬 비트데이터가 들어오면 매 비트마다 논리회로에 의해 계산된다. D-FF을 사용하여 논리 회로를 그리면 다음과 같다: 입력은 한클럭 동안 하나의 비트를 입력하고, 출력은 O2 O1 O0로 3비트이다. 직렬입력에 대해 매 클럭마다 CRC값이 출력된다. 디지털통신에서 물리계층으로 갈수록 직렬비트의 데이터 형태로 입력되어 처리되는 경향이 있다. 따라서 보통 위와같은 회로를 사용하여 CRC을 계산할 수 있다. 직렬이 아니고 병렬로 입력되어 여러비트를 한클럭에 계산할 필요가 있다면, 위의 예에서의 회로를 층구조로 쌓아 만들면 된다. 예를 들어 4비트를 동시에 계산하는 하드웨어를 구성하면 다음과 같은 예로 만들수 있다. 4비트 입력 b3:b2:b1:b0를 한클럭에 계산하려면 다음과 같은 회로로 구성할 수 있다: 입력 b[3:0]에 대해 계산된 CRC출력은 C[2:0]이다. 여기서 b0가 가장먼저 입력되고, 다음이 b1의 순으로 입력되는 경우이다. 고속 클럭에서 동작하는 회로에서는 XOR가 여러단 전파하면서 생기는 시간지연은 상황에 따라 고려하여 설계하여야 한다. 위에서 예로 들은 메시지 입력: 1101 0011 1011 0000 에 대해 계산을 하면 다음과 같이 4비트 단위로 나눌 수 있다. 여기서 회로의 입력순서는 1101 = b0 b1 b2 b3 = b[0:3] 으로 표시 하였다. 1 clock - 입력 1101 = b0 b1 b2 b3 = b[0:3] 000 <-- 처음 RESET에 의해 000으로 플립플롭을 초기화 1101 000 <-- 입력 1101이 동시에 들어 온다. ---- 1101 000 <-- 우선 이전의 CRC와 현재 입력을 XOR 한다. 초기에 000으로 설정되면 입력이 변하지 않는다. 1011 <-- 첫 번째 XOR 실행 ---- 0110 000 101 1 ---- 011 100 10 11 ---- 01 010 1 011 ---- 0 001 <-- 첫 번째 CRC 결과 C[2:0] = 001 2 clock - 입력 0011 = b0 b1 b2 b3 001 <-- 첫 번째 클럭에 의해 계산된 001이 반영된다. 0011 000 <-- 입력 ---- 0001 000 <-- 우선 이전의 CRC와 현재 입력을 XOR 한다. 0000 ---- 001 000 000 0 ---- 001 000 1 011 ---- 0000 011 <-- 두 번째 CRC 결과 C[2:0] = 011 3 clock - 입력 1011 = b0 b1 b2 b3 011 1011 000 1011 ---- 0110 000 101 1 ---- 11 100 10 11 ---- 1 010 1 011 ---- 0 001 <-- 세 번째 CRC 결과 C[2:0] = 001 4 clock - 입력 0000 = b0 b1 b2 b3 001 0000 000 0000 ---- 0010 000 10 11 ---- 00 110 <-- 네 번째 CRC 결과 C[2:0] = 110 최종 CRC 결과 C[2:0] = 110로 4클럭으로 계산 할 수 있다. 보통 CRC을 적용할 때 바이트(Octet) 단위로 구현한다. 많은 통신시스템에서 OCTET 단위가 기본이기 때문이다. 비트단위로 계산해야 하는 경우 속도등의 문제로 오히려 CRC 테이블 기법을 많이 사용한다. OCT단위로 입력되는 데이터를 계산해야 하는데, 루프를 실행해야 하므로 속도등에 문제가 발생할 수 있다. 특히 CRC의 비트수가 많을 수록 더욱 문제가 된다. 위의 예를 기반으로 소프트웨어 접근법을 위한 코드를 작성 하면: CRC 테이블을 만들어 변수화 한다. 데이터가 들어오면 OCTET 단위로 테이블 탐색을 통해 CRC을 결정 한다. 우선 모든 OCT 단위로 입력을 미리 계산한다. //#define CRC_SHIFT_5 static unsigned char crctable[256]; /// CRC 테이블 만들기 ///////////////////////////// // Generate a table for a byte-wise 3-bit CRC calculation on the polynomial: // x^3 + x + 1 void make_crc_table( void ) { int cnt, bcnt; unsigned short poly, c; // terms of polynomial defining this crc (except x^3): static const char p[] = {0,1}; // make exclusive-or pattern from polynomial poly = 0; for ( cnt = 0; cnt < sizeof(p)/sizeof(p[0]); cnt++ ) { poly |= 1 << p[cnt]; } poly <<= 5; for ( cnt = 0; cnt < 256; cnt++ ) { c = cnt; for ( bcnt = 0; bcnt < 8; bcnt++ ) { c = ( c & 0x80 ) ? poly ^ ( c << 1 ) : ( c << 1 ); } #ifdef CRC_SHIFT_5 crctable[cnt] = (unsigned char) (c>>5) & 0x07; #else crctable[cnt] = (unsigned char) (c & 0xE0); #endif } } int main(int argc, char* argv[]) { int cnt; unsigned char crc; make_crc_table(); FILE *fout; if ( (fout = fopen("crc3table.h", "wt")) == NULL) return -1; fprintf(fout, "#ifndef _CRC3TABLE_H\n" "#define _CRC3TABLE_H\n" "\nextern const unsigned char crctable[];\n" ); #ifdef CRC_SHIFT_5 fprintf(fout, "\n#define CRC_SHIFT_5\n"); #endif fprintf(fout, "\n#endif\n"); fclose(fout); if ( (fout = fopen("crc3table.c", "wt")) == NULL) return -1; fprintf(fout, "\nconst unsigned char crctable[256] = {\n "); for ( cnt = 0; cnt < 256; cnt++ ) { if (cnt == 255) { fprintf(fout, "0x%02X\n", crctable[cnt] ); break; } else fprintf(fout,"0x%02X,", crctable[cnt] ); if ( (cnt % 8) == 7) fprintf(fout,"\n "); else fprintf(fout," "); } fprintf(fout,"};\n"); fclose(fout); return 0; } 실행결과 : const unsigned char crctable[256] = { 0x00, 0x60, 0xC0, 0xA0, 0xE0, 0x80, 0x20, 0x40, 0xA0, 0xC0, 0x60, 0x00, 0x40, 0x20, 0x80, 0xE0, 0x20, 0x40, 0xE0, 0x80, 0xC0, 0xA0, 0x00, 0x60, 0x80, 0xE0, 0x40, 0x20, 0x60, 0x00, 0xA0, 0xC0, 0x40, 0x20, 0x80, 0xE0, 0xA0, 0xC0, 0x60, 0x00, 0xE0, 0x80, 0x20, 0x40, 0x00, 0x60, 0xC0, 0xA0, 0x60, 0x00, 0xA0, 0xC0, 0x80, 0xE0, 0x40, 0x20, 0xC0, 0xA0, 0x00, 0x60, 0x20, 0x40, 0xE0, 0x80, 0x80, 0xE0, 0x40, 0x20, 0x60, 0x00, 0xA0, 0xC0, 0x20, 0x40, 0xE0, 0x80, 0xC0, 0xA0, 0x00, 0x60, 0xA0, 0xC0, 0x60, 0x00, 0x40, 0x20, 0x80, 0xE0, 0x00, 0x60, 0xC0, 0xA0, 0xE0, 0x80, 0x20, 0x40, 0xC0, 0xA0, 0x00, 0x60, 0x20, 0x40, 0xE0, 0x80, 0x60, 0x00, 0xA0, 0xC0, 0x80, 0xE0, 0x40, 0x20, 0xE0, 0x80, 0x20, 0x40, 0x00, 0x60, 0xC0, 0xA0, 0x40, 0x20, 0x80, 0xE0, 0xA0, 0xC0, 0x60, 0x00, 0x60, 0x00, 0xA0, 0xC0, 0x80, 0xE0, 0x40, 0x20, 0xC0, 0xA0, 0x00, 0x60, 0x20, 0x40, 0xE0, 0x80, 0x40, 0x20, 0x80, 0xE0, 0xA0, 0xC0, 0x60, 0x00, 0xE0, 0x80, 0x20, 0x40, 0x00, 0x60, 0xC0, 0xA0, 0x20, 0x40, 0xE0, 0x80, 0xC0, 0xA0, 0x00, 0x60, 0x80, 0xE0, 0x40, 0x20, 0x60, 0x00, 0xA0, 0xC0, 0x00, 0x60, 0xC0, 0xA0, 0xE0, 0x80, 0x20, 0x40, 0xA0, 0xC0, 0x60, 0x00, 0x40, 0x20, 0x80, 0xE0, 0xE0, 0x80, 0x20, 0x40, 0x00, 0x60, 0xC0, 0xA0, 0x40, 0x20, 0x80, 0xE0, 0xA0, 0xC0, 0x60, 0x00, 0xC0, 0xA0, 0x00, 0x60, 0x20, 0x40, 0xE0, 0x80, 0x60, 0x00, 0xA0, 0xC0, 0x80, 0xE0, 0x40, 0x20, 0xA0, 0xC0, 0x60, 0x00, 0x40, 0x20, 0x80, 0xE0, 0x00, 0x60, 0xC0, 0xA0, 0xE0, 0x80, 0x20, 0x40, 0x80, 0xE0, 0x40, 0x20, 0x60, 0x00, 0xA0, 0xC0, 0x20, 0x40, 0xE0, 0x80, 0xC0, 0xA0, 0x00, 0x60 }; 변수 crctable[]이 바이트 단위로 모두 계산한다. 이것을 프로그램 파일로 만들어 CRC 계산하는데 사용한다. 이 파일이름을 crc3table.c라고 하면 다음에 이것을 사용하여 코딩한다. // File : crc3.h ////////////////////////////////////////// #ifndef _CRC3_H #define _CRC3_H #include "crc3table.h" #define CRC3_INIT_VALUE 0x0000 unsigned char crc3_CalcChecksum(const unsigned char icrc, const void *data, int length ); #endif // File : crc3.c ////////////////////////////////////////// // #include "crc3.h" /// CRC 테이블 사용하기 ////////////// #include "crc3table.c" // 위의 예에서 미리계산한 CRC 테이블 코드를 사용한다. unsigned char crc3_CalcChecksum(const unsigned char icrc, const void *data, int length ) { unsigned char crc; const unsigned char *buf = (const unsigned char *) data; crc = icrc; while (length--) { #ifdef CRC_SHIFT_5 crc = crctable[(crc<<5) ^ *buf++]; #else crc = crctable[crc ^ *buf++]; #endif } return crc; } // File : testcrc3main.c ////////////////////////////////////////// // #include <stdio.h> #include "crc3.h" int main(int argc, char* argv[]) { int cnt; unsigned char crc; unsigned char data[8] = { 0xD3, 0xB0 }; #define SZ_MSGDATA 2 crc = crc3_CalcChecksum(CRC3_INIT_VALUE, (void *)data, SZ_MSGDATA); printf("Input Data : "); for (cnt = 0;cnt < SZ_MSGDATA;cnt++) printf("0x%02X ", data[cnt] ); #ifdef CRC_SHIFT_5 printf(" : CRC = %X\n", crc); #else printf(" : CRC = 0x%02X [%x]\n", crc, crc >> 5 ); #endif int sz = SZ_MSGDATA; data[sz++] = 0xCB; data[sz++] = 0x0D; crc = crc3_CalcChecksum(crc, &data[SZ_MSGDATA], sz-SZ_MSGDATA); printf("Input Data : "); for (cnt = 0;cnt < sz;cnt++) printf("0x%02X ", data[cnt] ); #ifdef CRC_SHIFT_5 printf(" : CRC = %X\n", crc); #else printf(" : CRC = 0x%02X [%x]\n", crc, crc >> 5 ); #endif crc = crc3_CalcChecksum(CRC3_INIT_VALUE, (void *)data, sz); printf("다시 계산 : "); for (cnt = 0;cnt < sz;cnt++) printf("0x%02X ", data[cnt] ); #ifdef CRC_SHIFT_5 printf(" : CRC = %X\n", crc); #else printf(" : CRC = 0x%02X [%x]\n", crc, crc >> 5 ); #endif return 0; } 실행결과: Input Data : 0xD3 0xB0  : CRC = 0xC0 [6] Input Data : 0xD3 0xB0 0xCB 0x0D  : CRC = 0x20 [1] 다시 계산 : 0xD3 0xB0 0xCB 0x0D  : CRC = 0x20 [1] 2바이트의 3비트 CRC는 6으로 결정되었다. CRC 테이블 생성과 사용법 정해진 다항식에 따라 한 바이트에 해당하는 직렬데이터를 미리 계산을 하여 테이블화한다. 바이트 단위의 입력데이터를 인덱스로 하여, 다음 CRC 값을 테이블 탐색을 하여 찾는다. 《Class-1 Generation-2 UHF RFID Protocol》 (PDF). 1.2.0. EPCglobal. 2008년 10월 23일. 35쪽. 2012년 7월 4일에 확인함.  (Table 6.12) Chakravarty, Tridib (2001년 12월). 《Performance of Cyclic Redundancy Codes for Embedded Networks》 (PDF). Pittsburgh: Carnegie Mellon University. 5,18쪽. 2013년 7월 8일에 확인함.  지원되지 않는 변수 무시됨: |other= (추천: |others=) (도움말); 더 이상 지원되지 않는 변수를 사용함 (도움말) Koopman, Philip; Chakravarty, Tridib (2004년 6월). “Cyclic Redundancy Code (CRC) Polynomial Selection For Embedded Networks” (PDF). 《The International Conference on Dependable Systems and Networks》: 145–154. doi:10.1109/DSN.2004.1311885. ISBN 0-7695-2052-9. 2011년 1월 14일에 확인함.  더 이상 지원되지 않는 변수를 사용함 (도움말) Richardson, Andrew (2005년 3월 17일). 《WCDMA Handbook》. Cambridge, UK: Cambridge University Press. 223쪽. ISBN 0-521-82815-5.  《FlexRay Protocol Specification》. 3.0.1. Flexray Consortium. October 2010. 114쪽.  (4.2.8 Header CRC (11 bits)) Perez, A.; Wismer & Becker (1983). “Byte-Wise CRC Calculations”. 《IEEE Micro》 3 (3): 40–50. doi:10.1109/MM.1983.291120.  더 이상 지원되지 않는 변수를 사용함 (도움말) Ramabadran, T.V.; Gaitonde, S.S. (1988). “A tutorial on CRC computations”. 《IEEE Micro》 8 (4): 62–75. doi:10.1109/40.7773.  《A signalling standard for trunked private land mobile radio systems (MPT 1327)》 (PDF) 3판. Ofcom. 1997년 6월. 3-3쪽. 2012년 7월 16일에 확인함.  더 이상 지원되지 않는 변수를 사용함 (도움말) (3.2.3 Encoding and error checking) Thaler, Pat (2003년 8월 28일). “16-bit CRC polynomial selection” (PDF). INCITS T10. 2009년 8월 11일에 확인함.  “ETSI EN 300 175-3”. V2.2.1. Sophia Antipolis, France: European Telecommunications Standards Institute. November 2008.  Rehmann, Albert; Mestre, José D. (1995년 2월). “Air Ground Data Link VHF Airline Communications and Reporting System (ACARS) Preliminary Test Report” (PDF). Federal Aviation Authority Technical Center: 5. 2012년 8월 2일에 원본 문서 (PDF)에서 보존된 문서. 2012년 7월 7일에 확인함.  더 이상 지원되지 않는 변수를 사용함 (도움말) 《CAN with Flexible Data-Rate Specification》 (PDF). 1.0. Robert Bosch GmbH. April 17th, 2012. 13쪽. 2013년 8월 22일에 원본 문서 (PDF)에서 보존된 문서. 2013년 4월 2일에 확인함.  다음 날짜 값 확인 필요: |date= (도움말) (3.2.1 DATA FRAME) Boutell, Thomas; Randers-Pehrson, Glenn; et al. (1998년 7월 14일). “PNG (Portable Network Graphics) Specification, Version 1.2”. Libpng.org. 2011년 2월 3일에 확인함.  더 이상 지원되지 않는 변수를 사용함 (도움말) Koopman, Philip (2002년 7월). “32-Bit Cyclic Redundancy Codes for Internet Applications” (PDF). 《The International Conference on Dependable Systems and Networks》: 459–468. doi:10.1109/DSN.2002.1028931. ISBN 0-7695-1597-5. 2011년 1월 14일에 확인함.  더 이상 지원되지 않는 변수를 사용함 (도움말) 《AIXM Primer》 (PDF). 4.5. European Organisation for the Safety of Air Navigation. 2006년 3월 20일. 2013년 10월 31일에 원본 문서 (PDF)에서 보존된 문서. 2012년 7월 4일에 확인함.  Gammel, Berndt M. (2005년 10월 31일). 《Matpack documentation: Crypto - Codes》. Matpack.de. 2013년 4월 21일에 확인함.  (Note: MpCRC.html is included with the Matpack compressed software source code, under /html/LibDoc/Crypto) Geremia, Patrick (1999년 4월). “Cyclic redundancy check computation: an implementation using the TMS320C54x” (PDF) (SPRA530). Texas Instruments: 5. 2012년 7월 4일에 확인함.  더 이상 지원되지 않는 변수를 사용함 (도움말) Jones, David T. “An Improved 64-bit Cyclic Redundancy Check for Protein Sequences” (PDF). University College London. 2009년 12월 15일에 확인함.  오류 정정 부호 Adler-32 The CRC Pitstop A Painless Guide to CRC Error Detection Algorithms Understanding Cyclic Redundancy Check Serversniff.net 널리 쓰이는 CRC들(CRC-8/16/32/64)을 계산하는 도구 Online CRC calculator Online CRC Tool: Generator of synthesizable CRC functions Archived 2005년 11월 25일 - 웨이백 머신