1use once_cell::sync::Lazy;
2
3use regex::Regex;
4#[cfg(feature = "ed25519")]
5use sha2::{Digest, Sha256};
6
7use crate::base58;
8#[cfg(feature = "ed25519")]
9use crate::keys::{KeyType, PrivateKey, VerKey};
10use crate::{Qualifiable, Validatable, ValidationError};
11
12pub static DEFAULT_LIBINDY_DID: Lazy<DidValue> =
14 Lazy::new(|| DidValue::new("LibindyDid111111111111", None));
15
16#[cfg(feature = "ed25519")]
21pub fn generate_did(
22 seed: Option<&[u8]>,
23 version: Option<usize>,
24) -> Result<(ShortDidValue, PrivateKey, VerKey), crate::ConversionError> {
25 let sk = match seed {
26 Some(seed) => PrivateKey::from_seed(seed)?,
27 None => PrivateKey::generate(Some(KeyType::ED25519))?,
28 };
29
30 let pk = sk.public_key()?;
31 let did = match version {
32 Some(1) | None => Ok(base58::encode(&pk.as_ref()[..16])),
33 Some(2) => {
34 let mut hasher = Sha256::new();
35 Digest::update(&mut hasher, &pk.as_ref());
36 let hash = hasher.finalize();
37 Ok(base58::encode(&hash[..16]))
38 }
39 _ => Err("Version must be one of 1,2"),
40 }?;
41 Ok((ShortDidValue::from(did), sk, pk))
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Hash)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47pub struct DidMethod(pub String);
48
49impl Validatable for DidMethod {
50 fn validate(&self) -> Result<(), ValidationError> {
51 static REGEX_METHOD_NAME: Lazy<Regex> = Lazy::new(|| Regex::new("^[a-z0-9]+$").unwrap());
52
53 if !REGEX_METHOD_NAME.is_match(&self.0) {
54 return Err(invalid!(
55 "Invalid default name: {}. It does not match the DID method name format.",
56 self.0
57 ));
58 }
59 Ok(())
60 }
61}
62
63qualifiable_type!(DidValue, "A qualifiable DID type");
64
65impl Qualifiable for DidValue {
66 fn prefix() -> &'static str {
67 "did"
68 }
69}
70
71impl DidValue {
72 pub fn new(did: &str, method: Option<&str>) -> DidValue {
73 DidValue::combine(method, did)
74 }
75
76 pub fn to_short(&self) -> ShortDidValue {
77 ShortDidValue(self.to_unqualified().0)
78 }
79
80 pub fn is_abbreviatable(&self) -> bool {
81 match self.get_method() {
82 Some(ref method) if method.starts_with("sov") => true,
83 Some(_) => false,
84 None => true,
85 }
86 }
87}
88
89impl Validatable for DidValue {
90 fn validate(&self) -> Result<(), ValidationError> {
91 if self.is_fully_qualified() {
92 } else {
94 let did = base58::decode(&self.0).map_err(ValidationError::from_msg)?;
95 if did.len() != 16 && did.len() != 32 {
96 return Err(invalid!(
97 "Trying to use DID with unexpected length: {}. \
98 The 16- or 32-byte number upon which a DID is based should be 22/23 or 44/45 bytes when encoded as base58.", did.len()
99 ));
100 }
101 }
102 Ok(())
103 }
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Hash)]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109pub struct ShortDidValue(pub String);
110
111impl From<String> for ShortDidValue {
112 fn from(val: String) -> Self {
113 Self(val)
114 }
115}
116
117impl std::ops::Deref for ShortDidValue {
118 type Target = str;
119 fn deref(&self) -> &str {
120 &self.0
121 }
122}
123
124impl ShortDidValue {
125 pub fn qualify(&self, method: Option<String>) -> DidValue {
127 DidValue::combine(method.as_ref().map(String::as_str), &self)
128 }
129}
130
131impl Validatable for ShortDidValue {
132 fn validate(&self) -> Result<(), ValidationError> {
133 let did = base58::decode(&self.0).map_err(ValidationError::from_msg)?;
134 if did.len() != 16 && did.len() != 32 {
135 return Err(invalid!(
136 "Trying to use DID with unexpected length: {}. \
137 The 16- or 32-byte number upon which a DID is based should be 22/23 or 44/45 bytes when encoded as base58.", did.len()
138 ));
139 }
140 Ok(())
141 }
142}
143
144#[cfg(all(test, feature = "ed25519"))]
145mod tests {
146 use super::*;
147 use crate::keys::EncodedVerKey;
148
149 #[test]
150 fn generate_abbreviate() {
151 let (did, _sk, vk) = generate_did(None, None).unwrap();
152 let vk_b58 = vk.as_base58().unwrap();
153 let vk_short = vk_b58.abbreviated_for_did(&did).unwrap();
154 assert_eq!(vk_short.chars().next(), Some('~'));
155 let vk_long = EncodedVerKey::from_did_and_verkey(&did, &vk_short).unwrap();
156 assert_eq!(vk_long, vk_b58);
157 let cmp_vk = vk_long.decode().unwrap();
158 assert_eq!(vk, cmp_vk);
159 }
160}