use serde::{Deserialize, Serialize};
pub const VERIFICATION_METHOD_TYPE: &str = "Ed25519VerificationKey2020";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VerificationMethod {
pub id: String,
#[serde(rename = "type")]
pub method_type: String,
pub controller: String,
pub public_key_multibase: String,
}
impl VerificationMethod {
pub fn key_id(&self) -> &str {
self.id
.rsplit_once('#')
.map(|(_, frag)| frag)
.unwrap_or(&self.id)
}
pub fn new(did: &str, key_num: u32, public_key_multibase: &str) -> Self {
Self {
id: format!("{did}#key-{key_num}"),
method_type: VERIFICATION_METHOD_TYPE.to_string(),
controller: did.to_string(),
public_key_multibase: public_key_multibase.to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_creates_correct_structure() {
let vm = VerificationMethod::new("did:oas:ns:hmr:alice", 1, "zPubKey");
assert_eq!(vm.id, "did:oas:ns:hmr:alice#key-1");
assert_eq!(vm.method_type, VERIFICATION_METHOD_TYPE);
assert_eq!(vm.controller, "did:oas:ns:hmr:alice");
assert_eq!(vm.public_key_multibase, "zPubKey");
}
#[test]
fn key_id_extracts_fragment() {
let vm = VerificationMethod::new("did:oas:ns:hmr:alice", 2, "zKey");
assert_eq!(vm.key_id(), "key-2");
}
#[test]
fn serde_round_trip() {
let vm = VerificationMethod::new("did:oas:ns:agent:bot", 1, "zPubKey123");
let json = serde_json::to_string(&vm).unwrap_or_default();
let deserialized: VerificationMethod =
serde_json::from_str(&json).unwrap_or_else(|_| vm.clone());
assert_eq!(vm, deserialized);
}
#[test]
fn json_uses_camel_case() {
let vm = VerificationMethod::new("did:oas:ns:hmr:a", 1, "zK");
let json = serde_json::to_string(&vm).unwrap_or_default();
assert!(json.contains("publicKeyMultibase"));
assert!(json.contains(r#""type":"Ed25519VerificationKey2020""#));
}
}