1use baseid_core::error::DidError;
9use baseid_crypto::{Jwk, PublicKey};
10
11use crate::document::{DidDocument, VerificationMethod, VerificationRelationship};
12use crate::resolution::{DidResolver, ResolutionMetadata, ResolutionResult};
13use crate::url::DidUrl;
14
15const DID_CONTEXT: &str = "https://www.w3.org/ns/did/v1";
17const MULTIKEY_CONTEXT: &str = "https://w3id.org/security/multikey/v1";
19const JWS_CONTEXT: &str = "https://w3id.org/security/suites/jws-2020/v1";
21
22pub struct DidKeyResolver;
24
25impl DidResolver for DidKeyResolver {
26 fn method(&self) -> &str {
27 "key"
28 }
29
30 async fn resolve(&self, did: &str) -> baseid_core::Result<ResolutionResult> {
31 let url = DidUrl::parse(did)?;
32 if url.method != "key" {
33 return Err(DidError::UnsupportedMethod.into());
34 }
35
36 let public_key =
38 PublicKey::from_multibase(&url.method_id).map_err(|_| DidError::ResolutionFailed)?;
39
40 let document = Self::create(&public_key)?;
41
42 Ok(ResolutionResult {
43 document: Some(document),
44 metadata: ResolutionMetadata {
45 content_type: Some("application/did+ld+json".to_string()),
46 error: None,
47 },
48 })
49 }
50}
51
52impl DidKeyResolver {
53 pub fn create(public_key: &PublicKey) -> baseid_core::Result<DidDocument> {
58 let multibase = public_key.to_multibase();
59 let did = format!("did:key:{multibase}");
60
61 let vm_id_multikey = format!("{did}#{multibase}");
63 let vm_multikey = VerificationMethod {
64 id: vm_id_multikey.clone(),
65 r#type: "Multikey".to_string(),
66 controller: did.clone(),
67 public_key_jwk: None,
68 public_key_multibase: Some(multibase),
69 };
70
71 let jwk = Jwk::from_public_key(public_key)?;
73 let jwk_value = serde_json::to_value(&jwk).map_err(|_| DidError::ResolutionFailed)?;
74 let vm_id_jwk = format!("{did}#jwk");
75 let vm_jwk = VerificationMethod {
76 id: vm_id_jwk.clone(),
77 r#type: "JsonWebKey2020".to_string(),
78 controller: did.clone(),
79 public_key_jwk: Some(jwk_value),
80 public_key_multibase: None,
81 };
82
83 Ok(DidDocument {
84 id: did,
85 context: vec![
86 DID_CONTEXT.to_string(),
87 MULTIKEY_CONTEXT.to_string(),
88 JWS_CONTEXT.to_string(),
89 ],
90 verification_method: vec![vm_multikey, vm_jwk],
91 authentication: vec![VerificationRelationship::Reference(vm_id_multikey.clone())],
92 assertion_method: vec![VerificationRelationship::Reference(vm_id_multikey)],
93 key_agreement: vec![],
94 service: vec![],
95 })
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use baseid_core::types::KeyType;
103 use baseid_crypto::KeyPair;
104
105 #[test]
106 fn create_ed25519() {
107 let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
108 let doc = DidKeyResolver::create(&kp.public).unwrap();
109
110 assert!(doc.id.starts_with("did:key:z6Mk"));
111 assert_eq!(doc.context.len(), 3);
112 assert_eq!(doc.context[0], DID_CONTEXT);
113 assert_eq!(doc.verification_method.len(), 2);
114 assert_eq!(doc.verification_method[0].r#type, "Multikey");
115 assert_eq!(doc.verification_method[1].r#type, "JsonWebKey2020");
116 assert_eq!(doc.authentication.len(), 1);
117 assert_eq!(doc.assertion_method.len(), 1);
118 }
119
120 #[test]
121 fn create_p256() {
122 let kp = KeyPair::generate(KeyType::P256).unwrap();
123 let doc = DidKeyResolver::create(&kp.public).unwrap();
124
125 assert!(doc.id.starts_with("did:key:z"));
126 assert_eq!(doc.verification_method.len(), 2);
127
128 let jwk_vm = &doc.verification_method[1];
130 let jwk = jwk_vm.public_key_jwk.as_ref().unwrap();
131 assert_eq!(jwk["crv"], "P-256");
132 assert_eq!(jwk["kty"], "EC");
133 }
134
135 #[test]
136 fn create_p384() {
137 let kp = KeyPair::generate(KeyType::P384).unwrap();
138 let doc = DidKeyResolver::create(&kp.public).unwrap();
139
140 assert!(doc.id.starts_with("did:key:z"));
141 let jwk_vm = &doc.verification_method[1];
142 let jwk = jwk_vm.public_key_jwk.as_ref().unwrap();
143 assert_eq!(jwk["crv"], "P-384");
144 }
145
146 #[test]
147 fn create_secp256k1() {
148 let kp = KeyPair::generate(KeyType::Secp256k1).unwrap();
149 let doc = DidKeyResolver::create(&kp.public).unwrap();
150
151 assert!(doc.id.starts_with("did:key:z"));
152 let jwk_vm = &doc.verification_method[1];
153 let jwk = jwk_vm.public_key_jwk.as_ref().unwrap();
154 assert_eq!(jwk["crv"], "secp256k1");
155 }
156
157 #[tokio::test]
158 async fn resolve_ed25519() {
159 let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
160 let created = DidKeyResolver::create(&kp.public).unwrap();
161
162 let resolver = DidKeyResolver;
163 let result = resolver.resolve(&created.id).await.unwrap();
164 let resolved = result.document.unwrap();
165
166 assert_eq!(resolved.id, created.id);
167 assert_eq!(resolved.verification_method.len(), 2);
168 assert_eq!(
169 result.metadata.content_type.as_deref(),
170 Some("application/did+ld+json")
171 );
172 }
173
174 #[tokio::test]
175 async fn resolve_roundtrip_all_key_types() {
176 for key_type in [
177 KeyType::Ed25519,
178 KeyType::P256,
179 KeyType::P384,
180 KeyType::Secp256k1,
181 ] {
182 let kp = KeyPair::generate(key_type).unwrap();
183 let created = DidKeyResolver::create(&kp.public).unwrap();
184
185 let resolver = DidKeyResolver;
186 let result = resolver.resolve(&created.id).await.unwrap();
187 let resolved = result.document.unwrap();
188
189 assert_eq!(resolved.id, created.id);
190 assert_eq!(resolved.verification_method.len(), 2);
191
192 let mb = resolved.verification_method[0]
194 .public_key_multibase
195 .as_ref()
196 .unwrap();
197 let decoded = PublicKey::from_multibase(mb).unwrap();
198 assert_eq!(decoded.bytes, kp.public.bytes);
199 assert_eq!(decoded.key_type, kp.public.key_type);
200 }
201 }
202
203 #[tokio::test]
204 async fn resolve_known_test_vector() {
205 let did = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
207 let resolver = DidKeyResolver;
208 let result = resolver.resolve(did).await.unwrap();
209 let doc = result.document.unwrap();
210
211 assert_eq!(doc.id, did);
212 assert_eq!(doc.verification_method[0].r#type, "Multikey");
213 assert_eq!(
214 doc.verification_method[0].public_key_multibase.as_deref(),
215 Some("z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")
216 );
217 }
218
219 #[tokio::test]
220 async fn resolve_wrong_method_fails() {
221 let resolver = DidKeyResolver;
222 let result = resolver.resolve("did:web:example.com").await;
223 assert!(result.is_err());
224 }
225
226 #[tokio::test]
227 async fn resolve_invalid_did_fails() {
228 let resolver = DidKeyResolver;
229 assert!(resolver.resolve("not-a-did").await.is_err());
230 }
231
232 #[tokio::test]
233 async fn resolve_invalid_multibase_fails() {
234 let resolver = DidKeyResolver;
235 assert!(resolver.resolve("did:key:invalid!!!").await.is_err());
236 }
237
238 #[test]
239 fn document_serializes_to_json() {
240 let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
241 let doc = DidKeyResolver::create(&kp.public).unwrap();
242
243 let json = serde_json::to_string_pretty(&doc).unwrap();
244 assert!(json.contains("\"@context\""));
245 assert!(json.contains("\"verificationMethod\""));
246 assert!(json.contains("\"authentication\""));
247 assert!(json.contains("\"assertionMethod\""));
248 assert!(json.contains("\"Multikey\""));
249 assert!(json.contains("\"JsonWebKey2020\""));
250 }
251
252 #[test]
253 fn document_json_roundtrip() {
254 let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
255 let doc = DidKeyResolver::create(&kp.public).unwrap();
256
257 let json = serde_json::to_string(&doc).unwrap();
258 let deserialized: DidDocument = serde_json::from_str(&json).unwrap();
259
260 assert_eq!(deserialized.id, doc.id);
261 assert_eq!(deserialized.verification_method.len(), 2);
262 }
263
264 fn verify_did_key_vector(
269 key_type: KeyType,
270 secret: &[u8],
271 expected_public: &[u8],
272 expected_multibase: &str,
273 expected_did: &str,
274 ) {
275 let kp = KeyPair::from_bytes(key_type, secret).unwrap();
277 assert_eq!(&kp.public.bytes, expected_public, "public key mismatch");
278
279 let multibase = kp.public.to_multibase();
281 assert_eq!(multibase, expected_multibase, "multibase mismatch");
282
283 let doc = DidKeyResolver::create(&kp.public).unwrap();
285 assert_eq!(doc.id, expected_did, "DID string mismatch");
286
287 assert_eq!(
289 doc.verification_method[0].public_key_multibase.as_deref(),
290 Some(expected_multibase),
291 );
292
293 let decoded = PublicKey::from_multibase(expected_multibase).unwrap();
295 assert_eq!(decoded.key_type, key_type);
296 assert_eq!(decoded.bytes, expected_public);
297 }
298
299 #[test]
300 fn vector_ed25519() {
301 use baseid_test_vectors::did::vectors::ed25519;
302 verify_did_key_vector(
303 KeyType::Ed25519,
304 &ed25519::SECRET,
305 &ed25519::PUBLIC,
306 ed25519::MULTIBASE,
307 ed25519::DID,
308 );
309 }
310
311 #[test]
312 fn vector_p256() {
313 use baseid_test_vectors::did::vectors::p256;
314 verify_did_key_vector(
315 KeyType::P256,
316 &p256::SECRET,
317 &p256::PUBLIC,
318 p256::MULTIBASE,
319 p256::DID,
320 );
321 }
322
323 #[test]
324 fn vector_p384() {
325 use baseid_test_vectors::did::vectors::p384;
326 verify_did_key_vector(
327 KeyType::P384,
328 &p384::SECRET,
329 &p384::PUBLIC,
330 p384::MULTIBASE,
331 p384::DID,
332 );
333 }
334
335 #[test]
336 fn vector_secp256k1() {
337 use baseid_test_vectors::did::vectors::secp256k1;
338 verify_did_key_vector(
339 KeyType::Secp256k1,
340 &secp256k1::SECRET,
341 &secp256k1::PUBLIC,
342 secp256k1::MULTIBASE,
343 secp256k1::DID,
344 );
345 }
346
347 #[tokio::test]
348 async fn resolve_vector_ed25519() {
349 use baseid_test_vectors::did::vectors::ed25519;
350 let resolver = DidKeyResolver;
351 let result = resolver.resolve(ed25519::DID).await.unwrap();
352 let doc = result.document.unwrap();
353 assert_eq!(doc.id, ed25519::DID);
354
355 let mb = doc.verification_method[0]
357 .public_key_multibase
358 .as_ref()
359 .unwrap();
360 let pk = PublicKey::from_multibase(mb).unwrap();
361 assert_eq!(pk.bytes, ed25519::PUBLIC);
362 assert_eq!(pk.key_type, KeyType::Ed25519);
363 }
364
365 #[tokio::test]
366 async fn resolve_vector_p256() {
367 use baseid_test_vectors::did::vectors::p256;
368 let resolver = DidKeyResolver;
369 let result = resolver.resolve(p256::DID).await.unwrap();
370 let doc = result.document.unwrap();
371 assert_eq!(doc.id, p256::DID);
372
373 let mb = doc.verification_method[0]
374 .public_key_multibase
375 .as_ref()
376 .unwrap();
377 let pk = PublicKey::from_multibase(mb).unwrap();
378 assert_eq!(pk.bytes, p256::PUBLIC.to_vec());
379 assert_eq!(pk.key_type, KeyType::P256);
380
381 let jwk = doc.verification_method[1].public_key_jwk.as_ref().unwrap();
383 assert_eq!(jwk["crv"], "P-256");
384 }
385
386 #[tokio::test]
387 async fn resolve_vector_p384() {
388 use baseid_test_vectors::did::vectors::p384;
389 let resolver = DidKeyResolver;
390 let result = resolver.resolve(p384::DID).await.unwrap();
391 let doc = result.document.unwrap();
392 assert_eq!(doc.id, p384::DID);
393
394 let mb = doc.verification_method[0]
395 .public_key_multibase
396 .as_ref()
397 .unwrap();
398 let pk = PublicKey::from_multibase(mb).unwrap();
399 assert_eq!(pk.bytes, p384::PUBLIC.to_vec());
400
401 let jwk = doc.verification_method[1].public_key_jwk.as_ref().unwrap();
402 assert_eq!(jwk["crv"], "P-384");
403 }
404
405 #[tokio::test]
406 async fn resolve_vector_secp256k1() {
407 use baseid_test_vectors::did::vectors::secp256k1;
408 let resolver = DidKeyResolver;
409 let result = resolver.resolve(secp256k1::DID).await.unwrap();
410 let doc = result.document.unwrap();
411 assert_eq!(doc.id, secp256k1::DID);
412
413 let mb = doc.verification_method[0]
414 .public_key_multibase
415 .as_ref()
416 .unwrap();
417 let pk = PublicKey::from_multibase(mb).unwrap();
418 assert_eq!(pk.bytes, secp256k1::PUBLIC.to_vec());
419
420 let jwk = doc.verification_method[1].public_key_jwk.as_ref().unwrap();
421 assert_eq!(jwk["crv"], "secp256k1");
422 }
423}