codec_multicodec/
lookup.rs1use crate::table::{CodecTag, KeyLength, KeyMaterialKind, MULTICODEC_TABLE};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
9pub enum CodecPrefixError {
10 #[error("invalid multicodec prefix")]
12 InvalidPrefix,
13 #[error("multicodec does not identify public key material")]
15 NonPublicKeyMaterial,
16 #[error("invalid multicodec payload length")]
18 InvalidLength,
19}
20
21#[derive(Debug, Clone)]
23pub struct CodecLookupResult {
24 pub name: &'static str,
26 pub tag: CodecTag,
28 pub key_material: KeyMaterialKind,
30 pub alg: &'static str,
32 pub codec: &'static [u8],
34 pub key_length: KeyLength,
36}
37
38pub fn lookup_codec_prefix(bytes: &[u8]) -> Option<CodecLookupResult> {
40 for (name, spec) in MULTICODEC_TABLE {
41 let prefix = spec.codec;
42 if bytes.len() >= prefix.len() && bytes.starts_with(prefix) {
43 return Some(CodecLookupResult {
44 name,
45 tag: spec.tag,
46 key_material: spec.key_material,
47 alg: spec.alg,
48 codec: spec.codec,
49 key_length: spec.key_length,
50 });
51 }
52 }
53 None
54}
55
56pub fn strip_codec_prefix(bytes: &[u8]) -> Result<&[u8], CodecPrefixError> {
63 let found = lookup_codec_prefix(bytes).ok_or(CodecPrefixError::InvalidPrefix)?;
64 if found.key_material != KeyMaterialKind::PublicKey {
65 return Err(CodecPrefixError::NonPublicKeyMaterial);
66 }
67 let remainder = bytes
68 .get(found.codec.len()..)
69 .ok_or(CodecPrefixError::InvalidLength)?;
70 let valid = match found.key_length {
71 KeyLength::Fixed(expected) => remainder.len() == expected,
72 KeyLength::Variable => !remainder.is_empty(),
73 KeyLength::NotApplicable => false,
74 };
75 if !valid {
76 return Err(CodecPrefixError::InvalidLength);
77 }
78 Ok(remainder)
79}