2cd40ea1 Andy McCall 1 month ago ↶
1
2
3
4
5
6
7
# [ cfg ( all ( target_arch = " aarch64" , feature = " std" ) ) ]
8
use std:: arch:: is_aarch64_feature_detected;
9
10
use crate :: CrcParams;
11
12
# [ cfg ( target_arch = " aarch64" ) ]
13
use crate :: arch:: aarch64:: aes:: Aarch64AesOps;
14
15
# [ cfg ( target_arch = " aarch64" ) ]
16
use crate :: arch:: aarch64:: aes_sha3:: Aarch64AesSha3Ops;
17
18
# [ cfg ( any ( target_arch = " x86" , target_arch = " x86_64" , target_arch = " aarch64" ) ) ]
19
use crate : : {
20
algorithm,
21
structs:: { Width16, Width32, Width64} ,
22
} ;
23
24
pub mod aarch64 ;
25
pub mod software ;
26
pub mod x86 ;
27
pub mod x86_64 ;
28
29
30
31
32
33
# [ inline ( always ) ]
34
# [ cfg ( target_arch = " aarch64" ) ]
35
pub ( crate ) unsafe fn update ( state : u64 , bytes : & [u8 ], params : & CrcParams) -> u64 {
36
use crate :: feature_detection:: { get_arch_ops, ArchOpsInstance} ;
37
38
match get_arch_ops ( ) {
39
ArchOpsInstance:: Aarch64AesSha3( ops) => update_aarch64_aes_sha3 ( state, bytes, params, * ops) ,
40
ArchOpsInstance:: Aarch64Aes( ops) => update_aarch64_aes ( state, bytes, params, * ops) ,
41
ArchOpsInstance:: SoftwareFallback => {
42
# [ cfg ( feature = " std" ) ]
43
let has_features =
44
is_aarch64_feature_detected! ( " aes" ) & & is_aarch64_feature_detected! ( " neon" ) ;
45
# [ cfg ( not ( feature = " std" ) ) ]
46
let has_features = cfg! ( target_feature = " aes" ) & & cfg! ( target_feature = " neon" ) ;
47
48
if ! has_features {
49
# [ cfg ( any ( not ( target_feature = " aes" ) , not ( target_feature = " neon" ) ) ) ]
50
{
51
52
return crate :: arch:: software:: update( state, bytes, params) ;
53
}
54
}
55
56
57
panic! ( " aarch64 features missing (NEON and/or AES)" ) ;
58
}
59
}
60
}
61
62
# [ inline ]
63
# [ cfg ( target_arch = " aarch64" ) ]
64
# [ target_feature ( enable = " aes" ) ]
65
unsafe fn update_aarch64_aes (
66
state : u64 ,
67
bytes : & [u8 ],
68
params : & CrcParams,
69
ops : Aarch64AesOps,
70
) -> u64 {
71
match params.width {
72
64 => algorithm:: update:: < _ , Width64> ( state, bytes, params, & ops) ,
73
32 => algorithm:: update:: < _ , Width32> ( state as u32 , bytes, params, & ops) as u64 ,
74
16 => algorithm:: update:: < _ , Width16> ( state as u16 , bytes, params, & ops) as u64 ,
75
_ => panic! ( " Unsupported CRC width: {}" , params.width) ,
76
}
77
}
78
79
# [ inline ]
80
# [ cfg ( target_arch = " aarch64" ) ]
81
# [ target_feature ( enable = " aes,sha3" ) ]
82
unsafe fn update_aarch64_aes_sha3 (
83
state : u64 ,
84
bytes : & [u8 ],
85
params : & CrcParams,
86
ops : Aarch64AesSha3Ops,
87
) -> u64 {
88
match params.width {
89
64 => algorithm:: update:: < _ , Width64> ( state, bytes, params, & ops) ,
90
32 => algorithm:: update:: < _ , Width32> ( state as u32 , bytes, params, & ops) as u64 ,
91
16 => algorithm:: update:: < _ , Width16> ( state as u16 , bytes, params, & ops) as u64 ,
92
_ => panic! ( " Unsupported CRC width: {}" , params.width) ,
93
}
94
}
95
96
97
98
99
100
# [ inline ( always ) ]
101
# [ cfg ( any ( target_arch = " x86" , target_arch = " x86_64" ) ) ]
102
pub ( crate ) unsafe fn update ( state : u64 , bytes : & [u8 ], params : & CrcParams) -> u64 {
103
use crate :: feature_detection:: { get_arch_ops, ArchOpsInstance} ;
104
105
match get_arch_ops ( ) {
106
# [ cfg ( target_arch = " x86_64" ) ]
107
ArchOpsInstance:: X86_64Avx512Vpclmulqdq( ops) => {
108
update_x86_64_avx512_vpclmulqdq ( state, bytes, params, * ops)
109
}
110
# [ cfg ( target_arch = " x86_64" ) ]
111
ArchOpsInstance:: X86_64Avx512Pclmulqdq( ops) => {
112
update_x86_64_avx512_pclmulqdq ( state, bytes, params, * ops)
113
}
114
ArchOpsInstance:: X86SsePclmulqdq( ops) => {
115
update_x86_sse_pclmulqdq ( state, bytes, params, * ops)
116
}
117
ArchOpsInstance:: SoftwareFallback => crate :: arch:: software:: update( state, bytes, params) ,
118
}
119
}
120
121
# [ inline ]
122
# [ cfg ( any ( target_arch = " x86" , target_arch = " x86_64" ) ) ]
123
# [ target_feature ( enable = " sse4.1,pclmulqdq" ) ]
124
unsafe fn update_x86_sse_pclmulqdq (
125
state : u64 ,
126
bytes : & [u8 ],
127
params : & CrcParams,
128
ops : crate:: arch:: x86:: sse:: X86SsePclmulqdqOps,
129
) -> u64 {
130
match params.width {
131
64 => algorithm:: update:: < _ , Width64> ( state, bytes, params, & ops) ,
132
32 => algorithm:: update:: < _ , Width32> ( state as u32 , bytes, params, & ops) as u64 ,
133
16 => algorithm:: update:: < _ , Width16> ( state as u16 , bytes, params, & ops) as u64 ,
134
_ => panic! ( " Unsupported CRC width: {}" , params.width) ,
135
}
136
}
137
138
# [ inline ]
139
# [ cfg ( target_arch = " x86_64" ) ]
140
# [ target_feature ( enable = " avx512vl,pclmulqdq" ) ]
141
unsafe fn update_x86_64_avx512_pclmulqdq (
142
state : u64 ,
143
bytes : & [u8 ],
144
params : & CrcParams,
145
ops : crate:: arch:: x86_64:: avx512:: X86_64Avx512PclmulqdqOps,
146
) -> u64 {
147
match params.width {
148
64 => algorithm:: update:: < _ , Width64> ( state, bytes, params, & ops) ,
149
32 => algorithm:: update:: < _ , Width32> ( state as u32 , bytes, params, & ops) as u64 ,
150
16 => algorithm:: update:: < _ , Width16> ( state as u16 , bytes, params, & ops) as u64 ,
151
_ => panic! ( " Unsupported CRC width: {}" , params.width) ,
152
}
153
}
154
155
# [ inline ]
156
# [ cfg ( target_arch = " x86_64" ) ]
157
# [ target_feature ( enable = " avx512vl,vpclmulqdq" ) ]
158
unsafe fn update_x86_64_avx512_vpclmulqdq (
159
state : u64 ,
160
bytes : & [u8 ],
161
params : & CrcParams,
162
ops : crate:: arch:: x86_64:: avx512_vpclmulqdq:: X86_64Avx512VpclmulqdqOps,
163
) -> u64 {
164
match params.width {
165
64 => algorithm:: update:: < _ , Width64> ( state, bytes, params, & ops) ,
166
32 => algorithm:: update:: < _ , Width32> ( state as u32 , bytes, params, & ops) as u64 ,
167
16 => algorithm:: update:: < _ , Width16> ( state as u16 , bytes, params, & ops) as u64 ,
168
_ => panic! ( " Unsupported CRC width: {}" , params.width) ,
169
}
170
}
171
172
# [ inline ( always ) ]
173
# [ cfg ( all (
174
not ( target_arch = " x86" ) ,
175
not ( target_arch = " x86_64" ) ,
176
not ( target_arch = " aarch64" )
177
) ) ]
178
pub ( crate ) unsafe fn update ( state : u64 , bytes : & [u8 ], params : & CrcParams) -> u64 {
179
crate :: arch:: software:: update( state, bytes, params)
180
}
181
182
# [ cfg ( test ) ]
183
mod tests {
184
use super :: * ;
185
use crate :: crc32:: consts:: CRC32_BZIP2 ;
186
use crate :: crc64:: consts:: CRC64_NVME ;
187
use crate :: test:: consts:: { TEST_256_BYTES_STRING , TEST_ALL_CONFIGS , TEST_CHECK_STRING } ;
188
use crate :: test:: create_aligned_data;
189
use crate :: test:: enums:: AnyCrcTestConfig;
190
use rand:: { rng, Rng} ;
191
192
# [ test ]
193
fn test_check_value ( ) {
194
for config in TEST_ALL_CONFIGS {
195
196
let actual = unsafe {
197
update (
198
config.get_init_algorithm ( ) ,
199
TEST_CHECK_STRING ,
200
config.get_params ( ) ,
201
) ^ config.get_xorout ( )
202
} ;
203
204
assert_eq! (
205
actual,
206
config.get_check ( ) ,
207
" Mismatch CRC, {}, expected {:#x}, got {:#x}" ,
208
config.get_name ( ) ,
209
config.get_check ( ) ,
210
actual
211
) ;
212
}
213
}
214
215
# [ test ]
216
fn test_256_string ( ) {
217
for config in TEST_ALL_CONFIGS {
218
let actual = unsafe {
219
update (
220
config.get_init_algorithm ( ) ,
221
& create_aligned_data ( TEST_256_BYTES_STRING ) ,
222
config.get_params ( ) ,
223
) ^ config.get_xorout ( )
224
} ;
225
226
assert_eq! (
227
actual,
228
config.checksum_with_reference ( TEST_256_BYTES_STRING ) ,
229
" Mismatch CRC, {}, expected {:#x}, got {:#x}" ,
230
config.get_name ( ) ,
231
config.get_check ( ) ,
232
actual
233
) ;
234
}
235
}
236
237
# [ test ]
238
fn test_512_string ( ) {
239
let test_string = b " 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234561234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456" ;
240
241
for config in TEST_ALL_CONFIGS {
242
let actual = unsafe {
243
update (
244
config.get_init_algorithm ( ) ,
245
& create_aligned_data ( test_string) ,
246
config.get_params ( ) ,
247
) ^ config.get_xorout ( )
248
} ;
249
250
assert_eq! (
251
actual,
252
config.checksum_with_reference ( test_string) ,
253
" Mismatch CRC, {}, expected {:#x}, got {:#x}" ,
254
config.get_name ( ) ,
255
config.get_check ( ) ,
256
actual
257
) ;
258
}
259
}
260
261
# [ test ]
262
fn test_1024_string ( ) {
263
let test_string = b " 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345612345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234561234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456" ;
264
265
for config in TEST_ALL_CONFIGS {
266
let actual = unsafe {
267
update (
268
config.get_init_algorithm ( ) ,
269
& create_aligned_data ( test_string) ,
270
config.get_params ( ) ,
271
) ^ config.get_xorout ( )
272
} ;
273
274
assert_eq! (
275
actual,
276
config.checksum_with_reference ( test_string) ,
277
" Mismatch CRC, {}, expected {:#x}, got {:#x}" ,
278
config.get_name ( ) ,
279
config.get_check ( ) ,
280
actual
281
) ;
282
}
283
}
284
285
286
287
# [ test ]
288
fn test_crc64_nvme_standard_vectors ( ) {
289
static CASES : & [ ( & [ u8 ] , u64 ) ] = & [
290
291
292
293
( b " 123456789" , 0xae8b14860a799888 ) ,
294
295
296
297
298
299
300
( & [ 0 ; 4096 ] , 0x6482d367eb22b64e ) ,
301
( & [ 255 ; 4096 ] , 0xc0ddba7302eca3ac ) ,
302
303
304
( TEST_256_BYTES_STRING , 0xabdb9e6c30937916 ) ,
305
( b " " , 0 ) ,
306
( b " @" , 0x2808afa9582aa47 ) ,
307
( b " 1\x97 " , 0xb4af0ae0feb08e0f ) ,
308
( b " M\" \xdf " , 0x85d7cd041a2a8a5d ) ,
309
( b " l\xcd \x13 \xd7 " , 0x1860820ea79b0fa3 ) ,
310
( & [ 0 ; 32 ] , 0xcf3473434d4ecf3b ) ,
311
( & [ 255 ; 32 ] , 0xa0a06974c34d63c4 ) ,
312
( b " \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 \x08 \x09 \x0A \x0B \x0C \x0D \x0E \x0F \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1A \x1B \x1C \x1D \x1E \x1F " , 0xb9d9d4a8492cbd7f ) ,
313
( & [ 0 ; 1024 ] , 0x691bb2b09be5498a ) ,
314
( b " hello, world!" , 0xf8046e40c403f1d0 ) ,
315
] ;
316
317
for ( input, expected) in CASES {
318
unsafe {
319
let actual = update ( CRC64_NVME .init, input, & CRC64_NVME ) ^ CRC64_NVME .xorout;
320
321
assert_eq! (
322
actual, * expected,
323
" Mismatch CRC, expected {:#x}, got {:#x}, input: {:?}" ,
324
expected, actual, input
325
) ;
326
}
327
}
328
}
329
330
331
332
333
334
335
# [ test ]
336
fn test_crc32_php_standard_vectors ( ) {
337
static CASES : & [ ( & [ u8 ] , u64 ) ] = & [
338
( b " 123456789" , 0x181989fc ) ,
339
( & [ 0 ; 4096 ] , 0xe3380088 ) ,
340
( & [ 255 ; 4096 ] , 0x8f2ae650 ) ,
341
( b " hello, world!" , 0x5eacce7 ) ,
342
] ;
343
344
for ( input, expected) in CASES {
345
let bzip2_crc = unsafe {
346
( update ( CRC32_BZIP2 .init, input, & CRC32_BZIP2 ) ^ CRC32_BZIP2 .xorout) as u32
347
} ;
348
349
350
let actual = bzip2_crc.swap_bytes ( ) ;
351
352
assert_eq! (
353
actual, * expected as u32 ,
354
" Mismatch CRC, expected {:#x}, got {:#x}, input: {:?}" ,
355
expected, actual, input
356
) ;
357
}
358
}
359
360
361
# [ test ]
362
fn test_crc16_ibm_sdlc_check_value ( ) {
363
use crate :: crc16:: consts:: CRC16_IBM_SDLC ;
364
365
let actual = unsafe {
366
update ( CRC16_IBM_SDLC .init, TEST_CHECK_STRING , & CRC16_IBM_SDLC ) ^ CRC16_IBM_SDLC .xorout
367
} ;
368
369
assert_eq! (
370
actual, 0x906E ,
371
" CRC-16/IBM-SDLC check value mismatch: expected 0x906E, got {:#x}" ,
372
actual
373
) ;
374
}
375
376
377
# [ test ]
378
fn test_crc16_t10_dif_check_value ( ) {
379
use crate :: crc16:: consts:: CRC16_T10_DIF ;
380
381
let actual = unsafe {
382
update ( CRC16_T10_DIF .init, TEST_CHECK_STRING , & CRC16_T10_DIF ) ^ CRC16_T10_DIF .xorout
383
} ;
384
385
assert_eq! (
386
actual, 0xD0DB ,
387
" CRC-16/T10-DIF check value mismatch: expected 0xD0DB, got {:#x}" ,
388
actual
389
) ;
390
}
391
392
393
394
# [ test ]
395
# [ cfg_attr ( miri, ignore ) ]
396
fn test_small_lengths_all ( ) {
397
398
for config in TEST_ALL_CONFIGS {
399
400
for len in 0 .. = 255 {
401
test_length ( len, config) ;
402
}
403
}
404
}
405
406
407
408
# [ test ]
409
# [ cfg_attr ( miri, ignore ) ]
410
fn test_medium_lengths ( ) {
411
412
for config in TEST_ALL_CONFIGS {
413
414
for len in 256 .. = 1024 {
415
test_length ( len, config) ;
416
}
417
}
418
}
419
420
421
422
# [ test ]
423
# [ cfg_attr ( miri, ignore ) ]
424
fn test_large_lengths ( ) {
425
426
for config in TEST_ALL_CONFIGS {
427
428
for len in 1048575 .. = 1048577 {
429
test_length ( len, config) ;
430
}
431
}
432
}
433
434
fn test_length ( length : usize , config : & AnyCrcTestConfig) {
435
let mut data = vec! [ 0 u8 ; length] ;
436
rng ( ) .fill ( & mut data[ .. ] ) ;
437
438
439
let expected = config.checksum_with_reference ( & data) ;
440
441
442
let actual = unsafe {
443
update ( config.get_init_algorithm ( ) , & data, config.get_params ( ) ) ^ config.get_xorout ( )
444
} ;
445
446
assert_eq! (
447
actual,
448
expected,
449
" \n Failed for {} with length {}\n Got: {:016x}\n Expected: {:016x}" ,
450
config.get_name ( ) ,
451
length,
452
actual,
453
expected
454
) ;
455
}
456
}