1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Error types for the Tenzro Decentralized Identity Protocol
use thiserror::Error;
/// Result type for identity operations
pub type Result<T> = std::result::Result<T, IdentityError>;
/// Errors that can occur during identity operations
#[derive(Debug, Error)]
pub enum IdentityError {
/// DID could not be parsed
#[error("invalid DID format: {0}")]
InvalidDid(String),
/// Identity not found in the registry
#[error("identity not found: {0}")]
NotFound(String),
/// Identity already exists
#[error("identity already exists: {0}")]
AlreadyExists(String),
/// Identity is not in the required state
#[error("identity is not active: {0}")]
NotActive(String),
/// Operation not permitted
#[error("permission denied: {0}")]
PermissionDenied(String),
/// Delegation scope violated
#[error("delegation scope violation: {0}")]
DelegationViolation(String),
/// Credential error
#[error("credential error: {0}")]
CredentialError(String),
/// Verification failed
#[error("verification failed: {0}")]
VerificationFailed(String),
/// Trust chain is broken — an issuer in the chain is not Active,
/// is not in the registry, has no key the credential could verify
/// against, or its signature does not verify (CRITICAL #41).
#[error("trust chain broken at issuer {issuer}: {reason}")]
TrustChainBroken {
/// DID of the issuer where the chain broke
issuer: String,
/// Human-readable reason
reason: String,
},
/// A cycle was detected during trust chain traversal (CRITICAL #41).
/// Contains the DID that was revisited.
#[error("trust chain cycle detected at issuer {issuer}")]
TrustChainCycle {
/// DID that completed the cycle
issuer: String,
},
/// Trust chain exceeded the configured maximum traversal depth
/// (CRITICAL #41). Acts as a DoS guard against arbitrarily long
/// or maliciously crafted issuer chains.
#[error("trust chain exceeded max depth of {max_depth}")]
TrustChainTooDeep {
/// Maximum depth allowed by the verifier configuration
max_depth: usize,
},
/// Trust chain terminated without reaching a recognized trust root
/// (CRITICAL #41). The credential chain is internally consistent but
/// does not anchor to any DID the verifier was configured to trust.
#[error("trust chain did not reach a recognized trust root")]
NoTrustRoot,
/// Invalid service endpoint URL (MEDIUM #128)
#[error("invalid service endpoint: {0}")]
InvalidServiceEndpoint(String),
/// Credential already issued / replay attempt (MEDIUM #129)
#[error("duplicate credential: {0}")]
DuplicateCredential(String),
/// Username is already taken by another identity
#[error("username already taken: {0}")]
UsernameTaken(String),
/// Username does not meet validation requirements
#[error("invalid username: {0}")]
UsernameInvalid(String),
/// Wallet provisioning or binding error
#[error("wallet error: {0}")]
WalletError(String),
/// Caller-supplied public key was malformed (wrong length, wrong
/// curve, etc.). Used by BYOK registration paths.
#[error("invalid public key: {0}")]
InvalidPublicKey(String),
/// Cryptographic operation failed
#[error("crypto error: {0}")]
CryptoError(String),
/// Serialization/deserialization error
#[error("serialization error: {0}")]
SerializationError(String),
/// Revocation broadcast could not be dispatched to the network layer.
/// Best-effort: `revoke()` logs this and keeps the local revocation.
#[error("revocation broadcast error: {0}")]
BroadcastError(String),
/// Remote DID resolution backend failed (transport or upstream error).
/// `IdentityRegistry::resolve()` logs this and falls through to
/// `NotFound` — a broken upstream must not mask a local lookup.
#[error("resolution backend error: {0}")]
ResolutionError(String),
}
impl From<tenzro_crypto::CryptoError> for IdentityError {
fn from(e: tenzro_crypto::CryptoError) -> Self {
IdentityError::CryptoError(e.to_string())
}
}
impl From<tenzro_wallet::WalletError> for IdentityError {
fn from(e: tenzro_wallet::WalletError) -> Self {
IdentityError::WalletError(e.to_string())
}
}
impl From<serde_json::Error> for IdentityError {
fn from(e: serde_json::Error) -> Self {
IdentityError::SerializationError(e.to_string())
}
}