Skip to main content

walletkit_core/flamingo/
errors.rs

1use flamingo_verifier_sealed_types::{
2    ComparisonRole, FailureReason, ImageFailureReason, ImageRole,
3};
4use thiserror::Error;
5
6/// A rejection reported inside encryption; not a signed statement.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)]
8pub enum FlamingoMatchRejection {
9    /// Malformed encrypted request.
10    MalformedInputs,
11    /// Invalid PCP hashes file.
12    InvalidHashesJson,
13    /// Orb image did not match its PCP commitment.
14    ThumbnailHashMismatch,
15    /// Threshold was not a finite normalized cosine value.
16    InvalidThreshold,
17    /// An image was empty.
18    EmptyImage,
19    /// An image or total input exceeded the limit.
20    InputTooLarge,
21    /// Legacy rejection retained for binding compatibility; current verifiers support all captures.
22    UnsupportedCapture,
23    /// Legacy rejection retained for binding compatibility; current verifiers support all operations.
24    UnsupportedOperation,
25    /// A comparison did not meet the threshold.
26    MatchBelowThreshold {
27        /// The comparison that failed.
28        comparison: FlamingoComparison,
29    },
30    /// A named image could not pass analysis.
31    ImageRejected {
32        /// Image bytes or semantic image role.
33        image: FlamingoImageRole,
34        /// Approved validation reason.
35        reason: FlamingoImageFailureReason,
36    },
37    /// A named comparison failed.
38    MatchingFailed {
39        /// The comparison that failed.
40        comparison: FlamingoComparison,
41    },
42    /// An infrastructure failure, not a biological rejection.
43    Internal,
44}
45/// Comparison names match the worker protocol.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)]
47pub enum FlamingoComparison {
48    /// Orb credential versus live selfie.
49    OrbSelfie,
50    /// Orb credential versus RTMS challenge.
51    OrbChallenge,
52    /// Live selfie versus RTMS challenge.
53    SelfieChallenge,
54}
55/// Image roles match the worker protocol.
56#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)]
57pub enum FlamingoImageRole {
58    /// Orb credential image.
59    OrbCredential,
60    /// Live capture.
61    LiveSelfie,
62    /// RTMS challenge image.
63    RtmsChallenge,
64}
65/// Failures while configuring or performing a match request.
66#[derive(Debug, Error, uniffi::Error)]
67pub enum FlamingoError {
68    /// A caller-supplied value cannot form a valid match request.
69    #[error("invalid {attribute}: {reason}")]
70    InvalidInput {
71        /// Name of the invalid field.
72        attribute: String,
73        /// Why the value was rejected.
74        reason: String,
75    },
76    /// The verifier configuration was not valid.
77    #[error("invalid Flamingo verifier configuration: {0}")]
78    Configuration(String),
79    /// Assignment, attestation, transport, channel opening, or token verification failed.
80    #[error("Flamingo verifier request failed: {0}")]
81    Verifier(String),
82}
83
84impl From<FailureReason> for FlamingoMatchRejection {
85    fn from(value: FailureReason) -> Self {
86        match value {
87            FailureReason::MalformedInputs => Self::MalformedInputs,
88            FailureReason::InvalidHashesJson => Self::InvalidHashesJson,
89            FailureReason::ThumbnailHashMismatch => Self::ThumbnailHashMismatch,
90            FailureReason::InvalidThreshold => Self::InvalidThreshold,
91            FailureReason::EmptyImage => Self::EmptyImage,
92            FailureReason::InputTooLarge => Self::InputTooLarge,
93            FailureReason::Internal => Self::Internal,
94            FailureReason::MatchBelowThreshold(comparison) => {
95                Self::MatchBelowThreshold {
96                    comparison: comparison.into(),
97                }
98            }
99            FailureReason::MatchingFailed(comparison) => Self::MatchingFailed {
100                comparison: comparison.into(),
101            },
102            FailureReason::ImageRejected { image, reason } => Self::ImageRejected {
103                image: image.into(),
104                reason: reason.into(),
105            },
106        }
107    }
108}
109impl From<ComparisonRole> for FlamingoComparison {
110    fn from(value: ComparisonRole) -> Self {
111        match value {
112            ComparisonRole::OrbSelfie => Self::OrbSelfie,
113            ComparisonRole::OrbChallenge => Self::OrbChallenge,
114            ComparisonRole::SelfieChallenge => Self::SelfieChallenge,
115        }
116    }
117}
118impl From<ImageRole> for FlamingoImageRole {
119    fn from(value: ImageRole) -> Self {
120        match value {
121            ImageRole::OrbCredential => Self::OrbCredential,
122            ImageRole::LiveSelfie => Self::LiveSelfie,
123            ImageRole::RtmsChallenge => Self::RtmsChallenge,
124        }
125    }
126}
127/// Image rejection reasons, without raw engine diagnostics.
128#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)]
129pub enum FlamingoImageFailureReason {
130    /// Image decoding or dimension validation failed.
131    InvalidImage,
132    /// Embedding generation failed.
133    TemplateFailed,
134    /// Too many faces.
135    TooManyFaces,
136    /// Image too dark.
137    ImageTooDark,
138    /// Image too bright.
139    ImageTooBright,
140    /// Illumination variance.
141    IlluminationVariance,
142    /// Face too small.
143    FaceTooSmall,
144    /// Face too big.
145    FaceTooBig,
146    /// Face resolution too low.
147    FaceResolutionTooLow,
148    /// Face too high.
149    FaceTooHigh,
150    /// Face too low.
151    FaceTooLow,
152    /// Face too far left.
153    FaceTooFarLeft,
154    /// Face too far right.
155    FaceTooFarRight,
156    /// Head pose yaw.
157    HeadPoseYaw,
158    /// Head pose pitch too high.
159    HeadPosePitchTooHigh,
160    /// Head pose pitch too low.
161    HeadPosePitchTooLow,
162    /// Head pose roll.
163    HeadPoseRoll,
164    /// Low quality.
165    LowQuality,
166    /// Sunglasses occlusion detected.
167    SunglassesOcclusionDetected,
168    /// Glasses occlusion detected.
169    GlassesOcclusionDetected,
170    /// Mask occlusion detected.
171    MaskOcclusionDetected,
172    /// Other occlusion detected.
173    OtherOcclusionDetected,
174    /// Hair occlusion detected.
175    HairOcclusionDetected,
176    /// Fas occlusion detected.
177    FasOcclusionDetected,
178    /// Spoof detected.
179    SpoofDetected,
180    /// Depth spoof detected.
181    DepthSpoofDetected,
182    /// Thermal spoof detected.
183    ThermalSpoofDetected,
184    /// Age below threshold.
185    AgeBelowThreshold,
186    /// No face detected.
187    NoFaceDetected,
188    /// Eyes closed.
189    EyesClosed,
190    /// Non neutral expression.
191    NonNeutralExpression,
192    /// Landmarks alignment.
193    LandmarksAlignment,
194    /// Face overexposed.
195    FaceOverexposed,
196    /// Face underexposed.
197    FaceUnderexposed,
198    /// Segmentation occlusion proportion.
199    SegmentationOcclusionProportion,
200    /// Bright artifacts.
201    BrightArtifacts,
202    /// Light guard score too low.
203    LightGuardScoreTooLow,
204    /// Low contrast.
205    LowContrast,
206    /// Mesh expression score.
207    MeshExpressionScore,
208    /// High color distortion.
209    HighColorDistortion,
210    /// Uneven lighting.
211    UnevenLighting,
212    /// Blurry face.
213    BlurryFace,
214    /// Noisy thermal image.
215    NoisyThermalImage,
216}
217impl From<ImageFailureReason> for FlamingoImageFailureReason {
218    fn from(value: ImageFailureReason) -> Self {
219        match value {
220            ImageFailureReason::InvalidImage => Self::InvalidImage,
221            ImageFailureReason::TemplateFailed => Self::TemplateFailed,
222            ImageFailureReason::TooManyFaces => Self::TooManyFaces,
223            ImageFailureReason::ImageTooDark => Self::ImageTooDark,
224            ImageFailureReason::ImageTooBright => Self::ImageTooBright,
225            ImageFailureReason::IlluminationVariance => Self::IlluminationVariance,
226            ImageFailureReason::FaceTooSmall => Self::FaceTooSmall,
227            ImageFailureReason::FaceTooBig => Self::FaceTooBig,
228            ImageFailureReason::FaceResolutionTooLow => Self::FaceResolutionTooLow,
229            ImageFailureReason::FaceTooHigh => Self::FaceTooHigh,
230            ImageFailureReason::FaceTooLow => Self::FaceTooLow,
231            ImageFailureReason::FaceTooFarLeft => Self::FaceTooFarLeft,
232            ImageFailureReason::FaceTooFarRight => Self::FaceTooFarRight,
233            ImageFailureReason::HeadPoseYaw => Self::HeadPoseYaw,
234            ImageFailureReason::HeadPosePitchTooHigh => Self::HeadPosePitchTooHigh,
235            ImageFailureReason::HeadPosePitchTooLow => Self::HeadPosePitchTooLow,
236            ImageFailureReason::HeadPoseRoll => Self::HeadPoseRoll,
237            ImageFailureReason::LowQuality => Self::LowQuality,
238            ImageFailureReason::SunglassesOcclusionDetected => {
239                Self::SunglassesOcclusionDetected
240            }
241            ImageFailureReason::GlassesOcclusionDetected => {
242                Self::GlassesOcclusionDetected
243            }
244            ImageFailureReason::MaskOcclusionDetected => Self::MaskOcclusionDetected,
245            ImageFailureReason::OtherOcclusionDetected => Self::OtherOcclusionDetected,
246            ImageFailureReason::HairOcclusionDetected => Self::HairOcclusionDetected,
247            ImageFailureReason::FasOcclusionDetected => Self::FasOcclusionDetected,
248            ImageFailureReason::SpoofDetected => Self::SpoofDetected,
249            ImageFailureReason::DepthSpoofDetected => Self::DepthSpoofDetected,
250            ImageFailureReason::ThermalSpoofDetected => Self::ThermalSpoofDetected,
251            ImageFailureReason::AgeBelowThreshold => Self::AgeBelowThreshold,
252            ImageFailureReason::NoFaceDetected => Self::NoFaceDetected,
253            ImageFailureReason::EyesClosed => Self::EyesClosed,
254            ImageFailureReason::NonNeutralExpression => Self::NonNeutralExpression,
255            ImageFailureReason::LandmarksAlignment => Self::LandmarksAlignment,
256            ImageFailureReason::FaceOverexposed => Self::FaceOverexposed,
257            ImageFailureReason::FaceUnderexposed => Self::FaceUnderexposed,
258            ImageFailureReason::SegmentationOcclusionProportion => {
259                Self::SegmentationOcclusionProportion
260            }
261            ImageFailureReason::BrightArtifacts => Self::BrightArtifacts,
262            ImageFailureReason::LightGuardScoreTooLow => Self::LightGuardScoreTooLow,
263            ImageFailureReason::LowContrast => Self::LowContrast,
264            ImageFailureReason::MeshExpressionScore => Self::MeshExpressionScore,
265            ImageFailureReason::HighColorDistortion => Self::HighColorDistortion,
266            ImageFailureReason::UnevenLighting => Self::UnevenLighting,
267            ImageFailureReason::BlurryFace => Self::BlurryFace,
268            ImageFailureReason::NoisyThermalImage => Self::NoisyThermalImage,
269        }
270    }
271}