solid_pod_rs_didkey/
pubkey.rs1use crate::error::DidKeyError;
16
17pub const CODEC_ED25519: u64 = 0xed;
19
20pub const CODEC_SECP256K1: u64 = 0xe7;
22
23pub const CODEC_P256: u64 = 0x1200;
25
26pub const ED25519_LEN: usize = 32;
28
29pub const SEC1_COMPRESSED_LEN: usize = 33;
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34pub enum DidKeyPubkey {
35 Ed25519([u8; ED25519_LEN]),
37
38 P256(Vec<u8>),
40
41 Secp256k1(Vec<u8>),
43}
44
45impl DidKeyPubkey {
46 pub fn codec_name(&self) -> &'static str {
48 match self {
49 DidKeyPubkey::Ed25519(_) => "ed25519",
50 DidKeyPubkey::P256(_) => "p-256",
51 DidKeyPubkey::Secp256k1(_) => "secp256k1",
52 }
53 }
54
55 pub fn codec_code(&self) -> u64 {
57 match self {
58 DidKeyPubkey::Ed25519(_) => CODEC_ED25519,
59 DidKeyPubkey::P256(_) => CODEC_P256,
60 DidKeyPubkey::Secp256k1(_) => CODEC_SECP256K1,
61 }
62 }
63
64 pub fn jws_alg(&self) -> &'static str {
68 match self {
69 DidKeyPubkey::Ed25519(_) => "EdDSA",
70 DidKeyPubkey::P256(_) => "ES256",
71 DidKeyPubkey::Secp256k1(_) => "ES256K",
72 }
73 }
74
75 pub fn as_bytes(&self) -> &[u8] {
77 match self {
78 DidKeyPubkey::Ed25519(b) => b.as_slice(),
79 DidKeyPubkey::P256(v) => v.as_slice(),
80 DidKeyPubkey::Secp256k1(v) => v.as_slice(),
81 }
82 }
83
84 pub fn to_multicodec_bytes(&self) -> Vec<u8> {
88 let mut buf = [0u8; 10]; let varint = unsigned_varint::encode::u64(self.codec_code(), &mut buf);
90 let mut out = Vec::with_capacity(varint.len() + self.as_bytes().len());
91 out.extend_from_slice(varint);
92 out.extend_from_slice(self.as_bytes());
93 out
94 }
95
96 pub fn from_multicodec_bytes(bytes: &[u8]) -> Result<Self, DidKeyError> {
99 let (code, rest) = unsigned_varint::decode::u64(bytes)
100 .map_err(|e| DidKeyError::InvalidMultibase(format!("varint: {e}")))?;
101 match code {
102 CODEC_ED25519 => {
103 if rest.len() != ED25519_LEN {
104 return Err(DidKeyError::InvalidKeyLength {
105 codec: "ed25519",
106 expected: ED25519_LEN,
107 actual: rest.len(),
108 });
109 }
110 let mut arr = [0u8; ED25519_LEN];
111 arr.copy_from_slice(rest);
112 Ok(DidKeyPubkey::Ed25519(arr))
113 }
114 CODEC_P256 => {
115 if rest.len() != SEC1_COMPRESSED_LEN {
116 return Err(DidKeyError::InvalidKeyLength {
117 codec: "p-256",
118 expected: SEC1_COMPRESSED_LEN,
119 actual: rest.len(),
120 });
121 }
122 Ok(DidKeyPubkey::P256(rest.to_vec()))
123 }
124 CODEC_SECP256K1 => {
125 if rest.len() != SEC1_COMPRESSED_LEN {
126 return Err(DidKeyError::InvalidKeyLength {
127 codec: "secp256k1",
128 expected: SEC1_COMPRESSED_LEN,
129 actual: rest.len(),
130 });
131 }
132 Ok(DidKeyPubkey::Secp256k1(rest.to_vec()))
133 }
134 other => Err(DidKeyError::UnknownCodec(other)),
135 }
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn ed25519_roundtrip_multicodec() {
145 let k = DidKeyPubkey::Ed25519([7u8; ED25519_LEN]);
146 let bytes = k.to_multicodec_bytes();
147 let out = DidKeyPubkey::from_multicodec_bytes(&bytes).unwrap();
148 assert_eq!(k, out);
149 assert_eq!(k.jws_alg(), "EdDSA");
150 }
151
152 #[test]
153 fn p256_roundtrip_multicodec() {
154 let mut sec1 = vec![0x02; SEC1_COMPRESSED_LEN];
155 sec1[0] = 0x02; let k = DidKeyPubkey::P256(sec1);
157 let bytes = k.to_multicodec_bytes();
158 let out = DidKeyPubkey::from_multicodec_bytes(&bytes).unwrap();
159 assert_eq!(k, out);
160 assert_eq!(k.jws_alg(), "ES256");
161 }
162
163 #[test]
164 fn secp256k1_roundtrip_multicodec() {
165 let mut sec1 = vec![0x02; SEC1_COMPRESSED_LEN];
166 sec1[0] = 0x03;
167 let k = DidKeyPubkey::Secp256k1(sec1);
168 let bytes = k.to_multicodec_bytes();
169 let out = DidKeyPubkey::from_multicodec_bytes(&bytes).unwrap();
170 assert_eq!(k, out);
171 assert_eq!(k.jws_alg(), "ES256K");
172 }
173
174 #[test]
175 fn rejects_unknown_codec() {
176 let payload = vec![0xff, 0xff, 0x03, 1, 2, 3];
178 let err = DidKeyPubkey::from_multicodec_bytes(&payload).unwrap_err();
179 assert!(matches!(err, DidKeyError::UnknownCodec(_)));
180 }
181
182 #[test]
183 fn rejects_wrong_ed25519_length() {
184 let mut buf = [0u8; 10];
185 let varint = unsigned_varint::encode::u64(CODEC_ED25519, &mut buf);
186 let mut payload = varint.to_vec();
187 payload.extend_from_slice(&[0u8; 16]); let err = DidKeyPubkey::from_multicodec_bytes(&payload).unwrap_err();
189 assert!(matches!(err, DidKeyError::InvalidKeyLength { .. }));
190 }
191}