1use crate::errors::Error;
5use affinidi_did_common::{
6 Document,
7 verification_method::{VerificationMethod, VerificationRelationship},
8};
9use affinidi_secrets_resolver::{
10 crypto::ed25519::ed25519_public_to_x25519_public_key,
11 multicodec::{ED25519_PUB, MultiEncoded, P256_PUB, P384_PUB, SECP256K1_PUB, X25519_PUB},
12};
13use base58::FromBase58;
14use serde_json::{Value, json};
15use std::collections::HashMap;
16use url::Url;
17
18pub mod create;
19pub mod errors;
20
21pub struct DIDKey;
22
23impl DIDKey {
24 pub fn resolve<'a>(did: &'a str) -> Result<Document, Error<'a>> {
26 if !did.starts_with("did:key:z") {
27 return Err(Error::InvalidDid(
28 did,
29 "DID Url doesn't start with did:key:z".to_string(),
30 ));
31 }
32
33 let identifier = &did[8..]; let decoded = identifier[1..]
37 .from_base58()
38 .map_err(|_| Error::InvalidPublicKey("Couldn't decode base58".to_string()))?;
39
40 let multicodec = MultiEncoded::new(decoded.as_slice())
41 .map_err(|_| Error::InvalidPublicKey("Unknown multicodec value".to_string()))?;
42
43 let vm_id = Url::parse(&[did, "#", identifier].concat())
44 .map_err(|e| Error::InvalidDidUrl(did, e.to_string()))?;
45 let mut vms = Vec::new();
46
47 let mut key_agreement = Vec::new();
48
49 match multicodec.codec() {
51 P256_PUB => {
52 if multicodec.data().len() != 33 {
53 return Err(Error::InvalidPublicKeyLength(multicodec.data().len()));
54 }
55 key_agreement.push(VerificationRelationship::Reference(vm_id.clone()));
56 }
57 P384_PUB => {
58 if multicodec.data().len() != 49 {
59 return Err(Error::InvalidPublicKeyLength(multicodec.data().len()));
60 }
61 key_agreement.push(VerificationRelationship::Reference(vm_id.clone()));
62 }
63 SECP256K1_PUB => {
64 if multicodec.data().len() != 33 {
65 return Err(Error::InvalidPublicKeyLength(multicodec.data().len()));
66 }
67 key_agreement.push(VerificationRelationship::Reference(vm_id.clone()));
68 }
69 X25519_PUB => {
70 if multicodec.data().len() != 32 {
71 return Err(Error::InvalidPublicKeyLength(multicodec.data().len()));
72 }
73 key_agreement.push(VerificationRelationship::Reference(vm_id.clone()));
74 }
75 ED25519_PUB => {
76 if multicodec.data().len() != 32 {
77 return Err(Error::InvalidPublicKeyLength(multicodec.data().len()));
78 }
79
80 let (x25519_encoded, _) =
81 ed25519_public_to_x25519_public_key(identifier).map_err(|e| {
82 Error::InvalidPublicKey(format!(
83 "Couldn't convert ed25519 to x25519 public-key: {e}"
84 ))
85 })?;
86
87 let mut property_set = HashMap::new();
88 property_set.insert(
89 "publicKeyMultibase".to_string(),
90 Value::String(x25519_encoded.clone()),
91 );
92
93 let x25519_vm_id =
94 Url::parse(&[did, "#", &x25519_encoded].concat()).map_err(|e| {
95 Error::InvalidPublicKey(format!(
96 "Couldn't create valid URL ID for x25519 VerificationMethod: {e}"
97 ))
98 })?;
99
100 vms.push(VerificationMethod {
101 id: x25519_vm_id.clone(),
102 type_: "Multikey".to_string(),
103 controller: Url::parse(did)
104 .map_err(|e| Error::InvalidDidUrl(did, e.to_string()))?,
105 expires: None,
106 revoked: None,
107 property_set,
108 });
109
110 key_agreement.push(VerificationRelationship::Reference(x25519_vm_id.clone()));
111 }
112 _ => {
113 return Err(Error::UnsupportedPublicKeyType(format!(
114 "Unknown codec: {}",
115 multicodec.codec()
116 )));
117 }
118 }
119
120 let mut property_set = HashMap::new();
121 property_set.insert(
122 "publicKeyMultibase".to_string(),
123 Value::String(identifier.to_string()),
124 );
125
126 vms.insert(
127 0,
128 VerificationMethod {
129 id: vm_id.clone(),
130 type_: "Multikey".to_string(),
131 controller: Url::parse(did)
132 .map_err(|e| Error::InvalidDidUrl(did, e.to_string()))?,
133 expires: None,
134 revoked: None,
135 property_set,
136 },
137 );
138
139 let vm_relationship = VerificationRelationship::Reference(vm_id.clone());
140
141 let mut parameters_set = HashMap::new();
142 parameters_set.insert(
143 "@context".to_string(),
144 json!([
145 "https://www.w3.org/ns/did/v1".to_string(),
146 "https://w3id.org/security/multikey/v1".to_string(),
147 ]),
148 );
149
150 Ok(Document {
151 id: Url::parse(did).map_err(|e| Error::InvalidDidUrl(did, e.to_string()))?,
152 verification_method: vms,
153 authentication: vec![vm_relationship.clone()],
154 assertion_method: vec![vm_relationship.clone()],
155 key_agreement,
156 capability_invocation: vec![vm_relationship.clone()],
157 capability_delegation: vec![vm_relationship.clone()],
158 service: vec![],
159 parameters_set,
160 })
161 }
162}