1use crate::EncodingError;
9use serde::{Deserialize, Serialize};
10use zeroize::{Zeroize, ZeroizeOnDrop};
11
12pub const ED25519_PUB: u64 = 0xed;
17pub const ED25519_PRIV: u64 = 0x1300;
18pub const X25519_PUB: u64 = 0xec;
19pub const X25519_PRIV: u64 = 0x1302;
20pub const SECP256K1_PUB: u64 = 0xe7;
21pub const SECP256K1_PRIV: u64 = 0x1301;
22pub const P256_PUB: u64 = 0x1200;
23pub const P256_PRIV: u64 = 0x1306;
24pub const P384_PUB: u64 = 0x1201;
25pub const P384_PRIV: u64 = 0x1307;
26pub const P521_PUB: u64 = 0x1202;
27pub const P521_PRIV: u64 = 0x1308;
28
29pub const ML_DSA_44_PUB: u64 = 0x1210;
37pub const ML_DSA_44_PRIV_SEED: u64 = 0x131a;
38pub const ML_DSA_65_PUB: u64 = 0x1211;
39pub const ML_DSA_65_PRIV_SEED: u64 = 0x131b;
40pub const ML_DSA_87_PUB: u64 = 0x1212;
41pub const ML_DSA_87_PRIV_SEED: u64 = 0x131c;
42pub const SLH_DSA_SHA2_128S_PUB: u64 = 0x1220;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46pub enum Codec {
47 Ed25519Pub,
48 Ed25519Priv,
49 X25519Pub,
50 X25519Priv,
51 Secp256k1Pub,
52 Secp256k1Priv,
53 P256Pub,
54 P256Priv,
55 P384Pub,
56 P384Priv,
57 P521Pub,
58 P521Priv,
59 MlDsa44Pub,
60 MlDsa44PrivSeed,
61 MlDsa65Pub,
62 MlDsa65PrivSeed,
63 MlDsa87Pub,
64 MlDsa87PrivSeed,
65 SlhDsaSha2_128sPub,
66 Unknown(u64),
67}
68
69impl Codec {
70 pub fn from_u64(value: u64) -> Self {
72 match value {
73 ED25519_PUB => Codec::Ed25519Pub,
74 ED25519_PRIV => Codec::Ed25519Priv,
75 X25519_PUB => Codec::X25519Pub,
76 X25519_PRIV => Codec::X25519Priv,
77 SECP256K1_PUB => Codec::Secp256k1Pub,
78 SECP256K1_PRIV => Codec::Secp256k1Priv,
79 P256_PUB => Codec::P256Pub,
80 P256_PRIV => Codec::P256Priv,
81 P384_PUB => Codec::P384Pub,
82 P384_PRIV => Codec::P384Priv,
83 P521_PUB => Codec::P521Pub,
84 P521_PRIV => Codec::P521Priv,
85 ML_DSA_44_PUB => Codec::MlDsa44Pub,
86 ML_DSA_44_PRIV_SEED => Codec::MlDsa44PrivSeed,
87 ML_DSA_65_PUB => Codec::MlDsa65Pub,
88 ML_DSA_65_PRIV_SEED => Codec::MlDsa65PrivSeed,
89 ML_DSA_87_PUB => Codec::MlDsa87Pub,
90 ML_DSA_87_PRIV_SEED => Codec::MlDsa87PrivSeed,
91 SLH_DSA_SHA2_128S_PUB => Codec::SlhDsaSha2_128sPub,
92 other => Codec::Unknown(other),
93 }
94 }
95
96 pub fn to_u64(self) -> u64 {
98 match self {
99 Codec::Ed25519Pub => ED25519_PUB,
100 Codec::Ed25519Priv => ED25519_PRIV,
101 Codec::X25519Pub => X25519_PUB,
102 Codec::X25519Priv => X25519_PRIV,
103 Codec::Secp256k1Pub => SECP256K1_PUB,
104 Codec::Secp256k1Priv => SECP256K1_PRIV,
105 Codec::P256Pub => P256_PUB,
106 Codec::P256Priv => P256_PRIV,
107 Codec::P384Pub => P384_PUB,
108 Codec::P384Priv => P384_PRIV,
109 Codec::P521Pub => P521_PUB,
110 Codec::P521Priv => P521_PRIV,
111 Codec::MlDsa44Pub => ML_DSA_44_PUB,
112 Codec::MlDsa44PrivSeed => ML_DSA_44_PRIV_SEED,
113 Codec::MlDsa65Pub => ML_DSA_65_PUB,
114 Codec::MlDsa65PrivSeed => ML_DSA_65_PRIV_SEED,
115 Codec::MlDsa87Pub => ML_DSA_87_PUB,
116 Codec::MlDsa87PrivSeed => ML_DSA_87_PRIV_SEED,
117 Codec::SlhDsaSha2_128sPub => SLH_DSA_SHA2_128S_PUB,
118 Codec::Unknown(v) => v,
119 }
120 }
121
122 pub fn is_public(&self) -> bool {
124 matches!(
125 self,
126 Codec::Ed25519Pub
127 | Codec::X25519Pub
128 | Codec::Secp256k1Pub
129 | Codec::P256Pub
130 | Codec::P384Pub
131 | Codec::P521Pub
132 | Codec::MlDsa44Pub
133 | Codec::MlDsa65Pub
134 | Codec::MlDsa87Pub
135 | Codec::SlhDsaSha2_128sPub )
137 }
138
139 pub fn expected_key_length(&self) -> Option<usize> {
141 match self {
142 Codec::Ed25519Pub | Codec::Ed25519Priv => Some(32),
143 Codec::X25519Pub | Codec::X25519Priv => Some(32),
144 Codec::Secp256k1Pub => Some(33), Codec::P256Pub => Some(33), Codec::P384Pub => Some(49), Codec::P521Pub => Some(67), Codec::MlDsa44Pub => Some(1312),
150 Codec::MlDsa65Pub => Some(1952),
151 Codec::MlDsa87Pub => Some(2592),
152 Codec::MlDsa44PrivSeed | Codec::MlDsa65PrivSeed | Codec::MlDsa87PrivSeed => Some(32),
154 Codec::SlhDsaSha2_128sPub => Some(32),
156 _ => None,
157 }
158 }
159}
160
161#[derive(Zeroize, ZeroizeOnDrop)]
167#[repr(transparent)]
168pub struct MultiEncoded([u8]);
169
170impl MultiEncoded {
171 pub fn new(bytes: &[u8]) -> Result<&Self, EncodingError> {
174 unsigned_varint::decode::u64(bytes)
175 .map_err(|e| EncodingError::InvalidMulticodec(format!("varint decode: {e}")))?;
176
177 Ok(unsafe { &*(bytes as *const [u8] as *const MultiEncoded) })
183 }
184
185 pub fn len(&self) -> usize {
187 self.0.len()
188 }
189
190 pub fn is_empty(&self) -> bool {
192 self.0.is_empty()
193 }
194
195 pub fn parts(&self) -> (u64, &[u8]) {
197 unsigned_varint::decode::u64(&self.0).unwrap()
198 }
199
200 pub fn codec(&self) -> u64 {
202 self.parts().0
203 }
204
205 pub fn codec_type(&self) -> Codec {
207 Codec::from_u64(self.codec())
208 }
209
210 pub fn data(&self) -> &[u8] {
212 self.parts().1
213 }
214
215 pub fn as_bytes(&self) -> &[u8] {
217 &self.0
218 }
219}
220
221#[derive(Clone, Zeroize, ZeroizeOnDrop)]
223pub struct MultiEncodedBuf(Vec<u8>);
224
225impl MultiEncodedBuf {
226 pub fn new(bytes: Vec<u8>) -> Result<Self, EncodingError> {
228 unsigned_varint::decode::u64(&bytes)
229 .map_err(|e| EncodingError::InvalidMulticodec(format!("varint decode: {e}")))?;
230 Ok(Self(bytes))
231 }
232
233 pub fn encode(codec: Codec, bytes: &[u8]) -> Self {
235 Self::encode_raw(codec.to_u64(), bytes)
236 }
237
238 pub fn encode_bytes(codec: u64, bytes: &[u8]) -> Self {
240 Self::encode_raw(codec, bytes)
241 }
242
243 pub fn encode_raw(codec: u64, bytes: &[u8]) -> Self {
245 let mut codec_buffer = [0u8; 10];
246 let encoded_codec = unsigned_varint::encode::u64(codec, &mut codec_buffer);
247 let mut result = Vec::with_capacity(encoded_codec.len() + bytes.len());
248 result.extend(encoded_codec);
249 result.extend(bytes);
250 Self(result)
251 }
252
253 pub fn into_bytes(self) -> Vec<u8> {
256 self.0.clone()
257 }
258
259 pub fn as_bytes(&self) -> &[u8] {
261 &self.0
262 }
263
264 pub fn as_multi_encoded(&self) -> &MultiEncoded {
266 unsafe { &*(self.0.as_slice() as *const [u8] as *const MultiEncoded) }
270 }
271}
272
273impl AsRef<MultiEncoded> for MultiEncodedBuf {
274 fn as_ref(&self) -> &MultiEncoded {
275 self.as_multi_encoded()
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_encode_decode_ed25519() {
285 let key_bytes = [0u8; 32];
286 let encoded = MultiEncodedBuf::encode(Codec::Ed25519Pub, &key_bytes);
287
288 let decoded = MultiEncoded::new(encoded.as_bytes()).unwrap();
289 assert_eq!(decoded.codec(), ED25519_PUB);
290 assert_eq!(decoded.codec_type(), Codec::Ed25519Pub);
291 assert_eq!(decoded.data(), &key_bytes);
292 }
293
294 #[test]
295 fn test_codec_roundtrip() {
296 for codec in [
297 Codec::Ed25519Pub,
298 Codec::X25519Pub,
299 Codec::P256Pub,
300 Codec::P384Pub,
301 ] {
302 let raw = codec.to_u64();
303 assert_eq!(Codec::from_u64(raw), codec);
304 }
305 }
306}