Skip to main content

tap_agent/
did.rs

1//! DID resolution and generation functionality for the TAP Agent.
2//!
3//! This module provides a multi-resolver for Decentralized Identifiers (DIDs)
4//! that integrates with the didcomm library's DID resolution system. The multi-resolver
5//! currently supports the did:key method, with the architecture allowing for additional
6//! methods to be added in the future.
7//!
8//! It also provides functionality to generate new DIDs with different cryptographic curves.
9
10use 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/// DID Document
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
43pub struct DIDDoc {
44    /// DID that this document describes
45    pub id: String,
46
47    /// List of verification methods
48    pub verification_method: Vec<VerificationMethod>,
49
50    /// List of authentication verification method references (id strings)
51    pub authentication: Vec<String>,
52
53    /// List of key agreement verification method references (id strings)
54    pub key_agreement: Vec<String>,
55
56    /// List of assertion method verification method references (id strings)
57    #[serde(default)]
58    pub assertion_method: Vec<String>,
59
60    /// List of capability invocation verification method references (id strings)
61    #[serde(default)]
62    pub capability_invocation: Vec<String>,
63
64    /// List of capability delegation verification method references (id strings)
65    #[serde(default)]
66    pub capability_delegation: Vec<String>,
67
68    /// List of services
69    pub service: Vec<Service>,
70}
71
72/// Service definition in a DID Document
73#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
74pub struct Service {
75    /// Service ID
76    pub id: String,
77
78    /// Service type
79    #[serde(rename = "type")]
80    pub type_: String,
81
82    /// Service endpoint URL
83    pub service_endpoint: String,
84
85    /// Additional properties
86    #[serde(flatten)]
87    pub properties: HashMap<String, Value>,
88}
89
90/// Verification method in a DID Document
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
92pub struct VerificationMethod {
93    /// Verification method ID
94    pub id: String,
95
96    /// Verification method type
97    #[serde(rename = "type")]
98    pub type_: VerificationMethodType,
99
100    /// Controller DID
101    pub controller: String,
102
103    /// Verification material
104    #[serde(flatten)]
105    pub verification_material: VerificationMaterial,
106}
107
108/// Verification method type
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
110#[serde(rename_all = "camelCase")]
111pub enum VerificationMethodType {
112    /// Ed25519 Verification Key 2018
113    Ed25519VerificationKey2018,
114
115    /// X25519 Key Agreement Key 2019
116    X25519KeyAgreementKey2019,
117
118    /// ECDSA Secp256k1 Verification Key 2019
119    EcdsaSecp256k1VerificationKey2019,
120
121    /// JSON Web Key 2020
122    JsonWebKey2020,
123}
124
125/// Verification material
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
127#[serde(untagged)]
128pub enum VerificationMaterial {
129    /// Base58 encoded public key
130    Base58 {
131        /// Public key encoded in base58
132        public_key_base58: String,
133    },
134
135    /// Multibase encoded public key
136    Multibase {
137        /// Public key encoded in multibase
138        public_key_multibase: String,
139    },
140
141    /// JSON Web Key
142    JWK {
143        /// Public key in JWK format
144        public_key_jwk: Value,
145    },
146}
147
148/// Key types supported for DID generation
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum KeyType {
151    /// Ed25519 key type (EdDSA)
152    #[cfg(feature = "crypto-ed25519")]
153    Ed25519,
154    /// P-256 key type (ECDSA secp256r1)
155    #[cfg(feature = "crypto-p256")]
156    P256,
157    /// Secp256k1 key type (ECDSA secp256k1)
158    #[cfg(feature = "crypto-secp256k1")]
159    Secp256k1,
160}
161
162/// Generated key information
163#[derive(Debug, Clone)]
164pub struct GeneratedKey {
165    /// The key type
166    pub key_type: KeyType,
167    /// The generated DID
168    pub did: String,
169    /// The public key in binary form
170    pub public_key: Vec<u8>,
171    /// The private key in binary form
172    pub private_key: Vec<u8>,
173    /// The DID document
174    pub did_doc: DIDDoc,
175}
176
177/// Options for generating a DID
178#[derive(Debug, Clone)]
179pub struct DIDGenerationOptions {
180    /// Key type to use
181    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, // Fallback if ed25519 is not enabled
191        }
192    }
193}
194
195/// A trait for resolving DIDs to DID documents that is Send+Sync.
196/// This trait is only available in native builds.
197#[cfg(not(target_arch = "wasm32"))]
198#[async_trait]
199pub trait SyncDIDResolver: Send + Sync + Debug {
200    /// Resolve a DID to a DID document.
201    ///
202    /// # Parameters
203    /// * `did` - The DID to resolve
204    ///
205    /// # Returns
206    /// The DID document as an Option
207    async fn resolve(&self, did: &str) -> Result<Option<DIDDoc>>;
208}
209
210/// A resolver for a specific DID method.
211/// This trait is only available in native builds.
212#[cfg(not(target_arch = "wasm32"))]
213#[async_trait]
214#[cfg(not(target_arch = "wasm32"))]
215pub trait DIDMethodResolver: Send + Sync + Debug {
216    /// Returns the method name this resolver handles (e.g., "key", "web", "pkh").
217    fn method(&self) -> &str;
218
219    /// Resolve a DID to a DID document.
220    ///
221    /// # Parameters
222    /// * `did` - The DID to resolve
223    ///
224    /// # Returns
225    /// The DID document as an Option
226    async fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>>;
227}
228
229/// A simplified DID resolver for WebAssembly with no async or Send/Sync requirements.
230#[cfg(target_arch = "wasm32")]
231pub trait WasmDIDResolver: Debug {
232    /// Resolves a DID synchronously, returning the DID document.
233    fn resolve(&self, did: &str) -> Result<Option<DIDDoc>>;
234}
235
236/// A simplified method-specific DID resolver for WebAssembly.
237#[cfg(target_arch = "wasm32")]
238pub trait WasmDIDMethodResolver: Debug {
239    /// Returns the method name this resolver handles.
240    fn method(&self) -> &str;
241
242    /// Resolves a DID synchronously, returning the DID document.
243    fn resolve_method(&self, did: &str) -> Result<Option<DIDDoc>>;
244
245    /// Get this resolver as Any for downcasting
246    fn as_any(&self) -> &dyn std::any::Any;
247}
248
249/// A resolver for the did:key method.
250#[derive(Debug, Default)]
251pub struct KeyResolver;
252
253impl KeyResolver {
254    /// Create a new KeyResolver
255    pub fn new() -> Self {
256        Self
257    }
258
259    /// Convert an Ed25519 public key to an X25519 public key
260    ///
261    /// This follows the conversion process described in RFC 7748
262    /// https://datatracker.ietf.org/doc/html/rfc7748#section-5
263    #[cfg(feature = "crypto-ed25519")]
264    fn ed25519_to_x25519(ed25519_pubkey: &[u8]) -> Option<[u8; 32]> {
265        // The Ed25519 public key should be 32 bytes
266        if ed25519_pubkey.len() != 32 {
267            return None;
268        }
269
270        // Add debugging
271        debug!("Ed25519 pubkey: {:?}", ed25519_pubkey);
272
273        // Try to create a CompressedEdwardsY from the bytes
274        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        // Try to decompress to get the Edwards point
283        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        // Convert to Montgomery form
292        let montgomery_point = edwards_point.to_montgomery();
293
294        // Get the raw bytes representation of the X25519 key
295        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        // Same implementation but without async/await
311        // Validate that this is a did:key
312        if !did_key.starts_with("did:key:") {
313            return Ok(None);
314        }
315
316        // Parse the multibase-encoded public key
317        let key_id = &did_key[8..]; // Skip the "did:key:" prefix
318        let (_, key_bytes) = match decode(key_id) {
319            Ok(result) => result,
320            Err(_) => return Ok(None),
321        };
322
323        // Check the key prefix - for did:key only Ed25519 is supported
324        if key_bytes.len() < 2 {
325            return Ok(None);
326        }
327
328        // Verify the key type - 0xED01 for Ed25519
329        if key_bytes[0] != 0xED || key_bytes[1] != 0x01 {
330            return Ok(None);
331        }
332
333        // Create the DID Document with the Ed25519 public key
334        let ed25519_public_key = &key_bytes[2..];
335
336        let ed_vm_id = format!("{}#{}", did_key, key_id);
337
338        // Create the Ed25519 verification method
339        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        // Convert the Ed25519 public key to X25519 for key agreement
349        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            // Encode the X25519 public key in multibase format
355            let mut x25519_bytes = vec![0xEC, 0x01]; // Prefix for X25519
356            x25519_bytes.extend_from_slice(&x25519_key);
357            let x25519_multibase = encode(Base::Base58Btc, x25519_bytes);
358
359            // Create the X25519 verification method ID
360            let x25519_vm_id = format!("{}#{}", did_key, x25519_multibase);
361
362            // Create the X25519 verification method
363            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            // Add the X25519 key agreement method
373            verification_methods.push(x25519_verification_method);
374            key_agreement.push(x25519_vm_id);
375        }
376
377        // Create the DID document
378        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        // Validate that this is a did:key
402        if !did_key.starts_with("did:key:") {
403            return Ok(None);
404        }
405
406        // Parse the multibase-encoded public key
407        let key_id = &did_key[8..]; // Skip the "did:key:" prefix
408        let (_, key_bytes) = match decode(key_id) {
409            Ok(result) => result,
410            Err(_) => return Ok(None),
411        };
412
413        // Check the key prefix - for did:key only Ed25519 is supported
414        if key_bytes.len() < 2 {
415            return Ok(None);
416        }
417
418        // Verify the key type - 0xED01 for Ed25519
419        if key_bytes[0] != 0xED || key_bytes[1] != 0x01 {
420            return Ok(None);
421        }
422
423        // Create the DID Document with the Ed25519 public key
424        let ed25519_public_key = &key_bytes[2..];
425
426        let ed_vm_id = format!("{}#{}", did_key, key_id);
427
428        // Create the Ed25519 verification method
429        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        // Convert the Ed25519 public key to X25519 for key agreement
439        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            // Encode the X25519 public key in multibase format
446            let mut x25519_bytes = vec![0xEC, 0x01]; // Prefix for X25519
447            x25519_bytes.extend_from_slice(&x25519_key);
448            let x25519_multibase = encode(Base::Base58Btc, x25519_bytes);
449
450            // Create the X25519 verification method ID
451            let x25519_vm_id = format!("{}#{}", did_key, x25519_multibase);
452
453            // Create the X25519 verification method
454            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            // Add the X25519 key agreement method
464            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        // Create the DID document
471        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/// A multi-resolver for DID methods. This resolver manages multiple
487/// method-specific resolver. New resolvers can be added at runtime.
488#[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    /// Create a new empty MultiResolver
502    pub fn new() -> Self {
503        Self {
504            resolvers: RwLock::new(HashMap::new()),
505        }
506    }
507
508    /// Create a new MultiResolver with a list of resolvers
509    pub fn new_with_resolvers(resolvers: Vec<Arc<dyn DIDMethodResolver>>) -> Self {
510        let resolver = Self::new();
511
512        // Add each resolver to the map if we can acquire the write lock
513        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    /// Register a new resolver for a specific DID method
524    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/// DID Web Resolver for resolving did:web identifiers
536#[derive(Debug, Default)]
537pub struct WebResolver;
538
539impl WebResolver {
540    /// Create a new WebResolver
541    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        // For WASM, return a simple placeholder DID document without actual resolution
558        // Because we lack the proper web-fetch capabilities at the moment
559        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        // Create a minimal DID document for did:web
565        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        // Extract domain from did:web format
598        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        // Extract the domain (and path if present)
604        let domain_path = parts[2..].join(":");
605        let domain_path = domain_path.replace("%3A", ":");
606
607        // Construct the URL to fetch the DID document
608        // did:web:example.com -> https://example.com/.well-known/did.json
609        // did:web:example.com:path:to:resource -> https://example.com/path/to/resource/did.json
610
611        let url = if domain_path.contains(":") {
612            // Convert additional colons to slashes for path components
613            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            // Standard case: did:web:example.com
619            format!("https://{}/.well-known/did.json", domain_path)
620        };
621
622        // Attempt to fetch and parse the DID document
623        #[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                                // First try normal parsing
634                                let parse_result = serde_json::from_str::<DIDDoc>(&text);
635                                match parse_result {
636                                    Ok(doc) => {
637                                        // Validate that the document ID matches the requested DID
638                                        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                                        // If normal parsing fails, try to parse as a generic JSON Value
648                                        // and manually construct a DIDDoc with the essential fields
649                                        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                                                // Validate ID
668                                                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                                                // Try to extract verification methods and other fields
676                                                warn!("Using partial DID document parsing due to format issues");
677                                                warn!("Original parse error: {}", parse_error);
678
679                                                // Extract verification methods if present
680                                                // Create a longer-lived empty vec to handle the None case
681                                                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                                                // Attempt to parse each verification method
688                                                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                                                // Extract authentication references
700                                                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                                                // Extract key agreement references
711                                                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                                                // We'll create an empty services list for the DIDDoc
722                                                // But save service information separately for display purposes
723                                                let services = Vec::new();
724
725                                                // Extract raw service information for display
726                                                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                                                // Create a simplified DID document with whatever we could extract
755                                                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                        // Not found is a valid response, just return None
783                        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            // Create request options
806            let mut opts = RequestInit::new();
807            opts.method("GET");
808            opts.mode(RequestMode::Cors);
809
810            // Create the request
811            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            // Add Accept header
822            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            // Get the window object
847            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            // Send the request
857            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            // Convert response to Response object
868            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            // Check if successful
878            if resp.ok() {
879                // Get the text content
880                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                // Parse the DID document
908                match serde_json::from_str::<DIDDoc>(&text) {
909                    Ok(doc) => {
910                        // Validate that the document ID matches the requested DID
911                        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                        // If normal parsing fails, try to parse as a generic JSON Value
921                        // and manually construct a DIDDoc with the essential fields
922                        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                                // Validate ID
941                                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                                // Try to extract verification methods and other fields
949                                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                                // Extract verification methods if present
954                                // Create a longer-lived empty vec to handle the None case
955                                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                                // Attempt to parse each verification method
962                                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                                // Extract authentication references
972                                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                                // Extract key agreement references
981                                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                                // Create an empty services list for the DIDDoc
990                                let services = Vec::new();
991
992                                // Extract raw service information for console logging
993                                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                                // Create a simplified DID document with whatever we could extract
1025                                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                // Not found is a valid response, just return None
1047                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/// DID Key Generator for creating DIDs with different key types
1077#[derive(Debug, Default, Clone)]
1078pub struct DIDKeyGenerator;
1079
1080impl DIDKeyGenerator {
1081    /// Create a new DID key generator
1082    pub fn new() -> Self {
1083        Self
1084    }
1085
1086    /// Create a Secret from a GeneratedKey for a DID
1087    pub fn create_secret_from_key(&self, key: &GeneratedKey) -> Secret {
1088        // Determine the proper key ID based on DID method
1089        let kid = if key.did.starts_with("did:key:") {
1090            // For did:key, the key ID is the DID + fragment matching the multibase
1091            // Get the first verification method's ID which has the proper format
1092            key.did_doc
1093                .verification_method
1094                .first()
1095                .map(|vm| vm.id.clone())
1096                .unwrap_or_else(|| {
1097                    // Fallback: extract the multibase part and construct the ID
1098                    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            // For did:web, use #keys-1
1103            format!("{}#keys-1", key.did)
1104        } else {
1105            // For other DID methods, use a generic pattern
1106            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                    // public_key is uncompressed [0x04 || x(32) || y(32)], skip the 0x04 prefix
1130                    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                    // public_key is uncompressed [0x04 || x(32) || y(32)], skip the 0x04 prefix
1146                    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    /// Generate a did:key identifier with the specified key type
1160    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    /// Generate a did:key identifier with an Ed25519 key
1172    #[cfg(feature = "crypto-ed25519")]
1173    pub fn generate_ed25519_did(&self) -> Result<GeneratedKey> {
1174        // Generate a new Ed25519 keypair
1175        let mut csprng = OsRng;
1176        let signing_key = Ed25519SigningKey::generate(&mut csprng);
1177        let verifying_key = Ed25519VerifyingKey::from(&signing_key);
1178
1179        // Extract public and private keys
1180        let public_key = verifying_key.to_bytes().to_vec();
1181        let private_key = signing_key.to_bytes().to_vec();
1182
1183        // Create did:key identifier
1184        // Multicodec prefix for Ed25519: 0xed01
1185        let mut prefixed_key = vec![0xed, 0x01];
1186        prefixed_key.extend_from_slice(&public_key);
1187
1188        // Encode the key with multibase (base58btc with 'z' prefix)
1189        let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
1190        let did = format!("did:key:{}", multibase_encoded);
1191
1192        // Create the DID document
1193        let doc = self.create_did_doc(&did, &prefixed_key, KeyType::Ed25519)?;
1194
1195        // Return the generated key information
1196        Ok(GeneratedKey {
1197            key_type: KeyType::Ed25519,
1198            did,
1199            public_key,
1200            private_key,
1201            did_doc: doc,
1202        })
1203    }
1204
1205    /// Generate a did:key identifier with a P-256 key
1206    #[cfg(feature = "crypto-p256")]
1207    pub fn generate_p256_did(&self) -> Result<GeneratedKey> {
1208        // Generate a new P-256 keypair
1209        let mut rng = OsRng;
1210        let signing_key = P256SigningKey::random(&mut rng);
1211
1212        // Extract public and private keys
1213        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        // Create did:key identifier
1221        // Multicodec prefix for P-256: 0x1200
1222        let mut prefixed_key = vec![0x12, 0x00];
1223        prefixed_key.extend_from_slice(&public_key);
1224
1225        // Encode the key with multibase (base58btc with 'z' prefix)
1226        let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
1227        let did = format!("did:key:{}", multibase_encoded);
1228
1229        // Create the DID document
1230        let doc = self.create_did_doc(&did, &prefixed_key, KeyType::P256)?;
1231
1232        // Return the generated key information
1233        Ok(GeneratedKey {
1234            key_type: KeyType::P256,
1235            did,
1236            public_key,
1237            private_key,
1238            did_doc: doc,
1239        })
1240    }
1241
1242    /// Generate a did:key identifier with a Secp256k1 key
1243    #[cfg(feature = "crypto-secp256k1")]
1244    pub fn generate_secp256k1_did(&self) -> Result<GeneratedKey> {
1245        // Generate a new Secp256k1 keypair
1246        let mut rng = OsRng;
1247        let signing_key = Secp256k1SigningKey::random(&mut rng);
1248
1249        // Extract public and private keys
1250        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        // Create did:key identifier
1258        // Multicodec prefix for Secp256k1: 0xe701
1259        let mut prefixed_key = vec![0xe7, 0x01];
1260        prefixed_key.extend_from_slice(&public_key);
1261
1262        // Encode the key with multibase (base58btc with 'z' prefix)
1263        let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
1264        let did = format!("did:key:{}", multibase_encoded);
1265
1266        // Create the DID document
1267        let doc = self.create_did_doc(&did, &prefixed_key, KeyType::Secp256k1)?;
1268
1269        // Return the generated key information
1270        Ok(GeneratedKey {
1271            key_type: KeyType::Secp256k1,
1272            did,
1273            public_key,
1274            private_key,
1275            did_doc: doc,
1276        })
1277    }
1278
1279    /// Generate a did:web identifier with the given domain and key type
1280    pub fn generate_web_did(
1281        &self,
1282        domain: &str,
1283        options: DIDGenerationOptions,
1284    ) -> Result<GeneratedKey> {
1285        // First, generate a key DID of the appropriate type
1286        let key_did = self.generate_did(options)?;
1287
1288        // Format the did:web identifier
1289        let did = format!("did:web:{}", domain);
1290
1291        // Create a new DID document based on the key DID document but with the web DID
1292        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        // Return the generated key information with the web DID
1322        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    /// Create a DID document for a did:key
1332    fn create_did_doc(
1333        &self,
1334        did: &str,
1335        prefixed_public_key: &[u8],
1336        key_type: KeyType,
1337    ) -> Result<DIDDoc> {
1338        // Determine verification method type based on key type
1339        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, // Using Secp256k1 type as P256 isn't available
1344            #[cfg(feature = "crypto-secp256k1")]
1345            KeyType::Secp256k1 => VerificationMethodType::EcdsaSecp256k1VerificationKey2019,
1346        };
1347
1348        // Encode the prefixed public key with multibase
1349        let multibase_encoded = encode(Base::Base58Btc, prefixed_public_key);
1350
1351        // Create the verification method ID
1352        let vm_id = format!("{}#{}", did, multibase_encoded);
1353
1354        // Create the verification method
1355        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        // For Ed25519, also generate an X25519 verification method for key agreement
1365        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            // Only Ed25519 keys have an X25519 key agreement method
1371            if let Some(x25519_bytes) = self.ed25519_to_x25519(&prefixed_public_key[2..]) {
1372                // Prefix for X25519: 0xEC01
1373                let mut x25519_prefixed = vec![0xEC, 0x01];
1374                x25519_prefixed.extend_from_slice(&x25519_bytes);
1375
1376                // Encode the prefixed X25519 key with multibase
1377                let x25519_multibase = encode(Base::Base58Btc, &x25519_prefixed);
1378
1379                // Create the X25519 verification method ID
1380                let x25519_vm_id = format!("{}#{}", did, x25519_multibase);
1381
1382                // Create the X25519 verification method
1383                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                // Add the X25519 verification method and key agreement method
1393                verification_methods.push(x25519_verification_method);
1394                key_agreement.push(x25519_vm_id);
1395            }
1396        }
1397
1398        // Create the DID document
1399        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    /// Convert an Ed25519 public key to an X25519 public key
1414    ///
1415    /// This follows the conversion process described in RFC 7748
1416    /// https://datatracker.ietf.org/doc/html/rfc7748#section-5
1417    #[cfg(feature = "crypto-ed25519")]
1418    fn ed25519_to_x25519(&self, ed25519_pubkey: &[u8]) -> Option<[u8; 32]> {
1419        // The Ed25519 public key should be 32 bytes
1420        if ed25519_pubkey.len() != 32 {
1421            return None;
1422        }
1423
1424        // Try to create a CompressedEdwardsY from the bytes
1425        let edwards_y = match CompressedEdwardsY::from_slice(ed25519_pubkey) {
1426            Ok(point) => point,
1427            Err(_) => return None,
1428        };
1429
1430        // Try to decompress to get the Edwards point
1431        let edwards_point = edwards_y.decompress()?;
1432
1433        // Convert to Montgomery form
1434        let montgomery_point = edwards_point.to_montgomery();
1435
1436        // Get the raw bytes representation of the X25519 key
1437        Some(montgomery_point.to_bytes())
1438    }
1439
1440    // The create_secret_from_key method has been moved up
1441}
1442
1443#[derive(Debug)]
1444#[cfg(target_arch = "wasm32")]
1445pub struct MultiResolver {
1446    // WASM-specific implementation with no thread-safety requirements
1447    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        // Add default resolvers
1461        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        // Extract the DID method
1475        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        // Get the resolver from the map
1483        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        // Extract the DID method
1500        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        // Get the resolver from the map first
1508        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            // Lock is dropped here when resolver_guard goes out of scope
1519        };
1520
1521        // Now use the resolver without holding the lock
1522        resolver.resolve_method(did).await
1523    }
1524}
1525
1526// DIDResolver trait from didcomm is no longer needed since we've removed the didcomm dependency
1527
1528#[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        // The JS resolver should return its method
1561        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// This is a duplicate trait that conflicts with the one defined above
1572// So we're removing it here to avoid the conflict
1573
1574/// A wrapper for JavaScript DID resolvers.
1575#[cfg(target_arch = "wasm32")]
1576#[derive(Debug)]
1577pub struct JsDIDMethodResolver {
1578    method: String,
1579    #[allow(dead_code)] // Reserved for future async JS resolver implementation
1580    resolve_fn: Function,
1581}
1582
1583#[cfg(target_arch = "wasm32")]
1584impl JsDIDMethodResolver {
1585    /// Create a new JavaScript DID method resolver from a function in the global context
1586    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        // Ensure the DID is for the method that this resolver is for
1606        let parts: Vec<&str> = did.split(':').collect();
1607        if parts.len() < 3 || parts[1] != self.method {
1608            return Err(Error::InvalidDID);
1609        }
1610
1611        // In WASM target mode, we can't use async/await in this interface
1612        // This implementation is a simplified version that just returns None
1613        // The proper implementation would be in the JavaScript binding
1614        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        // Test a valid did:key for Ed25519
1637        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); // Should have both Ed25519 and X25519 methods
1645
1646        // Verify Ed25519 verification method is present
1647        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        // Verify X25519 verification method
1654        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        // Check that authentication uses the Ed25519 key
1661        assert!(doc.authentication.contains(&ed25519_method.id));
1662
1663        // Check that key agreement uses the X25519 key
1664        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        // Test resolving a valid did:key
1673        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); // Should have both Ed25519 and X25519 methods
1683
1684        // Test resolving an unsupported DID method
1685        let did = "did:unsupported:123";
1686        let result = <MultiResolver as SyncDIDResolver>::resolve(&resolver, did).await;
1687
1688        // This should return an error since it's an unsupported method
1689        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        // Generate an Ed25519 DID
1699        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        // Check the DID format
1709        assert!(key.did.starts_with("did:key:z"));
1710
1711        // Check that public and private keys have the correct length
1712        assert_eq!(key.public_key.len(), 32); // Ed25519 public key is 32 bytes
1713        assert_eq!(key.private_key.len(), 32); // Ed25519 private key is 32 bytes
1714
1715        // Check the DID document
1716        assert_eq!(key.did_doc.id, key.did);
1717        assert_eq!(key.did_doc.verification_method.len(), 2); // Should have both Ed25519 and X25519
1718
1719        // Verify Ed25519 verification method is present
1720        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        // Verify X25519 verification method
1728        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        // Check that authentication uses the Ed25519 key
1736        assert!(key.did_doc.authentication.contains(&ed25519_method.id));
1737
1738        // Check that key agreement uses the X25519 key
1739        assert!(key.did_doc.key_agreement.contains(&x25519_method.id));
1740
1741        // Create a secret from the key
1742        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        // Generate a P-256 DID
1753        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        // Check the DID format
1763        assert!(key.did.starts_with("did:key:z"));
1764
1765        // Check the DID document
1766        assert_eq!(key.did_doc.id, key.did);
1767        assert_eq!(key.did_doc.verification_method.len(), 1); // P-256 has no key agreement
1768
1769        // Verify P-256 verification method is present
1770        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            }) // Use available type
1780            .expect("Should have a P-256 verification method");
1781
1782        // Check that authentication uses the P-256 key
1783        assert!(key.did_doc.authentication.contains(&p256_method.id));
1784
1785        // Create a secret from the key
1786        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        // Generate a Secp256k1 DID
1797        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        // Check the DID format
1807        assert!(key.did.starts_with("did:key:z"));
1808
1809        // Check the DID document
1810        assert_eq!(key.did_doc.id, key.did);
1811        assert_eq!(key.did_doc.verification_method.len(), 1); // Secp256k1 has no key agreement
1812
1813        // Verify Secp256k1 verification method is present
1814        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        // Check that authentication uses the Secp256k1 key
1827        assert!(key.did_doc.authentication.contains(&secp256k1_method.id));
1828
1829        // Create a secret from the key
1830        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        // Generate a did:web
1840        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        // Check the DID format
1851        assert_eq!(key.did, format!("did:web:{}", domain));
1852
1853        // Check the DID document
1854        assert_eq!(key.did_doc.id, key.did);
1855        assert!(!key.did_doc.verification_method.is_empty());
1856
1857        // Verify that all verification methods have the correct controller
1858        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        // Create a secret from the key
1864        let secret = generator.create_secret_from_key(&key);
1865        assert_eq!(secret.id, key.did);
1866        assert!(matches!(secret.type_, SecretType::JsonWebKey2020));
1867    }
1868}