pqc_sig/error.rs
1//! Unified error type for the `pqc-sig` crate.
2//!
3//! All signature operations return `Result<T, SigError>`. This type is designed to be
4//! `no_std`-compatible (with `alloc`) and serializable for WASM boundary crossing.
5
6extern crate alloc;
7use alloc::string::{String, ToString};
8
9use thiserror::Error;
10
11/// Errors that can occur during signature operations.
12#[derive(Debug, Error, Clone, PartialEq)]
13pub enum SigError {
14 /// Key generation failed (e.g., RNG failure).
15 #[error("key generation failed: {0}")]
16 KeyGeneration(String),
17
18 /// Signing operation failed.
19 #[error("signing failed: {0}")]
20 Signing(String),
21
22 /// Signature verification failed (signature is invalid for the given message/key).
23 #[error("signature verification failed")]
24 VerificationFailed,
25
26 /// Invalid public key (wrong size, wrong algorithm tag, or malformed).
27 #[error("invalid public key: {0}")]
28 InvalidPublicKey(String),
29
30 /// Invalid secret key (wrong size, wrong algorithm tag, or malformed).
31 #[error("invalid secret key: {0}")]
32 InvalidSecretKey(String),
33
34 /// Invalid signature (wrong size, wrong algorithm tag, or malformed).
35 #[error("invalid signature: {0}")]
36 InvalidSignature(String),
37
38 /// Base64 decoding error.
39 #[error("base64 decode error: {0}")]
40 Base64Decode(String),
41
42 /// JSON serialization/deserialization error.
43 #[error("serialization error: {0}")]
44 Serialization(String),
45
46 /// The requested algorithm is not available (feature not enabled).
47 #[error("algorithm '{name}' not available; enable feature '{feature}'")]
48 AlgorithmNotAvailable { name: String, feature: String },
49
50 /// Hybrid signature verification failed on the classical (Ed25519) side.
51 #[error("hybrid verification failed: classical (Ed25519) signature invalid")]
52 HybridClassicalFailed,
53
54 /// Hybrid signature verification failed on the post-quantum (ML-DSA) side.
55 #[error("hybrid verification failed: post-quantum (ML-DSA) signature invalid")]
56 HybridPqcFailed,
57
58 /// Generic internal error.
59 #[error("internal error: {0}")]
60 Internal(String),
61
62 /// Domain-separation context string exceeds the FIPS 204/205/206 255-byte maximum.
63 ///
64 /// FIPS 204 §5.2, FIPS 205 §10.2, and the FIPS 206 (draft) `DomainContext` construction
65 /// all encode the context length in a single byte, capping it at 255 bytes. Returned by
66 /// every `sign_ctx`/`sign_ctx_deterministic`/`verify_ctx` method before it would
67 /// otherwise hit an opaque error from the underlying `ml-dsa`/`slh-dsa`/`fn-dsa` crate.
68 #[error("context string too long: {len} bytes (max 255)")]
69 ContextTooLong { len: usize },
70
71 /// Pre-hash digest length does not match the expected output size of the named
72 /// hash function (FIPS 204 §5.4.1 / FIPS 205 §10.2.2).
73 ///
74 /// Returned by every `sign_prehash`/`sign_prehash_deterministic`/`verify_prehash`
75 /// method before it would otherwise sign/verify a malformed digest.
76 #[error("digest length for {hash} must be {expected} bytes, got {got}")]
77 InvalidDigestLength { hash: &'static str, expected: usize, got: usize },
78
79 /// Pre-hash collision strength is weaker than the signature algorithm's required
80 /// security strength (FIPS 204 §5.4 / FIPS 205 §10.2.2).
81 ///
82 /// For example, `PreHash::Sha256` (128-bit collision strength) is rejected for
83 /// `MlDsa65Keypair`/`MlDsa87Keypair` (192/256-bit security strength).
84 #[error("pre-hash {hash} ({strength}-bit collision strength) is too weak for {algorithm} (requires >= {required} bits)")]
85 PreHashTooWeak { hash: &'static str, strength: u32, algorithm: &'static str, required: u32 },
86}
87
88impl SigError {
89 /// Convert to a string suitable for crossing the WASM boundary.
90 pub fn to_wasm_string(&self) -> String {
91 self.to_string()
92 }
93}
94
95/// Convenience type alias for signature results.
96pub type SigResult<T> = Result<T, SigError>;