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