did_method_key/
lib.rs

1//! The did:key Method v0.7.
2//!
3//! See: <https://w3c-ccg.github.io/did-method-key>
4use 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
20/// The did:key Method v0.7.
21///
22/// See: <https://w3c-ccg.github.io/did-method-key>
23pub 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                    // https://datatracker.ietf.org/doc/html/draft-denhartog-pairing-curves-jose-cose-00#section-3.1.3
207                    // FIXME: This should be a base 58 key according to the spec.
208                    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        // convert back to DID from JWK
435        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        // https://w3c-ccg.github.io/did-method-key/#p-256
443        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        // https://github.com/w3c-ccg/did-method-key/blob/master/test-vectors/nist-curves.json#L64-L69
475        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        // https://w3c-ccg.github.io/did-method-key/#bls-12381
492        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        // Note: this "x" value is generated by this implementation - not yet confirmed with other
515        // implementations.
516        // Related issue: https://github.com/mattrglobal/bls12381-jwk-draft/issues/5
517        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        // issue_options.verification_method = Some(URI::String(verification_method));
591        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(&params).await.unwrap().is_ok());
610
611        // test that issuer is verified
612        let mut vc_bad_issuer = vc.clone();
613        vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into();
614
615        // It should fail.
616        assert!(vc_bad_issuer.verify(&params).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        // issue_options.verification_method = Some(URI::String(verification_method));
645        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(&params).await.unwrap().is_ok());
664
665        // test that issuer is verified
666        let mut vc_bad_issuer = vc.clone();
667        vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into();
668
669        // It should fail.
670        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        // issue_options.verification_method = Some(URI::String(verification_method));
699        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(&params).await.unwrap().is_ok());
717
718        // test that issuer is verified
719        let mut vc_bad_issuer = vc.clone();
720        vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into();
721
722        // It should fail.
723        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}