1use std::fmt;
7use thiserror::Error;
8
9pub type Result<T> = std::result::Result<T, QuacError>;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16#[repr(i32)]
17pub enum ErrorCode {
18 Success = 0,
20 Error = -1,
22 InvalidParam = -2,
24 BufferSmall = -3,
26 DeviceNotFound = -4,
28 DeviceBusy = -5,
30 DeviceError = -6,
32 OutOfMemory = -7,
34 NotSupported = -8,
36 AuthRequired = -9,
38 AuthFailed = -10,
40 KeyNotFound = -11,
42 InvalidKey = -12,
44 VerificationFailed = -13,
46 DecapsFailed = -14,
48 HardwareUnavail = -15,
50 Timeout = -16,
52 NotInitialized = -17,
54 AlreadyInit = -18,
56 InvalidHandle = -19,
58 Cancelled = -20,
60 EntropyDepleted = -21,
62 SelfTestFailed = -22,
64 TamperDetected = -23,
66 Temperature = -24,
68 Power = -25,
70 InvalidAlgorithm = -26,
72 CryptoError = -27,
74 InternalError = -99,
76}
77
78impl ErrorCode {
79 pub fn message(&self) -> &'static str {
81 match self {
82 Self::Success => "Operation completed successfully",
83 Self::Error => "Generic error",
84 Self::InvalidParam => "Invalid parameter",
85 Self::BufferSmall => "Output buffer too small",
86 Self::DeviceNotFound => "No QUAC 100 device found",
87 Self::DeviceBusy => "Device is busy",
88 Self::DeviceError => "Device error",
89 Self::OutOfMemory => "Memory allocation failed",
90 Self::NotSupported => "Operation not supported",
91 Self::AuthRequired => "Authentication required",
92 Self::AuthFailed => "Authentication failed",
93 Self::KeyNotFound => "Key not found",
94 Self::InvalidKey => "Invalid key",
95 Self::VerificationFailed => "Signature verification failed",
96 Self::DecapsFailed => "Decapsulation failed",
97 Self::HardwareUnavail => "Hardware acceleration unavailable",
98 Self::Timeout => "Operation timed out",
99 Self::NotInitialized => "Library not initialized",
100 Self::AlreadyInit => "Library already initialized",
101 Self::InvalidHandle => "Invalid handle",
102 Self::Cancelled => "Operation cancelled",
103 Self::EntropyDepleted => "Entropy pool depleted",
104 Self::SelfTestFailed => "Self-test failed",
105 Self::TamperDetected => "Tamper detected",
106 Self::Temperature => "Temperature error",
107 Self::Power => "Power supply error",
108 Self::InvalidAlgorithm => "Invalid algorithm",
109 Self::CryptoError => "Cryptographic operation error",
110 Self::InternalError => "Internal error",
111 }
112 }
113
114 pub fn from_raw(code: i32) -> Self {
116 match code {
117 0 => Self::Success,
118 -1 => Self::Error,
119 -2 => Self::InvalidParam,
120 -3 => Self::BufferSmall,
121 -4 => Self::DeviceNotFound,
122 -5 => Self::DeviceBusy,
123 -6 => Self::DeviceError,
124 -7 => Self::OutOfMemory,
125 -8 => Self::NotSupported,
126 -9 => Self::AuthRequired,
127 -10 => Self::AuthFailed,
128 -11 => Self::KeyNotFound,
129 -12 => Self::InvalidKey,
130 -13 => Self::VerificationFailed,
131 -14 => Self::DecapsFailed,
132 -15 => Self::HardwareUnavail,
133 -16 => Self::Timeout,
134 -17 => Self::NotInitialized,
135 -18 => Self::AlreadyInit,
136 -19 => Self::InvalidHandle,
137 -20 => Self::Cancelled,
138 -21 => Self::EntropyDepleted,
139 -22 => Self::SelfTestFailed,
140 -23 => Self::TamperDetected,
141 -24 => Self::Temperature,
142 -25 => Self::Power,
143 -26 => Self::InvalidAlgorithm,
144 -27 => Self::CryptoError,
145 _ => Self::InternalError,
146 }
147 }
148
149 pub fn to_raw(self) -> i32 {
151 self as i32
152 }
153
154 pub fn is_success(self) -> bool {
156 self == Self::Success
157 }
158}
159
160impl fmt::Display for ErrorCode {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 write!(f, "{}", self.message())
163 }
164}
165
166#[derive(Error, Debug)]
168pub enum QuacError {
169 #[error("QUAC 100 error ({code:?}): {message}")]
171 Native {
172 code: ErrorCode,
174 message: String,
176 },
177
178 #[error("Device not found: {0}")]
180 DeviceNotFound(String),
181
182 #[error("Invalid parameter: {0}")]
184 InvalidParameter(String),
185
186 #[error("Verification failed")]
188 VerificationFailed,
189
190 #[error("Decapsulation failed")]
192 DecapsulationFailed,
193
194 #[error("Library not initialized")]
196 NotInitialized,
197
198 #[error("Buffer too small: need {needed} bytes, got {got}")]
200 BufferTooSmall {
201 needed: usize,
203 got: usize,
205 },
206
207 #[error("I/O error: {0}")]
209 Io(#[from] std::io::Error),
210
211 #[error("UTF-8 error: {0}")]
213 Utf8(#[from] std::str::Utf8Error),
214
215 #[error("Null pointer encountered")]
217 NullPointer,
218
219 #[error("Internal error: {0}")]
221 Internal(String),
222}
223
224impl QuacError {
225 pub fn from_code(code: ErrorCode) -> Self {
227 Self::Native {
228 message: code.message().to_string(),
229 code,
230 }
231 }
232
233 pub fn from_raw(code: i32) -> Self {
235 Self::from_code(ErrorCode::from_raw(code))
236 }
237
238 pub fn code(&self) -> Option<ErrorCode> {
240 match self {
241 Self::Native { code, .. } => Some(*code),
242 Self::DeviceNotFound(_) => Some(ErrorCode::DeviceNotFound),
243 Self::InvalidParameter(_) => Some(ErrorCode::InvalidParam),
244 Self::VerificationFailed => Some(ErrorCode::VerificationFailed),
245 Self::DecapsulationFailed => Some(ErrorCode::DecapsFailed),
246 Self::NotInitialized => Some(ErrorCode::NotInitialized),
247 Self::BufferTooSmall { .. } => Some(ErrorCode::BufferSmall),
248 _ => None,
249 }
250 }
251
252 pub fn is_verification_error(&self) -> bool {
254 matches!(
255 self,
256 Self::VerificationFailed | Self::Native { code: ErrorCode::VerificationFailed, .. }
257 )
258 }
259}
260
261pub(crate) fn check_error(code: i32) -> Result<()> {
263 if code == 0 {
264 Ok(())
265 } else {
266 Err(QuacError::from_raw(code))
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
275 fn test_error_code_from_raw() {
276 assert_eq!(ErrorCode::from_raw(0), ErrorCode::Success);
277 assert_eq!(ErrorCode::from_raw(-2), ErrorCode::InvalidParam);
278 assert_eq!(ErrorCode::from_raw(-17), ErrorCode::NotInitialized);
279 assert_eq!(ErrorCode::from_raw(-999), ErrorCode::InternalError);
280 }
281
282 #[test]
283 fn test_error_code_message() {
284 assert_eq!(ErrorCode::Success.message(), "Operation completed successfully");
285 assert!(ErrorCode::InvalidParam.message().contains("Invalid"));
286 }
287
288 #[test]
289 fn test_quac_error_from_code() {
290 let err = QuacError::from_code(ErrorCode::DeviceNotFound);
291 assert_eq!(err.code(), Some(ErrorCode::DeviceNotFound));
292 }
293
294 #[test]
295 fn test_check_error() {
296 assert!(check_error(0).is_ok());
297 assert!(check_error(-1).is_err());
298 }
299}