#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Backend {
Scalar,
Avx512Vbmi,
Avx2,
Ssse3Sse41,
Neon,
WasmSimd128,
}
impl Backend {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Scalar => "scalar",
Self::Avx512Vbmi => "avx512-vbmi",
Self::Avx2 => "avx2",
Self::Ssse3Sse41 => "ssse3-sse4.1",
Self::Neon => "neon",
Self::WasmSimd128 => "wasm-simd128",
}
}
#[must_use]
pub const fn required_cpu_features(self) -> &'static [&'static str] {
match self {
Self::Scalar => &[],
Self::Avx512Vbmi => &["avx512f", "avx512bw", "avx512vl", "avx512vbmi"],
Self::Avx2 => &["avx2"],
Self::Ssse3Sse41 => &["ssse3", "sse4.1"],
Self::Neon => &["neon"],
Self::WasmSimd128 => &["simd128"],
}
}
}
impl core::fmt::Display for Backend {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum CandidateDetectionMode {
SimdFeatureDisabled,
RuntimeCpuFeatures,
CompileTimeTargetFeatures,
}
impl CandidateDetectionMode {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::SimdFeatureDisabled => "simd-feature-disabled",
Self::RuntimeCpuFeatures => "runtime-cpu-features",
Self::CompileTimeTargetFeatures => "compile-time-target-features",
}
}
}
impl core::fmt::Display for CandidateDetectionMode {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum SecurityPosture {
ScalarOnly,
SimdCandidateScalarActive,
Accelerated,
}
impl SecurityPosture {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::ScalarOnly => "scalar-only",
Self::SimdCandidateScalarActive => "simd-candidate-scalar-active",
Self::Accelerated => "accelerated",
}
}
}
impl core::fmt::Display for SecurityPosture {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum WipePosture {
HardwareFence,
CompilerFenceOnly,
}
impl WipePosture {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::HardwareFence => "hardware-fence",
Self::CompilerFenceOnly => "compiler-fence-only",
}
}
}
impl core::fmt::Display for WipePosture {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum CtGatePosture {
HardwareSpeculationBarrier,
HardwareSpeculationBarrierUnattested,
OrderingFence,
CompilerFenceOnly,
}
impl CtGatePosture {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::HardwareSpeculationBarrier => "hardware-speculation-barrier",
Self::HardwareSpeculationBarrierUnattested => "hardware-speculation-barrier-unattested",
Self::OrderingFence => "ordering-fence",
Self::CompilerFenceOnly => "compiler-fence-only",
}
}
}
impl core::fmt::Display for CtGatePosture {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum MemoryLockPosture {
NotProvided,
}
impl MemoryLockPosture {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::NotProvided => "not-provided",
}
}
}
impl core::fmt::Display for MemoryLockPosture {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum BackendPolicy {
ScalarExecutionOnly,
SimdFeatureDisabled,
NoDetectedSimdCandidate,
HighAssuranceScalarOnly,
}
impl BackendPolicy {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::ScalarExecutionOnly => "scalar-execution-only",
Self::SimdFeatureDisabled => "simd-feature-disabled",
Self::NoDetectedSimdCandidate => "no-detected-simd-candidate",
Self::HighAssuranceScalarOnly => "high-assurance-scalar-only",
}
}
}
impl core::fmt::Display for BackendPolicy {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BackendPolicyError {
pub policy: BackendPolicy,
pub report: BackendReport,
}
impl core::fmt::Display for BackendPolicyError {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
formatter,
"runtime backend policy `{}` was not satisfied ({})",
self.policy, self.report,
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for BackendPolicyError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BackendReport {
pub active: Backend,
pub candidate: Backend,
pub candidate_detection_mode: CandidateDetectionMode,
pub simd_feature_enabled: bool,
pub accelerated_backend_active: bool,
pub unsafe_boundary_enforced: bool,
pub security_posture: SecurityPosture,
pub wipe_posture: WipePosture,
pub ct_gate_posture: CtGatePosture,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BackendSnapshot {
pub active: &'static str,
pub candidate: &'static str,
pub candidate_detection_mode: &'static str,
pub candidate_required_cpu_features: &'static [&'static str],
pub simd_feature_enabled: bool,
pub accelerated_backend_active: bool,
pub unsafe_boundary_enforced: bool,
pub security_posture: &'static str,
pub wipe_posture: &'static str,
pub ct_gate_posture: &'static str,
}
impl core::fmt::Display for BackendReport {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
formatter,
"active={} candidate={} candidate_detection_mode={} candidate_required_cpu_features=",
self.active, self.candidate, self.candidate_detection_mode,
)?;
write_feature_list(formatter, self.candidate_required_cpu_features())?;
write!(
formatter,
" simd_feature_enabled={} accelerated_backend_active={} unsafe_boundary_enforced={} security_posture={} wipe_posture={} ct_gate_posture={}",
self.simd_feature_enabled,
self.accelerated_backend_active,
self.unsafe_boundary_enforced,
self.security_posture,
self.wipe_posture,
self.ct_gate_posture,
)
}
}
impl BackendReport {
#[must_use]
pub const fn satisfies(self, policy: BackendPolicy) -> bool {
match policy {
BackendPolicy::ScalarExecutionOnly => {
matches!(self.active, Backend::Scalar) && !self.accelerated_backend_active
}
BackendPolicy::SimdFeatureDisabled => !self.simd_feature_enabled,
BackendPolicy::NoDetectedSimdCandidate => matches!(self.candidate, Backend::Scalar),
BackendPolicy::HighAssuranceScalarOnly => {
matches!(self.active, Backend::Scalar)
&& matches!(self.candidate, Backend::Scalar)
&& !self.simd_feature_enabled
&& !self.accelerated_backend_active
&& self.unsafe_boundary_enforced
&& matches!(
self.ct_gate_posture,
CtGatePosture::HardwareSpeculationBarrier
)
}
}
}
#[must_use]
pub const fn candidate_required_cpu_features(self) -> &'static [&'static str] {
self.candidate.required_cpu_features()
}
#[must_use]
pub const fn memory_lock_posture(self) -> MemoryLockPosture {
let _ = self;
MemoryLockPosture::NotProvided
}
#[must_use]
pub const fn snapshot(self) -> BackendSnapshot {
BackendSnapshot {
active: self.active.as_str(),
candidate: self.candidate.as_str(),
candidate_detection_mode: self.candidate_detection_mode.as_str(),
candidate_required_cpu_features: self.candidate_required_cpu_features(),
simd_feature_enabled: self.simd_feature_enabled,
accelerated_backend_active: self.accelerated_backend_active,
unsafe_boundary_enforced: self.unsafe_boundary_enforced,
security_posture: self.security_posture.as_str(),
wipe_posture: self.wipe_posture.as_str(),
ct_gate_posture: self.ct_gate_posture.as_str(),
}
}
}
#[must_use]
pub fn backend_report() -> BackendReport {
let active = active_backend();
let candidate = detected_candidate();
let candidate_detection_mode = candidate_detection_mode();
let accelerated_backend_active = active != Backend::Scalar;
let unsafe_boundary_enforced = !cfg!(feature = "simd");
let security_posture = if accelerated_backend_active {
SecurityPosture::Accelerated
} else if candidate != Backend::Scalar {
SecurityPosture::SimdCandidateScalarActive
} else {
SecurityPosture::ScalarOnly
};
BackendReport {
active,
candidate,
candidate_detection_mode,
simd_feature_enabled: cfg!(feature = "simd"),
accelerated_backend_active,
unsafe_boundary_enforced,
security_posture,
wipe_posture: wipe_posture(),
ct_gate_posture: ct_gate_posture(),
}
}
const fn wipe_posture() -> WipePosture {
if cfg!(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "x86",
target_arch = "x86_64",
)) {
WipePosture::HardwareFence
} else {
WipePosture::CompilerFenceOnly
}
}
const fn ct_gate_posture() -> CtGatePosture {
if cfg!(any(
target_arch = "x86",
target_arch = "x86_64",
all(target_arch = "aarch64", base64_ng_aarch64_csdb_attested)
)) {
CtGatePosture::HardwareSpeculationBarrier
} else if cfg!(target_arch = "aarch64") {
CtGatePosture::HardwareSpeculationBarrierUnattested
} else if cfg!(any(
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64"
)) {
CtGatePosture::OrderingFence
} else {
CtGatePosture::CompilerFenceOnly
}
}
pub fn require_backend_policy(policy: BackendPolicy) -> Result<(), BackendPolicyError> {
let report = backend_report();
if report.satisfies(policy) {
Ok(())
} else {
Err(BackendPolicyError { policy, report })
}
}
fn write_feature_list(
formatter: &mut core::fmt::Formatter<'_>,
features: &[&str],
) -> core::fmt::Result {
formatter.write_str("[")?;
let mut index = 0;
while index < features.len() {
if index != 0 {
formatter.write_str(",")?;
}
formatter.write_str(features[index])?;
index += 1;
}
formatter.write_str("]")
}
#[cfg(feature = "simd")]
fn active_backend() -> Backend {
match super::simd::active_backend() {
super::simd::ActiveBackend::Scalar => Backend::Scalar,
}
}
#[cfg(not(feature = "simd"))]
const fn active_backend() -> Backend {
Backend::Scalar
}
#[cfg(feature = "simd")]
fn detected_candidate() -> Backend {
match super::simd::detected_candidate() {
super::simd::Candidate::Scalar => Backend::Scalar,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
super::simd::Candidate::Avx512Vbmi => Backend::Avx512Vbmi,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
super::simd::Candidate::Avx2 => Backend::Avx2,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
super::simd::Candidate::Ssse3Sse41 => Backend::Ssse3Sse41,
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
super::simd::Candidate::Neon => Backend::Neon,
#[cfg(target_arch = "wasm32")]
super::simd::Candidate::WasmSimd128 => Backend::WasmSimd128,
}
}
#[cfg(not(feature = "simd"))]
const fn detected_candidate() -> Backend {
Backend::Scalar
}
#[cfg(all(
feature = "simd",
feature = "std",
any(target_arch = "x86", target_arch = "x86_64")
))]
const fn candidate_detection_mode() -> CandidateDetectionMode {
CandidateDetectionMode::RuntimeCpuFeatures
}
#[cfg(all(
feature = "simd",
not(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))
))]
const fn candidate_detection_mode() -> CandidateDetectionMode {
CandidateDetectionMode::CompileTimeTargetFeatures
}
#[cfg(not(feature = "simd"))]
const fn candidate_detection_mode() -> CandidateDetectionMode {
CandidateDetectionMode::SimdFeatureDisabled
}