Skip to main content

oas_document/
verification_method.rs

1// OAS Spec §5.1 — verificationMethod: Ed25519VerificationKey2020
2//! Verification method types for OAS Identity Documents.
3
4use serde::{Deserialize, Serialize};
5
6/// The fixed verification method type per OAS Specification §5.1.
7pub const VERIFICATION_METHOD_TYPE: &str = "Ed25519VerificationKey2020";
8
9/// An Ed25519 verification method as defined in OAS Identity Documents.
10///
11/// See OAS Specification §5.1 for the complete structure.
12///
13/// # Examples
14///
15/// ```
16/// use oas_document::verification_method::VerificationMethod;
17///
18/// let vm = VerificationMethod {
19///     id: "did:oas:acme:hmr:alice#key-1".to_string(),
20///     method_type: "Ed25519VerificationKey2020".to_string(),
21///     controller: "did:oas:acme:hmr:alice".to_string(),
22///     public_key_multibase: "z6Mktest123".to_string(),
23/// };
24/// assert_eq!(vm.key_id(), "key-1");
25/// ```
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct VerificationMethod {
29    /// The full key ID (e.g., `did:oas:acme:hmr:alice#key-1`).
30    pub id: String,
31
32    /// The verification method type. MUST be `Ed25519VerificationKey2020`.
33    #[serde(rename = "type")]
34    pub method_type: String,
35
36    /// The DID that controls this key.
37    pub controller: String,
38
39    /// The public key encoded as multibase base58btc (with `z` prefix).
40    pub public_key_multibase: String,
41}
42
43impl VerificationMethod {
44    /// Extracts the key fragment (the part after `#`) from the ID.
45    ///
46    /// # Returns
47    ///
48    /// The key fragment, or the full ID if no `#` is present.
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use oas_document::verification_method::VerificationMethod;
54    ///
55    /// let vm = VerificationMethod {
56    ///     id: "did:oas:ns:hmr:a#key-1".to_string(),
57    ///     method_type: "Ed25519VerificationKey2020".to_string(),
58    ///     controller: "did:oas:ns:hmr:a".to_string(),
59    ///     public_key_multibase: "zTest".to_string(),
60    /// };
61    /// assert_eq!(vm.key_id(), "key-1");
62    /// ```
63    pub fn key_id(&self) -> &str {
64        self.id
65            .rsplit_once('#')
66            .map(|(_, frag)| frag)
67            .unwrap_or(&self.id)
68    }
69
70    /// Creates a new verification method for an OAS entity.
71    ///
72    /// # Arguments
73    ///
74    /// * `did` - The entity's DID string.
75    /// * `key_num` - The key number (used to form the fragment, e.g., `key-1`).
76    /// * `public_key_multibase` - The multibase-encoded public key.
77    pub fn new(did: &str, key_num: u32, public_key_multibase: &str) -> Self {
78        Self {
79            id: format!("{did}#key-{key_num}"),
80            method_type: VERIFICATION_METHOD_TYPE.to_string(),
81            controller: did.to_string(),
82            public_key_multibase: public_key_multibase.to_string(),
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn new_creates_correct_structure() {
93        let vm = VerificationMethod::new("did:oas:ns:hmr:alice", 1, "zPubKey");
94        assert_eq!(vm.id, "did:oas:ns:hmr:alice#key-1");
95        assert_eq!(vm.method_type, VERIFICATION_METHOD_TYPE);
96        assert_eq!(vm.controller, "did:oas:ns:hmr:alice");
97        assert_eq!(vm.public_key_multibase, "zPubKey");
98    }
99
100    #[test]
101    fn key_id_extracts_fragment() {
102        let vm = VerificationMethod::new("did:oas:ns:hmr:alice", 2, "zKey");
103        assert_eq!(vm.key_id(), "key-2");
104    }
105
106    #[test]
107    fn serde_round_trip() {
108        let vm = VerificationMethod::new("did:oas:ns:agent:bot", 1, "zPubKey123");
109        let json = serde_json::to_string(&vm).unwrap_or_default();
110        let deserialized: VerificationMethod =
111            serde_json::from_str(&json).unwrap_or_else(|_| vm.clone());
112        assert_eq!(vm, deserialized);
113    }
114
115    #[test]
116    fn json_uses_camel_case() {
117        let vm = VerificationMethod::new("did:oas:ns:hmr:a", 1, "zK");
118        let json = serde_json::to_string(&vm).unwrap_or_default();
119        assert!(json.contains("publicKeyMultibase"));
120        assert!(json.contains(r#""type":"Ed25519VerificationKey2020""#));
121    }
122}