1use crate::{
5 library::from_did_key_verification_method::from_did_key_verification_method,
6 types::didcomm::context::DidCommContext, DidCommPrivateContext, DidCommPublicContext, Identity, IdentityBox,
7 IdentityResolver, IdentityResolverError, PrivateIdentity, SignError,
8};
9use anyhow::anyhow;
10use async_trait::async_trait;
11use co_primitives::{tags, Network, Secret};
12use did_key::{
13 from_existing_key, generate, resolve, CoreSign, DIDCore, Ed25519KeyPair, KeyMaterial, PatchedKeyPair, X25519KeyPair,
14};
15use std::{collections::BTreeSet, fmt::Debug, sync::Arc};
16
17#[derive(Clone)]
18pub struct DidKeyIdentity {
19 did: String,
20 key: Arc<PatchedKeyPair>,
21 private: bool,
22}
23impl DidKeyIdentity {
24 pub fn generate(seed: Option<&[u8]>) -> Self {
30 Self::from_key(generate::<Ed25519KeyPair>(seed))
31 }
32
33 pub fn generate_x25519(seed: Option<&[u8]>) -> Self {
34 Self::from_key(generate::<X25519KeyPair>(seed))
35 }
36
37 pub fn from_identity(identity: &str) -> Result<Self, anyhow::Error> {
38 Self::try_from(identity)
39 }
40
41 pub fn from_key(key: PatchedKeyPair) -> Self {
42 let private = !key.private_key_bytes().is_empty();
43 Self { did: key.get_did_document(Default::default()).id, key: Arc::new(key), private }
44 }
45
46 pub fn from_bytes(bytes: &[u8]) -> Result<Self, anyhow::Error> {
47 Self::try_from(bytes)
48 }
49
50 pub fn to_bytes(&self) -> &[u8] {
51 self.identity().as_bytes()
52 }
53
54 pub fn public_key_bytes(&self) -> Vec<u8> {
59 self.key.as_ref().public_key_bytes()
60 }
61
62 pub fn private_key_bytes(&self) -> Secret {
63 self.key.as_ref().private_key_bytes().into()
64 }
65
66 pub fn import(key: &co_core_keystore::Key) -> Result<Self, anyhow::Error> {
67 match (key.tags.string("format"), &key.secret) {
68 (Some("Ed25519"), co_core_keystore::Secret::PrivateKey(secret)) => {
69 Ok(Self::from_key(from_existing_key::<Ed25519KeyPair>(&[], Some(secret.divulge()))))
70 },
71 (Some("X25519"), co_core_keystore::Secret::PrivateKey(secret)) => {
72 Ok(Self::from_key(from_existing_key::<X25519KeyPair>(&[], Some(secret.divulge()))))
73 },
74 _ => Err(anyhow!("Invalid identity format or key")),
75 }
76 }
77
78 pub fn export(&self) -> Result<co_core_keystore::Key, anyhow::Error> {
79 Ok(co_core_keystore::Key {
80 description: "did:key identitiy".to_owned(),
81 name: self.identity().to_owned(),
82 tags: tags!("type": "co-identity", "format": "Ed25519"), uri: self.identity().to_owned(),
84 secret: co_core_keystore::Secret::PrivateKey(self.key.private_key_bytes().into()),
85 })
86 }
87}
88impl Debug for DidKeyIdentity {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 f.debug_struct("DidKeyIdentity")
91 .field("did", &self.did)
92 .field("public_key", &format_args!("{:02X?}", self.key.public_key_bytes()))
93 .finish()
94 }
95}
96impl TryFrom<&[u8]> for DidKeyIdentity {
97 type Error = anyhow::Error;
98
99 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
100 Ok(Self::from_key(resolve(std::str::from_utf8(value)?).map_err(|e| anyhow!("resolve failed: {:?}", e))?))
101 }
102}
103impl TryFrom<&str> for DidKeyIdentity {
104 type Error = anyhow::Error;
105
106 fn try_from(value: &str) -> Result<Self, Self::Error> {
107 Ok(Self::from_key(resolve(value).map_err(|e| anyhow!("resolve failed: {:?}", e))?))
108 }
109}
110impl Identity for DidKeyIdentity {
111 fn identity(&self) -> &str {
112 &self.did
113 }
114
115 fn public_key(&self) -> Option<Vec<u8>> {
116 None
118 }
119
120 fn verify(&self, signature: &[u8], data: &[u8], public_key: Option<&[u8]>) -> bool {
121 if let Some(key) = public_key {
123 if key != self.key.public_key_bytes() {
124 return false;
125 }
126 }
127
128 self.key.verify(data, signature).is_ok()
130 }
131
132 fn didcomm_public(&self) -> Option<DidCommPublicContext> {
133 let doc = self
134 .key
135 .get_did_document(did_key::Config { use_jose_format: false, serialize_secrets: false });
136 let verfication_method = from_did_key_verification_method(doc.verification_method.first()?.clone(), None);
137 let key_aggrements = doc.key_agreement?;
138 let key_aggrement_id = key_aggrements.first()?;
139 let key_agreement = from_did_key_verification_method(
140 doc.verification_method
141 .iter()
142 .find(|item| &item.id == key_aggrement_id)?
143 .clone(),
144 None,
145 );
146 Some(DidCommPublicContext::new(self.identity().to_owned(), verfication_method, key_agreement))
147 }
148
149 fn networks(&self) -> BTreeSet<Network> {
150 Default::default()
151 }
152}
153impl PrivateIdentity for DidKeyIdentity {
154 fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SignError> {
155 if !self.private {
156 return Err(SignError::Unauthorized);
157 }
158 Ok(self.key.sign(data))
159 }
160
161 fn didcomm_private(&self) -> Option<DidCommPrivateContext> {
162 let public = self.didcomm_public()?;
163 let doc = self
164 .key
165 .get_did_document(did_key::Config { use_jose_format: false, serialize_secrets: true });
166 let verfication_method_private = doc.verification_method.iter().find_map(|vm| {
167 if vm.id == public.verification_method().id && vm.private_key.is_some() {
168 from_did_key_verification_method(vm.clone(), vm.private_key.clone())
169 .public_key_bytes()
170 .ok()
171 } else {
172 None
173 }
174 })?;
175 let key_agreement_private = doc.verification_method.iter().find_map(|vm| {
176 if vm.id == public.key_agreement().id && vm.private_key.is_some() {
177 from_did_key_verification_method(vm.clone(), vm.private_key.clone())
178 .public_key_bytes()
179 .ok()
180 } else {
181 None
182 }
183 })?;
184 Some(DidCommPrivateContext::new(public, verfication_method_private.into(), key_agreement_private.into()))
185 }
186}
187
188#[derive(Debug, Clone)]
189pub struct DidKeyIdentityResolver {}
190impl Default for DidKeyIdentityResolver {
191 fn default() -> Self {
192 Self::new()
193 }
194}
195impl DidKeyIdentityResolver {
196 pub fn new() -> DidKeyIdentityResolver {
197 Self {}
198 }
199}
200#[async_trait]
201impl IdentityResolver for DidKeyIdentityResolver {
202 async fn resolve(&self, identity: &str) -> Result<IdentityBox, IdentityResolverError> {
203 if identity.starts_with("did:key:") {
204 if let Ok(did_key_identity) = DidKeyIdentity::try_from(identity) {
205 return Ok(IdentityBox::new(did_key_identity));
206 }
207 }
208 Err(IdentityResolverError::NotFound)
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use crate::{DidCommHeader, DidKeyIdentity, Identity, IdentityBox, MemoryIdentityResolver, PrivateIdentity};
215 use co_primitives::StaticCoDate;
216
217 #[test]
218 fn it_should_sign_and_verfiy() {
219 let data = "hello world".as_bytes();
220 let identity = DidKeyIdentity::generate(None);
221 let signature = identity.sign(data).unwrap();
222 assert!(identity.verify(signature.as_slice(), data, None));
223 }
224
225 #[test]
226 fn it_should_sign_and_verfiy_with_public_key() {
227 let data = "hello world".as_bytes();
228 let identity = DidKeyIdentity::generate(None);
229 let public_key = identity.public_key();
230 let signature = identity.sign(data).unwrap();
231 assert!(identity.verify(signature.as_slice(), data, public_key.as_deref()));
232 }
233
234 #[test]
235 fn it_should_have_public_context() {
236 let identity = DidKeyIdentity::generate(None);
237 identity.try_didcomm_public().unwrap();
238 }
239
240 #[test]
241 fn it_should_have_private_context() {
242 let identity = DidKeyIdentity::generate(None);
243 identity.try_didcomm_private().unwrap();
244 }
245
246 #[test]
247 fn test_import_export() {
248 let identity = DidKeyIdentity::generate(None);
249 let export = identity.export().unwrap();
250 let import = DidKeyIdentity::import(&export).unwrap();
251 import.try_didcomm_public().unwrap();
252 import.try_didcomm_private().unwrap();
253 }
254
255 #[tokio::test]
256 async fn test_jwe_roundtrip() {
257 let from = DidKeyIdentity::import(&DidKeyIdentity::generate(None).export().unwrap()).unwrap();
260 let to = DidKeyIdentity::import(&DidKeyIdentity::generate(None).export().unwrap()).unwrap();
261
262 let mut resolver = MemoryIdentityResolver::default();
264 resolver.insert(IdentityBox::new(from.clone())).await;
265 resolver.insert(IdentityBox::new(to.clone())).await;
266
267 let (from_private, to_public, header) = DidCommHeader::create(&StaticCoDate(0), &from, &to, "test").unwrap();
269 let message = from_private.jwe(&to_public, header.clone(), "null").unwrap();
270
271 let to_private = to.try_didcomm_private().unwrap();
273 let (received_header, received_body) = to_private.receive(&resolver, &message).await.unwrap();
274 assert_eq!(received_header, header);
275 assert_eq!(received_body, "null");
276 }
277}