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};