1
- //! Autodetection support for AVX2 CPU intrinsics on x86 CPUs, with fallback
2
- //! to the SSE2 backend when it's unavailable (the `sse2` target feature is
3
- //! enabled-by-default on all x86(_64) CPUs)
1
+ //! Autodetection support for AVX2 CPU and SSE2 intrinsics on x86 CPUs, with
2
+ //! fallback to a portable version when they're unavailable.
4
3
5
- use super :: { avx2, sse2} ;
4
+ use super :: { avx2, soft , sse2} ;
6
5
use crate :: { rounds:: Rounds , BLOCK_SIZE , IV_SIZE , KEY_SIZE } ;
7
6
use core:: mem:: ManuallyDrop ;
8
7
@@ -13,75 +12,99 @@ use core::mem::ManuallyDrop;
13
12
pub ( crate ) const BUFFER_SIZE : usize = BLOCK_SIZE * 4 ;
14
13
15
14
cpufeatures:: new!( avx2_cpuid, "avx2" ) ;
15
+ cpufeatures:: new!( sse2_cpuid, "sse2" ) ;
16
16
17
17
/// The ChaCha20 core function.
18
18
pub struct Core < R : Rounds > {
19
19
inner : Inner < R > ,
20
- token : avx2_cpuid:: InitToken ,
20
+ avx2_token : avx2_cpuid:: InitToken ,
21
+ sse2_token : sse2_cpuid:: InitToken ,
21
22
}
22
23
23
24
union Inner < R : Rounds > {
24
25
avx2 : ManuallyDrop < avx2:: Core < R > > ,
25
26
sse2 : ManuallyDrop < sse2:: Core < R > > ,
27
+ soft : ManuallyDrop < soft:: Core < R > > ,
26
28
}
27
29
28
30
impl < R : Rounds > Core < R > {
29
31
/// Initialize ChaCha core function with the given key size, IV, and
30
32
/// number of rounds.
33
+ ///
34
+ /// Attempts to use AVX2 if present, followed by SSE2, with fallback to a
35
+ /// portable software implementation if neither are available.
31
36
#[ inline]
32
37
pub fn new ( key : & [ u8 ; KEY_SIZE ] , iv : [ u8 ; IV_SIZE ] ) -> Self {
33
- let ( token, avx2_present) = avx2_cpuid:: init_get ( ) ;
38
+ let ( avx2_token, avx2_present) = avx2_cpuid:: init_get ( ) ;
39
+ let ( sse2_token, sse2_present) = sse2_cpuid:: init_get ( ) ;
34
40
35
41
let inner = if avx2_present {
36
42
Inner {
37
43
avx2 : ManuallyDrop :: new ( avx2:: Core :: new ( key, iv) ) ,
38
44
}
39
- } else {
45
+ } else if sse2_present {
40
46
Inner {
41
47
sse2 : ManuallyDrop :: new ( sse2:: Core :: new ( key, iv) ) ,
42
48
}
49
+ } else {
50
+ Inner {
51
+ soft : ManuallyDrop :: new ( soft:: Core :: new ( key, iv) ) ,
52
+ }
43
53
} ;
44
54
45
- Self { inner, token }
55
+ Self {
56
+ inner,
57
+ avx2_token,
58
+ sse2_token,
59
+ }
46
60
}
47
61
48
- /// Generate output, overwriting data already in the buffer
62
+ /// Generate output, overwriting data already in the buffer.
49
63
#[ inline]
50
- pub fn generate ( & self , counter : u64 , output : & mut [ u8 ] ) {
51
- if self . token . get ( ) {
64
+ pub fn generate ( & mut self , counter : u64 , output : & mut [ u8 ] ) {
65
+ if self . avx2_token . get ( ) {
52
66
unsafe { ( * self . inner . avx2 ) . generate ( counter, output) }
53
- } else {
67
+ } else if self . sse2_token . get ( ) {
54
68
unsafe { ( * self . inner . sse2 ) . generate ( counter, output) }
69
+ } else {
70
+ unsafe { ( * self . inner . soft ) . generate ( counter, output) }
55
71
}
56
72
}
57
73
58
- /// Apply generated keystream to the output buffer
74
+ /// Apply generated keystream to the output buffer.
59
75
#[ inline]
60
76
#[ cfg( feature = "cipher" ) ]
61
- pub fn apply_keystream ( & self , counter : u64 , output : & mut [ u8 ] ) {
62
- if self . token . get ( ) {
77
+ pub fn apply_keystream ( & mut self , counter : u64 , output : & mut [ u8 ] ) {
78
+ if self . avx2_token . get ( ) {
63
79
unsafe { ( * self . inner . avx2 ) . apply_keystream ( counter, output) }
64
- } else {
80
+ } else if self . sse2_token . get ( ) {
65
81
unsafe { ( * self . inner . sse2 ) . apply_keystream ( counter, output) }
82
+ } else {
83
+ unsafe { ( * self . inner . soft ) . apply_keystream ( counter, output) }
66
84
}
67
85
}
68
86
}
69
87
70
88
impl < R : Rounds > Clone for Core < R > {
71
89
fn clone ( & self ) -> Self {
72
- let inner = if self . token . get ( ) {
90
+ let inner = if self . avx2_token . get ( ) {
73
91
Inner {
74
92
avx2 : ManuallyDrop :: new ( unsafe { ( * self . inner . avx2 ) . clone ( ) } ) ,
75
93
}
76
- } else {
94
+ } else if self . sse2_token . get ( ) {
77
95
Inner {
78
96
sse2 : ManuallyDrop :: new ( unsafe { ( * self . inner . sse2 ) . clone ( ) } ) ,
79
97
}
98
+ } else {
99
+ Inner {
100
+ soft : ManuallyDrop :: new ( unsafe { ( * self . inner . soft ) . clone ( ) } ) ,
101
+ }
80
102
} ;
81
103
82
104
Self {
83
105
inner,
84
- token : self . token ,
106
+ avx2_token : self . avx2_token ,
107
+ sse2_token : self . sse2_token ,
85
108
}
86
109
}
87
110
}
0 commit comments