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}