1use crate::attestor::IONAttestor;
3use crate::ion::IONTest as ION;
4use crate::TrustchainIONError;
5use did_ion::sidetree::{DIDStatePatch, PublicKeyJwk, ServiceEndpointEntry, Sidetree};
6use serde_json::{Map, Value};
7use ssi::did::ServiceEndpoint;
8use ssi::did_resolve::{DocumentMetadata, Metadata};
9use ssi::jwk::JWK;
10use std::convert::TryFrom;
11use trustchain_core::attestor::Attestor;
12use trustchain_core::controller::Controller;
13use trustchain_core::key_manager::{ControllerKeyManager, KeyManager, KeyManagerError, KeyType};
14use trustchain_core::subject::Subject;
15use trustchain_core::utils::generate_key;
16use trustchain_core::{TRUSTCHAIN_PROOF_SERVICE_ID_VALUE, TRUSTCHAIN_PROOF_SERVICE_TYPE_VALUE};
17impl KeyManager for IONController {}
18impl ControllerKeyManager for IONController {}
19
20pub struct ControllerData {
22 did: String,
23 controlled_did: String,
24 update_key: JWK,
25 recovery_key: JWK,
26}
27
28impl ControllerData {
29 pub fn new(did: String, controlled_did: String, update_key: JWK, recovery_key: JWK) -> Self {
30 ControllerData {
31 did,
32 controlled_did,
33 update_key,
34 recovery_key,
35 }
36 }
37}
38
39impl TryFrom<ControllerData> for IONController {
40 type Error = Box<dyn std::error::Error>;
41 fn try_from(data: ControllerData) -> Result<Self, Self::Error> {
42 let controller = IONController {
43 did: data.did,
44 controlled_did: data.controlled_did,
45 };
46 controller.save_key(
48 controller.controlled_did_suffix(),
49 KeyType::UpdateKey,
50 &data.update_key,
51 false,
52 )?;
53 controller.save_key(
55 controller.controlled_did_suffix(),
56 KeyType::RecoveryKey,
57 &data.recovery_key,
58 false,
59 )?;
60 Ok(controller)
61 }
62}
63
64pub struct IONController {
66 did: String,
67 controlled_did: String,
68}
69
70impl IONController {
71 pub fn new(did: &str, controlled_did: &str) -> Result<Self, Box<dyn std::error::Error>> {
73 Ok(Self {
74 did: did.to_owned(),
75 controlled_did: controlled_did.to_owned(),
76 })
77 }
78
79 }
84
85impl Subject for IONController {
86 fn did(&self) -> &str {
87 &self.did
88 }
89}
90
91impl Controller for IONController {
92 fn controlled_did(&self) -> &str {
93 &self.controlled_did
94 }
95
96 fn update_key(&self) -> Result<JWK, KeyManagerError> {
97 let update_key = self.read_update_key(self.controlled_did_suffix())?;
98 Ok(update_key)
99 }
100
101 fn next_update_key(&self) -> Result<Option<JWK>, KeyManagerError> {
102 let next_update_key = self.read_next_update_key(self.controlled_did_suffix())?;
103 Ok(Some(next_update_key))
104 }
105
106 fn generate_next_update_key(&self) -> Result<(), KeyManagerError> {
107 let key = generate_key();
108 self.save_key(
109 self.controlled_did_suffix(),
110 KeyType::NextUpdateKey,
111 &key,
112 false,
113 )?;
114 Ok(())
115 }
116
117 fn recovery_key(&self) -> Result<JWK, KeyManagerError> {
118 let recovery_key = self.read_recovery_key(self.controlled_did_suffix())?;
119 Ok(recovery_key)
120 }
121
122 fn to_attestor(&self) -> Box<dyn Attestor> {
123 Box::new(IONAttestor::new(&self.did))
124 }
125}
126
127impl IONController {
128 pub fn is_proof_in_doc_meta(&self, doc_meta: &DocumentMetadata) -> bool {
130 if let Some(property_set) = doc_meta.property_set.as_ref() {
131 property_set.contains_key("proof")
132 } else {
133 false
134 }
135 }
136
137 pub fn add_proof_service(&self, did: &str, proof: &str) -> DIDStatePatch {
139 let mut obj: Map<String, Value> = Map::new();
140 obj.insert("controller".to_string(), Value::from(did));
141 obj.insert("proofValue".to_string(), Value::from(proof.to_owned()));
142
143 DIDStatePatch::AddServices {
144 services: vec![ServiceEndpointEntry {
145 id: TRUSTCHAIN_PROOF_SERVICE_ID_VALUE.to_string(),
146 r#type: TRUSTCHAIN_PROOF_SERVICE_TYPE_VALUE.to_string(),
147 service_endpoint: ServiceEndpoint::Map(serde_json::Value::Object(obj.clone())),
148 }],
149 }
150 }
151
152 pub fn is_commitment_key(
154 &self,
155 doc_meta: &DocumentMetadata,
156 key: &JWK,
157 key_type: KeyType,
158 ) -> bool {
159 if let Ok(expected_commitment) = self.key_to_commitment(key) {
160 if let Ok(actual_commitment) = self.extract_commitment(doc_meta, key_type) {
161 actual_commitment == expected_commitment
162 } else {
163 eprintln!("Unable to extract a commitment from document metadata.");
164 false
166 }
167 } else {
168 eprintln!("Unable to convert key to commitment.");
169 false
171 }
172 }
173
174 fn extract_commitment(
176 &self,
177 doc_meta: &DocumentMetadata,
178 key_type: KeyType,
179 ) -> Result<String, TrustchainIONError> {
180 if let Some(property_set) = doc_meta.property_set.as_ref() {
181 if let Some(Metadata::Map(method)) = property_set.get("method") {
182 let k = match key_type {
183 KeyType::UpdateKey => "updateCommitment",
184 KeyType::NextUpdateKey => "updateCommitment",
185 KeyType::RecoveryKey => "recoveryCommitment",
186 _ => return Err(TrustchainIONError::IncorrectKeyType),
187 };
188 if let Some(Metadata::String(s)) = method.get(k) {
189 Ok(s.to_owned())
190 } else {
191 Err(TrustchainIONError::FailedToExtractCommitment)
192 }
193 } else {
194 Err(TrustchainIONError::FailedToExtractCommitment)
195 }
196 } else {
197 Err(TrustchainIONError::FailedToExtractCommitment)
198 }
199 }
200
201 fn key_to_commitment(&self, next_update_key: &JWK) -> Result<String, TrustchainIONError> {
203 match &PublicKeyJwk::try_from(next_update_key.to_public()) {
204 Ok(pk_jwk) => match ION::commitment_scheme(pk_jwk) {
205 Ok(commitment) => Ok(commitment),
206 Err(_) => Err(TrustchainIONError::FailedToConvertToCommitment),
207 },
208 Err(_) => Err(TrustchainIONError::FailedToConvertToCommitment),
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use trustchain_core::data::{
217 TEST_RECOVERY_KEY, TEST_SIDETREE_DOCUMENT_METADATA, TEST_TRUSTCHAIN_DOCUMENT_METADATA,
218 TEST_UPDATE_KEY,
219 };
220 use trustchain_core::utils::init;
221
222 fn test_controller(
224 did: &str,
225 controlled_did: &str,
226 ) -> Result<IONController, Box<dyn std::error::Error>> {
227 let update_key: JWK = serde_json::from_str(TEST_UPDATE_KEY)?;
228 let recovery_key: JWK = serde_json::from_str(TEST_RECOVERY_KEY)?;
229 IONController::try_from(ControllerData::new(
230 did.to_string(),
231 controlled_did.to_string(),
232 update_key,
233 recovery_key,
234 ))
235 }
236
237 #[test]
238 fn test_try_from() -> Result<(), Box<dyn std::error::Error>> {
239 init();
240 let update_key: JWK = serde_json::from_str(TEST_UPDATE_KEY)?;
241 let recovery_key: JWK = serde_json::from_str(TEST_RECOVERY_KEY)?;
242 let did = "did:example:did_try_from";
243 let controlled_did = "did:example:controlled_did_try_from";
244 let controlled_did_suffix = "controlled_did_try_from";
245
246 let target = test_controller(did, controlled_did)?;
248
249 assert_eq!(target.controlled_did_suffix(), controlled_did_suffix);
250
251 let loaded_update_key = target.update_key()?;
252 assert_eq!(loaded_update_key, update_key);
253
254 let loaded_recovery_key = target.recovery_key()?;
255 assert_eq!(loaded_recovery_key, recovery_key);
256
257 Ok(())
258 }
259
260 #[test]
261 fn test_to_attestor() -> Result<(), Box<dyn std::error::Error>> {
262 init();
263 let did = "did:example:did_to_attestor";
264 let controlled_did = "did:example:controlled_did_to_attestor";
265 let did_suffix = "did_to_attestor";
266 let controlled_did_suffix = "controlled_did_to_attestor";
267 let target = test_controller(did, controlled_did)?;
268 assert_eq!(target.did(), did);
269 assert_ne!(target.did(), controlled_did);
270 assert_eq!(target.did_suffix(), did_suffix);
271 assert_ne!(target.did_suffix(), controlled_did_suffix);
272
273 let result = target.to_attestor();
274 assert_eq!(result.did(), did);
275 assert_ne!(result.did(), controlled_did);
276 assert_eq!(result.did_suffix(), did_suffix);
277 assert_ne!(result.did_suffix(), controlled_did_suffix);
278 Ok(())
279 }
280
281 #[test]
282 fn test_is_proof_in_doc_meta() -> Result<(), Box<dyn std::error::Error>> {
283 init();
284 let did = "did:example:did_is_proof_in_doc_meta";
285 let controlled_did = "did:example:controlled_is_proof_in_doc_meta";
286 let controller = test_controller(did, controlled_did)?;
287
288 let tc_doc_meta: DocumentMetadata =
289 serde_json::from_str(TEST_TRUSTCHAIN_DOCUMENT_METADATA)?;
290 assert!(controller.is_proof_in_doc_meta(&tc_doc_meta));
291
292 let sidetree_doc_meta: DocumentMetadata =
293 serde_json::from_str(TEST_SIDETREE_DOCUMENT_METADATA)?;
294 assert!(!controller.is_proof_in_doc_meta(&sidetree_doc_meta));
295
296 Ok(())
297 }
298
299 #[test]
300 fn test_extract_commitment() -> Result<(), Box<dyn std::error::Error>> {
301 init();
302 let did = "did:example:did_extract_commitment";
303 let controlled_did = "did:example:controlled_extract_commitment";
304 let controller = test_controller(did, controlled_did)?;
305 let expected_recovery_commitment = "EiDZpHjQ5x7aRRqv6aUtmOdHsxWktAm1kU1IZl1w7iexsw";
306 let expected_update_commitment = "EiBWPR1JNdAQ4j3ZMqurb4rt10NA7s17lztFF9OIcEO3ew";
307 let doc_meta: DocumentMetadata = serde_json::from_str(TEST_TRUSTCHAIN_DOCUMENT_METADATA)?;
308
309 let update_commiment = controller.extract_commitment(&doc_meta, KeyType::UpdateKey)?;
310 assert_eq!(expected_update_commitment, update_commiment.as_str());
311
312 let next_update_commiment =
313 controller.extract_commitment(&doc_meta, KeyType::NextUpdateKey)?;
314 assert_eq!(expected_update_commitment, next_update_commiment.as_str());
315
316 let recovery_commiment = controller.extract_commitment(&doc_meta, KeyType::RecoveryKey)?;
317 assert_eq!(expected_recovery_commitment, recovery_commiment.as_str());
318 Ok(())
319 }
320
321 #[test]
322 fn test_key_to_commitment() -> Result<(), Box<dyn std::error::Error>> {
323 init();
324 let did = "did:example:did_key_to_commitment";
325 let controlled_did = "did:example:controlled_key_to_commitment";
326 let update_key: JWK = serde_json::from_str(TEST_UPDATE_KEY)?;
327 let recovery_key: JWK = serde_json::from_str(TEST_RECOVERY_KEY)?;
328
329 let controller = test_controller(did, controlled_did)?;
330
331 let expected_recovery_commitment = "EiDZpHjQ5x7aRRqv6aUtmOdHsxWktAm1kU1IZl1w7iexsw";
332 let expected_update_commitment = "EiBWPR1JNdAQ4j3ZMqurb4rt10NA7s17lztFF9OIcEO3ew";
333
334 let update_commitment = controller.key_to_commitment(&update_key)?;
335 let recovery_commitment = controller.key_to_commitment(&recovery_key)?;
336
337 assert_eq!(expected_update_commitment, update_commitment);
338 assert_eq!(expected_recovery_commitment, recovery_commitment);
339
340 Ok(())
341 }
342
343 #[test]
344 fn test_is_commitment_key() -> Result<(), Box<dyn std::error::Error>> {
345 init();
346 let did = "did:example:did_is_commitment_key";
347 let controlled_did = "did:example:controlled_is_commitment_key";
348 let update_key: JWK = serde_json::from_str(TEST_UPDATE_KEY)?;
349 let recovery_key: JWK = serde_json::from_str(TEST_RECOVERY_KEY)?;
350 let controller = test_controller(did, controlled_did)?;
351 let doc_meta: DocumentMetadata = serde_json::from_str(TEST_TRUSTCHAIN_DOCUMENT_METADATA)?;
352
353 assert!(controller.is_commitment_key(&doc_meta, &update_key, KeyType::UpdateKey));
354 assert!(controller.is_commitment_key(&doc_meta, &recovery_key, KeyType::RecoveryKey));
355 Ok(())
356 }
357
358 #[test]
359 fn test_add_proof_service() -> Result<(), Box<dyn std::error::Error>> {
360 init();
361 let did = "did:example:did_add_proof_service";
362 let controlled_did = "did:example:controlled_add_proof_service";
363 let controller = test_controller(did, controlled_did)?;
364 let proof = "test_proof_information";
365 let _ = controller.add_proof_service(controlled_did, proof);
366 Ok(())
367 }
368}