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;