OXYGENHUB
◆ carried-not-removed oxygen / vendor / crc-fast / src / arch / software.rs
46.2 KiB · Rust · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago source blame history raw
1
// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.
2
3
//! This module contains a software fallback for unsupported architectures.
4
5
use crate::tables;
6
use crate::CrcAlgorithm;
7
use crate::CrcParams;
8
9
// ============================================================================
10
// Native Table Generation Functions
11
// ============================================================================
12
13
/// Computes a single CRC-16 value for table generation.
14
const fn crc16_single(poly: u16, reflect: bool, mut value: u16) -> u16 {
15
    if reflect {
16
        let mut i = 0;
17
        while i < 8 {
18
            value = (value >> 1) ^ ((value & 1) * poly);
19
            i += 1;
20
        }
21
    } else {
22
        value <<= 8;
23
        let mut i = 0;
24
        while i < 8 {
25
            value = (value << 1) ^ (((value >> 15) & 1) * poly);
26
            i += 1;
27
        }
28
    }
29
    value
30
}
31
32
/// Computes a single CRC-32 value for table generation.
33
const fn crc32_single(poly: u32, reflect: bool, mut value: u32) -> u32 {
34
    if reflect {
35
        let mut i = 0;
36
        while i < 8 {
37
            value = (value >> 1) ^ ((value & 1) * poly);
38
            i += 1;
39
        }
40
    } else {
41
        value <<= 24;
42
        let mut i = 0;
43
        while i < 8 {
44
            value = (value << 1) ^ (((value >> 31) & 1) * poly);
45
            i += 1;
46
        }
47
    }
48
    value
49
}
50
51
/// Computes a single CRC-64 value for table generation.
52
const fn crc64_single(poly: u64, reflect: bool, mut value: u64) -> u64 {
53
    if reflect {
54
        let mut i = 0;
55
        while i < 8 {
56
            value = (value >> 1) ^ ((value & 1) * poly);
57
            i += 1;
58
        }
59
    } else {
60
        value <<= 56;
61
        let mut i = 0;
62
        while i < 8 {
63
            value = (value << 1) ^ (((value >> 63) & 1) * poly);
64
            i += 1;
65
        }
66
    }
67
    value
68
}
69
70
/// Generates a 16-lane lookup table for CRC-16 calculations.
71
///
72
/// This function creates a table compatible with the `crc` crate's `Table<16>` format,
73
/// enabling processing of 16 bytes at a time for improved performance.
74
pub const fn generate_table_u16(width: u8, poly: u16, reflect: bool) -> [[u16; 256]; 16] {
75
    let poly = if reflect {
76
        let poly = poly.reverse_bits();
77
        poly >> (16u8 - width)
78
    } else {
79
        poly << (16u8 - width)
80
    };
81
82
    let mut table = [[0u16; 256]; 16];
83
84
    // Generate first table (lane 0) directly
85
    let mut i = 0;
86
    while i < 256 {
87
        table[0][i] = crc16_single(poly, reflect, i as u16);
88
        i += 1;
89
    }
90
91
    // Generate subsequent lanes based on lane 0
92
    let mut i = 0;
93
    while i < 256 {
94
        let mut e = 1;
95
        while e < 16 {
96
            let one_lower = table[e - 1][i];
97
            if reflect {
98
                table[e][i] = (one_lower >> 8) ^ table[0][(one_lower & 0xFF) as usize];
99
            } else {
100
                table[e][i] = (one_lower << 8) ^ table[0][((one_lower >> 8) & 0xFF) as usize];
101
            }
102
            e += 1;
103
        }
104
        i += 1;
105
    }
106
107
    table
108
}
109
110
/// Generates a 16-lane lookup table for CRC-32 calculations.
111
///
112
/// This function creates a table compatible with the `crc` crate's `Table<16>` format,
113
/// enabling processing of 16 bytes at a time for improved performance.
114
pub const fn generate_table_u32(width: u8, poly: u32, reflect: bool) -> [[u32; 256]; 16] {
115
    let poly = if reflect {
116
        let poly = poly.reverse_bits();
117
        poly >> (32u8 - width)
118
    } else {
119
        poly << (32u8 - width)
120
    };
121
122
    let mut table = [[0u32; 256]; 16];
123
124
    // Generate first table (lane 0) directly
125
    let mut i = 0;
126
    while i < 256 {
127
        table[0][i] = crc32_single(poly, reflect, i as u32);
128
        i += 1;
129
    }
130
131
    // Generate subsequent lanes based on lane 0
132
    let mut i = 0;
133
    while i < 256 {
134
        let mut e = 1;
135
        while e < 16 {
136
            let one_lower = table[e - 1][i];
137
            if reflect {
138
                table[e][i] = (one_lower >> 8) ^ table[0][(one_lower & 0xFF) as usize];
139
            } else {
140
                table[e][i] = (one_lower << 8) ^ table[0][((one_lower >> 24) & 0xFF) as usize];
141
            }
142
            e += 1;
143
        }
144
        i += 1;
145
    }
146
147
    table
148
}
149
150
/// Generates a 16-lane lookup table for CRC-64 calculations.
151
///
152
/// This function creates a table compatible with the `crc` crate's `Table<16>` format,
153
/// enabling processing of 16 bytes at a time for improved performance.
154
pub const fn generate_table_u64(width: u8, poly: u64, reflect: bool) -> [[u64; 256]; 16] {
155
    let poly = if reflect {
156
        let poly = poly.reverse_bits();
157
        poly >> (64u8 - width)
158
    } else {
159
        poly << (64u8 - width)
160
    };
161
162
    let mut table = [[0u64; 256]; 16];
163
164
    // Generate first table (lane 0) directly
165
    let mut i = 0;
166
    while i < 256 {
167
        table[0][i] = crc64_single(poly, reflect, i as u64);
168
        i += 1;
169
    }
170
171
    // Generate subsequent lanes based on lane 0
172
    let mut i = 0;
173
    while i < 256 {
174
        let mut e = 1;
175
        while e < 16 {
176
            let one_lower = table[e - 1][i];
177
            if reflect {
178
                table[e][i] = (one_lower >> 8) ^ table[0][(one_lower & 0xFF) as usize];
179
            } else {
180
                table[e][i] = (one_lower << 8) ^ table[0][((one_lower >> 56) & 0xFF) as usize];
181
            }
182
            e += 1;
183
        }
184
        i += 1;
185
    }
186
187
    table
188
}
189
190
// ============================================================================
191
// Caching for custom CRC algorithms
192
// ============================================================================
193
194
#[cfg(feature = "alloc")]
195
#[cfg(feature = "std")]
196
use std::collections::HashMap;
197
#[cfg(feature = "alloc")]
198
#[cfg(feature = "std")]
199
use std::sync::{Mutex, OnceLock};
200
201
#[cfg(feature = "alloc")]
202
#[cfg(all(not(feature = "std"), feature = "cache"))]
203
use hashbrown::HashMap;
204
#[cfg(feature = "alloc")]
205
#[cfg(all(not(feature = "std"), feature = "cache"))]
206
use spin::{Mutex, Once};
207
208
// Cache key types for custom algorithms
209
#[cfg(feature = "alloc")]
210
#[cfg(any(feature = "std", feature = "cache"))]
211
type Crc16Key = (u16, u16, bool, bool, u16, u16);
212
#[cfg(feature = "alloc")]
213
#[cfg(any(feature = "std", feature = "cache"))]
214
type Crc32Key = (u32, u32, bool, bool, u32, u32);
215
#[cfg(feature = "alloc")]
216
#[cfg(any(feature = "std", feature = "cache"))]
217
type Crc64Key = (u64, u64, bool, bool, u64, u64);
218
219
// Cache value types for custom algorithms - stores the generated table
220
#[cfg(feature = "alloc")]
221
#[cfg(any(feature = "std", feature = "cache"))]
222
type Crc16CacheValue = &'static [[u16; 256]; 16];
223
#[cfg(feature = "alloc")]
224
#[cfg(any(feature = "std", feature = "cache"))]
225
type Crc32CacheValue = &'static [[u32; 256]; 16];
226
#[cfg(feature = "alloc")]
227
#[cfg(any(feature = "std", feature = "cache"))]
228
type Crc64CacheValue = &'static [[u64; 256]; 16];
229
230
// Global caches for custom algorithms (std version)
231
#[cfg(feature = "alloc")]
232
#[cfg(feature = "std")]
233
static CUSTOM_CRC16_CACHE: OnceLock<Mutex<HashMap<Crc16Key, Crc16CacheValue>>> = OnceLock::new();
234
#[cfg(feature = "alloc")]
235
#[cfg(feature = "std")]
236
static CUSTOM_CRC32_CACHE: OnceLock<Mutex<HashMap<Crc32Key, Crc32CacheValue>>> = OnceLock::new();
237
#[cfg(feature = "alloc")]
238
#[cfg(feature = "std")]
239
static CUSTOM_CRC64_CACHE: OnceLock<Mutex<HashMap<Crc64Key, Crc64CacheValue>>> = OnceLock::new();
240
241
// Global caches for custom algorithms (no_std + cache version)
242
#[cfg(feature = "alloc")]
243
#[cfg(all(not(feature = "std"), feature = "cache"))]
244
static CUSTOM_CRC16_CACHE: Once<Mutex<HashMap<Crc16Key, Crc16CacheValue>>> = Once::new();
245
#[cfg(feature = "alloc")]
246
#[cfg(all(not(feature = "std"), feature = "cache"))]
247
static CUSTOM_CRC32_CACHE: Once<Mutex<HashMap<Crc32Key, Crc32CacheValue>>> = Once::new();
248
#[cfg(feature = "alloc")]
249
#[cfg(all(not(feature = "std"), feature = "cache"))]
250
static CUSTOM_CRC64_CACHE: Once<Mutex<HashMap<Crc64Key, Crc64CacheValue>>> = Once::new();
251
252
// ============================================================================
253
// Main dispatch function
254
// ============================================================================
255
256
#[allow(unused)]
257
#[allow(deprecated)]
258
pub(crate) fn update(state: u64, data: &[u8], params: &CrcParams) -> u64 {
259
    match params.width {
260
        16 => update_crc16(state as u16, data, params) as u64,
261
        32 => update_crc32(state as u32, data, params) as u64,
262
        64 => update_crc64(state, data, params),
263
        _ => panic!("Unsupported CRC width: {}", params.width),
264
    }
265
}
266
267
// ============================================================================
268
// CRC-16 dispatch
269
// ============================================================================
270
271
fn update_crc16(state: u16, data: &[u8], params: &CrcParams) -> u16 {
272
    let (table, refin) = match params.algorithm {
273
        CrcAlgorithm::Crc16Arc => (&tables::crc16::CRC16_ARC_TABLE, true),
274
        CrcAlgorithm::Crc16Cdma2000 => (&tables::crc16::CRC16_CDMA2000_TABLE, false),
275
        CrcAlgorithm::Crc16Cms => (&tables::crc16::CRC16_CMS_TABLE, false),
276
        CrcAlgorithm::Crc16Dds110 => (&tables::crc16::CRC16_DDS_110_TABLE, false),
277
        CrcAlgorithm::Crc16DectR => (&tables::crc16::CRC16_DECT_R_TABLE, false),
278
        CrcAlgorithm::Crc16DectX => (&tables::crc16::CRC16_DECT_X_TABLE, false),
279
        CrcAlgorithm::Crc16Dnp => (&tables::crc16::CRC16_DNP_TABLE, true),
280
        CrcAlgorithm::Crc16En13757 => (&tables::crc16::CRC16_EN_13757_TABLE, false),
281
        CrcAlgorithm::Crc16Genibus => (&tables::crc16::CRC16_GENIBUS_TABLE, false),
282
        CrcAlgorithm::Crc16Gsm => (&tables::crc16::CRC16_GSM_TABLE, false),
283
        CrcAlgorithm::Crc16Ibm3740 => (&tables::crc16::CRC16_IBM_3740_TABLE, false),
284
        CrcAlgorithm::Crc16IbmSdlc => (&tables::crc16::CRC16_IBM_SDLC_TABLE, true),
285
        CrcAlgorithm::Crc16IsoIec144433A => (&tables::crc16::CRC16_ISO_IEC_14443_3_A_TABLE, true),
286
        CrcAlgorithm::Crc16Kermit => (&tables::crc16::CRC16_KERMIT_TABLE, true),
287
        CrcAlgorithm::Crc16Lj1200 => (&tables::crc16::CRC16_LJ1200_TABLE, false),
288
        CrcAlgorithm::Crc16M17 => (&tables::crc16::CRC16_M17_TABLE, false),
289
        CrcAlgorithm::Crc16MaximDow => (&tables::crc16::CRC16_MAXIM_DOW_TABLE, true),
290
        CrcAlgorithm::Crc16Mcrf4xx => (&tables::crc16::CRC16_MCRF4XX_TABLE, true),
291
        CrcAlgorithm::Crc16Modbus => (&tables::crc16::CRC16_MODBUS_TABLE, true),
292
        CrcAlgorithm::Crc16Nrsc5 => (&tables::crc16::CRC16_NRSC_5_TABLE, true),
293
        CrcAlgorithm::Crc16OpensafetyA => (&tables::crc16::CRC16_OPENSAFETY_A_TABLE, false),
294
        CrcAlgorithm::Crc16OpensafetyB => (&tables::crc16::CRC16_OPENSAFETY_B_TABLE, false),
295
        CrcAlgorithm::Crc16Profibus => (&tables::crc16::CRC16_PROFIBUS_TABLE, false),
296
        CrcAlgorithm::Crc16Riello => (&tables::crc16::CRC16_RIELLO_TABLE, true),
297
        CrcAlgorithm::Crc16SpiFujitsu => (&tables::crc16::CRC16_SPI_FUJITSU_TABLE, false),
298
        CrcAlgorithm::Crc16T10Dif => (&tables::crc16::CRC16_T10_DIF_TABLE, false),
299
        CrcAlgorithm::Crc16Teledisk => (&tables::crc16::CRC16_TELEDISK_TABLE, false),
300
        CrcAlgorithm::Crc16Tms37157 => (&tables::crc16::CRC16_TMS37157_TABLE, true),
301
        CrcAlgorithm::Crc16Umts => (&tables::crc16::CRC16_UMTS_TABLE, false),
302
        CrcAlgorithm::Crc16Usb => (&tables::crc16::CRC16_USB_TABLE, true),
303
        CrcAlgorithm::Crc16Xmodem => (&tables::crc16::CRC16_XMODEM_TABLE, false),
304
        CrcAlgorithm::CrcCustom => {
305
            return update_crc16_custom(state, data, params);
306
        }
307
        _ => panic!("Invalid algorithm for u16 CRC"),
308
    };
309
310
    native_update_u16(state, table, refin, data)
311
}
312
313
#[cfg(feature = "alloc")]
314
fn update_crc16_custom(state: u16, data: &[u8], params: &CrcParams) -> u16 {
315
    extern crate alloc;
316
    use alloc::boxed::Box;
317
318
    let refin = params.refin;
319
320
    #[cfg(any(feature = "std", feature = "cache"))]
321
    let table: &'static [[u16; 256]; 16] = {
322
        let key: Crc16Key = (
323
            params.poly as u16,
324
            params.init as u16,
325
            params.refin,
326
            params.refout,
327
            params.xorout as u16,
328
            params.check as u16,
329
        );
330
331
        #[cfg(feature = "std")]
332
        {
333
            let cache = CUSTOM_CRC16_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
334
            let mut cache_guard = cache.lock().unwrap();
335
336
            cache_guard.entry(key).or_insert_with(|| {
337
                let table = generate_table_u16(params.width, params.poly as u16, refin);
338
                Box::leak(Box::new(table))
339
            })
340
        }
341
342
        #[cfg(all(not(feature = "std"), feature = "cache"))]
343
        {
344
            let cache = CUSTOM_CRC16_CACHE.call_once(|| Mutex::new(HashMap::new()));
345
            let mut cache_guard = cache.lock();
346
347
            cache_guard.entry(key).or_insert_with(|| {
348
                let table = generate_table_u16(params.width, params.poly as u16, refin);
349
                Box::leak(Box::new(table))
350
            })
351
        }
352
    };
353
354
    #[cfg(not(any(feature = "std", feature = "cache")))]
355
    let table: &'static [[u16; 256]; 16] = {
356
        let table = generate_table_u16(params.width, params.poly as u16, refin);
357
        Box::leak(Box::new(table))
358
    };
359
360
    native_update_u16(state, table, refin, data)
361
}
362
363
#[cfg(not(feature = "alloc"))]
364
fn update_crc16_custom(_state: u16, _data: &[u8], _params: &CrcParams) -> u16 {
365
    panic!("Custom CRC parameters require the 'alloc' feature")
366
}
367
368
// ============================================================================
369
// CRC-32 dispatch
370
// ============================================================================
371
372
fn update_crc32(state: u32, data: &[u8], params: &CrcParams) -> u32 {
373
    let (table, refin) = match params.algorithm {
374
        CrcAlgorithm::Crc32Aixm => (&tables::crc32::CRC32_AIXM_TABLE, false),
375
        CrcAlgorithm::Crc32Autosar => (&tables::crc32::CRC32_AUTOSAR_TABLE, true),
376
        CrcAlgorithm::Crc32Base91D => (&tables::crc32::CRC32_BASE91_D_TABLE, true),
377
        CrcAlgorithm::Crc32Bzip2 => (&tables::crc32::CRC32_BZIP2_TABLE, false),
378
        CrcAlgorithm::Crc32CdRomEdc => (&tables::crc32::CRC32_CD_ROM_EDC_TABLE, true),
379
        CrcAlgorithm::Crc32Cksum => (&tables::crc32::CRC32_CKSUM_TABLE, false),
380
        CrcAlgorithm::Crc32Iscsi => (&tables::crc32::CRC32_ISCSI_TABLE, true),
381
        CrcAlgorithm::Crc32IsoHdlc => (&tables::crc32::CRC32_ISO_HDLC_TABLE, true),
382
        CrcAlgorithm::Crc32Jamcrc => (&tables::crc32::CRC32_JAMCRC_TABLE, true),
383
        CrcAlgorithm::Crc32Mef => (&tables::crc32::CRC32_MEF_TABLE, true),
384
        CrcAlgorithm::Crc32Mpeg2 => (&tables::crc32::CRC32_MPEG_2_TABLE, false),
385
        CrcAlgorithm::Crc32Xfer => (&tables::crc32::CRC32_XFER_TABLE, false),
386
        #[allow(deprecated)]
387
        CrcAlgorithm::Crc32Custom | CrcAlgorithm::CrcCustom => {
388
            return update_crc32_custom(state, data, params);
389
        }
390
        _ => panic!("Invalid algorithm for u32 CRC"),
391
    };
392
393
    native_update_u32(state, table, refin, data)
394
}
395
396
#[cfg(feature = "alloc")]
397
fn update_crc32_custom(state: u32, data: &[u8], params: &CrcParams) -> u32 {
398
    extern crate alloc;
399
    use alloc::boxed::Box;
400
401
    let refin = params.refin;
402
403
    #[cfg(any(feature = "std", feature = "cache"))]
404
    let table: &'static [[u32; 256]; 16] = {
405
        let key: Crc32Key = (
406
            params.poly as u32,
407
            params.init as u32,
408
            params.refin,
409
            params.refout,
410
            params.xorout as u32,
411
            params.check as u32,
412
        );
413
414
        #[cfg(feature = "std")]
415
        {
416
            let cache = CUSTOM_CRC32_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
417
            let mut cache_guard = cache.lock().unwrap();
418
419
            cache_guard.entry(key).or_insert_with(|| {
420
                let table = generate_table_u32(params.width, params.poly as u32, refin);
421
                Box::leak(Box::new(table))
422
            })
423
        }
424
425
        #[cfg(all(not(feature = "std"), feature = "cache"))]
426
        {
427
            let cache = CUSTOM_CRC32_CACHE.call_once(|| Mutex::new(HashMap::new()));
428
            let mut cache_guard = cache.lock();
429
430
            cache_guard.entry(key).or_insert_with(|| {
431
                let table = generate_table_u32(params.width, params.poly as u32, refin);
432
                Box::leak(Box::new(table))
433
            })
434
        }
435
    };
436
437
    #[cfg(not(any(feature = "std", feature = "cache")))]
438
    let table: &'static [[u32; 256]; 16] = {
439
        let table = generate_table_u32(params.width, params.poly as u32, refin);
440
        Box::leak(Box::new(table))
441
    };
442
443
    native_update_u32(state, table, refin, data)
444
}
445
446
#[cfg(not(feature = "alloc"))]
447
fn update_crc32_custom(_state: u32, _data: &[u8], _params: &CrcParams) -> u32 {
448
    panic!("Custom CRC parameters require the 'alloc' feature")
449
}
450
451
// ============================================================================
452
// CRC-64 dispatch
453
// ============================================================================
454
455
fn update_crc64(state: u64, data: &[u8], params: &CrcParams) -> u64 {
456
    let (table, refin) = match params.algorithm {
457
        CrcAlgorithm::Crc64Ecma182 => (&tables::crc64::CRC64_ECMA_182_TABLE, false),
458
        CrcAlgorithm::Crc64GoIso => (&tables::crc64::CRC64_GO_ISO_TABLE, true),
459
        CrcAlgorithm::Crc64Ms => (&tables::crc64::CRC64_MS_TABLE, true),
460
        CrcAlgorithm::Crc64Nvme => (&tables::crc64::CRC64_NVME_TABLE, true),
461
        CrcAlgorithm::Crc64Redis => (&tables::crc64::CRC64_REDIS_TABLE, true),
462
        CrcAlgorithm::Crc64We => (&tables::crc64::CRC64_WE_TABLE, false),
463
        CrcAlgorithm::Crc64Xz => (&tables::crc64::CRC64_XZ_TABLE, true),
464
        #[allow(deprecated)]
465
        CrcAlgorithm::Crc64Custom | CrcAlgorithm::CrcCustom => {
466
            return update_crc64_custom(state, data, params);
467
        }
468
        _ => panic!("Invalid algorithm for u64 CRC"),
469
    };
470
471
    native_update_u64(state, table, refin, data)
472
}
473
474
#[cfg(feature = "alloc")]
475
fn update_crc64_custom(state: u64, data: &[u8], params: &CrcParams) -> u64 {
476
    extern crate alloc;
477
    use alloc::boxed::Box;
478
479
    let refin = params.refin;
480
481
    #[cfg(any(feature = "std", feature = "cache"))]
482
    let table: &'static [[u64; 256]; 16] = {
483
        let key: Crc64Key = (
484
            params.poly,
485
            params.init,
486
            params.refin,
487
            params.refout,
488
            params.xorout,
489
            params.check,
490
        );
491
492
        #[cfg(feature = "std")]
493
        {
494
            let cache = CUSTOM_CRC64_CACHE.get_or_init(|| Mutex::new(HashMap::new()));
495
            let mut cache_guard = cache.lock().unwrap();
496
497
            cache_guard.entry(key).or_insert_with(|| {
498
                let table = generate_table_u64(params.width, params.poly, refin);
499
                Box::leak(Box::new(table))
500
            })
501
        }
502
503
        #[cfg(all(not(feature = "std"), feature = "cache"))]
504
        {
505
            let cache = CUSTOM_CRC64_CACHE.call_once(|| Mutex::new(HashMap::new()));
506
            let mut cache_guard = cache.lock();
507
508
            cache_guard.entry(key).or_insert_with(|| {
509
                let table = generate_table_u64(params.width, params.poly, refin);
510
                Box::leak(Box::new(table))
511
            })
512
        }
513
    };
514
515
    #[cfg(not(any(feature = "std", feature = "cache")))]
516
    let table: &'static [[u64; 256]; 16] = {
517
        let table = generate_table_u64(params.width, params.poly, refin);
518
        Box::leak(Box::new(table))
519
    };
520
521
    native_update_u64(state, table, refin, data)
522
}
523
524
#[cfg(not(feature = "alloc"))]
525
fn update_crc64_custom(_state: u64, _data: &[u8], _params: &CrcParams) -> u64 {
526
    panic!("Custom CRC parameters require the 'alloc' feature")
527
}
528
529
// ============================================================================
530
// Native CRC Update Functions (Table<16> equivalent)
531
// ============================================================================
532
533
/// Native CRC-16 update function using 16-lane lookup tables.
534
///
535
/// Processes 16 bytes at a time for improved performance, then handles
536
/// remaining bytes with single-byte lookups.
537
#[allow(dead_code)]
538
pub(crate) fn native_update_u16(
539
    mut crc: u16,
540
    table: &[[u16; 256]; 16],
541
    reflect: bool,
542
    bytes: &[u8],
543
) -> u16 {
544
    let len = bytes.len();
545
    let mut i = 0;
546
547
    // Process 16 bytes at a time
548
    while i + 16 <= len {
549
        if reflect {
550
            let current0 = bytes[i] ^ (crc as u8);
551
            let current1 = bytes[i + 1] ^ ((crc >> 8) as u8);
552
553
            crc = table[0][bytes[i + 15] as usize]
554
                ^ table[1][bytes[i + 14] as usize]
555
                ^ table[2][bytes[i + 13] as usize]
556
                ^ table[3][bytes[i + 12] as usize]
557
                ^ table[4][bytes[i + 11] as usize]
558
                ^ table[5][bytes[i + 10] as usize]
559
                ^ table[6][bytes[i + 9] as usize]
560
                ^ table[7][bytes[i + 8] as usize]
561
                ^ table[8][bytes[i + 7] as usize]
562
                ^ table[9][bytes[i + 6] as usize]
563
                ^ table[10][bytes[i + 5] as usize]
564
                ^ table[11][bytes[i + 4] as usize]
565
                ^ table[12][bytes[i + 3] as usize]
566
                ^ table[13][bytes[i + 2] as usize]
567
                ^ table[14][current1 as usize]
568
                ^ table[15][current0 as usize];
569
        } else {
570
            let current0 = bytes[i] ^ ((crc >> 8) as u8);
571
            let current1 = bytes[i + 1] ^ (crc as u8);
572
573
            crc = table[0][bytes[i + 15] as usize]
574
                ^ table[1][bytes[i + 14] as usize]
575
                ^ table[2][bytes[i + 13] as usize]
576
                ^ table[3][bytes[i + 12] as usize]
577
                ^ table[4][bytes[i + 11] as usize]
578
                ^ table[5][bytes[i + 10] as usize]
579
                ^ table[6][bytes[i + 9] as usize]
580
                ^ table[7][bytes[i + 8] as usize]
581
                ^ table[8][bytes[i + 7] as usize]
582
                ^ table[9][bytes[i + 6] as usize]
583
                ^ table[10][bytes[i + 5] as usize]
584
                ^ table[11][bytes[i + 4] as usize]
585
                ^ table[12][bytes[i + 3] as usize]
586
                ^ table[13][bytes[i + 2] as usize]
587
                ^ table[14][current1 as usize]
588
                ^ table[15][current0 as usize];
589
        }
590
        i += 16;
591
    }
592
593
    // Process remaining bytes one at a time
594
    if reflect {
595
        while i < len {
596
            let table_index = ((crc ^ bytes[i] as u16) & 0xFF) as usize;
597
            crc = table[0][table_index] ^ (crc >> 8);
598
            i += 1;
599
        }
600
    } else {
601
        while i < len {
602
            let table_index = (((crc >> 8) ^ bytes[i] as u16) & 0xFF) as usize;
603
            crc = table[0][table_index] ^ (crc << 8);
604
            i += 1;
605
        }
606
    }
607
608
    crc
609
}
610
611
/// Native CRC-32 update function using 16-lane lookup tables.
612
///
613
/// Processes 16 bytes at a time for improved performance, then handles
614
/// remaining bytes with single-byte lookups.
615
#[allow(dead_code)]
616
pub(crate) fn native_update_u32(
617
    mut crc: u32,
618
    table: &[[u32; 256]; 16],
619
    reflect: bool,
620
    bytes: &[u8],
621
) -> u32 {
622
    let len = bytes.len();
623
    let mut i = 0;
624
625
    // Process 16 bytes at a time
626
    while i + 16 <= len {
627
        if reflect {
628
            let current0 = bytes[i] ^ (crc as u8);
629
            let current1 = bytes[i + 1] ^ ((crc >> 8) as u8);
630
            let current2 = bytes[i + 2] ^ ((crc >> 16) as u8);
631
            let current3 = bytes[i + 3] ^ ((crc >> 24) as u8);
632
633
            crc = table[0][bytes[i + 15] as usize]
634
                ^ table[1][bytes[i + 14] as usize]
635
                ^ table[2][bytes[i + 13] as usize]
636
                ^ table[3][bytes[i + 12] as usize]
637
                ^ table[4][bytes[i + 11] as usize]
638
                ^ table[5][bytes[i + 10] as usize]
639
                ^ table[6][bytes[i + 9] as usize]
640
                ^ table[7][bytes[i + 8] as usize]
641
                ^ table[8][bytes[i + 7] as usize]
642
                ^ table[9][bytes[i + 6] as usize]
643
                ^ table[10][bytes[i + 5] as usize]
644
                ^ table[11][bytes[i + 4] as usize]
645
                ^ table[12][current3 as usize]
646
                ^ table[13][current2 as usize]
647
                ^ table[14][current1 as usize]
648
                ^ table[15][current0 as usize];
649
        } else {
650
            let current0 = bytes[i] ^ ((crc >> 24) as u8);
651
            let current1 = bytes[i + 1] ^ ((crc >> 16) as u8);
652
            let current2 = bytes[i + 2] ^ ((crc >> 8) as u8);
653
            let current3 = bytes[i + 3] ^ (crc as u8);
654
655
            crc = table[0][bytes[i + 15] as usize]
656
                ^ table[1][bytes[i + 14] as usize]
657
                ^ table[2][bytes[i + 13] as usize]
658
                ^ table[3][bytes[i + 12] as usize]
659
                ^ table[4][bytes[i + 11] as usize]
660
                ^ table[5][bytes[i + 10] as usize]
661
                ^ table[6][bytes[i + 9] as usize]
662
                ^ table[7][bytes[i + 8] as usize]
663
                ^ table[8][bytes[i + 7] as usize]
664
                ^ table[9][bytes[i + 6] as usize]
665
                ^ table[10][bytes[i + 5] as usize]
666
                ^ table[11][bytes[i + 4] as usize]
667
                ^ table[12][current3 as usize]
668
                ^ table[13][current2 as usize]
669
                ^ table[14][current1 as usize]
670
                ^ table[15][current0 as usize];
671
        }
672
        i += 16;
673
    }
674
675
    // Process remaining bytes one at a time
676
    if reflect {
677
        while i < len {
678
            let table_index = ((crc ^ bytes[i] as u32) & 0xFF) as usize;
679
            crc = table[0][table_index] ^ (crc >> 8);
680
            i += 1;
681
        }
682
    } else {
683
        while i < len {
684
            let table_index = (((crc >> 24) ^ bytes[i] as u32) & 0xFF) as usize;
685
            crc = table[0][table_index] ^ (crc << 8);
686
            i += 1;
687
        }
688
    }
689
690
    crc
691
}
692
693
/// Native CRC-64 update function using 16-lane lookup tables.
694
///
695
/// Processes 16 bytes at a time for improved performance, then handles
696
/// remaining bytes with single-byte lookups.
697
#[allow(dead_code)]
698
pub(crate) fn native_update_u64(
699
    mut crc: u64,
700
    table: &[[u64; 256]; 16],
701
    reflect: bool,
702
    bytes: &[u8],
703
) -> u64 {
704
    let len = bytes.len();
705
    let mut i = 0;
706
707
    // Process 16 bytes at a time
708
    while i + 16 <= len {
709
        if reflect {
710
            let current0 = bytes[i] ^ (crc as u8);
711
            let current1 = bytes[i + 1] ^ ((crc >> 8) as u8);
712
            let current2 = bytes[i + 2] ^ ((crc >> 16) as u8);
713
            let current3 = bytes[i + 3] ^ ((crc >> 24) as u8);
714
            let current4 = bytes[i + 4] ^ ((crc >> 32) as u8);
715
            let current5 = bytes[i + 5] ^ ((crc >> 40) as u8);
716
            let current6 = bytes[i + 6] ^ ((crc >> 48) as u8);
717
            let current7 = bytes[i + 7] ^ ((crc >> 56) as u8);
718
719
            crc = table[0][bytes[i + 15] as usize]
720
                ^ table[1][bytes[i + 14] as usize]
721
                ^ table[2][bytes[i + 13] as usize]
722
                ^ table[3][bytes[i + 12] as usize]
723
                ^ table[4][bytes[i + 11] as usize]
724
                ^ table[5][bytes[i + 10] as usize]
725
                ^ table[6][bytes[i + 9] as usize]
726
                ^ table[7][bytes[i + 8] as usize]
727
                ^ table[8][current7 as usize]
728
                ^ table[9][current6 as usize]
729
                ^ table[10][current5 as usize]
730
                ^ table[11][current4 as usize]
731
                ^ table[12][current3 as usize]
732
                ^ table[13][current2 as usize]
733
                ^ table[14][current1 as usize]
734
                ^ table[15][current0 as usize];
735
        } else {
736
            let current0 = bytes[i] ^ ((crc >> 56) as u8);
737
            let current1 = bytes[i + 1] ^ ((crc >> 48) as u8);
738
            let current2 = bytes[i + 2] ^ ((crc >> 40) as u8);
739
            let current3 = bytes[i + 3] ^ ((crc >> 32) as u8);
740
            let current4 = bytes[i + 4] ^ ((crc >> 24) as u8);
741
            let current5 = bytes[i + 5] ^ ((crc >> 16) as u8);
742
            let current6 = bytes[i + 6] ^ ((crc >> 8) as u8);
743
            let current7 = bytes[i + 7] ^ (crc as u8);
744
745
            crc = table[0][bytes[i + 15] as usize]
746
                ^ table[1][bytes[i + 14] as usize]
747
                ^ table[2][bytes[i + 13] as usize]
748
                ^ table[3][bytes[i + 12] as usize]
749
                ^ table[4][bytes[i + 11] as usize]
750
                ^ table[5][bytes[i + 10] as usize]
751
                ^ table[6][bytes[i + 9] as usize]
752
                ^ table[7][bytes[i + 8] as usize]
753
                ^ table[8][current7 as usize]
754
                ^ table[9][current6 as usize]
755
                ^ table[10][current5 as usize]
756
                ^ table[11][current4 as usize]
757
                ^ table[12][current3 as usize]
758
                ^ table[13][current2 as usize]
759
                ^ table[14][current1 as usize]
760
                ^ table[15][current0 as usize];
761
        }
762
        i += 16;
763
    }
764
765
    // Process remaining bytes one at a time
766
    if reflect {
767
        while i < len {
768
            let table_index = ((crc ^ bytes[i] as u64) & 0xFF) as usize;
769
            crc = table[0][table_index] ^ (crc >> 8);
770
            i += 1;
771
        }
772
    } else {
773
        while i < len {
774
            let table_index = (((crc >> 56) ^ bytes[i] as u64) & 0xFF) as usize;
775
            crc = table[0][table_index] ^ (crc << 8);
776
            i += 1;
777
        }
778
    }
779
780
    crc
781
}
782
783
// ============================================================================
784
// Property Tests for Native Implementation
785
// ============================================================================
786
787
#[cfg(test)]
788
mod property_tests {
789
    use crate::test::consts::{
790
        RUST_CRC16_ARC, RUST_CRC16_IBM_SDLC, RUST_CRC16_T10_DIF, RUST_CRC32_BZIP2,
791
        RUST_CRC32_ISCSI, RUST_CRC32_ISO_HDLC, RUST_CRC64_ECMA_182, RUST_CRC64_NVME, RUST_CRC64_XZ,
792
        TEST_CHECK_STRING,
793
    };
794
    use crate::test::miri_compatible_proptest_config;
795
    use crate::{checksum, checksum_with_params, CrcAlgorithm, CrcParams, Digest};
796
    use proptest::prelude::*;
797
798
    proptest! {
799
        #![proptest_config(miri_compatible_proptest_config())]
800
801
        /// Feature: remove-crc-runtime-dependency, Property 1: Native Implementation Correctness
802
        /// *For any* supported CRC algorithm and *for any* byte sequence, the native implementation
803
        /// SHALL produce the same checksum as the `crc` crate reference implementation.
804
        /// **Validates: Requirements 2.2, 2.3, 4.2, 4.3, 6.2, 6.5**
805
        #[test]
806
        fn prop_native_crc16_reflected_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
807
            // Test CRC-16/IBM-SDLC (reflected)
808
            let our_result = checksum(CrcAlgorithm::Crc16IbmSdlc, &data);
809
            let reference_result = RUST_CRC16_IBM_SDLC.checksum(&data) as u64;
810
            prop_assert_eq!(
811
                our_result, reference_result,
812
                "CRC-16/IBM-SDLC native mismatch for {} bytes: our=0x{:04X}, ref=0x{:04X}",
813
                data.len(), our_result, reference_result
814
            );
815
        }
816
817
        /// Feature: remove-crc-runtime-dependency, Property 1: Native Implementation Correctness
818
        /// *For any* supported CRC algorithm and *for any* byte sequence, the native implementation
819
        /// SHALL produce the same checksum as the `crc` crate reference implementation.
820
        /// **Validates: Requirements 2.2, 2.3, 4.2, 4.3, 6.2, 6.5**
821
        #[test]
822
        fn prop_native_crc16_forward_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
823
            // Test CRC-16/T10-DIF (forward/non-reflected)
824
            let our_result = checksum(CrcAlgorithm::Crc16T10Dif, &data);
825
            let reference_result = RUST_CRC16_T10_DIF.checksum(&data) as u64;
826
            prop_assert_eq!(
827
                our_result, reference_result,
828
                "CRC-16/T10-DIF native mismatch for {} bytes: our=0x{:04X}, ref=0x{:04X}",
829
                data.len(), our_result, reference_result
830
            );
831
        }
832
833
        /// Feature: remove-crc-runtime-dependency, Property 1: Native Implementation Correctness
834
        /// *For any* supported CRC algorithm and *for any* byte sequence, the native implementation
835
        /// SHALL produce the same checksum as the `crc` crate reference implementation.
836
        /// **Validates: Requirements 2.2, 2.3, 4.2, 4.3, 6.2, 6.5**
837
        #[test]
838
        fn prop_native_crc32_reflected_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
839
            // Test CRC-32/ISO-HDLC (reflected)
840
            let our_result = checksum(CrcAlgorithm::Crc32IsoHdlc, &data);
841
            let reference_result = RUST_CRC32_ISO_HDLC.checksum(&data) as u64;
842
            prop_assert_eq!(
843
                our_result, reference_result,
844
                "CRC-32/ISO-HDLC native mismatch for {} bytes: our=0x{:08X}, ref=0x{:08X}",
845
                data.len(), our_result, reference_result
846
            );
847
        }
848
849
        /// Feature: remove-crc-runtime-dependency, Property 1: Native Implementation Correctness
850
        /// *For any* supported CRC algorithm and *for any* byte sequence, the native implementation
851
        /// SHALL produce the same checksum as the `crc` crate reference implementation.
852
        /// **Validates: Requirements 2.2, 2.3, 4.2, 4.3, 6.2, 6.5**
853
        #[test]
854
        fn prop_native_crc32_forward_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
855
            // Test CRC-32/BZIP2 (forward/non-reflected)
856
            let our_result = checksum(CrcAlgorithm::Crc32Bzip2, &data);
857
            let reference_result = RUST_CRC32_BZIP2.checksum(&data) as u64;
858
            prop_assert_eq!(
859
                our_result, reference_result,
860
                "CRC-32/BZIP2 native mismatch for {} bytes: our=0x{:08X}, ref=0x{:08X}",
861
                data.len(), our_result, reference_result
862
            );
863
        }
864
865
        /// Feature: remove-crc-runtime-dependency, Property 1: Native Implementation Correctness
866
        /// *For any* supported CRC algorithm and *for any* byte sequence, the native implementation
867
        /// SHALL produce the same checksum as the `crc` crate reference implementation.
868
        /// **Validates: Requirements 2.2, 2.3, 4.2, 4.3, 6.2, 6.5**
869
        #[test]
870
        fn prop_native_crc64_reflected_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
871
            // Test CRC-64/XZ (reflected)
872
            let our_result = checksum(CrcAlgorithm::Crc64Xz, &data);
873
            let reference_result = RUST_CRC64_XZ.checksum(&data);
874
            prop_assert_eq!(
875
                our_result, reference_result,
876
                "CRC-64/XZ native mismatch for {} bytes: our=0x{:016X}, ref=0x{:016X}",
877
                data.len(), our_result, reference_result
878
            );
879
        }
880
881
        /// Feature: remove-crc-runtime-dependency, Property 1: Native Implementation Correctness
882
        /// *For any* supported CRC algorithm and *for any* byte sequence, the native implementation
883
        /// SHALL produce the same checksum as the `crc` crate reference implementation.
884
        /// **Validates: Requirements 2.2, 2.3, 4.2, 4.3, 6.2, 6.5**
885
        #[test]
886
        fn prop_native_crc64_forward_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
887
            // Test CRC-64/ECMA-182 (forward/non-reflected)
888
            let our_result = checksum(CrcAlgorithm::Crc64Ecma182, &data);
889
            let reference_result = RUST_CRC64_ECMA_182.checksum(&data);
890
            prop_assert_eq!(
891
                our_result, reference_result,
892
                "CRC-64/ECMA-182 native mismatch for {} bytes: our=0x{:016X}, ref=0x{:016X}",
893
                data.len(), our_result, reference_result
894
            );
895
        }
896
897
        /// Feature: remove-crc-runtime-dependency, Property 3: Incremental Update Equivalence
898
        /// *For any* CRC algorithm and *for any* way of partitioning input data into chunks,
899
        /// computing the CRC incrementally via `Digest::update()` calls SHALL produce the same
900
        /// result as computing it in a single `checksum()` call.
901
        /// **Validates: Requirements 6.3, 6.5**
902
        #[test]
903
        fn prop_incremental_update_crc32_equivalence(
904
            data in proptest::collection::vec(any::<u8>(), 0..1024),
905
            split_point in 0usize..=1024usize
906
        ) {
907
            let split_point = split_point.min(data.len());
908
            let (part1, part2) = data.split_at(split_point);
909
910
            // Compute incrementally
911
            let mut digest = Digest::new(CrcAlgorithm::Crc32IsoHdlc);
912
            digest.update(part1);
913
            digest.update(part2);
914
            let incremental_result = digest.finalize();
915
916
            // Compute in one shot
917
            let single_result = checksum(CrcAlgorithm::Crc32IsoHdlc, &data);
918
919
            prop_assert_eq!(
920
                incremental_result, single_result,
921
                "CRC-32/ISO-HDLC incremental mismatch: incremental=0x{:08X}, single=0x{:08X}, split_point={}",
922
                incremental_result, single_result, split_point
923
            );
924
        }
925
926
        /// Feature: remove-crc-runtime-dependency, Property 3: Incremental Update Equivalence
927
        /// *For any* CRC algorithm and *for any* way of partitioning input data into chunks,
928
        /// computing the CRC incrementally via `Digest::update()` calls SHALL produce the same
929
        /// result as computing it in a single `checksum()` call.
930
        /// **Validates: Requirements 6.3, 6.5**
931
        #[test]
932
        fn prop_incremental_update_crc64_equivalence(
933
            data in proptest::collection::vec(any::<u8>(), 0..1024),
934
            split_point in 0usize..=1024usize
935
        ) {
936
            let split_point = split_point.min(data.len());
937
            let (part1, part2) = data.split_at(split_point);
938
939
            // Compute incrementally
940
            let mut digest = Digest::new(CrcAlgorithm::Crc64Nvme);
941
            digest.update(part1);
942
            digest.update(part2);
943
            let incremental_result = digest.finalize();
944
945
            // Compute in one shot
946
            let single_result = checksum(CrcAlgorithm::Crc64Nvme, &data);
947
948
            prop_assert_eq!(
949
                incremental_result, single_result,
950
                "CRC-64/NVME incremental mismatch: incremental=0x{:016X}, single=0x{:016X}, split_point={}",
951
                incremental_result, single_result, split_point
952
            );
953
        }
954
955
        /// Feature: remove-crc-runtime-dependency, Property 4: Custom Parameters Correctness
956
        /// *For any* valid custom CRC parameters (width 16, 32, or 64) and *for any* byte sequence,
957
        /// the native implementation SHALL produce the same checksum as the `crc` crate when
958
        /// configured with equivalent parameters.
959
        /// **Validates: Requirements 5.1, 6.4**
960
        #[test]
961
        fn prop_custom_params_crc16_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
962
            // Custom CRC-16 parameters equivalent to CRC-16/ARC
963
            let custom_params = CrcParams::new(
964
                "CRC-16/CUSTOM-ARC",
965
                16,
966
                0x8005,  // poly
967
                0x0000,  // init
968
                true,    // refin
969
                0x0000,  // xorout
970
                0xBB3D,  // check
971
            );
972
            let our_result = checksum_with_params(custom_params, &data);
973
            let reference_result = RUST_CRC16_ARC.checksum(&data) as u64;
974
            prop_assert_eq!(
975
                our_result, reference_result,
976
                "CRC-16 custom params mismatch for {} bytes: our=0x{:04X}, ref=0x{:04X}",
977
                data.len(), our_result, reference_result
978
            );
979
        }
980
981
        /// Feature: remove-crc-runtime-dependency, Property 4: Custom Parameters Correctness
982
        /// *For any* valid custom CRC parameters (width 16, 32, or 64) and *for any* byte sequence,
983
        /// the native implementation SHALL produce the same checksum as the `crc` crate when
984
        /// configured with equivalent parameters.
985
        /// **Validates: Requirements 5.1, 6.4**
986
        #[test]
987
        fn prop_custom_params_crc32_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
988
            // Custom CRC-32 parameters equivalent to CRC-32/ISCSI
989
            let custom_params = CrcParams::new(
990
                "CRC-32/CUSTOM-ISCSI",
991
                32,
992
                0x1EDC6F41,  // poly
993
                0xFFFFFFFF,  // init
994
                true,        // refin
995
                0xFFFFFFFF,  // xorout
996
                0xE3069283,  // check
997
            );
998
            let our_result = checksum_with_params(custom_params, &data);
999
            let reference_result = RUST_CRC32_ISCSI.checksum(&data) as u64;
1000
            prop_assert_eq!(
1001
                our_result, reference_result,
1002
                "CRC-32 custom params mismatch for {} bytes: our=0x{:08X}, ref=0x{:08X}",
1003
                data.len(), our_result, reference_result
1004
            );
1005
        }
1006
1007
        /// Feature: remove-crc-runtime-dependency, Property 4: Custom Parameters Correctness
1008
        /// *For any* valid custom CRC parameters (width 16, 32, or 64) and *for any* byte sequence,
1009
        /// the native implementation SHALL produce the same checksum as the `crc` crate when
1010
        /// configured with equivalent parameters.
1011
        /// **Validates: Requirements 5.1, 6.4**
1012
        #[test]
1013
        fn prop_custom_params_crc64_matches_reference(data in proptest::collection::vec(any::<u8>(), 0..1024)) {
1014
            // Custom CRC-64 parameters equivalent to CRC-64/NVME
1015
            let custom_params = CrcParams::new(
1016
                "CRC-64/CUSTOM-NVME",
1017
                64,
1018
                0xAD93D23594C93659,  // poly
1019
                0xFFFFFFFFFFFFFFFF,  // init
1020
                true,                 // refin
1021
                0xFFFFFFFFFFFFFFFF,  // xorout
1022
                0xAE8B14860A799888,  // check
1023
            );
1024
            let our_result = checksum_with_params(custom_params, &data);
1025
            let reference_result = RUST_CRC64_NVME.checksum(&data);
1026
            prop_assert_eq!(
1027
                our_result, reference_result,
1028
                "CRC-64 custom params mismatch for {} bytes: our=0x{:016X}, ref=0x{:016X}",
1029
                data.len(), our_result, reference_result
1030
            );
1031
        }
1032
    }
1033
1034
    /// Feature: remove-crc-runtime-dependency, Property 2: Check Value Verification
1035
    /// *For any* known CRC algorithm constant, computing the CRC of the byte sequence
1036
    /// `b"123456789"` SHALL produce the documented check value from the CRC catalogue specification.
1037
    /// **Validates: Requirements 3.2, 3.3, 3.4, 3.5**
1038
    #[test]
1039
    fn test_check_values_crc16() {
1040
        use crate::crc16::consts::*;
1041
1042
        let test_cases: &[(&str, CrcParams, u64)] = &[
1043
            ("CRC-16/ARC", CRC16_ARC, 0xBB3D),
1044
            ("CRC-16/CDMA2000", CRC16_CDMA2000, 0x4C06),
1045
            ("CRC-16/CMS", CRC16_CMS, 0xAEE7),
1046
            ("CRC-16/DDS-110", CRC16_DDS_110, 0x9ECF),
1047
            ("CRC-16/DECT-R", CRC16_DECT_R, 0x007E),
1048
            ("CRC-16/DECT-X", CRC16_DECT_X, 0x007F),
1049
            ("CRC-16/DNP", CRC16_DNP, 0xEA82),
1050
            ("CRC-16/EN-13757", CRC16_EN_13757, 0xC2B7),
1051
            ("CRC-16/GENIBUS", CRC16_GENIBUS, 0xD64E),
1052
            ("CRC-16/GSM", CRC16_GSM, 0xCE3C),
1053
            ("CRC-16/IBM-3740", CRC16_IBM_3740, 0x29B1),
1054
            ("CRC-16/IBM-SDLC", CRC16_IBM_SDLC, 0x906E),
1055
            ("CRC-16/ISO-IEC-14443-3-A", CRC16_ISO_IEC_14443_3_A, 0xBF05),
1056
            ("CRC-16/KERMIT", CRC16_KERMIT, 0x2189),
1057
            ("CRC-16/LJ1200", CRC16_LJ1200, 0xBDF4),
1058
            ("CRC-16/M17", CRC16_M17, 0x772B),
1059
            ("CRC-16/MAXIM-DOW", CRC16_MAXIM_DOW, 0x44C2),
1060
            ("CRC-16/MCRF4XX", CRC16_MCRF4XX, 0x6F91),
1061
            ("CRC-16/MODBUS", CRC16_MODBUS, 0x4B37),
1062
            ("CRC-16/NRSC-5", CRC16_NRSC_5, 0xA066),
1063
            ("CRC-16/OPENSAFETY-A", CRC16_OPENSAFETY_A, 0x5D38),
1064
            ("CRC-16/OPENSAFETY-B", CRC16_OPENSAFETY_B, 0x20FE),
1065
            ("CRC-16/PROFIBUS", CRC16_PROFIBUS, 0xA819),
1066
            ("CRC-16/RIELLO", CRC16_RIELLO, 0x63D0),
1067
            ("CRC-16/SPI-FUJITSU", CRC16_SPI_FUJITSU, 0xE5CC),
1068
            ("CRC-16/T10-DIF", CRC16_T10_DIF, 0xD0DB),
1069
            ("CRC-16/TELEDISK", CRC16_TELEDISK, 0x0FB3),
1070
            ("CRC-16/TMS37157", CRC16_TMS37157, 0x26B1),
1071
            ("CRC-16/UMTS", CRC16_UMTS, 0xFEE8),
1072
            ("CRC-16/USB", CRC16_USB, 0xB4C8),
1073
            ("CRC-16/XMODEM", CRC16_XMODEM, 0x31C3),
1074
        ];
1075
1076
        for (name, params, expected_check) in test_cases {
1077
            let result = checksum_with_params(*params, TEST_CHECK_STRING);
1078
            assert_eq!(
1079
                result, *expected_check,
1080
                "{} check value mismatch: got 0x{:04X}, expected 0x{:04X}",
1081
                name, result, expected_check
1082
            );
1083
        }
1084
    }
1085
1086
    /// Feature: remove-crc-runtime-dependency, Property 2: Check Value Verification
1087
    /// *For any* known CRC algorithm constant, computing the CRC of the byte sequence
1088
    /// `b"123456789"` SHALL produce the documented check value from the CRC catalogue specification.
1089
    /// **Validates: Requirements 3.2, 3.3, 3.4, 3.5**
1090
    #[test]
1091
    fn test_check_values_crc32() {
1092
        use crate::crc32::consts::*;
1093
1094
        let test_cases: &[(&str, CrcParams, u64)] = &[
1095
            ("CRC-32/AIXM", CRC32_AIXM, 0x3010BF7F),
1096
            ("CRC-32/AUTOSAR", CRC32_AUTOSAR, 0x1697D06A),
1097
            ("CRC-32/BASE91-D", CRC32_BASE91_D, 0x87315576),
1098
            ("CRC-32/BZIP2", CRC32_BZIP2, 0xFC891918),
1099
            ("CRC-32/CD-ROM-EDC", CRC32_CD_ROM_EDC, 0x6EC2EDC4),
1100
            ("CRC-32/CKSUM", CRC32_CKSUM, 0x765E7680),
1101
            ("CRC-32/ISCSI", CRC32_ISCSI, 0xE3069283),
1102
            ("CRC-32/ISO-HDLC", CRC32_ISO_HDLC, 0xCBF43926),
1103
            ("CRC-32/JAMCRC", CRC32_JAMCRC, 0x340BC6D9),
1104
            ("CRC-32/MEF", CRC32_MEF, 0xD2C22F51),
1105
            ("CRC-32/MPEG-2", CRC32_MPEG_2, 0x0376E6E7),
1106
            ("CRC-32/XFER", CRC32_XFER, 0xBD0BE338),
1107
        ];
1108
1109
        for (name, params, expected_check) in test_cases {
1110
            let result = checksum_with_params(*params, TEST_CHECK_STRING);
1111
            assert_eq!(
1112
                result, *expected_check,
1113
                "{} check value mismatch: got 0x{:08X}, expected 0x{:08X}",
1114
                name, result, expected_check
1115
            );
1116
        }
1117
    }
1118
1119
    /// Feature: remove-crc-runtime-dependency, Property 2: Check Value Verification
1120
    /// *For any* known CRC algorithm constant, computing the CRC of the byte sequence
1121
    /// `b"123456789"` SHALL produce the documented check value from the CRC catalogue specification.
1122
    /// **Validates: Requirements 3.2, 3.3, 3.4, 3.5**
1123
    #[test]
1124
    fn test_check_values_crc64() {
1125
        use crate::crc64::consts::*;
1126
1127
        let test_cases: &[(&str, CrcParams, u64)] = &[
1128
            ("CRC-64/ECMA-182", CRC64_ECMA_182, 0x6C40DF5F0B497347),
1129
            ("CRC-64/GO-ISO", CRC64_GO_ISO, 0xB90956C775A41001),
1130
            ("CRC-64/MS", CRC64_MS, 0x75D4B74F024ECEEA),
1131
            ("CRC-64/NVME", CRC64_NVME, 0xAE8B14860A799888),
1132
            ("CRC-64/REDIS", CRC64_REDIS, 0xE9C6D914C4B8D9CA),
1133
            ("CRC-64/WE", CRC64_WE, 0x62EC59E3F1A4F00A),
1134
            ("CRC-64/XZ", CRC64_XZ, 0x995DC9BBDF1939FA),
1135
        ];
1136
1137
        for (name, params, expected_check) in test_cases {
1138
            let result = checksum_with_params(*params, TEST_CHECK_STRING);
1139
            assert_eq!(
1140
                result, *expected_check,
1141
                "{} check value mismatch: got 0x{:016X}, expected 0x{:016X}",
1142
                name, result, expected_check
1143
            );
1144
        }
1145
    }
1146
}