2022-12-08 16:52:42 +00:00
|
|
|
//! This selects the curve25519_dalek_bits either by default from target_pointer_width or explicitly set
|
|
|
|
|
|
2023-03-10 18:21:20 +00:00
|
|
|
#![deny(clippy::unwrap_used, dead_code)]
|
|
|
|
|
|
2022-12-10 02:09:24 +00:00
|
|
|
#[allow(non_camel_case_types)]
|
2026-06-29 14:44:40 +00:00
|
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
2022-12-10 02:09:24 +00:00
|
|
|
enum DalekBits {
|
|
|
|
|
Dalek32,
|
|
|
|
|
Dalek64,
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-01 14:35:23 +00:00
|
|
|
use std::fmt::Formatter;
|
|
|
|
|
|
|
|
|
|
impl std::fmt::Display for DalekBits {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
|
|
|
let w_bits = match self {
|
|
|
|
|
DalekBits::Dalek32 => "32",
|
|
|
|
|
DalekBits::Dalek64 => "64",
|
|
|
|
|
};
|
2025-10-24 21:20:50 +00:00
|
|
|
write!(f, "{w_bits}")
|
2024-03-01 14:35:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-29 14:44:40 +00:00
|
|
|
fn target_has_feature(feature: &str) -> bool {
|
|
|
|
|
std::env::var("CARGO_CFG_TARGET_FEATURE")
|
|
|
|
|
.map(|features| features.split(',').any(|f| f == feature))
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 16:52:42 +00:00
|
|
|
fn main() {
|
2024-03-01 14:35:23 +00:00
|
|
|
let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") {
|
|
|
|
|
Ok(arch) => arch,
|
|
|
|
|
_ => "".to_string(),
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-18 08:34:47 +00:00
|
|
|
let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() {
|
|
|
|
|
Ok("32") => DalekBits::Dalek32,
|
|
|
|
|
Ok("64") => DalekBits::Dalek64,
|
2024-03-01 14:35:23 +00:00
|
|
|
_ => deterministic::determine_curve25519_dalek_bits(&target_arch),
|
2023-03-18 08:34:47 +00:00
|
|
|
};
|
2022-12-10 02:09:24 +00:00
|
|
|
|
2024-03-01 14:35:23 +00:00
|
|
|
println!("cargo:rustc-cfg=curve25519_dalek_bits=\"{curve25519_dalek_bits}\"");
|
2023-03-30 06:16:18 +00:00
|
|
|
|
2023-04-11 11:55:47 +00:00
|
|
|
let rustc_version = rustc_version::version().expect("failed to detect rustc version");
|
|
|
|
|
if rustc_version.major == 1 && rustc_version.minor <= 64 {
|
|
|
|
|
// Old versions of Rust complain when you have an `unsafe fn` and you use `unsafe {}` inside,
|
|
|
|
|
// so for those we want to apply the `#[allow(unused_unsafe)]` attribute to get rid of that warning.
|
|
|
|
|
println!("cargo:rustc-cfg=allow_unused_unsafe");
|
|
|
|
|
}
|
2023-06-22 05:46:27 +00:00
|
|
|
|
|
|
|
|
// Backend overrides / defaults
|
2026-06-29 14:44:40 +00:00
|
|
|
let curve25519_dalek_backend =
|
|
|
|
|
match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() {
|
|
|
|
|
Ok("fiat") => "fiat",
|
|
|
|
|
Ok("serial") => "serial",
|
|
|
|
|
Ok("simd") => {
|
|
|
|
|
// simd can only be enabled on x86_64 & 64bit target_pointer_width
|
|
|
|
|
match is_capable_simd(&target_arch, curve25519_dalek_bits) {
|
|
|
|
|
true => "simd",
|
|
|
|
|
// If override is not possible this must result to compile error
|
|
|
|
|
// See: issues/532
|
|
|
|
|
false => panic!("Could not override curve25519_dalek_backend to simd"),
|
|
|
|
|
}
|
2024-09-08 05:13:36 +00:00
|
|
|
}
|
2026-06-29 14:44:40 +00:00
|
|
|
Ok("avx512") => {
|
|
|
|
|
// AVX-512 can only be enabled on x86_64 & 64bit target_pointer_width
|
|
|
|
|
match is_capable_simd(&target_arch, curve25519_dalek_bits) {
|
|
|
|
|
true => {
|
|
|
|
|
// Enable SIMD as fallback through stable backend
|
|
|
|
|
// NOTE: Compiler permits duplicate / multi value on the same key
|
|
|
|
|
println!("cargo:rustc-cfg=curve25519_dalek_backend=\"simd\"");
|
|
|
|
|
"avx512"
|
|
|
|
|
}
|
|
|
|
|
// If override is not possible this must result to compile error
|
|
|
|
|
// See: issues/532
|
|
|
|
|
false => panic!("Could not override curve25519_dalek_backend to avx512"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// default between serial / simd / avx512 (if potentially capable)
|
|
|
|
|
_ => match is_capable_avx512(&target_arch, curve25519_dalek_bits, rustc_version) {
|
2024-09-08 05:13:36 +00:00
|
|
|
true => {
|
|
|
|
|
println!("cargo:rustc-cfg=curve25519_dalek_backend=\"simd\"");
|
2026-06-29 14:44:40 +00:00
|
|
|
"avx512"
|
2023-06-22 05:46:27 +00:00
|
|
|
}
|
2026-06-29 14:44:40 +00:00
|
|
|
false => match is_capable_simd(&target_arch, curve25519_dalek_bits) {
|
|
|
|
|
true => "simd",
|
|
|
|
|
false => "serial",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
2023-06-22 05:46:27 +00:00
|
|
|
println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Is the target arch & curve25519_dalek_bits potentially simd capable ?
|
|
|
|
|
fn is_capable_simd(arch: &str, bits: DalekBits) -> bool {
|
|
|
|
|
arch == "x86_64" && bits == DalekBits::Dalek64
|
2022-12-08 16:52:42 +00:00
|
|
|
}
|
2023-03-10 18:21:20 +00:00
|
|
|
|
2026-06-29 14:44:40 +00:00
|
|
|
// Is the target arch & curve25519_dalek_bits potentially AVX-512 capable ?
|
|
|
|
|
fn is_capable_avx512(arch: &str, bits: DalekBits, rustc_version: rustc_version::Version) -> bool {
|
|
|
|
|
// AVX-512 requires rustc >=1.89 or nightly
|
|
|
|
|
if rustc_version.major == 1 && rustc_version.minor < 89 {
|
|
|
|
|
let channel = rustc_version::version_meta()
|
|
|
|
|
.expect("failed to detect rustc version")
|
|
|
|
|
.channel;
|
|
|
|
|
|
|
|
|
|
if channel != rustc_version::Channel::Nightly {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_capable_simd(arch, bits)
|
|
|
|
|
&& target_has_feature("avx512ifma")
|
|
|
|
|
&& target_has_feature("avx512vl")
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-10 18:21:20 +00:00
|
|
|
// Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set.
|
|
|
|
|
mod deterministic {
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
2024-03-01 14:35:23 +00:00
|
|
|
// Custom Rust non-cargo build tooling needs to set CARGO_CFG_TARGET_POINTER_WIDTH
|
|
|
|
|
static ERR_MSG_NO_POINTER_WIDTH: &str =
|
|
|
|
|
"Standard Cargo TARGET_POINTER_WIDTH environment variable is not set.";
|
2023-03-10 18:21:20 +00:00
|
|
|
|
2024-03-01 14:35:23 +00:00
|
|
|
// When either non-32 or 64 TARGET_POINTER_WIDTH detected
|
|
|
|
|
static ERR_MSG_UNKNOWN_POINTER_WIDTH: &str = "Unknown TARGET_POINTER_WIDTH detected.";
|
2023-03-10 18:21:20 +00:00
|
|
|
|
2023-03-18 08:34:47 +00:00
|
|
|
// Warning when the curve25519_dalek_bits cannot be determined
|
|
|
|
|
fn determine_curve25519_dalek_bits_warning(cause: &str) {
|
|
|
|
|
println!("cargo:warning=\"Defaulting to curve25519_dalek_bits=32: {cause}\"");
|
2023-03-10 18:21:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine the curve25519_dalek_bits based on Rust standard TARGET triplet
|
2024-03-01 14:35:23 +00:00
|
|
|
pub(super) fn determine_curve25519_dalek_bits(target_arch: &String) -> DalekBits {
|
|
|
|
|
let target_pointer_width = match std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH") {
|
|
|
|
|
Ok(pw) => pw,
|
2023-03-18 08:34:47 +00:00
|
|
|
Err(_) => {
|
2024-03-01 14:35:23 +00:00
|
|
|
determine_curve25519_dalek_bits_warning(ERR_MSG_NO_POINTER_WIDTH);
|
2023-03-18 08:34:47 +00:00
|
|
|
return DalekBits::Dalek32;
|
|
|
|
|
}
|
2023-03-10 18:21:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[allow(clippy::match_single_binding)]
|
2024-03-01 14:35:23 +00:00
|
|
|
match &target_arch {
|
2023-03-10 18:21:20 +00:00
|
|
|
//Issues: 449 and 456
|
2024-03-01 14:35:23 +00:00
|
|
|
//TODO: When adding arch defaults use proper types not String match
|
2023-03-10 18:21:20 +00:00
|
|
|
//TODO(Arm): Needs tests + benchmarks to back this up
|
|
|
|
|
//TODO(Wasm32): Needs tests + benchmarks to back this up
|
2024-03-01 14:35:23 +00:00
|
|
|
_ => match target_pointer_width.as_ref() {
|
|
|
|
|
"64" => DalekBits::Dalek64,
|
|
|
|
|
"32" => DalekBits::Dalek32,
|
2023-03-10 18:21:20 +00:00
|
|
|
// Intended default solely for non-32/64 target pointer widths
|
|
|
|
|
// Otherwise known target platforms only.
|
2024-03-01 14:35:23 +00:00
|
|
|
_ => {
|
|
|
|
|
determine_curve25519_dalek_bits_warning(ERR_MSG_UNKNOWN_POINTER_WIDTH);
|
|
|
|
|
DalekBits::Dalek32
|
|
|
|
|
}
|
2023-03-10 18:21:20 +00:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|