oxirs_did/
lib.rs

1//! # OxiRS DID
2//!
3//! [![Version](https://img.shields.io/badge/version-0.1.0-blue)](https://github.com/cool-japan/oxirs/releases)
4//!
5//! **Status**: Production Release (v0.1.0)
6//!
7//! W3C Decentralized Identifiers (DID) and Verifiable Credentials (VC) implementation
8//! for OxiRS, enabling signed RDF graphs and trust layer for data sovereignty.
9//!
10//! ## Features
11//!
12//! - **DID Methods**: did:key (Ed25519), did:web (HTTP-based)
13//! - **Verifiable Credentials**: W3C VC Data Model 2.0
14//! - **Signed Graphs**: RDF Dataset Canonicalization + Ed25519 signatures
15//! - **Key Management**: Secure key storage and derivation
16//!
17//! ## Example
18//!
19//! ```rust,ignore
20//! use oxirs_did::{Did, DidResolver, VerifiableCredential, CredentialIssuer};
21//!
22//! // Create DID from key
23//! let did = Did::new_key(&public_key)?;
24//!
25//! // Issue credential
26//! let issuer = CredentialIssuer::new(keystore);
27//! let vc = issuer.issue(subject, types, &issuer_did).await?;
28//!
29//! // Verify credential
30//! let verifier = CredentialVerifier::new(resolver);
31//! let result = verifier.verify(&vc).await?;
32//! ```
33
34pub mod did;
35pub mod key_management;
36pub mod proof;
37pub mod rdf_integration;
38pub mod signed_graph;
39pub mod vc;
40
41use chrono::{DateTime, Utc};
42use serde::{Deserialize, Serialize};
43use thiserror::Error;
44
45// Re-exports
46pub use did::{Did, DidDocument, DidResolver};
47pub use key_management::Keystore;
48pub use proof::{Proof, ProofPurpose, ProofType};
49pub use signed_graph::SignedGraph;
50pub use vc::{
51    CredentialIssuer, CredentialSubject, CredentialVerifier, VerifiableCredential,
52    VerifiablePresentation,
53};
54
55/// DID error types
56#[derive(Error, Debug)]
57pub enum DidError {
58    #[error("Invalid DID format: {0}")]
59    InvalidFormat(String),
60
61    #[error("Unsupported DID method: {0}")]
62    UnsupportedMethod(String),
63
64    #[error("Resolution failed: {0}")]
65    ResolutionFailed(String),
66
67    #[error("Verification failed: {0}")]
68    VerificationFailed(String),
69
70    #[error("Signing failed: {0}")]
71    SigningFailed(String),
72
73    #[error("Key not found: {0}")]
74    KeyNotFound(String),
75
76    #[error("Invalid key: {0}")]
77    InvalidKey(String),
78
79    #[error("Credential expired")]
80    CredentialExpired,
81
82    #[error("Invalid proof: {0}")]
83    InvalidProof(String),
84
85    #[error("Canonicalization failed: {0}")]
86    CanonicalizationFailed(String),
87
88    #[error("Serialization error: {0}")]
89    SerializationError(String),
90
91    #[error("Network error: {0}")]
92    NetworkError(String),
93
94    #[error("Internal error: {0}")]
95    InternalError(String),
96}
97
98pub type DidResult<T> = Result<T, DidError>;
99
100/// Verification method in DID Document
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct VerificationMethod {
104    /// Verification method ID
105    pub id: String,
106    /// Type of verification method
107    #[serde(rename = "type")]
108    pub method_type: String,
109    /// Controller DID
110    pub controller: String,
111    /// Public key in multibase format
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub public_key_multibase: Option<String>,
114    /// Public key in JWK format
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub public_key_jwk: Option<serde_json::Value>,
117}
118
119impl VerificationMethod {
120    /// Create Ed25519 verification method
121    pub fn ed25519(id: &str, controller: &str, public_key: &[u8]) -> Self {
122        // Multibase encode with base58btc prefix 'z'
123        let multibase = format!("z{}", bs58::encode(public_key).into_string());
124
125        Self {
126            id: id.to_string(),
127            method_type: "Ed25519VerificationKey2020".to_string(),
128            controller: controller.to_string(),
129            public_key_multibase: Some(multibase),
130            public_key_jwk: None,
131        }
132    }
133
134    /// Get public key bytes
135    pub fn get_public_key_bytes(&self) -> DidResult<Vec<u8>> {
136        if let Some(ref multibase) = self.public_key_multibase {
137            // Remove multibase prefix and decode
138            if let Some(stripped) = multibase.strip_prefix('z') {
139                bs58::decode(stripped)
140                    .into_vec()
141                    .map_err(|e| DidError::InvalidKey(e.to_string()))
142            } else {
143                Err(DidError::InvalidKey("Unknown multibase prefix".to_string()))
144            }
145        } else {
146            Err(DidError::InvalidKey("No public key available".to_string()))
147        }
148    }
149}
150
151/// Service endpoint in DID Document
152#[derive(Debug, Clone, Serialize, Deserialize)]
153#[serde(rename_all = "camelCase")]
154pub struct Service {
155    /// Service ID
156    pub id: String,
157    /// Service type
158    #[serde(rename = "type")]
159    pub service_type: String,
160    /// Service endpoint URL
161    pub service_endpoint: String,
162}
163
164/// Verification result
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct VerificationResult {
167    /// Whether verification succeeded
168    pub valid: bool,
169    /// Verified issuer DID
170    pub issuer: Option<String>,
171    /// Verification timestamp
172    pub verified_at: DateTime<Utc>,
173    /// Error message if verification failed
174    pub error: Option<String>,
175    /// Checks performed
176    pub checks: Vec<VerificationCheck>,
177}
178
179/// Individual verification check
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct VerificationCheck {
182    /// Check name
183    pub name: String,
184    /// Whether check passed
185    pub passed: bool,
186    /// Details
187    pub details: Option<String>,
188}
189
190impl VerificationResult {
191    pub fn success(issuer: &str) -> Self {
192        Self {
193            valid: true,
194            issuer: Some(issuer.to_string()),
195            verified_at: Utc::now(),
196            error: None,
197            checks: vec![],
198        }
199    }
200
201    pub fn failure(error: &str) -> Self {
202        Self {
203            valid: false,
204            issuer: None,
205            verified_at: Utc::now(),
206            error: Some(error.to_string()),
207            checks: vec![],
208        }
209    }
210
211    pub fn with_check(mut self, name: &str, passed: bool, details: Option<&str>) -> Self {
212        self.checks.push(VerificationCheck {
213            name: name.to_string(),
214            passed,
215            details: details.map(String::from),
216        });
217        self
218    }
219}
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224
225    #[test]
226    fn test_verification_method_ed25519() {
227        let public_key = vec![
228            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
229            25, 26, 27, 28, 29, 30, 31, 32,
230        ];
231
232        let vm = VerificationMethod::ed25519("did:key:z123#key-1", "did:key:z123", &public_key);
233
234        assert_eq!(vm.method_type, "Ed25519VerificationKey2020");
235        assert!(vm.public_key_multibase.is_some());
236
237        let recovered = vm.get_public_key_bytes().unwrap();
238        assert_eq!(recovered, public_key);
239    }
240
241    #[test]
242    fn test_verification_result() {
243        let result = VerificationResult::success("did:key:z123")
244            .with_check("signature", true, None)
245            .with_check("expiration", true, Some("Not expired"));
246
247        assert!(result.valid);
248        assert_eq!(result.checks.len(), 2);
249    }
250}