ssi_verification_methods/methods/w3c/
ed25519_verification_key_2020.rs

1use std::{borrow::Cow, hash::Hash, str::FromStr};
2
3use ed25519_dalek::{Signer, Verifier};
4use iref::{Iri, IriBuf, UriBuf};
5use rand_core::{CryptoRng, RngCore};
6use rdf_types::{Interpretation, Vocabulary};
7use serde::{Deserialize, Serialize};
8use ssi_claims_core::{InvalidProof, MessageSignatureError, ProofValidationError, ProofValidity};
9use ssi_jwk::JWK;
10use ssi_multicodec::MultiEncodedBuf;
11use ssi_security::{Multibase, MultibaseBuf};
12use ssi_verification_methods_core::{JwkVerificationMethod, VerificationMethodSet, VerifyBytes};
13use static_iref::iri;
14
15use crate::{
16    ExpectedType, GenericVerificationMethod, InvalidVerificationMethod, SigningMethod,
17    TypedVerificationMethod, VerificationMethod,
18};
19
20/// Ed25519 Verification Key 2020 type name.
21pub const ED25519_VERIFICATION_KEY_2020_TYPE: &str = "Ed25519VerificationKey2020";
22
23/// Deprecated verification method for the `Ed25519Signature2020` suite.
24///
25/// See: <https://w3c.github.io/vc-di-eddsa/#ed25519verificationkey2020>
26#[derive(
27    Debug,
28    Clone,
29    PartialEq,
30    Eq,
31    Hash,
32    Serialize,
33    Deserialize,
34    linked_data::Serialize,
35    linked_data::Deserialize,
36)]
37#[serde(tag = "type", rename = "Ed25519VerificationKey2020")]
38#[ld(prefix("sec" = "https://w3id.org/security#"))]
39#[ld(type = "sec:Ed25519VerificationKey2020")]
40pub struct Ed25519VerificationKey2020 {
41    /// Key identifier.
42    #[ld(id)]
43    pub id: IriBuf,
44
45    /// Controller of the verification method.
46    #[ld("sec:controller")]
47    pub controller: UriBuf,
48
49    /// Public key encoded according to [MULTICODEC] and formatted according to
50    /// [MULTIBASE].
51    ///
52    /// The multicodec encoding of an Ed25519 public key is the
53    /// two-byte prefix 0xed01 followed by the 32-byte public key data. The 34
54    /// byte value is then encoded using base58-btc (z) as the prefix. Any other
55    /// encoding MUST NOT be allowed.
56    ///
57    /// [MULTICODEC]: <https://github.com/multiformats/multicodec>
58    /// [MULTIBASE]: <https://github.com/multiformats/multibase>
59    #[serde(rename = "publicKeyMultibase")]
60    #[ld("sec:publicKeyMultibase")]
61    pub public_key: PublicKey,
62}
63
64impl Ed25519VerificationKey2020 {
65    pub const NAME: &'static str = ED25519_VERIFICATION_KEY_2020_TYPE;
66    pub const IRI: &'static Iri = iri!("https://w3id.org/security#Ed25519VerificationKey2020");
67
68    pub fn public_key_jwk(&self) -> JWK {
69        self.public_key.to_jwk()
70    }
71
72    pub fn generate_key_pair(
73        id: IriBuf,
74        controller: UriBuf,
75        csprng: &mut (impl RngCore + CryptoRng),
76    ) -> (Self, ed25519_dalek::SigningKey) {
77        let key = ed25519_dalek::SigningKey::generate(csprng);
78        (
79            Self::from_public_key(id, controller, key.verifying_key()),
80            key,
81        )
82    }
83
84    pub fn from_public_key(
85        id: IriBuf,
86        controller: UriBuf,
87        public_key: ed25519_dalek::VerifyingKey,
88    ) -> Self {
89        Self {
90            id,
91            controller,
92            public_key: PublicKey::encode(public_key),
93        }
94    }
95
96    // pub fn sign_bytes(&self, data: &[u8], key_pair: &ed25519_dalek::Keypair) -> Vec<u8> {
97    //     let signature = key_pair.sign(data);
98    //     signature.to_bytes().to_vec()
99    // }
100
101    pub fn sign_bytes<'a>(
102        &self,
103        secret_key: impl Into<SecretKeyRef<'a>>,
104        signing_bytes: &[u8],
105    ) -> Result<Vec<u8>, MessageSignatureError> {
106        match secret_key.into() {
107            SecretKeyRef::Ed25519(key_pair) => {
108                let signature = key_pair.sign(signing_bytes);
109                Ok(signature.to_bytes().to_vec())
110            }
111            SecretKeyRef::Jwk(secret_key) => {
112                let algorithm = ssi_jwk::Algorithm::EdDSA;
113                let key_algorithm = secret_key.algorithm.unwrap_or(algorithm);
114                if !algorithm.is_compatible_with(key_algorithm) {
115                    return Err(MessageSignatureError::InvalidSecretKey);
116                }
117
118                ssi_jws::sign_bytes(algorithm, signing_bytes, secret_key)
119                    .map_err(|_| MessageSignatureError::InvalidSecretKey)
120            }
121        }
122    }
123
124    pub fn verify_bytes(
125        &self,
126        data: &[u8],
127        signature_bytes: &[u8],
128    ) -> Result<ProofValidity, ProofValidationError> {
129        let signature = ed25519_dalek::Signature::try_from(signature_bytes)
130            .map_err(|_| ProofValidationError::InvalidSignature)?;
131        Ok(self.public_key.verify(data, &signature))
132    }
133}
134
135pub enum SecretKeyRef<'a> {
136    Ed25519(&'a ed25519_dalek::SigningKey),
137    Jwk(&'a JWK),
138}
139
140impl<'a> From<&'a ed25519_dalek::SigningKey> for SecretKeyRef<'a> {
141    fn from(value: &'a ed25519_dalek::SigningKey) -> Self {
142        Self::Ed25519(value)
143    }
144}
145
146impl<'a> From<&'a JWK> for SecretKeyRef<'a> {
147    fn from(value: &'a JWK) -> Self {
148        Self::Jwk(value)
149    }
150}
151
152impl VerificationMethod for Ed25519VerificationKey2020 {
153    fn id(&self) -> &Iri {
154        self.id.as_iri()
155    }
156
157    fn controller(&self) -> Option<&Iri> {
158        Some(self.controller.as_iri())
159    }
160}
161
162impl VerificationMethodSet for Ed25519VerificationKey2020 {
163    type TypeSet = &'static str;
164
165    fn type_set() -> Self::TypeSet {
166        Self::NAME
167    }
168}
169
170impl TypedVerificationMethod for Ed25519VerificationKey2020 {
171    fn expected_type() -> Option<ExpectedType> {
172        Some(ED25519_VERIFICATION_KEY_2020_TYPE.to_string().into())
173    }
174
175    fn type_match(ty: &str) -> bool {
176        ty == ED25519_VERIFICATION_KEY_2020_TYPE
177    }
178
179    fn type_(&self) -> &str {
180        ED25519_VERIFICATION_KEY_2020_TYPE
181    }
182}
183
184impl JwkVerificationMethod for Ed25519VerificationKey2020 {
185    fn to_jwk(&self) -> Cow<JWK> {
186        Cow::Owned(self.public_key_jwk())
187    }
188}
189
190impl SigningMethod<ed25519_dalek::SigningKey, ssi_crypto::algorithm::EdDSA>
191    for Ed25519VerificationKey2020
192{
193    fn sign_bytes(
194        &self,
195        secret: &ed25519_dalek::SigningKey,
196        _algorithm: ssi_crypto::algorithm::EdDSA,
197        message: &[u8],
198    ) -> Result<Vec<u8>, MessageSignatureError> {
199        self.sign_bytes(secret, message)
200    }
201}
202
203impl SigningMethod<JWK, ssi_crypto::algorithm::EdDSA> for Ed25519VerificationKey2020 {
204    fn sign_bytes(
205        &self,
206        secret_key: &JWK,
207        _algorithm: ssi_crypto::algorithm::EdDSA,
208        message: &[u8],
209    ) -> Result<Vec<u8>, MessageSignatureError> {
210        self.sign_bytes(secret_key, message)
211    }
212}
213
214impl VerifyBytes<ssi_crypto::algorithm::EdDSA> for Ed25519VerificationKey2020 {
215    fn verify_bytes(
216        &self,
217        _: ssi_crypto::algorithm::EdDSA,
218        signing_bytes: &[u8],
219        signature: &[u8],
220    ) -> Result<ProofValidity, ProofValidationError> {
221        self.verify_bytes(signing_bytes, signature)
222    }
223}
224
225impl TryFrom<GenericVerificationMethod> for Ed25519VerificationKey2020 {
226    type Error = InvalidVerificationMethod;
227
228    fn try_from(m: GenericVerificationMethod) -> Result<Self, Self::Error> {
229        Ok(Self {
230            id: m.id,
231            controller: m.controller,
232            public_key: m
233                .properties
234                .get("publicKeyMultibase")
235                .ok_or_else(|| InvalidVerificationMethod::missing_property("publicKeyMultibase"))?
236                .as_str()
237                .ok_or_else(|| {
238                    InvalidVerificationMethod::invalid_property(
239                        "publicKeyMultibase is not a string",
240                    )
241                })?
242                .parse()
243                .map_err(|e| {
244                    InvalidVerificationMethod::invalid_property(&format!(
245                        "publicKeyMultibase parsing failed because: {e}"
246                    ))
247                })?,
248        })
249    }
250}
251
252/// Public key of an Ed25519 Verification Key 2020 verification method.
253#[derive(Debug, Clone)]
254pub struct PublicKey {
255    /// Multibase-encoded public key.
256    ///
257    /// The multicodec encoding of an Ed25519 public key is the
258    /// two-byte prefix 0xed01 followed by the 32-byte public key data. The 34
259    /// byte value is then encoded using base58-btc (z) as the prefix. Any other
260    /// encoding MUST NOT be allowed.
261    encoded: MultibaseBuf,
262
263    /// Decoded public key.
264    decoded: ed25519_dalek::VerifyingKey,
265}
266
267impl PublicKey {
268    pub fn encode(decoded: ed25519_dalek::VerifyingKey) -> Self {
269        let multi_encoded =
270            MultiEncodedBuf::encode_bytes(ssi_multicodec::ED25519_PUB, decoded.as_bytes());
271
272        Self {
273            encoded: MultibaseBuf::encode(multibase::Base::Base58Btc, multi_encoded.as_bytes()),
274            decoded,
275        }
276    }
277
278    pub fn decode(encoded: MultibaseBuf) -> Result<Self, InvalidPublicKey> {
279        let pk_multi_encoded = MultiEncodedBuf::new(encoded.decode()?.1)?;
280
281        let (pk_codec, pk_data) = pk_multi_encoded.parts();
282        if pk_codec == ssi_multicodec::ED25519_PUB {
283            let decoded = ed25519_dalek::VerifyingKey::try_from(pk_data)?;
284            Ok(Self { encoded, decoded })
285        } else {
286            Err(InvalidPublicKey::InvalidKeyType)
287        }
288    }
289
290    pub fn encoded(&self) -> &Multibase {
291        &self.encoded
292    }
293
294    pub fn decoded(&self) -> &ed25519_dalek::VerifyingKey {
295        &self.decoded
296    }
297
298    pub fn to_jwk(&self) -> JWK {
299        self.decoded.into()
300    }
301
302    pub fn verify(&self, data: &[u8], signature: &ed25519_dalek::Signature) -> ProofValidity {
303        self.decoded
304            .verify(data, signature)
305            .map_err(|_| InvalidProof::Signature)
306    }
307}
308
309impl Serialize for PublicKey {
310    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
311    where
312        S: serde::Serializer,
313    {
314        self.encoded.serialize(serializer)
315    }
316}
317
318impl<'a> Deserialize<'a> for PublicKey {
319    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
320    where
321        D: serde::Deserializer<'a>,
322    {
323        use serde::de::Error;
324        let encoded = MultibaseBuf::deserialize(deserializer)?;
325        Self::decode(encoded).map_err(D::Error::custom)
326    }
327}
328
329impl FromStr for PublicKey {
330    type Err = InvalidPublicKey;
331
332    fn from_str(s: &str) -> Result<Self, Self::Err> {
333        Self::decode(MultibaseBuf::new(s.to_owned()))
334    }
335}
336
337impl PartialEq for PublicKey {
338    fn eq(&self, other: &Self) -> bool {
339        self.decoded.eq(&other.decoded)
340    }
341}
342
343impl Eq for PublicKey {}
344
345impl Hash for PublicKey {
346    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
347        self.encoded.hash(state)
348    }
349}
350
351impl<I: Interpretation, V: Vocabulary> linked_data::LinkedDataResource<I, V> for PublicKey
352where
353    MultibaseBuf: linked_data::LinkedDataResource<I, V>,
354{
355    fn interpretation(
356        &self,
357        vocabulary: &mut V,
358        interpretation: &mut I,
359    ) -> linked_data::ResourceInterpretation<I, V> {
360        self.encoded.interpretation(vocabulary, interpretation)
361    }
362}
363
364impl<I: Interpretation, V: Vocabulary> linked_data::LinkedDataSubject<I, V> for PublicKey
365where
366    MultibaseBuf: linked_data::LinkedDataSubject<I, V>,
367{
368    fn visit_subject<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
369    where
370        S: linked_data::SubjectVisitor<I, V>,
371    {
372        self.encoded.visit_subject(serializer)
373    }
374}
375
376impl<I: Interpretation, V: Vocabulary> linked_data::LinkedDataPredicateObjects<I, V> for PublicKey
377where
378    MultibaseBuf: linked_data::LinkedDataPredicateObjects<I, V>,
379{
380    fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
381    where
382        S: linked_data::PredicateObjectsVisitor<I, V>,
383    {
384        self.encoded.visit_objects(visitor)
385    }
386}
387
388#[derive(Debug, thiserror::Error)]
389pub enum InvalidPublicKey {
390    #[error(transparent)]
391    Multibase(#[from] multibase::Error),
392
393    #[error(transparent)]
394    Multicodec(#[from] ssi_multicodec::Error),
395
396    #[error("invalid key type")]
397    InvalidKeyType,
398
399    #[error(transparent)]
400    Ed25519(#[from] ed25519_dalek::SignatureError),
401}