credibil_did/key/
operator.rs1use anyhow::anyhow;
8use base64ct::{Base64UrlUnpadded, Encoding};
9use ed25519_dalek::{PUBLIC_KEY_LENGTH, VerifyingKey};
10use multibase::Base;
11use serde_json::json;
12
13use super::DidKey;
14use crate::core::Kind;
15use crate::document::{CreateOptions, Document, MethodType, PublicKeyFormat, VerificationMethod};
16use crate::error::Error;
17use crate::{DidOperator, ED25519_CODEC, KeyPurpose, X25519_CODEC};
18
19impl DidKey {
20 pub fn create(op: &impl DidOperator, options: CreateOptions) -> crate::Result<Document> {
27 let Some(verifying_key) = op.verification(KeyPurpose::VerificationMethod) else {
28 return Err(Error::Other(anyhow!("no verification key")));
29 };
30 let key_bytes = Base64UrlUnpadded::decode_vec(&verifying_key.x)
31 .map_err(|e| Error::InvalidPublicKey(format!("issue decoding key: {e}")))?;
32
33 let mut multi_bytes = ED25519_CODEC.to_vec();
34 multi_bytes.extend_from_slice(&key_bytes);
35 let multikey = multibase::encode(Base::Base58Btc, &multi_bytes);
36
37 let did = format!("did:key:{multikey}");
38
39 let context = if options.public_key_format == PublicKeyFormat::Multikey
40 || options.public_key_format == PublicKeyFormat::Ed25519VerificationKey2020
41 {
42 Kind::String("https://w3id.org/security/data-integrity/v1".into())
43 } else {
44 let verif_type = &options.public_key_format;
45 Kind::Object(json!({
46 "publicKeyJwk": {
47 "@id": "https://w3id.org/security#publicKeyJwk",
48 "@type": "@json"
49 },
50 verif_type.to_string(): format!("https://w3id.org/security#{verif_type}"),
51 }))
52 };
53
54 let key_agreement = if options.enable_encryption_key_derivation {
57 let verifier_bytes: [u8; PUBLIC_KEY_LENGTH] = key_bytes.try_into().map_err(|_| {
58 Error::InvalidPublicKey(format!("public key is not {PUBLIC_KEY_LENGTH} bytes"))
59 })?;
60 let verifier = VerifyingKey::from_bytes(&verifier_bytes).map_err(|e| {
61 Error::InvalidPublicKey(format!("public key is not correct size: {e}"))
62 })?;
63 let x25519_bytes = verifier.to_montgomery().to_bytes();
64
65 let mut multi_bytes = vec![];
67 multi_bytes.extend_from_slice(&X25519_CODEC);
68 multi_bytes.extend_from_slice(&x25519_bytes);
69 let multikey = multibase::encode(Base::Base58Btc, &multi_bytes);
70
71 let method_type = match options.public_key_format {
72 PublicKeyFormat::Multikey => MethodType::Multikey {
73 public_key_multibase: multikey.clone(),
74 },
75 _ => return Err(Error::InvalidPublicKey("Unsupported public key format".into())),
76 };
77
78 Some(vec![Kind::Object(VerificationMethod {
79 id: format!("{did}#{multikey}"),
80 controller: did.clone(),
81 method_type,
82 ..VerificationMethod::default()
83 })])
84 } else {
85 None
86 };
87
88 let kid = format!("{did}#{multikey}");
89
90 let method_type = match options.public_key_format {
91 PublicKeyFormat::Multikey => MethodType::Multikey {
92 public_key_multibase: multikey,
93 },
94 _ => MethodType::JsonWebKey {
95 public_key_jwk: verifying_key,
96 },
97 };
98
99 Ok(Document {
100 context: vec![Kind::String(options.default_context), context],
101 id: did.clone(),
102 verification_method: Some(vec![VerificationMethod {
103 id: kid.clone(),
104 controller: did,
105 method_type,
106 ..VerificationMethod::default()
107 }]),
108 authentication: Some(vec![Kind::String(kid.clone())]),
109 assertion_method: Some(vec![Kind::String(kid.clone())]),
110 capability_invocation: Some(vec![Kind::String(kid.clone())]),
111 capability_delegation: Some(vec![Kind::String(kid)]),
112 key_agreement,
113 ..Document::default()
114 })
115 }
116}
117
118#[cfg(test)]
119mod test {
120 use credibil_infosec::{Curve, KeyType, PublicKeyJwk};
121 use ed25519_dalek::SigningKey;
122 use rand::rngs::OsRng;
123
124 use super::*;
125
126 #[test]
127 fn create() {
128 let mut options = CreateOptions::default();
129 options.enable_encryption_key_derivation = true;
130
131 let op = Operator;
132 let res = DidKey::create(&op, options).expect("should create");
133
134 let json = serde_json::to_string_pretty(&res).expect("should serialize");
135 println!("{json}");
136 }
137
138 struct Operator;
139 impl DidOperator for Operator {
140 fn verification(&self, purpose: KeyPurpose) -> Option<PublicKeyJwk> {
141 match purpose {
142 KeyPurpose::VerificationMethod => {
143 let key = generate();
144
145 Some(PublicKeyJwk {
146 kty: KeyType::Okp,
147 crv: Curve::Ed25519,
148 x: Base64UrlUnpadded::encode_string(&key),
149 ..PublicKeyJwk::default()
150 })
151 }
152 _ => panic!("unsupported purpose"),
153 }
154 }
155 }
156
157 #[allow(dead_code)]
159 pub fn generate() -> Vec<u8> {
160 let signing_key = SigningKey::generate(&mut OsRng);
162 let secret = Base64UrlUnpadded::encode_string(signing_key.as_bytes());
163 println!("secret: {secret}");
164
165 signing_key.verifying_key().to_bytes().to_vec()
166 }
167}