identity_storage/storage/
did_jwk_document_ext.rs1use crate::JwkGenOutput;
5use crate::JwkStorage;
6#[cfg(feature = "jpt-bbs-plus")]
7use crate::JwkStorageBbsPlusExt;
8use crate::JwkStorageDocumentError as Error;
9#[cfg(feature = "pqc")]
10use crate::JwkStoragePQ;
11#[cfg(feature = "hybrid")]
12use crate::KeyId;
13use crate::KeyIdStorage;
14use crate::KeyType;
15use crate::MethodDigest;
16use async_trait::async_trait;
17#[cfg(feature = "hybrid")]
18use identity_did::DIDCompositeJwk;
19use identity_did::DIDJwk;
20use identity_document::document::CoreDocument;
21#[cfg(feature = "hybrid")]
22use identity_verification::jwk::CompositeAlgId;
23#[cfg(feature = "hybrid")]
24use identity_verification::jwk::CompositeJwk;
25use identity_verification::jws::JwsAlgorithm;
26use identity_verification::jwu::encode_b64_json;
27#[cfg(feature = "jpt-bbs-plus")]
28use jsonprooftoken::jpa::algs::ProofAlgorithm;
29
30use super::Storage;
31use super::StorageResult;
32
33#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
35#[cfg_attr(feature = "send-sync-storage", async_trait)]
36pub trait DidJwkDocumentExt {
37 async fn new_did_jwk<K, I>(
39 storage: &Storage<K, I>,
40 key_type: KeyType,
41 alg: JwsAlgorithm,
42 ) -> StorageResult<(CoreDocument, String)>
43 where
44 K: JwkStorage,
45 I: KeyIdStorage;
46 #[cfg(feature = "pqc")]
48 async fn new_did_jwk_pqc<K, I>(
49 storage: &Storage<K, I>,
50 key_type: KeyType,
51 alg: JwsAlgorithm,
52 ) -> StorageResult<(CoreDocument, String)>
53 where
54 K: JwkStoragePQ,
55 I: KeyIdStorage;
56 #[cfg(feature = "jpt-bbs-plus")]
58 async fn new_did_jwk_zk<K, I>(
59 storage: &Storage<K, I>,
60 key_type: KeyType,
61 alg: ProofAlgorithm,
62 ) -> StorageResult<(CoreDocument, String)>
63 where
64 K: JwkStorageBbsPlusExt,
65 I: KeyIdStorage;
66
67 #[cfg(feature = "hybrid")]
69 async fn new_did_compositejwk<K, I>(
70 storage: &Storage<K, I>,
71 alg: identity_verification::jwk::CompositeAlgId,
72 ) -> StorageResult<(CoreDocument, String)>
73 where
74 K: JwkStorage + JwkStoragePQ,
75 I: KeyIdStorage;
76}
77
78#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
79#[cfg_attr(feature = "send-sync-storage", async_trait)]
80impl DidJwkDocumentExt for CoreDocument {
81 async fn new_did_jwk<K, I>(
82 storage: &Storage<K, I>,
83 key_type: KeyType,
84 alg: JwsAlgorithm,
85 ) -> StorageResult<(CoreDocument, String)>
86 where
87 K: JwkStorage,
88 I: KeyIdStorage,
89 {
90 let JwkGenOutput { key_id, jwk } = K::generate(storage.key_storage(), key_type, alg)
91 .await
92 .map_err(Error::KeyStorageError)?;
93
94 let b64 = encode_b64_json(&jwk).map_err(|err| Error::EncodingError(Box::new(err)))?;
95
96 let did =
97 DIDJwk::parse(format!("{}{}", "did:jwk:", b64).as_str()).map_err(|err| Error::EncodingError(Box::new(err)))?;
98
99 let document = CoreDocument::expand_did_jwk(did).map_err(|err| Error::EncodingError(Box::new(err)))?;
100
101 let fragment = "0";
102
103 let verification_method = document
104 .resolve_method(fragment, None)
105 .ok_or(identity_verification::Error::MissingIdFragment)
106 .map_err(Error::VerificationMethodConstructionError)?;
107
108 let method_digest = MethodDigest::new(verification_method).map_err(Error::MethodDigestConstructionError)?;
109
110 I::insert_key_id(storage.key_id_storage(), method_digest, key_id.clone())
111 .await
112 .map_err(Error::KeyIdStorageError)?;
113
114 Ok((document, fragment.to_string()))
115 }
116
117 #[cfg(feature = "pqc")]
118 async fn new_did_jwk_pqc<K, I>(
119 storage: &Storage<K, I>,
120 key_type: KeyType,
121 alg: JwsAlgorithm,
122 ) -> StorageResult<(CoreDocument, String)>
123 where
124 K: JwkStoragePQ,
125 I: KeyIdStorage,
126 {
127 let JwkGenOutput { key_id, jwk } = K::generate_pq_key(storage.key_storage(), key_type, alg)
128 .await
129 .map_err(Error::KeyStorageError)?;
130
131 let b64 = encode_b64_json(&jwk).map_err(|err| Error::EncodingError(Box::new(err)))?;
132
133 let did =
134 DIDJwk::parse(format!("{}{}", "did:jwk:", b64).as_str()).map_err(|err| Error::EncodingError(Box::new(err)))?;
135
136 let document = CoreDocument::expand_did_jwk(did).map_err(|err| Error::EncodingError(Box::new(err)))?;
137
138 let fragment = "0";
139
140 let verification_method = document
141 .resolve_method(fragment, None)
142 .ok_or(identity_verification::Error::MissingIdFragment)
143 .map_err(Error::VerificationMethodConstructionError)?;
144
145 let method_digest = MethodDigest::new(verification_method).map_err(Error::MethodDigestConstructionError)?;
146
147 I::insert_key_id(storage.key_id_storage(), method_digest, key_id.clone())
148 .await
149 .map_err(Error::KeyIdStorageError)?;
150
151 Ok((document, fragment.to_string()))
152 }
153
154 #[cfg(feature = "jpt-bbs-plus")]
155 async fn new_did_jwk_zk<K, I>(
156 storage: &Storage<K, I>,
157 key_type: KeyType,
158 alg: ProofAlgorithm,
159 ) -> StorageResult<(CoreDocument, String)>
160 where
161 K: JwkStorageBbsPlusExt,
162 I: KeyIdStorage,
163 {
164 let JwkGenOutput { key_id, jwk } = K::generate_bbs(storage.key_storage(), key_type, alg)
165 .await
166 .map_err(Error::KeyStorageError)?;
167
168 let b64 = encode_b64_json(&jwk).map_err(|err| Error::EncodingError(Box::new(err)))?;
169
170 let did =
171 DIDJwk::parse(format!("{}{}", "did:jwk:", b64).as_str()).map_err(|err| Error::EncodingError(Box::new(err)))?;
172
173 let document = CoreDocument::expand_did_jwk(did).map_err(|err| Error::EncodingError(Box::new(err)))?;
174
175 let fragment = "0";
176
177 let verification_method = document
178 .resolve_method(fragment, None)
179 .ok_or(identity_verification::Error::MissingIdFragment)
180 .map_err(Error::VerificationMethodConstructionError)?;
181
182 let method_digest = MethodDigest::new(verification_method).map_err(Error::MethodDigestConstructionError)?;
183
184 I::insert_key_id(storage.key_id_storage(), method_digest, key_id.clone())
185 .await
186 .map_err(Error::KeyIdStorageError)?;
187
188 Ok((document, fragment.to_string()))
189 }
190
191 #[cfg(feature = "hybrid")]
192 async fn new_did_compositejwk<K, I>(
193 storage: &Storage<K, I>,
194 alg: CompositeAlgId,
195 ) -> StorageResult<(CoreDocument, String)>
196 where
197 K: JwkStorage + JwkStoragePQ,
198 I: KeyIdStorage,
199 {
200 use identity_verification::jwk::PostQuantumJwk;
201 use identity_verification::jwk::TraditionalJwk;
202
203 let (pq_key_type, pq_alg, trad_key_type, trad_alg) = match alg {
204 CompositeAlgId::IdMldsa44Ed25519 => (
205 KeyType::from_static_str("AKP"),
206 JwsAlgorithm::ML_DSA_44,
207 KeyType::from_static_str("Ed25519"),
208 JwsAlgorithm::EdDSA,
209 ),
210 CompositeAlgId::IdMldsa65Ed25519 => (
211 KeyType::from_static_str("AKP"),
212 JwsAlgorithm::ML_DSA_65,
213 KeyType::from_static_str("Ed25519"),
214 JwsAlgorithm::EdDSA,
215 ),
216 _ => {
217 return Err(Error::InvalidJwsAlgorithm);
218 }
219 };
220
221 let JwkGenOutput {
222 key_id: t_key_id,
223 jwk: t_jwk,
224 } = K::generate(storage.key_storage(), trad_key_type, trad_alg)
225 .await
226 .map_err(Error::KeyStorageError)?;
227
228 let JwkGenOutput {
229 key_id: pq_key_id,
230 jwk: pq_jwk,
231 } = K::generate_pq_key(storage.key_storage(), pq_key_type, pq_alg)
232 .await
233 .map_err(Error::KeyStorageError)?;
234
235 let key_id = KeyId::new(format!("{}~{}", t_key_id.as_str(), pq_key_id.as_str()));
236
237 let pq_jwk = PostQuantumJwk::try_from(pq_jwk).map_err(|err| Error::EncodingError(Box::new(err)))?;
238
239 let traditional_jwk = TraditionalJwk::try_from(t_jwk).map_err(|err| Error::EncodingError(Box::new(err)))?;
240
241 let composite_pk = CompositeJwk::new(alg, traditional_jwk, pq_jwk);
242
243 let b64 = encode_b64_json(&composite_pk).map_err(|err| Error::EncodingError(Box::new(err)))?;
244
245 let did = DIDCompositeJwk::parse(format!("{}{}", "did:compositejwk:", b64).as_str())
246 .map_err(|err| Error::EncodingError(Box::new(err)))?;
247
248 let document = CoreDocument::expand_did_compositejwk(did).map_err(|err| Error::EncodingError(Box::new(err)))?;
249
250 let fragment = "0";
251
252 let verification_method = document
253 .resolve_method(fragment, None)
254 .ok_or(identity_verification::Error::MissingIdFragment)
255 .map_err(Error::VerificationMethodConstructionError)?;
256
257 let method_digest = MethodDigest::new(verification_method).map_err(Error::MethodDigestConstructionError)?;
258
259 I::insert_key_id(storage.key_id_storage(), method_digest, key_id.clone())
260 .await
261 .map_err(Error::KeyIdStorageError)?;
262
263 Ok((document, fragment.to_string()))
264 }
265}