Skip to content

Commit b636fb8

Browse files
pinkforestrozbb
andauthoredSep 8, 2024··
Make AVX512IFMA opt-in backend (#695)
* Make AVX512IFMA opt-in backend * Updated README to have backend info * Added entry to changelog --------- Co-authored-by: Michael Rosenberg <michael@mrosenberg.pub>
1 parent 0964f80 commit b636fb8

File tree

11 files changed

+87
-45
lines changed

11 files changed

+87
-45
lines changed
 

‎curve25519-dalek/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
Entries are listed in reverse chronological order per undeprecated
44
major series.
55

6+
## Unreleased
7+
8+
* Move AVX-512 backend selection logic to a separate CFG flag that requires nightly
9+
610
## 4.x series
711

812
### 4.1.3

‎curve25519-dalek/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive"
7676
level = "warn"
7777
check-cfg = [
7878
'cfg(allow_unused_unsafe)',
79-
'cfg(curve25519_dalek_backend, values("fiat", "serial", "simd"))',
79+
'cfg(curve25519_dalek_backend, values("fiat", "serial", "simd", "unstable_avx512"))',
8080
'cfg(curve25519_dalek_diagnostics, values("build"))',
8181
'cfg(curve25519_dalek_bits, values("32", "64"))',
8282
'cfg(nightly)',

‎curve25519-dalek/README.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,12 @@ This release also does a lot of dependency updates and relaxations to unblock up
9090

9191
Curve arithmetic is implemented and used by one of the following backends:
9292

93-
| Backend | Selection | Implementation | Bits / Word sizes |
94-
| :--- | :--- | :--- | :--- |
95-
| `serial` | Automatic | An optimized, non-parllel implementation | `32` and `64` |
96-
| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` |
97-
| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only |
93+
| Backend | Selection | Implementation | Bits / Word sizes |
94+
| :--- | :--- | :--- | :--- |
95+
| `serial` | Automatic | An optimized, non-parllel implementation | `32` and `64` |
96+
| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` |
97+
| `simd` | Automatic | Intel AVX2 accelerated backend | `64` only |
98+
| `unstable_avx512` | Manual | Intel AVX512 IFMA accelerated backend (requires nightly) | `64` only |
9899

99100
At runtime, `curve25519-dalek` selects an arithmetic backend from the set of backends it was compiled to support. For Intel x86-64 targets, unless otherwise specified, it will build itself with `simd` support, and default to `serial` at runtime if the appropriate CPU features aren't detected. See [SIMD backend] for more details.
100101

@@ -148,16 +149,16 @@ $ cargo build --target i686-unknown-linux-gnu
148149

149150
## SIMD backend
150151

151-
The specific SIMD backend (AVX512 / AVX2 / `serial` default) is selected automatically at runtime, depending on the currently available CPU features, and whether Rust nightly is being used for compilation. The precise conditions are specified below.
152+
When the `simd` backend is selected, the AVX2 or `serial` implementation is selected automatically at runtime, depending on the currently available CPU features. Similarly, when the `unstable_avx512` backend is selected, the AVX512 implementation is selected automatically at runtime if available, or else selection falls through to the aforementioned `simd` backend logic.
152153

153154
For a given CPU feature, you can also specify an appropriate `-C target_feature` to build a binary which assumes the required SIMD instructions are always available. Don't do this if you don't have a good reason.
154155

155156
| Backend | `RUSTFLAGS` | Requires nightly? |
156157
| :--- | :--- | :--- |
157-
| avx2 | `-C target_feature=+avx2` | no |
158-
| avx512 | `-C target_feature=+avx512ifma,+avx512vl` | yes |
158+
| AVX2 | `-C target_feature=+avx2` | no |
159+
| AVX512 | `-C target_feature=+avx512ifma,+avx512vl` | yes |
159160

160-
If compiled on a non-nightly compiler, `curve25519-dalek` will not include AVX512 code, and therefore will never select it at runtime.
161+
To reiterate, the `simd` backend will NOT use AVX512 code under any circumstance. The only way to enable AVX512 currently is to select the `unstable_avx512` backend and use a nightly compiler.
161162

162163
# Documentation
163164

‎curve25519-dalek/build.rs

+41-19
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ fn main() {
3535

3636
println!("cargo:rustc-cfg=curve25519_dalek_bits=\"{curve25519_dalek_bits}\"");
3737

38-
if rustc_version::version_meta()
38+
let nightly = if rustc_version::version_meta()
3939
.expect("failed to detect rustc version")
4040
.channel
4141
== rustc_version::Channel::Nightly
4242
{
4343
println!("cargo:rustc-cfg=nightly");
44-
}
44+
true
45+
} else {
46+
false
47+
};
4548

4649
let rustc_version = rustc_version::version().expect("failed to detect rustc version");
4750
if rustc_version.major == 1 && rustc_version.minor <= 64 {
@@ -51,25 +54,44 @@ fn main() {
5154
}
5255

5356
// Backend overrides / defaults
54-
let curve25519_dalek_backend =
55-
match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() {
56-
Ok("fiat") => "fiat",
57-
Ok("serial") => "serial",
58-
Ok("simd") => {
59-
// simd can only be enabled on x86_64 & 64bit target_pointer_width
60-
match is_capable_simd(&target_arch, curve25519_dalek_bits) {
61-
true => "simd",
62-
// If override is not possible this must result to compile error
63-
// See: issues/532
64-
false => panic!("Could not override curve25519_dalek_backend to simd"),
57+
let curve25519_dalek_backend = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND")
58+
.as_deref()
59+
{
60+
Ok("fiat") => "fiat",
61+
Ok("serial") => "serial",
62+
Ok("simd") => {
63+
// simd can only be enabled on x86_64 & 64bit target_pointer_width
64+
match is_capable_simd(&target_arch, curve25519_dalek_bits) {
65+
true => "simd",
66+
// If override is not possible this must result to compile error
67+
// See: issues/532
68+
false => panic!("Could not override curve25519_dalek_backend to simd"),
69+
}
70+
}
71+
Ok("unstable_avx512") if nightly => {
72+
// simd can only be enabled on x86_64 & 64bit target_pointer_width
73+
match is_capable_simd(&target_arch, curve25519_dalek_bits) {
74+
true => {
75+
// In addition enable Avx2 fallback through simd stable backend
76+
// NOTE: Compiler permits duplicate / multi value on the same key
77+
println!("cargo:rustc-cfg=curve25519_dalek_backend=\"simd\"");
78+
79+
"unstable_avx512"
6580
}
81+
// If override is not possible this must result to compile error
82+
// See: issues/532
83+
false => panic!("Could not override curve25519_dalek_backend to unstable_avx512"),
6684
}
67-
// default between serial / simd (if potentially capable)
68-
_ => match is_capable_simd(&target_arch, curve25519_dalek_bits) {
69-
true => "simd",
70-
false => "serial",
71-
},
72-
};
85+
}
86+
Ok("unstable_avx512") if !nightly => {
87+
panic!("Could not override curve25519_dalek_backend to unstable_avx512, as this is nigthly only");
88+
}
89+
// default between serial / simd (if potentially capable)
90+
_ => match is_capable_simd(&target_arch, curve25519_dalek_bits) {
91+
true => "simd",
92+
false => "serial",
93+
},
94+
};
7395
println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\"");
7496
}
7597

‎curve25519-dalek/src/backend/mod.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ pub mod vector;
4646
enum BackendKind {
4747
#[cfg(curve25519_dalek_backend = "simd")]
4848
Avx2,
49-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
49+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
5050
Avx512,
5151
Serial,
5252
}
5353

5454
#[inline]
5555
fn get_selected_backend() -> BackendKind {
56-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
56+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
5757
{
5858
cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl");
5959
let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init();
@@ -88,7 +88,7 @@ where
8888
#[cfg(curve25519_dalek_backend = "simd")]
8989
BackendKind::Avx2 =>
9090
vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
91-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
91+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
9292
BackendKind::Avx512 =>
9393
vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::<I, J>(scalars, points),
9494
BackendKind::Serial =>
@@ -100,7 +100,7 @@ where
100100
pub(crate) enum VartimePrecomputedStraus {
101101
#[cfg(curve25519_dalek_backend = "simd")]
102102
Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus),
103-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
103+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
104104
Avx512ifma(
105105
vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus,
106106
),
@@ -120,7 +120,7 @@ impl VartimePrecomputedStraus {
120120
#[cfg(curve25519_dalek_backend = "simd")]
121121
BackendKind::Avx2 =>
122122
VartimePrecomputedStraus::Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)),
123-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
123+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
124124
BackendKind::Avx512 =>
125125
VartimePrecomputedStraus::Avx512ifma(vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)),
126126
BackendKind::Serial =>
@@ -150,7 +150,7 @@ impl VartimePrecomputedStraus {
150150
dynamic_scalars,
151151
dynamic_points,
152152
),
153-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
153+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
154154
VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul(
155155
static_scalars,
156156
dynamic_scalars,
@@ -181,7 +181,7 @@ where
181181
BackendKind::Avx2 => {
182182
vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::<I, J>(scalars, points)
183183
}
184-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
184+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
185185
BackendKind::Avx512 => {
186186
vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::<I, J>(
187187
scalars, points,
@@ -210,7 +210,7 @@ where
210210
scalars, points,
211211
)
212212
}
213-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
213+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
214214
BackendKind::Avx512 => {
215215
vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::<
216216
I,
@@ -228,7 +228,7 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint
228228
match get_selected_backend() {
229229
#[cfg(curve25519_dalek_backend = "simd")]
230230
BackendKind::Avx2 => vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar),
231-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
231+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
232232
BackendKind::Avx512 => {
233233
vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar)
234234
}
@@ -242,7 +242,7 @@ pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> Edwa
242242
match get_selected_backend() {
243243
#[cfg(curve25519_dalek_backend = "simd")]
244244
BackendKind::Avx2 => vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b),
245-
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
245+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
246246
BackendKind::Avx512 => {
247247
vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b)
248248
}

‎curve25519-dalek/src/backend/vector/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub mod packed_simd;
1616

1717
pub mod avx2;
1818

19-
#[cfg(nightly)]
19+
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
2020
pub mod ifma;
2121

2222
pub mod scalar_mul;

‎curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111

1212
#[curve25519_dalek_derive::unsafe_target_feature_specialize(
1313
"avx2",
14-
conditional("avx512ifma,avx512vl", nightly)
14+
conditional(
15+
"avx512ifma,avx512vl",
16+
all(curve25519_dalek_backend = "unstable_avx512", nightly)
17+
)
1518
)]
1619
pub mod spec {
1720

‎curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
#[curve25519_dalek_derive::unsafe_target_feature_specialize(
1515
"avx2",
16-
conditional("avx512ifma,avx512vl", nightly)
16+
conditional(
17+
"avx512ifma,avx512vl",
18+
all(curve25519_dalek_backend = "unstable_avx512", nightly)
19+
)
1720
)]
1821
pub mod spec {
1922

‎curve25519-dalek/src/backend/vector/scalar_mul/straus.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
#[curve25519_dalek_derive::unsafe_target_feature_specialize(
1515
"avx2",
16-
conditional("avx512ifma,avx512vl", nightly)
16+
conditional(
17+
"avx512ifma,avx512vl",
18+
all(curve25519_dalek_backend = "unstable_avx512", nightly)
19+
)
1720
)]
1821
pub mod spec {
1922

‎curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
#[curve25519_dalek_derive::unsafe_target_feature_specialize(
44
"avx2",
5-
conditional("avx512ifma,avx512vl", nightly)
5+
conditional(
6+
"avx512ifma,avx512vl",
7+
all(curve25519_dalek_backend = "unstable_avx512", nightly)
8+
)
69
)]
710
pub mod spec {
811

‎curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
#[curve25519_dalek_derive::unsafe_target_feature_specialize(
1515
"avx2",
16-
conditional("avx512ifma,avx512vl", nightly)
16+
conditional(
17+
"avx512ifma,avx512vl",
18+
all(curve25519_dalek_backend = "unstable_avx512", nightly)
19+
)
1720
)]
1821
pub mod spec {
1922

0 commit comments

Comments
 (0)