1use multibase::Base;
5use ssi_dids_core::{
6 document::{
7 self,
8 representation::{self, MediaType},
9 verification_method::ValueOrReference,
10 DIDVerificationMethod,
11 },
12 resolution::{self, DIDMethodResolver, Error},
13 DIDBuf, DIDMethod, DIDURLBuf, Document,
14};
15use ssi_jwk::JWK;
16use ssi_multicodec::MultiEncodedBuf;
17use static_iref::{iri, iri_ref};
18use std::collections::BTreeMap;
19
20pub struct DIDKey;
24
25impl DIDKey {
26 pub fn generate(jwk: &JWK) -> Result<DIDBuf, GenerateError> {
27 let multi_encoded = jwk.to_multicodec()?;
28 let id = multibase::encode(multibase::Base::Base58Btc, multi_encoded.into_bytes());
29
30 Ok(DIDBuf::from_string(format!("did:key:{id}")).unwrap())
31 }
32
33 pub fn generate_url(jwk: &JWK) -> Result<DIDURLBuf, GenerateError> {
34 let multi_encoded = jwk.to_multicodec()?;
35 let id = multibase::encode(multibase::Base::Base58Btc, multi_encoded.into_bytes());
36
37 Ok(DIDURLBuf::from_string(format!("did:key:{id}#{id}")).unwrap())
38 }
39}
40
41pub type GenerateError = ssi_jwk::ToMulticodecError;
42
43impl DIDMethod for DIDKey {
44 const DID_METHOD_NAME: &'static str = "key";
45}
46
47impl DIDMethodResolver for DIDKey {
48 async fn resolve_method_representation<'a>(
49 &'a self,
50 id: &'a str,
51 options: resolution::Options,
52 ) -> Result<resolution::Output<Vec<u8>>, Error> {
53 let did = DIDBuf::from_string(format!("did:key:{id}")).unwrap();
54
55 let (_base, data) =
56 multibase::decode(id).map_err(|_| Error::InvalidMethodSpecificId(id.to_owned()))?;
57
58 let multi_encoded = MultiEncodedBuf::new(data)
59 .map_err(|_| Error::InvalidMethodSpecificId(id.to_owned()))?;
60
61 let vm_type = match options.parameters.public_key_format {
62 Some(name) => VerificationMethodType::from_name(&name).ok_or_else(|| {
63 Error::Internal(format!(
64 "verification method type `{name}` unsupported by did:key"
65 ))
66 })?,
67 None => VerificationMethodType::Multikey,
68 };
69
70 let public_key = vm_type.decode(id, multi_encoded)?;
71
72 let vm_didurl = DIDURLBuf::from_string(format!("{did}#{id}")).unwrap();
73
74 let mut doc = Document::new(did.to_owned());
75 doc.verification_method.push(
76 VerificationMethod {
77 id: vm_didurl.clone(),
78 type_: vm_type,
79 controller: did,
80 public_key,
81 }
82 .into(),
83 );
84 doc.verification_relationships
85 .authentication
86 .push(ValueOrReference::Reference(vm_didurl.clone().into()));
87 doc.verification_relationships
88 .assertion_method
89 .push(ValueOrReference::Reference(vm_didurl.into()));
90
91 let mut json_ld_context = Vec::new();
92 if let Some(context) = vm_type.context_entry() {
93 json_ld_context.push(context)
94 }
95
96 let content_type = options.accept.unwrap_or(MediaType::JsonLd);
97 let represented = doc.into_representation(representation::Options::from_media_type(
98 content_type,
99 move || representation::json_ld::Options {
100 context: representation::json_ld::Context::array(
101 representation::json_ld::DIDContext::V1,
102 json_ld_context,
103 ),
104 },
105 ));
106
107 Ok(resolution::Output::new(
108 represented.to_bytes(),
109 document::Metadata::default(),
110 resolution::Metadata::from_content_type(Some(content_type.to_string())),
111 ))
112 }
113}
114
115#[derive(Debug, Clone, Copy)]
116#[non_exhaustive]
117pub enum VerificationMethodType {
118 Multikey,
119 Ed25519VerificationKey2020,
120 Ed25519VerificationKey2018,
121 #[cfg(feature = "secp256k1")]
122 EcdsaSecp256k1VerificationKey2019,
123 EcdsaSecp256r1VerificationKey2019,
124 JsonWebKey2020,
125 #[cfg(feature = "bbs")]
126 Bls12381G2Key2020,
127}
128
129impl VerificationMethodType {
130 pub fn from_name(name: &str) -> Option<Self> {
131 match name {
132 "Multikey" => Some(Self::Multikey),
133 "Ed25519VerificationKey2020" => Some(Self::Ed25519VerificationKey2020),
134 "Ed25519VerificationKey2018" => Some(Self::Ed25519VerificationKey2018),
135 #[cfg(feature = "secp256k1")]
136 "EcdsaSecp256k1VerificationKey2019" => Some(Self::EcdsaSecp256k1VerificationKey2019),
137 "EcdsaSecp256r1VerificationKey2019" => Some(Self::EcdsaSecp256r1VerificationKey2019),
138 "JsonWebKey2020" => Some(Self::JsonWebKey2020),
139 #[cfg(feature = "bbs")]
140 "Bls12381G2Key2020" => Some(Self::Bls12381G2Key2020),
141 _ => None,
142 }
143 }
144
145 pub fn name(&self) -> &'static str {
146 match self {
147 Self::Multikey => "Multikey",
148 Self::Ed25519VerificationKey2020 => "Ed25519VerificationKey2020",
149 Self::Ed25519VerificationKey2018 => "Ed25519VerificationKey2018",
150 #[cfg(feature = "secp256k1")]
151 Self::EcdsaSecp256k1VerificationKey2019 => "EcdsaSecp256k1VerificationKey2019",
152 Self::EcdsaSecp256r1VerificationKey2019 => "EcdsaSecp256r1VerificationKey2019",
153 Self::JsonWebKey2020 => "JsonWebKey2020",
154 #[cfg(feature = "bbs")]
155 Self::Bls12381G2Key2020 => "Bls12381G2Key2020",
156 }
157 }
158
159 #[allow(unused_variables)]
160 pub fn decode(&self, id: &str, encoded: MultiEncodedBuf) -> Result<PublicKey, Error> {
161 match self {
162 Self::Multikey => {
163 let multibase_encoded = multibase::encode(Base::Base58Btc, encoded.as_bytes());
164 Ok(PublicKey::Multibase(multibase_encoded))
165 }
166 Self::Ed25519VerificationKey2020 => match encoded.codec() {
167 ssi_multicodec::ED25519_PUB => {
168 let multibase_encoded = multibase::encode(Base::Base58Btc, encoded.as_bytes());
169 Ok(PublicKey::Multibase(multibase_encoded))
170 }
171 _ => Err(Error::internal("did:key is not ED25519 as required by method type `Ed25519VerificationKey2020`")),
172 }
173 Self::Ed25519VerificationKey2018 => match encoded.codec() {
174 ssi_multicodec::ED25519_PUB => {
175 let key = bs58::encode(encoded.data()).into_string();
176 Ok(PublicKey::Base58(key))
177 }
178 _ => Err(Error::internal("did:key is not ED25519 as required by method type `Ed25519VerificationKey2018`")),
179 }
180 #[cfg(feature = "secp256k1")]
181 Self::EcdsaSecp256k1VerificationKey2019 => match encoded.codec() {
182 ssi_multicodec::SECP256K1_PUB => {
183 match ssi_jwk::secp256k1_parse(encoded.data()) {
184 Ok(jwk) => Ok(PublicKey::Jwk(Box::new(jwk))),
185 Err(_) => Err(Error::InvalidMethodSpecificId(id.to_owned())),
186 }
187 }
188 _ => Err(Error::internal("did:key is not SECP256K1 as required by method type `EcdsaSecp256k1VerificationKey2019`")),
189 }
190 Self::EcdsaSecp256r1VerificationKey2019 => match encoded.codec() {
191 ssi_multicodec::P256_PUB => {
192 let multibase_encoded = multibase::encode(Base::Base58Btc, encoded.as_bytes());
193 Ok(PublicKey::Multibase(multibase_encoded))
194 }
195 _ => Err(Error::internal("did:key is not P256 as required by method type `EcdsaSecp256r1VerificationKey2019`")),
196 }
197 Self::JsonWebKey2020 => {
198 let key = JWK::from_multicodec(&encoded)
199 .map_err(Error::internal)?;
200 Ok(PublicKey::Jwk(Box::new(key)))
201 }
202 #[cfg(feature = "bbs")]
203 Self::Bls12381G2Key2020 => match encoded.codec() {
204 ssi_multicodec::BLS12_381_G2_PUB => {
205 let jwk = ssi_jwk::bls12381g2_parse(encoded.data()).map_err(Error::internal)?;
206 Ok(PublicKey::Jwk(Box::new(jwk)))
209 }
210 _ => Err(Error::internal("did:key is not BLS12_381_G2 as required by method type `Bls12381G2Key2020`")),
211 }
212 }
213 }
214
215 pub fn context_entry(&self) -> Option<ssi_json_ld::syntax::ContextEntry> {
216 use ssi_json_ld::syntax::{
217 context::{
218 term_definition::{Expanded, Id, Type, TypeKeyword},
219 Definition, TermDefinition,
220 },
221 ContextEntry, Nullable,
222 };
223 match self {
224 Self::Multikey => Some(ContextEntry::IriRef(
225 iri_ref!("https://w3id.org/security/multikey/v1").to_owned(),
226 )),
227 Self::Ed25519VerificationKey2020 => Some(ContextEntry::IriRef(
228 iri_ref!("https://w3id.org/security/suites/ed25519-2020/v1").to_owned(),
229 )),
230 Self::Ed25519VerificationKey2018 => Some(ContextEntry::IriRef(
231 iri_ref!("https://w3id.org/security/suites/ed25519-2018/v1").to_owned(),
232 )),
233 #[cfg(feature = "secp256k1")]
234 Self::EcdsaSecp256k1VerificationKey2019 => {
235 let mut definition = Definition::new();
236 definition.bindings.insert(
237 "EcdsaSecp256k1VerificationKey2019".into(),
238 TermDefinition::Simple(
239 iri!("https://w3id.org/security#EcdsaSecp256k1VerificationKey2019")
240 .to_owned()
241 .into(),
242 )
243 .into(),
244 );
245 definition.bindings.insert(
246 "publicKeyJwk".into(),
247 TermDefinition::Expanded(Box::new(Expanded {
248 id: Some(Nullable::Some(Id::Term(
249 iri!("https://w3id.org/security#publicKeyJwk")
250 .to_owned()
251 .into_string(),
252 ))),
253 type_: Some(Nullable::Some(Type::Keyword(TypeKeyword::Json))),
254 ..Default::default()
255 }))
256 .into(),
257 );
258 Some(ContextEntry::Definition(definition))
259 }
260 Self::EcdsaSecp256r1VerificationKey2019 => {
261 let mut definition = Definition::new();
262 definition.bindings.insert(
263 "EcdsaSecp256r1VerificationKey2019".into(),
264 TermDefinition::Simple(
265 iri!("https://w3id.org/security#EcdsaSecp256r1VerificationKey2019")
266 .to_owned()
267 .into(),
268 )
269 .into(),
270 );
271 definition.bindings.insert(
272 "publicKeyMultibase".into(),
273 TermDefinition::Expanded(Box::new(Expanded {
274 id: Some(Nullable::Some(Id::Term(
275 iri!("https://w3id.org/security#publicMultibase")
276 .to_owned()
277 .into_string(),
278 ))),
279 type_: Some(Nullable::Some(Type::Keyword(TypeKeyword::Json))),
280 ..Default::default()
281 }))
282 .into(),
283 );
284 Some(ContextEntry::Definition(definition))
285 }
286 Self::JsonWebKey2020 => Some(ContextEntry::IriRef(
287 iri_ref!("https://w3id.org/security/suites/jws-2020/v1").to_owned(),
288 )),
289 #[cfg(feature = "bbs")]
290 Self::Bls12381G2Key2020 => {
291 let mut definition = Definition::new();
292 definition.bindings.insert(
293 "Bls12381G2Key2020".into(),
294 TermDefinition::Simple(
295 iri!("https://w3id.org/security#Bls12381G2Key2020")
296 .to_owned()
297 .into(),
298 )
299 .into(),
300 );
301 definition.bindings.insert(
302 "publicKeyJwk".into(),
303 TermDefinition::Expanded(Box::new(Expanded {
304 id: Some(Nullable::Some(Id::Term(
305 iri!("https://w3id.org/security#publicKeyJwk")
306 .to_owned()
307 .into_string(),
308 ))),
309 type_: Some(Nullable::Some(Type::Keyword(TypeKeyword::Json))),
310 ..Default::default()
311 }))
312 .into(),
313 );
314 Some(ContextEntry::Definition(definition))
315 }
316 }
317 }
318}
319
320pub struct VerificationMethod {
321 id: DIDURLBuf,
322 type_: VerificationMethodType,
323 controller: DIDBuf,
324 public_key: PublicKey,
325}
326
327impl From<VerificationMethod> for DIDVerificationMethod {
328 fn from(value: VerificationMethod) -> Self {
329 let mut properties = BTreeMap::new();
330
331 match value.public_key {
332 PublicKey::Jwk(jwk) => {
333 properties.insert(
334 "publicKeyJwk".to_owned(),
335 serde_json::to_value(jwk).unwrap(),
336 );
337 }
338 PublicKey::Base58(key) => {
339 properties.insert("publicKeyBase58".to_owned(), key.into());
340 }
341 PublicKey::Multibase(key) => {
342 properties.insert("publicKeyMultibase".to_owned(), key.into());
343 }
344 }
345
346 Self {
347 id: value.id,
348 type_: value.type_.name().to_owned(),
349 controller: value.controller,
350 properties,
351 }
352 }
353}
354
355pub enum PublicKey {
356 Jwk(Box<JWK>),
357 Base58(String),
358 Multibase(String),
359}
360
361#[cfg(test)]
362mod tests {
363 use rand_chacha::rand_core::SeedableRng;
364 use resolution::Parameters;
365 use ssi_claims::{
366 data_integrity::{AnyInputSuiteOptions, AnySuite},
367 vc::v1::JsonCredential,
368 VerificationParameters,
369 };
370 use ssi_data_integrity::{CryptographicSuite, ProofOptions as SuiteOptions};
371 use ssi_dids_core::{
372 did, resolution::Options, DIDResolver, VerificationMethodDIDResolver, DIDURL,
373 };
374 use ssi_jwk::JWKResolver;
375 use ssi_verification_methods::AnyMethod;
376 use ssi_verification_methods_core::{ProofPurpose, ReferenceOrOwned, SingleSecretSigner};
377 use static_iref::uri;
378
379 use super::*;
380
381 #[async_std::test]
382 async fn from_did_key() {
383 let did_url = DIDURL::new(b"did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH").unwrap();
384 let output = DIDKey.dereference(did_url).await.unwrap();
385 let vm = output.content.into_verification_method().unwrap();
386 eprintln!("vm = {}", serde_json::to_string_pretty(&vm).unwrap());
387 vm.properties.get("publicKeyMultibase").unwrap();
388 }
389
390 #[async_std::test]
391 async fn from_did_key_with_format() {
392 let did_url = DIDURL::new(b"did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH").unwrap();
393 let output = DIDKey
394 .dereference_with(
395 did_url,
396 Options {
397 accept: None,
398 parameters: Parameters {
399 public_key_format: Some("Ed25519VerificationKey2018".to_string()),
400 ..Default::default()
401 },
402 },
403 )
404 .await
405 .unwrap();
406 let vm = output.content.into_verification_method().unwrap();
407 vm.properties.get("publicKeyBase58").unwrap();
408 }
409
410 #[async_std::test]
411 #[cfg(feature = "secp256k1")]
412 async fn from_did_key_secp256k1() {
413 let did = did!("did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme");
414 DIDKey.resolve(did).await.unwrap();
415
416 let did_url = DIDURL::new(b"did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme#zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme").unwrap();
417 let output = DIDKey
418 .dereference_with(
419 did_url,
420 Options {
421 accept: None,
422 parameters: Parameters {
423 public_key_format: Some("EcdsaSecp256k1VerificationKey2019".to_string()),
424 ..Default::default()
425 },
426 },
427 )
428 .await
429 .unwrap();
430 let mut vm = output.content.into_verification_method().unwrap();
431 let key: JWK =
432 serde_json::from_value(vm.properties.remove("publicKeyJwk").unwrap()).unwrap();
433
434 let did1 = DIDKey::generate(&key).unwrap();
436 assert_eq!(did1, did);
437 }
438
439 #[cfg(feature = "secp256r1")]
440 #[async_std::test]
441 async fn from_did_key_p256() {
442 let did = did!("did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169");
444 DIDKey.resolve(did).await.unwrap();
445
446 let did_url = DIDURL::new(b"did:key:zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169#zDnaerDaTF5BXEavCrfRZEk316dpbLsfPDZ3WJ5hRTPFU2169").unwrap();
447 let output = DIDKey
448 .dereference_with(
449 did_url,
450 Options {
451 accept: None,
452 parameters: Parameters {
453 public_key_format: Some("EcdsaSecp256r1VerificationKey2019".to_string()),
454 ..Default::default()
455 },
456 },
457 )
458 .await
459 .unwrap();
460 let vm = output.content.into_verification_method().unwrap();
461 let multibase_key = vm
462 .properties
463 .get("publicKeyMultibase")
464 .unwrap()
465 .as_str()
466 .unwrap();
467 let (base, encoded_key) = multibase::decode(multibase_key).unwrap();
468 assert_eq!(base, multibase::Base::Base58Btc);
469 let encoded_key = ssi_multicodec::MultiEncodedBuf::new(encoded_key).unwrap();
470 assert_eq!(encoded_key.codec(), ssi_multicodec::P256_PUB);
471 let key = ssi_jwk::JWK::from_multicodec(&encoded_key).unwrap();
472 eprintln!("key {}", serde_json::to_string_pretty(&key).unwrap());
473
474 let key_expected: JWK = serde_json::from_value(serde_json::json!({
476 "kty": "EC",
477 "crv": "P-256",
478 "x": "fyNYMN0976ci7xqiSdag3buk-ZCwgXU4kz9XNkBlNUI",
479 "y": "hW2ojTNfH7Jbi8--CJUo3OCbH3y5n91g-IMA9MLMbTU"
480 }))
481 .unwrap();
482 assert_eq!(key, key_expected);
483
484 let did1 = DIDKey::generate(&key).unwrap();
485 assert_eq!(did1, did);
486 }
487
488 #[cfg(feature = "bbs")]
489 #[async_std::test]
490 async fn from_did_key_bls() {
491 let did = did!("did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY");
493 DIDKey.resolve(did).await.unwrap();
494
495 let did_url = DIDURL::new(b"did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY").unwrap();
496 let output = DIDKey
497 .dereference_with(
498 did_url,
499 Options {
500 accept: None,
501 parameters: Parameters {
502 public_key_format: Some("Bls12381G2Key2020".to_string()),
503 ..Default::default()
504 },
505 },
506 )
507 .await
508 .unwrap();
509 let mut vm = output.content.into_verification_method().unwrap();
510 let key: JWK =
511 serde_json::from_value(vm.properties.remove("publicKeyJwk").unwrap()).unwrap();
512 eprintln!("key {}", serde_json::to_string_pretty(&key).unwrap());
513
514 let key_expected: JWK = serde_json::from_value(serde_json::json!({
518 "kty": "EC",
519 "crv": "BLS12381G2",
520 "x": "FKWJu0SOY7onl4tEyOOH11XBriQN2JgzV-UmjgBMSsNkcAx3_l97SVYViSDBouTVBkBfrLh33C5icDD-4UEDxNO3Wn1ijMHvn2N63DU4pkezA3kGN81jGbwbrsMPpiOF",
521 "y": "DxwQn0pJ1DsBB8esxf3JvxFzS8BlyJVYvY_-HkYUxI-u6GdOHnMvNVSXKlEGjHw3DyTPeGOZ8KNbh62CaqWGE-4XAm23nzoD5dWg61Nvs5DGV4S4tLPmOXRYgHIPfRdq"
522 }))
523 .unwrap();
524 assert_eq!(key, key_expected);
525
526 let did1 = DIDKey::generate(&key).unwrap();
527 assert_eq!(did1, did);
528 }
529
530 #[async_std::test]
531 async fn from_did_key_rsa() {
532 let did = did!("did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i");
533 DIDKey.resolve(did).await.unwrap();
534
535 let vm = DIDURL::new(b"did:key:z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i#z4MXj1wBzi9jUstyPMS4jQqB6KdJaiatPkAtVtGc6bQEQEEsKTic4G7Rou3iBf9vPmT5dbkm9qsZsuVNjq8HCuW1w24nhBFGkRE4cd2Uf2tfrB3N7h4mnyPp1BF3ZttHTYv3DLUPi1zMdkULiow3M1GfXkoC6DoxDUm1jmN6GBj22SjVsr6dxezRVQc7aj9TxE7JLbMH1wh5X3kA58H3DFW8rnYMakFGbca5CB2Jf6CnGQZmL7o5uJAdTwXfy2iiiyPxXEGerMhHwhjTA1mKYobyk2CpeEcmvynADfNZ5MBvcCS7m3XkFCMNUYBS9NQ3fze6vMSUPsNa6GVYmKx2x6JrdEjCk3qRMMmyjnjCMfR4pXbRMZa3i").unwrap();
536 let output = DIDKey
537 .dereference_with(
538 vm,
539 Options {
540 accept: None,
541 parameters: Parameters {
542 public_key_format: Some("JsonWebKey2020".to_string()),
543 ..Default::default()
544 },
545 },
546 )
547 .await
548 .unwrap();
549 let mut vm = output.content.into_verification_method().unwrap();
550 let key: JWK =
551 serde_json::from_value(vm.properties.remove("publicKeyJwk").unwrap()).unwrap();
552 eprintln!("key {}", serde_json::to_string_pretty(&key).unwrap());
553
554 let key_expected: JWK = serde_json::from_value(serde_json::json!({
555 "kty": "RSA",
556 "e": "AQAB",
557 "n": "sbX82NTV6IylxCh7MfV4hlyvaniCajuP97GyOqSvTmoEdBOflFvZ06kR_9D6ctt45Fk6hskfnag2GG69NALVH2o4RCR6tQiLRpKcMRtDYE_thEmfBvDzm_VVkOIYfxu-Ipuo9J_S5XDNDjczx2v-3oDh5-CIHkU46hvFeCvpUS-L8TJSbgX0kjVk_m4eIb9wh63rtmD6Uz_KBtCo5mmR4TEtcLZKYdqMp3wCjN-TlgHiz_4oVXWbHUefCEe8rFnX1iQnpDHU49_SaXQoud1jCaexFn25n-Aa8f8bc5Vm-5SeRwidHa6ErvEhTvf1dz6GoNPp2iRvm-wJ1gxwWJEYPQ"
558 }))
559 .unwrap();
560 assert_eq!(key, key_expected);
561
562 let did1 = DIDKey::generate(&key).unwrap();
563 assert_eq!(did1, did);
564 }
565
566 #[async_std::test]
567 async fn credential_prove_verify_did_key_ed25519() {
568 let didkey = VerificationMethodDIDResolver::new(DIDKey);
569 let params = VerificationParameters::from_resolver(&didkey);
570
571 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(2);
572 let key = JWK::generate_ed25519_from(&mut rng).unwrap();
573 let did = DIDKey::generate(&key).unwrap();
574
575 let cred = JsonCredential::new(
576 Some(uri!("http://example.org/credentials/3731").to_owned()),
577 did.clone().into_uri().into(),
578 "2020-08-19T21:41:50Z".parse().unwrap(),
579 vec![json_syntax::json!({
580 "id": "did:example:d23dd687a7dc6787646f2eb98d0"
581 })],
582 );
583
584 let verification_method = DIDKey
585 .resolve_into_any_verification_method(&did)
586 .await
587 .unwrap()
588 .unwrap();
589 let verification_method_ref = ReferenceOrOwned::Reference(verification_method.id.into());
590 let suite = AnySuite::pick(&key, Some(&verification_method_ref)).unwrap();
592
593 let issue_options = SuiteOptions::new(
594 "2020-08-19T21:41:50Z".parse().unwrap(),
595 verification_method_ref,
596 ProofPurpose::Assertion,
597 AnyInputSuiteOptions::default(),
598 );
599 let signer = SingleSecretSigner::new(key).into_local();
600 let vc = suite
601 .sign(cred, &didkey, &signer, issue_options)
602 .await
603 .unwrap();
604 println!(
605 "proof: {}",
606 serde_json::to_string_pretty(&vc.proofs).unwrap()
607 );
608 assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..o4SzDo1RBQqdK49OPdmfVRVh68xCTNEmb7hq39IVqISkelld6t6Aatg4PCXKpopIXmX8RCCF4BwrO8ERg1YFBg");
609 assert!(vc.verify(¶ms).await.unwrap().is_ok());
610
611 let mut vc_bad_issuer = vc.clone();
613 vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into();
614
615 assert!(vc_bad_issuer.verify(¶ms).await.unwrap().is_err());
617 }
618
619 #[async_std::test]
620 #[cfg(feature = "secp256k1")]
621 async fn credential_prove_verify_did_key_secp256k1() {
622 let didkey = VerificationMethodDIDResolver::new(DIDKey);
623 let params = VerificationParameters::from_resolver(&didkey);
624
625 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(2);
626 let key = JWK::generate_secp256k1_from(&mut rng);
627 let did = DIDKey::generate(&key).unwrap();
628
629 let cred = JsonCredential::new(
630 None,
631 did.clone().into_uri().into(),
632 "2021-02-18T20:17:46Z".parse().unwrap(),
633 vec![json_syntax::json!({
634 "id": "did:example:d23dd687a7dc6787646f2eb98d0"
635 })],
636 );
637
638 let verification_method = DIDKey
639 .resolve_into_any_verification_method(&did)
640 .await
641 .unwrap()
642 .unwrap();
643 let verification_method_ref = ReferenceOrOwned::Reference(verification_method.id.into());
644 let suite = AnySuite::pick(&key, Some(&verification_method_ref)).unwrap();
646 eprintln!("suite: {suite:?}");
647 let issue_options = SuiteOptions::new(
648 "2021-02-18T20:17:46Z".parse().unwrap(),
649 verification_method_ref,
650 ProofPurpose::Assertion,
651 AnyInputSuiteOptions::default(),
652 );
653 let signer = SingleSecretSigner::new(key).into_local();
654 let vc = suite
655 .sign(cred, &didkey, &signer, issue_options)
656 .await
657 .unwrap();
658 println!(
659 "proof: {}",
660 serde_json::to_string_pretty(&vc.proofs).unwrap()
661 );
662 assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "eyJhbGciOiJFUzI1NksiLCJjcml0IjpbImI2NCJdLCJiNjQiOmZhbHNlfQ..jTUkFd_eYI72Y8j2OS5LRLhlc3gZn-gVsb76soi3FuJ5gWrbOb0W2CW6D-sjEsCuLkvSOfYd8Y8hB9pyeeZ2TQ");
663 assert!(vc.verify(¶ms).await.unwrap().is_ok());
664
665 let mut vc_bad_issuer = vc.clone();
667 vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into();
668
669 assert!(vc_bad_issuer.verify(params).await.unwrap().is_err());
671 }
672
673 #[async_std::test]
674 #[cfg(feature = "secp256r1")]
675 async fn credential_prove_verify_did_key_p256() {
676 let didkey = VerificationMethodDIDResolver::new(DIDKey);
677 let params = VerificationParameters::from_resolver(&didkey);
678
679 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(2);
680 let key = JWK::generate_p256_from(&mut rng);
681 let did = DIDKey::generate(&key).unwrap();
682
683 let cred = JsonCredential::new(
684 None,
685 did.clone().into_uri().into(),
686 "2021-02-18T20:17:46Z".parse().unwrap(),
687 vec![json_syntax::json!({
688 "id": "did:example:d23dd687a7dc6787646f2eb98d0"
689 })],
690 );
691
692 let verification_method = DIDKey
693 .resolve_into_any_verification_method(&did)
694 .await
695 .unwrap()
696 .unwrap();
697 let verification_method_ref = ReferenceOrOwned::Reference(verification_method.id.into());
698 let suite = AnySuite::pick(&key, Some(&verification_method_ref)).unwrap();
700 eprintln!("suite: {suite:?}");
701 let issue_options = SuiteOptions::new(
702 "2021-02-18T20:17:46Z".parse().unwrap(),
703 verification_method_ref,
704 ProofPurpose::Assertion,
705 AnyInputSuiteOptions::default(),
706 );
707 let signer = SingleSecretSigner::new(key).into_local();
708 let vc = suite
709 .sign(cred, &didkey, &signer, issue_options)
710 .await
711 .unwrap();
712 println!(
713 "proof: {}",
714 serde_json::to_string_pretty(&vc.proofs).unwrap()
715 );
716 assert!(vc.verify(¶ms).await.unwrap().is_ok());
717
718 let mut vc_bad_issuer = vc.clone();
720 vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into();
721
722 assert!(vc_bad_issuer.verify(params).await.unwrap().is_err());
724 }
725
726 async fn fetch_jwk(jwk: JWK) {
727 let did = DIDKey::generate(&jwk).unwrap();
728 let resolver: VerificationMethodDIDResolver<_, AnyMethod> =
729 VerificationMethodDIDResolver::new(DIDKey);
730 let vm = DIDKey
731 .resolve_into_any_verification_method(&did)
732 .await
733 .unwrap()
734 .unwrap();
735 let public_jwk = resolver.fetch_public_jwk(Some(&vm.id)).await.unwrap();
736 assert_eq!(*public_jwk, jwk.to_public());
737 }
738
739 #[async_std::test]
740 async fn fetch_jwk_ed25519() {
741 let jwk = JWK::generate_ed25519().unwrap();
742 fetch_jwk(jwk).await;
743 }
744
745 #[async_std::test]
746 #[cfg(feature = "secp256k1")]
747 async fn fetch_jwk_secp256k1() {
748 let jwk = JWK::generate_secp256k1();
749 fetch_jwk(jwk).await;
750 }
751
752 #[async_std::test]
753 #[cfg(feature = "secp256r1")]
754 async fn fetch_jwk_secp256r1() {
755 let jwk = JWK::generate_p256();
756 fetch_jwk(jwk).await;
757 }
758
759 #[async_std::test]
760 #[cfg(feature = "secp384r1")]
761 async fn fetch_jwk_secp384r1() {
762 let jwk = JWK::generate_p384();
763 fetch_jwk(jwk).await;
764 }
765}