Development: Small Table CRC
From WxWiki
From the comp.sys.mac.programmer Digest
/* Computing CRCs This set of implementations was written by David M. Dantowitz, and has been placed in the public domain, to be used at the user's discretion. The original code was implemented in Turbo Pascal 3.0 this submission is a version written in C. This program demonstrates various ways by which Cyclic Redundancy Checks (CRC) may be computed and their relative speeds. CRC polynomials in this program are represented by replacing each term that is non-zero with a 1 and each zero term with a 0. Note that the highest order bits represent the low order terms of the polynomial. Thus X^3+X^1+1 becomes 1101 and X^4+X^1+1 becomes 11001. Now, since all polynomials have a highest term (X^a) we drop the highest term during computation (shift right one bit, dropping the low bit). Here are some examples of conversion from symbolic to binary representation (but not necessarily polynomials with desirable CRC properties): Polynomial Representation Hex X^5 + X^2 + 1 10100 $14 X^7 + 1 1000000 $40 X^3+X^2+X^1+1 111 $7 X^6+X^5+X^3+1 100101 $25 For a good discussion of polynomial selection see "Cyclic Codes for Error Detection", by W. W. Peterson and D. T. Brown, Proceedings of the IEEE, volume 49, pp 228-235, January 1961. A reference on table driven CRC computation is "A Cyclic Redundancy Checking (CRC) Algorithm" by A. B. Marton and T. K. Frambs, The Honeywell Computer Journal, volume 5, number 3, 1971. Also used to prepare these examples was "Computer Networks", by Andrew S. Tanenbaum, Prentice Hall, Inc. Englewood Cliffs, New Jersey, 1981. The following four polynomials are international standards: CRC-12 = X^12 + X^11 + X^3 + X^2 + X^1 + 1 CRC-16 = X^16 + X^15 + X^2 + 1 CRC-CCITT = X^16 + X^12 + X^5 + 1 CCITT-32 = X^32 + X^26 + X^23 + X^22 + X^16 + X^12 + X^11 + X^10 + X^8 + X^7 + X^5 + X^4 + X^2 + X^1 + 1 In Binary and hexadecimal : Binary Hex CRC-12 = 1111 0000 0001 $0F01 CRC-16 = 1010 0000 0000 0001 $A001 CRC-CCITT = 1000 0100 0000 1000 $8404 (Used below) CCITT-32 = 1110 1101 1011 1000 1000 0011 0010 0000 $EDB88320 The first is used with 6-bit characters and the second two with 8-bit characters. All of the above will detect any odd number of errors. The second two will catch all 16-bit bursts, a high percentage of 17-bit bursts (~99.997%) and also a large percentage of 18-bit or larger bursts (~99.998%). The paper mentioned above (Peterson and Brown) discusses how to compute the statistics presented which have been quoted from Tanenbaum. (A burst of length N is defined a sequence of N bits, where the first and last bits are incorrect and the bits in the middle are any possible combination of correct and incorrect. See the paper by Peterson and Brown for more information) Note that when using a polynomial of degree N, the CRC is the first N bits of the value returned by the routines below. (e.g. with CRC-12, the CRC is bits 0 to 11 of the CRC value, with the other two mentioned above, the CRC is all 16 bits.) Here is a quick idea of what is being calculated ... The CRC is the residual from division of the data stream by the CRC polynomial. The data stream is also thought of as a polynomial, with the highest order term being the lowest bit of the first byte of the data stream and the lowest order term of the polynomial being the high bit of the last byte of data. The actual division is performed on the data stream polynomial multiplied by X^y where y is the degree of the CRC polynomial. All math used to compute CRCs is done modulo 2. This means the following relationships are used: 0+0=0 0+1=1 1+0=1 1+1=0 (XOR) 0-0=0 0-1=1 1-0=1 1-1=0 (XOR) 0*0=0 0*1=0 1*0=0 1*1=1 (AND) Thus addition and subtraction have NO carries or borrows. Here is a sample computation showing the actual division. Polynomial = X^4+X^3+1; Data = $94. The division performed is 1001 into 0010 1001. Notice that the highest order terms of the data polynomial are the lowest order bits of the data stream. We will also multiply the dividend by X^4 as noted above: 1011011 - The quotient is not important and is discarded. 1001/001010010000 -1001 ---- The extra 0s result from multiplying the data by X^4 ---- 1101 <-- The code below calculates this value -1001 ---- 1000 -1001 ---- 1000 -1001 ---- 0001 This is the CRC (the residual from the division)! The code below does not shift the data by the number of bits equal to the degree of the CRC polynomial. There is no ill effect caused by not doing this multiply. Now, the result of the CRC computation is just the residue from the division of the data by the CRC. None of the routines below appear to compute a division. In the example above the subtractions are really XORs (pronounced exclusive OR). XOR has the same behavior as +/- in modulo two arithmetic, so it is used in the computations. The first CRC routine below (Simple_CRC) models the computation lucidly. The other routines use various optimization techniques to speed the computation. CRC use ... The CRC is appended to the end of the original data stream (or stored separetely). When the receiver gets the data stream, the CRC is again computed and matched against the received CRC, if the two do not match then an error has most likely occurred. My address is David Dantowitz Dantowitz Consulting and Research P.O. Box 8105 Englewood, NJ 07631 (201) Low-Bug-C AppleLink: Dantowitz */ #include <stdio.h> #include <string.h> #define INITIAL_CRC 0xFFFFFFFF /* This result was obtained by calling make_crc_table(0xedb88320). */ int crc_table[16] = { 0x00000000, 0xfdb71064, 0xfb6e20c8, 0x06d930ac, 0xf6dc4190, 0x0b6b51f4, 0x0db26158, 0xf005713c, 0xedb88320, 0x100f9344, 0x16d6a3e8, 0xeb61b38c, 0x1b64c2b0, 0xe6d3d2d4, 0xe00ae278, 0x1dbdf21c }; make_crc_table(crc_poly) int crc_poly; { int i, val, result; for (val = 0; val < 16; val++) { result = val; for (i = 0; i < 4; i++) if (result & 1) result = (result >> 1) ^ crc_poly; else result >>= 1; crc_table[val] = result; printf("0x%08lx\n", result); } } int compute_crc(old_crc, s, len) int old_crc; char *s; int len; { int i; for (i = 0; i < len; i++) { /* XOR in the data. */ old_crc ^= s[i]; /* Perform the XORing for each nybble */ old_crc = (old_crc >> 4) ^ crc_table[old_crc & 0x0f]; old_crc = (old_crc >> 4) ^ crc_table[old_crc & 0x0f]; } return (old_crc); } main() { char line[100]; int crc_val; int len; /* make_crc_table(0xedb88320); done at compile time... */ /* initialize the crc -- start with this value each time you start a session. */ crc_val = INITIAL_CRC; strcpy(line, "This will test the crc function"); len = strlen(line); crc_val = compute_crc(crc_val, line, len); /* let's add MORE text to the CRC -- they can be cumulative across many blocks of data. */ strcpy(line, "More text to add"); len = strlen(line); crc_val = compute_crc(crc_val, line, len); }
