2cd40ea1 Andy McCall 1 month ago ↶
1
2
3
#! [ cfg_attr ( not ( feature = " std" ) , no_std) ]
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# [ cfg ( all (
146
feature = " panic-handler" ,
147
not ( feature = " std" ) ,
148
not ( test ) ,
149
not ( doctest )
150
) ) ]
151
# [ panic_handler ]
152
fn panic ( _info : & core:: panic:: PanicInfo) -> ! {
153
loop { }
154
}
155
156
157
158
# [ cfg ( all (
159
feature = " panic-handler" ,
160
feature = " alloc" ,
161
not ( feature = " std" ) ,
162
not ( test ) ,
163
not ( doctest )
164
) ) ]
165
# [ global_allocator ]
166
static ALLOCATOR : StubAllocator = StubAllocator;
167
168
# [ cfg ( all (
169
feature = " panic-handler" ,
170
feature = " alloc" ,
171
not ( feature = " std" ) ,
172
not ( test ) ,
173
not ( doctest )
174
) ) ]
175
struct StubAllocator ;
176
177
# [ cfg ( all (
178
feature = " panic-handler" ,
179
feature = " alloc" ,
180
not ( feature = " std" ) ,
181
not ( test ) ,
182
not ( doctest )
183
) ) ]
184
unsafe impl core:: alloc:: GlobalAlloc for StubAllocator {
185
unsafe fn alloc ( & self , _layout : core:: alloc:: Layout) -> * mut u8 {
186
core:: ptr:: null_mut( )
187
}
188
unsafe fn dealloc ( & self , _ptr : *mut u8 , _layout : core:: alloc:: Layout) { }
189
}
190
191
use crate :: crc16:: consts:: {
192
CRC16_ARC , CRC16_CDMA2000 , CRC16_CMS , CRC16_DDS_110 , CRC16_DECT_R , CRC16_DECT_X , CRC16_DNP ,
193
CRC16_EN_13757 , CRC16_GENIBUS , CRC16_GSM , CRC16_IBM_3740 , CRC16_IBM_SDLC ,
194
CRC16_ISO_IEC_14443_3_A , CRC16_KERMIT , CRC16_LJ1200 , CRC16_M17 , CRC16_MAXIM_DOW , CRC16_MCRF4XX ,
195
CRC16_MODBUS , CRC16_NRSC_5 , CRC16_OPENSAFETY_A , CRC16_OPENSAFETY_B , CRC16_PROFIBUS ,
196
CRC16_RIELLO , CRC16_SPI_FUJITSU , CRC16_T10_DIF , CRC16_TELEDISK , CRC16_TMS37157 , CRC16_UMTS ,
197
CRC16_USB , CRC16_XMODEM ,
198
} ;
199
200
use crate :: crc32:: consts:: {
201
CRC32_AIXM , CRC32_AUTOSAR , CRC32_BASE91_D , CRC32_BZIP2 , CRC32_CD_ROM_EDC , CRC32_CKSUM ,
202
CRC32_ISCSI , CRC32_ISO_HDLC , CRC32_JAMCRC , CRC32_MEF , CRC32_MPEG_2 , CRC32_XFER ,
203
} ;
204
205
# [ cfg ( any ( target_arch = " x86" , target_arch = " x86_64" , target_arch = " aarch64" ) ) ]
206
# [ cfg ( feature = " std" ) ]
207
use crate :: crc32:: fusion;
208
209
use crate :: crc64:: consts:: {
210
CRC64_ECMA_182 , CRC64_GO_ISO , CRC64_MS , CRC64_NVME , CRC64_REDIS , CRC64_WE , CRC64_XZ ,
211
} ;
212
use crate :: structs:: Calculator;
213
use crate :: traits:: CrcCalculator;
214
# [ cfg ( feature = " alloc" ) ]
215
use digest:: DynDigest;
216
# [ cfg ( feature = " alloc" ) ]
217
use digest:: InvalidBufferSize;
218
219
# [ cfg ( any ( target_arch = " x86" , target_arch = " x86_64" , target_arch = " aarch64" ) ) ]
220
use crate :: feature_detection:: get_arch_ops;
221
# [ cfg ( feature = " std" ) ]
222
use std:: fs:: File;
223
# [ cfg ( feature = " std" ) ]
224
use std:: io:: { Read, Write} ;
225
226
# [ cfg ( all ( feature = " alloc" , not ( feature = " std" ) ) ) ]
227
extern crate alloc;
228
# [ cfg ( all ( feature = " alloc" , not ( feature = " std" ) ) ) ]
229
use alloc:: boxed:: Box;
230
# [ cfg ( all ( feature = " alloc" , not ( feature = " std" ) ) ) ]
231
use alloc:: string:: String;
232
233
mod algorithm ;
234
pub mod arch ;
235
mod cache ;
236
mod combine ;
237
mod consts ;
238
mod crc16 ;
239
mod crc32 ;
240
mod crc64 ;
241
mod enums ;
242
mod feature_detection ;
243
# [ cfg ( feature = " ffi" ) ]
244
mod ffi ;
245
mod generate ;
246
mod structs ;
247
mod tables ;
248
mod test ;
249
mod traits ;
250
251
252
# [ derive ( Debug, Clone, Copy, PartialEq ) ]
253
pub enum CrcAlgorithm {
254
255
256
CrcCustom,
257
Crc16Arc,
258
Crc16Cdma2000,
259
Crc16Cms,
260
Crc16Dds110,
261
Crc16DectR,
262
Crc16DectX,
263
Crc16Dnp,
264
Crc16En13757,
265
Crc16Genibus,
266
Crc16Gsm,
267
Crc16Ibm3740,
268
Crc16IbmSdlc,
269
Crc16IsoIec144433A,
270
Crc16Kermit,
271
Crc16Lj1200,
272
Crc16M17,
273
Crc16MaximDow,
274
Crc16Mcrf4xx,
275
Crc16Modbus,
276
Crc16Nrsc5,
277
Crc16OpensafetyA,
278
Crc16OpensafetyB,
279
Crc16Profibus,
280
Crc16Riello,
281
Crc16SpiFujitsu,
282
Crc16T10Dif,
283
Crc16Teledisk,
284
Crc16Tms37157,
285
Crc16Umts,
286
Crc16Usb,
287
Crc16Xmodem,
288
Crc32Aixm,
289
Crc32Autosar,
290
Crc32Base91D,
291
Crc32Bzip2,
292
Crc32CdRomEdc,
293
Crc32Cksum,
294
# [ deprecated (
295
since = " 1.9.0" ,
296
note = " Use CrcCustom instead, which works with any supported width (16, 32, 64)"
297
) ]
298
Crc32Custom,
299
Crc32Iscsi,
300
Crc32IsoHdlc,
301
Crc32Jamcrc,
302
Crc32Mef,
303
Crc32Mpeg2,
304
Crc32Xfer,
305
# [ deprecated (
306
since = " 1.9.0" ,
307
note = " Use CrcCustom instead, which works with any supported width (16, 32, 64)"
308
) ]
309
Crc64Custom,
310
Crc64Ecma182,
311
Crc64GoIso,
312
Crc64Ms,
313
Crc64Nvme,
314
Crc64Redis,
315
Crc64We,
316
Crc64Xz,
317
}
318
319
320
321
322
# [ derive ( Clone, Copy, Debug, PartialEq ) ]
323
pub enum CrcKeysStorage {
324
325
KeysFold256( [ u64 ; 23 ] ) ,
326
327
KeysFutureTest( [ u64 ; 25 ] ) ,
328
}
329
330
impl CrcKeysStorage {
331
332
# [ inline ( always ) ]
333
const fn get_key ( self , index : usize ) -> u64 {
334
match self {
335
CrcKeysStorage:: KeysFold256( keys) => {
336
if index < 23 {
337
keys[ index]
338
} else {
339
0
340
}
341
}
342
CrcKeysStorage:: KeysFutureTest( keys) => {
343
if index < 25 {
344
keys[ index]
345
} else {
346
0
347
}
348
}
349
}
350
}
351
352
353
# [ inline ( always ) ]
354
const fn key_count ( self ) -> usize {
355
match self {
356
CrcKeysStorage:: KeysFold256( _ ) => 23 ,
357
CrcKeysStorage:: KeysFutureTest( _ ) => 25 ,
358
}
359
}
360
361
362
# [ inline ( always ) ]
363
const fn from_keys_fold_256 ( keys : [u64 ; 23]) -> Self {
364
CrcKeysStorage:: KeysFold256( keys)
365
}
366
367
368
# [ inline ( always ) ]
369
# [ allow ( dead_code ) ]
370
const fn from_keys_fold_future_test ( keys : [u64 ; 25]) -> Self {
371
CrcKeysStorage:: KeysFutureTest( keys)
372
}
373
374
375
376
377
# [ inline ( always ) ]
378
pub fn to_keys_array_23 ( self ) -> [ u64 ; 23 ] {
379
match self {
380
CrcKeysStorage:: KeysFold256( keys) => keys,
381
CrcKeysStorage:: KeysFutureTest( keys) => {
382
let mut result = [ 0 u64 ; 23 ] ;
383
result.copy_from_slice ( & keys[ .. 23 ] ) ;
384
result
385
}
386
}
387
}
388
}
389
390
391
impl PartialEq< [ u64 ; 23 ] > for CrcKeysStorage {
392
fn eq ( & self , other : & [u64 ; 23]) -> bool {
393
self .to_keys_array_23 ( ) = = * other
394
}
395
}
396
397
impl PartialEq< CrcKeysStorage> for [u64 ; 23] {
398
fn eq ( & self , other : & CrcKeysStorage) -> bool {
399
* self = = other.to_keys_array_23 ( )
400
}
401
}
402
403
404
# [ derive ( Clone, Copy, Debug ) ]
405
pub struct CrcParams {
406
pub algorithm : CrcAlgorithm,
407
pub name : & 'static str ,
408
pub width : u8 ,
409
pub poly : u64 ,
410
pub init : u64 ,
411
412
413
414
415
416
417
418
419
420
421
422
pub init_algorithm : u64 ,
423
pub refin : bool ,
424
pub refout : bool ,
425
pub xorout : u64 ,
426
pub check : u64 ,
427
pub keys : CrcKeysStorage,
428
}
429
430
431
432
433
434
435
436
437
438
439
440
441
type CalculatorFn = fn (
442
u64 ,
443
& [ u8 ] ,
444
& CrcParams,
445
) -> u64 ;
446
447
448
449
450
451
452
# [ derive ( Copy, Clone, Debug ) ]
453
pub struct Digest {
454
455
state : u64 ,
456
457
458
amount : u64 ,
459
460
461
params : CrcParams,
462
463
464
calculator : CalculatorFn,
465
}
466
467
# [ cfg ( feature = " alloc" ) ]
468
impl DynDigest for Digest {
469
# [ inline ( always ) ]
470
fn update ( & mut self , data : & [u8 ]) {
471
self .update ( data) ;
472
}
473
474
# [ inline ( always ) ]
475
fn finalize_into ( self , buf : & mut [u8 ]) -> Result< ( ) , InvalidBufferSize> {
476
if buf.len ( ) ! = self .output_size ( ) {
477
return Err ( InvalidBufferSize) ;
478
}
479
480
let result = self .finalize ( ) ;
481
let be_bytes = result.to_be_bytes ( ) ;
482
let start = 8 - self .output_size ( ) ;
483
buf.copy_from_slice ( & be_bytes[ start.. ] ) ;
484
485
Ok ( ( ) )
486
}
487
488
# [ inline ( always ) ]
489
fn finalize_into_reset ( & mut self , out : & mut [u8 ]) -> Result< ( ) , InvalidBufferSize> {
490
if out.len ( ) ! = self .output_size ( ) {
491
return Err ( InvalidBufferSize) ;
492
}
493
let result = self .finalize ( ) ;
494
self .reset ( ) ;
495
let be_bytes = result.to_be_bytes ( ) ;
496
let start = 8 - self .output_size ( ) ;
497
out.copy_from_slice ( & be_bytes[ start.. ] ) ;
498
Ok ( ( ) )
499
}
500
501
# [ inline ( always ) ]
502
fn reset ( & mut self ) {
503
self .reset ( ) ;
504
}
505
506
# [ inline ( always ) ]
507
fn output_size ( & self ) -> usize {
508
self .params.width as usize / 8
509
}
510
511
fn box_clone ( & self ) -> Box< dyn DynDigest> {
512
Box :: new( * self )
513
}
514
}
515
516
impl Digest {
517
518
519
520
521
522
523
524
525
526
527
528
529
530
# [ inline ( always ) ]
531
pub fn new ( algorithm : CrcAlgorithm) -> Self {
532
let ( calculator, params) = get_calculator_params ( algorithm) ;
533
534
Self {
535
state: params.init_algorithm,
536
amount: 0 ,
537
params,
538
calculator,
539
}
540
}
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# [ inline ( always ) ]
566
pub fn new_with_init_state ( algorithm : CrcAlgorithm, init_state : u64 ) -> Self {
567
let ( calculator, params) = get_calculator_params ( algorithm) ;
568
569
Self {
570
state: init_state,
571
amount: 0 ,
572
params,
573
calculator,
574
}
575
}
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
# [ inline ( always ) ]
602
pub fn new_with_params ( params : CrcParams) -> Self {
603
let calculator = Calculator:: calculate as CalculatorFn;
604
605
Self {
606
state: params.init_algorithm,
607
amount: 0 ,
608
params,
609
calculator,
610
}
611
}
612
613
614
# [ inline ( always ) ]
615
pub fn update ( & mut self , data : & [u8 ]) {
616
self .state = ( self .calculator) ( self .state, data, & self .params) ;
617
self .amount + = data.len ( ) as u64 ;
618
}
619
620
621
# [ inline ( always ) ]
622
pub fn finalize ( & self ) -> u64 {
623
self .state ^ self .params.xorout
624
}
625
626
627
# [ inline ( always ) ]
628
pub fn finalize_reset ( & mut self ) -> u64 {
629
let result = self .finalize ( ) ;
630
self .reset ( ) ;
631
632
result
633
}
634
635
636
# [ inline ( always ) ]
637
pub fn reset ( & mut self ) {
638
self .state = self .params.init_algorithm;
639
self .amount = 0 ;
640
}
641
642
643
# [ inline ( always ) ]
644
pub fn combine ( & mut self , other : & Self ) {
645
self .amount + = other.amount;
646
let other_crc = other.finalize ( ) ;
647
648
649
650
self .state = combine:: checksums(
651
self .state ^ self .params.xorout,
652
other_crc,
653
other.amount,
654
& self .params,
655
) ^ self .params.xorout;
656
}
657
658
659
# [ inline ( always ) ]
660
pub fn get_amount ( & self ) -> u64 {
661
self .amount
662
}
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
# [ inline ( always ) ]
681
pub fn get_state ( & self ) -> u64 {
682
self .state
683
}
684
}
685
686
# [ cfg ( feature = " std" ) ]
687
impl Write for Digest {
688
# [ inline ( always ) ]
689
fn write ( & mut self , buf : & [u8 ]) -> std:: io:: Result< usize > {
690
self .update ( buf) ;
691
Ok ( buf.len ( ) )
692
}
693
694
# [ inline ( always ) ]
695
fn write_vectored ( & mut self , bufs : & [std:: io:: IoSlice< '_ > ]) -> std:: io:: Result< usize > {
696
let len: usize = bufs
697
.iter ( )
698
.map ( | buf | {
699
self .update ( buf) ;
700
buf.len ( )
701
} )
702
.sum ( ) ;
703
704
Ok ( len)
705
}
706
707
# [ inline ( always ) ]
708
fn flush ( & mut self ) -> std:: io:: Result< ( ) > {
709
Ok ( ( ) )
710
}
711
712
# [ inline ( always ) ]
713
fn write_all ( & mut self , buf : & [u8 ]) -> std:: io:: Result< ( ) > {
714
self .update ( buf) ;
715
716
Ok ( ( ) )
717
}
718
}
719
720
721
722
723
724
725
726
727
728
# [ inline ]
729
# [ allow ( deprecated ) ]
730
pub fn checksum ( algorithm : CrcAlgorithm, buf : & [u8 ]) -> u64 {
731
732
match algorithm {
733
CrcAlgorithm:: Crc16Arc => {
734
Calculator:: calculate( CRC16_ARC .init, buf, & CRC16_ARC ) ^ CRC16_ARC .xorout
735
}
736
CrcAlgorithm:: Crc16Cdma2000 => {
737
Calculator:: calculate( CRC16_CDMA2000 .init, buf, & CRC16_CDMA2000 ) ^ CRC16_CDMA2000 .xorout
738
}
739
CrcAlgorithm:: Crc16Cms => {
740
Calculator:: calculate( CRC16_CMS .init, buf, & CRC16_CMS ) ^ CRC16_CMS .xorout
741
}
742
CrcAlgorithm:: Crc16Dds110 => {
743
Calculator:: calculate( CRC16_DDS_110 .init, buf, & CRC16_DDS_110 ) ^ CRC16_DDS_110 .xorout
744
}
745
CrcAlgorithm:: Crc16DectR => {
746
Calculator:: calculate( CRC16_DECT_R .init, buf, & CRC16_DECT_R ) ^ CRC16_DECT_R .xorout
747
}
748
CrcAlgorithm:: Crc16DectX => {
749
Calculator:: calculate( CRC16_DECT_X .init, buf, & CRC16_DECT_X ) ^ CRC16_DECT_X .xorout
750
}
751
CrcAlgorithm:: Crc16Dnp => {
752
Calculator:: calculate( CRC16_DNP .init, buf, & CRC16_DNP ) ^ CRC16_DNP .xorout
753
}
754
CrcAlgorithm:: Crc16En13757 => {
755
Calculator:: calculate( CRC16_EN_13757 .init, buf, & CRC16_EN_13757 ) ^ CRC16_EN_13757 .xorout
756
}
757
CrcAlgorithm:: Crc16Genibus => {
758
Calculator:: calculate( CRC16_GENIBUS .init, buf, & CRC16_GENIBUS ) ^ CRC16_GENIBUS .xorout
759
}
760
CrcAlgorithm:: Crc16Gsm => {
761
Calculator:: calculate( CRC16_GSM .init, buf, & CRC16_GSM ) ^ CRC16_GSM .xorout
762
}
763
CrcAlgorithm:: Crc16Ibm3740 => {
764
Calculator:: calculate( CRC16_IBM_3740 .init, buf, & CRC16_IBM_3740 ) ^ CRC16_IBM_3740 .xorout
765
}
766
CrcAlgorithm:: Crc16IbmSdlc => {
767
Calculator:: calculate( CRC16_IBM_SDLC .init, buf, & CRC16_IBM_SDLC ) ^ CRC16_IBM_SDLC .xorout
768
}
769
CrcAlgorithm:: Crc16IsoIec144433A => {
770
Calculator:: calculate(
771
CRC16_ISO_IEC_14443_3_A .init_algorithm,
772
buf,
773
& CRC16_ISO_IEC_14443_3_A ,
774
) ^ CRC16_ISO_IEC_14443_3_A .xorout
775
}
776
CrcAlgorithm:: Crc16Kermit => {
777
Calculator:: calculate( CRC16_KERMIT .init, buf, & CRC16_KERMIT ) ^ CRC16_KERMIT .xorout
778
}
779
CrcAlgorithm:: Crc16Lj1200 => {
780
Calculator:: calculate( CRC16_LJ1200 .init, buf, & CRC16_LJ1200 ) ^ CRC16_LJ1200 .xorout
781
}
782
CrcAlgorithm:: Crc16M17 => {
783
Calculator:: calculate( CRC16_M17 .init, buf, & CRC16_M17 ) ^ CRC16_M17 .xorout
784
}
785
CrcAlgorithm:: Crc16MaximDow => {
786
Calculator:: calculate( CRC16_MAXIM_DOW .init, buf, & CRC16_MAXIM_DOW )
787
^ CRC16_MAXIM_DOW .xorout
788
}
789
CrcAlgorithm:: Crc16Mcrf4xx => {
790
Calculator:: calculate( CRC16_MCRF4XX .init, buf, & CRC16_MCRF4XX ) ^ CRC16_MCRF4XX .xorout
791
}
792
CrcAlgorithm:: Crc16Modbus => {
793
Calculator:: calculate( CRC16_MODBUS .init, buf, & CRC16_MODBUS ) ^ CRC16_MODBUS .xorout
794
}
795
CrcAlgorithm:: Crc16Nrsc5 => {
796
Calculator:: calculate( CRC16_NRSC_5 .init, buf, & CRC16_NRSC_5 ) ^ CRC16_NRSC_5 .xorout
797
}
798
CrcAlgorithm:: Crc16OpensafetyA => {
799
Calculator:: calculate( CRC16_OPENSAFETY_A .init, buf, & CRC16_OPENSAFETY_A )
800
^ CRC16_OPENSAFETY_A .xorout
801
}
802
CrcAlgorithm:: Crc16OpensafetyB => {
803
Calculator:: calculate( CRC16_OPENSAFETY_B .init, buf, & CRC16_OPENSAFETY_B )
804
^ CRC16_OPENSAFETY_B .xorout
805
}
806
CrcAlgorithm:: Crc16Profibus => {
807
Calculator:: calculate( CRC16_PROFIBUS .init, buf, & CRC16_PROFIBUS ) ^ CRC16_PROFIBUS .xorout
808
}
809
CrcAlgorithm:: Crc16Riello => {
810
Calculator:: calculate( CRC16_RIELLO .init_algorithm, buf, & CRC16_RIELLO )
811
^ CRC16_RIELLO .xorout
812
}
813
CrcAlgorithm:: Crc16SpiFujitsu => {
814
Calculator:: calculate( CRC16_SPI_FUJITSU .init, buf, & CRC16_SPI_FUJITSU )
815
^ CRC16_SPI_FUJITSU .xorout
816
}
817
CrcAlgorithm:: Crc16T10Dif => {
818
Calculator:: calculate( CRC16_T10_DIF .init, buf, & CRC16_T10_DIF ) ^ CRC16_T10_DIF .xorout
819
}
820
CrcAlgorithm:: Crc16Teledisk => {
821
Calculator:: calculate( CRC16_TELEDISK .init, buf, & CRC16_TELEDISK ) ^ CRC16_TELEDISK .xorout
822
}
823
CrcAlgorithm:: Crc16Tms37157 => {
824
Calculator:: calculate( CRC16_TMS37157 .init_algorithm, buf, & CRC16_TMS37157 )
825
^ CRC16_TMS37157 .xorout
826
}
827
CrcAlgorithm:: Crc16Umts => {
828
Calculator:: calculate( CRC16_UMTS .init, buf, & CRC16_UMTS ) ^ CRC16_UMTS .xorout
829
}
830
CrcAlgorithm:: Crc16Usb => {
831
Calculator:: calculate( CRC16_USB .init, buf, & CRC16_USB ) ^ CRC16_USB .xorout
832
}
833
CrcAlgorithm:: Crc16Xmodem => {
834
Calculator:: calculate( CRC16_XMODEM .init, buf, & CRC16_XMODEM ) ^ CRC16_XMODEM .xorout
835
}
836
CrcAlgorithm:: Crc32Aixm => {
837
Calculator:: calculate( CRC32_AIXM .init, buf, & CRC32_AIXM ) ^ CRC32_AIXM .xorout
838
}
839
CrcAlgorithm:: Crc32Autosar => {
840
Calculator:: calculate( CRC32_AUTOSAR .init, buf, & CRC32_AUTOSAR ) ^ CRC32_AUTOSAR .xorout
841
}
842
CrcAlgorithm:: Crc32Base91D => {
843
Calculator:: calculate( CRC32_BASE91_D .init, buf, & CRC32_BASE91_D ) ^ CRC32_BASE91_D .xorout
844
}
845
CrcAlgorithm:: Crc32Bzip2 => {
846
Calculator:: calculate( CRC32_BZIP2 .init, buf, & CRC32_BZIP2 ) ^ CRC32_BZIP2 .xorout
847
}
848
CrcAlgorithm:: Crc32CdRomEdc => {
849
Calculator:: calculate( CRC32_CD_ROM_EDC .init, buf, & CRC32_CD_ROM_EDC )
850
^ CRC32_CD_ROM_EDC .xorout
851
}
852
CrcAlgorithm:: Crc32Cksum => {
853
Calculator:: calculate( CRC32_CKSUM .init, buf, & CRC32_CKSUM ) ^ CRC32_CKSUM .xorout
854
}
855
CrcAlgorithm:: Crc32Custom => {
856
panic! ( " Custom CRC-32 requires parameters via CrcParams::new()" )
857
}
858
CrcAlgorithm:: Crc32Iscsi => {
859
crc32_iscsi_calculator ( CRC32_ISCSI .init, buf, & CRC32_ISCSI ) ^ CRC32_ISCSI .xorout
860
}
861
CrcAlgorithm:: Crc32IsoHdlc => {
862
crc32_iso_hdlc_calculator ( CRC32_ISO_HDLC .init, buf, & CRC32_ISO_HDLC )
863
^ CRC32_ISO_HDLC .xorout
864
}
865
CrcAlgorithm:: Crc32Jamcrc => {
866
Calculator:: calculate( CRC32_JAMCRC .init, buf, & CRC32_JAMCRC ) ^ CRC32_JAMCRC .xorout
867
}
868
CrcAlgorithm:: Crc32Mef => {
869
Calculator:: calculate( CRC32_MEF .init, buf, & CRC32_MEF ) ^ CRC32_MEF .xorout
870
}
871
CrcAlgorithm:: Crc32Mpeg2 => {
872
Calculator:: calculate( CRC32_MPEG_2 .init, buf, & CRC32_MPEG_2 ) ^ CRC32_MPEG_2 .xorout
873
}
874
CrcAlgorithm:: Crc32Xfer => {
875
Calculator:: calculate( CRC32_XFER .init, buf, & CRC32_XFER ) ^ CRC32_XFER .xorout
876
}
877
CrcAlgorithm:: CrcCustom => {
878
panic! ( " Custom CRC requires parameters via CrcParams::new()" )
879
}
880
CrcAlgorithm:: Crc64Custom => {
881
panic! ( " Custom CRC-64 requires parameters via CrcParams::new()" )
882
}
883
CrcAlgorithm:: Crc64Ecma182 => {
884
Calculator:: calculate( CRC64_ECMA_182 .init, buf, & CRC64_ECMA_182 ) ^ CRC64_ECMA_182 .xorout
885
}
886
CrcAlgorithm:: Crc64GoIso => {
887
Calculator:: calculate( CRC64_GO_ISO .init, buf, & CRC64_GO_ISO ) ^ CRC64_GO_ISO .xorout
888
}
889
CrcAlgorithm:: Crc64Ms => {
890
Calculator:: calculate( CRC64_MS .init, buf, & CRC64_MS ) ^ CRC64_MS .xorout
891
}
892
CrcAlgorithm:: Crc64Nvme => {
893
Calculator:: calculate( CRC64_NVME .init, buf, & CRC64_NVME ) ^ CRC64_NVME .xorout
894
}
895
CrcAlgorithm:: Crc64Redis => {
896
Calculator:: calculate( CRC64_REDIS .init, buf, & CRC64_REDIS ) ^ CRC64_REDIS .xorout
897
}
898
CrcAlgorithm:: Crc64We => {
899
Calculator:: calculate( CRC64_WE .init, buf, & CRC64_WE ) ^ CRC64_WE .xorout
900
}
901
CrcAlgorithm:: Crc64Xz => {
902
Calculator:: calculate( CRC64_XZ .init, buf, & CRC64_XZ ) ^ CRC64_XZ .xorout
903
}
904
}
905
}
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
pub fn checksum_with_params ( params : CrcParams, buf : & [u8 ]) -> u64 {
930
let calculator = Calculator:: calculate as CalculatorFn;
931
932
calculator ( params.init_algorithm, buf, & params) ^ params.xorout
933
}
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
# [ cfg ( feature = " std" ) ]
958
# [ inline ( always ) ]
959
pub fn checksum_file (
960
algorithm : CrcAlgorithm,
961
path : & str ,
962
chunk_size : Option< usize > ,
963
) -> Result< u64 , std:: io:: Error> {
964
checksum_file_with_digest ( Digest:: new( algorithm) , path, chunk_size)
965
}
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# [ cfg ( feature = " std" ) ]
1001
pub fn checksum_file_with_params (
1002
params : CrcParams,
1003
path : & str ,
1004
chunk_size : Option< usize > ,
1005
) -> Result< u64 , std:: io:: Error> {
1006
checksum_file_with_digest ( Digest:: new_with_params( params) , path, chunk_size)
1007
}
1008
1009
1010
1011
1012
1013
1014
# [ cfg ( feature = " std" ) ]
1015
fn checksum_file_with_digest (
1016
mut digest : Digest,
1017
path : & str ,
1018
chunk_size : Option< usize > ,
1019
) -> Result< u64 , std:: io:: Error> {
1020
let mut file = File:: open( path) ? ;
1021
1022
1023
1024
1025
1026
1027
let chunk_size = chunk_size.unwrap_or ( 524288 ) ;
1028
1029
let mut buf = vec! [ 0 ; chunk_size] ;
1030
1031
while let Ok ( n) = file.read ( & mut buf) {
1032
if n = = 0 {
1033
break ;
1034
}
1035
digest.update ( & buf[ .. n] ) ;
1036
}
1037
1038
Ok ( digest.finalize ( ) )
1039
}
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
# [ inline ( always ) ]
1054
pub fn checksum_combine (
1055
algorithm : CrcAlgorithm,
1056
checksum1 : u64 ,
1057
checksum2 : u64 ,
1058
checksum2_len : u64 ,
1059
) -> u64 {
1060
let params = get_calculator_params ( algorithm) .1 ;
1061
1062
combine:: checksums( checksum1, checksum2, checksum2_len, & params)
1063
}
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
pub fn checksum_combine_with_params (
1090
params : CrcParams,
1091
checksum1 : u64 ,
1092
checksum2 : u64 ,
1093
checksum2_len : u64 ,
1094
) -> u64 {
1095
combine:: checksums( checksum1, checksum2, checksum2_len, & params)
1096
}
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
# [ cfg ( all (
1128
feature = " alloc" ,
1129
any ( target_arch = " aarch64" , target_arch = " x86" , target_arch = " x86_64" )
1130
) ) ]
1131
pub fn get_calculator_target ( _algorithm : CrcAlgorithm) -> String {
1132
let arch_ops = get_arch_ops ( ) ;
1133
arch_ops.get_target_string ( )
1134
}
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
# [ inline ( always ) ]
1152
pub fn crc32_iscsi ( data : & [u8 ]) -> u32 {
1153
crc32_iscsi_calculator ( CRC32_ISCSI .init, data, & CRC32_ISCSI ) as u32 ^ CRC32_ISCSI .xorout as u32
1154
}
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
# [ inline ( always ) ]
1172
pub fn crc32_iso_hdlc ( data : & [u8 ]) -> u32 {
1173
crc32_iso_hdlc_calculator ( CRC32_ISO_HDLC .init, data, & CRC32_ISO_HDLC ) as u32
1174
^ CRC32_ISO_HDLC .xorout as u32
1175
}
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
# [ inline ( always ) ]
1192
pub fn crc64_nvme ( data : & [u8 ]) -> u64 {
1193
Calculator:: calculate( CRC64_NVME .init, data, & CRC64_NVME ) ^ CRC64_NVME .xorout
1194
}
1195
1196
1197
# [ cfg ( all (
1198
feature = " alloc" ,
1199
not ( any ( target_arch = " aarch64" , target_arch = " x86" , target_arch = " x86_64" ) )
1200
) ) ]
1201
pub fn get_calculator_target ( _algorithm : CrcAlgorithm) -> String {
1202
extern crate alloc;
1203
use alloc:: string:: ToString;
1204
" software-fallback-tables" .to_string ( )
1205
}
1206
1207
1208
# [ inline ( always ) ]
1209
# [ allow ( deprecated ) ]
1210
fn get_calculator_params ( algorithm : CrcAlgorithm) -> ( CalculatorFn, CrcParams) {
1211
match algorithm {
1212
CrcAlgorithm:: Crc16Arc => ( Calculator:: calculate as CalculatorFn, CRC16_ARC ) ,
1213
CrcAlgorithm:: Crc16Cdma2000 => ( Calculator:: calculate as CalculatorFn, CRC16_CDMA2000 ) ,
1214
CrcAlgorithm:: Crc16Cms => ( Calculator:: calculate as CalculatorFn, CRC16_CMS ) ,
1215
CrcAlgorithm:: Crc16Dds110 => ( Calculator:: calculate as CalculatorFn, CRC16_DDS_110 ) ,
1216
CrcAlgorithm:: Crc16DectR => ( Calculator:: calculate as CalculatorFn, CRC16_DECT_R ) ,
1217
CrcAlgorithm:: Crc16DectX => ( Calculator:: calculate as CalculatorFn, CRC16_DECT_X ) ,
1218
CrcAlgorithm:: Crc16Dnp => ( Calculator:: calculate as CalculatorFn, CRC16_DNP ) ,
1219
CrcAlgorithm:: Crc16En13757 => ( Calculator:: calculate as CalculatorFn, CRC16_EN_13757 ) ,
1220
CrcAlgorithm:: Crc16Genibus => ( Calculator:: calculate as CalculatorFn, CRC16_GENIBUS ) ,
1221
CrcAlgorithm:: Crc16Gsm => ( Calculator:: calculate as CalculatorFn, CRC16_GSM ) ,
1222
CrcAlgorithm:: Crc16Ibm3740 => ( Calculator:: calculate as CalculatorFn, CRC16_IBM_3740 ) ,
1223
CrcAlgorithm:: Crc16IbmSdlc => ( Calculator:: calculate as CalculatorFn, CRC16_IBM_SDLC ) ,
1224
CrcAlgorithm:: Crc16IsoIec144433A => (
1225
Calculator:: calculate as CalculatorFn,
1226
CRC16_ISO_IEC_14443_3_A ,
1227
) ,
1228
CrcAlgorithm:: Crc16Kermit => ( Calculator:: calculate as CalculatorFn, CRC16_KERMIT ) ,
1229
CrcAlgorithm:: Crc16Lj1200 => ( Calculator:: calculate as CalculatorFn, CRC16_LJ1200 ) ,
1230
CrcAlgorithm:: Crc16M17 => ( Calculator:: calculate as CalculatorFn, CRC16_M17 ) ,
1231
CrcAlgorithm:: Crc16MaximDow => ( Calculator:: calculate as CalculatorFn, CRC16_MAXIM_DOW ) ,
1232
CrcAlgorithm:: Crc16Mcrf4xx => ( Calculator:: calculate as CalculatorFn, CRC16_MCRF4XX ) ,
1233
CrcAlgorithm:: Crc16Modbus => ( Calculator:: calculate as CalculatorFn, CRC16_MODBUS ) ,
1234
CrcAlgorithm:: Crc16Nrsc5 => ( Calculator:: calculate as CalculatorFn, CRC16_NRSC_5 ) ,
1235
CrcAlgorithm:: Crc16OpensafetyA => {
1236
( Calculator:: calculate as CalculatorFn, CRC16_OPENSAFETY_A )
1237
}
1238
CrcAlgorithm:: Crc16OpensafetyB => {
1239
( Calculator:: calculate as CalculatorFn, CRC16_OPENSAFETY_B )
1240
}
1241
CrcAlgorithm:: Crc16Profibus => ( Calculator:: calculate as CalculatorFn, CRC16_PROFIBUS ) ,
1242
CrcAlgorithm:: Crc16Riello => ( Calculator:: calculate as CalculatorFn, CRC16_RIELLO ) ,
1243
CrcAlgorithm:: Crc16SpiFujitsu => ( Calculator:: calculate as CalculatorFn, CRC16_SPI_FUJITSU ) ,
1244
CrcAlgorithm:: Crc16T10Dif => ( Calculator:: calculate as CalculatorFn, CRC16_T10_DIF ) ,
1245
CrcAlgorithm:: Crc16Teledisk => ( Calculator:: calculate as CalculatorFn, CRC16_TELEDISK ) ,
1246
CrcAlgorithm:: Crc16Tms37157 => ( Calculator:: calculate as CalculatorFn, CRC16_TMS37157 ) ,
1247
CrcAlgorithm:: Crc16Umts => ( Calculator:: calculate as CalculatorFn, CRC16_UMTS ) ,
1248
CrcAlgorithm:: Crc16Usb => ( Calculator:: calculate as CalculatorFn, CRC16_USB ) ,
1249
CrcAlgorithm:: Crc16Xmodem => ( Calculator:: calculate as CalculatorFn, CRC16_XMODEM ) ,
1250
CrcAlgorithm:: Crc32Aixm => ( Calculator:: calculate as CalculatorFn, CRC32_AIXM ) ,
1251
CrcAlgorithm:: Crc32Autosar => ( Calculator:: calculate as CalculatorFn, CRC32_AUTOSAR ) ,
1252
CrcAlgorithm:: Crc32Base91D => ( Calculator:: calculate as CalculatorFn, CRC32_BASE91_D ) ,
1253
CrcAlgorithm:: Crc32Bzip2 => ( Calculator:: calculate as CalculatorFn, CRC32_BZIP2 ) ,
1254
CrcAlgorithm:: Crc32CdRomEdc => ( Calculator:: calculate as CalculatorFn, CRC32_CD_ROM_EDC ) ,
1255
CrcAlgorithm:: Crc32Cksum => ( Calculator:: calculate as CalculatorFn, CRC32_CKSUM ) ,
1256
CrcAlgorithm:: Crc32Custom => {
1257
panic! ( " Custom CRC-32 requires parameters via CrcParams::new()" )
1258
}
1259
CrcAlgorithm:: Crc32Iscsi => ( crc32_iscsi_calculator as CalculatorFn, CRC32_ISCSI ) ,
1260
CrcAlgorithm:: Crc32IsoHdlc => ( crc32_iso_hdlc_calculator as CalculatorFn, CRC32_ISO_HDLC ) ,
1261
CrcAlgorithm:: Crc32Jamcrc => ( Calculator:: calculate as CalculatorFn, CRC32_JAMCRC ) ,
1262
CrcAlgorithm:: Crc32Mef => ( Calculator:: calculate as CalculatorFn, CRC32_MEF ) ,
1263
CrcAlgorithm:: Crc32Mpeg2 => ( Calculator:: calculate as CalculatorFn, CRC32_MPEG_2 ) ,
1264
CrcAlgorithm:: Crc32Xfer => ( Calculator:: calculate as CalculatorFn, CRC32_XFER ) ,
1265
CrcAlgorithm:: CrcCustom => {
1266
panic! ( " Custom CRC requires parameters via CrcParams::new()" )
1267
}
1268
CrcAlgorithm:: Crc64Custom => {
1269
panic! ( " Custom CRC-64 requires parameters via CrcParams::new()" )
1270
}
1271
CrcAlgorithm:: Crc64Ecma182 => ( Calculator:: calculate as CalculatorFn, CRC64_ECMA_182 ) ,
1272
CrcAlgorithm:: Crc64GoIso => ( Calculator:: calculate as CalculatorFn, CRC64_GO_ISO ) ,
1273
CrcAlgorithm:: Crc64Ms => ( Calculator:: calculate as CalculatorFn, CRC64_MS ) ,
1274
CrcAlgorithm:: Crc64Nvme => ( Calculator:: calculate as CalculatorFn, CRC64_NVME ) ,
1275
CrcAlgorithm:: Crc64Redis => ( Calculator:: calculate as CalculatorFn, CRC64_REDIS ) ,
1276
CrcAlgorithm:: Crc64We => ( Calculator:: calculate as CalculatorFn, CRC64_WE ) ,
1277
CrcAlgorithm:: Crc64Xz => ( Calculator:: calculate as CalculatorFn, CRC64_XZ ) ,
1278
}
1279
}
1280
1281
1282
1283
1284
1285
1286
# [ inline ( always ) ]
1287
fn crc32_iscsi_calculator ( state : u64 , data : & [u8 ], _params : & CrcParams) -> u64 {
1288
# [ cfg ( all ( target_arch = " aarch64" , feature = " std" ) ) ]
1289
{
1290
use crate :: feature_detection:: PerformanceTier;
1291
1292
let arch_ops = get_arch_ops ( ) ;
1293
match arch_ops.get_tier ( ) {
1294
PerformanceTier:: AArch64AesSha3 | PerformanceTier:: AArch64Aes => {
1295
return fusion:: crc32_iscsi( state as u32 , data) as u64 ;
1296
}
1297
_ => { }
1298
}
1299
}
1300
1301
# [ cfg ( all ( any ( target_arch = " x86_64" , target_arch = " x86" ) , feature = " std" ) ) ]
1302
{
1303
use crate :: feature_detection:: PerformanceTier;
1304
1305
let arch_ops = get_arch_ops ( ) ;
1306
match arch_ops.get_tier ( ) {
1307
PerformanceTier:: X86_64Avx512Vpclmulqdq
1308
| PerformanceTier:: X86_64Avx512Pclmulqdq
1309
| PerformanceTier:: X86_64SsePclmulqdq
1310
| PerformanceTier:: X86SsePclmulqdq => {
1311
1312
if is_x86_feature_detected! ( " sse4.2" ) {
1313
return fusion:: crc32_iscsi( state as u32 , data) as u64 ;
1314
}
1315
}
1316
_ => { }
1317
}
1318
}
1319
1320
Calculator:: calculate( state, data, _params)
1321
}
1322
1323
1324
1325
1326
1327
1328
1329
# [ inline ( always ) ]
1330
fn crc32_iso_hdlc_calculator ( state : u64 , data : & [u8 ], _params : & CrcParams) -> u64 {
1331
# [ cfg ( all ( target_arch = " aarch64" , feature = " std" ) ) ]
1332
{
1333
use crate :: feature_detection:: { get_arch_ops, PerformanceTier} ;
1334
let arch_ops = get_arch_ops ( ) ;
1335
1336
match arch_ops.get_tier ( ) {
1337
PerformanceTier:: AArch64AesSha3 | PerformanceTier:: AArch64Aes => {
1338
return fusion:: crc32_iso_hdlc( state as u32 , data) as u64 ;
1339
}
1340
_ => { }
1341
}
1342
}
1343
1344
Calculator:: calculate( state, data, _params)
1345
}
1346
1347
# [ cfg ( test ) ]
1348
mod lib {
1349
#! [ allow ( unused ) ]
1350
1351
use super :: * ;
1352
use crate :: test:: consts:: { TEST_ALL_CONFIGS , TEST_CHECK_STRING } ;
1353
use crate :: test:: enums:: AnyCrcTestConfig;
1354
use cbindgen:: Language:: C;
1355
use cbindgen:: Style:: Both;
1356
use rand:: { rng, Rng} ;
1357
use std:: fs:: { read, write} ;
1358
1359
# [ test ]
1360
fn test_checksum_check ( ) {
1361
for config in TEST_ALL_CONFIGS {
1362
assert_eq! (
1363
checksum ( config.get_algorithm ( ) , TEST_CHECK_STRING ) ,
1364
config.get_check ( )
1365
) ;
1366
}
1367
}
1368
1369
# [ test ]
1370
fn test_checksum_reference ( ) {
1371
for config in TEST_ALL_CONFIGS {
1372
assert_eq! (
1373
checksum ( config.get_algorithm ( ) , TEST_CHECK_STRING ) ,
1374
config.checksum_with_reference ( TEST_CHECK_STRING )
1375
) ;
1376
}
1377
}
1378
1379
# [ test ]
1380
fn test_checksum_with_custom_params ( ) {
1381
crate :: cache:: clear_cache( ) ;
1382
1383
1384
assert_eq! (
1385
checksum_with_params ( get_custom_crc32_reflected ( ) , TEST_CHECK_STRING ) ,
1386
CRC32_ISCSI .check,
1387
) ;
1388
1389
1390
assert_eq! (
1391
checksum_with_params ( get_custom_crc32_forward ( ) , TEST_CHECK_STRING ) ,
1392
CRC32_BZIP2 .check,
1393
) ;
1394
1395
1396
assert_eq! (
1397
checksum_with_params ( get_custom_crc64_reflected ( ) , TEST_CHECK_STRING ) ,
1398
CRC64_NVME .check,
1399
) ;
1400
1401
1402
assert_eq! (
1403
checksum_with_params ( get_custom_crc64_forward ( ) , TEST_CHECK_STRING ) ,
1404
CRC64_ECMA_182 .check,
1405
) ;
1406
}
1407
1408
# [ test ]
1409
fn test_get_custom_params ( ) {
1410
crate :: cache:: clear_cache( ) ;
1411
1412
assert_eq! (
1413
checksum_with_params ( get_custom_crc32_reflected ( ) , TEST_CHECK_STRING ) ,
1414
CRC32_ISCSI .check,
1415
) ;
1416
1417
assert_eq! (
1418
checksum_with_params ( get_custom_crc32_forward ( ) , TEST_CHECK_STRING ) ,
1419
CRC32_BZIP2 .check,
1420
) ;
1421
1422
assert_eq! (
1423
checksum_with_params ( get_custom_crc64_reflected ( ) , TEST_CHECK_STRING ) ,
1424
CRC64_NVME .check,
1425
) ;
1426
1427
assert_eq! (
1428
checksum_with_params ( get_custom_crc64_forward ( ) , TEST_CHECK_STRING ) ,
1429
CRC64_ECMA_182 .check,
1430
) ;
1431
}
1432
1433
# [ test ]
1434
fn test_get_calculator_target_format ( ) {
1435
let target = get_calculator_target ( CrcAlgorithm:: Crc32IsoHdlc) ;
1436
1437
1438
assert! ( ! target.is_empty ( ) ) ;
1439
1440
1441
let valid_prefixes = [ " aarch64-" , " x86_64-" , " x86-" , " software-" ] ;
1442
assert! (
1443
valid_prefixes
1444
.iter ( )
1445
.any ( | prefix | target.starts_with ( prefix) ) ,
1446
" Target '{}' should start with a valid architecture prefix" ,
1447
target
1448
) ;
1449
1450
1451
let parts: Vec< & str > = target.split ( ' -' ) .collect ( ) ;
1452
assert! (
1453
parts.len ( ) > = 3 ,
1454
" Target '{}' should have at least 3 parts: architecture-family-features" ,
1455
target
1456
) ;
1457
}
1458
1459
# [ test ]
1460
fn test_get_calculator_target_consistency ( ) {
1461
1462
let target1 = get_calculator_target ( CrcAlgorithm:: Crc32IsoHdlc) ;
1463
let target2 = get_calculator_target ( CrcAlgorithm:: Crc32Iscsi) ;
1464
let target3 = get_calculator_target ( CrcAlgorithm:: Crc64Nvme) ;
1465
1466
assert_eq! (
1467
target1, target2,
1468
" Target should be consistent across different CRC-32 algorithms"
1469
) ;
1470
assert_eq! (
1471
target1, target3,
1472
" Target should be consistent across CRC-32 and CRC-64 algorithms"
1473
) ;
1474
}
1475
1476
# [ test ]
1477
fn test_get_calculator_target_uses_cached_detection ( ) {
1478
1479
1480
1481
1482
let target1 = get_calculator_target ( CrcAlgorithm:: Crc32IsoHdlc) ;
1483
let target2 = get_calculator_target ( CrcAlgorithm:: Crc32IsoHdlc) ;
1484
1485
assert_eq! (
1486
target1, target2,
1487
" Cached detection should return identical results"
1488
) ;
1489
}
1490
1491
# [ test ]
1492
fn test_digest_updates_check ( ) {
1493
for config in TEST_ALL_CONFIGS {
1494
check_digest ( Digest:: new( config.get_algorithm ( ) ) , config.get_check ( ) ) ;
1495
}
1496
}
1497
1498
# [ test ]
1499
fn test_digest_updates_check_with_custom_params ( ) {
1500
crate :: cache:: clear_cache( ) ;
1501
1502
1503
check_digest (
1504
Digest:: new_with_params( get_custom_crc32_reflected ( ) ) ,
1505
CRC32_ISCSI .check,
1506
) ;
1507
1508
1509
check_digest (
1510
Digest:: new_with_params( get_custom_crc32_forward ( ) ) ,
1511
CRC32_BZIP2 .check,
1512
) ;
1513
1514
1515
check_digest (
1516
Digest:: new_with_params( get_custom_crc64_reflected ( ) ) ,
1517
CRC64_NVME .check,
1518
) ;
1519
1520
1521
check_digest (
1522
Digest:: new_with_params( get_custom_crc64_forward ( ) ) ,
1523
CRC64_ECMA_182 .check,
1524
) ;
1525
}
1526
1527
fn check_digest ( mut digest : Digest, check : u64 ) {
1528
digest.update ( b " 123" ) ;
1529
digest.update ( b " 456" ) ;
1530
digest.update ( b " 789" ) ;
1531
assert_eq! ( digest.finalize ( ) , check, ) ;
1532
}
1533
1534
# [ test ]
1535
fn test_1024_length ( ) {
1536
for config in TEST_ALL_CONFIGS {
1537
test_length ( 1024 , config) ;
1538
}
1539
}
1540
1541
1542
1543
# [ test ]
1544
# [ cfg_attr ( miri, ignore ) ]
1545
fn test_small_all_lengths ( ) {
1546
for config in TEST_ALL_CONFIGS {
1547
1548
for len in 1 .. = 255 {
1549
test_length ( len, config) ;
1550
}
1551
}
1552
}
1553
1554
1555
1556
# [ test ]
1557
# [ cfg_attr ( miri, ignore ) ]
1558
fn test_medium_lengths ( ) {
1559
for config in TEST_ALL_CONFIGS {
1560
1561
for len in 256 .. = 1024 {
1562
test_length ( len, config) ;
1563
}
1564
}
1565
}
1566
1567
1568
1569
# [ test ]
1570
# [ cfg_attr ( miri, ignore ) ]
1571
fn test_large_lengths ( ) {
1572
for config in TEST_ALL_CONFIGS {
1573
1574
for len in 1048575 .. 1048577 {
1575
test_length ( len, config) ;
1576
}
1577
}
1578
}
1579
1580
fn test_length ( length : usize , config : & AnyCrcTestConfig) {
1581
let mut data = vec! [ 0 u8 ; length] ;
1582
rng ( ) .fill ( & mut data[ .. ] ) ;
1583
1584
1585
let expected = config.checksum_with_reference ( & data) ;
1586
1587
let result = checksum ( config.get_algorithm ( ) , & data) ;
1588
1589
assert_eq! (
1590
result,
1591
expected,
1592
" Failed for algorithm: {:?}, length: {}, expected: {:#x}, got: {:#x}" ,
1593
config.get_algorithm ( ) ,
1594
length,
1595
expected,
1596
result
1597
) ;
1598
}
1599
1600
# [ test ]
1601
fn test_combine ( ) {
1602
for config in TEST_ALL_CONFIGS {
1603
let algorithm = config.get_algorithm ( ) ;
1604
let check = config.get_check ( ) ;
1605
1606
1607
let checksum1 = checksum ( algorithm, " 1234" .as_ref ( ) ) ;
1608
let checksum2 = checksum ( algorithm, " 56789" .as_ref ( ) ) ;
1609
1610
1611
assert_eq! ( checksum_combine ( algorithm, checksum1, checksum2, 5 ) , check) ;
1612
1613
1614
let mut digest1 = Digest:: new( algorithm) ;
1615
digest1.update ( " 1234" .as_ref ( ) ) ;
1616
1617
let mut digest2 = Digest:: new( algorithm) ;
1618
digest2.update ( " 56789" .as_ref ( ) ) ;
1619
1620
digest1.combine ( & digest2) ;
1621
1622
assert_eq! ( digest1.finalize ( ) , check)
1623
}
1624
}
1625
1626
# [ test ]
1627
fn test_combine_with_custom_params ( ) {
1628
crate :: cache:: clear_cache( ) ;
1629
1630
1631
let crc32_params = get_custom_crc32_reflected ( ) ;
1632
let checksum1 = checksum_with_params ( crc32_params, " 1234" .as_ref ( ) ) ;
1633
let checksum2 = checksum_with_params ( crc32_params, " 56789" .as_ref ( ) ) ;
1634
assert_eq! (
1635
checksum_combine_with_params ( crc32_params, checksum1, checksum2, 5 ) ,
1636
CRC32_ISCSI .check,
1637
) ;
1638
1639
1640
let crc32_params = get_custom_crc32_forward ( ) ;
1641
let checksum1 = checksum_with_params ( crc32_params, " 1234" .as_ref ( ) ) ;
1642
let checksum2 = checksum_with_params ( crc32_params, " 56789" .as_ref ( ) ) ;
1643
assert_eq! (
1644
checksum_combine_with_params ( crc32_params, checksum1, checksum2, 5 ) ,
1645
CRC32_BZIP2 .check,
1646
) ;
1647
1648
1649
let crc64_params = get_custom_crc64_reflected ( ) ;
1650
let checksum1 = checksum_with_params ( crc64_params, " 1234" .as_ref ( ) ) ;
1651
let checksum2 = checksum_with_params ( crc64_params, " 56789" .as_ref ( ) ) ;
1652
assert_eq! (
1653
checksum_combine_with_params ( crc64_params, checksum1, checksum2, 5 ) ,
1654
CRC64_NVME .check,
1655
) ;
1656
1657
1658
let crc64_params = get_custom_crc64_forward ( ) ;
1659
let checksum1 = checksum_with_params ( crc64_params, " 1234" .as_ref ( ) ) ;
1660
let checksum2 = checksum_with_params ( crc64_params, " 56789" .as_ref ( ) ) ;
1661
assert_eq! (
1662
checksum_combine_with_params ( crc64_params, checksum1, checksum2, 5 ) ,
1663
CRC64_ECMA_182 .check,
1664
) ;
1665
}
1666
1667
1668
1669
# [ test ]
1670
# [ cfg_attr ( miri, ignore ) ]
1671
fn test_checksum_file ( ) {
1672
1673
let test_file_path = " test/test_crc32_hash_file.bin" ;
1674
let data = vec! [ 0 u8 ; 1024 * 1024 ] ;
1675
if let Err ( e) = write ( test_file_path, & data) {
1676
eprintln! ( " Skipping test due to write error: {}" , e) ;
1677
return ;
1678
}
1679
1680
for config in TEST_ALL_CONFIGS {
1681
let result = checksum_file ( config.get_algorithm ( ) , test_file_path, None ) .unwrap ( ) ;
1682
assert_eq! ( result, config.checksum_with_reference ( & data) ) ;
1683
}
1684
1685
std:: fs:: remove_file( test_file_path) .unwrap ( ) ;
1686
}
1687
1688
1689
1690
# [ test ]
1691
# [ cfg_attr ( miri, ignore ) ]
1692
fn test_checksum_file_with_custom_params ( ) {
1693
crate :: cache:: clear_cache( ) ;
1694
1695
1696
let test_file_path = " test/test_crc32_hash_file_custom.bin" ;
1697
let data = vec! [ 0 u8 ; 1024 * 1024 ] ;
1698
if let Err ( e) = write ( test_file_path, & data) {
1699
eprintln! ( " Skipping test due to write error: {}" , e) ;
1700
return ;
1701
}
1702
1703
1704
check_file (
1705
get_custom_crc32_reflected ( ) ,
1706
test_file_path,
1707
CRC32_ISCSI .check,
1708
) ;
1709
1710
1711
check_file (
1712
get_custom_crc32_forward ( ) ,
1713
test_file_path,
1714
CRC32_BZIP2 .check,
1715
) ;
1716
1717
1718
check_file (
1719
get_custom_crc64_reflected ( ) ,
1720
test_file_path,
1721
CRC64_NVME .check,
1722
) ;
1723
1724
1725
check_file (
1726
get_custom_crc64_forward ( ) ,
1727
test_file_path,
1728
CRC64_ECMA_182 .check,
1729
) ;
1730
1731
std:: fs:: remove_file( test_file_path) .unwrap ( ) ;
1732
}
1733
1734
fn check_file ( params : CrcParams, file_path : & str , check : u64 ) {
1735
let result = checksum_file_with_params ( params, file_path, None ) .unwrap ( ) ;
1736
assert_eq! ( result, check) ;
1737
}
1738
1739
1740
1741
# [ test ]
1742
# [ cfg_attr ( miri, ignore ) ]
1743
fn test_writer ( ) {
1744
1745
let test_file_path = " test/test_crc32_writer_file.bin" ;
1746
let data = vec! [ 0 u8 ; 1024 * 1024 ] ;
1747
if let Err ( e) = std:: fs:: write( test_file_path, & data) {
1748
eprintln! ( " Skipping test due to write error: {}" , e) ;
1749
return ;
1750
}
1751
1752
for config in TEST_ALL_CONFIGS {
1753
let mut digest = Digest:: new( config.get_algorithm ( ) ) ;
1754
let mut file = File:: open( test_file_path) .unwrap ( ) ;
1755
std:: io:: copy( & mut file, & mut digest) .unwrap ( ) ;
1756
assert_eq! ( digest.finalize ( ) , config.checksum_with_reference ( & data) ) ;
1757
}
1758
1759
std:: fs:: remove_file( test_file_path) .unwrap ( ) ;
1760
}
1761
# [ test ]
1762
fn test_digest_reset ( ) {
1763
for config in TEST_ALL_CONFIGS {
1764
let mut digest = Digest:: new( config.get_algorithm ( ) ) ;
1765
digest.update ( b " 42" ) ;
1766
digest.reset ( ) ;
1767
digest.update ( TEST_CHECK_STRING ) ;
1768
assert_eq! ( digest.finalize ( ) , config.get_check ( ) ) ;
1769
}
1770
}
1771
1772
# [ test ]
1773
fn test_digest_finalize_reset ( ) {
1774
for config in TEST_ALL_CONFIGS {
1775
let check = config.get_check ( ) ;
1776
1777
let mut digest = Digest:: new( config.get_algorithm ( ) ) ;
1778
digest.update ( TEST_CHECK_STRING ) ;
1779
assert_eq! ( digest.finalize_reset ( ) , check) ;
1780
1781
digest.update ( TEST_CHECK_STRING ) ;
1782
assert_eq! ( digest.finalize ( ) , check) ;
1783
}
1784
}
1785
1786
# [ test ]
1787
fn test_digest_finalize_into ( ) {
1788
for config in TEST_ALL_CONFIGS {
1789
let mut digest = Digest:: new( config.get_algorithm ( ) ) ;
1790
digest.update ( TEST_CHECK_STRING ) ;
1791
1792
match digest.params.width {
1793
16 => {
1794
let mut output = [ 0 u8 ; 2 ] ;
1795
digest.finalize_into ( & mut output) .unwrap ( ) ;
1796
let result = u16 :: from_be_bytes( output) as u64 ;
1797
assert_eq! ( result, config.get_check ( ) ) ;
1798
}
1799
32 => {
1800
let mut output = [ 0 u8 ; 4 ] ;
1801
digest.finalize_into ( & mut output) .unwrap ( ) ;
1802
let result = u32 :: from_be_bytes( output) as u64 ;
1803
assert_eq! ( result, config.get_check ( ) ) ;
1804
}
1805
64 => {
1806
let mut output = [ 0 u8 ; 8 ] ;
1807
digest.finalize_into ( & mut output) .unwrap ( ) ;
1808
let result = u64 :: from_be_bytes( output) ;
1809
assert_eq! ( result, config.get_check ( ) ) ;
1810
}
1811
_ => panic! ( " Unsupported CRC width" ) ,
1812
}
1813
}
1814
}
1815
1816
# [ test ]
1817
fn test_digest_finalize_into_reset ( ) {
1818
for config in TEST_ALL_CONFIGS {
1819
let mut digest = Digest:: new( config.get_algorithm ( ) ) ;
1820
digest.update ( TEST_CHECK_STRING ) ;
1821
1822
let mut output: Vec< u8 > = match digest.params.width {
1823
16 => vec! [ 0 u8 ; 2 ] ,
1824
32 => vec! [ 0 u8 ; 4 ] ,
1825
64 => vec! [ 0 u8 ; 8 ] ,
1826
_ => panic! ( " Unsupported CRC width" ) ,
1827
} ;
1828
1829
digest.finalize_into_reset ( & mut output) .unwrap ( ) ;
1830
let result = match output.len ( ) {
1831
2 => u16 :: from_be_bytes( output.try_into ( ) .unwrap ( ) ) as u64 ,
1832
4 => u32 :: from_be_bytes( output.try_into ( ) .unwrap ( ) ) as u64 ,
1833
8 => u64 :: from_be_bytes( output.try_into ( ) .unwrap ( ) ) ,
1834
_ => panic! ( " Unsupported CRC width" ) ,
1835
} ;
1836
assert_eq! ( result, config.get_check ( ) ) ;
1837
1838
digest.update ( TEST_CHECK_STRING ) ;
1839
assert_eq! ( digest.finalize ( ) , config.get_check ( ) ) ;
1840
}
1841
}
1842
1843
1844
# [ test ]
1845
# [ cfg_attr ( miri, ignore ) ]
1846
fn test_ffi_header ( ) -> Result< ( ) , String> {
1847
# [ cfg ( target_os = " windows" ) ]
1848
{
1849
1850
eprintln! ( " Skipping test on Windows" ) ;
1851
1852
return Ok ( ( ) ) ;
1853
}
1854
1855
const HEADER : & str = " libcrc_fast.h" ;
1856
1857
let crate_dir = std:: env:: var( " CARGO_MANIFEST_DIR" ) .map_err ( | error | error.to_string ( ) ) ? ;
1858
1859
let mut expected = Vec :: new( ) ;
1860
cbindgen:: Builder:: new( )
1861
.with_crate ( crate_dir)
1862
.with_include_guard ( " CRC_FAST_H" )
1863
.with_header ( " /* crc_fast library C/C++ API - Copyright 2025 Don MacAskill */\n /* This header is auto-generated. Do not edit directly. */\n " )
1864
1865
.exclude_item ( " crc32_iscsi_impl" )
1866
.exclude_item ( " crc32_iso_hdlc_impl" )
1867
.exclude_item ( " get_iscsi_target" )
1868
.exclude_item ( " get_iso_hdlc_target" )
1869
.exclude_item ( " ISO_HDLC_TARGET" )
1870
.exclude_item ( " ISCSI_TARGET" )
1871
.exclude_item ( " CrcParams" )
1872
.rename_item ( " Digest" , " CrcFastDigest" )
1873
.with_style ( Both)
1874
1875
.with_language ( C)
1876
1877
.with_cpp_compat ( true )
1878
.generate ( )
1879
.map_err ( | error | error.to_string ( ) ) ?
1880
.write ( & mut expected) ;
1881
1882
1883
1884
let header_content = String :: from_utf8( expected) .map_err ( | error | error.to_string ( ) ) ? ;
1885
1886
1887
let regex = regex:: Regex:: new( r "\n{3,}" ) .map_err ( | error | error.to_string ( ) ) ? ;
1888
let cleaned_content = regex.replace_all ( & header_content, " \n \n " ) .to_string ( ) ;
1889
1890
1891
expected = cleaned_content.into_bytes ( ) ;
1892
1893
let actual = read ( HEADER ) .map_err ( | error | error.to_string ( ) ) ? ;
1894
1895
if expected ! = actual {
1896
write ( HEADER , expected) .map_err ( | error | error.to_string ( ) ) ? ;
1897
return Err ( format! (
1898
" {HEADER} is not up-to-date, commit the generated file and try again"
1899
) ) ;
1900
}
1901
1902
Ok ( ( ) )
1903
}
1904
1905
fn get_custom_crc32_reflected ( ) -> CrcParams {
1906
CrcParams:: new(
1907
" Custom CRC-32/ISCSI" ,
1908
32 ,
1909
CRC32_ISCSI .poly,
1910
CRC32_ISCSI .init,
1911
CRC32_ISCSI .refin,
1912
CRC32_ISCSI .xorout,
1913
CRC32_ISCSI .check,
1914
)
1915
}
1916
1917
fn get_custom_crc32_forward ( ) -> CrcParams {
1918
CrcParams:: new(
1919
" Custom CRC-32/BZIP2" ,
1920
32 ,
1921
CRC32_BZIP2 .poly,
1922
CRC32_BZIP2 .init,
1923
CRC32_BZIP2 .refin,
1924
CRC32_BZIP2 .xorout,
1925
CRC32_BZIP2 .check,
1926
)
1927
}
1928
1929
fn get_custom_crc64_reflected ( ) -> CrcParams {
1930
CrcParams:: new(
1931
" Custom CRC-64/NVME" ,
1932
64 ,
1933
CRC64_NVME .poly,
1934
CRC64_NVME .init,
1935
CRC64_NVME .refin,
1936
CRC64_NVME .xorout,
1937
CRC64_NVME .check,
1938
)
1939
}
1940
1941
fn get_custom_crc64_forward ( ) -> CrcParams {
1942
CrcParams:: new(
1943
" Custom CRC-64/ECMA-182" ,
1944
64 ,
1945
CRC64_ECMA_182 .poly,
1946
CRC64_ECMA_182 .init,
1947
CRC64_ECMA_182 .refin,
1948
CRC64_ECMA_182 .xorout,
1949
CRC64_ECMA_182 .check,
1950
)
1951
}
1952
1953
# [ test ]
1954
# [ allow ( clippy::needless_range_loop ) ]
1955
fn test_crc_keys_storage_fold_256 ( ) {
1956
let test_keys = [
1957
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 ,
1958
] ;
1959
let storage = CrcKeysStorage:: from_keys_fold_256( test_keys) ;
1960
1961
1962
for i in 0 .. 23 {
1963
assert_eq! ( storage.get_key ( i) , test_keys[ i] ) ;
1964
}
1965
1966
1967
assert_eq! ( storage.get_key ( 23 ) , 0 ) ;
1968
assert_eq! ( storage.get_key ( 24 ) , 0 ) ;
1969
assert_eq! ( storage.get_key ( 100 ) , 0 ) ;
1970
1971
1972
assert_eq! ( storage.key_count ( ) , 23 ) ;
1973
}
1974
1975
# [ test ]
1976
# [ allow ( clippy::needless_range_loop ) ]
1977
fn test_crc_keys_storage_future_test ( ) {
1978
let test_keys = [
1979
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 ,
1980
25 ,
1981
] ;
1982
let storage = CrcKeysStorage:: from_keys_fold_future_test( test_keys) ;
1983
1984
1985
for i in 0 .. 25 {
1986
assert_eq! ( storage.get_key ( i) , test_keys[ i] ) ;
1987
}
1988
1989
1990
assert_eq! ( storage.get_key ( 25 ) , 0 ) ;
1991
assert_eq! ( storage.get_key ( 26 ) , 0 ) ;
1992
assert_eq! ( storage.get_key ( 100 ) , 0 ) ;
1993
1994
1995
assert_eq! ( storage.key_count ( ) , 25 ) ;
1996
}
1997
1998
# [ test ]
1999
# [ allow ( clippy::needless_range_loop ) ]
2000
fn test_crc_params_safe_accessors ( ) {
2001
2002
let test_keys = [
2003
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 ,
2004
] ;
2005
let params = CrcParams {
2006
algorithm: CrcAlgorithm:: Crc32IsoHdlc,
2007
name: " test" ,
2008
width: 32 ,
2009
poly: 0x04C11DB7 ,
2010
init: 0xFFFFFFFF ,
2011
init_algorithm: 0xFFFFFFFF ,
2012
refin: true ,
2013
refout: true ,
2014
xorout: 0xFFFFFFFF ,
2015
check: 0xCBF43926 ,
2016
keys: CrcKeysStorage:: from_keys_fold_256( test_keys) ,
2017
} ;
2018
2019
2020
for i in 0 .. 23 {
2021
assert_eq! ( params.get_key ( i) , test_keys[ i] ) ;
2022
assert_eq! ( params.get_key_checked ( i) , Some ( test_keys[ i] ) ) ;
2023
}
2024
2025
2026
assert_eq! ( params.get_key ( 23 ) , 0 ) ;
2027
assert_eq! ( params.get_key ( 24 ) , 0 ) ;
2028
assert_eq! ( params.get_key ( 100 ) , 0 ) ;
2029
2030
assert_eq! ( params.get_key_checked ( 23 ) , None ) ;
2031
assert_eq! ( params.get_key_checked ( 24 ) , None ) ;
2032
assert_eq! ( params.get_key_checked ( 100 ) , None ) ;
2033
2034
2035
assert_eq! ( params.key_count ( ) , 23 ) ;
2036
}
2037
2038
# [ test ]
2039
fn test_crc_keys_storage_const_constructors ( ) {
2040
2041
const TEST_KEYS_23 : [ u64 ; 23 ] = [ 1 ; 23 ] ;
2042
const TEST_KEYS_25 : [ u64 ; 25 ] = [ 2 ; 25 ] ;
2043
2044
const STORAGE_256 : CrcKeysStorage = CrcKeysStorage:: from_keys_fold_256( TEST_KEYS_23 ) ;
2045
const STORAGE_FUTURE : CrcKeysStorage =
2046
CrcKeysStorage:: from_keys_fold_future_test( TEST_KEYS_25 ) ;
2047
2048
2049
assert_eq! ( STORAGE_256 .get_key ( 0 ) , 1 ) ;
2050
assert_eq! ( STORAGE_256 .key_count ( ) , 23 ) ;
2051
2052
assert_eq! ( STORAGE_FUTURE .get_key ( 0 ) , 2 ) ;
2053
assert_eq! ( STORAGE_FUTURE .key_count ( ) , 25 ) ;
2054
}
2055
2056
# [ test ]
2057
fn test_crc_keys_storage_bounds_safety ( ) {
2058
let storage_256 = CrcKeysStorage:: from_keys_fold_256( [ 42 ; 23 ] ) ;
2059
let storage_future = CrcKeysStorage:: from_keys_fold_future_test( [ 84 ; 25 ] ) ;
2060
2061
2062
assert_eq! ( storage_256.get_key ( 22 ) , 42 ) ;
2063
assert_eq! ( storage_256.get_key ( 23 ) , 0 ) ;
2064
2065
assert_eq! ( storage_future.get_key ( 24 ) , 84 ) ;
2066
assert_eq! ( storage_future.get_key ( 25 ) , 0 ) ;
2067
2068
2069
assert_eq! ( storage_256.get_key ( usize :: MAX ) , 0 ) ;
2070
assert_eq! ( storage_future.get_key ( usize :: MAX ) , 0 ) ;
2071
}
2072
}