| 2cd40ea1 Andy McCall ↶ | 1 | // Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0. |
| 2 | |
|
| 3 | //! This module calculates the keys needed for CRC calculations using PCLMULQDQ. |
|
| 4 | //! |
|
| 5 | //! Docs generated by Claude.ai |
|
| 6 | //! |
|
| 7 | //! # Overview |
|
| 8 | //! |
|
| 9 | //! This implements key generation for hardware-accelerated CRC computation using Intel's |
|
| 10 | //! PCLMULQDQ instruction (carryless multiplication). The keys enable a "fold-by-8" algorithm |
|
| 11 | //! that processes data in parallel chunks. |
|
| 12 | //! |
|
| 13 | //! # The PCLMULQDQ Algorithm |
|
| 14 | //! |
|
| 15 | //! Traditional CRC computation processes data byte-by-byte, which is slow. The PCLMULQDQ |
|
| 16 | //! instruction enables parallel processing by treating CRC computation as polynomial |
|
| 17 | //! multiplication in GF(2) (Galois Field with 2 elements, where addition is XOR). |
|
| 18 | //! |
|
| 19 | //! The algorithm works by: |
|
| 20 | //! 1. Loading multiple data chunks into SIMD registers |
|
| 21 | //! 2. Using precomputed keys to "fold" distant chunks together |
|
| 22 | //! 3. Reducing the result modulo the CRC polynomial |
|
| 23 | //! |
|
| 24 | //! # What Are "Keys"? |
|
| 25 | //! |
|
| 26 | //! Keys are precomputed constants representing x^n mod P(x), where: |
|
| 27 | //! - x^n represents a bit shift of n positions |
|
| 28 | //! - P(x) is the CRC polynomial |
|
| 29 | //! - The modulo operation is polynomial division in GF(2) |
|
| 30 | //! |
|
| 31 | //! Each key answers: "If I have a CRC value, and I want to shift it by N bits and reduce it, |
|
| 32 | //! what constant should I multiply by?" |
|
| 33 | //! |
|
| 34 | //! # The Distance Concept |
|
| 35 | //! |
|
| 36 | //! The "distance" or "exponent" refers to how many bits apart two data chunks are. When |
|
| 37 | //! processing data in 128-bit (16-byte) SIMD registers: |
|
| 38 | //! |
|
| 39 | //! - For fold-by-8: We process 8 registers (128 bytes) at once |
|
| 40 | //! - Keys at distance 32*N (CRC-32) or 64*N (CRC-64) let us combine chunks N registers apart |
|
| 41 | //! |
|
| 42 | //! Example for CRC-32: |
|
| 43 | //! - Distance 32*3 = 96 bits = 12 bytes (3 registers of 32-bit data) |
|
| 44 | //! - This key folds together data chunks that are 12 bytes apart |
|
| 45 | //! |
|
| 46 | //! The larger distances (32*63, 32*65) handle 256-byte chunks for very high throughput, such as |
|
| 47 | //! using AVX-512 VPCLMULQDQ. |
|
| 48 | |
|
| 49 | //! # Why CRC-32 and CRC-64 Implementations Differ So Greatly |
|
| 50 | //! |
|
| 51 | //! The implementations look very different, but they're solving the same problem at |
|
| 52 | //! different scales. Here are the key differences: |
|
| 53 | //! |
|
| 54 | //! ## 1. Polynomial Size |
|
| 55 | //! |
|
| 56 | //! - **CRC-32**: 33-bit polynomial (32 data bits + implicit leading 1) |
|
| 57 | //! - **CRC-64**: 65-bit polynomial (64 data bits + implicit leading 1) |
|
| 58 | //! |
|
| 59 | //! This fundamental difference cascades through every function. |
|
| 60 | //! |
|
| 61 | //! ## 2. Register Representation |
|
| 62 | //! |
|
| 63 | //! - **CRC-32**: Uses u64 with values in upper bits (e.g., 0x080000000 = bit 35) |
|
| 64 | //! - Has "headroom" above 32 bits for intermediate calculations |
|
| 65 | //! - Results often need alignment shifts (>> 31) |
|
| 66 | //! |
|
| 67 | //! - **CRC-64**: Uses u64 directly (e.g., 0x8000000000000000 = bit 63) |
|
| 68 | //! - No headroom - must use two u64s for μ calculation |
|
| 69 | //! - Results are naturally aligned, no extra shifts needed |
|
| 70 | //! |
|
| 71 | //! ## 3. Distance Scaling |
|
| 72 | //! |
|
| 73 | //! Both algorithms fold data in chunks, but the chunk sizes differ: |
|
| 74 | //! |
|
| 75 | //! | Concept | CRC-32 | CRC-64 | Why? | |
|
| 76 | //! |---------|--------|--------|------| |
|
| 77 | //! | Base unit | 32 bits (4 bytes) | 64 bits (8 bytes) | Matches polynomial width | |
|
| 78 | //! | Distance 1 | 96 bits (12 bytes) | 128 bits (16 bytes) | 3× vs 2× base unit | |
|
| 79 | //! | Large chunk | 2016 bits (252 bytes) | 2048 bits (256 bytes) | Aligned to cache lines | |
|
| 80 | //! |
|
| 81 | //! The multipliers are smaller for CRC-64 (2×, 3× vs 3×, 5×) because the base unit |
|
| 82 | //! is already larger. |
|
| 83 | //! |
|
| 84 | //! ## 4. Algorithm Variations |
|
| 85 | //! |
|
| 86 | //! - **Key generation**: CRC-32 uses simple if-check; CRC-64 uses bit-mask trick |
|
| 87 | //! - Both compute x^n mod P(x), but CRC-64's approach is more efficient |
|
| 88 | //! |
|
| 89 | //! - **Mu calculation**: CRC-32 uses single u64; CRC-64 needs double-register |
|
| 90 | //! - CRC-64 can't fit x^128 ÷ P(x) in one u64 |
|
| 91 | //! |
|
| 92 | //! - **Iteration counts**: Off-by-one differences everywhere |
|
| 93 | //! - Reflects different starting points and alignment requirements |
|
| 94 | //! |
|
| 95 | //! ## 5. Reflection Handling |
|
| 96 | //! |
|
| 97 | //! - **CRC-32**: Reverses 32 bits, then shifts by 31 |
|
| 98 | //! - **CRC-64**: Reverses 64 bits, no additional shift |
|
| 99 | //! |
|
| 100 | //! Both create the reflected representation needed for LSB-first CRCs, but |
|
| 101 | //! CRC-64's cleaner alignment means less post-processing. |
|
| 102 | //! |
|
| 103 | //! ## The Big Picture |
|
| 104 | //! |
|
| 105 | //! Despite the implementation differences, both are doing the same thing: |
|
| 106 | //! precomputing constants that let PCLMULQDQ fold distant data chunks together |
|
| 107 | //! efficiently. The differences arise from working with different-sized polynomials |
|
| 108 | //! within the constraints of fixed-size integer types (u64). |
|
| 109 | |
|
| 110 | |
|
| 111 | ||
| 112 | use ; |
|
| 113 | ||
| 114 | /// Exponents (bit distances) for CRC-16 key generation. |
|
| 115 | /// |
|
| 116 | /// CRC-16 uses the same exponents as CRC-32 because the folding algorithm operates on |
|
| 117 | /// 128-bit SIMD registers regardless of CRC width. CRC-16 computation is performed by |
|
| 118 | /// scaling 16-bit values to 32-bit space, using the CRC-32 algorithm infrastructure, |
|
| 119 | /// and then scaling the result back to 16 bits. |
|
| 120 | /// |
|
| 121 | /// See CRC32_EXPONENTS for detailed documentation of the exponent values. |
|
| 122 | const CRC16_EXPONENTS: = |
|
| 123 | |
|
| 124 | |
|
| 125 | |
|
| 126 | |
|
| 127 | |
|
| 128 | |
|
| 129 | |
|
| 130 | |
|
| 131 | |
|
| 132 | |
|
| 133 | |
|
| 134 | |
|
| 135 | |
|
| 136 | |
|
| 137 | |
|
| 138 | |
|
| 139 | |
|
| 140 | |
|
| 141 | |
|
| 142 | |
|
| 143 | |
|
| 144 | |
|
| 145 | |
|
| 146 | ; |
|
| 147 | ||
| 148 | /// Exponents (bit distances) for CRC-32 key generation. |
|
| 149 | /// |
|
| 150 | /// These represent bit distances for the fold-by-8 algorithm. Each exponent defines |
|
| 151 | /// how many bits apart two data chunks are when folding. |
|
| 152 | /// |
|
| 153 | /// # Why These Specific Values? |
|
| 154 | /// |
|
| 155 | /// For CRC-32, the polynomial is 33 bits (including the implicit leading 1), so we work |
|
| 156 | /// with 32-bit data chunks. The exponents are designed to efficiently fold 128-byte chunks: |
|
| 157 | /// |
|
| 158 | /// - Indices 1-4: Primary folding constants for 8-chunk (128-byte) processing |
|
| 159 | /// - 32*3, 32*5: Used for folding the first half |
|
| 160 | /// - 32*31, 32*33: Used for folding the second half |
|
| 161 | /// - Indices 5-6: Short-distance folding |
|
| 162 | /// - 32*3, 32*2: For final reduction stages |
|
| 163 | /// - Indices 7-8: Special values (mu and polynomial) computed separately |
|
| 164 | /// - Indices 9-20: Additional folding distances for progressive reduction |
|
| 165 | /// - These allow folding from 8 chunks down to 4, then 2, then 1 |
|
| 166 | /// - Indices 21-22: Large distances for 256-byte chunk processing, such as using AVX-512 VPCLMULQDQ |
|
| 167 | /// - 32*63 = 2016 bits (252 bytes) |
|
| 168 | /// - 32*65 = 2080 bits (260 bytes) |
|
| 169 | /// - These enable very high-throughput processing of large buffers |
|
| 170 | const CRC32_EXPONENTS: = |
|
| 171 | |
|
| 172 | |
|
| 173 | |
|
| 174 | |
|
| 175 | |
|
| 176 | |
|
| 177 | |
|
| 178 | |
|
| 179 | |
|
| 180 | |
|
| 181 | |
|
| 182 | |
|
| 183 | |
|
| 184 | |
|
| 185 | |
|
| 186 | |
|
| 187 | |
|
| 188 | |
|
| 189 | |
|
| 190 | |
|
| 191 | |
|
| 192 | |
|
| 193 | |
|
| 194 | ; |
|
| 195 | ||
| 196 | /// Exponents (bit distances) for CRC-64 key generation. |
|
| 197 | /// |
|
| 198 | /// Similar to CRC32_EXPONENTS but scaled for 64-bit CRC polynomials. |
|
| 199 | /// |
|
| 200 | /// # Why Different From CRC-32? |
|
| 201 | /// |
|
| 202 | /// CRC-64 uses a 65-bit polynomial (64 bits + implicit leading 1), so: |
|
| 203 | /// - Data chunks are 64 bits instead of 32 |
|
| 204 | /// - All distances are in multiples of 64 instead of 32 |
|
| 205 | /// - The actual byte distances are larger (64*N bits = 8*N bytes) |
|
| 206 | /// |
|
| 207 | /// # Distance Comparison |
|
| 208 | /// |
|
| 209 | /// | Index | CRC-32 Distance | CRC-64 Distance | Purpose | |
|
| 210 | /// |-------|-----------------|-----------------|----------------------| |
|
| 211 | /// | 1 | 96 bits (12B) | 128 bits (16B) | Primary fold | |
|
| 212 | /// | 2 | 160 bits (20B) | 192 bits (24B) | Primary fold | |
|
| 213 | /// | 21 | 2016 bits (252B)| 2048 bits (256B)| Large chunk folding | |
|
| 214 | /// |
|
| 215 | /// The smaller multipliers (2, 3 vs 3, 5) reflect the larger base unit (64 vs 32 bits). |
|
| 216 | const CRC64_EXPONENTS: = |
|
| 217 | |
|
| 218 | |
|
| 219 | |
|
| 220 | |
|
| 221 | |
|
| 222 | |
|
| 223 | |
|
| 224 | |
|
| 225 | |
|
| 226 | |
|
| 227 | |
|
| 228 | |
|
| 229 | |
|
| 230 | |
|
| 231 | |
|
| 232 | |
|
| 233 | |
|
| 234 | |
|
| 235 | |
|
| 236 | |
|
| 237 | |
|
| 238 | |
|
| 239 | |
|
| 240 | ; |
|
| 241 | ||
| 242 | /// Generates the 23 keys needed to calculate CRCs for a given polynomial using PCLMULQDQ when |
|
| 243 | /// folding by 8. |
|
| 244 | |
|
| 245 | |
|
| 246 | |
|
| 247 | |
|
| 248 | |
|
| 249 | |
|
| 250 | |
|
| 251 | |
|
| 252 | |
|
| 253 | |
|
| 254 | |
|
| 255 | |
|
| 256 | |
|
| 257 | |
|
| 258 | |
|
| 259 | |
|
| 260 | |
|
| 261 | |
|
| 262 | |
|
| 263 | |
|
| 264 | |
|
| 265 | |
|
| 266 | |
|
| 267 | |
|
| 268 | |
|
| 269 | |
|
| 270 | |
|
| 271 | |
|
| 272 | |
|
| 273 | |
|
| 274 | |
|
| 275 | ||
| 276 | |
|
| 277 | |
|
| 278 | |
|
| 279 | |
|
| 280 | |
|
| 281 | |
|
| 282 | |
|
| 283 | |
|
| 284 | |
|
| 285 | |
|
| 286 | |
|
| 287 | ||
| 288 | /// Computes a CRC-16 folding key for a given bit distance (exponent). |
|
| 289 | /// |
|
| 290 | /// # Algorithm |
|
| 291 | /// |
|
| 292 | /// CRC-16 key generation uses the same algorithm as CRC-32 because CRC-16 computation |
|
| 293 | /// is performed by scaling 16-bit values to 32-bit space. The polynomial is already |
|
| 294 | /// scaled to 32-bit space (poly << 16 | 1 << 32) before this function is called. |
|
| 295 | /// |
|
| 296 | /// 1. Start with x^32 (represented as 0x080000000, bit 35 set) |
|
| 297 | /// 2. Multiply by x repeatedly (left shift), reducing modulo P(x) each time |
|
| 298 | /// 3. After (exponent - 31) iterations, we have x^exponent mod P(x) |
|
| 299 | /// |
|
| 300 | /// # Reflection |
|
| 301 | /// |
|
| 302 | /// For reflected CRC-16, we bit-reverse the 16-bit result and shift right by 31 bits |
|
| 303 | /// to align it properly for PCLMULQDQ operations. |
|
| 304 | |
|
| 305 | |
|
| 306 | |
|
| 307 | |
|
| 308 | |
|
| 309 | |
|
| 310 | |
|
| 311 | |
|
| 312 | |
|
| 313 | |
|
| 314 | |
|
| 315 | |
|
| 316 | |
|
| 317 | |
|
| 318 | |
|
| 319 | |
|
| 320 | |
|
| 321 | |
|
| 322 | |
|
| 323 | |
|
| 324 | |
|
| 325 | ||
| 326 | /// Computes a CRC-32 folding key for a given bit distance (exponent). |
|
| 327 | /// |
|
| 328 | /// # Algorithm |
|
| 329 | /// |
|
| 330 | /// This calculates x^exponent mod P(x) where P(x) is the CRC-32 polynomial. |
|
| 331 | /// |
|
| 332 | /// 1. Start with x^32 (represented as 0x080000000, bit 35 set) |
|
| 333 | /// 2. Multiply by x repeatedly (left shift), reducing modulo P(x) each time |
|
| 334 | /// 3. After (exponent - 31) iterations, we have x^exponent mod P(x) |
|
| 335 | /// |
|
| 336 | /// # Why Start at x^32? |
|
| 337 | /// |
|
| 338 | /// For CRC-32, we're working with 33-bit polynomials (32 data bits + leading 1). |
|
| 339 | /// Starting at x^32 (bit 35 in a 36-bit representation) gives us the right alignment |
|
| 340 | /// for the first reduction step. |
|
| 341 | /// |
|
| 342 | /// # Why exponent - 31? |
|
| 343 | /// |
|
| 344 | /// We start at x^32 and want to reach x^exponent, so we need (exponent - 32) more |
|
| 345 | /// multiplications. But the first shift happens before the first check, so it's |
|
| 346 | /// actually (exponent - 31) iterations. |
|
| 347 | /// |
|
| 348 | /// # Reflection |
|
| 349 | /// |
|
| 350 | /// If the CRC is reflected (LSB-first), we bit-reverse the result and shift right |
|
| 351 | /// by 31 bits to align it properly for PCLMULQDQ operations. |
|
| 352 | |
|
| 353 | |
|
| 354 | |
|
| 355 | |
|
| 356 | |
|
| 357 | |
|
| 358 | |
|
| 359 | |
|
| 360 | |
|
| 361 | |
|
| 362 | |
|
| 363 | |
|
| 364 | |
|
| 365 | |
|
| 366 | |
|
| 367 | |
|
| 368 | |
|
| 369 | |
|
| 370 | |
|
| 371 | |
|
| 372 | |
|
| 373 | ||
| 374 | /// Computes a CRC-64 folding key for a given bit distance (exponent). |
|
| 375 | /// |
|
| 376 | /// # Algorithm |
|
| 377 | /// |
|
| 378 | /// Similar to CRC-32 but adapted for 64-bit polynomials: |
|
| 379 | /// |
|
| 380 | /// 1. Start with x^63 (represented as 0x8000000000000000, bit 63 set) |
|
| 381 | /// 2. Multiply by x repeatedly, reducing modulo P(x) each time |
|
| 382 | /// 3. After (exponent - 63 or - 64) iterations, we have x^exponent mod P(x) |
|
| 383 | /// |
|
| 384 | /// # Key Differences From CRC-32 |
|
| 385 | /// |
|
| 386 | /// 1. **Starting point**: 0x8000000000000000 vs 0x080000000 |
|
| 387 | /// - CRC-64 uses bit 63 (the MSB of a 64-bit value) |
|
| 388 | /// - CRC-32 uses bit 35 (extended beyond 32 bits) |
|
| 389 | /// |
|
| 390 | /// 2. **Iteration count**: Depends on reflection |
|
| 391 | /// - Reflected: exponent - 64 (because we iterate from x^64) |
|
| 392 | /// - Non-reflected: exponent - 63 (because we start at x^63) |
|
| 393 | /// |
|
| 394 | /// 3. **Reduction step**: Uses a more efficient formulation |
|
| 395 | /// - `(n << 1) ^ ((0_u64.wrapping_sub(n >> 63)) & polynomial)` |
|
| 396 | /// - This is equivalent to: if MSB is set, shift and XOR with poly; else just shift |
|
| 397 | /// - The wrapping_sub creates a mask of all 1s or all 0s based on the MSB |
|
| 398 | /// |
|
| 399 | /// 4. **No additional shift in result**: The result is already properly aligned |
|
| 400 | /// - CRC-32 needs `>> 31` adjustment for reflected case |
|
| 401 | /// - CRC-64 doesn't need this because it operates on full 64-bit values |
|
| 402 | |
|
| 403 | |
|
| 404 | |
|
| 405 | |
|
| 406 | |
|
| 407 | |
|
| 408 | |
|
| 409 | |
|
| 410 | |
|
| 411 | |
|
| 412 | |
|
| 413 | |
|
| 414 | |
|
| 415 | |
|
| 416 | |
|
| 417 | |
|
| 418 | |
|
| 419 | |
|
| 420 | |
|
| 421 | |
|
| 422 | |
|
| 423 | |
|
| 424 | ||
| 425 | |
|
| 426 | |
|
| 427 | |
|
| 428 | |
|
| 429 | |
|
| 430 | |
|
| 431 | |
|
| 432 | |
|
| 433 | |
|
| 434 | |
|
| 435 | |
|
| 436 | ||
| 437 | /// Formats a CRC-16 polynomial for use in PCLMULQDQ operations. |
|
| 438 | /// |
|
| 439 | /// # Polynomial Representation |
|
| 440 | /// |
|
| 441 | /// The polynomial passed to this function is already scaled to 32-bit space |
|
| 442 | /// (original_poly << 16 | 1 << 32). This function formats it for PCLMULQDQ. |
|
| 443 | /// |
|
| 444 | /// # Non-Reflected Case |
|
| 445 | /// |
|
| 446 | /// For non-reflected CRCs, the polynomial is already in the correct format |
|
| 447 | /// from the scaling done in keys(). |
|
| 448 | /// |
|
| 449 | /// # Reflected Case |
|
| 450 | /// |
|
| 451 | /// For reflected (LSB-first) CRCs, we need to: |
|
| 452 | /// 1. Extract the original 16-bit polynomial from the scaled value |
|
| 453 | /// 2. Bit-reverse the 16-bit polynomial |
|
| 454 | /// 3. Shift left by 1 bit and set the LSB to 1 |
|
| 455 | |
|
| 456 | |
|
| 457 | |
|
| 458 | |
|
| 459 | |
|
| 460 | |
|
| 461 | |
|
| 462 | |
|
| 463 | |
|
| 464 | |
|
| 465 | ||
| 466 | /// Formats a CRC-32 polynomial for use in PCLMULQDQ operations. |
|
| 467 | /// |
|
| 468 | /// # Polynomial Representation |
|
| 469 | /// |
|
| 470 | /// CRC polynomials are typically written without the implicit leading 1. For example: |
|
| 471 | /// - CRC-32 (IEEE 802.3): 0x04C11DB7 |
|
| 472 | /// - The full polynomial is actually 0x104C11DB7 (33 bits) |
|
| 473 | /// |
|
| 474 | /// # Non-Reflected Case |
|
| 475 | /// |
|
| 476 | /// For non-reflected CRCs, we simply add the leading 1: |
|
| 477 | /// - Input: 0x04C11DB7 |
|
| 478 | /// - Output: 0x104C11DB7 (bit 32 set) |
|
| 479 | /// |
|
| 480 | /// # Reflected Case |
|
| 481 | /// |
|
| 482 | /// For reflected (LSB-first) CRCs, we need to: |
|
| 483 | /// 1. Bit-reverse the 32-bit polynomial value |
|
| 484 | /// 2. Shift left by 1 bit |
|
| 485 | /// 3. Set the LSB to 1 |
|
| 486 | /// |
|
| 487 | /// This creates the reflected polynomial in the format expected by PCLMULQDQ. |
|
| 488 | /// |
|
| 489 | /// Example: |
|
| 490 | /// - Original: 0x04C11DB7 |
|
| 491 | /// - Bit-reversed: 0xEDB88320 |
|
| 492 | /// - Shifted and ORed: 0x1DB710641 |
|
| 493 | |
|
| 494 | |
|
| 495 | |
|
| 496 | |
|
| 497 | |
|
| 498 | |
|
| 499 | |
|
| 500 | |
|
| 501 | |
|
| 502 | |
|
| 503 | ||
| 504 | /// Formats a CRC-64 polynomial for use in PCLMULQDQ operations. |
|
| 505 | /// |
|
| 506 | /// # Key Difference From CRC-32 |
|
| 507 | /// |
|
| 508 | /// # Non-Reflected Case |
|
| 509 | /// |
|
| 510 | /// For non-reflected CRCs, we simply return the polynomial as-is. |
|
| 511 | /// |
|
| 512 | /// # Reflected Case |
|
| 513 | /// |
|
| 514 | /// For reflected CRC-64: |
|
| 515 | /// 1. Bit-reverse all 64 bits of the polynomial |
|
| 516 | /// 2. Shift left by 1 |
|
| 517 | /// 3. Set LSB to 1 |
|
| 518 | /// |
|
| 519 | /// Unlike CRC-32 which only reverses 32 bits, this reverses the full 64-bit value. |
|
| 520 | |
|
| 521 | |
|
| 522 | |
|
| 523 | |
|
| 524 | |
|
| 525 | |
|
| 526 | |
|
| 527 | |
|
| 528 | ||
| 529 | |
|
| 530 | |
|
| 531 | |
|
| 532 | |
|
| 533 | |
|
| 534 | |
|
| 535 | |
|
| 536 | |
|
| 537 | |
|
| 538 | |
|
| 539 | |
|
| 540 | ||
| 541 | /// Computes the Barrett reduction constant (μ) for CRC-16. |
|
| 542 | /// |
|
| 543 | /// # What Is μ (Mu)? |
|
| 544 | /// |
|
| 545 | /// Mu is used in Barrett reduction for fast modular reduction without division. |
|
| 546 | /// For CRC-16 operations (scaled to 32-bit space), μ = floor(x^64 / P(x)). |
|
| 547 | /// |
|
| 548 | /// # Algorithm |
|
| 549 | /// |
|
| 550 | /// This uses the same algorithm as CRC-32 mu calculation because CRC-16 is |
|
| 551 | /// computed in 32-bit space. The polynomial is already scaled (poly << 16 | 1 << 32). |
|
| 552 | /// |
|
| 553 | /// 1. Start with x^64 (represented as 0x100000000, bit 32 set) |
|
| 554 | /// 2. For each bit position from MSB down: |
|
| 555 | /// - If the dividend has a bit at position 32, record a 1 in quotient |
|
| 556 | /// - XOR the dividend with the polynomial |
|
| 557 | /// - Shift dividend left |
|
| 558 | /// 3. After 33 iterations, q contains μ |
|
| 559 | |
|
| 560 | |
|
| 561 | |
|
| 562 | |
|
| 563 | |
|
| 564 | |
|
| 565 | |
|
| 566 | |
|
| 567 | |
|
| 568 | |
|
| 569 | |
|
| 570 | |
|
| 571 | |
|
| 572 | |
|
| 573 | |
|
| 574 | |
|
| 575 | |
|
| 576 | |
|
| 577 | |
|
| 578 | ||
| 579 | /// Computes the Barrett reduction constant (μ) for CRC-32. |
|
| 580 | /// |
|
| 581 | /// # What Is μ (Mu)? |
|
| 582 | /// |
|
| 583 | /// Mu is used in Barrett reduction, an algorithm for fast modular reduction without division. |
|
| 584 | /// For CRC operations, μ = floor(x^(2n) / P(x)) where n is the polynomial degree. |
|
| 585 | /// |
|
| 586 | /// # Algorithm |
|
| 587 | /// |
|
| 588 | /// This performs polynomial long division: |
|
| 589 | /// 1. Start with x^64 (represented as 0x100000000, bit 32 set in a 65-bit view) |
|
| 590 | /// 2. For each bit position from MSB down: |
|
| 591 | /// - If the dividend has a bit at position 32, record a 1 in quotient |
|
| 592 | /// - XOR the dividend with the polynomial (subtract in GF(2)) |
|
| 593 | /// - Shift dividend left |
|
| 594 | /// 3. After 33 iterations, q contains μ |
|
| 595 | /// |
|
| 596 | /// # Why 33 Iterations? |
|
| 597 | /// |
|
| 598 | /// We're dividing a 65-bit value (x^64) by a 33-bit polynomial, giving a 33-bit quotient. |
|
| 599 | /// |
|
| 600 | /// # Reflection |
|
| 601 | /// |
|
| 602 | /// If reflected, the result is bit-reversed and shifted right by 31 to align properly. |
|
| 603 | |
|
| 604 | |
|
| 605 | |
|
| 606 | |
|
| 607 | |
|
| 608 | |
|
| 609 | |
|
| 610 | |
|
| 611 | |
|
| 612 | |
|
| 613 | |
|
| 614 | |
|
| 615 | |
|
| 616 | |
|
| 617 | |
|
| 618 | |
|
| 619 | |
|
| 620 | |
|
| 621 | |
|
| 622 | ||
| 623 | /// Computes the Barrett reduction constant (μ) for CRC-64. |
|
| 624 | /// |
|
| 625 | /// # Key Differences From CRC-32 |
|
| 626 | /// |
|
| 627 | /// CRC-64 requires dividing a 129-bit value (x^128) by a 65-bit polynomial, which |
|
| 628 | /// doesn't fit in a single u64. This implementation uses two u64 variables to represent |
|
| 629 | /// a 128-bit dividend. |
|
| 630 | /// |
|
| 631 | /// # Algorithm |
|
| 632 | /// |
|
| 633 | /// 1. Start with x^128 represented as (n_hi=1, n_lo=0) |
|
| 634 | /// 2. For each bit position: |
|
| 635 | /// - If n_hi is non-zero, record 1 in quotient and XOR n_lo with polynomial |
|
| 636 | /// - Shift the double-register left: n_hi = n_lo >> 63; n_lo <<= 1 |
|
| 637 | /// 3. After 64 or 65 iterations, q contains μ |
|
| 638 | /// |
|
| 639 | /// # Why Two Registers? |
|
| 640 | /// |
|
| 641 | /// - n_hi:n_lo forms a 128-bit value |
|
| 642 | /// - We can only XOR with the polynomial when "bit 64" is set (n_hi != 0) |
|
| 643 | /// - The shift operation propagates the MSB of n_lo into n_hi |
|
| 644 | /// |
|
| 645 | /// # Iteration Count Difference |
|
| 646 | /// |
|
| 647 | /// - Reflected: 64 iterations (matches the polynomial degree) |
|
| 648 | /// - Non-reflected: 65 iterations (one extra for proper alignment) |
|
| 649 | /// |
|
| 650 | /// This asymmetry exists because reflected CRCs process data LSB-first, |
|
| 651 | /// changing the division mechanics slightly. |
|
| 652 | /// |
|
| 653 | /// # No Additional Shift |
|
| 654 | /// |
|
| 655 | /// Unlike CRC-32's `>> 31`, CRC-64 doesn't need an extra shift in the reflected |
|
| 656 | /// case because the 64-bit result is already properly aligned. |
|
| 657 | |
|
| 658 | |
|
| 659 | |
|
| 660 | |
|
| 661 | |
|
| 662 | |
|
| 663 | |
|
| 664 | |
|
| 665 | |
|
| 666 | |
|
| 667 | |
|
| 668 | |
|
| 669 | |
|
| 670 | |
|
| 671 | |
|
| 672 | |
|
| 673 | |
|
| 674 | |
|
| 675 | |
|
| 676 | |
|
| 677 | |
|
| 678 | |
|
| 679 | |
|
| 680 | ||
| 681 | /// Reverses the bits of a value (MSB becomes LSB and vice versa). |
|
| 682 | /// |
|
| 683 | /// # Purpose in CRC Calculations |
|
| 684 | /// |
|
| 685 | /// Reflected (LSB-first) CRCs process data in reverse bit order. This function |
|
| 686 | /// converts between normal and reflected representations. |
|
| 687 | /// |
|
| 688 | /// # Why Generic? |
|
| 689 | /// |
|
| 690 | /// This works with any unsigned integer type (u32, u64) through trait bounds, |
|
| 691 | /// allowing the same code to handle both CRC-32 (which reverses 32 bits) and |
|
| 692 | /// CRC-64 (which reverses 64 bits). |
|
| 693 | /// |
|
| 694 | /// # Example |
|
| 695 | /// |
|
| 696 | /// For u32: 0x12345678 → 0x1E6A2C48 |
|
| 697 | /// - Binary: 0001 0010 0011 0100 0101 0110 0111 1000 |
|
| 698 | /// - Reversed: 0001 1110 0110 1010 0010 1100 0100 1000 |
|
| 699 | |
|
| 700 | |
|
| 701 | |
|
| 702 | |
|
| 703 | |
|
| 704 | |
|
| 705 | |
|
| 706 | |
|
| 707 | |
|
| 708 | |
|
| 709 | |
|
| 710 | |
|
| 711 | |
|
| 712 | |
|
| 713 | |
|
| 714 | |
|
| 715 | |
|
| 716 | |
|
| 717 | |
|
| 718 | |
|
| 719 | |
|
| 720 | |
|
| 721 | |
|
| 722 | |
|
| 723 | |
|
| 724 | |
|
| 725 | |
|
| 726 | |
|
| 727 | |
|
| 728 | |
|
| 729 | ||
| 730 | |
|
| 731 | |
|
| 732 | |
|
| 733 | |
|
| 734 | |
|
| 735 | |
|
| 736 | |
|
| 737 | |
|
| 738 | |
|
| 739 | |
|
| 740 | |
|
| 741 | |
|
| 742 | |
|
| 743 | |
|
| 744 | |
|
| 745 | |
|
| 746 | |
|
| 747 | |
|
| 748 | |
|
| 749 | |
|
| 750 | |
|
| 751 | |
|
| 752 | |
|
| 753 | |
|
| 754 | |
|
| 755 | |
|
| 756 | |
|
| 757 | |
|
| 758 | |
|
| 759 | |
|
| 760 | |
|
| 761 | |
|
| 762 | |
|
| 763 | |
|
| 764 | |
|
| 765 | |
|
| 766 | |
|
| 767 | |
|
| 768 | |
|
| 769 | |
|
| 770 | |
|
| 771 | |
|
| 772 | |
|
| 773 | |
|
| 774 | |
|
| 775 | |
|
| 776 | |
|
| 777 | |
|
| 778 | |
|
| 779 | |
|
| 780 | |
|
| 781 | |
|
| 782 | |
|
| 783 | |
|
| 784 | ||
| 785 | |
|
| 786 | |
|
| 787 | |
|
| 788 | |
|
| 789 | |
|
| 790 | |
|
| 791 | |
|
| 792 | |
|
| 793 | |
|
| 794 | |
|
| 795 | |
|
| 796 | |
|
| 797 | |
|
| 798 | |
|
| 799 | |
|
| 800 | |
|
| 801 | |
|
| 802 | |
|
| 803 | |
|
| 804 | |
|
| 805 | |
|
| 806 | |
|
| 807 | |
|
| 808 | |
|
| 809 | |
|
| 810 | |
|
| 811 | |
|
| 812 | |
|
| 813 | |
|
| 814 | |
|
| 815 | |
|
| 816 | |
|
| 817 | |
|
| 818 | |
|
| 819 | |
|
| 820 | |
|
| 821 | |
|
| 822 | |
|
| 823 | |
|
| 824 | |
|
| 825 | |
|
| 826 | |
|
| 827 | |
|
| 828 | |
|
| 829 | |
|
| 830 | |
|
| 831 | |
|
| 832 | |
|
| 833 | |
|
| 834 | |
|
| 835 | |
|
| 836 | |
|
| 837 | |
|
| 838 | |