RFC 3309

Stream Control Transmission Protocol (SCTP) Checksum Change

๐Ÿ“… published September 2002, from ietf

Okay bestie, let's talk about RFC 3309 ๐ŸŽ€ It's a Standards track doc from September 2002, written by J. Stone (Stanford), R. Stewart (Cisco Systems), and D. Otis (SANlight) ๐Ÿ’œ It updates RFC 2960, which is the big SCTP spec, and this one swaps out one piece of it ๐Ÿฆ‹ The title is below, and the status and copyright stuff comes right after.

Stream Control Transmission Protocol (SCTP) Checksum Change โœจ

Status of this Memo ๐Ÿ“œ

This document specifies an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐ŸŒธ If you want the current standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐Ÿซถ

Copyright (C) The Internet Society (2002). All Rights Reserved. ๐Ÿ’–

Abstract ๐Ÿฆ‹

SCTP currently uses an Adler-32 checksum, and that's the problem ๐Ÿ˜ญ For small packets, Adler-32 gives weak error detection. So this doc changes the checksum and updates SCTP to use a 32 bit CRC checksum ๐Ÿ”ฅ

Table of Contents ๐Ÿ—‚๏ธ

   1 Introduction ...................................................  2
   2 Checksum Procedures ............................................  3
   3 Security Considerations.........................................  6
   4 IANA Considerations.............................................  6
   5 Acknowledgments ................................................  6
   6 References .....................................................  7
   Appendix .........................................................  9
   Authors' Addresses ............................................... 16
   Full Copyright Statement ......................................... 17

1. Introduction ๐Ÿ’…

Okay so there's a fundamental weakness in SCTP's current Adler-32 checksum algorithm, and it was found by [STONE] ๐Ÿ˜ญ This document updates and replaces the Adler-32 checksum definition in [RFC 2960]. The tea is that there's no graceful transition mechanism for moving to the new checksum ๐Ÿ“ Implementations are expected to switch to the new algorithm immediately, and using the old algorithm is deprecated ๐Ÿ™ˆ

Here's the main vibe check: an effective checksum has to evenly and smoothly spread its input packets over the available check bits โœจ

Jonathan Stone, who analyzed Adler-32 for his doctoral thesis, emailed about this, and honestly he's so right ๐Ÿ‘‘ Here's what he said:

"Briefly, the problem is that, for very short packets, Adler32 is guaranteed to give poor coverage of the available bits. Don't take my word for it, ask Mark Adler. :-)

Adler-32 uses two 16-bit counters, s1 and s2. s1 is the sum of the input, taken as 8-bit bytes. s2 is a running sum of each value of s1. Both s1 and s2 are computed mod-65521 (the largest prime less than 2^16). Consider a packet of 128 bytes. The most that each byte can be is 255. There are only 128 bytes of input, so the greatest value which the s1 accumulator can have is 255 * 128 = 32640. So, for 128-byte packets, s1 never wraps. That is critical. Why?

The key is to consider the distribution of the s1 values, over some distribution of the values of the individual input bytes in each packet. Because s1 never wraps, s1 is simply the sum of the individual input bytes. (Even Doug's trick of adding 0x5555 doesn't help here, and an even larger value doesn't really help: we can get at most one mod-65521 reduction.)

Given the further assumption that the input bytes are drawn independently from some distribution (they probably aren't: for file system data, it's even worse than that!), the Central Limit Theorem tells us that that s1 will tend to have a normal distribution. That's bad: it tells us that the value of s1 will have hot-spots at around 128 times the mean of the input distribution: around 16k, assuming a uniform distribution. That's bad. We want the accumulator to wrap as many times as possible, so that the resulting sum has as close to a uniform distribution as possible. (I call this "fairness".)

So, for short packets, the Adler-32 s1 sum is guaranteed to be unfair. Why is that bad? It's bad because the space of valid packets -- input data, plus checksum values -- is also small. If all packets have checksum values very close to 32640, then the likelihood of even a 'small' error leaving a damaged packet with a valid checksum is higher than if all checksum values are equally likely."

Stone's point is basically that short packets get unfair Adler-32 sums, and that makes damaged packets way more likely to sneak through with a valid checksum ๐Ÿ˜ญ That's a whole mood.

Because of this built-in weakness, plus the fact that SCTP will first be used as a signaling transport protocol where signaling messages are usually less than 128 bytes, this document specifies a new checksum algorithm. It replaces Adler-32 with CRC-32c ๐Ÿฆ‹ Iconic glow-up, no notes.

1.1. Conventions ๐ŸŒˆ

The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL, when they appear in this document, are to be interpreted as described in [RFC2119] ๐Ÿ“–

Bit number order is defined in [RFC1700] ๐Ÿ”ข

2. Checksum Procedures ๐Ÿงš

The procedures described in section 2.1 of this document MUST be followed, replacing the current checksum defined in [RFC2960] โœจ

Also, any references within [RFC2960] to Adler-32 MUST be treated as a reference to CRC-32c ๐Ÿ’œ Section 2.1 of this document describes the new calculation and verification procedures that MUST be followed. No skipping, periodt ๐Ÿ’…

๐ŸŒˆ โœจ Part 1 done, but there's more coming, so the story keeps going โœจ ๐ŸŒˆ

2.1 Checksum Calculation ๐Ÿ’–

okay bestie, this is the part where SCTP gets serious about data integrity ๐Ÿซถ whenever an endpoint sends an SCTP packet, it MUST beef up the transmission by including a CRC-32c checksum value calculated over the packet. no skipping this, it's giving security guard ๐Ÿ’…

once the packet is built (SCTP common header plus one or more control or DATA chunks), the transmitter shall:

  1. Fill in the proper Verification Tag in the SCTP common header and set the Checksum field to 0's. ๐ŸŒธ
  2. Calculate the CRC-32c of the whole packet, including the SCTP common header and all the chunks. ๐Ÿงฎ
  3. Put the result into the Checksum field of the common header, and leave all the other bits alone. โœจ

when a packet comes in, the receiver MUST check the CRC-32c checksum first ๐Ÿ‘€

  1. Store the CRC-32c value it received. ๐Ÿ“ฆ
  2. Swap the 32 bits of the Checksum field in the received packet for all '0's, then calculate a CRC-32c over the entire received packet. ๐Ÿ”
  3. Check that the calculated CRC-32c matches the received one. If they don't match, the receiver MUST treat the packet as an invalid SCTP packet. ๐Ÿšซ

the default move for invalid SCTP packets is to silently discard them. ๐Ÿคซ no drama, just gone ๐Ÿฆ‹

any hardware implementation SHOULD be done in a way the software can verify. ๐Ÿ”ฅ

now the math bit ๐Ÿค“ we define a 'reflected value' as one that is the opposite of the machine's normal bit order. the 32-bit CRC is calculated as described for CRC-32c and uses the polynomial code 0x11EDC6F41 (Castagnoli93), or x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+x^8+x^6+x^0. it's a procedure similar to ETHERNET CRC [ITU32], just modified for transport-level usage ๐ŸŽ€

CRC computation runs on polynomial division. a message bit-string M gets turned into a polynomial, M(X), and the CRC is worked out from M(X) using polynomial arithmetic [Peterson 72]. ๐Ÿ’œ

with link-layer CRCs, the polynomial comes from the on-the-wire bit order: the first bit on the wire is the high-order coefficient. but SCTP is a transport-level protocol, so it can't know the actual serial-media bit order ๐Ÿ™ˆ and different links along the path between SCTP endpoints can use different link-level bit orders. chaotic, I know ๐Ÿ˜ญ

so we need a shared convention for turning SCTP messages into polynomials. here's the deal: bytes are read most-significant first, but within each byte, bits are read least-significant first. the first byte of the message gives the eight highest coefficients. inside each byte, the least-significant SCTP bit becomes the most significant polynomial coefficient of that byte, and the most-significant SCTP bit becomes the least significant one. this is sometimes called 'mirrored' or 'reflected' [Williams93]. CRC polynomials then get mapped back into SCTP transport-level byte values, using a consistent mapping ๐ŸŒˆ

the SCTP transport-level CRC value should be calculated like this:

  • CRC input data are assigned to a byte stream, numbered from 0 to N-1.
  • the transport-level byte stream is mapped to a polynomial value. An N-byte PDU with j bytes numbered 0 to N-1 is treated as the coefficients of a polynomial M(x) of order 8N-1, with bit 0 of byte j as the coefficient x^(8(N-j)-8) and bit 7 of byte j as the coefficient x^(8(N-j)-1).
  • the CRC remainder register starts with all 1s, and the CRC is computed with an algorithm that multiplies by x^32 and divides by the CRC polynomial at the same time.
  • the polynomial is multiplied by x^32 and divided by G(x), the generator polynomial, leaving a remainder R(x) of degree less than or equal to 31.
  • the coefficients of R(x) are read as a 32-bit sequence.
  • the bit sequence gets complemented. The result is the CRC polynomial.
  • the CRC polynomial maps back into SCTP transport-level bytes. The coefficient of x^31 is the value of bit 7 of SCTP byte 0, and the coefficient of x^24 is the value of bit 0 of byte 0. The coefficient of x^7 is bit 7 of byte 3, and the coefficient of x^0 is bit 0 of byte 3. The resulting four-byte transport-level sequence is the 32-bit SCTP checksum value. ๐Ÿง
IMPLEMENTATION NOTE: standards docs, textbooks, and vendor literature on CRCs often use a different formulation, where the remainder register starts at zero instead of all 1s, and the first 32 bits of the message get complemented instead. our long-division algorithm combines the initial multiplication by 2^32 and the long division into one simultaneous operation. for algorithms like that, and for messages longer than 64 bits, the two specs are precisely equivalent, and that equivalence is the whole point of this document ๐Ÿ’… implementors, be warned: both formulations are out there in the literature, sometimes with no restriction on the long-division algorithm. this document picks its formulation so that non-SCTP usage can use the same CRC algorithm to protect messages shorter than 64 bits ๐ŸŽ€

if SCTP could follow link-level CRC use, the CRC would be computed over the link-level bit stream. the first bit on the link maps to the highest-order coefficient, and so on down to the last link-level bit as the lowest-order coefficient. the CRC value would then be sent right after the input message as a link-level 'trailer'. the resulting bit stream would be ((M(X)x) * x^32) + (M(X)*x^32))/ G(x), which is divisible by G(X). that means a constant CRC remainder for 'good' packets ๐Ÿง  but RFC 2960 implementations have already spread everywhere, so the IETF discussions decided the benefit of a 'trailer' CRC didn't outweigh the cost of a massive change to protocol processing ๐Ÿ˜ญ plus, packets accepted by the SCTP 'header' CRC correspond one-to-one with packets accepted by a modified procedure using a 'trailer' CRC value, where the SCTP common checksum header is zero on transmission and received as zero. ๐Ÿฆ‹

there may be a computational advantage to validating the Association against the Verification Tag before doing the checksum, since invalid tags will usually lead to the same action as a bad checksum. the exceptions would be INIT and some SHUTDOWN-COMPLETE exchanges, plus a stale COOKIE-ECHO. these special exchanges must be small packets, so the checksum cost stays minimal ๐ŸŒธ


3 Security Considerations ๐Ÿ”

okay this one is short but NOT to be ignored ๐Ÿฅบ in general, the security considerations of RFC 2960 apply to the protocol with the new checksum as well. so everything RFC 2960 warned you about still applies, no exceptions. ๐Ÿ’€

4 IANA Considerations ๐Ÿ“‹

no IANA considerations are required in this document. nothing to register, nothing to assign, pure vibes โœจ

5 Acknowledgments ๐Ÿซถ

the authors would like to give a huge shoutout to the people who gave comments and input on the checksum issue ๐Ÿ’œ

Mark Adler, Ran Atkinson, Stephen Bailey, David Black, Scott Bradner, Mikael Degermark, Laurent Glaude, Klaus Gradischnig, Alf Heidermark, Jacob Heitz, Gareth Kiely, David Lehmann, Allision Mankin, Lyndon Ong, Craig Partridge, Vern Paxson, Kacheong Poon, Michael Ramalho, David Reed, Ian Rytina, Hanns Juergen Schwarzbauer, Chip Sharp, Bill Sommerfeld, Michael Tuexen, Jim Williams, Jim Wendt, Michael Welzl, Jonathan Wood, Lloyd Wood, Qiaobing Xie, La Monte Yarroll. ๐ŸŒŸ

special thanks to Dafna Scheinwald, Julian Satran, Pat Thaler, Matt Wakeley, and Vince Cavanna, for their work on selection criteria for polynomials and their examination of CRC polynomials, especially CRC-32c [Castagnoli93] ๐Ÿ‘‘

special thanks also to Mr. Ross Williams and his document [Williams93]. this non-formal take on the software side of CRCs helped authors who were new to CRC computation get it ๐Ÿงš the more formal treatments in [Blahut 94] or [Peterson 72] were also essential ๐Ÿ“š

6 References ๐Ÿ“š

[Castagnoli93] G. Castagnoli, S. Braeuer and M. Herrman, "Optimization of Cyclic Redundancy-Check Codes with 24 and 32 Parity Bits", IEEE Transactions on Communications, Vol. 41, No. 6, June 1993

[McKee75] H. McKee, "Improved {CRC} techniques detects erroneous leading and trailing 0's in transmitted data blocks", Computer Design Volume 14 Number 10 Pages 102-4,106, October 1975

[RFC1700] Reynolds, J. and J. Postel, "ASSIGNED NUMBERS", RFC 1700, October 1994.

[RFC2026] Bradner, S., "The Internet Standards Process -- Revision 3", BCP 9, RFC 2026, October 1996.

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C., Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., Zhang, L. and V. Paxson, "Stream Control Transmission Protocol," RFC 2960, October 2000.

[ITU32] ITU-T Recommendation V.42, "Error-correcting procedures for DCEs using asynchronous-to-synchronous conversion", section 8.1.1.6.2, October 1996.

7.1 Informative References ๐Ÿฆ‹

[STONE] Stone, J., "Checksums in the Internet", Doctoral dissertation - August 2001.

[Williams93] Williams, R., "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" - Internet publication, August 1993, http://www.geocities.com/SiliconValley/Pines/8659/crc.htm.

[Blahut 1994] R.E. Blahut, Theory and Practice of Error Control Codes, Addison-Wesley, 1994.

[Easics 2001] http://www.easics.be/webtools/crctool. Online tools for synthesis of CRC Verilog and VHDL.

[Feldmeier 95] David C. Feldmeier, Fast software implementation of error detection codes, IEEE Transactions on Networking, vol 3 no 6, pp 640-651, December, 1995.

[Glaise 1997] R. J. Glaise, A two-step computation of cyclic redundancy code CRC-32 for ATM networks, IBM Journal of Research and Development} vol 41 no 6, 1997. http://www.research.ibm.com/journal/rd/416/glaise.html.

[Prange 1957] E. Prange, Cyclic Error-Correcting codes in two symbols, Technical report AFCRC-TN-57-103, Air Force Cambridge Research Center, Cambridge, Mass. 1957.

[Peterson 1972] W. W. Peterson and E.J Weldon, Error Correcting Codes, 2nd. edition, MIT Press, Cambridge, Massachusetts.

[Shie2001] Ming-Der Shieh et. al, A Systematic Approach for Parallel CRC Computations. Journal of Information Science and Engineering, Vol.17 No.3, pp.445-461

[Sprachman2001] Michael Sprachman, Automatic Generation of Parallel CRC Circuits, IEEE Design & Test May-June 2001

Appendix โœจ

bestie, this appendix is just for info and it is NOT part of the standard ๐Ÿงš It's basically a tour of how people actually compute CRCs, because SCTP runs on everything from cellular-power telephony gadgets at tens of kilobits to local links at tens of gigabits ๐Ÿ˜ญ Implementors should look at their link speed and pick a CRC implementation from the big menu that fits their design point for size, cost, and throughput. There are so many ways to compute CRCs, and this appendix only surveys a few so you can get a vibe for the range ๐Ÿ’…

CRCs come from early work by Prange in the 1950s [Prange 57] ๐ŸŒธ The theory behind CRCs and how you pick a generator polynomial can be introduced either through Galois fields [Blahut 94] or as ideals of an algebra over cyclic codes [cite Peterson 72]. It's giving math main character energy ๐Ÿค“

One of the simplest techniques is direct bit-serial hardware, where the generator polynomial becomes the taps of a linear feedback shift register (LSFR) ๐Ÿฆ‹ LSFR computation follows straight from the math and is generally credited to Prange. You can even use tools that take a CRC generator polynomial and spit out synthesizable Verilog for CRC hardware [Easics 2001] โœจ

LSFRs don't scale well in speed, though, so people have explored a bunch of other techniques ๐Ÿ˜ฉ One trick uses the fact that the divisor of the polynomial long division, G, is known in advance. That means you can pre-compute lookup tables giving the polynomial remainder of multiple input bits at a time, typically 2, 4, or 8 bits of input ๐Ÿ“ This works in software or in hardware. Software to compute lookup tables yielding 2, 4, or 8 bits of result is freely available [Williams93] ๐Ÿ’œ

For multi-gigabit links, even those techniques might not be fast enough ๐Ÿ’€ One technique for computing CRCS at OC-48 rates is 'two-stage' CRC computation [Glaise 1997] โœจ The idea is to choose some multiple of G(x), namely G(x)H(x), so that the number of nonzero coefficients (the weight) of the product G(x)H(x) is minimized. A low-weight product polynomial is easy to implement in hardware as a divide-by-constant, which is very efficient ๐Ÿ”ฅ The first stage gives M(x)/ (G(x)H(x)) as its result. The second stage then divides the first-stage result by H(x), yielding (M(x)/(G(x)H(x)))/H(x). If H(x) is also relatively prime to G(x), this gives M(x)/G(x). More developments on this approach can be found in [Shie2001] and [Sprachman2001] ๐Ÿซถ

The literature also has a variety of software CRC implementations ๐ŸŒˆ One approach uses carefully tuned assembly code for direct polynomial division. [Feldmeier 95] reports that for low-weight polynomials, tuned polynomial arithmetic gives higher throughput than table-lookup algorithms ๐Ÿ‘‘ Even inside table-lookup algorithms, you can tune the table size, either for total cache footprint or, for space-restricted environments, to minimize total size ๐ŸŽ€

Now, implementors should keep in mind the bit ordering described in Section 2 ๐Ÿ™ˆ The ordering of bits within bytes for computing CRCs in SCTP is that the least significant bit of each byte is the most-significant polynomial coefficient (and vice-versa). This 'reflected' SCTP CRC bit ordering matches the on-the-wire bit order for Ethernet and other serial media, but it's the reverse of traditional Internet bit ordering ๐Ÿฆ‹

One technique to deal with this bit-reversal goes like this: sketch out a hardware implementation, assuming the bits are in CRC bit order, then perform a left-to-right inversion (mirror image) on the entire algorithm. (We'll defer the issue of byte order within words for a moment ๐Ÿงš) Then compute that "mirror image" in software. The CRC from the "mirror image" algorithm will be the bit-reversal of a correct hardware implementation. When the link-level media sends each byte, the byte goes out in the reverse of the host CPU bit-order. Serializing each byte of the "reflected" CRC value re-reverses the bit order, so in the end, each byte gets transmitted on-the-wire in the specified bit order ๐Ÿ’–

The following non-normative sample code (so not binding, just vibes โœจ) is taken from an open-source CRC generator [Williams93]. It uses the "mirroring" technique and yields a lookup table for SCTP CRC32-c with 256 entries, each 32 bits wide ๐Ÿ’… It's neither especially slow nor especially fast as software table-lookup CRCs go, but it has the advantage of working on both big-endian and little-endian CPUs, using the same (host-order) lookup tables, and using only the pre-defined ntohl() and htonl() operations ๐Ÿซถ The code is somewhat modified from [Williams93] to ensure portability between big-endian and little-endian architectures. (Note that if the byte endian-ness of the target architecture is known to be little-endian, the final bit-reversal and byte-reversal steps can be folded into a single operation ๐ŸŒธ)

/*************************************************************/
/* Note Definition for Ross Williams table generator would   */
/* be: TB_WIDTH=4, TB_POLLY=0x1EDC6F41, TB_REVER=TRUE        */
/* For Mr. Williams direct calculation code use the settings */
/* cm_width=32, cm_poly=0x1EDC6F41, cm_init=0xFFFFFFFF,      */
/* cm_refin=TRUE, cm_refot=TRUE, cm_xorort=0x00000000        */
/*************************************************************/

/* Example of the crc table file */
#ifndef __crc32cr_table_h__
#define __crc32cr_table_h__

#define CRC32C_POLY 0x1EDC6F41
#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])

unsigned long  crc_c[256] =
{
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
};

#endif

 /* Example of table build routine */



#include <stdio.h>
#include <stdlib.h>

#define OUTPUT_FILE   "crc32cr.h"
#define CRC32C_POLY    0x1EDC6F41L
FILE *tf;
unsigned long
reflect_32 (unsigned long b)
{
  int i;
  unsigned long rw = 0L;

  for (i = 0; i < 32; i++){
      if (b & 1)
        rw |= 1 << (31 - i);
      b >>= 1;
  }
  return (rw);
}

unsigned long
build_crc_table (int index)
{
  int i;
  unsigned long rb;

  rb = reflect_32 (index);

  for (i = 0; i < 8; i++){
      if (rb & 0x80000000L)
       rb = (rb << 1) ^ CRC32C_POLY;
      else
       rb <<= 1;
  }
  return (reflect_32 (rb));
}

main ()
{
  int i;

  printf ("\nGenerating CRC-32c table file <%s>\n", OUTPUT_FILE);
  if ((tf = fopen (OUTPUT_FILE, "w")) == NULL){
      printf ("Unable to open %s\n", OUTPUT_FILE);
      exit (1);
  }
  fprintf (tf, "#ifndef __crc32cr_table_h__\n");
  fprintf (tf, "#define __crc32cr_table_h__\n\n");
  fprintf (tf, "#define CRC32C_POLY 0x%08lX\n", CRC32C_POLY);
  fprintf (tf, "#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])\n");
  fprintf (tf, "\nunsigned long  crc_c[256] =\n{\n");
  for (i = 0; i < 256; i++){
      fprintf (tf, "0x%08lXL, ", build_crc_table (i));
      if ((i & 3) == 3)

        fprintf (tf, "\n");
  }
   fprintf (tf, "};\n\n#endif\n");

  if (fclose (tf) != 0)
    printf ("Unable to close <%s>." OUTPUT_FILE);
  else
    printf ("\nThe CRC-32c table has been written to <%s>.\n",
      OUTPUT_FILE);
}



/* Example of crc insertion */

#include "crc32cr.h"

unsigned long
generate_crc32c(unsigned char *buffer, unsigned int length)
{
  unsigned int i;
  unsigned long crc32 = ~0L;
  unsigned long result;
  unsigned char byte0,byte1,byte2,byte3;

  for (i = 0; i < length; i++){
      CRC32C(crc32, buffer[i]);
  }
  result = ~crc32;

  /*  result  now holds the negated polynomial remainder;
   *  since the table and algorithm is "reflected" [williams95].
   *  That is,  result has the same value as if we mapped the message
   *  to a polynomial, computed the host-bit-order polynomial
   *  remainder, performed final negation, then did an end-for-end
   *  bit-reversal.
   *  Note that a 32-bit bit-reversal is identical to four inplace
   *  8-bit reversals followed by an end-for-end byteswap.
   *  In other words, the bytes of each bit are in the right order,
   *  but the bytes have been byteswapped.  So we now do an explicit
   *  byteswap.  On a little-endian machine, this byteswap and
   *  the final ntohl cancel out and could be elided.
   */

  byte0 = result & 0xff;
  byte1 = (result>>8) & 0xff;
  byte2 = (result>>16) & 0xff;
  byte3 = (result>>24) & 0xff;
  crc32 = ((byte0 << 24) |
           (byte1 << 16) |
           (byte2 << 8)  |
           byte3);
  return ( crc32 );
}

int
insert_crc32(unsigned char *buffer, unsigned int length)
{
  SCTP_message *message;
  unsigned long crc32;
  message = (SCTP_message *) buffer;
  message->common_header.checksum = 0L;
  crc32 = generate_crc32c(buffer,length);
  /* and insert it into the message */
  message->common_header.checksum = htonl(crc32);
  return 1;
}

int
validate_crc32(unsigned char *buffer, unsigned int length)
{
  SCTP_message *message;
  unsigned int i;
  unsigned long original_crc32;
  unsigned long crc32 = ~0L;

  /* save and zero checksum */
  message = (SCTP_message *) buffer;
  original_crc32 = ntohl(message->common_header.checksum);
  message->common_header.checksum = 0L;
  crc32 = generate_crc32c(buffer,length);
  return ((original_crc32 == crc32)? 1 : -1);
}

Authors' Addresses ๐Ÿ’Œ

okay bestie, here are the lovely humans who wrote this, with their addresses so you can reach out ๐Ÿซถ

   Jonathan Stone
   Room 446, Mail code 9040
   Gates building 4A
   Stanford, Ca 94305

   EMail: jonathan@dsg.stanford.edu


   Randall R. Stewart
   24 Burning Bush Trail.
   Crystal Lake, IL 60012
   USA

   EMail: rrs@cisco.com


   Douglas Otis
   800 E. Middlefield
   Mountain View, CA 94043
   USA

   EMail: dotis@sanlight.net

this part is legal stuff, so I'm keeping the wording exactly as it is, no cap ๐Ÿ’œ

   Copyright (C) The Internet Society (2002).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement ๐Ÿซถ

okay last bit, and it's a sweet one ๐ŸŒธ the RFC Editor function is funded right now by the Internet Society, so a big thank you to them ๐Ÿ’–

That's the whole thing, bestie. Main character RFC energy, fully served ๐Ÿ‘‘โœจ

๐Ÿ“ฆ where this page comes from