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;
28pub const BLS12381_G1_PUB: u64 = 0xea;
31pub const BLS12381_G2_PUB: u64 = 0xeb;
32
33pub const ML_DSA_44_PUB: u64 = 0x1210;
41pub const ML_DSA_44_PRIV_SEED: u64 = 0x131a;
42pub const ML_DSA_65_PUB: u64 = 0x1211;
43pub const ML_DSA_65_PRIV_SEED: u64 = 0x131b;
44pub const ML_DSA_87_PUB: u64 = 0x1212;
45pub const ML_DSA_87_PRIV_SEED: u64 = 0x131c;
46pub const SLH_DSA_SHA2_128S_PUB: u64 = 0x1220;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
50pub enum Codec {
51 Ed25519Pub,
52 Ed25519Priv,
53 X25519Pub,
54 X25519Priv,
55 Secp256k1Pub,
56 Secp256k1Priv,
57 P256Pub,
58 P256Priv,
59 P384Pub,
60 P384Priv,
61 P521Pub,
62 P521Priv,
63 Bls12381G1Pub,
64 Bls12381G2Pub,
65 MlDsa44Pub,
66 MlDsa44PrivSeed,
67 MlDsa65Pub,
68 MlDsa65PrivSeed,
69 MlDsa87Pub,
70 MlDsa87PrivSeed,
71 SlhDsaSha2_128sPub,
72 Unknown(u64),
73}
74
75impl Codec {
76 pub fn from_u64(value: u64) -> Self {
78 match value {
79 ED25519_PUB => Codec::Ed25519Pub,
80 ED25519_PRIV => Codec::Ed25519Priv,
81 X25519_PUB => Codec::X25519Pub,
82 X25519_PRIV => Codec::X25519Priv,
83 SECP256K1_PUB => Codec::Secp256k1Pub,
84 SECP256K1_PRIV => Codec::Secp256k1Priv,
85 P256_PUB => Codec::P256Pub,
86 P256_PRIV => Codec::P256Priv,
87 P384_PUB => Codec::P384Pub,
88 P384_PRIV => Codec::P384Priv,
89 P521_PUB => Codec::P521Pub,
90 P521_PRIV => Codec::P521Priv,
91 BLS12381_G1_PUB => Codec::Bls12381G1Pub,
92 BLS12381_G2_PUB => Codec::Bls12381G2Pub,
93 ML_DSA_44_PUB => Codec::MlDsa44Pub,
94 ML_DSA_44_PRIV_SEED => Codec::MlDsa44PrivSeed,
95 ML_DSA_65_PUB => Codec::MlDsa65Pub,
96 ML_DSA_65_PRIV_SEED => Codec::MlDsa65PrivSeed,
97 ML_DSA_87_PUB => Codec::MlDsa87Pub,
98 ML_DSA_87_PRIV_SEED => Codec::MlDsa87PrivSeed,
99 SLH_DSA_SHA2_128S_PUB => Codec::SlhDsaSha2_128sPub,
100 other => Codec::Unknown(other),
101 }
102 }
103
104 pub fn to_u64(self) -> u64 {
106 match self {
107 Codec::Ed25519Pub => ED25519_PUB,
108 Codec::Ed25519Priv => ED25519_PRIV,
109 Codec::X25519Pub => X25519_PUB,
110 Codec::X25519Priv => X25519_PRIV,
111 Codec::Secp256k1Pub => SECP256K1_PUB,
112 Codec::Secp256k1Priv => SECP256K1_PRIV,
113 Codec::P256Pub => P256_PUB,
114 Codec::P256Priv => P256_PRIV,
115 Codec::P384Pub => P384_PUB,
116 Codec::P384Priv => P384_PRIV,
117 Codec::P521Pub => P521_PUB,
118 Codec::P521Priv => P521_PRIV,
119 Codec::Bls12381G1Pub => BLS12381_G1_PUB,
120 Codec::Bls12381G2Pub => BLS12381_G2_PUB,
121 Codec::MlDsa44Pub => ML_DSA_44_PUB,
122 Codec::MlDsa44PrivSeed => ML_DSA_44_PRIV_SEED,
123 Codec::MlDsa65Pub => ML_DSA_65_PUB,
124 Codec::MlDsa65PrivSeed => ML_DSA_65_PRIV_SEED,
125 Codec::MlDsa87Pub => ML_DSA_87_PUB,
126 Codec::MlDsa87PrivSeed => ML_DSA_87_PRIV_SEED,
127 Codec::SlhDsaSha2_128sPub => SLH_DSA_SHA2_128S_PUB,
128 Codec::Unknown(v) => v,
129 }
130 }
131
132 pub fn is_public(&self) -> bool {
134 matches!(
135 self,
136 Codec::Ed25519Pub
137 | Codec::X25519Pub
138 | Codec::Secp256k1Pub
139 | Codec::P256Pub
140 | Codec::P384Pub
141 | Codec::P521Pub
142 | Codec::Bls12381G1Pub
143 | Codec::Bls12381G2Pub
144 | Codec::MlDsa44Pub
145 | Codec::MlDsa65Pub
146 | Codec::MlDsa87Pub
147 | Codec::SlhDsaSha2_128sPub )
149 }
150
151 pub fn expected_key_length(&self) -> Option<usize> {
153 match self {
154 Codec::Ed25519Pub | Codec::Ed25519Priv => Some(32),
155 Codec::X25519Pub | Codec::X25519Priv => Some(32),
156 Codec::Secp256k1Pub => Some(33), Codec::P256Pub => Some(33), Codec::P384Pub => Some(49), Codec::P521Pub => Some(67), Codec::Bls12381G1Pub => Some(48),
162 Codec::Bls12381G2Pub => Some(96),
163 Codec::MlDsa44Pub => Some(1312),
165 Codec::MlDsa65Pub => Some(1952),
166 Codec::MlDsa87Pub => Some(2592),
167 Codec::MlDsa44PrivSeed | Codec::MlDsa65PrivSeed | Codec::MlDsa87PrivSeed => Some(32),
169 Codec::SlhDsaSha2_128sPub => Some(32),
171 _ => None,
172 }
173 }
174}
175
176#[derive(Zeroize, ZeroizeOnDrop)]
182#[repr(transparent)]
183pub struct MultiEncoded([u8]);
184
185impl MultiEncoded {
186 pub fn new(bytes: &[u8]) -> Result<&Self, EncodingError> {
189 unsigned_varint::decode::u64(bytes)
190 .map_err(|e| EncodingError::InvalidMulticodec(format!("varint decode: {e}")))?;
191
192 Ok(unsafe { &*(bytes as *const [u8] as *const MultiEncoded) })
198 }
199
200 pub fn len(&self) -> usize {
202 self.0.len()
203 }
204
205 pub fn is_empty(&self) -> bool {
207 self.0.is_empty()
208 }
209
210 pub fn parts(&self) -> (u64, &[u8]) {
212 unsigned_varint::decode::u64(&self.0).unwrap()
213 }
214
215 pub fn codec(&self) -> u64 {
217 self.parts().0
218 }
219
220 pub fn codec_type(&self) -> Codec {
222 Codec::from_u64(self.codec())
223 }
224
225 pub fn data(&self) -> &[u8] {
227 self.parts().1
228 }
229
230 pub fn as_bytes(&self) -> &[u8] {
232 &self.0
233 }
234}
235
236#[derive(Clone, Zeroize, ZeroizeOnDrop)]
238pub struct MultiEncodedBuf(Vec<u8>);
239
240impl MultiEncodedBuf {
241 pub fn new(bytes: Vec<u8>) -> Result<Self, EncodingError> {
243 unsigned_varint::decode::u64(&bytes)
244 .map_err(|e| EncodingError::InvalidMulticodec(format!("varint decode: {e}")))?;
245 Ok(Self(bytes))
246 }
247
248 pub fn encode(codec: Codec, bytes: &[u8]) -> Self {
250 Self::encode_raw(codec.to_u64(), bytes)
251 }
252
253 pub fn encode_bytes(codec: u64, bytes: &[u8]) -> Self {
255 Self::encode_raw(codec, bytes)
256 }
257
258 pub fn encode_raw(codec: u64, bytes: &[u8]) -> Self {
260 let mut codec_buffer = [0u8; 10];
261 let encoded_codec = unsigned_varint::encode::u64(codec, &mut codec_buffer);
262 let mut result = Vec::with_capacity(encoded_codec.len() + bytes.len());
263 result.extend(encoded_codec);
264 result.extend(bytes);
265 Self(result)
266 }
267
268 pub fn into_bytes(self) -> Vec<u8> {
271 self.0.clone()
272 }
273
274 pub fn as_bytes(&self) -> &[u8] {
276 &self.0
277 }
278
279 pub fn as_multi_encoded(&self) -> &MultiEncoded {
281 unsafe { &*(self.0.as_slice() as *const [u8] as *const MultiEncoded) }
285 }
286}
287
288impl AsRef<MultiEncoded> for MultiEncodedBuf {
289 fn as_ref(&self) -> &MultiEncoded {
290 self.as_multi_encoded()
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn test_encode_decode_ed25519() {
300 let key_bytes = [0u8; 32];
301 let encoded = MultiEncodedBuf::encode(Codec::Ed25519Pub, &key_bytes);
302
303 let decoded = MultiEncoded::new(encoded.as_bytes()).unwrap();
304 assert_eq!(decoded.codec(), ED25519_PUB);
305 assert_eq!(decoded.codec_type(), Codec::Ed25519Pub);
306 assert_eq!(decoded.data(), &key_bytes);
307 }
308
309 #[test]
310 fn test_codec_roundtrip() {
311 for codec in [
312 Codec::Ed25519Pub,
313 Codec::X25519Pub,
314 Codec::P256Pub,
315 Codec::P384Pub,
316 ] {
317 let raw = codec.to_u64();
318 assert_eq!(Codec::from_u64(raw), codec);
319 }
320 }
321}