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: key material is not public")]
212 NonPublicKeyMaterial,
213
214 #[error("multikey: empty public key")]
216 EmptyKey,
217
218 #[error("multikey: invalid compressed EC point tag")]
220 InvalidCompressedPoint,
221
222 #[error("multikey: unknown codec name: {reason}")]
224 UnknownCodecName {
225 reason: CodecNameReason,
227 },
228
229 #[error("multikey: key length mismatch for {codec}: expected {expected}, got {actual}")]
231 KeyLengthMismatch {
232 codec: MultikeyCodecKind,
234 expected: usize,
236 actual: usize,
238 },
239
240 #[error("multikey: key too large for {codec}: maximum {max}, got {actual}")]
242 KeyTooLarge {
243 codec: MultikeyCodecKind,
245 max: usize,
247 actual: usize,
249 },
250
251 #[error("multikey: encoded payload too large")]
253 EncodedPayloadTooLarge,
254
255 #[error(
257 "multikey: binding type '{binding_type}' does not match codec '{codec}' (alg={algorithm})"
258 )]
259 BindingTypeCodecMismatch {
260 binding_type: BindingTypeKind,
262 codec: MultikeyCodecKind,
264 algorithm: BindingAlgorithmKind,
266 },
267
268 #[error(
270 "multikey: algorithm mismatch: binding.algorithm='{binding_alg}' but codec implies '{codec_algorithm}'"
271 )]
272 BindingAlgorithmMismatch {
273 binding_alg: BindingAlgorithmKind,
275 codec_algorithm: BindingAlgorithmKind,
277 },
278
279 #[error(
281 "multikey: binding.algorithm missing but binding type '{binding_type}' requires an explicit algorithm"
282 )]
283 BindingAlgorithmMissing {
284 binding_type: BindingTypeKind,
286 },
287}
288
289pub(crate) fn classify_binding_type(binding_type: &str) -> BindingTypeKind {
290 match binding_type {
291 "Multikey" => BindingTypeKind::Multikey,
292 "P256Key2024" => BindingTypeKind::P256Key2024,
293 "P384Key2024" => BindingTypeKind::P384Key2024,
294 "P521Key2024" => BindingTypeKind::P521Key2024,
295 "RsaVerificationKey2024" => BindingTypeKind::RsaVerificationKey2024,
296 "ML_DSA_44Key2024" => BindingTypeKind::MlDsa44Key2024,
297 "ML_DSA_65Key2024" => BindingTypeKind::MlDsa65Key2024,
298 "ML_DSA_87Key2024" => BindingTypeKind::MlDsa87Key2024,
299 "MLKEM512Key2024" => BindingTypeKind::MlKem512Key2024,
300 "MLKEM768Key2024" => BindingTypeKind::MlKem768Key2024,
301 "MLKEM1024Key2024" => BindingTypeKind::MlKem1024Key2024,
302 _ => BindingTypeKind::Unsupported,
303 }
304}
305
306pub(crate) fn classify_binding_algorithm(algorithm: &str) -> BindingAlgorithmKind {
307 match algorithm {
308 "Ed25519" => BindingAlgorithmKind::Ed25519,
309 "Ed448" => BindingAlgorithmKind::Ed448,
310 "X25519" => BindingAlgorithmKind::X25519,
311 "P-256" => BindingAlgorithmKind::P256,
312 "P-384" => BindingAlgorithmKind::P384,
313 "P-521" => BindingAlgorithmKind::P521,
314 "RSA" => BindingAlgorithmKind::Rsa,
315 "secp256k1" => BindingAlgorithmKind::Secp256k1,
316 "ML-DSA-44" => BindingAlgorithmKind::MlDsa44,
317 "ML-DSA-65" => BindingAlgorithmKind::MlDsa65,
318 "ML-DSA-87" => BindingAlgorithmKind::MlDsa87,
319 "ML-KEM-512" => BindingAlgorithmKind::MlKem512,
320 "ML-KEM-768" => BindingAlgorithmKind::MlKem768,
321 "ML-KEM-1024" => BindingAlgorithmKind::MlKem1024,
322 _ => BindingAlgorithmKind::Unsupported,
323 }
324}
325
326pub(crate) fn classify_multikey_codec(codec_name: &str) -> MultikeyCodecKind {
327 match codec_name {
328 "ed25519-pub" => MultikeyCodecKind::Ed25519,
329 "ed448-pub" => MultikeyCodecKind::Ed448,
330 "x25519-pub" => MultikeyCodecKind::X25519,
331 "p256-pub" => MultikeyCodecKind::P256,
332 "p384-pub" => MultikeyCodecKind::P384,
333 "p521-pub" => MultikeyCodecKind::P521,
334 "rsa-pub" => MultikeyCodecKind::Rsa,
335 "secp256k1-pub" => MultikeyCodecKind::Secp256k1,
336 "mldsa-44-pub" => MultikeyCodecKind::MlDsa44,
337 "mldsa-65-pub" => MultikeyCodecKind::MlDsa65,
338 "mldsa-87-pub" => MultikeyCodecKind::MlDsa87,
339 "mlkem-512-pub" => MultikeyCodecKind::MlKem512,
340 "mlkem-768-pub" => MultikeyCodecKind::MlKem768,
341 "mlkem-1024-pub" => MultikeyCodecKind::MlKem1024,
342 _ => MultikeyCodecKind::Unsupported,
343 }
344}