solid_pod_rs_didkey/
did.rs1use multibase::Base;
10
11use crate::error::DidKeyError;
12use crate::pubkey::DidKeyPubkey;
13
14pub const DID_KEY_PREFIX: &str = "did:key:";
16
17pub fn encode(pubkey: &DidKeyPubkey) -> String {
19 let payload = pubkey.to_multicodec_bytes();
20 let mb = multibase::encode(Base::Base58Btc, payload);
21 format!("{DID_KEY_PREFIX}{mb}")
22}
23
24pub fn decode(did: &str) -> Result<DidKeyPubkey, DidKeyError> {
30 let stripped = did
31 .strip_prefix(DID_KEY_PREFIX)
32 .ok_or_else(|| DidKeyError::NotDidKey(did.to_string()))?;
33 let body = stripped.split('#').next().unwrap_or(stripped);
34 if !body.starts_with('z') {
35 return Err(DidKeyError::InvalidMultibase(format!(
36 "did:key requires base58btc 'z' prefix, got '{}'",
37 body.chars().next().unwrap_or(' ')
38 )));
39 }
40 let (base, bytes) = multibase::decode(body)
41 .map_err(|e| DidKeyError::InvalidMultibase(format!("decode: {e}")))?;
42 if base != Base::Base58Btc {
43 return Err(DidKeyError::InvalidMultibase(format!(
44 "did:key multibase must be base58btc, got {base:?}"
45 )));
46 }
47 DidKeyPubkey::from_multicodec_bytes(&bytes)
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::pubkey::{ED25519_LEN, SEC1_COMPRESSED_LEN};
54
55 #[test]
56 fn encode_rejects_method_fragment() {
57 let k = DidKeyPubkey::Ed25519([9u8; ED25519_LEN]);
60 let did = encode(&k);
61 let with_frag = format!("{did}#keys-0");
62 let decoded = decode(&with_frag).unwrap();
63 assert_eq!(decoded, k);
64 }
65
66 #[test]
67 fn ed25519_roundtrip() {
68 let k = DidKeyPubkey::Ed25519([42u8; ED25519_LEN]);
69 let did = encode(&k);
70 assert!(did.starts_with("did:key:z"));
71 let back = decode(&did).unwrap();
72 assert_eq!(back, k);
73 }
74
75 #[test]
76 fn p256_roundtrip() {
77 let mut sec1 = vec![0u8; SEC1_COMPRESSED_LEN];
78 sec1[0] = 0x02;
79 for (i, byte) in sec1.iter_mut().enumerate().skip(1) {
80 *byte = i as u8;
81 }
82 let k = DidKeyPubkey::P256(sec1);
83 let did = encode(&k);
84 let back = decode(&did).unwrap();
85 assert_eq!(back, k);
86 }
87
88 #[test]
89 fn secp256k1_roundtrip() {
90 let mut sec1 = vec![0u8; SEC1_COMPRESSED_LEN];
91 sec1[0] = 0x03;
92 for (i, byte) in sec1.iter_mut().enumerate().skip(1) {
93 *byte = (i as u8).wrapping_mul(3);
94 }
95 let k = DidKeyPubkey::Secp256k1(sec1);
96 let did = encode(&k);
97 let back = decode(&did).unwrap();
98 assert_eq!(back, k);
99 }
100
101 #[test]
102 fn rejects_wrong_prefix() {
103 let err = decode("did:example:123").unwrap_err();
104 assert!(matches!(err, DidKeyError::NotDidKey(_)));
105 }
106
107 #[test]
108 fn rejects_non_base58btc_multibase() {
109 let err = decode("did:key:uAQIDBAUGBw").unwrap_err();
111 assert!(matches!(err, DidKeyError::InvalidMultibase(_)));
112 }
113
114 #[test]
115 fn rejects_malformed_multibase_body() {
116 let err = decode("did:key:z0OIl").unwrap_err();
119 assert!(matches!(err, DidKeyError::InvalidMultibase(_)));
120 }
121}