Skip to main content

crypto_core/
error.rs

1// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use thiserror::Error;
6
7/// Backend implementation that performed an AEAD operation.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum AeadBackend {
11    /// Pure-Rust native backend.
12    Native,
13    /// Swift/Apple platform backend.
14    Swift,
15    /// WebAssembly backend.
16    Wasm,
17    /// Kotlin/Android platform backend.
18    Kotlin,
19}
20
21impl core::fmt::Display for AeadBackend {
22    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23        let name = match self {
24            AeadBackend::Native => "native",
25            AeadBackend::Swift => "swift",
26            AeadBackend::Wasm => "wasm",
27            AeadBackend::Kotlin => "kotlin",
28        };
29        write!(f, "{name}")
30    }
31}
32
33/// Specific reason an AEAD encrypt or decrypt operation failed.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[non_exhaustive]
36pub enum AeadFailureKind {
37    /// The supplied key material was not valid for the cipher.
38    InvalidKeyMaterial,
39    /// An input length exceeded the representable range.
40    LengthOverflow,
41    /// The ciphertext was shorter than the authentication tag.
42    ShortCiphertext,
43    /// The backend returned an output of unexpected length.
44    InvalidOutputLength,
45    /// Tag verification failed (ciphertext or AAD tampered/wrong key).
46    AuthenticationFailed,
47    /// The backend reported an unspecified internal failure.
48    BackendFailure,
49}
50
51impl core::fmt::Display for AeadFailureKind {
52    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53        let detail = match self {
54            AeadFailureKind::InvalidKeyMaterial => "invalid key material",
55            AeadFailureKind::LengthOverflow => "length overflow",
56            AeadFailureKind::ShortCiphertext => "ciphertext shorter than tag",
57            AeadFailureKind::InvalidOutputLength => "backend returned invalid output length",
58            AeadFailureKind::AuthenticationFailed => "authentication failed",
59            AeadFailureKind::BackendFailure => "backend failure",
60        };
61        write!(f, "{detail}")
62    }
63}
64
65/// Backend implementation that performed a signature operation.
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[non_exhaustive]
68pub enum SignatureBackend {
69    /// Pure-Rust native backend.
70    Native,
71    /// Swift/Apple platform backend.
72    Swift,
73    /// WebAssembly backend.
74    Wasm,
75    /// Kotlin/Android platform backend.
76    Kotlin,
77    /// Apple Secure Enclave hardware-backed backend.
78    SecureEnclave,
79}
80
81impl core::fmt::Display for SignatureBackend {
82    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83        let name = match self {
84            SignatureBackend::Native => "native",
85            SignatureBackend::Swift => "swift",
86            SignatureBackend::Wasm => "wasm",
87            SignatureBackend::Kotlin => "kotlin",
88            SignatureBackend::SecureEnclave => "secure_enclave",
89        };
90        write!(f, "{name}")
91    }
92}
93
94/// Signature-related operation being attempted when a failure occurred.
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96#[non_exhaustive]
97pub enum SignatureOperation {
98    /// Producing a signature over a message.
99    Sign,
100    /// Verifying a signature against a message.
101    Verify,
102    /// Key generation, import, or other key management.
103    KeyManagement,
104}
105
106impl core::fmt::Display for SignatureOperation {
107    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108        let op = match self {
109            SignatureOperation::Sign => "sign",
110            SignatureOperation::Verify => "verify",
111            SignatureOperation::KeyManagement => "key_management",
112        };
113        write!(f, "{op}")
114    }
115}
116
117/// Specific reason a signature operation failed.
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119#[non_exhaustive]
120pub enum SignatureFailureKind {
121    /// The backend reported an unspecified internal failure.
122    BackendFailure,
123    /// The supplied private key was malformed or invalid.
124    InvalidPrivateKey,
125    /// The supplied public key was malformed or invalid.
126    InvalidPublicKey,
127    /// The signature was malformed or failed verification.
128    InvalidSignature,
129    /// The message input was invalid for the operation.
130    InvalidMessage,
131    /// Key generation did not succeed.
132    KeyGenerationFailed,
133    /// The Secure Enclave was not available on this device.
134    SecureEnclaveUnavailable,
135    /// The Secure Enclave rejected the supplied key.
136    SecureEnclaveRejectedKey,
137}
138
139impl core::fmt::Display for SignatureFailureKind {
140    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
141        let detail = match self {
142            SignatureFailureKind::BackendFailure => "backend failure",
143            SignatureFailureKind::InvalidPrivateKey => "invalid private key",
144            SignatureFailureKind::InvalidPublicKey => "invalid public key",
145            SignatureFailureKind::InvalidSignature => "invalid signature",
146            SignatureFailureKind::InvalidMessage => "invalid message",
147            SignatureFailureKind::KeyGenerationFailed => "key generation failed",
148            SignatureFailureKind::SecureEnclaveUnavailable => "secure enclave unavailable",
149            SignatureFailureKind::SecureEnclaveRejectedKey => "secure enclave rejected key",
150        };
151        write!(f, "{detail}")
152    }
153}
154
155/// Specific reason a key agreement operation failed.
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157#[non_exhaustive]
158pub enum KeyAgreementFailureKind {
159    /// Deriving the shared secret did not succeed.
160    DeriveSharedSecretFailed,
161    /// Key generation did not succeed.
162    KeyGenerationFailed,
163}
164
165impl core::fmt::Display for KeyAgreementFailureKind {
166    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167        let detail = match self {
168            KeyAgreementFailureKind::DeriveSharedSecretFailed => "derive shared secret failed",
169            KeyAgreementFailureKind::KeyGenerationFailed => "key generation failed",
170        };
171        write!(f, "{detail}")
172    }
173}
174
175/// Specific reason a KEM (key encapsulation) operation failed.
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177#[non_exhaustive]
178pub enum KemFailureKind {
179    /// Key generation did not succeed.
180    KeyGenerationFailed,
181    /// Encapsulation did not succeed.
182    EncapsulateFailed,
183    /// Decapsulation did not succeed.
184    DecapsulateFailed,
185}
186
187impl core::fmt::Display for KemFailureKind {
188    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189        let detail = match self {
190            KemFailureKind::KeyGenerationFailed => "key generation failed",
191            KemFailureKind::EncapsulateFailed => "encapsulate failed",
192            KemFailureKind::DecapsulateFailed => "decapsulate failed",
193        };
194        write!(f, "{detail}")
195    }
196}
197
198/// Key-wrapping algorithm identifier.
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200#[non_exhaustive]
201pub enum KeyWrapAlgorithm {
202    /// AES-256 Key Wrap as specified by RFC 3394 / NIST SP 800-38F.
203    Aes256Kw,
204}
205
206impl core::fmt::Display for KeyWrapAlgorithm {
207    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
208        let detail = match self {
209            KeyWrapAlgorithm::Aes256Kw => "AES-256-KW",
210        };
211        write!(f, "{detail}")
212    }
213}
214
215/// Key-wrap operation being attempted when a failure occurred.
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217#[non_exhaustive]
218pub enum KeyWrapOperation {
219    /// Wrapping plaintext key material.
220    Wrap,
221    /// Unwrapping wrapped key material.
222    Unwrap,
223}
224
225impl core::fmt::Display for KeyWrapOperation {
226    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
227        let op = match self {
228            KeyWrapOperation::Wrap => "wrap",
229            KeyWrapOperation::Unwrap => "unwrap",
230        };
231        write!(f, "{op}")
232    }
233}
234
235/// Specific reason a key-wrap operation failed.
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
237#[non_exhaustive]
238pub enum KeyWrapFailureKind {
239    /// The key-encryption key did not have the required length.
240    InvalidKekLength,
241    /// Plaintext key material was too short for RFC 3394 AES-KW.
242    InvalidPlaintextLength,
243    /// Wrapped key material was too short or malformed for RFC 3394 AES-KW.
244    InvalidWrappedLength,
245    /// An input or output length exceeded the representable range.
246    LengthOverflow,
247    /// The wrapped key integrity check failed.
248    IntegrityCheckFailed,
249    /// The backend reported an unspecified internal failure.
250    BackendFailure,
251}
252
253impl core::fmt::Display for KeyWrapFailureKind {
254    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255        let detail = match self {
256            KeyWrapFailureKind::InvalidKekLength => "invalid key-encryption key length",
257            KeyWrapFailureKind::InvalidPlaintextLength => "invalid plaintext key length",
258            KeyWrapFailureKind::InvalidWrappedLength => "invalid wrapped key length",
259            KeyWrapFailureKind::LengthOverflow => "length overflow",
260            KeyWrapFailureKind::IntegrityCheckFailed => "integrity check failed",
261            KeyWrapFailureKind::BackendFailure => "backend failure",
262        };
263        write!(f, "{detail}")
264    }
265}
266
267/// Password-based key derivation algorithm identifier.
268#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269pub enum KdfAlgorithm {
270    /// Argon2id memory-hard KDF.
271    Argon2id,
272    /// PBKDF2 password-based KDF for legacy interop.
273    Pbkdf2,
274    /// NIST Concat KDF as profiled by JOSE/JWA ECDH-ES.
275    ConcatKdf,
276}
277
278impl core::fmt::Display for KdfAlgorithm {
279    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
280        let detail = match self {
281            KdfAlgorithm::Argon2id => "Argon2id",
282            KdfAlgorithm::Pbkdf2 => "PBKDF2",
283            KdfAlgorithm::ConcatKdf => "Concat KDF",
284        };
285        write!(f, "{detail}")
286    }
287}
288
289/// Versioned parameter profile for the KDF.
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291pub enum KdfProfile {
292    /// Argon2id parameter profile version 1.
293    Argon2idV1,
294    /// Argon2id parameter profile version 2.
295    Argon2idV2,
296    /// PBKDF2 using HMAC-SHA-256 as the PRF.
297    Pbkdf2HmacSha256,
298    /// PBKDF2 using HMAC-SHA-512 as the PRF.
299    Pbkdf2HmacSha512,
300    /// JWA ECDH-ES Concat KDF using SHA-256.
301    JwaEcdhEsSha256,
302}
303
304impl core::fmt::Display for KdfProfile {
305    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
306        let detail = match self {
307            KdfProfile::Argon2idV1 => "Argon2id v1",
308            KdfProfile::Argon2idV2 => "Argon2id v2",
309            KdfProfile::Pbkdf2HmacSha256 => "PBKDF2-HMAC-SHA-256",
310            KdfProfile::Pbkdf2HmacSha512 => "PBKDF2-HMAC-SHA-512",
311            KdfProfile::JwaEcdhEsSha256 => "JWA ECDH-ES Concat KDF SHA-256",
312        };
313        write!(f, "{detail}")
314    }
315}
316
317/// Specific reason a KDF operation failed.
318#[derive(Debug, Clone, Copy, PartialEq, Eq)]
319#[non_exhaustive]
320pub enum KdfFailureKind {
321    /// The secret/password input had an unacceptable length.
322    InvalidSecretLength,
323    /// The salt input had an unacceptable length.
324    InvalidSaltLength,
325    /// The requested output length was unacceptable.
326    InvalidOutputLength,
327    /// The iteration count was zero or outside this API's accepted range.
328    InvalidIterationCount,
329    /// The supplied KDF parameters were invalid.
330    InvalidParams,
331    /// The derivation itself did not succeed.
332    DerivationFailed,
333}
334
335impl core::fmt::Display for KdfFailureKind {
336    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
337        let detail = match self {
338            KdfFailureKind::InvalidSecretLength => "invalid secret length",
339            KdfFailureKind::InvalidSaltLength => "invalid salt length",
340            KdfFailureKind::InvalidOutputLength => "invalid output length",
341            KdfFailureKind::InvalidIterationCount => "invalid iteration count",
342            KdfFailureKind::InvalidParams => "invalid parameters",
343            KdfFailureKind::DerivationFailed => "derivation failed",
344        };
345        write!(f, "{detail}")
346    }
347}
348
349/// Hash function underlying an HKDF operation.
350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
351pub enum HkdfHash {
352    /// HKDF using SHA-2-256.
353    Sha2_256,
354    /// HKDF using SHA-3-256.
355    Sha3_256,
356}
357
358impl core::fmt::Display for HkdfHash {
359    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
360        let detail = match self {
361            HkdfHash::Sha2_256 => "SHA2-256",
362            HkdfHash::Sha3_256 => "SHA3-256",
363        };
364        write!(f, "{detail}")
365    }
366}
367
368/// Specific reason an HKDF operation failed.
369#[derive(Debug, Clone, Copy, PartialEq, Eq)]
370#[non_exhaustive]
371pub enum HkdfFailureKind {
372    /// The input key material had an unacceptable length.
373    InvalidIkmLength,
374    /// The domain-separation tag had an unacceptable length.
375    InvalidDomainTagLength,
376    /// The domain-separation tag contained an invalid byte.
377    InvalidDomainTagByte,
378    /// An input length exceeded the representable range.
379    LengthOverflow,
380    /// The requested output length was unacceptable.
381    InvalidOutputLength,
382    /// The HKDF expand step did not succeed.
383    ExpandFailed,
384}
385
386impl core::fmt::Display for HkdfFailureKind {
387    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
388        let detail = match self {
389            HkdfFailureKind::InvalidIkmLength => "invalid input key material length",
390            HkdfFailureKind::InvalidDomainTagLength => "invalid domain tag length",
391            HkdfFailureKind::InvalidDomainTagByte => "invalid domain tag byte",
392            HkdfFailureKind::LengthOverflow => "length overflow",
393            HkdfFailureKind::InvalidOutputLength => "invalid output length",
394            HkdfFailureKind::ExpandFailed => "expand failed",
395        };
396        write!(f, "{detail}")
397    }
398}
399
400/// Hash function underlying an HMAC operation.
401#[derive(Debug, Clone, Copy, PartialEq, Eq)]
402pub enum MacHash {
403    /// HMAC using SHA-256.
404    Sha2_256,
405    /// HMAC using SHA-512.
406    Sha2_512,
407}
408
409impl core::fmt::Display for MacHash {
410    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
411        let detail = match self {
412            MacHash::Sha2_256 => "SHA-256",
413            MacHash::Sha2_512 => "SHA-512",
414        };
415        write!(f, "{detail}")
416    }
417}
418
419/// Specific reason an HMAC operation failed.
420#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421#[non_exhaustive]
422pub enum MacFailureKind {
423    /// The supplied key was empty or exceeded the accepted size limit.
424    InvalidKeyLength,
425    /// The supplied authentication tag length did not match the algorithm.
426    InvalidTagLength,
427    /// Tag verification failed.
428    VerificationFailed,
429    /// The backend reported an unspecified internal failure.
430    BackendFailure,
431}
432
433impl core::fmt::Display for MacFailureKind {
434    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
435        let detail = match self {
436            MacFailureKind::InvalidKeyLength => "invalid key length",
437            MacFailureKind::InvalidTagLength => "invalid tag length",
438            MacFailureKind::VerificationFailed => "verification failed",
439            MacFailureKind::BackendFailure => "backend failure",
440        };
441        write!(f, "{detail}")
442    }
443}
444
445/// Purpose of the random output being generated.
446#[derive(Debug, Clone, Copy, PartialEq, Eq)]
447pub enum RngOutputKind {
448    /// Generic random bytes with no fixed length.
449    Generic,
450    /// A 12-byte AEAD nonce.
451    AeadNonce12,
452    /// A 16-byte Argon2 salt.
453    Argon2Salt16,
454    /// A 32-byte Argon2 salt.
455    Argon2Salt32,
456}
457
458impl core::fmt::Display for RngOutputKind {
459    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
460        let detail = match self {
461            RngOutputKind::Generic => "random bytes",
462            RngOutputKind::AeadNonce12 => "AEAD nonce",
463            RngOutputKind::Argon2Salt16 => "Argon2 16-byte salt",
464            RngOutputKind::Argon2Salt32 => "Argon2 32-byte salt",
465        };
466        write!(f, "{detail}")
467    }
468}
469
470/// Specific reason secure random generation failed.
471#[derive(Debug, Clone, Copy, PartialEq, Eq)]
472#[non_exhaustive]
473pub enum RngFailureKind {
474    /// The system entropy source was unavailable.
475    EntropyUnavailable,
476    /// The requested output length was unacceptable.
477    InvalidOutputLength,
478}
479
480impl core::fmt::Display for RngFailureKind {
481    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
482        let detail = match self {
483            RngFailureKind::EntropyUnavailable => "entropy unavailable",
484            RngFailureKind::InvalidOutputLength => "invalid output length",
485        };
486        write!(f, "{detail}")
487    }
488}
489
490/// Specific reason a constant-time comparison did not match.
491#[derive(Debug, Clone, Copy, PartialEq, Eq)]
492#[non_exhaustive]
493pub enum ConstantTimeFailureKind {
494    /// The two inputs had different lengths.
495    LengthMismatch,
496    /// The two inputs had equal length but unequal contents.
497    NotEqual,
498}
499
500impl core::fmt::Display for ConstantTimeFailureKind {
501    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
502        let detail = match self {
503            ConstantTimeFailureKind::LengthMismatch => "length mismatch",
504            ConstantTimeFailureKind::NotEqual => "not equal",
505        };
506        write!(f, "{detail}")
507    }
508}
509
510/// Typed error taxonomy for all crypto operations in the workspace.
511#[derive(Debug, Error, Clone, PartialEq, Eq)]
512#[non_exhaustive]
513pub enum CryptoError {
514    /// Supplied key material was malformed or otherwise invalid.
515    #[error("invalid key material")]
516    InvalidKey,
517
518    /// An AEAD key did not have the length the cipher requires.
519    #[error("invalid AEAD key length: expected {expected} bytes, got {actual} bytes")]
520    InvalidAeadKeyLength {
521        /// Key length in bytes the cipher requires.
522        expected: usize,
523        /// Key length in bytes that was supplied.
524        actual: usize,
525    },
526
527    /// An AEAD nonce did not have the length the cipher requires.
528    #[error("invalid AEAD nonce length: expected {expected} bytes, got {actual} bytes")]
529    InvalidAeadNonceLength {
530        /// Nonce length in bytes the cipher requires.
531        expected: usize,
532        /// Nonce length in bytes that was supplied.
533        actual: usize,
534    },
535
536    /// A ciphertext was shorter than the minimum (tag) length.
537    #[error("invalid ciphertext length: minimum {minimum} bytes, got {actual} bytes")]
538    InvalidCiphertextLength {
539        /// Minimum ciphertext length in bytes (the authentication tag length).
540        minimum: usize,
541        /// Ciphertext length in bytes that was supplied.
542        actual: usize,
543    },
544
545    /// AEAD encryption failed in the given backend for the given reason.
546    #[error("AEAD encryption failed in {backend} backend: {kind}")]
547    AeadEncrypt {
548        /// Backend lane in which the failure occurred.
549        backend: AeadBackend,
550        /// Specific encryption failure cause.
551        kind: AeadFailureKind,
552    },
553
554    /// AEAD decryption failed in the given backend for the given reason.
555    #[error("AEAD decryption failed in {backend} backend: {kind}")]
556    AeadDecrypt {
557        /// Backend lane in which the failure occurred.
558        backend: AeadBackend,
559        /// Specific decryption failure cause (includes authentication failure).
560        kind: AeadFailureKind,
561    },
562
563    /// A signature operation failed in the given backend for the given reason.
564    #[error("signature failed in {backend} backend during {operation}: {kind}")]
565    Signature {
566        /// Backend lane in which the failure occurred.
567        backend: SignatureBackend,
568        /// Operation (sign, verify, keygen, encode) that failed.
569        operation: SignatureOperation,
570        /// Specific signature failure cause.
571        kind: SignatureFailureKind,
572    },
573
574    /// A key agreement operation failed for the given reason.
575    #[error("key agreement failed: {kind}")]
576    KeyAgreementFailure {
577        /// Specific key-agreement failure cause.
578        kind: KeyAgreementFailureKind,
579    },
580
581    /// A KEM (key encapsulation) operation failed for the given reason.
582    #[error("KEM operation failed: {kind}")]
583    KemFailure {
584        /// Specific KEM failure cause.
585        kind: KemFailureKind,
586    },
587
588    /// A key-wrap operation failed for the given algorithm and reason.
589    #[error("key wrap failed for {algorithm} during {operation}: {kind}")]
590    KeyWrap {
591        /// Key-wrap algorithm that failed.
592        algorithm: KeyWrapAlgorithm,
593        /// Operation (wrap or unwrap) that failed.
594        operation: KeyWrapOperation,
595        /// Specific key-wrap failure cause.
596        kind: KeyWrapFailureKind,
597    },
598
599    /// A password-based KDF operation failed for the given algorithm/profile.
600    #[error("KDF failed for {algorithm}/{profile}: {kind}")]
601    Kdf {
602        /// KDF algorithm that failed.
603        algorithm: KdfAlgorithm,
604        /// Cost profile in effect at the time of failure.
605        profile: KdfProfile,
606        /// Specific KDF failure cause.
607        kind: KdfFailureKind,
608    },
609
610    /// An HKDF operation failed for the given hash and reason.
611    #[error("HKDF failed for {hash}: {kind}")]
612    Hkdf {
613        /// Hash suite underlying the HKDF operation.
614        hash: HkdfHash,
615        /// Specific HKDF failure cause.
616        kind: HkdfFailureKind,
617    },
618
619    /// An HMAC operation failed for the given hash and reason.
620    #[error("HMAC failed for {hash}: {kind}")]
621    Mac {
622        /// Hash suite underlying the HMAC operation.
623        hash: MacHash,
624        /// Specific HMAC failure cause.
625        kind: MacFailureKind,
626    },
627
628    /// Secure random generation failed for the given output purpose.
629    #[error("secure random generation failed for {output}: {kind}")]
630    Rng {
631        /// Purpose the requested random bytes were being generated for.
632        output: RngOutputKind,
633        /// Specific RNG failure cause.
634        kind: RngFailureKind,
635    },
636
637    /// A constant-time comparison did not match, with the two input lengths.
638    #[error("constant-time comparison failed: {kind}")]
639    ConstantTimeComparison {
640        /// Specific comparison failure cause.
641        kind: ConstantTimeFailureKind,
642        /// Length in bytes of the left-hand input.
643        left_len: usize,
644        /// Length in bytes of the right-hand input.
645        right_len: usize,
646    },
647
648    /// The requested operation is not supported.
649    #[error("unsupported operation")]
650    Unsupported,
651}