@@ -41,17 +41,24 @@ mod crc32c_constants {
4141 pub const REDUCE_64 : ( u32 , u32 ) = ( 0x3da6d0cb , 0xba4fc28e ) ;
4242}
4343
44- /// CRC32-IEEE (ISO-HDLC) Barrett reduction constants.
44+ /// CRC32-IEEE (ISO-HDLC) CLMUL folding and Barrett reduction constants.
4545/// These are used for pure CLMUL reduction since x86 has no IEEE HW instruction.
46+ ///
47+ /// Constants from crc32fast (MIT licensed, same as Intel paper constants):
48+ /// - K1/K2: 64-byte (512-bit) folding
49+ /// - K3/K4: 16-byte (128-bit) folding
50+ /// - MU/POLY: Barrett reduction
51+ ///
52+ /// These are 33-bit values with bit 32 set, as required by the Intel algorithm.
4653mod crc32_ieee_constants {
47- /// 128 -byte block folding (x^1024+64 mod P, x^1024 mod P) .
48- pub const FOLD_128 : ( u64 , u64 ) = ( 0x00000001_54442bd4 , 0x00000001_c6e41596 ) ;
49- /// 16-byte lane folding (x^128+64 mod P, x^128 mod P).
50- pub const FOLD_16 : ( u64 , u64 ) = ( 0x0000_0000_1519_97d0 , 0x0000_0000_ccaa_009e ) ;
51- /// Barrett reduction: k3 (x^64 mod P), k4 (x^32 mod P).
52- pub const K3_K4 : ( u64 , u64 ) = ( 0x00000001_f7011641 , 0x00000000_db710641 ) ;
53- /// Barrett: µ (floor(x^64/P) with bit 32 set) , P' (polynomial ).
54- pub const MU_POLY : ( u64 , u64 ) = ( 0x00000001_00000001 , 0x00000001_db710641 ) ;
54+ /// 64 -byte block folding: (K1, K2) for 512-bit fold .
55+ pub const FOLD_64 : ( u64 , u64 ) = ( 0x0000_0001_5444_2bd4 , 0x0000_0001_c6e4_1596 ) ;
56+
57+ /// 16-byte lane folding : (K3, K4) for 128-bit fold.
58+ pub const FOLD_16 : ( u64 , u64 ) = ( 0x0000_0001_7519_97d0 , 0x0000_0000_ccaa_009e ) ;
59+
60+ /// Barrett reduction: (µ , P').
61+ pub const MU_POLY : ( u64 , u64 ) = ( 0x0000_0001_F701_1641 , 0x0000_0001_DB71_0641 ) ;
5562}
5663
5764// ─────────────────────────────────────────────────────────────────────────────
@@ -396,28 +403,31 @@ pub fn crc32c_pclmul_safe(crc: u32, data: &[u8]) -> u32 {
396403// ─────────────────────────────────────────────────────────────────────────────
397404
398405/// Barrett reduction from 128 bits to 32 bits for CRC32-IEEE.
406+ ///
407+ /// Algorithm based on Intel's "Fast CRC Computation" paper.
408+ /// Uses K3/K4 for 128→64→32 reduction, then Barrett for final step.
399409#[ target_feature( enable = "pclmulqdq" , enable = "sse4.1" ) ]
400410unsafe fn barrett_reduce_ieee ( acc : __m128i ) -> u32 {
401411 // SAFETY: target_feature ensures PCLMULQDQ and SSE4.1 availability
402412 let k3_k4 = _mm_set_epi64x (
403- crc32_ieee_constants:: K3_K4 . 1 as i64 ,
404- crc32_ieee_constants:: K3_K4 . 0 as i64 ,
413+ crc32_ieee_constants:: FOLD_16 . 1 as i64 , // K4
414+ crc32_ieee_constants:: FOLD_16 . 0 as i64 , // K3
405415 ) ;
406416 let mu_poly = _mm_set_epi64x (
407- crc32_ieee_constants:: MU_POLY . 1 as i64 ,
408- crc32_ieee_constants:: MU_POLY . 0 as i64 ,
417+ crc32_ieee_constants:: MU_POLY . 1 as i64 , // POLY
418+ crc32_ieee_constants:: MU_POLY . 0 as i64 , // MU
409419 ) ;
410420
411- // Fold 128→64 bits using k3
412- let t1 = _mm_clmulepi64_si128 ( acc, k3_k4, 0x10 ) ;
421+ // Fold 128→64 bits: multiply high 64 bits by K3, XOR with low 64 bits
422+ let t1 = _mm_clmulepi64_si128 ( acc, k3_k4, 0x10 ) ; // acc.hi × K3
413423 let t2 = _mm_xor_si128 ( t1, _mm_srli_si128 ( acc, 8 ) ) ;
414424 let t3 = _mm_xor_si128 ( t2, _mm_slli_si128 ( acc, 8 ) ) ;
415425
416- // Fold 64→32 using k4
417- let t4 = _mm_clmulepi64_si128 ( t3, k3_k4, 0x01 ) ;
426+ // Fold 64→32 bits: multiply bits [63:32] by K4
427+ let t4 = _mm_clmulepi64_si128 ( t3, k3_k4, 0x01 ) ; // t3.lo × K4
418428 let t5 = _mm_xor_si128 ( t4, t3) ;
419429
420- // Barrett reduction
430+ // Barrett reduction: 64→32 bits
421431 let t6 = _mm_clmulepi64_si128 ( _mm_and_si128 ( t5, _mm_set_epi32 ( 0 , 0 , !0 , !0 ) ) , mu_poly, 0x00 ) ;
422432 let t7 = _mm_clmulepi64_si128 ( t6, mu_poly, 0x10 ) ;
423433 let result = _mm_xor_si128 ( t5, t7) ;
@@ -447,9 +457,9 @@ pub unsafe fn crc32_ieee_pclmul(mut crc: u32, data: &[u8]) -> u32 {
447457 crc32_ieee_constants:: FOLD_16 . 1 as i64 ,
448458 crc32_ieee_constants:: FOLD_16 . 0 as i64 ,
449459 ) ;
450- let fold_128_k = _mm_set_epi64x (
451- crc32_ieee_constants:: FOLD_128 . 1 as i64 ,
452- crc32_ieee_constants:: FOLD_128 . 0 as i64 ,
460+ let fold_64_k = _mm_set_epi64x (
461+ crc32_ieee_constants:: FOLD_64 . 1 as i64 ,
462+ crc32_ieee_constants:: FOLD_64 . 0 as i64 ,
453463 ) ;
454464
455465 // Initialize 4 lanes with first 64 bytes
@@ -466,8 +476,8 @@ pub unsafe fn crc32_ieee_pclmul(mut crc: u32, data: &[u8]) -> u32 {
466476 while ptr. add ( FOLD_BYTES ) <= end {
467477 for ( i, lane) in lanes. iter_mut ( ) . enumerate ( ) {
468478 let new_data = _mm_loadu_si128 ( ptr. add ( i * 16 ) as * const __m128i ) ;
469- let lo = clmul_lo ( * lane, fold_128_k ) ;
470- let hi = clmul_hi ( * lane, fold_128_k ) ;
479+ let lo = clmul_lo ( * lane, fold_64_k ) ;
480+ let hi = clmul_hi ( * lane, fold_64_k ) ;
471481 * lane = _mm_xor_si128 ( _mm_xor_si128 ( lo, hi) , new_data) ;
472482 }
473483 ptr = ptr. add ( FOLD_BYTES ) ;
0 commit comments