use super::{
Backend, BackendHealthPosture, BackendPolicy, CandidateDetectionMode, CtGatePosture,
MemoryLockPosture, OperationBackendReport, OperationKind, OperationSecurityPosture,
SecurityPosture, WasmArtifactPosture, WasmRuntimePosture, WipePosture,
operation::{wasm_artifact_posture, wasm_runtime_posture},
};
#[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)]
#[allow(clippy::struct_excessive_bools)]
pub struct BackendReport {
pub active: Backend,
pub accelerated_backend_active: bool,
pub security_posture: SecurityPosture,
pub encode_backend: OperationBackendReport,
pub strict_decode_backend: OperationBackendReport,
pub secret_decode_backend: OperationBackendReport,
pub candidate: Backend,
pub candidate_detection_mode: CandidateDetectionMode,
pub simd_feature_enabled: bool,
pub ordinary_acceleration_active: bool,
pub unsafe_boundary_enforced: bool,
pub wasm_artifact_posture: WasmArtifactPosture,
pub wasm_runtime_posture: WasmRuntimePosture,
pub wipe_posture: WipePosture,
pub ct_gate_posture: CtGatePosture,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[allow(clippy::struct_excessive_bools)]
pub struct BackendSnapshot {
pub active: &'static str,
pub accelerated_backend_active: bool,
pub security_posture: &'static str,
pub encode_backend: super::OperationBackendSnapshot,
pub strict_decode_backend: super::OperationBackendSnapshot,
pub secret_decode_backend: super::OperationBackendSnapshot,
pub candidate: &'static str,
pub candidate_detection_mode: &'static str,
pub candidate_required_cpu_features: &'static [&'static str],
pub simd_feature_enabled: bool,
pub ordinary_acceleration_active: bool,
pub unsafe_boundary_enforced: bool,
pub wasm_artifact_posture: &'static str,
pub wasm_runtime_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={} accelerated_backend_active={} security_posture={} encode_backend={} strict_decode_backend={} secret_decode_backend={} candidate={} candidate_detection_mode={} candidate_required_cpu_features=",
self.active,
self.accelerated_backend_active,
self.security_posture,
self.encode_backend.backend,
self.strict_decode_backend.backend,
self.secret_decode_backend.backend,
self.candidate,
self.candidate_detection_mode,
)?;
write_feature_list(formatter, self.candidate_required_cpu_features())?;
write!(
formatter,
" simd_feature_enabled={} ordinary_acceleration_active={} unsafe_boundary_enforced={} wasm_artifact_posture={} wasm_runtime_posture={} wipe_posture={} ct_gate_posture={}",
self.simd_feature_enabled,
self.ordinary_acceleration_active,
self.unsafe_boundary_enforced,
self.wasm_artifact_posture.as_str(),
self.wasm_runtime_posture.as_str(),
self.wipe_posture,
self.ct_gate_posture,
)
}
}
impl BackendReport {
#[must_use]
pub const fn satisfies(self, policy: BackendPolicy) -> bool {
match policy {
BackendPolicy::ScalarExecutionOnly => {
stably_scalar(self.encode_backend)
&& stably_scalar(self.strict_decode_backend)
&& !self.ordinary_acceleration_active
}
BackendPolicy::SimdFeatureDisabled => !self.simd_feature_enabled,
BackendPolicy::NoDetectedSimdCandidate => matches!(self.candidate, Backend::Scalar),
BackendPolicy::HighAssuranceScalarOnly => {
matches!(
self.encode_backend.security_posture,
OperationSecurityPosture::OrdinaryScalar
) && matches!(
self.strict_decode_backend.security_posture,
OperationSecurityPosture::OrdinaryScalar
) && matches!(
self.secret_decode_backend.security_posture,
OperationSecurityPosture::ScalarConstantTimeOriented
) && matches!(self.candidate, Backend::Scalar)
&& !self.simd_feature_enabled
&& !self.ordinary_acceleration_active
&& self.unsafe_boundary_enforced
&& matches!(
self.ct_gate_posture,
CtGatePosture::HardwareSpeculationBarrier
| CtGatePosture::HardwareSpeculationBarrierBuildAsserted
)
}
}
}
#[must_use]
pub const fn candidate_required_cpu_features(self) -> &'static [&'static str] {
self.candidate.required_cpu_features()
}
#[must_use]
pub fn active_decode_backend(self) -> Backend {
let _ = self;
active_decode_backend()
}
#[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(),
accelerated_backend_active: self.accelerated_backend_active,
security_posture: self.security_posture.as_str(),
encode_backend: self.encode_backend.snapshot(),
strict_decode_backend: self.strict_decode_backend.snapshot(),
secret_decode_backend: self.secret_decode_backend.snapshot(),
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,
ordinary_acceleration_active: self.ordinary_acceleration_active,
unsafe_boundary_enforced: self.unsafe_boundary_enforced,
wasm_artifact_posture: self.wasm_artifact_posture.as_str(),
wasm_runtime_posture: self.wasm_runtime_posture.as_str(),
wipe_posture: self.wipe_posture.as_str(),
ct_gate_posture: self.ct_gate_posture.as_str(),
}
}
}
const fn stably_scalar(report: OperationBackendReport) -> bool {
matches!(
report.security_posture,
OperationSecurityPosture::OrdinaryScalar
) && matches!(
report.health_posture,
BackendHealthPosture::ScalarFixed
| BackendHealthPosture::Quarantined
| BackendHealthPosture::SynchronizationUnavailable
)
}
#[must_use]
pub fn backend_report() -> BackendReport {
let encode = active_backend();
let strict_decode = active_decode_backend();
let encode_candidate = encode_candidate_backend();
let decode_candidate = decode_candidate_backend();
let candidate = detected_candidate();
let candidate_detection_mode = candidate_detection_mode();
let accelerated_backend_active = encode != Backend::Scalar;
let ordinary_acceleration_active =
encode != Backend::Scalar || strict_decode != Backend::Scalar;
let unsafe_boundary_enforced = !cfg!(feature = "simd");
let security_posture = if accelerated_backend_active {
SecurityPosture::Accelerated
} else if candidate == Backend::Scalar {
SecurityPosture::ScalarOnly
} else {
SecurityPosture::SimdCandidateScalarActive
};
BackendReport {
active: encode,
accelerated_backend_active,
security_posture,
encode_backend: OperationBackendReport::ordinary(
OperationKind::Encode,
encode,
encode_candidate,
),
strict_decode_backend: OperationBackendReport::ordinary(
OperationKind::StrictDecode,
strict_decode,
decode_candidate,
),
secret_decode_backend: OperationBackendReport::secret_decode(),
candidate,
candidate_detection_mode,
simd_feature_enabled: cfg!(feature = "simd"),
ordinary_acceleration_active,
unsafe_boundary_enforced,
wasm_artifact_posture: wasm_artifact_posture(),
wasm_runtime_posture: wasm_runtime_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")) {
CtGatePosture::HardwareSpeculationBarrier
} else if cfg!(all(
target_arch = "aarch64",
base64_ng_aarch64_csdb_attested
)) {
CtGatePosture::HardwareSpeculationBarrierBuildAsserted
} 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 {
crate::encode_backend::active_encode_backend().reported()
}
#[cfg(not(feature = "simd"))]
const fn active_backend() -> Backend {
Backend::Scalar
}
#[cfg(feature = "simd")]
fn active_decode_backend() -> Backend {
crate::decode_backend::active_decode_backend().reported()
}
#[cfg(not(feature = "simd"))]
const fn active_decode_backend() -> Backend {
Backend::Scalar
}
#[cfg(feature = "simd")]
fn encode_candidate_backend() -> Backend {
crate::encode_backend::candidate_encode_backend().reported()
}
#[cfg(not(feature = "simd"))]
const fn encode_candidate_backend() -> Backend {
Backend::Scalar
}
#[cfg(feature = "simd")]
fn decode_candidate_backend() -> Backend {
crate::decode_backend::candidate_decode_backend().reported()
}
#[cfg(not(feature = "simd"))]
const fn decode_candidate_backend() -> Backend {
Backend::Scalar
}
#[cfg(feature = "simd")]
fn detected_candidate() -> Backend {
match crate::simd::detected_candidate() {
crate::simd::Candidate::Scalar => Backend::Scalar,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
crate::simd::Candidate::Avx512Vbmi => Backend::Avx512Vbmi,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
crate::simd::Candidate::Avx2 => Backend::Avx2,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
crate::simd::Candidate::Ssse3Sse41 => Backend::Ssse3Sse41,
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
crate::simd::Candidate::Neon => Backend::Neon,
#[cfg(target_arch = "wasm32")]
crate::simd::Candidate::WasmSimd128 => Backend::WasmSimd128,
#[cfg(target_arch = "riscv64")]
crate::simd::Candidate::Rvv => Backend::Rvv,
#[cfg(all(target_arch = "aarch64", base64_ng_sve_candidate))]
crate::simd::Candidate::Sve => Backend::Sve,
}
}
#[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",
all(target_arch = "aarch64", base64_ng_sve_candidate),
target_arch = "riscv64"
)
))]
const fn candidate_detection_mode() -> CandidateDetectionMode {
CandidateDetectionMode::RuntimeCpuFeatures
}
#[cfg(all(
feature = "simd",
not(all(
feature = "std",
any(
target_arch = "x86",
target_arch = "x86_64",
all(target_arch = "aarch64", base64_ng_sve_candidate),
target_arch = "riscv64"
)
))
))]
const fn candidate_detection_mode() -> CandidateDetectionMode {
CandidateDetectionMode::CompileTimeTargetFeatures
}
#[cfg(not(feature = "simd"))]
const fn candidate_detection_mode() -> CandidateDetectionMode {
CandidateDetectionMode::SimdFeatureDisabled
}