Skip to main content

base64_ng/runtime/
operation.rs

1//! Stable per-operation backend reporting primitives.
2
3use super::Backend;
4
5/// Operation whose backend is being reported.
6#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
7#[non_exhaustive]
8pub enum OperationKind {
9    /// Ordinary Base64 encoding.
10    Encode,
11    /// Ordinary strict Base64 decoding.
12    StrictDecode,
13    /// Secret, fixed-work, constant-time-oriented decoding.
14    SecretDecode,
15}
16
17impl OperationKind {
18    /// Returns the stable operation identifier.
19    #[must_use]
20    pub const fn as_str(self) -> &'static str {
21        match self {
22            Self::Encode => "encode",
23            Self::StrictDecode => "strict-decode",
24            Self::SecretDecode => "secret-decode",
25        }
26    }
27}
28
29/// Opaque stable identifier for one operation backend.
30///
31/// Values are created by `base64-ng`; callers can log or compare the stable
32/// string without assuming that future backends extend a public enum.
33#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
34pub struct BackendIdentifier(&'static str);
35
36impl BackendIdentifier {
37    pub(crate) const SCALAR_CT_ORIENTED: Self = Self("scalar-constant-time-oriented");
38
39    pub(crate) const fn ordinary(backend: Backend) -> Self {
40        Self(backend.as_str())
41    }
42
43    /// Returns the stable lowercase identifier.
44    #[must_use]
45    pub const fn as_str(self) -> &'static str {
46        self.0
47    }
48}
49
50impl core::fmt::Display for BackendIdentifier {
51    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52        formatter.write_str(self.0)
53    }
54}
55
56/// Security classification of one operation backend.
57#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
58#[non_exhaustive]
59pub enum OperationSecurityPosture {
60    /// Ordinary scalar processing; no secret timing claim.
61    OrdinaryScalar,
62    /// Ordinary accelerated processing; no secret timing claim.
63    OrdinaryAccelerated,
64    /// Scalar fixed-work, constant-time-oriented secret processing.
65    ScalarConstantTimeOriented,
66}
67
68impl OperationSecurityPosture {
69    /// Returns the stable posture identifier.
70    #[must_use]
71    pub const fn as_str(self) -> &'static str {
72        match self {
73            Self::OrdinaryScalar => "ordinary-scalar",
74            Self::OrdinaryAccelerated => "ordinary-accelerated",
75            Self::ScalarConstantTimeOriented => "scalar-constant-time-oriented",
76        }
77    }
78}
79
80/// Current ordinary backend-health evidence.
81#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
82#[non_exhaustive]
83pub enum BackendHealthPosture {
84    /// Scalar execution has no accelerated implementation to self-test.
85    ScalarFixed,
86    /// The selected candidate has not completed its known-answer test.
87    NeverRun,
88    /// A thread is currently running the candidate's known-answer test.
89    Testing,
90    /// The candidate passed its known-answer test.
91    Healthy,
92    /// The candidate failed an integrity check and is permanently disabled.
93    Quarantined,
94    /// This target cannot provide the atomic health latch required for SIMD.
95    SynchronizationUnavailable,
96    /// The secret scalar boundary is fixed by policy rather than selected by
97    /// ordinary SIMD dispatch.
98    SecretPolicyFixed,
99}
100
101impl BackendHealthPosture {
102    /// Returns the stable health identifier.
103    #[must_use]
104    pub const fn as_str(self) -> &'static str {
105        match self {
106            Self::ScalarFixed => "scalar-fixed",
107            Self::NeverRun => "never-run",
108            Self::Testing => "testing",
109            Self::Healthy => "healthy",
110            Self::Quarantined => "quarantined",
111            Self::SynchronizationUnavailable => "synchronization-unavailable",
112            Self::SecretPolicyFixed => "secret-policy-fixed",
113        }
114    }
115}
116
117/// Wasm artifact selection posture.
118#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
119#[non_exhaustive]
120pub enum WasmArtifactPosture {
121    /// The current target is not Wasm.
122    NotWasm,
123    /// A scalar Wasm artifact was selected.
124    ScalarArtifact,
125    /// A `simd128` Wasm artifact was selected at compile time.
126    Simd128Artifact,
127}
128
129impl WasmArtifactPosture {
130    /// Returns the stable artifact identifier.
131    #[must_use]
132    pub const fn as_str(self) -> &'static str {
133        match self {
134            Self::NotWasm => "not-wasm",
135            Self::ScalarArtifact => "wasm-scalar-artifact",
136            Self::Simd128Artifact => "wasm-simd128-artifact",
137        }
138    }
139}
140
141/// Wasm host-runtime identification posture.
142#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
143#[non_exhaustive]
144pub enum WasmRuntimePosture {
145    /// The current target is not Wasm.
146    NotWasm,
147    /// The guest cannot authenticate which host runtime/JIT selected it.
148    HostRuntimeUnidentified,
149}
150
151impl WasmRuntimePosture {
152    /// Returns the stable runtime identifier.
153    #[must_use]
154    pub const fn as_str(self) -> &'static str {
155        match self {
156            Self::NotWasm => "not-wasm",
157            Self::HostRuntimeUnidentified => "wasm-host-runtime-unidentified",
158        }
159    }
160}
161
162/// Selected backend and posture for one operation family.
163#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
164pub struct OperationBackendReport {
165    /// Operation family.
166    pub operation: OperationKind,
167    /// Opaque stable backend identifier.
168    pub backend: BackendIdentifier,
169    /// Security classification for this operation only.
170    pub security_posture: OperationSecurityPosture,
171    /// Honest current backend-health posture.
172    pub health_posture: BackendHealthPosture,
173    /// Context-independent admission generation.
174    ///
175    /// This generation is not an `AssuranceContext` generation.
176    /// Allocation-gated reports carry those values separately.
177    pub health_generation: usize,
178    /// Last backend integrity fault, if this operation was quarantined.
179    pub backend_fault: Option<crate::BackendFault>,
180}
181
182impl OperationBackendReport {
183    pub(crate) fn ordinary(operation: OperationKind, backend: Backend, candidate: Backend) -> Self {
184        let security_posture = if matches!(backend, Backend::Scalar) {
185            OperationSecurityPosture::OrdinaryScalar
186        } else {
187            OperationSecurityPosture::OrdinaryAccelerated
188        };
189        let health = crate::v2::backend_health::snapshot(operation, candidate);
190        let health_posture = if candidate == Backend::Scalar {
191            BackendHealthPosture::ScalarFixed
192        } else {
193            match health.state {
194                crate::BackendHealthState::NeverRun => {
195                    if cfg!(target_has_atomic = "ptr") {
196                        BackendHealthPosture::NeverRun
197                    } else {
198                        BackendHealthPosture::SynchronizationUnavailable
199                    }
200                }
201                crate::BackendHealthState::Testing => BackendHealthPosture::Testing,
202                crate::BackendHealthState::Healthy => BackendHealthPosture::Healthy,
203                crate::BackendHealthState::Quarantined => BackendHealthPosture::Quarantined,
204            }
205        };
206        Self {
207            operation,
208            backend: BackendIdentifier::ordinary(backend),
209            security_posture,
210            health_posture,
211            health_generation: health.generation,
212            backend_fault: health.fault,
213        }
214    }
215
216    pub(crate) const fn secret_decode() -> Self {
217        Self {
218            operation: OperationKind::SecretDecode,
219            backend: BackendIdentifier::SCALAR_CT_ORIENTED,
220            security_posture: OperationSecurityPosture::ScalarConstantTimeOriented,
221            health_posture: BackendHealthPosture::SecretPolicyFixed,
222            health_generation: 1,
223            backend_fault: None,
224        }
225    }
226
227    /// Returns a stable structured snapshot.
228    #[must_use]
229    pub const fn snapshot(self) -> OperationBackendSnapshot {
230        OperationBackendSnapshot {
231            operation: self.operation.as_str(),
232            backend: self.backend.as_str(),
233            security_posture: self.security_posture.as_str(),
234            health_posture: self.health_posture.as_str(),
235            health_generation: self.health_generation,
236            backend_fault: match self.backend_fault {
237                Some(fault) => Some(fault.as_str()),
238                None => None,
239            },
240        }
241    }
242}
243
244/// Stable logging snapshot for one operation backend.
245#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
246pub struct OperationBackendSnapshot {
247    /// Stable operation identifier.
248    pub operation: &'static str,
249    /// Stable opaque backend identifier.
250    pub backend: &'static str,
251    /// Stable operation-security identifier.
252    pub security_posture: &'static str,
253    /// Stable backend-health identifier.
254    pub health_posture: &'static str,
255    /// Backend-health generation.
256    pub health_generation: usize,
257    /// Stable last backend-fault identifier.
258    pub backend_fault: Option<&'static str>,
259}
260
261pub(crate) const fn wasm_artifact_posture() -> WasmArtifactPosture {
262    #[cfg(all(feature = "simd", target_arch = "wasm32"))]
263    if crate::simd::wasm_simd128_artifact_selected() {
264        return WasmArtifactPosture::Simd128Artifact;
265    }
266    if cfg!(target_arch = "wasm32") {
267        WasmArtifactPosture::ScalarArtifact
268    } else {
269        WasmArtifactPosture::NotWasm
270    }
271}
272
273pub(crate) const fn wasm_runtime_posture() -> WasmRuntimePosture {
274    if cfg!(target_arch = "wasm32") {
275        WasmRuntimePosture::HostRuntimeUnidentified
276    } else {
277        WasmRuntimePosture::NotWasm
278    }
279}