From 4b235c9c3b57703b5be376ccc394ff2f46d919d3 Mon Sep 17 00:00:00 2001 From: Cody Boone Ferguson <53008573+xexyl@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:49:23 -0700 Subject: [PATCH] Fixes in 1998/tomtorfs Format fixes. Use Internet Wayback Machine as the link was dead. This was done in winners.html and winners.csv as well. Add crc.txt - a file the author referred to. Found it at https://opensource.apple.com/source/tcl/tcl-20/tcl_ext/trf/trf/doc/painless-guide-to-crc.txt. This should complete format fixes in 1998. --- 1998/tomtorfs/README.md | 179 ++-- 1998/tomtorfs/crc.txt | 2069 +++++++++++++++++++++++++++++++++++++++ tmp/winners.csv | 2 +- winners.html | 2 +- 4 files changed, 2176 insertions(+), 76 deletions(-) create mode 100644 1998/tomtorfs/crc.txt diff --git a/1998/tomtorfs/README.md b/1998/tomtorfs/README.md index f5b77887b..453113765 100644 --- a/1998/tomtorfs/README.md +++ b/1998/tomtorfs/README.md @@ -1,105 +1,136 @@ # Best Self-Documenting - Tom Torfs - De Nayer Instituut - Cuperuslei 12 (home address) - 2220 Heist-op-den-Berg - Belgium - - http://members.xoom.com/tomtorfs +Tom Torfs +De Nayer Instituut +Cuperuslei 12 (home address) +2220 Heist-op-den-Berg +Belgium + ## To build: - make all +```sh +make all +``` ## To run: - ./tomtorfs tomtorfs.c 32 04C11DB7 1 FFFFFFFF FFFFFFFF +```sh +./tomtorfs tomtorfs.c 32 04C11DB7 1 FFFFFFFF FFFFFFFF +``` -## Judges' remarks +## Try: - Also try: +```sh +echo "abscond conferrable" > file.A +echo "adorn condolence" > file.B +echo "adorn condolence too" > file.C +./tomtorfs file.A 32 04C11DB7 1 FFFFFFFF FFFFFFFF +./tomtorfs file.B 32 04C11DB7 1 FFFFFFFF FFFFFFFF +./tomtorfs file.C 32 04C11DB7 1 FFFFFFFF FFFFFFFF +``` - echo "abscond conferrable" > file.A - echo "adorn condolence" > file.B - echo "adorn condolence too" > file.C - ./tomtorfs file.A 32 04C11DB7 1 FFFFFFFF FFFFFFFF - ./tomtorfs file.B 32 04C11DB7 1 FFFFFFFF FFFFFFFF - ./tomtorfs file.C 32 04C11DB7 1 FFFFFFFF FFFFFFFF +## Judges' remarks: - If you don't believe the program is correct, try and compare the output - of the program with the value of CRC computed by PKZIP or any other - archiver that uses the CRC-32 algorithm. +If you don't believe the program is correct, try and compare the output +of the program with the value of CRC computed by PKZIP or any other +archiver that uses the CRC-32 algorithm. -## Author's remarks +## Author's remarks: - Usage: - crc filename bitwidth polynom reflected init xor +``` +Usage: +./tomtorfs filename bitwidth polynom reflected init xor - filename : file to calculate the CRC of - bitwidth : width of the CRC in bits (decimal) - polynom : polynomial used for the CRC (hexadecimal) - reflected : 0 if the CRC is not reflected, 1 if it is - init : initial value for the CRC (hexadecimal) - xor : value to xor the final CRC with (hexadecimal) +filename : file to calculate the CRC of +bitwidth : width of the CRC in bits (decimal) +polynom : polynomial used for the CRC (hexadecimal) +reflected : 0 if the CRC is not reflected, 1 if it is +init : initial value for the CRC (hexadecimal) +xor : value to xor the final CRC with (hexadecimal) +``` - Examples: +### Examples - CRC-16: crc filename 16 1021 0 FFFF 0000 - CRC-32: crc filename 32 04C11DB7 1 FFFFFFFF FFFFFFFF - XMODEM: crc filename 16 8408 1 0000 0000 - ARC: crc filename 16 8005 1 0000 0000 +#### CRC-16: - Portability notes: +```sh +./tomtorfs filename 16 1021 0 FFFF 0000 +``` - The program assumes CHAR_BIT==8. Results are undefined if - bitwidth > sizeof(unsigned long) * 8. It is also assumed - that EOF is -1 and 1 is a valid exit value to indicate - failure (replace them with EOF resp. EXIT_FAILURE if the - assumptions are false). Otherwise ANSI/ISO C. - No special build options required. +#### CRC-32: - Special notes: - Count the number of non-whitespace characters in the source - file to find out what dark force drove me to write this ;-). +```sh +./tomtorfs filename 32 04C11DB7 1 FFFFFFFF FFFFFFFF +``` - Spoiler: +#### XMODEM: - First of all, if you run a C beautifier on the program - (thereby of course losing the nice code shape I worked - so hard on ;-) the code will become a bit more readable. +```sh +./tomtorfs filename 16 8408 1 0000 0000 - The variable names are not very descriptive. They have the - following meanings: - a = argc - A = argv - b = array of unsigned long variables - b[0] = bit-width of the CRC (argv[2]) - b[1] = CRC polynomial (argv[3]) - b[2] = nonzero if CRC is reflected (argv[4]) - b[3] = initial value of CRC (argv[5]) - b[4] = value final CRC is XORed with (argv[6]) - b[5] = CRC value - b[6] = byte from file - b[7] = counter - B = FILE * through which the file argv[1] is opened - C = typedef for unsigned long +``` - The first for loop simply reads the command-line arguments - in the b[] array. The third parameter to strtoul() causes - all arguments to be in base-16 (hex) except the first one, - which will be in base-10 (decimal). +#### ARC: - The rest of the program "simply" calculates the crc in b[5] - and then prints it to stdout. The bit reflection loops may - appear a bit tricky at first, but if you have a good look - at them they should become obvious also. +```sh +./tomtorfs filename 16 8005 1 0000 0000 +``` - Acknowledgments: +### Portability notes - Ross N. Williams, whose CRC guide was very useful to me - for writing this. You can find it as CRC.TXT in Snippets. +The program assumes `CHAR_BIT==8`. Results are undefined if `bitwidth > +sizeof(unsigned long) * 8`. It is also assumed that `EOF` is `-1` and `1` is a +valid exit value to indicate failure (replace them with `EOF` resp. +`EXIT_FAILURE` if the assumptions are false). Otherwise ANSI/ISO C. + +No special build options required. + +### Special notes + +Count the number of non-whitespace characters in the source +file to find out what dark force drove me to write this ;-). + +### Spoiler + +First of all, if you run a C beautifier on the program (thereby of course losing +the nice code shape I worked so hard on ;-) ) the code will become a bit more +readable. + +The variable names are not very descriptive. They have the +following meanings: + +``` +a = argc +A = argv +b = array of unsigned long variables + b[0] = bit-width of the CRC (argv[2]) + b[1] = CRC polynomial (argv[3]) + b[2] = nonzero if CRC is reflected (argv[4]) + b[3] = initial value of CRC (argv[5]) + b[4] = value final CRC is XORed with (argv[6]) + b[5] = CRC value + b[6] = byte from file + b[7] = counter +B = FILE * through which the file argv[1] is opened +C = typedef for unsigned long +``` + +The first for loop simply reads the command-line arguments +in the `b[]` array. The third parameter to `strtoul()` causes +all arguments to be in base-16 (hex) except the first one, +which will be in base-10 (decimal). + +The rest of the program "simply" calculates the CRC in `b[5]` +and then prints it to stdout. The bit reflection loops may +appear a bit tricky at first, but if you have a good look +at them they should become obvious also. + +### Acknowledgments: + +Ross N. Williams, whose CRC guide was very useful to me +for writing this. You can find it in [crc.txt](crc.txt). ## Copyright and CC BY-SA 4.0 License: diff --git a/1998/tomtorfs/crc.txt b/1998/tomtorfs/crc.txt new file mode 100644 index 000000000..ca92e1b86 --- /dev/null +++ b/1998/tomtorfs/crc.txt @@ -0,0 +1,2069 @@ + +A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS +================================================== +"Everything you wanted to know about CRC algorithms, but were afraid +to ask for fear that errors in your understanding might be detected." + +Version : 3. +Date : 19 August 1993. +Author : Ross N. Williams. +Net : ross@guest.adelaide.edu.au. +FTP : ftp.adelaide.edu.au/pub/rocksoft/crc_v3.txt +Company : Rocksoft^tm Pty Ltd. +Snail : 16 Lerwick Avenue, Hazelwood Park 5066, Australia. +Fax : +61 8 373-4911 (c/- Internode Systems Pty Ltd). +Phone : +61 8 379-9217 (10am to 10pm Adelaide Australia time). +Note : "Rocksoft" is a trademark of Rocksoft Pty Ltd, Australia. +Status : Copyright (C) Ross Williams, 1993. However, permission is + granted to make and distribute verbatim copies of this + document provided that this information block and copyright + notice is included. Also, the C code modules included + in this document are fully public domain. +Thanks : Thanks to Jean-loup Gailly (jloup@chorus.fr) and Mark Adler + (me@quest.jpl.nasa.gov) who both proof read this document + and picked out lots of nits as well as some big fat bugs. + +Table of Contents +----------------- + Abstract + 1. Introduction: Error Detection + 2. The Need For Complexity + 3. The Basic Idea Behind CRC Algorithms + 4. Polynomical Arithmetic + 5. Binary Arithmetic with No Carries + 6. A Fully Worked Example + 7. Choosing A Poly + 8. A Straightforward CRC Implementation + 9. A Table-Driven Implementation +10. A Slightly Mangled Table-Driven Implementation +11. "Reflected" Table-Driven Implementations +12. "Reversed" Polys +13. Initial and Final Values +14. Defining Algorithms Absolutely +15. A Parameterized Model For CRC Algorithms +16. A Catalog of Parameter Sets for Standards +17. An Implementation of the Model Algorithm +18. Roll Your Own Table-Driven Implementation +19. Generating A Lookup Table +20. Summary +21. Corrections + A. Glossary + B. References + C. References I Have Detected But Haven't Yet Sighted + + +Abstract +-------- +This document explains CRCs (Cyclic Redundancy Codes) and their +table-driven implementations in full, precise detail. Much of the +literature on CRCs, and in particular on their table-driven +implementations, is a little obscure (or at least seems so to me). +This document is an attempt to provide a clear and simple no-nonsense +explanation of CRCs and to absolutely nail down every detail of the +operation of their high-speed implementations. In addition to this, +this document presents a parameterized model CRC algorithm called the +"Rocksoft^tm Model CRC Algorithm". The model algorithm can be +parameterized to behave like most of the CRC implementations around, +and so acts as a good reference for describing particular algorithms. +A low-speed implementation of the model CRC algorithm is provided in +the C programming language. Lastly there is a section giving two forms +of high-speed table driven implementations, and providing a program +that generates CRC lookup tables. + + +1. Introduction: Error Detection +-------------------------------- +The aim of an error detection technique is to enable the receiver of a +message transmitted through a noisy (error-introducing) channel to +determine whether the message has been corrupted. To do this, the +transmitter constructs a value (called a checksum) that is a function +of the message, and appends it to the message. The receiver can then +use the same function to calculate the checksum of the received +message and compare it with the appended checksum to see if the +message was correctly received. For example, if we chose a checksum +function which was simply the sum of the bytes in the message mod 256 +(i.e. modulo 256), then it might go something as follows. All numbers +are in decimal. + + Message : 6 23 4 + Message with checksum : 6 23 4 33 + Message after transmission : 6 27 4 33 + +In the above, the second byte of the message was corrupted from 23 to +27 by the communications channel. However, the receiver can detect +this by comparing the transmitted checksum (33) with the computer +checksum of 37 (6 + 27 + 4). If the checksum itself is corrupted, a +correctly transmitted message might be incorrectly identified as a +corrupted one. However, this is a safe-side failure. A dangerous-side +failure occurs where the message and/or checksum is corrupted in a +manner that results in a transmission that is internally consistent. +Unfortunately, this possibility is completely unavoidable and the best +that can be done is to minimize its probability by increasing the +amount of information in the checksum (e.g. widening the checksum from +one byte to two bytes). + +Other error detection techniques exist that involve performing complex +transformations on the message to inject it with redundant +information. However, this document addresses only CRC algorithms, +which fall into the class of error detection algorithms that leave the +data intact and append a checksum on the end. i.e.: + + + + +2. The Need For Complexity +-------------------------- +In the checksum example in the previous section, we saw how a +corrupted message was detected using a checksum algorithm that simply +sums the bytes in the message mod 256: + + Message : 6 23 4 + Message with checksum : 6 23 4 33 + Message after transmission : 6 27 4 33 + +A problem with this algorithm is that it is too simple. If a number of +random corruptions occur, there is a 1 in 256 chance that they will +not be detected. For example: + + Message : 6 23 4 + Message with checksum : 6 23 4 33 + Message after transmission : 8 20 5 33 + +To strengthen the checksum, we could change from an 8-bit register to +a 16-bit register (i.e. sum the bytes mod 65536 instead of mod 256) so +as to apparently reduce the probability of failure from 1/256 to +1/65536. While basically a good idea, it fails in this case because +the formula used is not sufficiently "random"; with a simple summing +formula, each incoming byte affects roughly only one byte of the +summing register no matter how wide it is. For example, in the second +example above, the summing register could be a Megabyte wide, and the +error would still go undetected. This problem can only be solved by +replacing the simple summing formula with a more sophisticated formula +that causes each incoming byte to have an effect on the entire +checksum register. + +Thus, we see that at least two aspects are required to form a strong +checksum function: + + WIDTH: A register width wide enough to provide a low a-priori + probability of failure (e.g. 32-bits gives a 1/2^32 chance + of failure). + + CHAOS: A formula that gives each input byte the potential to change + any number of bits in the register. + +Note: The term "checksum" was presumably used to describe early +summing formulas, but has now taken on a more general meaning +encompassing more sophisticated algorithms such as the CRC ones. The +CRC algorithms to be described satisfy the second condition very well, +and can be configured to operate with a variety of checksum widths. + + +3. The Basic Idea Behind CRC Algorithms +--------------------------------------- +Where might we go in our search for a more complex function than +summing? All sorts of schemes spring to mind. We could construct +tables using the digits of pi, or hash each incoming byte with all the +bytes in the register. We could even keep a large telephone book +on-line, and use each incoming byte combined with the register bytes +to index a new phone number which would be the next register value. +The possibilities are limitless. + +However, we do not need to go so far; the next arithmetic step +suffices. While addition is clearly not strong enough to form an +effective checksum, it turns out that division is, so long as the +divisor is about as wide as the checksum register. + +The basic idea of CRC algorithms is simply to treat the message as an +enormous binary number, to divide it by another fixed binary number, +and to make the remainder from this division the checksum. Upon +receipt of the message, the receiver can perform the same division and +compare the remainder with the "checksum" (transmitted remainder). + +Example: Suppose the the message consisted of the two bytes (6,23) as +in the previous example. These can be considered to be the hexadecimal +number 0617 which can be considered to be the binary number +0000-0110-0001-0111. Suppose that we use a checksum register one-byte +wide and use a constant divisor of 1001, then the checksum is the +remainder after 0000-0110-0001-0111 is divided by 1001. While in this +case, this calculation could obviously be performed using common +garden variety 32-bit registers, in the general case this is messy. So +instead, we'll do the division using good-'ol long division which you +learnt in school (remember?). Except this time, it's in binary: + + ...0000010101101 = 00AD = 173 = QUOTIENT + ____-___-___-___- +9= 1001 ) 0000011000010111 = 0617 = 1559 = DIVIDEND +DIVISOR 0000.,,....,.,,, + ----.,,....,.,,, + 0000,,....,.,,, + 0000,,....,.,,, + ----,,....,.,,, + 0001,....,.,,, + 0000,....,.,,, + ----,....,.,,, + 0011....,.,,, + 0000....,.,,, + ----....,.,,, + 0110...,.,,, + 0000...,.,,, + ----...,.,,, + 1100..,.,,, + 1001..,.,,, + ====..,.,,, + 0110.,.,,, + 0000.,.,,, + ----.,.,,, + 1100,.,,, + 1001,.,,, + ====,.,,, + 0111.,,, + 0000.,,, + ----.,,, + 1110,,, + 1001,,, + ====,,, + 1011,, + 1001,, + ====,, + 0101, + 0000, + ---- + 1011 + 1001 + ==== + 0010 = 02 = 2 = REMAINDER + + +In decimal this is "1559 divided by 9 is 173 with a remainder of 2". + +Although the effect of each bit of the input message on the quotient +is not all that significant, the 4-bit remainder gets kicked about +quite a lot during the calculation, and if more bytes were added to +the message (dividend) it's value could change radically again very +quickly. This is why division works where addition doesn't. + +In case you're wondering, using this 4-bit checksum the transmitted +message would look like this (in hexadecimal): 06172 (where the 0617 +is the message and the 2 is the checksum). The receiver would divide +0617 by 9 and see whether the remainder was 2. + + +4. Polynomical Arithmetic +------------------------- +While the division scheme described in the previous section is very +very similar to the checksumming schemes called CRC schemes, the CRC +schemes are in fact a bit weirder, and we need to delve into some +strange number systems to understand them. + +The word you will hear all the time when dealing with CRC algorithms +is the word "polynomial". A given CRC algorithm will be said to be +using a particular polynomial, and CRC algorithms in general are said +to be operating using polynomial arithmetic. What does this mean? + +Instead of the divisor, dividend (message), quotient, and remainder +(as described in the previous section) being viewed as positive +integers, they are viewed as polynomials with binary coefficients. +This is done by treating each number as a bit-string whose bits are +the coefficients of a polynomial. For example, the ordinary number 23 +(decimal) is 17 (hex) and 10111 binary and so it corresponds to the +polynomial: + + 1*x^4 + 0*x^3 + 1*x^2 + 1*x^1 + 1*x^0 + +or, more simply: + + x^4 + x^2 + x^1 + x^0 + +Using this technique, the message, and the divisor can be represented +as polynomials and we can do all our arithmetic just as before, except +that now it's all cluttered up with Xs. For example, suppose we wanted +to multiply 1101 by 1011. We can do this simply by multiplying the +polynomials: + +(x^3 + x^2 + x^0)(x^3 + x^1 + x^0) += (x^6 + x^4 + x^3 + + x^5 + x^3 + x^2 + + x^3 + x^1 + x^0) = x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0 + +At this point, to get the right answer, we have to pretend that x is 2 +and propagate binary carries from the 3*x^3 yielding + + x^7 + x^3 + x^2 + x^1 + x^0 + +It's just like ordinary arithmetic except that the base is abstracted +and brought into all the calculations explicitly instead of being +there implicitly. So what's the point? + +The point is that IF we pretend that we DON'T know what x is, we CAN'T +perform the carries. We don't know that 3*x^3 is the same as x^4 + x^3 +because we don't know that x is 2. In this true polynomial arithmetic +the relationship between all the coefficients is unknown and so the +coefficients of each power effectively become strongly typed; +coefficients of x^2 are effectively of a different type to +coefficients of x^3. + +With the coefficients of each power nicely isolated, mathematicians +came up with all sorts of different kinds of polynomial arithmetics +simply by changing the rules about how coefficients work. Of these +schemes, one in particular is relevant here, and that is a polynomial +arithmetic where the coefficients are calculated MOD 2 and there is no +carry; all coefficients must be either 0 or 1 and no carries are +calculated. This is called "polynomial arithmetic mod 2". Thus, +returning to the earlier example: + +(x^3 + x^2 + x^0)(x^3 + x^1 + x^0) += (x^6 + x^4 + x^3 + + x^5 + x^3 + x^2 + + x^3 + x^1 + x^0) += x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0 + +Under the other arithmetic, the 3*x^3 term was propagated using the +carry mechanism using the knowledge that x=2. Under "polynomial +arithmetic mod 2", we don't know what x is, there are no carries, and +all coefficients have to be calculated mod 2. Thus, the result +becomes: + += x^6 + x^5 + x^4 + x^3 + x^2 + x^1 + x^0 + +As Knuth [Knuth81] says (p.400): + + "The reader should note the similarity between polynomial + arithmetic and multiple-precision arithmetic (Section 4.3.1), where + the radix b is substituted for x. The chief difference is that the + coefficient u_k of x^k in polynomial arithmetic bears little or no + relation to its neighboring coefficients x^{k-1} [and x^{k+1}], so + the idea of "carrying" from one place to another is absent. In fact + polynomial arithmetic modulo b is essentially identical to multiple + precision arithmetic with radix b, except that all carries are + suppressed." + +Thus polynomical arithmetic mod 2 is just binary arithmetic mod 2 with +no carries. While polynomials provide useful mathematical machinery in +more analytical approaches to CRC and error-correction algorithms, for +the purposes of exposition they provide no extra insight and some +encumbrance and have been discarded in the remainder of this document +in favour of direct manipulation of the arithmetical system with which +they are isomorphic: binary arithmetic with no carry. + + +5. Binary Arithmetic with No Carries +------------------------------------ +Having dispensed with polynomials, we can focus on the real arithmetic +issue, which is that all the arithmetic performed during CRC +calculations is performed in binary with no carries. Often this is +called polynomial arithmetic, but as I have declared the rest of this +document a polynomial free zone, we'll have to call it CRC arithmetic +instead. As this arithmetic is a key part of CRC calculations, we'd +better get used to it. Here we go: + +Adding two numbers in CRC arithmetic is the same as adding numbers in +ordinary binary arithmetic except there is no carry. This means that +each pair of corresponding bits determine the corresponding output bit +without reference to any other bit positions. For example: + + 10011011 + +11001010 + -------- + 01010001 + -------- + +There are only four cases for each bit position: + + 0+0=0 + 0+1=1 + 1+0=1 + 1+1=0 (no carry) + +Subtraction is identical: + + 10011011 + -11001010 + -------- + 01010001 + -------- + +with + + 0-0=0 + 0-1=1 (wraparound) + 1-0=1 + 1-1=0 + +In fact, both addition and subtraction in CRC arithmetic is equivalent +to the XOR operation, and the XOR operation is its own inverse. This +effectively reduces the operations of the first level of power +(addition, subtraction) to a single operation that is its own inverse. +This is a very convenient property of the arithmetic. + +By collapsing of addition and subtraction, the arithmetic discards any +notion of magnitude beyond the power of its highest one bit. While it +seems clear that 1010 is greater than 10, it is no longer the case +that 1010 can be considered to be greater than 1001. To see this, note +that you can get from 1010 to 1001 by both adding and subtracting the +same quantity: + + 1010 = 1010 + 0011 + 1010 = 1010 - 0011 + +This makes nonsense of any notion of order. + +Having defined addition, we can move to multiplication and division. +Multiplication is absolutely straightforward, being the sum of the +first number, shifted in accordance with the second number. + + 1101 + x 1011 + ---- + 1101 + 1101. + 0000.. + 1101... + ------- + 1111111 Note: The sum uses CRC addition + ------- + +Division is a little messier as we need to know when "a number goes +into another number". To do this, we invoke the weak definition of +magnitude defined earlier: that X is greater than or equal to Y iff +the position of the highest 1 bit of X is the same or greater than the +position of the highest 1 bit of Y. Here's a fully worked division +(nicked from [Tanenbaum81]). + + 1100001010 + _______________ +10011 ) 11010110110000 + 10011,,.,,.... + -----,,.,,.... + 10011,.,,.... + 10011,.,,.... + -----,.,,.... + 00001.,,.... + 00000.,,.... + -----.,,.... + 00010,,.... + 00000,,.... + -----,,.... + 00101,.... + 00000,.... + -----,.... + 01011.... + 00000.... + -----.... + 10110... + 10011... + -----... + 01010.. + 00000.. + -----.. + 10100. + 10011. + -----. + 01110 + 00000 + ----- + 1110 = Remainder + +That's really it. Before proceeding further, however, it's worth our +while playing with this arithmetic a bit to get used to it. + +We've already played with addition and subtraction, noticing that they +are the same thing. Here, though, we should note that in this +arithmetic A+0=A and A-0=A. This obvious property is very useful +later. + +In dealing with CRC multiplication and division, it's worth getting a +feel for the concepts of MULTIPLE and DIVISIBLE. + +If a number A is a multiple of B then what this means in CRC +arithmetic is that it is possible to construct A from zero by XORing +in various shifts of B. For example, if A was 0111010110 and B was 11, +we could construct A from B as follows: + + 0111010110 + = .......11. + + ....11.... + + ...11..... + .11....... + +However, if A is 0111010111, it is not possible to construct it out of +various shifts of B (can you see why? - see later) so it is said to be +not divisible by B in CRC arithmetic. + +Thus we see that CRC arithmetic is primarily about XORing particular +values at various shifting offsets. + + +6. A Fully Worked Example +------------------------- +Having defined CRC arithmetic, we can now frame a CRC calculation as +simply a division, because that's all it is! This section fills in the +details and gives an example. + +To perform a CRC calculation, we need to choose a divisor. In maths +marketing speak the divisor is called the "generator polynomial" or +simply the "polynomial", and is a key parameter of any CRC algorithm. +It would probably be more friendly to call the divisor something else, +but the poly talk is so deeply ingrained in the field that it would +now be confusing to avoid it. As a compromise, we will refer to the +CRC polynomial as the "poly". Just think of this number as a sort of +parrot. "Hello poly!" + +You can choose any poly and come up with a CRC algorithm. However, +some polys are better than others, and so it is wise to stick with the +tried an tested ones. A later section addresses this issue. + +The width (position of the highest 1 bit) of the poly is very +important as it dominates the whole calculation. Typically, widths of +16 or 32 are chosen so as to simplify implementation on modern +computers. The width of a poly is the actual bit position of the +highest bit. For example, the width of 10011 is 4, not 5. For the +purposes of example, we will chose a poly of 10011 (of width W of 4). + +Having chosen a poly, we can proceed with the calculation. This is +simply a division (in CRC arithmetic) of the message by the poly. The +only trick is that W zero bits are appended to the message before the +CRC is calculated. Thus we have: + + Original message : 1101011011 + Poly : 10011 + Message after appending W zeros : 11010110110000 + +Now we simply divide the augmented message by the poly using CRC +arithmetic. This is the same division as before: + + 1100001010 = Quotient (nobody cares about the quotient) + _______________ +10011 ) 11010110110000 = Augmented message (1101011011 + 0000) +=Poly 10011,,.,,.... + -----,,.,,.... + 10011,.,,.... + 10011,.,,.... + -----,.,,.... + 00001.,,.... + 00000.,,.... + -----.,,.... + 00010,,.... + 00000,,.... + -----,,.... + 00101,.... + 00000,.... + -----,.... + 01011.... + 00000.... + -----.... + 10110... + 10011... + -----... + 01010.. + 00000.. + -----.. + 10100. + 10011. + -----. + 01110 + 00000 + ----- + 1110 = Remainder = THE CHECKSUM!!!! + +The division yields a quotient, which we throw away, and a remainder, +which is the calculated checksum. This ends the calculation. + +Usually, the checksum is then appended to the message and the result +transmitted. In this case the transmission would be: 11010110111110. + +At the other end, the receiver can do one of two things: + + a. Separate the message and checksum. Calculate the checksum for + the message (after appending W zeros) and compare the two + checksums. + + b. Checksum the whole lot (without appending zeros) and see if it + comes out as zero! + +These two options are equivalent. However, in the next section, we +will be assuming option b because it is marginally mathematically +cleaner. + +A summary of the operation of the class of CRC algorithms: + + 1. Choose a width W, and a poly G (of width W). + 2. Append W zero bits to the message. Call this M'. + 3. Divide M' by G using CRC arithmetic. The remainder is the checksum. + +That's all there is to it. + +7. Choosing A Poly +------------------ +Choosing a poly is somewhat of a black art and the reader is referred +to [Tanenbaum81] (p.130-132) which has a very clear discussion of this +issue. This section merely aims to put the fear of death into anyone +who so much as toys with the idea of making up their own poly. If you +don't care about why one poly might be better than another and just +want to find out about high-speed implementations, choose one of the +arithmetically sound polys listed at the end of this section and skip +to the next section. + +First note that the transmitted message T is a multiple of the poly. +To see this, note that 1) the last W bits of T is the remainder after +dividing the augmented (by zeros remember) message by the poly, and 2) +addition is the same as subtraction so adding the remainder pushes the +value up to the next multiple. Now note that if the transmitted +message is corrupted in transmission that we will receive T+E where E +is an error vector (and + is CRC addition (i.e. XOR)). Upon receipt of +this message, the receiver divides T+E by G. As T mod G is 0, (T+E) +mod G = E mod G. Thus, the capacity of the poly we choose to catch +particular kinds of errors will be determined by the set of multiples +of G, for any corruption E that is a multiple of G will be undetected. +Our task then is to find classes of G whose multiples look as little +like the kind of line noise (that will be creating the corruptions) as +possible. So let's examine the kinds of line noise we can expect. + +SINGLE BIT ERRORS: A single bit error means E=1000...0000. We can +ensure that this class of error is always detected by making sure that +G has at least two bits set to 1. Any multiple of G will be +constructed using shifting and adding and it is impossible to +construct a value with a single bit by shifting an adding a single +value with more than one bit set, as the two end bits will always +persist. + +TWO-BIT ERRORS: To detect all errors of the form 100...000100...000 +(i.e. E contains two 1 bits) choose a G that does not have multiples +that are 11, 101, 1001, 10001, 100001, etc. It is not clear to me how +one goes about doing this (I don't have the pure maths background), +but Tanenbaum assures us that such G do exist, and cites G with 1 bits +(15,14,1) turned on as an example of one G that won't divide anything +less than 1...1 where ... is 32767 zeros. + +ERRORS WITH AN ODD NUMBER OF BITS: We can catch all corruptions where +E has an odd number of bits by choosing a G that has an even number of +bits. To see this, note that 1) CRC multiplication is simply XORing a +constant value into a register at various offsets, 2) XORing is simply +a bit-flip operation, and 3) if you XOR a value with an even number of +bits into a register, the oddness of the number of 1 bits in the +register remains invariant. Example: Starting with E=111, attempt to +flip all three bits to zero by the repeated application of XORing in +11 at one of the two offsets (i.e. "E=E XOR 011" and "E=E XOR 110") +This is nearly isomorphic to the "glass tumblers" party puzzle where +you challenge someone to flip three tumblers by the repeated +application of the operation of flipping any two. Most of the popular +CRC polys contain an even number of 1 bits. (Note: Tanenbaum states +more specifically that all errors with an odd number of bits can be +caught by making G a multiple of 11). + +BURST ERRORS: A burst error looks like E=000...000111...11110000...00. +That is, E consists of all zeros except for a run of 1s somewhere +inside. This can be recast as E=(10000...00)(1111111...111) where +there are z zeros in the LEFT part and n ones in the RIGHT part. To +catch errors of this kind, we simply set the lowest bit of G to 1. +Doing this ensures that LEFT cannot be a factor of G. Then, so long as +G is wider than RIGHT, the error will be detected. See Tanenbaum for a +clearer explanation of this; I'm a little fuzzy on this one. Note: +Tanenbaum asserts that the probability of a burst of length greater +than W getting through is (0.5)^W. + +That concludes the section on the fine art of selecting polys. + +Some popular polys are: +16 bits: (16,12,5,0) [X25 standard] + (16,15,2,0) ["CRC-16"] +32 bits: (32,26,23,22,16,12,11,10,8,7,5,4,2,1,0) [Ethernet] + + +8. A Straightforward CRC Implementation +--------------------------------------- +That's the end of the theory; now we turn to implementations. To start +with, we examine an absolutely straight-down-the-middle boring +straightforward low-speed implementation that doesn't use any speed +tricks at all. We'll then transform that program progessively until we +end up with the compact table-driven code we all know and love and +which some of us would like to understand. + +To implement a CRC algorithm all we have to do is implement CRC +division. There are two reasons why we cannot simply use the divide +instruction of whatever machine we are on. The first is that we have +to do the divide in CRC arithmetic. The second is that the dividend +might be ten megabytes long, and todays processors do not have +registers that big. + +So to implement CRC division, we have to feed the message through a +division register. At this point, we have to be absolutely precise +about the message data. In all the following examples the message will +be considered to be a stream of bytes (each of 8 bits) with bit 7 of +each byte being considered to be the most significant bit (MSB). The +bit stream formed from these bytes will be the bit stream with the MSB +(bit 7) of the first byte first, going down to bit 0 of the first +byte, and then the MSB of the second byte and so on. + +With this in mind, we can sketch an implementation of the CRC +division. For the purposes of example, consider a poly with W=4 and +the poly=10111. Then, the perform the division, we need to use a 4-bit +register: + + 3 2 1 0 Bits + +---+---+---+---+ + Pop! <-- | | | | | <----- Augmented message + +---+---+---+---+ + + 1 0 1 1 1 = The Poly + +(Reminder: The augmented message is the message followed by W zero bits.) + +To perform the division perform the following: + + Load the register with zero bits. + Augment the message by appending W zero bits to the end of it. + While (more message bits) + Begin + Shift the register left by one bit, reading the next bit of the + augmented message into register bit position 0. + If (a 1 bit popped out of the register during step 3) + Register = Register XOR Poly. + End + The register now contains the remainder. + +(Note: In practice, the IF condition can be tested by testing the top + bit of R before performing the shift.) + +We will call this algorithm "SIMPLE". + +This might look a bit messy, but all we are really doing is +"subtracting" various powers (i.e. shiftings) of the poly from the +message until there is nothing left but the remainder. Study the +manual examples of long division if you don't understand this. + +It should be clear that the above algorithm will work for any width W. + + +9. A Table-Driven Implementation +-------------------------------- +The SIMPLE algorithm above is a good starting point because it +corresponds directly to the theory presented so far, and because it is +so SIMPLE. However, because it operates at the bit level, it is rather +awkward to code (even in C), and inefficient to execute (it has to +loop once for each bit). To speed it up, we need to find a way to +enable the algorithm to process the message in units larger than one +bit. Candidate quantities are nibbles (4 bits), bytes (8 bits), words +(16 bits) and longwords (32 bits) and higher if we can achieve it. Of +these, 4 bits is best avoided because it does not correspond to a byte +boundary. At the very least, any speedup should allow us to operate at +byte boundaries, and in fact most of the table driven algorithms +operate a byte at a time. + +For the purposes of discussion, let us switch from a 4-bit poly to a +32-bit one. Our register looks much the same, except the boxes +represent bytes instead of bits, and the Poly is 33 bits (one implicit +1 bit at the top and 32 "active" bits) (W=32). + + 3 2 1 0 Bytes + +----+----+----+----+ + Pop! <-- | | | | | <----- Augmented message + +----+----+----+----+ + + 1<------32 bits------> + +The SIMPLE algorithm is still applicable. Let us examine what it does. +Imagine that the SIMPLE algorithm is in full swing and consider the +top 8 bits of the 32-bit register (byte 3) to have the values: + + t7 t6 t5 t4 t3 t2 t1 t0 + +In the next iteration of SIMPLE, t7 will determine whether the Poly +will be XORed into the entire register. If t7=1, this will happen, +otherwise it will not. Suppose that the top 8 bits of the poly are g7 +g6.. g0, then after the next iteration, the top byte will be: + + t6 t5 t4 t3 t2 t1 t0 ?? ++ t7 * (g7 g6 g5 g4 g3 g2 g1 g0) [Reminder: + is XOR] + +The NEW top bit (that will control what happens in the next iteration) +now has the value t6 + t7*g7. The important thing to notice here is +that from an informational point of view, all the information required +to calculate the NEW top bit was present in the top TWO bits of the +original top byte. Similarly, the NEXT top bit can be calculated in +advance SOLELY from the top THREE bits t7, t6, and t5. In fact, in +general, the value of the top bit in the register in k iterations can +be calculated from the top k bits of the register. Let us take this +for granted for a moment. + +Consider for a moment that we use the top 8 bits of the register to +calculate the value of the top bit of the register during the next 8 +iterations. Suppose that we drive the next 8 iterations using the +calculated values (which we could perhaps store in a single byte +register and shift out to pick off each bit). Then we note three +things: + + * The top byte of the register now doesn't matter. No matter how + many times and at what offset the poly is XORed to the top 8 + bits, they will all be shifted out the right hand side during the + next 8 iterations anyway. + + + * The remaining bits will be shifted left one position and the + rightmost byte of the register will be shifted in the next byte + + AND + + * While all this is going on, the register will be subjected to a + series of XOR's in accordance with the bits of the pre-calculated + control byte. + +Now consider the effect of XORing in a constant value at various +offsets to a register. For example: + + 0100010 Register + ...0110 XOR this + ..0110. XOR this + 0110... XOR this + ------- + 0011000 + ------- + +The point of this is that you can XOR constant values into a register +to your heart's delight, and in the end, there will exist a value +which when XORed in with the original register will have the same +effect as all the other XORs. + +Perhaps you can see the solution now. Putting all the pieces together +we have an algorithm that goes like this: + + While (augmented message is not exhausted) + Begin + Examine the top byte of the register + Calculate the control byte from the top byte of the register + Sum all the Polys at various offsets that are to be XORed into + the register in accordance with the control byte + Shift the register left by one byte, reading a new message byte + into the rightmost byte of the register + XOR the summed polys to the register + End + +As it stands this is not much better than the SIMPLE algorithm. +However, it turns out that most of the calculation can be precomputed +and assembled into a table. As a result, the above algorithm can be +reduced to: + + While (augmented message is not exhaused) + Begin + Top = top_byte(Register); + Register = (Register << 24) | next_augmessage_byte; + Register = Register XOR precomputed_table[Top]; + End + +There! If you understand this, you've grasped the main idea of +table-driven CRC algorithms. The above is a very efficient algorithm +requiring just a shift, and OR, an XOR, and a table lookup per byte. +Graphically, it looks like this: + + 3 2 1 0 Bytes + +----+----+----+----+ + +-----<| | | | | <----- Augmented message + | +----+----+----+----+ + | ^ + | | + | XOR + | | + | 0+----+----+----+----+ Algorithm + v +----+----+----+----+ --------- + | +----+----+----+----+ 1. Shift the register left by + | +----+----+----+----+ one byte, reading in a new + | +----+----+----+----+ message byte. + | +----+----+----+----+ 2. Use the top byte just rotated + | +----+----+----+----+ out of the register to index + +----->+----+----+----+----+ the table of 256 32-bit values. + +----+----+----+----+ 3. XOR the table value into the + +----+----+----+----+ register. + +----+----+----+----+ 4. Goto 1 iff more augmented + +----+----+----+----+ message bytes. + 255+----+----+----+----+ + + +In C, the algorithm main loop looks like this: + + r=0; + while (len--) + { + byte t = (r >> 24) & 0xFF; + r = (r << 8) | *p++; + r^=table[t]; + } + +where len is the length of the augmented message in bytes, p points to +the augmented message, r is the register, t is a temporary, and table +is the computed table. This code can be made even more unreadable as +follows: + + r=0; while (len--) r = ((r << 8) | *p++) ^ t[(r >> 24) & 0xFF]; + +This is a very clean, efficient loop, although not a very obvious one +to the casual observer not versed in CRC theory. We will call this the +TABLE algorithm. + + +10. A Slightly Mangled Table-Driven Implementation +-------------------------------------------------- +Despite the terse beauty of the line + + r=0; while (len--) r = ((r << 8) | *p++) ^ t[(r >> 24) & 0xFF]; + +those optimizing hackers couldn't leave it alone. The trouble, you +see, is that this loop operates upon the AUGMENTED message and in +order to use this code, you have to append W/8 zero bytes to the end +of the message before pointing p at it. Depending on the run-time +environment, this may or may not be a problem; if the block of data +was handed to us by some other code, it could be a BIG problem. One +alternative is simply to append the following line after the above +loop, once for each zero byte: + + for (i=0; i> 24) & 0xFF]; + +This looks like a sane enough solution to me. However, at the further +expense of clarity (which, you must admit, is already a pretty scare +commodity in this code) we can reorganize this small loop further so +as to avoid the need to either augment the message with zero bytes, or +to explicitly process zero bytes at the end as above. To explain the +optimization, we return to the processing diagram given earlier. + + 3 2 1 0 Bytes + +----+----+----+----+ + +-----<| | | | | <----- Augmented message + | +----+----+----+----+ + | ^ + | | + | XOR + | | + | 0+----+----+----+----+ Algorithm + v +----+----+----+----+ --------- + | +----+----+----+----+ 1. Shift the register left by + | +----+----+----+----+ one byte, reading in a new + | +----+----+----+----+ message byte. + | +----+----+----+----+ 2. Use the top byte just rotated + | +----+----+----+----+ out of the register to index + +----->+----+----+----+----+ the table of 256 32-bit values. + +----+----+----+----+ 3. XOR the table value into the + +----+----+----+----+ register. + +----+----+----+----+ 4. Goto 1 iff more augmented + +----+----+----+----+ message bytes. + 255+----+----+----+----+ + +Now, note the following facts: + +TAIL: The W/4 augmented zero bytes that appear at the end of the + message will be pushed into the register from the right as all + the other bytes are, but their values (0) will have no effect + whatsoever on the register because 1) XORing with zero does not + change the target byte, and 2) the four bytes are never + propagated out the left side of the register where their + zeroness might have some sort of influence. Thus, the sole + function of the W/4 augmented zero bytes is to drive the + calculation for another W/4 byte cycles so that the end of the + REAL data passes all the way through the register. + +HEAD: If the initial value of the register is zero, the first four + iterations of the loop will have the sole effect of shifting in + the first four bytes of the message from the right. This is + because the first 32 control bits are all zero and so nothing is + XORed into the register. Even if the initial value is not zero, + the first 4 byte iterations of the algorithm will have the sole + effect of shifting the first 4 bytes of the message into the + register and then XORing them with some constant value (that is + a function of the initial value of the register). + +These facts, combined with the XOR property + + (A xor B) xor C = A xor (B xor C) + +mean that message bytes need not actually travel through the W/4 bytes +of the register. Instead, they can be XORed into the top byte just +before it is used to index the lookup table. This leads to the +following modified version of the algorithm. + + + +-----+----+----+----+----+ next message byte to yield an + +----+----+----+----+ index into the table ([0,255]). + +----+----+----+----+ 3. XOR the table value into the + +----+----+----+----+ register. + +----+----+----+----+ 4. Goto 1 iff more augmented + 255+----+----+----+----+ message bytes. + + +Note: The initial register value for this algorithm must be the +initial value of the register for the previous algorithm fed through +the table four times. Note: The table is such that if the previous +algorithm used 0, the new algorithm will too. + +This is an IDENTICAL algorithm and will yield IDENTICAL results. The C +code looks something like this: + + r=0; while (len--) r = (r<<8) ^ t[(r >> 24) ^ *p++]; + +and THIS is the code that you are likely to find inside current +table-driven CRC implementations. Some FF masks might have to be ANDed +in here and there for portability's sake, but basically, the above +loop is IT. We will call this the DIRECT TABLE ALGORITHM. + +During the process of trying to understand all this stuff, I managed +to derive the SIMPLE algorithm and the table-driven version derived +from that. However, when I compared my code with the code found in +real-implementations, I was totally bamboozled as to why the bytes +were being XORed in at the wrong end of the register! It took quite a +while before I figured out that theirs and my algorithms were actually +the same. Part of why I am writing this document is that, while the +link between division and my earlier table-driven code is vaguely +apparent, any such link is fairly well erased when you start pumping +bytes in at the "wrong end" of the register. It looks all wrong! + +If you've got this far, you not only understand the theory, the +practice, the optimized practice, but you also understand the real +code you are likely to run into. Could get any more complicated? Yes +it can. + + +11. "Reflected" Table-Driven Implementations +-------------------------------------------- +Despite the fact that the above code is probably optimized about as +much as it could be, this did not stop some enterprising individuals +from making things even more complicated. To understand how this +happened, we have to enter the world of hardware. + +DEFINITION: A value/register is reflected if it's bits are swapped +around its centre. For example: 0101 is the 4-bit reflection of 1010. +0011 is the reflection of 1100. +0111-0101-1010-1111-0010-0101-1011-1100 is the reflection of +0011-1101-1010-0100-1111-0101-1010-1110. + +Turns out that UARTs (those handy little chips that perform serial IO) +are in the habit of transmitting each byte with the least significant +bit (bit 0) first and the most significant bit (bit 7) last (i.e. +reflected). An effect of this convention is that hardware engineers +constructing hardware CRC calculators that operate at the bit level +took to calculating CRCs of bytes streams with each of the bytes +reflected within itself. The bytes are processed in the same order, +but the bits in each byte are swapped; bit 0 is now bit 7, bit 1 is +now bit 6, and so on. Now this wouldn't matter much if this convention +was restricted to hardware land. However it seems that at some stage +some of these CRC values were presented at the software level and +someone had to write some code that would interoperate with the +hardware CRC calculation. + +In this situation, a normal sane software engineer would simply +reflect each byte before processing it. However, it would seem that +normal sane software engineers were thin on the ground when this early +ground was being broken, because instead of reflecting the bytes, +whoever was responsible held down the byte and reflected the world, +leading to the following "reflected" algorithm which is identical to +the previous one except that everything is reflected except the input +bytes. + + + Message (non augmented) >-----+ + | + Bytes 0 1 2 3 v + +----+----+----+----+ | + | | | | |>----XOR + +----+----+----+----+ | + ^ | + | | + XOR | + | | + +----+----+----+----+0 | + +----+----+----+----+ v + +----+----+----+----+ | + +----+----+----+----+ | + +----+----+----+----+ | + +----+----+----+----+ | + +----+----+----+----+ | + +----+----+----+----+<-----+ + +----+----+----+----+ + +----+----+----+----+ + +----+----+----+----+ + +----+----+----+----+ + +----+----+----+----+255 + +Notes: + + * The table is identical to the one in the previous algorithm + except that each entry has been reflected. + + * The initial value of the register is the same as in the previous + algorithm except that it has been reflected. + + * The bytes of the message are processed in the same order as + before (i.e. the message itself is not reflected). + + * The message bytes themselves don't need to be explicitly + reflected, because everything else has been! + +At the end of execution, the register contains the reflection of the +final CRC value (remainder). Actually, I'm being rather hard on +whoever cooked this up because it seems that hardware implementations +of the CRC algorithm used the reflected checksum value and so +producing a reflected CRC was just right. In fact reflecting the world +was probably a good engineering solution - if a confusing one. + +We will call this the REFLECTED algorithm. + +Whether or not it made sense at the time, the effect of having +reflected algorithms kicking around the world's FTP sites is that +about half the CRC implementations one runs into are reflected and the +other half not. It's really terribly confusing. In particular, it +would seem to me that the casual reader who runs into a reflected, +table-driven implementation with the bytes "fed in the wrong end" +would have Buckley's chance of ever connecting the code to the concept +of binary mod 2 division. + +It couldn't get any more confusing could it? Yes it could. + + +12. "Reversed" Polys +-------------------- +As if reflected implementations weren't enough, there is another +concept kicking around which makes the situation bizaarly confusing. +The concept is reversed Polys. + +It turns out that the reflection of good polys tend to be good polys +too! That is, if G=11101 is a good poly value, then 10111 will be as +well. As a consequence, it seems that every time an organization (such +as CCITT) standardizes on a particularly good poly ("polynomial"), +those in the real world can't leave the poly's reflection alone +either. They just HAVE to use it. As a result, the set of "standard" +poly's has a corresponding set of reflections, which are also in use. +To avoid confusion, we will call these the "reversed" polys. + + X25 standard: 1-0001-0000-0010-0001 + X25 reversed: 1-0000-1000-0001-0001 + + CRC16 standard: 1-1000-0000-0000-0101 + CRC16 reversed: 1-0100-0000-0000-0011 + +Note that here it is the entire poly that is being reflected/reversed, +not just the bottom W bits. This is an important distinction. In the +reflected algorithm described in the previous section, the poly used +in the reflected algorithm was actually identical to that used in the +non-reflected algorithm; all that had happened is that the bytes had +effectively been reflected. As such, all the 16-bit/32-bit numbers in +the algorithm had to be reflected. In contrast, the ENTIRE poly +includes the implicit one bit at the top, and so reversing a poly is +not the same as reflecting its bottom 16 or 32 bits. + +The upshot of all this is that a reflected algorithm is not equivalent +to the original algorithm with the poly reflected. Actually, this is +probably less confusing than if they were duals. + +If all this seems a bit unclear, don't worry, because we're going to +sort it all out "real soon now". Just one more section to go before +that. + + +13. Initial and Final Values +---------------------------- +In addition to the complexity already seen, CRC algorithms differ from +each other in two other regards: + + * The initial value of the register. + + * The value to be XORed with the final register value. + +For example, the "CRC32" algorithm initializes its register to +FFFFFFFF and XORs the final register value with FFFFFFFF. + +Most CRC algorithms initialize their register to zero. However, some +initialize it to a non-zero value. In theory (i.e. with no assumptions +about the message), the initial value has no affect on the strength of +the CRC algorithm, the initial value merely providing a fixed starting +point from which the register value can progress. However, in +practice, some messages are more likely than others, and it is wise to +initialize the CRC algorithm register to a value that does not have +"blind spots" that are likely to occur in practice. By "blind spot" is +meant a sequence of message bytes that do not result in the register +changing its value. In particular, any CRC algorithm that initializes +its register to zero will have a blind spot of zero when it starts up +and will be unable to "count" a leading run of zero bytes. As a +leading run of zero bytes is quite common in real messages, it is wise +to initialize the algorithm register to a non-zero value. + + +14. Defining Algorithms Absolutely +---------------------------------- +At this point we have covered all the different aspects of +table-driven CRC algorithms. As there are so many variations on these +algorithms, it is worth trying to establish a nomenclature for them. +This section attempts to do that. + +We have seen that CRC algorithms vary in: + + * Width of the poly (polynomial). + * Value of the poly. + * Initial value for the register. + * Whether the bits of each byte are reflected before being processed. + * Whether the algorithm feeds input bytes through the register or + xors them with a byte from one end and then straight into the table. + * Whether the final register value should be reversed (as in reflected + versions). + * Value to XOR with the final register value. + +In order to be able to talk about particular CRC algorithms, we need +to able to define them more precisely than this. For this reason, the +next section attempts to provide a well-defined parameterized model +for CRC algorithms. To refer to a particular algorithm, we need then +simply specify the algorithm in terms of parameters to the model. + + +15. A Parameterized Model For CRC Algorithms +-------------------------------------------- +In this section we define a precise parameterized model CRC algorithm +which, for want of a better name, we will call the "Rocksoft^tm Model +CRC Algorithm" (and why not? Rocksoft^tm could do with some free +advertising :-). + +The most important aspect of the model algorithm is that it focusses +exclusively on functionality, ignoring all implementation details. The +aim of the exercise is to construct a way of referring precisely to +particular CRC algorithms, regardless of how confusingly they are +implemented. To this end, the model must be as simple and precise as +possible, with as little confusion as possible. + +The Rocksoft^tm Model CRC Algorithm is based essentially on the DIRECT +TABLE ALGORITHM specified earlier. However, the algorithm has to be +further parameterized to enable it to behave in the same way as some +of the messier algorithms out in the real world. + +To enable the algorithm to behave like reflected algorithms, we +provide a boolean option to reflect the input bytes, and a boolean +option to specify whether to reflect the output checksum value. By +framing reflection as an input/output transformation, we avoid the +confusion of having to mentally map the parameters of reflected and +non-reflected algorithms. + +An extra parameter allows the algorithm's register to be initialized +to a particular value. A further parameter is XORed with the final +value before it is returned. + +By putting all these pieces together we end up with the parameters of +the algorithm: + + NAME: This is a name given to the algorithm. A string value. + + WIDTH: This is the width of the algorithm expressed in bits. This + is one less than the width of the Poly. + + POLY: This parameter is the poly. This is a binary value that + should be specified as a hexadecimal number. The top bit of the + poly should be omitted. For example, if the poly is 10110, you + should specify 06. An important aspect of this parameter is that it + represents the unreflected poly; the bottom bit of this parameter + is always the LSB of the divisor during the division regardless of + whether the algorithm being modelled is reflected. + + INIT: This parameter specifies the initial value of the register + when the algorithm starts. This is the value that is to be assigned + to the register in the direct table algorithm. In the table + algorithm, we may think of the register always commencing with the + value zero, and this value being XORed into the register after the + N'th bit iteration. This parameter should be specified as a + hexadecimal number. + + REFIN: This is a boolean parameter. If it is FALSE, input bytes are + processed with bit 7 being treated as the most significant bit + (MSB) and bit 0 being treated as the least significant bit. If this + parameter is FALSE, each byte is reflected before being processed. + + REFOUT: This is a boolean parameter. If it is set to FALSE, the + final value in the register is fed into the XOROUT stage directly, + otherwise, if this parameter is TRUE, the final register value is + reflected first. + + XOROUT: This is an W-bit value that should be specified as a + hexadecimal number. It is XORed to the final register value (after + the REFOUT) stage before the value is returned as the official + checksum. + + CHECK: This field is not strictly part of the definition, and, in + the event of an inconsistency between this field and the other + field, the other fields take precedence. This field is a check + value that can be used as a weak validator of implementations of + the algorithm. The field contains the checksum obtained when the + ASCII string "123456789" is fed through the specified algorithm + (i.e. 313233... (hexadecimal)). + +With these parameters defined, the model can now be used to specify a +particular CRC algorithm exactly. Here is an example specification for +a popular form of the CRC-16 algorithm. + + Name : "CRC-16" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : BB3D + + +16. A Catalog of Parameter Sets for Standards +--------------------------------------------- +At this point, I would like to give a list of the specifications for +commonly used CRC algorithms. However, most of the algorithms that I +have come into contact with so far are specified in such a vague way +that this has not been possible. What I can provide is a list of polys +for various CRC standards I have heard of: + + X25 standard : 1021 [CRC-CCITT, ADCCP, SDLC/HDLC] + X25 reversed : 0811 + + CRC16 standard : 8005 + CRC16 reversed : 4003 [LHA] + + CRC32 : 04C11DB7 [PKZIP, AUTODIN II, Ethernet, FDDI] + +I would be interested in hearing from anyone out there who can tie +down the complete set of model parameters for any of these standards. + +However, a program that was kicking around seemed to imply the +following specifications. Can anyone confirm or deny them (or provide +the check values (which I couldn't be bothered coding up and +calculating)). + + Name : "CRC-16/CITT" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : False + RefOut : False + XorOut : 0000 + Check : ? + + + Name : "XMODEM" + Width : 16 + Poly : 8408 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : ? + + + Name : "ARC" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : ? + +Here is the specification for the CRC-32 algorithm which is reportedly +used in PKZip, AUTODIN II, Ethernet, and FDDI. + + Name : "CRC-32" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : CBF43926 + + +17. An Implementation of the Model Algorithm +-------------------------------------------- +Here is an implementation of the model algorithm in the C programming +language. The implementation consists of a header file (.h) and an +implementation file (.c). If you're reading this document in a +sequential scroller, you can skip this code by searching for the +string "Roll Your Own". + +To ensure that the following code is working, configure it for the +CRC-16 and CRC-32 algorithms given above and ensure that they produce +the specified "check" checksum when fed the test string "123456789" +(see earlier). + +/******************************************************************************/ +/* Start of crcmodel.h */ +/******************************************************************************/ +/* */ +/* Author : Ross Williams (ross@guest.adelaide.edu.au.). */ +/* Date : 3 June 1993. */ +/* Status : Public domain. */ +/* */ +/* Description : This is the header (.h) file for the reference */ +/* implementation of the Rocksoft^tm Model CRC Algorithm. For more */ +/* information on the Rocksoft^tm Model CRC Algorithm, see the document */ +/* titled "A Painless Guide to CRC Error Detection Algorithms" by Ross */ +/* Williams (ross@guest.adelaide.edu.au.). This document is likely to be in */ +/* "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia. */ +/* */ +/******************************************************************************/ +/* */ +/* How to Use This Package */ +/* ----------------------- */ +/* Step 1: Declare a variable of type cm_t. Declare another variable */ +/* (p_cm say) of type p_cm_t and initialize it to point to the first */ +/* variable (e.g. p_cm_t p_cm = &cm_t). */ +/* */ +/* Step 2: Assign values to the parameter fields of the structure. */ +/* If you don't know what to assign, see the document cited earlier. */ +/* For example: */ +/* p_cm->cm_width = 16; */ +/* p_cm->cm_poly = 0x8005L; */ +/* p_cm->cm_init = 0L; */ +/* p_cm->cm_refin = TRUE; */ +/* p_cm->cm_refot = TRUE; */ +/* p_cm->cm_xorot = 0L; */ +/* Note: Poly is specified without its top bit (18005 becomes 8005). */ +/* Note: Width is one bit less than the raw poly width. */ +/* */ +/* Step 3: Initialize the instance with a call cm_ini(p_cm); */ +/* */ +/* Step 4: Process zero or more message bytes by placing zero or more */ +/* successive calls to cm_nxt. Example: cm_nxt(p_cm,ch); */ +/* */ +/* Step 5: Extract the CRC value at any time by calling crc = cm_crc(p_cm); */ +/* If the CRC is a 16-bit value, it will be in the bottom 16 bits. */ +/* */ +/******************************************************************************/ +/* */ +/* Design Notes */ +/* ------------ */ +/* PORTABILITY: This package has been coded very conservatively so that */ +/* it will run on as many machines as possible. For example, all external */ +/* identifiers have been restricted to 6 characters and all internal ones to */ +/* 8 characters. The prefix cm (for Crc Model) is used as an attempt to avoid */ +/* namespace collisions. This package is endian independent. */ +/* */ +/* EFFICIENCY: This package (and its interface) is not designed for */ +/* speed. The purpose of this package is to act as a well-defined reference */ +/* model for the specification of CRC algorithms. If you want speed, cook up */ +/* a specific table-driven implementation as described in the document cited */ +/* above. This package is designed for validation only; if you have found or */ +/* implemented a CRC algorithm and wish to describe it as a set of parameters */ +/* to the Rocksoft^tm Model CRC Algorithm, your CRC algorithm implementation */ +/* should behave identically to this package under those parameters. */ +/* */ +/******************************************************************************/ + +/* The following #ifndef encloses this entire */ +/* header file, rendering it indempotent. */ +#ifndef CM_DONE +#define CM_DONE + +/******************************************************************************/ + +/* The following definitions are extracted from my style header file which */ +/* would be cumbersome to distribute with this package. The DONE_STYLE is the */ +/* idempotence symbol used in my style header file. */ + +#ifndef DONE_STYLE + +typedef unsigned long ulong; +typedef unsigned bool; +typedef unsigned char * p_ubyte_; + +#ifndef TRUE +#define FALSE 0 +#define TRUE 1 +#endif + +/* Change to the second definition if you don't have prototypes. */ +#define P_(A) A +/* #define P_(A) () */ + +/* Uncomment this definition if you don't have void. */ +/* typedef int void; */ + +#endif + +/******************************************************************************/ + +/* CRC Model Abstract Type */ +/* ----------------------- */ +/* The following type stores the context of an executing instance of the */ +/* model algorithm. Most of the fields are model parameters which must be */ +/* set before the first initializing call to cm_ini. */ +typedef struct + { + int cm_width; /* Parameter: Width in bits [8,32]. */ + ulong cm_poly; /* Parameter: The algorithm's polynomial. */ + ulong cm_init; /* Parameter: Initial register value. */ + bool cm_refin; /* Parameter: Reflect input bytes? */ + bool cm_refot; /* Parameter: Reflect output CRC? */ + ulong cm_xorot; /* Parameter: XOR this to output CRC. */ + + ulong cm_reg; /* Context: Context during execution. */ + } cm_t; +typedef cm_t *p_cm_t; + +/******************************************************************************/ + +/* Functions That Implement The Model */ +/* ---------------------------------- */ +/* The following functions animate the cm_t abstraction. */ + +void cm_ini P_((p_cm_t p_cm)); +/* Initializes the argument CRC model instance. */ +/* All parameter fields must be set before calling this. */ + +void cm_nxt P_((p_cm_t p_cm,int ch)); +/* Processes a single message byte [0,255]. */ + +void cm_blk P_((p_cm_t p_cm,p_ubyte_ blk_adr,ulong blk_len)); +/* Processes a block of message bytes. */ + +ulong cm_crc P_((p_cm_t p_cm)); +/* Returns the CRC value for the message bytes processed so far. */ + +/******************************************************************************/ + +/* Functions For Table Calculation */ +/* ------------------------------- */ +/* The following function can be used to calculate a CRC lookup table. */ +/* It can also be used at run-time to create or check static tables. */ + +ulong cm_tab P_((p_cm_t p_cm,int index)); +/* Returns the i'th entry for the lookup table for the specified algorithm. */ +/* The function examines the fields cm_width, cm_poly, cm_refin, and the */ +/* argument table index in the range [0,255] and returns the table entry in */ +/* the bottom cm_width bytes of the return value. */ + +/******************************************************************************/ + +/* End of the header file idempotence #ifndef */ +#endif + +/******************************************************************************/ +/* End of crcmodel.h */ +/******************************************************************************/ + + +/******************************************************************************/ +/* Start of crcmodel.c */ +/******************************************************************************/ +/* */ +/* Author : Ross Williams (ross@guest.adelaide.edu.au.). */ +/* Date : 3 June 1993. */ +/* Status : Public domain. */ +/* */ +/* Description : This is the implementation (.c) file for the reference */ +/* implementation of the Rocksoft^tm Model CRC Algorithm. For more */ +/* information on the Rocksoft^tm Model CRC Algorithm, see the document */ +/* titled "A Painless Guide to CRC Error Detection Algorithms" by Ross */ +/* Williams (ross@guest.adelaide.edu.au.). This document is likely to be in */ +/* "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia. */ +/* */ +/******************************************************************************/ +/* */ +/* Implementation Notes */ +/* -------------------- */ +/* To avoid inconsistencies, the specification of each function is not echoed */ +/* here. See the header file for a description of these functions. */ +/* This package is light on checking because I want to keep it short and */ +/* simple and portable (i.e. it would be too messy to distribute my entire */ +/* C culture (e.g. assertions package) with this package. */ +/* */ +/******************************************************************************/ + +#include "crcmodel.h" + +/******************************************************************************/ + +/* The following definitions make the code more readable. */ + +#define BITMASK(X) (1L << (X)) +#define MASK32 0xFFFFFFFFL +#define LOCAL static + +/******************************************************************************/ + +LOCAL ulong reflect P_((ulong v,int b)); +LOCAL ulong reflect (v,b) +/* Returns the value v with the bottom b [0,32] bits reflected. */ +/* Example: reflect(0x3e23L,3) == 0x3e26 */ +ulong v; +int b; +{ + int i; + ulong t = v; + for (i=0; i>=1; + } + return v; +} + +/******************************************************************************/ + +LOCAL ulong widmask P_((p_cm_t)); +LOCAL ulong widmask (p_cm) +/* Returns a longword whose value is (2^p_cm->cm_width)-1. */ +/* The trick is to do this portably (e.g. without doing <<32). */ +p_cm_t p_cm; +{ + return (((1L<<(p_cm->cm_width-1))-1L)<<1)|1L; +} + +/******************************************************************************/ + +void cm_ini (p_cm) +p_cm_t p_cm; +{ + p_cm->cm_reg = p_cm->cm_init; +} + +/******************************************************************************/ + +void cm_nxt (p_cm,ch) +p_cm_t p_cm; +int ch; +{ + int i; + ulong uch = (ulong) ch; + ulong topbit = BITMASK(p_cm->cm_width-1); + + if (p_cm->cm_refin) uch = reflect(uch,8); + p_cm->cm_reg ^= (uch << (p_cm->cm_width-8)); + for (i=0; i<8; i++) + { + if (p_cm->cm_reg & topbit) + p_cm->cm_reg = (p_cm->cm_reg << 1) ^ p_cm->cm_poly; + else + p_cm->cm_reg <<= 1; + p_cm->cm_reg &= widmask(p_cm); + } +} + +/******************************************************************************/ + +void cm_blk (p_cm,blk_adr,blk_len) +p_cm_t p_cm; +p_ubyte_ blk_adr; +ulong blk_len; +{ + while (blk_len--) cm_nxt(p_cm,*blk_adr++); +} + +/******************************************************************************/ + +ulong cm_crc (p_cm) +p_cm_t p_cm; +{ + if (p_cm->cm_refot) + return p_cm->cm_xorot ^ reflect(p_cm->cm_reg,p_cm->cm_width); + else + return p_cm->cm_xorot ^ p_cm->cm_reg; +} + +/******************************************************************************/ + +ulong cm_tab (p_cm,index) +p_cm_t p_cm; +int index; +{ + int i; + ulong r; + ulong topbit = BITMASK(p_cm->cm_width-1); + ulong inbyte = (ulong) index; + + if (p_cm->cm_refin) inbyte = reflect(inbyte,8); + r = inbyte << (p_cm->cm_width-8); + for (i=0; i<8; i++) + if (r & topbit) + r = (r << 1) ^ p_cm->cm_poly; + else + r<<=1; + if (p_cm->cm_refin) r = reflect(r,p_cm->cm_width); + return r & widmask(p_cm); +} + +/******************************************************************************/ +/* End of crcmodel.c */ +/******************************************************************************/ + + +18. Roll Your Own Table-Driven Implementation +--------------------------------------------- +Despite all the fuss I've made about understanding and defining CRC +algorithms, the mechanics of their high-speed implementation remains +trivial. There are really only two forms: normal and reflected. Normal +shifts to the left and covers the case of algorithms with Refin=FALSE +and Refot=FALSE. Reflected shifts to the right and covers algorithms +with both those parameters true. (If you want one parameter true and +the other false, you'll have to figure it out for yourself!) The +polynomial is embedded in the lookup table (to be discussed). The +other parameters, Init and XorOt can be coded as macros. Here is the +32-bit normal form (the 16-bit form is similar). + + unsigned long crc_normal (); + unsigned long crc_normal (blk_adr,blk_len) + unsigned char *blk_adr; + unsigned long blk_len; + { + unsigned long crc = INIT; + while (blk_len--) + crc = crctable[((crc>>24) ^ *blk_adr++) & 0xFFL] ^ (crc << 8); + return crc ^ XOROT; + } + +Here is the reflected form: + + unsigned long crc_reflected (); + unsigned long crc_reflected (blk_adr,blk_len) + unsigned char *blk_adr; + unsigned long blk_len; + { + unsigned long crc = INIT_REFLECTED; + while (blk_len--) + crc = crctable[(crc ^ *blk_adr++) & 0xFFL] ^ (crc >> 8)); + return crc ^ XOROT; + } + +Note: I have carefully checked the above two code fragments, but I +haven't actually compiled or tested them. This shouldn't matter to +you, as, no matter WHAT you code, you will always be able to tell if +you have got it right by running whatever you have created against the +reference model given earlier. The code fragments above are really +just a rough guide. The reference model is the definitive guide. + +Note: If you don't care much about speed, just use the reference model +code! + + +19. Generating A Lookup Table +----------------------------- +The only component missing from the normal and reversed code fragments +in the previous section is the lookup table. The lookup table can be +computed at run time using the cm_tab function of the model package +given earlier, or can be pre-computed and inserted into the C program. +In either case, it should be noted that the lookup table depends only +on the POLY and RefIn (and RefOt) parameters. Basically, the +polynomial determines the table, but you can generate a reflected +table too if you want to use the reflected form above. + +The following program generates any desired 16-bit or 32-bit lookup +table. Skip to the word "Summary" if you want to skip over this code. + + + +/******************************************************************************/ +/* Start of crctable.c */ +/******************************************************************************/ +/* */ +/* Author : Ross Williams (ross@guest.adelaide.edu.au.). */ +/* Date : 3 June 1993. */ +/* Version : 1.0. */ +/* Status : Public domain. */ +/* */ +/* Description : This program writes a CRC lookup table (suitable for */ +/* inclusion in a C program) to a designated output file. The program can be */ +/* statically configured to produce any table covered by the Rocksoft^tm */ +/* Model CRC Algorithm. For more information on the Rocksoft^tm Model CRC */ +/* Algorithm, see the document titled "A Painless Guide to CRC Error */ +/* Detection Algorithms" by Ross Williams (ross@guest.adelaide.edu.au.). This */ +/* document is likely to be in "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia. */ +/* */ +/******************************************************************************/ + +#include +#include +#include "crcmodel.h" + +/******************************************************************************/ + +/* TABLE PARAMETERS */ +/* ================ */ +/* The following parameters entirely determine the table to be generated. You */ +/* should need to modify only the definitions in this section before running */ +/* this program. */ +/* */ +/* TB_FILE is the name of the output file. */ +/* TB_WIDTH is the table width in bytes (either 2 or 4). */ +/* TB_POLY is the "polynomial", which must be TB_WIDTH bytes wide. */ +/* TB_REVER indicates whether the table is to be reversed (reflected). */ +/* */ +/* Example: */ +/* */ +/* #define TB_FILE "crctable.out" */ +/* #define TB_WIDTH 2 */ +/* #define TB_POLY 0x8005L */ +/* #define TB_REVER TRUE */ + +#define TB_FILE "crctable.out" +#define TB_WIDTH 4 +#define TB_POLY 0x04C11DB7L +#define TB_REVER TRUE + +/******************************************************************************/ + +/* Miscellaneous definitions. */ + +#define LOCAL static +FILE *outfile; +#define WR(X) fprintf(outfile,(X)) +#define WP(X,Y) fprintf(outfile,(X),(Y)) + +/******************************************************************************/ + +LOCAL void chk_err P_((char *)); +LOCAL void chk_err (mess) +/* If mess is non-empty, write it out and abort. Otherwise, check the error */ +/* status of outfile and abort if an error has occurred. */ +char *mess; +{ + if (mess[0] != 0 ) {printf("%s\n",mess); exit(EXIT_FAILURE);} + if (ferror(outfile)) {perror("chk_err"); exit(EXIT_FAILURE);} +} + +/******************************************************************************/ + +LOCAL void chkparam P_((void)); +LOCAL void chkparam () +{ + if ((TB_WIDTH != 2) && (TB_WIDTH != 4)) + chk_err("chkparam: Width parameter is illegal."); + if ((TB_WIDTH == 2) && (TB_POLY & 0xFFFF0000L)) + chk_err("chkparam: Poly parameter is too wide."); + if ((TB_REVER != FALSE) && (TB_REVER != TRUE)) + chk_err("chkparam: Reverse parameter is not boolean."); +} + +/******************************************************************************/ + +LOCAL void gentable P_((void)); +LOCAL void gentable () +{ + WR("/*****************************************************************/\n"); + WR("/* */\n"); + WR("/* CRC LOOKUP TABLE */\n"); + WR("/* ================ */\n"); + WR("/* The following CRC lookup table was generated automagically */\n"); + WR("/* by the Rocksoft^tm Model CRC Algorithm Table Generation */\n"); + WR("/* Program V1.0 using the following model parameters: */\n"); + WR("/* */\n"); + WP("/* Width : %1lu bytes. */\n", + (ulong) TB_WIDTH); + if (TB_WIDTH == 2) + WP("/* Poly : 0x%04lX */\n", + (ulong) TB_POLY); + else + WP("/* Poly : 0x%08lXL */\n", + (ulong) TB_POLY); + if (TB_REVER) + WR("/* Reverse : TRUE. */\n"); + else + WR("/* Reverse : FALSE. */\n"); + WR("/* */\n"); + WR("/* For more information on the Rocksoft^tm Model CRC Algorithm, */\n"); + WR("/* see the document titled \"A Painless Guide to CRC Error */\n"); + WR("/* Detection Algorithms\" by Ross Williams */\n"); + WR("/* (ross@guest.adelaide.edu.au.). This document is likely to be */\n"); + WR("/* in the FTP archive \"ftp.adelaide.edu.au/pub/rocksoft\". */\n"); + WR("/* */\n"); + WR("/*****************************************************************/\n"); + WR("\n"); + switch (TB_WIDTH) + { + case 2: WR("unsigned short crctable[256] =\n{\n"); break; + case 4: WR("unsigned long crctable[256] =\n{\n"); break; + default: chk_err("gentable: TB_WIDTH is invalid."); + } + chk_err(""); + + { + int i; + cm_t cm; + char *form = (TB_WIDTH==2) ? "0x%04lX" : "0x%08lXL"; + int perline = (TB_WIDTH==2) ? 8 : 4; + + cm.cm_width = TB_WIDTH*8; + cm.cm_poly = TB_POLY; + cm.cm_refin = TB_REVER; + + for (i=0; i<256; i++) + { + WR(" "); + WP(form,(ulong) cm_tab(&cm,i)); + if (i != 255) WR(","); + if (((i+1) % perline) == 0) WR("\n"); + chk_err(""); + } + + WR("};\n"); + WR("\n"); + WR("/*****************************************************************/\n"); + WR("/* End of CRC Lookup Table */\n"); + WR("/*****************************************************************/\n"); + WR(""); + chk_err(""); +} +} + +/******************************************************************************/ + +main () +{ + printf("\n"); + printf("Rocksoft^tm Model CRC Algorithm Table Generation Program V1.0\n"); + printf("-------------------------------------------------------------\n"); + printf("Output file is \"%s\".\n",TB_FILE); + chkparam(); + outfile = fopen(TB_FILE,"w"); chk_err(""); + gentable(); + if (fclose(outfile) != 0) + chk_err("main: Couldn't close output file."); + printf("\nSUCCESS: The table has been successfully written.\n"); +} + +/******************************************************************************/ +/* End of crctable.c */ +/******************************************************************************/ + +20. Summary +----------- +This document has provided a detailed explanation of CRC algorithms +explaining their theory and stepping through increasingly +sophisticated implementations ranging from simple bit shifting through +to byte-at-a-time table-driven implementations. The various +implementations of different CRC algorithms that make them confusing +to deal with have been explained. A parameterized model algorithm has +been described that can be used to precisely define a particular CRC +algorithm, and a reference implementation provided. Finally, a program +to generate CRC tables has been provided. + +21. Corrections +--------------- +If you think that any part of this document is unclear or incorrect, +or have any other information, or suggestions on how this document +could be improved, please context the author. In particular, I would +like to hear from anyone who can provide Rocksoft^tm Model CRC +Algorithm parameters for standard algorithms out there. + +A. Glossary +----------- +CHECKSUM - A number that has been calculated as a function of some +message. The literal interpretation of this word "Check-Sum" indicates +that the function should involve simply adding up the bytes in the +message. Perhaps this was what early checksums were. Today, however, +although more sophisticated formulae are used, the term "checksum" is +still used. + +CRC - This stands for "Cyclic Redundancy Code". Whereas the term +"checksum" seems to be used to refer to any non-cryptographic checking +information unit, the term "CRC" seems to be reserved only for +algorithms that are based on the "polynomial" division idea. + +G - This symbol is used in this document to represent the Poly. + +MESSAGE - The input data being checksummed. This is usually structured +as a sequence of bytes. Whether the top bit or the bottom bit of each +byte is treated as the most significant or least significant is a +parameter of CRC algorithms. + +POLY - This is my friendly term for the polynomial of a CRC. + +POLYNOMIAL - The "polynomial" of a CRC algorithm is simply the divisor +in the division implementing the CRC algorithm. + +REFLECT - A binary number is reflected by swapping all of its bits +around the central point. For example, 1101 is the reflection of 1011. + +ROCKSOFT^TM MODEL CRC ALGORITHM - A parameterized algorithm whose +purpose is to act as a solid reference for describing CRC algorithms. +Typically CRC algorithms are specified by quoting a polynomial. +However, in order to construct a precise implementation, one also +needs to know initialization values and so on. + +WIDTH - The width of a CRC algorithm is the width of its polynomical +minus one. For example, if the polynomial is 11010, the width would be +4 bits. The width is usually set to be a multiple of 8 bits. + +B. References +------------- +[Griffiths87] Griffiths, G., Carlyle Stones, G., "The Tea-Leaf Reader +Algorithm: An Efficient Implementation of CRC-16 and CRC-32", +Communications of the ACM, 30(7), pp.617-620. Comment: This paper +describes a high-speed table-driven implementation of CRC algorithms. +The technique seems to be a touch messy, and is superceded by the +Sarwete algorithm. + +[Knuth81] Knuth, D.E., "The Art of Computer Programming", Volume 2: +Seminumerical Algorithms, Section 4.6. + +[Nelson 91] Nelson, M., "The Data Compression Book", M&T Books, (501 +Galveston Drive, Redwood City, CA 94063), 1991, ISBN: 1-55851-214-4. +Comment: If you want to see a real implementation of a real 32-bit +checksum algorithm, look on pages 440, and 446-448. + +[Sarwate88] Sarwate, D.V., "Computation of Cyclic Redundancy Checks +via Table Look-Up", Communications of the ACM, 31(8), pp.1008-1013. +Comment: This paper describes a high-speed table-driven implementation +for CRC algorithms that is superior to the tea-leaf algorithm. +Although this paper describes the technique used by most modern CRC +implementations, I found the appendix of this paper (where all the +good stuff is) difficult to understand. + +[Tanenbaum81] Tanenbaum, A.S., "Computer Networks", Prentice Hall, +1981, ISBN: 0-13-164699-0. Comment: Section 3.5.3 on pages 128 to 132 +provides a very clear description of CRC codes. However, it does not +describe table-driven implementation techniques. + + +C. References I Have Detected But Haven't Yet Sighted +----------------------------------------------------- +Boudreau, Steen, "Cyclic Redundancy Checking by Program," AFIPS +Proceedings, Vol. 39, 1971. + +Davies, Barber, "Computer Networks and Their Protocols," J. Wiley & +Sons, 1979. + +Higginson, Kirstein, "On the Computation of Cyclic Redundancy Checks +by Program," The Computer Journal (British), Vol. 16, No. 1, Feb 1973. + +McNamara, J. E., "Technical Aspects of Data Communication," 2nd +Edition, Digital Press, Bedford, Massachusetts, 1982. + +Marton and Frambs, "A Cyclic Redundancy Checking (CRC) Algorithm," +Honeywell Computer Journal, Vol. 5, No. 3, 1971. + +Nelson M., "File verification using CRC", Dr Dobbs Journal, May 1992, +pp.64-67. + +Ramabadran T.V., Gaitonde S.S., "A tutorial on CRC computations", IEEE +Micro, Aug 1988. + +Schwaderer W.D., "CRC Calculation", April 85 PC Tech Journal, +pp.118-133. + +Ward R.K, Tabandeh M., "Error Correction and Detection, A Geometric +Approach" The Computer Journal, Vol. 27, No. 3, 1984, pp.246-253. + +Wecker, S., "A Table-Lookup Algorithm for Software Computation of +Cyclic Redundancy Check (CRC)," Digital Equipment Corporation +memorandum, 1974. + diff --git a/tmp/winners.csv b/tmp/winners.csv index 532277e87..e88294997 100644 --- a/tmp/winners.csv +++ b/tmp/winners.csv @@ -183,7 +183,7 @@ Thomas P John,Thomas_P_John,http://tomx.tripod.com/,null,thomaspjohn@hotmail.com Thomas Stewart,Thomas_Stewart,null,null,null,US,null); Thor Eldby,Thor_Eldby,null,null,null,null,null); Timo Poikola,Timo_Poikola,https://ig.fi/other/ioccc,null,timo@ig.fi,null,@timpoiko); -Tom Torfs,Tom Torfs,http://members.xoom.com/tomtorfs,null,null,null,null); +Tom Torfs,Tom_Torfs,https://web.archive.org/web/20010520021948/http://members.nbci.com/tomtorfs/,null,null,null); Tony Finch,Tony_Finch,http://dotat.at/,null,dot@dotat.at,null,null); Tsukasa Hamano,Tsukasa_Hamano,null,null,hamano@cuspy.org,null,null); Uri Goren,Uri_Goren,null,goren.uri@gmail.com,null,null); diff --git a/winners.html b/winners.html index 128b93d27..9e14cf7f3 100644 --- a/winners.html +++ b/winners.html @@ -1174,7 +1174,7 @@ Contest
  • Best non-chess game (2011 toledo)
    -
  • Tom Torfs -- http://members.xoom.com/tomtorfs +
  • Tom Torfs -- https://web.archive.org/web/20010520021948/http://members.nbci.com/tomtorfs/