|
| 1 | +\chapter{CRC algorithm implementations} |
| 2 | + |
| 3 | +\section{CRC-16/CCITT-FALSE}\label{sec:appendix_crc16ccitt_false} |
| 4 | + |
| 5 | +This algorithm is also known as CRC-16/AUTOSAR or CRC-16/IBM-3740. |
| 6 | +Not to be confused with CRC-16/KERMIT. |
| 7 | + |
| 8 | +This algorithm has the following parameters: |
| 9 | +\begin{itemize} |
| 10 | + \item width: 16 bits; |
| 11 | + \item polynomial: $\mathrm{1021}_{16}$; |
| 12 | + \item initial value: $\mathrm{FFFF}_{16}$; |
| 13 | + \item input not reflected; |
| 14 | + \item output not reflected; |
| 15 | + \item no output XOR; |
| 16 | + \item the native byte order is big endian. |
| 17 | +\end{itemize} |
| 18 | + |
| 19 | +The value for the input sequence $\left(49, 50, \ldots, 56, 57\right)$ is $\mathrm{29B1}_{16}$. |
| 20 | + |
| 21 | +\subsection{C++, bitwise} |
| 22 | + |
| 23 | +\begin{samepage} |
| 24 | +\begin{minted}{cpp} |
| 25 | +#include <array> |
| 26 | +#include <cstdint> |
| 27 | +#include <cstddef> |
| 28 | + |
| 29 | +class CRC16_CCITT_False final |
| 30 | +{ |
| 31 | +public: |
| 32 | + void add(const std::uint8_t byte) |
| 33 | + { |
| 34 | + value_ ^= static_cast<std::uint16_t>(byte) << 8U; |
| 35 | + for (std::uint8_t bit = 8; bit > 0; --bit) |
| 36 | + { |
| 37 | + if ((value_ & 0x8000U) != 0) |
| 38 | + { |
| 39 | + value_ = (value_ << 1U) ^ 0x1021U; |
| 40 | + } |
| 41 | + else |
| 42 | + { |
| 43 | + value_ = value_ << 1U; |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + void add(const std::uint8_t* bytes, std::size_t length) |
| 49 | + { |
| 50 | + while (length --> 0) |
| 51 | + { |
| 52 | + add(*bytes++); |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + [[nodiscard]] std::uint16_t get() const { return value_; } |
| 57 | + |
| 58 | + [[nodiscard]] std::array<std::uint8_t, 2> getBytes() const noexcept |
| 59 | + { |
| 60 | + const auto x = get(); |
| 61 | + return {static_cast<std::uint8_t>(x >> 8U), static_cast<std::uint8_t>(x & 0xFFU)}; |
| 62 | + } |
| 63 | + |
| 64 | +private: |
| 65 | + std::uint16_t value_ = 0xFFFFU; |
| 66 | +}; |
| 67 | +\end{minted} |
| 68 | +\end{samepage} |
| 69 | + |
| 70 | +\subsection{Python, bytewise} |
| 71 | + |
| 72 | +\begin{samepage} |
| 73 | +\begin{minted}{python} |
| 74 | +class CRC16CCITT: |
| 75 | + def __init__(self) -> None: |
| 76 | + self._value = 0xFFFF |
| 77 | + |
| 78 | + def add(self, data: bytes | bytearray | memoryview) -> None: |
| 79 | + val = self._value |
| 80 | + for x in data: |
| 81 | + val = ((val << 8) & 0xFFFF) ^ self._TABLE[(val >> 8) ^ x] |
| 82 | + self._value = val |
| 83 | + |
| 84 | + def check_residue(self) -> bool: |
| 85 | + return self._value == 0 |
| 86 | + |
| 87 | + @property |
| 88 | + def value(self) -> int: |
| 89 | + return self._value |
| 90 | + |
| 91 | + @property |
| 92 | + def value_as_bytes(self) -> bytes: |
| 93 | + return self.value.to_bytes(2, "big") |
| 94 | + |
| 95 | + _TABLE = [ |
| 96 | + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, |
| 97 | + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, |
| 98 | + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, |
| 99 | + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, |
| 100 | + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, |
| 101 | + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, |
| 102 | + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, |
| 103 | + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, |
| 104 | + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, |
| 105 | + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, |
| 106 | + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, |
| 107 | + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, |
| 108 | + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, |
| 109 | + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, |
| 110 | + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, |
| 111 | + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, |
| 112 | + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, |
| 113 | + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, |
| 114 | + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, |
| 115 | + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, |
| 116 | + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, |
| 117 | + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, |
| 118 | + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, |
| 119 | + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, |
| 120 | + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, |
| 121 | + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, |
| 122 | + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, |
| 123 | + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, |
| 124 | + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, |
| 125 | + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, |
| 126 | + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, |
| 127 | + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, |
| 128 | + ] |
| 129 | +\end{minted} |
| 130 | +\end{samepage} |
| 131 | + |
| 132 | +\newpage |
| 133 | +\section{CRC-32C}\label{sec:appendix_crc32c} |
| 134 | + |
| 135 | +This algorithm is also known as CRC-32/ISCSI, CRC-32/CASTAGNOLI, CRC-32/BASE91-C, or CRC-32/INTERLAKEN. |
| 136 | + |
| 137 | +This algorithm has the following parameters: |
| 138 | +\begin{itemize} |
| 139 | + \item width: 32 bits; |
| 140 | + \item polynomial: $\mathrm{1EDC6F41}_{16}$; |
| 141 | + \item initial value: $\mathrm{FFFFFFFF}_{16}$; |
| 142 | + \item input reflected; |
| 143 | + \item output reflected; |
| 144 | + \item output XOR: $\mathrm{FFFFFFFF}_{16}$; |
| 145 | + \item residue: $\mathrm{B798B438}_{16}$ before output XOR, $\mathrm{48674BC7}_{16}$ after output XOR; |
| 146 | + \item the native byte order is little endian. |
| 147 | +\end{itemize} |
| 148 | + |
| 149 | +The value for the input sequence $\left(49, 50, \ldots, 56, 57\right)$ is $\mathrm{E3069283}_{16}$. |
| 150 | + |
| 151 | +\subsection{C++, bitwise} |
| 152 | + |
| 153 | +\begin{samepage} |
| 154 | +\begin{minted}{cpp} |
| 155 | +#include <array> |
| 156 | +#include <cstdint> |
| 157 | +#include <cstddef> |
| 158 | + |
| 159 | +class CRC32C final |
| 160 | +{ |
| 161 | +public: |
| 162 | + static constexpr std::size_t Size = 4; |
| 163 | + |
| 164 | + void update(const std::uint8_t b) noexcept |
| 165 | + { |
| 166 | + value_ ^= static_cast<std::uint32_t>(b); |
| 167 | + for (auto i = 0U; i < 8U; i++) |
| 168 | + { |
| 169 | + value_ = ((value_ & 1U) != 0) ? ((value_ >> 1U) ^ ReflectedPoly) : (value_ >> 1U); |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + [[nodiscard]] std::uint32_t get() const noexcept { return value_ ^ Xor; } |
| 174 | + |
| 175 | + [[nodiscard]] std::array<std::uint8_t, Size> getBytes() const noexcept |
| 176 | + { |
| 177 | + const auto x = get(); |
| 178 | + return { |
| 179 | + static_cast<std::uint8_t>(x >> (8U * 0U)), |
| 180 | + static_cast<std::uint8_t>(x >> (8U * 1U)), |
| 181 | + static_cast<std::uint8_t>(x >> (8U * 2U)), |
| 182 | + static_cast<std::uint8_t>(x >> (8U * 3U)), |
| 183 | + }; |
| 184 | + } |
| 185 | + |
| 186 | + [[nodiscard]] auto isResidueCorrect() const noexcept { return value_ == Residue; } |
| 187 | + |
| 188 | +private: |
| 189 | + static constexpr std::uint32_t Xor = 0xFFFF'FFFFUL; |
| 190 | + static constexpr std::uint32_t ReflectedPoly = 0x82F6'3B78UL; |
| 191 | + static constexpr std::uint32_t Residue = 0xB798'B438UL; |
| 192 | + |
| 193 | + std::uint32_t value_ = Xor; |
| 194 | +}; |
| 195 | +\end{minted} |
| 196 | +\end{samepage} |
| 197 | + |
| 198 | +\subsection{Python, bytewise} |
| 199 | + |
| 200 | +\begin{samepage} |
| 201 | +\begin{minted}{python} |
| 202 | +class CRC32C: |
| 203 | + def __init__(self) -> None: |
| 204 | + self._value = 0xFFFFFFFF |
| 205 | + |
| 206 | + def add(self, data: bytes | bytearray | memoryview) -> None: |
| 207 | + val = self._value |
| 208 | + for x in data: |
| 209 | + val = (val >> 8) ^ self._TABLE[x ^ (val & 0xFF)] |
| 210 | + self._value = val |
| 211 | + |
| 212 | + def check_residue(self) -> bool: |
| 213 | + return self._value == 0xB798B438 # Checked before the output XOR is applied. |
| 214 | + |
| 215 | + @property |
| 216 | + def value(self) -> int: |
| 217 | + return self._value ^ 0xFFFFFFFF |
| 218 | + |
| 219 | + @property |
| 220 | + def value_as_bytes(self) -> bytes: |
| 221 | + return self.value.to_bytes(4, "little") |
| 222 | + |
| 223 | + _TABLE = [ |
| 224 | + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, |
| 225 | + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, |
| 226 | + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, |
| 227 | + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, |
| 228 | + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, |
| 229 | + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, |
| 230 | + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, |
| 231 | + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, |
| 232 | + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, |
| 233 | + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, |
| 234 | + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, |
| 235 | + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, |
| 236 | + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, |
| 237 | + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, |
| 238 | + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, |
| 239 | + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, |
| 240 | + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, |
| 241 | + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, |
| 242 | + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, |
| 243 | + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, |
| 244 | + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, |
| 245 | + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, |
| 246 | + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, |
| 247 | + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, |
| 248 | + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, |
| 249 | + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, |
| 250 | + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, |
| 251 | + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, |
| 252 | + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, |
| 253 | + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, |
| 254 | + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, |
| 255 | + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, |
| 256 | + ] |
| 257 | +\end{minted} |
| 258 | +\end{samepage} |
0 commit comments