Skip to content

Commit 40a543e

Browse files
committed
rscrypto: fixing crc32 again
1 parent 8be1572 commit 40a543e

1 file changed

Lines changed: 33 additions & 23 deletions

File tree

crates/checksum/src/crc32/x86_64.rs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
4653
mod 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")]
400410
unsafe 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

Comments
 (0)