Skip to main content

base64_ng/runtime/
mod.rs

1//! Runtime backend reporting for security-sensitive deployments.
2//!
3//! This module exposes backend posture so callers can log, assert, or audit
4//! whether execution is scalar-only, using an admitted encode backend, or
5//! merely detecting future SIMD candidates.
6
7/// A backend that can be reported by `base64-ng`.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9#[non_exhaustive]
10pub enum Backend {
11    /// The audited scalar backend.
12    Scalar,
13    /// An AVX-512 VBMI candidate was detected.
14    Avx512Vbmi,
15    /// An AVX2 candidate was detected.
16    Avx2,
17    /// An SSSE3/SSE4.1 candidate was detected.
18    Ssse3Sse41,
19    /// An ARM NEON candidate was detected.
20    Neon,
21    /// A wasm `simd128` candidate was detected.
22    WasmSimd128,
23    /// RVV 1.0 was detected.
24    ///
25    /// Production execution is restricted to the measured Linux `SpacemiT` X60
26    /// profile; broader project-owned builds report RVV only as a candidate.
27    Rvv,
28    /// An `AArch64` SVE candidate was detected.
29    ///
30    /// The 2.0 development branch reports this only from the internal
31    /// project-owned candidate build. Production dispatch remains on admitted
32    /// NEON or scalar until native-hardware admission evidence is accepted.
33    Sve,
34}
35
36impl Backend {
37    /// Returns the stable lowercase identifier for this backend.
38    ///
39    /// ```
40    /// assert_eq!(base64_ng::runtime::Backend::Scalar.as_str(), "scalar");
41    /// ```
42    #[must_use]
43    pub const fn as_str(self) -> &'static str {
44        match self {
45            Self::Scalar => "scalar",
46            Self::Avx512Vbmi => "avx512-vbmi",
47            Self::Avx2 => "avx2",
48            Self::Ssse3Sse41 => "ssse3-sse4.1",
49            Self::Neon => "neon",
50            Self::WasmSimd128 => "wasm-simd128",
51            Self::Rvv => "rvv",
52            Self::Sve => "sve",
53        }
54    }
55
56    /// Returns the CPU features required before this backend may be used.
57    ///
58    /// Security logs can record exactly which CPU feature bundle is required by
59    /// an active backend or visible candidate.
60    ///
61    /// ```
62    /// assert_eq!(
63    ///     base64_ng::runtime::Backend::Avx512Vbmi.required_cpu_features(),
64    ///     ["avx512f", "avx512bw", "avx512vl", "avx512vbmi"],
65    /// );
66    /// ```
67    #[must_use]
68    pub const fn required_cpu_features(self) -> &'static [&'static str] {
69        match self {
70            Self::Scalar => &[],
71            Self::Avx512Vbmi => &["avx512f", "avx512bw", "avx512vl", "avx512vbmi"],
72            Self::Avx2 => &["avx2"],
73            Self::Ssse3Sse41 => &["ssse3", "sse4.1"],
74            Self::Neon => &["neon"],
75            Self::WasmSimd128 => &["simd128"],
76            Self::Rvv => &["v"],
77            Self::Sve => &["sve"],
78        }
79    }
80}
81
82impl core::fmt::Display for Backend {
83    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        formatter.write_str(self.as_str())
85    }
86}
87
88/// How SIMD backend candidates were detected for this build.
89#[derive(Clone, Copy, Debug, Eq, PartialEq)]
90#[non_exhaustive]
91pub enum CandidateDetectionMode {
92    /// SIMD candidate detection is disabled because the `simd` feature is
93    /// not enabled.
94    SimdFeatureDisabled,
95    /// Candidate detection uses runtime CPU feature probing.
96    RuntimeCpuFeatures,
97    /// Candidate detection uses compile-time target features.
98    ///
99    /// This mode does not prove that the deployment CPU has the reported
100    /// feature; it only reflects how the binary was compiled.
101    CompileTimeTargetFeatures,
102}
103
104impl CandidateDetectionMode {
105    /// Returns the stable lowercase identifier for this detection mode.
106    ///
107    /// ```
108    /// assert_eq!(
109    ///     base64_ng::runtime::CandidateDetectionMode::SimdFeatureDisabled.as_str(),
110    ///     "simd-feature-disabled",
111    /// );
112    /// ```
113    #[must_use]
114    pub const fn as_str(self) -> &'static str {
115        match self {
116            Self::SimdFeatureDisabled => "simd-feature-disabled",
117            Self::RuntimeCpuFeatures => "runtime-cpu-features",
118            Self::CompileTimeTargetFeatures => "compile-time-target-features",
119        }
120    }
121}
122
123impl core::fmt::Display for CandidateDetectionMode {
124    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125        formatter.write_str(self.as_str())
126    }
127}
128
129/// Security posture for the active runtime backend.
130#[derive(Clone, Copy, Debug, Eq, PartialEq)]
131#[non_exhaustive]
132pub enum SecurityPosture {
133    /// No accelerated backend is active.
134    ScalarOnly,
135    /// SIMD support may be detected, but execution still uses scalar.
136    SimdCandidateScalarActive,
137    /// A SIMD backend is active.
138    Accelerated,
139}
140
141impl SecurityPosture {
142    /// Returns the stable lowercase identifier for this security posture.
143    ///
144    /// ```
145    /// assert_eq!(
146    ///     base64_ng::runtime::SecurityPosture::ScalarOnly.as_str(),
147    ///     "scalar-only",
148    /// );
149    /// ```
150    #[must_use]
151    pub const fn as_str(self) -> &'static str {
152        match self {
153            Self::ScalarOnly => "scalar-only",
154            Self::SimdCandidateScalarActive => "simd-candidate-scalar-active",
155            Self::Accelerated => "accelerated",
156        }
157    }
158}
159
160impl core::fmt::Display for SecurityPosture {
161    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
162        formatter.write_str(self.as_str())
163    }
164}
165
166/// Wipe-barrier posture for this build and target.
167#[derive(Clone, Copy, Debug, Eq, PartialEq)]
168#[non_exhaustive]
169pub enum WipePosture {
170    /// The target uses a native store-ordering hardware fence in addition
171    /// to volatile writes and compiler fences.
172    ///
173    /// This describes wipe-store ordering only. It is separate from
174    /// [`CtGatePosture`], which reports whether the constant-time result
175    /// gate has a speculation barrier or only an ordering fence.
176    HardwareFence,
177    /// The target uses volatile writes and compiler fences only.
178    CompilerFenceOnly,
179}
180
181impl WipePosture {
182    /// Returns the stable lowercase identifier for this wipe posture.
183    #[must_use]
184    pub const fn as_str(self) -> &'static str {
185        match self {
186            Self::HardwareFence => "hardware-fence",
187            Self::CompilerFenceOnly => "compiler-fence-only",
188        }
189    }
190}
191
192impl core::fmt::Display for WipePosture {
193    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194        formatter.write_str(self.as_str())
195    }
196}
197
198/// Constant-time result-gate barrier posture for this build and target.
199#[derive(Clone, Copy, Debug, Eq, PartialEq)]
200#[non_exhaustive]
201pub enum CtGatePosture {
202    /// The target uses a native speculation barrier before public CT
203    /// success/failure or equality-result branches.
204    HardwareSpeculationBarrier,
205    /// The target is treated as having an effective speculation barrier only
206    /// because the build provided an explicit operator attestation cfg.
207    ///
208    /// On `AArch64`, this is reported when the build sets
209    /// `base64_ng_aarch64_csdb_attested`. It remains distinct from
210    /// [`Self::HardwareSpeculationBarrier`] so logs preserve the evidence
211    /// chain instead of making a build assertion look like a native target
212    /// guarantee.
213    HardwareSpeculationBarrierBuildAsserted,
214    /// The target emits a hardware speculation-barrier sequence whose
215    /// effectiveness depends on platform or core-level attestation.
216    ///
217    /// On `AArch64` this uses `isb sy` plus the CSDB hint encoding. Full
218    /// CSDB effectiveness depends on the deployed ARM architecture level;
219    /// older cores may treat the hint as a no-op.
220    HardwareSpeculationBarrierUnattested,
221    /// The target uses an ordering fence where the base ISA does not
222    /// provide a canonical speculation barrier.
223    OrderingFence,
224    /// The target uses compiler fences only.
225    CompilerFenceOnly,
226}
227
228impl CtGatePosture {
229    /// Returns the stable lowercase identifier for this CT gate posture.
230    #[must_use]
231    pub const fn as_str(self) -> &'static str {
232        match self {
233            Self::HardwareSpeculationBarrier => "hardware-speculation-barrier",
234            Self::HardwareSpeculationBarrierBuildAsserted => {
235                "hardware-speculation-barrier-build-asserted"
236            }
237            Self::HardwareSpeculationBarrierUnattested => "hardware-speculation-barrier-unattested",
238            Self::OrderingFence => "ordering-fence",
239            Self::CompilerFenceOnly => "compiler-fence-only",
240        }
241    }
242}
243
244impl core::fmt::Display for CtGatePosture {
245    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
246        formatter.write_str(self.as_str())
247    }
248}
249
250/// Whether this crate locks secret allocations into physical memory.
251#[derive(Clone, Copy, Debug, Eq, PartialEq)]
252#[non_exhaustive]
253pub enum MemoryLockPosture {
254    /// The crate does not lock memory. Deployments that need locked secret
255    /// pages must use platform controls outside `base64-ng`.
256    NotProvided,
257}
258
259impl MemoryLockPosture {
260    /// Returns the stable lowercase identifier for this memory-locking posture.
261    #[must_use]
262    pub const fn as_str(self) -> &'static str {
263        match self {
264            Self::NotProvided => "not-provided",
265        }
266    }
267}
268
269impl core::fmt::Display for MemoryLockPosture {
270    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
271        formatter.write_str(self.as_str())
272    }
273}
274
275/// Deployment policy for runtime backend assertions.
276#[derive(Clone, Copy, Debug, Eq, PartialEq)]
277#[non_exhaustive]
278pub enum BackendPolicy {
279    /// Require encode/decode execution to remain on a terminal scalar backend.
280    ///
281    /// `NeverRun` and `Testing` health states do not satisfy this policy:
282    /// their temporary scalar fallback may later transition to acceleration.
283    ScalarExecutionOnly,
284    /// Require the crate to be built without the `simd` feature.
285    SimdFeatureDisabled,
286    /// Require no SIMD candidate to be visible to this build and target.
287    NoDetectedSimdCandidate,
288    /// Require scalar execution, the `simd` feature disabled, no detected
289    /// SIMD candidate, the unsafe boundary enforced, and a CT result gate
290    /// classified as a native hardware speculation barrier.
291    ///
292    /// This policy intentionally rejects targets that report only an
293    /// unattested hardware barrier, ordering fence, or compiler fence for the
294    /// CT result gate. On `AArch64`, the crate emits `isb sy` plus the CSDB
295    /// hint but reports that posture as unattested; deployments that rely on
296    /// CSDB must carry platform evidence outside this built-in policy check.
297    HighAssuranceScalarOnly,
298}
299
300impl BackendPolicy {
301    /// Returns the stable lowercase identifier for this policy.
302    ///
303    /// ```
304    /// assert_eq!(
305    ///     base64_ng::runtime::BackendPolicy::HighAssuranceScalarOnly.as_str(),
306    ///     "high-assurance-scalar-only",
307    /// );
308    /// ```
309    #[must_use]
310    pub const fn as_str(self) -> &'static str {
311        match self {
312            Self::ScalarExecutionOnly => "scalar-execution-only",
313            Self::SimdFeatureDisabled => "simd-feature-disabled",
314            Self::NoDetectedSimdCandidate => "no-detected-simd-candidate",
315            Self::HighAssuranceScalarOnly => "high-assurance-scalar-only",
316        }
317    }
318}
319
320impl core::fmt::Display for BackendPolicy {
321    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322        formatter.write_str(self.as_str())
323    }
324}
325
326mod operation;
327mod report;
328
329#[cfg(feature = "simd")]
330pub use crate::StaticBackendToken;
331pub use crate::{
332    BackendHealthSnapshot, BackendHealthState, BackendInitializationReport, initialize_backends,
333};
334pub use operation::{
335    BackendHealthPosture, BackendIdentifier, OperationBackendReport, OperationBackendSnapshot,
336    OperationKind, OperationSecurityPosture, WasmArtifactPosture, WasmRuntimePosture,
337};
338pub use report::{
339    BackendPolicyError, BackendReport, BackendSnapshot, backend_report, require_backend_policy,
340};
341
342#[cfg(test)]
343mod tests;