1use thiserror::Error;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum CodecNameReason {
11 Unsupported,
13}
14
15impl core::fmt::Display for CodecNameReason {
16 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17 let detail = match self {
18 CodecNameReason::Unsupported => "unsupported codec name",
19 };
20 write!(f, "{detail}")
21 }
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[non_exhaustive]
27pub enum MultikeyCodecKind {
28 Ed25519,
30 Ed448,
32 X25519,
34 P256,
36 P384,
38 P521,
40 Rsa,
42 Secp256k1,
44 MlDsa44,
46 MlDsa65,
48 MlDsa87,
50 MlKem512,
52 MlKem768,
54 MlKem1024,
56 Unsupported,
58}
59
60impl core::fmt::Display for MultikeyCodecKind {
61 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
62 let detail = match self {
63 MultikeyCodecKind::Ed25519 => "ed25519-pub",
64 MultikeyCodecKind::Ed448 => "ed448-pub",
65 MultikeyCodecKind::X25519 => "x25519-pub",
66 MultikeyCodecKind::P256 => "p256-pub",
67 MultikeyCodecKind::P384 => "p384-pub",
68 MultikeyCodecKind::P521 => "p521-pub",
69 MultikeyCodecKind::Rsa => "rsa-pub",
70 MultikeyCodecKind::Secp256k1 => "secp256k1-pub",
71 MultikeyCodecKind::MlDsa44 => "mldsa-44-pub",
72 MultikeyCodecKind::MlDsa65 => "mldsa-65-pub",
73 MultikeyCodecKind::MlDsa87 => "mldsa-87-pub",
74 MultikeyCodecKind::MlKem512 => "mlkem-512-pub",
75 MultikeyCodecKind::MlKem768 => "mlkem-768-pub",
76 MultikeyCodecKind::MlKem1024 => "mlkem-1024-pub",
77 MultikeyCodecKind::Unsupported => "unsupported codec",
78 };
79 write!(f, "{detail}")
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85#[non_exhaustive]
86pub enum BindingTypeKind {
87 Multikey,
89 P256Key2024,
91 P384Key2024,
93 P521Key2024,
95 RsaVerificationKey2024,
97 MlDsa44Key2024,
99 MlDsa65Key2024,
101 MlDsa87Key2024,
103 MlKem512Key2024,
105 MlKem768Key2024,
107 MlKem1024Key2024,
109 Unsupported,
111}
112
113impl core::fmt::Display for BindingTypeKind {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 let detail = match self {
116 BindingTypeKind::Multikey => "Multikey",
117 BindingTypeKind::P256Key2024 => "P256Key2024",
118 BindingTypeKind::P384Key2024 => "P384Key2024",
119 BindingTypeKind::P521Key2024 => "P521Key2024",
120 BindingTypeKind::RsaVerificationKey2024 => "RsaVerificationKey2024",
121 BindingTypeKind::MlDsa44Key2024 => "ML_DSA_44Key2024",
122 BindingTypeKind::MlDsa65Key2024 => "ML_DSA_65Key2024",
123 BindingTypeKind::MlDsa87Key2024 => "ML_DSA_87Key2024",
124 BindingTypeKind::MlKem512Key2024 => "MLKEM512Key2024",
125 BindingTypeKind::MlKem768Key2024 => "MLKEM768Key2024",
126 BindingTypeKind::MlKem1024Key2024 => "MLKEM1024Key2024",
127 BindingTypeKind::Unsupported => "unsupported binding type",
128 };
129 write!(f, "{detail}")
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135#[non_exhaustive]
136pub enum BindingAlgorithmKind {
137 Ed25519,
139 Ed448,
141 X25519,
143 P256,
145 P384,
147 P521,
149 Rsa,
151 Secp256k1,
153 MlDsa44,
155 MlDsa65,
157 MlDsa87,
159 MlKem512,
161 MlKem768,
163 MlKem1024,
165 Unsupported,
167}
168
169impl core::fmt::Display for BindingAlgorithmKind {
170 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
171 let detail = match self {
172 BindingAlgorithmKind::Ed25519 => "Ed25519",
173 BindingAlgorithmKind::Ed448 => "Ed448",
174 BindingAlgorithmKind::X25519 => "X25519",
175 BindingAlgorithmKind::P256 => "P-256",
176 BindingAlgorithmKind::P384 => "P-384",
177 BindingAlgorithmKind::P521 => "P-521",
178 BindingAlgorithmKind::Rsa => "RSA",
179 BindingAlgorithmKind::Secp256k1 => "secp256k1",
180 BindingAlgorithmKind::MlDsa44 => "ML-DSA-44",
181 BindingAlgorithmKind::MlDsa65 => "ML-DSA-65",
182 BindingAlgorithmKind::MlDsa87 => "ML-DSA-87",
183 BindingAlgorithmKind::MlKem512 => "ML-KEM-512",
184 BindingAlgorithmKind::MlKem768 => "ML-KEM-768",
185 BindingAlgorithmKind::MlKem1024 => "ML-KEM-1024",
186 BindingAlgorithmKind::Unsupported => "unsupported algorithm",
187 };
188 write!(f, "{detail}")
189 }
190}
191
192#[derive(Debug, Error)]
196#[non_exhaustive]
197pub enum MultikeyError {
198 #[error("multikey: invalid multibase string")]
200 InvalidMultibase,
201
202 #[error("multikey: decoded key too short: length={0}")]
204 DecodedTooShort(usize),
205
206 #[error("multikey: unknown multicodec prefix")]
208 UnknownCodecPrefix,
209
210 #[error("multikey: unknown codec name: {reason}")]
212 UnknownCodecName {
213 reason: CodecNameReason,
215 },
216
217 #[error("multikey: key length mismatch for {codec}: expected {expected}, got {actual}")]
219 KeyLengthMismatch {
220 codec: MultikeyCodecKind,
222 expected: usize,
224 actual: usize,
226 },
227
228 #[error("multikey: key too large for {codec}: maximum {max}, got {actual}")]
230 KeyTooLarge {
231 codec: MultikeyCodecKind,
233 max: usize,
235 actual: usize,
237 },
238
239 #[error("multikey: encoded payload too large")]
241 EncodedPayloadTooLarge,
242
243 #[error(
245 "multikey: binding type '{binding_type}' does not match codec '{codec}' (alg={algorithm})"
246 )]
247 BindingTypeCodecMismatch {
248 binding_type: BindingTypeKind,
250 codec: MultikeyCodecKind,
252 algorithm: BindingAlgorithmKind,
254 },
255
256 #[error(
258 "multikey: algorithm mismatch: binding.algorithm='{binding_alg}' but codec implies '{codec_algorithm}'"
259 )]
260 BindingAlgorithmMismatch {
261 binding_alg: BindingAlgorithmKind,
263 codec_algorithm: BindingAlgorithmKind,
265 },
266
267 #[error(
269 "multikey: binding.algorithm missing but binding type '{binding_type}' requires an explicit algorithm"
270 )]
271 BindingAlgorithmMissing {
272 binding_type: BindingTypeKind,
274 },
275}
276
277pub(crate) fn classify_binding_type(binding_type: &str) -> BindingTypeKind {
278 match binding_type {
279 "Multikey" => BindingTypeKind::Multikey,
280 "P256Key2024" => BindingTypeKind::P256Key2024,
281 "P384Key2024" => BindingTypeKind::P384Key2024,
282 "P521Key2024" => BindingTypeKind::P521Key2024,
283 "RsaVerificationKey2024" => BindingTypeKind::RsaVerificationKey2024,
284 "ML_DSA_44Key2024" => BindingTypeKind::MlDsa44Key2024,
285 "ML_DSA_65Key2024" => BindingTypeKind::MlDsa65Key2024,
286 "ML_DSA_87Key2024" => BindingTypeKind::MlDsa87Key2024,
287 "MLKEM512Key2024" => BindingTypeKind::MlKem512Key2024,
288 "MLKEM768Key2024" => BindingTypeKind::MlKem768Key2024,
289 "MLKEM1024Key2024" => BindingTypeKind::MlKem1024Key2024,
290 _ => BindingTypeKind::Unsupported,
291 }
292}
293
294pub(crate) fn classify_binding_algorithm(algorithm: &str) -> BindingAlgorithmKind {
295 match algorithm {
296 "Ed25519" => BindingAlgorithmKind::Ed25519,
297 "Ed448" => BindingAlgorithmKind::Ed448,
298 "X25519" => BindingAlgorithmKind::X25519,
299 "P-256" => BindingAlgorithmKind::P256,
300 "P-384" => BindingAlgorithmKind::P384,
301 "P-521" => BindingAlgorithmKind::P521,
302 "RSA" => BindingAlgorithmKind::Rsa,
303 "secp256k1" => BindingAlgorithmKind::Secp256k1,
304 "ML-DSA-44" => BindingAlgorithmKind::MlDsa44,
305 "ML-DSA-65" => BindingAlgorithmKind::MlDsa65,
306 "ML-DSA-87" => BindingAlgorithmKind::MlDsa87,
307 "ML-KEM-512" => BindingAlgorithmKind::MlKem512,
308 "ML-KEM-768" => BindingAlgorithmKind::MlKem768,
309 "ML-KEM-1024" => BindingAlgorithmKind::MlKem1024,
310 _ => BindingAlgorithmKind::Unsupported,
311 }
312}
313
314pub(crate) fn classify_multikey_codec(codec_name: &str) -> MultikeyCodecKind {
315 match codec_name {
316 "ed25519-pub" => MultikeyCodecKind::Ed25519,
317 "ed448-pub" => MultikeyCodecKind::Ed448,
318 "x25519-pub" => MultikeyCodecKind::X25519,
319 "p256-pub" => MultikeyCodecKind::P256,
320 "p384-pub" => MultikeyCodecKind::P384,
321 "p521-pub" => MultikeyCodecKind::P521,
322 "rsa-pub" => MultikeyCodecKind::Rsa,
323 "secp256k1-pub" => MultikeyCodecKind::Secp256k1,
324 "mldsa-44-pub" => MultikeyCodecKind::MlDsa44,
325 "mldsa-65-pub" => MultikeyCodecKind::MlDsa65,
326 "mldsa-87-pub" => MultikeyCodecKind::MlDsa87,
327 "mlkem-512-pub" => MultikeyCodecKind::MlKem512,
328 "mlkem-768-pub" => MultikeyCodecKind::MlKem768,
329 "mlkem-1024-pub" => MultikeyCodecKind::MlKem1024,
330 _ => MultikeyCodecKind::Unsupported,
331 }
332}