1use crate::key_manager::{Secret, SecretMaterial, SecretType};
11#[cfg(not(target_arch = "wasm32"))]
12use async_trait::async_trait;
13use base64::Engine;
14#[cfg(feature = "crypto-ed25519")]
15use curve25519_dalek::edwards::CompressedEdwardsY;
16#[cfg(feature = "crypto-ed25519")]
17use ed25519_dalek::{SigningKey as Ed25519SigningKey, VerifyingKey as Ed25519VerifyingKey};
18#[cfg(feature = "crypto-secp256k1")]
19use k256::ecdsa::SigningKey as Secp256k1SigningKey;
20use multibase::{decode, encode, Base};
21#[cfg(feature = "crypto-p256")]
22use p256::ecdsa::SigningKey as P256SigningKey;
23#[cfg(any(
24 feature = "crypto-ed25519",
25 feature = "crypto-p256",
26 feature = "crypto-secp256k1"
27))]
28use rand::rngs::OsRng;
29use serde::{Deserialize, Serialize};
30use serde_json::Value;
31use std::collections::HashMap;
32use std::fmt::Debug;
33#[cfg(not(target_arch = "wasm32"))]
34use std::sync::{Arc, RwLock};
35use tracing::debug;
36#[cfg(not(target_arch = "wasm32"))]
37use tracing::warn;
38
39use crate::error::{Error, Result};
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
43pub struct DIDDoc {
44 pub id: String,
46
47 pub verification_method: Vec<VerificationMethod>,
49
50 pub authentication: Vec<String>,
52
53 pub key_agreement: Vec<String>,
55
56 #[serde(default)]
58 pub assertion_method: Vec<String>,
59
60 #[serde(default)]
62 pub capability_invocation: Vec<String>,
63
64 #[serde(default)]
66 pub capability_delegation: Vec<String>,
67
68 pub service: Vec<Service>,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
74pub struct Service {
75 pub id: String,
77
78 #[serde(rename = "type")]
80 pub type_: String,
81
82 pub service_endpoint: String,
84
85 #[serde(flatten)]
87 pub properties: HashMap<String, Value>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
92pub struct VerificationMethod {
93 pub id: String,
95
96 #[serde(rename = "type")]
98 pub type_: VerificationMethodType,
99
100 pub controller: String,
102
103 #[serde(flatten)]
105 pub verification_material: VerificationMaterial,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
110#[serde(rename_all = "camelCase")]
111pub enum VerificationMethodType {
112 Ed25519VerificationKey2018,
114
115 X25519KeyAgreementKey2019,
117
118 EcdsaSecp256k1VerificationKey2019,
120
121 JsonWebKey2020,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
127#[serde(untagged)]
128pub enum VerificationMaterial {
129 Base58 {
131 public_key_base58: String,
133 },
134
135 Multibase {
137 public_key_multibase: String,
139 },
140
141 JWK {
143 public_key_jwk: Value,
145 },
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum KeyType {
151 #[cfg(feature = "crypto-ed25519")]
153 Ed25519,
154 #[cfg(feature = "crypto-p256")]
156 P256,
157 #[cfg(feature = "crypto-secp256k1")]
159 Secp256k1,
160}
161
162#[derive(Debug, Clone)]
164pub struct GeneratedKey {
165 pub key_type: KeyType,
167 pub did: String,
169 pub public_key: Vec<u8>,
171 pub private_key: Vec<u8>,
173 pub did_doc: DIDDoc,
175}
176
177#[derive(Debug, Clone)]
179pub struct DIDGenerationOptions {
180 pub key_type: KeyType,
182}
183
184impl Default for DIDGenerationOptions {
185 fn default() -> Self {
186 Self {
187 #[cfg(feature = "crypto-ed25519")]
188 key_type: KeyType::Ed25519,
189 #[cfg(not(feature = "crypto-ed25519"))]
190 key_type: KeyType::P256, }
192 }
193}
194
195#[cfg(not(target_arch = "wasm32"))]
198#[async_trait]
199pub trait SyncDIDResolver: Send + Sync + Debug {
200 async fn resolve(&self, did: &str) -> Result<Option<DIDDoc>>;
208}
209
210#[cfg(not(target_arch = "wasm32"))]
213#[async_trait]
214#[cfg(not(target_arch = "wasm32"))]
215pub trait DIDMethodResolver: Send + Sync + Debug {
216 fn method(&self) -> &str;
218
219 async fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>>;
227}
228
229#[cfg(target_arch = "wasm32")]
231pub trait WasmDIDResolver: Debug {
232 fn resolve(&self, did: &str) -> Result<Option<DIDDoc>>;
234}
235
236#[cfg(target_arch = "wasm32")]
238pub trait WasmDIDMethodResolver: Debug {
239 fn method(&self) -> &str;
241
242 fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>>;
244
245 fn as_any(&self) -> &dyn std::any::Any;
247}
248
249#[derive(Debug, Default)]
251pub struct KeyResolver;
252
253impl KeyResolver {
254 pub fn new() -> Self {
256 Self
257 }
258
259 #[cfg(feature = "crypto-ed25519")]
264 fn ed25519_to_x25519(ed25519_pubkey: &[u8]) -> Option<[u8; 32]> {
265 if ed25519_pubkey.len() != 32 {
267 return None;
268 }
269
270 debug!("Ed25519 pubkey: {:?}", ed25519_pubkey);
272
273 let edwards_y = match CompressedEdwardsY::try_from(ed25519_pubkey) {
275 Ok(point) => point,
276 Err(e) => {
277 debug!("Error converting to Compressed EdwardsY: {:?}", e);
278 return None;
279 }
280 };
281
282 let edwards_point = match edwards_y.decompress() {
284 Some(point) => point,
285 None => {
286 debug!("Failed to decompress Edwards point");
287 return None;
288 }
289 };
290
291 let montgomery_point = edwards_point.to_montgomery();
293
294 Some(montgomery_point.to_bytes())
296 }
297}
298
299#[cfg(target_arch = "wasm32")]
300impl WasmDIDMethodResolver for KeyResolver {
301 fn method(&self) -> &str {
302 "key"
303 }
304
305 fn as_any(&self) -> &dyn std::any::Any {
306 self
307 }
308
309 fn resolve_method(&self, did_key: &str) -> Result<Option<DIDDoc>> {
310 if !did_key.starts_with("did:key:") {
313 return Ok(None);
314 }
315
316 let key_id = &did_key[8..]; let (_, key_bytes) = match decode(key_id) {
319 Ok(result) => result,
320 Err(_) => return Ok(None),
321 };
322
323 if key_bytes.len() < 2 {
325 return Ok(None);
326 }
327
328 if key_bytes[0] != 0xED || key_bytes[1] != 0x01 {
330 return Ok(None);
331 }
332
333 let ed25519_public_key = &key_bytes[2..];
335
336 let ed_vm_id = format!("{}#{}", did_key, key_id);
337
338 let ed_verification_method = VerificationMethod {
340 id: ed_vm_id.clone(),
341 type_: VerificationMethodType::Ed25519VerificationKey2018,
342 controller: did_key.to_string(),
343 verification_material: VerificationMaterial::Multibase {
344 public_key_multibase: key_id.to_string(),
345 },
346 };
347
348 let mut verification_methods = vec![ed_verification_method.clone()];
350 let mut key_agreement = Vec::new();
351
352 #[cfg(feature = "crypto-ed25519")]
353 if let Some(x25519_key) = Self::ed25519_to_x25519(ed25519_public_key) {
354 let mut x25519_bytes = vec![0xEC, 0x01]; x25519_bytes.extend_from_slice(&x25519_key);
357 let x25519_multibase = encode(Base::Base58Btc, x25519_bytes);
358
359 let x25519_vm_id = format!("{}#{}", did_key, x25519_multibase);
361
362 let x25519_verification_method = VerificationMethod {
364 id: x25519_vm_id.clone(),
365 type_: VerificationMethodType::X25519KeyAgreementKey2019,
366 controller: did_key.to_string(),
367 verification_material: VerificationMaterial::Multibase {
368 public_key_multibase: x25519_multibase,
369 },
370 };
371
372 verification_methods.push(x25519_verification_method);
374 key_agreement.push(x25519_vm_id);
375 }
376
377 let did_doc = DIDDoc {
379 id: did_key.to_string(),
380 verification_method: verification_methods,
381 authentication: vec![ed_vm_id],
382 key_agreement,
383 assertion_method: Vec::new(),
384 capability_invocation: Vec::new(),
385 capability_delegation: Vec::new(),
386 service: Vec::new(),
387 };
388
389 Ok(Some(did_doc))
390 }
391}
392
393#[cfg(not(target_arch = "wasm32"))]
394#[async_trait]
395impl DIDMethodResolver for KeyResolver {
396 fn method(&self) -> &str {
397 "key"
398 }
399
400 async fn resolve_method(&self, did_key: &str) -> Result<Option<DIDDoc>> {
401 if !did_key.starts_with("did:key:") {
403 return Ok(None);
404 }
405
406 let key_id = &did_key[8..]; let (_, key_bytes) = match decode(key_id) {
409 Ok(result) => result,
410 Err(_) => return Ok(None),
411 };
412
413 if key_bytes.len() < 2 {
415 return Ok(None);
416 }
417
418 if key_bytes[0] != 0xED || key_bytes[1] != 0x01 {
420 return Ok(None);
421 }
422
423 let ed25519_public_key = &key_bytes[2..];
425
426 let ed_vm_id = format!("{}#{}", did_key, key_id);
427
428 let ed_verification_method = VerificationMethod {
430 id: ed_vm_id.clone(),
431 type_: VerificationMethodType::Ed25519VerificationKey2018,
432 controller: did_key.to_string(),
433 verification_material: VerificationMaterial::Multibase {
434 public_key_multibase: key_id.to_string(),
435 },
436 };
437
438 let mut verification_methods = vec![ed_verification_method.clone()];
440 let mut key_agreement = Vec::new();
441
442 #[cfg(feature = "crypto-ed25519")]
443 if let Some(x25519_key) = Self::ed25519_to_x25519(ed25519_public_key) {
444 debug!("Successfully converted Ed25519 to X25519!");
445 let mut x25519_bytes = vec![0xEC, 0x01]; x25519_bytes.extend_from_slice(&x25519_key);
448 let x25519_multibase = encode(Base::Base58Btc, x25519_bytes);
449
450 let x25519_vm_id = format!("{}#{}", did_key, x25519_multibase);
452
453 let x25519_verification_method = VerificationMethod {
455 id: x25519_vm_id.clone(),
456 type_: VerificationMethodType::X25519KeyAgreementKey2019,
457 controller: did_key.to_string(),
458 verification_material: VerificationMaterial::Multibase {
459 public_key_multibase: x25519_multibase,
460 },
461 };
462
463 verification_methods.push(x25519_verification_method);
465 key_agreement.push(x25519_vm_id);
466 } else {
467 debug!("Failed to convert Ed25519 to X25519!");
468 }
469
470 let did_doc = DIDDoc {
472 id: did_key.to_string(),
473 verification_method: verification_methods,
474 authentication: vec![ed_vm_id],
475 key_agreement,
476 assertion_method: Vec::new(),
477 capability_invocation: Vec::new(),
478 capability_delegation: Vec::new(),
479 service: Vec::new(),
480 };
481
482 Ok(Some(did_doc))
483 }
484}
485
486#[derive(Debug)]
489#[cfg(not(target_arch = "wasm32"))]
490pub struct MultiResolver {
491 resolvers: RwLock<HashMap<String, Arc<dyn DIDMethodResolver>>>,
492}
493
494#[cfg(not(target_arch = "wasm32"))]
495unsafe impl Send for MultiResolver {}
496#[cfg(not(target_arch = "wasm32"))]
497unsafe impl Sync for MultiResolver {}
498
499#[cfg(not(target_arch = "wasm32"))]
500impl MultiResolver {
501 pub fn new() -> Self {
503 Self {
504 resolvers: RwLock::new(HashMap::new()),
505 }
506 }
507
508 pub fn new_with_resolvers(resolvers: Vec<Arc<dyn DIDMethodResolver>>) -> Self {
510 let resolver = Self::new();
511
512 if let Ok(mut resolver_map) = resolver.resolvers.write() {
514 for r in resolvers {
515 let method = r.method().to_string();
516 resolver_map.insert(method, r);
517 }
518 }
519
520 resolver
521 }
522
523 pub fn register_method<R>(&mut self, method: &str, resolver: R) -> &mut Self
525 where
526 R: DIDMethodResolver + Send + Sync + 'static,
527 {
528 if let Ok(mut resolvers) = self.resolvers.write() {
529 resolvers.insert(method.to_string(), Arc::new(resolver));
530 }
531 self
532 }
533}
534
535#[derive(Debug, Default)]
537pub struct WebResolver;
538
539impl WebResolver {
540 pub fn new() -> Self {
542 Self {}
543 }
544}
545
546#[cfg(target_arch = "wasm32")]
547impl WasmDIDMethodResolver for WebResolver {
548 fn method(&self) -> &str {
549 "web"
550 }
551
552 fn as_any(&self) -> &dyn std::any::Any {
553 self
554 }
555
556 fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>> {
557 let parts: Vec<&str> = did.split(':').collect();
560 if parts.len() < 3 || parts[0] != "did" || parts[1] != "web" {
561 return Err(Error::InvalidDID);
562 }
563
564 let verification_method = VerificationMethod {
566 id: format!("{}#keys-1", did),
567 type_: VerificationMethodType::Ed25519VerificationKey2018,
568 controller: did.to_string(),
569 verification_material: VerificationMaterial::Multibase {
570 public_key_multibase: "zMockPublicKey".to_string(),
571 },
572 };
573
574 let did_doc = DIDDoc {
575 id: did.to_string(),
576 verification_method: vec![verification_method.clone()],
577 authentication: vec![verification_method.id.clone()],
578 key_agreement: Vec::new(),
579 assertion_method: Vec::new(),
580 capability_invocation: Vec::new(),
581 capability_delegation: Vec::new(),
582 service: Vec::new(),
583 };
584
585 Ok(Some(did_doc))
586 }
587}
588
589#[cfg(not(target_arch = "wasm32"))]
590#[async_trait]
591impl DIDMethodResolver for WebResolver {
592 fn method(&self) -> &str {
593 "web"
594 }
595
596 async fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>> {
597 let parts: Vec<&str> = did.split(':').collect();
599 if parts.len() < 3 || parts[0] != "did" || parts[1] != "web" {
600 return Err(Error::InvalidDID);
601 }
602
603 let domain_path = parts[2..].join(":");
605 let domain_path = domain_path.replace("%3A", ":");
606
607 let url = if domain_path.contains(":") {
612 let path_segments: Vec<&str> = domain_path.split(':').collect();
614 let domain = path_segments[0];
615 let path = path_segments[1..].join("/");
616 format!("https://{}/{}/did.json", domain, path)
617 } else {
618 format!("https://{}/.well-known/did.json", domain_path)
620 };
621
622 #[cfg(feature = "native")]
624 {
625 use reqwest::Client;
626
627 let client = Client::new();
628 match client.get(&url).send().await {
629 Ok(response) => {
630 if response.status().is_success() {
631 match response.text().await {
632 Ok(text) => {
633 let parse_result = serde_json::from_str::<DIDDoc>(&text);
635 match parse_result {
636 Ok(doc) => {
637 if doc.id != did {
639 return Err(Error::DIDResolution(format!(
640 "DID Document ID ({}) does not match requested DID ({})",
641 doc.id, did
642 )));
643 }
644 Ok(Some(doc))
645 }
646 Err(parse_error) => {
647 match serde_json::from_str::<serde_json::Value>(&text) {
650 Ok(json_value) => {
651 let doc_id = match json_value.get("id") {
652 Some(id) => match id.as_str() {
653 Some(id_str) => id_str.to_string(),
654 None => return Err(Error::DIDResolution(
655 "DID Document has invalid 'id' field"
656 .to_string(),
657 )),
658 },
659 None => {
660 return Err(Error::DIDResolution(
661 "DID Document missing 'id' field"
662 .to_string(),
663 ))
664 }
665 };
666
667 if doc_id != did {
669 return Err(Error::DIDResolution(format!(
670 "DID Document ID ({}) does not match requested DID ({})",
671 doc_id, did
672 )));
673 }
674
675 warn!("Using partial DID document parsing due to format issues");
677 warn!("Original parse error: {}", parse_error);
678
679 let empty_vec = Vec::new();
682 let vm_array = json_value
683 .get("verificationMethod")
684 .and_then(|v| v.as_array())
685 .unwrap_or(&empty_vec);
686
687 let mut verification_methods = Vec::new();
689 for vm_value in vm_array {
690 if let Ok(vm) = serde_json::from_value::<
691 VerificationMethod,
692 >(
693 vm_value.clone()
694 ) {
695 verification_methods.push(vm);
696 }
697 }
698
699 let authentication = json_value
701 .get("authentication")
702 .and_then(|v| v.as_array())
703 .unwrap_or(&empty_vec)
704 .iter()
705 .filter_map(|v| {
706 v.as_str().map(|s| s.to_string())
707 })
708 .collect();
709
710 let key_agreement = json_value
712 .get("keyAgreement")
713 .and_then(|v| v.as_array())
714 .unwrap_or(&empty_vec)
715 .iter()
716 .filter_map(|v| {
717 v.as_str().map(|s| s.to_string())
718 })
719 .collect();
720
721 let services = Vec::new();
724
725 if let Some(svc_array) = json_value
727 .get("service")
728 .and_then(|v| v.as_array())
729 {
730 debug!("\nService endpoints (extracted from JSON):");
731 for (i, svc_value) in
732 svc_array.iter().enumerate()
733 {
734 if let (Some(id), Some(endpoint)) = (
735 svc_value
736 .get("id")
737 .and_then(|v| v.as_str()),
738 svc_value
739 .get("serviceEndpoint")
740 .and_then(|v| v.as_str()),
741 ) {
742 let type_value = svc_value
743 .get("type")
744 .and_then(|v| v.as_str())
745 .unwrap_or("Unknown");
746
747 debug!(" [{}] ID: {}", i + 1, id);
748 debug!(" Type: {}", type_value);
749 debug!(" Endpoint: {}", endpoint);
750 }
751 }
752 }
753
754 let simplified_doc = DIDDoc {
756 id: doc_id,
757 verification_method: verification_methods,
758 authentication,
759 key_agreement,
760 assertion_method: Vec::new(),
761 capability_invocation: Vec::new(),
762 capability_delegation: Vec::new(),
763 service: services,
764 };
765
766 Ok(Some(simplified_doc))
767 }
768 Err(_) => Err(Error::DIDResolution(format!(
769 "Failed to parse DID document from {}: {}",
770 url, parse_error
771 ))),
772 }
773 }
774 }
775 }
776 Err(e) => Err(Error::DIDResolution(format!(
777 "Failed to read response body from {}: {}",
778 url, e
779 ))),
780 }
781 } else if response.status().as_u16() == 404 {
782 Ok(None)
784 } else {
785 Err(Error::DIDResolution(format!(
786 "HTTP error fetching DID document from {}: {}",
787 url,
788 response.status()
789 )))
790 }
791 }
792 Err(e) => Err(Error::DIDResolution(format!(
793 "Failed to fetch DID document from {}: {}",
794 url, e
795 ))),
796 }
797 }
798
799 #[cfg(target_arch = "wasm32")]
800 {
801 use wasm_bindgen::JsValue;
802 use wasm_bindgen_futures::JsFuture;
803 use web_sys::{Headers, Request, RequestInit, RequestMode, Response};
804
805 let mut opts = RequestInit::new();
807 opts.method("GET");
808 opts.mode(RequestMode::Cors);
809
810 let request = match Request::new_with_str_and_init(&url, &opts) {
812 Ok(req) => req,
813 Err(e) => {
814 return Err(Error::DIDResolution(format!(
815 "Failed to create request for {}: {:?}",
816 url, e
817 )));
818 }
819 };
820
821 let headers = match Headers::new() {
823 Ok(h) => h,
824 Err(e) => {
825 return Err(Error::DIDResolution(format!(
826 "Failed to create headers: {:?}",
827 e
828 )));
829 }
830 };
831
832 if let Err(e) = headers.set("Accept", "application/json") {
833 return Err(Error::DIDResolution(format!(
834 "Failed to set Accept header: {:?}",
835 e
836 )));
837 }
838
839 if let Err(e) = request.headers().set("Accept", "application/json") {
840 return Err(Error::DIDResolution(format!(
841 "Failed to set Accept header: {:?}",
842 e
843 )));
844 }
845
846 let window = match web_sys::window() {
848 Some(w) => w,
849 None => {
850 return Err(Error::DIDResolution(
851 "No window object available".to_string(),
852 ));
853 }
854 };
855
856 let resp_value = match JsFuture::from(window.fetch_with_request(&request)).await {
858 Ok(response) => response,
859 Err(e) => {
860 return Err(Error::DIDResolution(format!(
861 "Failed to fetch DID document from {}: {:?}",
862 url, e
863 )));
864 }
865 };
866
867 let resp: Response = match resp_value.dyn_into() {
869 Ok(r) => r,
870 Err(_) => {
871 return Err(Error::DIDResolution(
872 "Failed to convert response".to_string(),
873 ));
874 }
875 };
876
877 if resp.ok() {
879 let text_promise = match resp.text() {
881 Ok(t) => t,
882 Err(e) => {
883 return Err(Error::DIDResolution(format!(
884 "Failed to get text from response: {:?}",
885 e
886 )));
887 }
888 };
889
890 let text_jsval = match JsFuture::from(text_promise).await {
891 Ok(t) => t,
892 Err(e) => {
893 return Err(Error::DIDResolution(format!(
894 "Failed to await text promise: {:?}",
895 e
896 )));
897 }
898 };
899
900 let text = match text_jsval.as_string() {
901 Some(t) => t,
902 None => {
903 return Err(Error::DIDResolution("Response is not a string".to_string()));
904 }
905 };
906
907 match serde_json::from_str::<DIDDoc>(&text) {
909 Ok(doc) => {
910 if doc.id != did {
912 return Err(Error::DIDResolution(format!(
913 "DID Document ID ({}) does not match requested DID ({})",
914 doc.id, did
915 )));
916 }
917 Ok(Some(doc))
918 }
919 Err(parse_error) => {
920 match serde_json::from_str::<serde_json::Value>(&text) {
923 Ok(json_value) => {
924 let doc_id = match json_value.get("id") {
925 Some(id) => match id.as_str() {
926 Some(id_str) => id_str.to_string(),
927 None => {
928 return Err(Error::DIDResolution(
929 "DID Document has invalid 'id' field".to_string(),
930 ))
931 }
932 },
933 None => {
934 return Err(Error::DIDResolution(
935 "DID Document missing 'id' field".to_string(),
936 ))
937 }
938 };
939
940 if doc_id != did {
942 return Err(Error::DIDResolution(format!(
943 "DID Document ID ({}) does not match requested DID ({})",
944 doc_id, did
945 )));
946 }
947
948 web_sys::console::log_1(&JsValue::from_str(
950 &format!("WARNING: Using partial DID document parsing due to format issues\nOriginal parse error: {}", parse_error)
951 ));
952
953 let empty_vec = Vec::new();
956 let vm_array = json_value
957 .get("verificationMethod")
958 .and_then(|v| v.as_array())
959 .unwrap_or(&empty_vec);
960
961 let mut verification_methods = Vec::new();
963 for vm_value in vm_array {
964 if let Ok(vm) = serde_json::from_value::<VerificationMethod>(
965 vm_value.clone(),
966 ) {
967 verification_methods.push(vm);
968 }
969 }
970
971 let authentication = json_value
973 .get("authentication")
974 .and_then(|v| v.as_array())
975 .unwrap_or(&empty_vec)
976 .iter()
977 .filter_map(|v| v.as_str().map(|s| s.to_string()))
978 .collect();
979
980 let key_agreement = json_value
982 .get("keyAgreement")
983 .and_then(|v| v.as_array())
984 .unwrap_or(&empty_vec)
985 .iter()
986 .filter_map(|v| v.as_str().map(|s| s.to_string()))
987 .collect();
988
989 let services = Vec::new();
991
992 if let Some(svc_array) =
994 json_value.get("service").and_then(|v| v.as_array())
995 {
996 web_sys::console::log_1(&JsValue::from_str(
997 "Service endpoints (extracted from JSON):",
998 ));
999 for (i, svc_value) in svc_array.iter().enumerate() {
1000 if let (Some(id), Some(endpoint)) = (
1001 svc_value.get("id").and_then(|v| v.as_str()),
1002 svc_value
1003 .get("serviceEndpoint")
1004 .and_then(|v| v.as_str()),
1005 ) {
1006 let type_value = svc_value
1007 .get("type")
1008 .and_then(|v| v.as_str())
1009 .unwrap_or("Unknown");
1010
1011 web_sys::console::log_1(&JsValue::from_str(&format!(
1012 "[{}] ID: {}
1013Type: {}
1014Endpoint: {}",
1015 i + 1,
1016 id,
1017 type_value,
1018 endpoint
1019 )));
1020 }
1021 }
1022 }
1023
1024 let simplified_doc = DIDDoc {
1026 id: doc_id,
1027 verification_method: verification_methods,
1028 authentication,
1029 key_agreement,
1030 assertion_method: Vec::new(),
1031 capability_invocation: Vec::new(),
1032 capability_delegation: Vec::new(),
1033 service: services,
1034 };
1035
1036 Ok(Some(simplified_doc))
1037 }
1038 Err(_) => Err(Error::DIDResolution(format!(
1039 "Failed to parse DID document from {}: {}",
1040 url, parse_error
1041 ))),
1042 }
1043 }
1044 }
1045 } else if resp.status() == 404 {
1046 Ok(None)
1048 } else {
1049 Err(Error::DIDResolution(format!(
1050 "HTTP error fetching DID document from {}: {}",
1051 url,
1052 resp.status()
1053 )))
1054 }
1055 }
1056
1057 #[cfg(all(not(target_arch = "wasm32"), not(feature = "native")))]
1058 {
1059 Err(Error::DIDResolution(
1060 "Web DID resolution requires the 'native' feature or WASM".to_string(),
1061 ))
1062 }
1063 }
1064}
1065
1066#[cfg(not(target_arch = "wasm32"))]
1067impl Default for MultiResolver {
1068 fn default() -> Self {
1069 let mut resolver = Self::new();
1070 resolver.register_method("key", KeyResolver::new());
1071 resolver.register_method("web", WebResolver::new());
1072 resolver
1073 }
1074}
1075
1076#[derive(Debug, Default, Clone)]
1078pub struct DIDKeyGenerator;
1079
1080impl DIDKeyGenerator {
1081 pub fn new() -> Self {
1083 Self
1084 }
1085
1086 pub fn create_secret_from_key(&self, key: &GeneratedKey) -> Secret {
1088 let kid = if key.did.starts_with("did:key:") {
1090 key.did_doc
1093 .verification_method
1094 .first()
1095 .map(|vm| vm.id.clone())
1096 .unwrap_or_else(|| {
1097 let multibase = key.did.strip_prefix("did:key:").unwrap_or("");
1099 format!("{}#{}", key.did, multibase)
1100 })
1101 } else if key.did.starts_with("did:web:") {
1102 format!("{}#keys-1", key.did)
1104 } else {
1105 format!("{}#key-1", key.did)
1107 };
1108
1109 match key.key_type {
1110 #[cfg(feature = "crypto-ed25519")]
1111 KeyType::Ed25519 => Secret {
1112 id: key.did.clone(),
1113 type_: SecretType::JsonWebKey2020,
1114 secret_material: SecretMaterial::JWK {
1115 private_key_jwk: serde_json::json!({
1116 "kty": "OKP",
1117 "kid": kid,
1118 "crv": "Ed25519",
1119 "x": base64::engine::general_purpose::STANDARD.encode(&key.public_key),
1120 "d": base64::engine::general_purpose::STANDARD.encode(&key.private_key)
1121 }),
1122 },
1123 },
1124 #[cfg(feature = "crypto-p256")]
1125 KeyType::P256 => Secret {
1126 id: key.did.clone(),
1127 type_: SecretType::JsonWebKey2020,
1128 secret_material: SecretMaterial::JWK {
1129 private_key_jwk: serde_json::json!({
1131 "kty": "EC",
1132 "kid": kid,
1133 "crv": "P-256",
1134 "x": base64::engine::general_purpose::STANDARD.encode(&key.public_key[1..33]),
1135 "y": base64::engine::general_purpose::STANDARD.encode(&key.public_key[33..65]),
1136 "d": base64::engine::general_purpose::STANDARD.encode(&key.private_key)
1137 }),
1138 },
1139 },
1140 #[cfg(feature = "crypto-secp256k1")]
1141 KeyType::Secp256k1 => Secret {
1142 id: key.did.clone(),
1143 type_: SecretType::JsonWebKey2020,
1144 secret_material: SecretMaterial::JWK {
1145 private_key_jwk: serde_json::json!({
1147 "kty": "EC",
1148 "kid": kid,
1149 "crv": "secp256k1",
1150 "x": base64::engine::general_purpose::STANDARD.encode(&key.public_key[1..33]),
1151 "y": base64::engine::general_purpose::STANDARD.encode(&key.public_key[33..65]),
1152 "d": base64::engine::general_purpose::STANDARD.encode(&key.private_key)
1153 }),
1154 },
1155 },
1156 }
1157 }
1158
1159 pub fn generate_did(&self, options: DIDGenerationOptions) -> Result<GeneratedKey> {
1161 match options.key_type {
1162 #[cfg(feature = "crypto-ed25519")]
1163 KeyType::Ed25519 => self.generate_ed25519_did(),
1164 #[cfg(feature = "crypto-p256")]
1165 KeyType::P256 => self.generate_p256_did(),
1166 #[cfg(feature = "crypto-secp256k1")]
1167 KeyType::Secp256k1 => self.generate_secp256k1_did(),
1168 }
1169 }
1170
1171 #[cfg(feature = "crypto-ed25519")]
1173 pub fn generate_ed25519_did(&self) -> Result<GeneratedKey> {
1174 let mut csprng = OsRng;
1176 let signing_key = Ed25519SigningKey::generate(&mut csprng);
1177 let verifying_key = Ed25519VerifyingKey::from(&signing_key);
1178
1179 let public_key = verifying_key.to_bytes().to_vec();
1181 let private_key = signing_key.to_bytes().to_vec();
1182
1183 let mut prefixed_key = vec![0xed, 0x01];
1186 prefixed_key.extend_from_slice(&public_key);
1187
1188 let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
1190 let did = format!("did:key:{}", multibase_encoded);
1191
1192 let doc = self.create_did_doc(&did, &prefixed_key, KeyType::Ed25519)?;
1194
1195 Ok(GeneratedKey {
1197 key_type: KeyType::Ed25519,
1198 did,
1199 public_key,
1200 private_key,
1201 did_doc: doc,
1202 })
1203 }
1204
1205 #[cfg(feature = "crypto-p256")]
1207 pub fn generate_p256_did(&self) -> Result<GeneratedKey> {
1208 let mut rng = OsRng;
1210 let signing_key = P256SigningKey::random(&mut rng);
1211
1212 let private_key = signing_key.to_bytes().to_vec();
1214 let public_key = signing_key
1215 .verifying_key()
1216 .to_encoded_point(false)
1217 .to_bytes()
1218 .to_vec();
1219
1220 let mut prefixed_key = vec![0x12, 0x00];
1223 prefixed_key.extend_from_slice(&public_key);
1224
1225 let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
1227 let did = format!("did:key:{}", multibase_encoded);
1228
1229 let doc = self.create_did_doc(&did, &prefixed_key, KeyType::P256)?;
1231
1232 Ok(GeneratedKey {
1234 key_type: KeyType::P256,
1235 did,
1236 public_key,
1237 private_key,
1238 did_doc: doc,
1239 })
1240 }
1241
1242 #[cfg(feature = "crypto-secp256k1")]
1244 pub fn generate_secp256k1_did(&self) -> Result<GeneratedKey> {
1245 let mut rng = OsRng;
1247 let signing_key = Secp256k1SigningKey::random(&mut rng);
1248
1249 let private_key = signing_key.to_bytes().to_vec();
1251 let public_key = signing_key
1252 .verifying_key()
1253 .to_encoded_point(false)
1254 .to_bytes()
1255 .to_vec();
1256
1257 let mut prefixed_key = vec![0xe7, 0x01];
1260 prefixed_key.extend_from_slice(&public_key);
1261
1262 let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
1264 let did = format!("did:key:{}", multibase_encoded);
1265
1266 let doc = self.create_did_doc(&did, &prefixed_key, KeyType::Secp256k1)?;
1268
1269 Ok(GeneratedKey {
1271 key_type: KeyType::Secp256k1,
1272 did,
1273 public_key,
1274 private_key,
1275 did_doc: doc,
1276 })
1277 }
1278
1279 pub fn generate_web_did(
1281 &self,
1282 domain: &str,
1283 options: DIDGenerationOptions,
1284 ) -> Result<GeneratedKey> {
1285 let key_did = self.generate_did(options)?;
1287
1288 let did = format!("did:web:{}", domain);
1290
1291 let verification_methods: Vec<VerificationMethod> = key_did
1293 .did_doc
1294 .verification_method
1295 .iter()
1296 .map(|vm| {
1297 let id = format!("{}#keys-1", did);
1298 VerificationMethod {
1299 id: id.clone(),
1300 type_: vm.type_.clone(),
1301 controller: did.clone(),
1302 verification_material: vm.verification_material.clone(),
1303 }
1304 })
1305 .collect();
1306
1307 let did_doc = DIDDoc {
1308 id: did.clone(),
1309 verification_method: verification_methods.clone(),
1310 authentication: verification_methods
1311 .iter()
1312 .map(|vm| vm.id.clone())
1313 .collect(),
1314 key_agreement: key_did.did_doc.key_agreement,
1315 assertion_method: Vec::new(),
1316 capability_invocation: Vec::new(),
1317 capability_delegation: Vec::new(),
1318 service: vec![],
1319 };
1320
1321 Ok(GeneratedKey {
1323 key_type: key_did.key_type,
1324 did,
1325 public_key: key_did.public_key,
1326 private_key: key_did.private_key,
1327 did_doc,
1328 })
1329 }
1330
1331 fn create_did_doc(
1333 &self,
1334 did: &str,
1335 prefixed_public_key: &[u8],
1336 key_type: KeyType,
1337 ) -> Result<DIDDoc> {
1338 let verification_method_type = match key_type {
1340 #[cfg(feature = "crypto-ed25519")]
1341 KeyType::Ed25519 => VerificationMethodType::Ed25519VerificationKey2018,
1342 #[cfg(feature = "crypto-p256")]
1343 KeyType::P256 => VerificationMethodType::EcdsaSecp256k1VerificationKey2019, #[cfg(feature = "crypto-secp256k1")]
1345 KeyType::Secp256k1 => VerificationMethodType::EcdsaSecp256k1VerificationKey2019,
1346 };
1347
1348 let multibase_encoded = encode(Base::Base58Btc, prefixed_public_key);
1350
1351 let vm_id = format!("{}#{}", did, multibase_encoded);
1353
1354 let verification_method = VerificationMethod {
1356 id: vm_id.clone(),
1357 type_: verification_method_type.clone(),
1358 controller: did.to_string(),
1359 verification_material: VerificationMaterial::Multibase {
1360 public_key_multibase: multibase_encoded.clone(),
1361 },
1362 };
1363
1364 let mut verification_methods = vec![verification_method.clone()];
1366 let mut key_agreement = Vec::new();
1367
1368 #[cfg(feature = "crypto-ed25519")]
1369 if key_type == KeyType::Ed25519 {
1370 if let Some(x25519_bytes) = self.ed25519_to_x25519(&prefixed_public_key[2..]) {
1372 let mut x25519_prefixed = vec![0xEC, 0x01];
1374 x25519_prefixed.extend_from_slice(&x25519_bytes);
1375
1376 let x25519_multibase = encode(Base::Base58Btc, &x25519_prefixed);
1378
1379 let x25519_vm_id = format!("{}#{}", did, x25519_multibase);
1381
1382 let x25519_verification_method = VerificationMethod {
1384 id: x25519_vm_id.clone(),
1385 type_: VerificationMethodType::X25519KeyAgreementKey2019,
1386 controller: did.to_string(),
1387 verification_material: VerificationMaterial::Multibase {
1388 public_key_multibase: x25519_multibase,
1389 },
1390 };
1391
1392 verification_methods.push(x25519_verification_method);
1394 key_agreement.push(x25519_vm_id);
1395 }
1396 }
1397
1398 let did_doc = DIDDoc {
1400 id: did.to_string(),
1401 verification_method: verification_methods,
1402 authentication: vec![vm_id.clone()],
1403 key_agreement,
1404 assertion_method: Vec::new(),
1405 capability_invocation: Vec::new(),
1406 capability_delegation: Vec::new(),
1407 service: vec![],
1408 };
1409
1410 Ok(did_doc)
1411 }
1412
1413 #[cfg(feature = "crypto-ed25519")]
1418 fn ed25519_to_x25519(&self, ed25519_pubkey: &[u8]) -> Option<[u8; 32]> {
1419 if ed25519_pubkey.len() != 32 {
1421 return None;
1422 }
1423
1424 let edwards_y = match CompressedEdwardsY::from_slice(ed25519_pubkey) {
1426 Ok(point) => point,
1427 Err(_) => return None,
1428 };
1429
1430 let edwards_point = edwards_y.decompress()?;
1432
1433 let montgomery_point = edwards_point.to_montgomery();
1435
1436 Some(montgomery_point.to_bytes())
1438 }
1439
1440 }
1442
1443#[derive(Debug)]
1444#[cfg(target_arch = "wasm32")]
1445pub struct MultiResolver {
1446 resolvers: HashMap<String, Box<dyn WasmDIDMethodResolver>>,
1448}
1449
1450#[cfg(target_arch = "wasm32")]
1451impl MultiResolver {
1452 pub fn new() -> Self {
1453 Self {
1454 resolvers: HashMap::new(),
1455 }
1456 }
1457
1458 pub fn default() -> Self {
1459 let mut resolver = Self::new();
1460 resolver.add_resolver(Box::new(KeyResolver::new()));
1462 resolver
1463 }
1464
1465 pub fn add_resolver(&mut self, resolver: Box<dyn WasmDIDMethodResolver>) {
1466 self.resolvers
1467 .insert(resolver.method().to_string(), resolver);
1468 }
1469}
1470
1471#[cfg(target_arch = "wasm32")]
1472impl WasmDIDResolver for MultiResolver {
1473 fn resolve(&self, did: &str) -> Result<Option<DIDDoc>> {
1474 let parts: Vec<&str> = did.split(':').collect();
1476 if parts.len() < 3 {
1477 return Err(Error::InvalidDID);
1478 }
1479
1480 let method = parts[1];
1481
1482 if let Some(resolver) = self.resolvers.get(method) {
1484 resolver.resolve_method(did)
1485 } else {
1486 Err(Error::UnsupportedDIDMethod(format!(
1487 "Method {} is not a WasmDIDMethodResolver",
1488 method
1489 )))
1490 }
1491 }
1492}
1493
1494#[cfg(not(target_arch = "wasm32"))]
1495#[async_trait]
1496#[cfg(not(target_arch = "wasm32"))]
1497impl SyncDIDResolver for MultiResolver {
1498 async fn resolve(&self, did: &str) -> Result<Option<DIDDoc>> {
1499 let parts: Vec<&str> = did.split(':').collect();
1501 if parts.len() < 3 {
1502 return Err(Error::InvalidDID);
1503 }
1504
1505 let method = parts[1];
1506
1507 let resolver = {
1509 let resolver_guard = self
1510 .resolvers
1511 .read()
1512 .map_err(|_| Error::FailedToAcquireResolverReadLock)?;
1513 if let Some(resolver) = resolver_guard.get(method) {
1514 resolver.clone()
1515 } else {
1516 return Err(Error::UnsupportedDIDMethod(method.to_string()));
1517 }
1518 };
1520
1521 resolver.resolve_method(did).await
1523 }
1524}
1525
1526#[cfg(target_arch = "wasm32")]
1529use wasm_bindgen::prelude::*;
1530
1531#[cfg(target_arch = "wasm32")]
1532use js_sys::Function;
1533
1534#[cfg(target_arch = "wasm32")]
1535#[wasm_bindgen]
1536extern "C" {
1537 #[wasm_bindgen(typescript_type = "Promise<string>")]
1538 pub type JsPromiseString;
1539
1540 #[wasm_bindgen(typescript_type = "Promise<string | null>")]
1541 pub type JsPromiseStringOrNull;
1542}
1543
1544#[cfg(target_arch = "wasm32")]
1545#[wasm_bindgen]
1546pub struct JsDIDResolver {
1547 resolve_fn: Function,
1548}
1549
1550#[cfg(target_arch = "wasm32")]
1551#[wasm_bindgen]
1552impl JsDIDResolver {
1553 #[wasm_bindgen(constructor)]
1554 pub fn new(resolve_fn: Function) -> Self {
1555 Self { resolve_fn }
1556 }
1557
1558 #[wasm_bindgen]
1559 pub fn method(&self) -> String {
1560 let this = JsValue::null();
1562 let method = self
1563 .resolve_fn
1564 .call1(&this, &JsValue::from_str("method"))
1565 .unwrap_or_else(|_| JsValue::from_str("unknown"));
1566
1567 method.as_string().unwrap_or_else(|| "unknown".to_string())
1568 }
1569}
1570
1571#[cfg(target_arch = "wasm32")]
1576#[derive(Debug)]
1577pub struct JsDIDMethodResolver {
1578 method: String,
1579 #[allow(dead_code)] resolve_fn: Function,
1581}
1582
1583#[cfg(target_arch = "wasm32")]
1584impl JsDIDMethodResolver {
1585 pub fn new(method: &str, resolve_fn: Function) -> Self {
1587 Self {
1588 method: method.to_string(),
1589 resolve_fn,
1590 }
1591 }
1592}
1593
1594#[cfg(target_arch = "wasm32")]
1595impl WasmDIDMethodResolver for JsDIDMethodResolver {
1596 fn method(&self) -> &str {
1597 &self.method
1598 }
1599
1600 fn as_any(&self) -> &dyn std::any::Any {
1601 self
1602 }
1603
1604 fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>> {
1605 let parts: Vec<&str> = did.split(':').collect();
1607 if parts.len() < 3 || parts[1] != self.method {
1608 return Err(Error::InvalidDID);
1609 }
1610
1611 Err(Error::NotImplemented(
1615 "JS resolver not supported in this context".to_string(),
1616 ))
1617 }
1618
1619 #[cfg(not(feature = "wasm"))]
1620 async fn resolve_method(&self, _did: &str) -> Result<Option<DIDDoc>> {
1621 Err(Error::NotImplemented(
1622 "JavaScript DID Method resolver is only available with the 'wasm' feature".to_string(),
1623 ))
1624 }
1625}
1626
1627#[cfg(test)]
1628mod tests {
1629 use super::*;
1630
1631 #[cfg(feature = "native")]
1632 #[tokio::test]
1633 async fn test_key_resolver() {
1634 let resolver = KeyResolver::new();
1635
1636 let did = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
1638 let result = resolver.resolve_method(did).await.unwrap();
1639
1640 assert!(result.is_some());
1641 let doc = result.unwrap();
1642
1643 assert_eq!(doc.id, did);
1644 assert_eq!(doc.verification_method.len(), 2); let ed25519_method = doc
1648 .verification_method
1649 .iter()
1650 .find(|vm| matches!(vm.type_, VerificationMethodType::Ed25519VerificationKey2018))
1651 .expect("Should have an Ed25519 verification method");
1652
1653 let x25519_method = doc
1655 .verification_method
1656 .iter()
1657 .find(|vm| matches!(vm.type_, VerificationMethodType::X25519KeyAgreementKey2019))
1658 .expect("Should have an X25519 key agreement method");
1659
1660 assert!(doc.authentication.contains(&ed25519_method.id));
1662
1663 assert!(doc.key_agreement.contains(&x25519_method.id));
1665 }
1666
1667 #[cfg(feature = "native")]
1668 #[tokio::test]
1669 async fn test_multi_resolver() {
1670 let resolver = MultiResolver::default();
1671
1672 let did = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
1674 let result = <MultiResolver as SyncDIDResolver>::resolve(&resolver, did).await;
1675
1676 assert!(result.is_ok());
1677 let doc_option = result.unwrap();
1678 assert!(doc_option.is_some());
1679
1680 let doc = doc_option.unwrap();
1681 assert_eq!(doc.id, did);
1682 assert_eq!(doc.verification_method.len(), 2); let did = "did:unsupported:123";
1686 let result = <MultiResolver as SyncDIDResolver>::resolve(&resolver, did).await;
1687
1688 assert!(result.is_err());
1690 let err = result.unwrap_err();
1691 assert!(err.to_string().contains("Unsupported DID method"));
1692 }
1693
1694 #[test]
1695 fn test_did_key_generator_ed25519() {
1696 let generator = DIDKeyGenerator::new();
1697
1698 let options = DIDGenerationOptions {
1700 key_type: KeyType::Ed25519,
1701 };
1702
1703 let key_result = generator.generate_did(options);
1704 assert!(key_result.is_ok());
1705
1706 let key = key_result.unwrap();
1707
1708 assert!(key.did.starts_with("did:key:z"));
1710
1711 assert_eq!(key.public_key.len(), 32); assert_eq!(key.private_key.len(), 32); assert_eq!(key.did_doc.id, key.did);
1717 assert_eq!(key.did_doc.verification_method.len(), 2); let ed25519_method = key
1721 .did_doc
1722 .verification_method
1723 .iter()
1724 .find(|vm| matches!(vm.type_, VerificationMethodType::Ed25519VerificationKey2018))
1725 .expect("Should have an Ed25519 verification method");
1726
1727 let x25519_method = key
1729 .did_doc
1730 .verification_method
1731 .iter()
1732 .find(|vm| matches!(vm.type_, VerificationMethodType::X25519KeyAgreementKey2019))
1733 .expect("Should have an X25519 key agreement method");
1734
1735 assert!(key.did_doc.authentication.contains(&ed25519_method.id));
1737
1738 assert!(key.did_doc.key_agreement.contains(&x25519_method.id));
1740
1741 let secret = generator.create_secret_from_key(&key);
1743 assert_eq!(secret.id, key.did);
1744 assert!(matches!(secret.type_, SecretType::JsonWebKey2020));
1745 }
1746
1747 #[test]
1748 #[cfg(feature = "crypto-p256")]
1749 fn test_did_key_generator_p256() {
1750 let generator = DIDKeyGenerator::new();
1751
1752 let options = DIDGenerationOptions {
1754 key_type: KeyType::P256,
1755 };
1756
1757 let key_result = generator.generate_did(options);
1758 assert!(key_result.is_ok());
1759
1760 let key = key_result.unwrap();
1761
1762 assert!(key.did.starts_with("did:key:z"));
1764
1765 assert_eq!(key.did_doc.id, key.did);
1767 assert_eq!(key.did_doc.verification_method.len(), 1); let p256_method = key
1771 .did_doc
1772 .verification_method
1773 .iter()
1774 .find(|vm| {
1775 matches!(
1776 vm.type_,
1777 VerificationMethodType::EcdsaSecp256k1VerificationKey2019
1778 )
1779 }) .expect("Should have a P-256 verification method");
1781
1782 assert!(key.did_doc.authentication.contains(&p256_method.id));
1784
1785 let secret = generator.create_secret_from_key(&key);
1787 assert_eq!(secret.id, key.did);
1788 assert!(matches!(secret.type_, SecretType::JsonWebKey2020));
1789 }
1790
1791 #[test]
1792 #[cfg(feature = "crypto-secp256k1")]
1793 fn test_did_key_generator_secp256k1() {
1794 let generator = DIDKeyGenerator::new();
1795
1796 let options = DIDGenerationOptions {
1798 key_type: KeyType::Secp256k1,
1799 };
1800
1801 let key_result = generator.generate_did(options);
1802 assert!(key_result.is_ok());
1803
1804 let key = key_result.unwrap();
1805
1806 assert!(key.did.starts_with("did:key:z"));
1808
1809 assert_eq!(key.did_doc.id, key.did);
1811 assert_eq!(key.did_doc.verification_method.len(), 1); let secp256k1_method = key
1815 .did_doc
1816 .verification_method
1817 .iter()
1818 .find(|vm| {
1819 matches!(
1820 vm.type_,
1821 VerificationMethodType::EcdsaSecp256k1VerificationKey2019
1822 )
1823 })
1824 .expect("Should have a Secp256k1 verification method");
1825
1826 assert!(key.did_doc.authentication.contains(&secp256k1_method.id));
1828
1829 let secret = generator.create_secret_from_key(&key);
1831 assert_eq!(secret.id, key.did);
1832 assert!(matches!(secret.type_, SecretType::JsonWebKey2020));
1833 }
1834
1835 #[test]
1836 fn test_did_web_generator() {
1837 let generator = DIDKeyGenerator::new();
1838
1839 let domain = "example.com";
1841 let options = DIDGenerationOptions {
1842 key_type: KeyType::Ed25519,
1843 };
1844
1845 let key_result = generator.generate_web_did(domain, options);
1846 assert!(key_result.is_ok());
1847
1848 let key = key_result.unwrap();
1849
1850 assert_eq!(key.did, format!("did:web:{}", domain));
1852
1853 assert_eq!(key.did_doc.id, key.did);
1855 assert!(!key.did_doc.verification_method.is_empty());
1856
1857 for vm in &key.did_doc.verification_method {
1859 assert_eq!(vm.controller, key.did);
1860 assert!(vm.id.starts_with(&key.did));
1861 }
1862
1863 let secret = generator.create_secret_from_key(&key);
1865 assert_eq!(secret.id, key.did);
1866 assert!(matches!(secret.type_, SecretType::JsonWebKey2020));
1867 }
1868}