Skip to main content

vauban_claim/
error.rs

1//! Error types for encoding and composition.
2
3use alloc::string::String;
4use thiserror::Error;
5
6/// Errors arising during canonical encoding or decoding.
7#[derive(Debug, Error)]
8pub enum EncodingError {
9    /// CBOR serialisation failed.
10    #[error("cbor serialisation failed: {0}")]
11    CborSer(String),
12
13    /// CBOR deserialisation failed.
14    #[error("cbor deserialisation failed: {0}")]
15    CborDe(String),
16
17    /// JSON serialisation failed.
18    #[error("json serialisation failed: {0}")]
19    JsonSer(#[from] serde_json::Error),
20
21    /// Encoded form contains a forbidden floating-point item (§ Numeric semantics).
22    #[error("CBOR float encountered: floats MUST NOT appear in conformant Claims")]
23    FloatForbidden,
24
25    /// Map keys not in canonical order (RFC 8949 §4.2.1).
26    #[error("non-canonical CBOR map key order")]
27    NonCanonicalMapOrder,
28}
29
30/// Errors arising during composition (operator application or validity check).
31#[derive(Debug, Error, PartialEq, Eq)]
32pub enum CompositionError {
33    /// Conjunction §6.1 C-1: subjects differ and no `linkage_proof` was provided.
34    #[error("conjunction: subjects differ and no linkage proof supplied (C-1)")]
35    SubjectMismatch,
36
37    /// Conjunction §6.1 C-3: temporal windows do not intersect.
38    #[error("conjunction: temporal windows do not intersect (C-3)")]
39    TemporalDisjoint,
40
41    /// Delegation §6.2 D-3: delegated scope exceeds parent scope.
42    #[error("delegation: scope exceeds parent (D-2)")]
43    ScopeOverflow,
44
45    /// Delegation §6.2: cycle detected in the delegation chain.
46    #[error("delegation: cycle detected — chain rejected per RFC 5280 §6.1.3")]
47    DelegationCycle,
48
49    /// Aggregation §6.3 G-1: two operands share an issuer key.
50    #[error("aggregation: issuer-diversity violation (G-1)")]
51    IssuerDuplicate,
52
53    /// Aggregation §6.3: fewer than two operands.
54    #[error("aggregation: at least 2 operands required")]
55    AggregationTooFew,
56
57    /// Restriction §6.4 R-1: new mask discloses fields not in the source mask.
58    #[error("restriction: mask non-monotonic (R-1)")]
59    MaskNonMonotonic,
60
61    /// Restriction §6.4 M-1: `disclosed` and `committed` overlap in the new mask.
62    #[error("restriction: disclosed ∩ committed ≠ ∅ (M-1)")]
63    MaskDisjointnessViolation,
64
65    /// Revocation §6.5 V-1: revoker is neither the original issuer nor a
66    /// delegated authority.
67    #[error("revocation: unauthorised revoker (V-1)")]
68    UnauthorisedRevoker,
69
70    /// Revocation §6.5: temporal frame already marks the source revoked.
71    #[error("revocation: source already revoked (sticky)")]
72    AlreadyRevoked,
73
74    /// Generic structural validity violation (catch-all for invariant checks).
75    #[error("structural invariant violated: {0}")]
76    Invariant(&'static str),
77}
78
79/// Errors arising during TranscriptT1 operations.
80#[derive(Debug, Error)]
81pub enum TranscriptError {
82    /// A required field is missing (e.g. subject.id both bytes and utf8 are None).
83    #[error("transcript: missing field: {0}")]
84    Missing(&'static str),
85
86    /// CBOR encoding failed during transcript absorption.
87    #[error("transcript: encoding failed: {0}")]
88    Encoding(String),
89
90    /// Transcript version mismatch — Claim's `transcript_version` does not match
91    /// the verifier's expected version. Rejects downgrade attacks (§6 Q5).
92    #[error("transcript: version mismatch: claim has {claim:?}, verifier expects {expected:?}")]
93    VersionMismatch {
94        /// The version tag found on the Claim.
95        claim: alloc::string::String,
96        /// The version tag required by the verifier.
97        expected: alloc::string::String,
98    },
99}