Skip to main content

h33_substrate_verifier/
error.rs

1//! Error type for the verifier.
2//!
3//! All fallible operations in this crate return [`VerifierError`]. The
4//! error variants are stable and semantic — calling code can match on
5//! them to drive UI, metrics, or retry logic.
6
7use alloc::string::String;
8use thiserror::Error;
9
10/// Every way verification can fail to *run*.
11///
12/// A successful [`verify_structural`](crate::verify::verify_structural)
13/// call still returns a [`VerificationResult`](crate::verify::VerificationResult)
14/// which itself may report failed checks — those are NOT
15/// [`VerifierError`]s. This type is reserved for inputs that are
16/// malformed to the point where no verdict can be produced.
17#[derive(Debug, Error)]
18#[non_exhaustive]
19pub enum VerifierError {
20    /// The `X-H33-Substrate` header was not 64 hex characters.
21    #[error("X-H33-Substrate header must be 64 hex characters (32 bytes), got {actual}")]
22    InvalidSubstrateHeaderLength {
23        /// Number of characters actually present in the header value.
24        actual: usize,
25    },
26
27    /// The `X-H33-Substrate` header contained invalid hex.
28    #[error("X-H33-Substrate header is not valid hex: {0}")]
29    InvalidSubstrateHeaderHex(String),
30
31    /// The `X-H33-Receipt` header was not 84 hex characters.
32    #[error("X-H33-Receipt header must be 84 hex characters (42 bytes), got {actual}")]
33    InvalidReceiptHeaderLength {
34        /// Number of characters actually present in the header value.
35        actual: usize,
36    },
37
38    /// The `X-H33-Receipt` header contained invalid hex.
39    #[error("X-H33-Receipt header is not valid hex: {0}")]
40    InvalidReceiptHeaderHex(String),
41
42    /// The decoded receipt bytes had an unexpected version byte.
43    ///
44    /// The expected version for this verifier build is
45    /// [`RECEIPT_VERSION`](crate::receipt::RECEIPT_VERSION).
46    #[error("CompactReceipt version byte is 0x{actual:02X}, expected 0x{expected:02X}")]
47    UnsupportedReceiptVersion {
48        /// The version byte the receipt actually carried.
49        actual: u8,
50        /// The version byte this verifier build understands.
51        expected: u8,
52    },
53
54    /// The decoded receipt bytes were not exactly 42 bytes.
55    #[error("CompactReceipt must decode to exactly {expected} bytes, got {actual}")]
56    InvalidReceiptSize {
57        /// Byte length the parser read.
58        actual: usize,
59        /// Byte length the spec requires.
60        expected: usize,
61    },
62
63    /// The receipt's algorithm flags byte had bits set that the verifier
64    /// does not recognize. This can happen when a newer server adds a
65    /// fourth signature family before the verifier crate catches up.
66    /// Not fatal — the recognized families still verify — but the
67    /// caller should know that the full algorithm set was not inspected.
68    #[error(
69        "CompactReceipt algorithm flags 0x{flags:02X} contain unrecognized bits; \
70         verifier only knows Dilithium (0x01), FALCON (0x02), SPHINCS+ (0x04)"
71    )]
72    UnknownAlgorithmBits {
73        /// The raw algorithm flags byte.
74        flags: u8,
75    },
76
77    /// The public-keys JSON document could not be parsed.
78    #[error("public keys JSON parse failed: {0}")]
79    PublicKeysParse(String),
80
81    /// A base64 value in the public-keys JSON could not be decoded.
82    #[error("public keys contained invalid base64 for field `{field}`: {detail}")]
83    PublicKeysBase64 {
84        /// The JSON field the bad base64 was in.
85        field: &'static str,
86        /// Human-readable decoder detail.
87        detail: String,
88    },
89
90    /// An unknown algorithm string appeared in `X-H33-Algorithms`. The
91    /// verifier recognizes exactly these identifiers:
92    ///
93    /// - `ML-DSA-65` (Dilithium, NIST FIPS 204)
94    /// - `FALCON-512`
95    /// - `SPHINCS+-SHA2-128f` (SLH-DSA, NIST FIPS 205)
96    #[error("unknown algorithm identifier in X-H33-Algorithms: `{0}`")]
97    UnknownAlgorithm(String),
98}
99
100#[cfg(feature = "std")]
101impl From<VerifierError> for std::io::Error {
102    fn from(e: VerifierError) -> Self {
103        Self::new(std::io::ErrorKind::InvalidData, e.to_string())
104    }
105}