ssi_verification_methods/methods/w3c/
multikey.rs

1use iref::{Iri, IriBuf, UriBuf};
2use multibase::Base;
3use rdf_types::{
4    dataset::PatternMatchingDataset,
5    interpretation::{ReverseIriInterpretation, ReverseLiteralInterpretation},
6    vocabulary::{IriVocabularyMut, LiteralVocabulary},
7    Interpretation, Vocabulary,
8};
9use serde::{Deserialize, Serialize};
10use ssi_claims_core::{
11    InvalidProof, MessageSignatureError, ProofValidationError, ProofValidity, SignatureError,
12};
13use ssi_crypto::algorithm::SignatureAlgorithmType;
14use ssi_jwk::JWK;
15use ssi_multicodec::{MultiCodec, MultiEncodedBuf};
16use ssi_security::MultibaseBuf;
17use ssi_verification_methods_core::{
18    MaybeJwkVerificationMethod, SigningMethod, VerificationMethodSet, VerifyBytes,
19};
20use static_iref::iri;
21use std::{borrow::Cow, hash::Hash, str::FromStr, sync::OnceLock};
22
23use crate::{
24    ExpectedType, GenericVerificationMethod, InvalidVerificationMethod, TypedVerificationMethod,
25    VerificationMethod,
26};
27
28/// Multikey type name.
29pub const MULTIKEY_TYPE: &str = "Multikey";
30
31/// Multikey verification method.
32///
33/// See: <https://www.w3.org/TR/vc-data-integrity/#multikey>
34#[derive(
35    Debug,
36    Clone,
37    PartialEq,
38    Eq,
39    Hash,
40    Serialize,
41    Deserialize,
42    linked_data::Serialize,
43    linked_data::Deserialize,
44)]
45#[serde(tag = "type", rename = "Multikey")]
46#[ld(prefix("sec" = "https://w3id.org/security#"))]
47#[ld(type = "sec:Multikey")]
48pub struct Multikey {
49    /// Key identifier.
50    #[ld(id)]
51    pub id: IriBuf,
52
53    /// Controller of the verification method.
54    #[ld("sec:controller")]
55    pub controller: UriBuf,
56
57    /// Public key encoded according to [MULTICODEC] and formatted according to
58    /// [MULTIBASE].
59    ///
60    /// [MULTICODEC]: <https://github.com/multiformats/multicodec>
61    /// [MULTIBASE]: <https://github.com/multiformats/multibase>
62    #[serde(rename = "publicKeyMultibase")]
63    #[ld("sec:publicKeyMultibase")]
64    pub public_key: PublicKey,
65}
66
67#[derive(Debug, Clone, thiserror::Error)]
68pub enum InvalidPublicKey {
69    #[error(transparent)]
70    Multibase(#[from] multibase::Error),
71
72    #[error(transparent)]
73    Multicodec(#[from] ssi_multicodec::Error),
74}
75
76impl From<InvalidPublicKey> for ProofValidationError {
77    fn from(_value: InvalidPublicKey) -> Self {
78        ProofValidationError::InvalidKey
79    }
80}
81
82impl From<InvalidPublicKey> for MessageSignatureError {
83    fn from(_value: InvalidPublicKey) -> Self {
84        MessageSignatureError::InvalidPublicKey
85    }
86}
87
88impl From<InvalidPublicKey> for SignatureError {
89    fn from(_value: InvalidPublicKey) -> Self {
90        SignatureError::InvalidPublicKey
91    }
92}
93
94impl Multikey {
95    pub const NAME: &'static str = MULTIKEY_TYPE;
96    pub const IRI: &'static Iri = iri!("https://w3id.org/security#Multikey");
97
98    pub fn public_key_jwk(&self) -> Option<JWK> {
99        self.public_key.decode().ok()?.to_jwk()
100    }
101
102    #[cfg(feature = "ed25519")]
103    pub fn generate_ed25519_key_pair(
104        id: IriBuf,
105        controller: UriBuf,
106        csprng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
107    ) -> (Self, ed25519_dalek::SigningKey) {
108        let key = ed25519_dalek::SigningKey::generate(csprng);
109        (
110            Self::from_public_key(id, controller, &key.verifying_key()),
111            key,
112        )
113    }
114
115    pub fn from_public_key<K: MultiCodec>(id: IriBuf, controller: UriBuf, public_key: &K) -> Self {
116        Self {
117            id,
118            controller,
119            public_key: PublicKey::new(public_key),
120        }
121    }
122}
123
124pub enum SecretKeyRef<'a> {
125    #[cfg(feature = "ed25519")]
126    Ed25519(&'a ed25519_dalek::SigningKey),
127    Jwk(&'a JWK),
128}
129
130#[cfg(feature = "ed25519")]
131impl<'a> From<&'a ed25519_dalek::SigningKey> for SecretKeyRef<'a> {
132    fn from(value: &'a ed25519_dalek::SigningKey) -> Self {
133        Self::Ed25519(value)
134    }
135}
136
137impl<'a> From<&'a JWK> for SecretKeyRef<'a> {
138    fn from(value: &'a JWK) -> Self {
139        Self::Jwk(value)
140    }
141}
142
143impl VerificationMethod for Multikey {
144    fn id(&self) -> &Iri {
145        self.id.as_iri()
146    }
147
148    fn controller(&self) -> Option<&Iri> {
149        Some(self.controller.as_iri())
150    }
151}
152
153impl VerificationMethodSet for Multikey {
154    type TypeSet = &'static str;
155
156    fn type_set() -> Self::TypeSet {
157        Self::NAME
158    }
159}
160
161impl<A: Into<ssi_jwk::Algorithm>> VerifyBytes<A> for Multikey {
162    fn verify_bytes(
163        &self,
164        algorithm: A,
165        signing_bytes: &[u8],
166        signature: &[u8],
167    ) -> Result<ProofValidity, ProofValidationError> {
168        let key = self
169            .public_key_jwk()
170            .ok_or(ProofValidationError::UnknownKey)?;
171        Ok(
172            ssi_jws::verify_bytes(algorithm.into(), signing_bytes, &key, signature)
173                .map_err(|_| InvalidProof::Signature),
174        )
175    }
176}
177
178impl<A: SignatureAlgorithmType> SigningMethod<JWK, A> for Multikey
179where
180    A::Instance: Into<ssi_crypto::AlgorithmInstance>,
181{
182    fn sign_bytes(
183        &self,
184        secret: &JWK,
185        algorithm: A::Instance,
186        bytes: &[u8],
187    ) -> Result<Vec<u8>, MessageSignatureError> {
188        ssi_jws::sign_bytes(algorithm.into().try_into()?, bytes, secret)
189            .map_err(MessageSignatureError::signature_failed)
190    }
191
192    #[allow(unused_variables)]
193    fn sign_bytes_multi(
194        &self,
195        secret: &JWK,
196        algorithm: A::Instance,
197        messages: &[Vec<u8>],
198    ) -> Result<Vec<u8>, MessageSignatureError> {
199        match algorithm.into() {
200            #[cfg(feature = "bbs")]
201            ssi_crypto::AlgorithmInstance::Bbs(bbs_algorithm) => {
202                let secret: ssi_bbs::BBSplusSecretKey = secret
203                    .try_into()
204                    .map_err(|_| MessageSignatureError::InvalidSecretKey)?;
205                self.sign_bytes_multi(&secret, bbs_algorithm, messages)
206            }
207            other => Err(MessageSignatureError::UnsupportedAlgorithm(
208                other.algorithm().to_string(),
209            )),
210        }
211    }
212}
213
214#[cfg(feature = "ed25519")]
215impl SigningMethod<ed25519_dalek::SigningKey, ssi_crypto::algorithm::EdDSA> for Multikey {
216    fn sign_bytes(
217        &self,
218        secret: &ed25519_dalek::SigningKey,
219        _algorithm: ssi_crypto::algorithm::EdDSA,
220        bytes: &[u8],
221    ) -> Result<Vec<u8>, MessageSignatureError> {
222        use ed25519_dalek::Signer;
223        let signature = secret.sign(bytes);
224        Ok(signature.to_bytes().to_vec())
225    }
226}
227
228#[cfg(feature = "bbs")]
229impl SigningMethod<ssi_bbs::BBSplusSecretKey, ssi_crypto::algorithm::Bbs> for Multikey {
230    fn sign_bytes(
231        &self,
232        secret: &ssi_bbs::BBSplusSecretKey,
233        algorithm: ssi_crypto::algorithm::BbsInstance,
234        bytes: &[u8],
235    ) -> Result<Vec<u8>, MessageSignatureError> {
236        self.sign_bytes_multi(secret, algorithm, &[bytes.to_vec()])
237    }
238
239    fn sign_bytes_multi(
240        &self,
241        secret: &ssi_bbs::BBSplusSecretKey,
242        algorithm: ssi_crypto::algorithm::BbsInstance,
243        messages: &[Vec<u8>],
244    ) -> Result<Vec<u8>, MessageSignatureError> {
245        #[allow(irrefutable_let_patterns)]
246        let DecodedMultikey::Bls12_381(pk) = self.public_key.decode()?
247        else {
248            return Err(MessageSignatureError::InvalidPublicKey);
249        };
250
251        ssi_bbs::sign(*algorithm.0, secret, pk, messages)
252    }
253}
254
255impl TypedVerificationMethod for Multikey {
256    fn expected_type() -> Option<ExpectedType> {
257        Some(MULTIKEY_TYPE.to_string().into())
258    }
259
260    fn type_match(ty: &str) -> bool {
261        ty == MULTIKEY_TYPE
262    }
263
264    fn type_(&self) -> &str {
265        MULTIKEY_TYPE
266    }
267}
268
269impl MaybeJwkVerificationMethod for Multikey {
270    fn try_to_jwk(&self) -> Option<Cow<JWK>> {
271        self.public_key_jwk().map(Cow::Owned)
272    }
273}
274
275impl TryFrom<GenericVerificationMethod> for Multikey {
276    type Error = InvalidVerificationMethod;
277
278    fn try_from(m: GenericVerificationMethod) -> Result<Self, Self::Error> {
279        Ok(Self {
280            id: m.id,
281            controller: m.controller,
282            public_key: m
283                .properties
284                .get("publicKeyMultibase")
285                .ok_or_else(|| InvalidVerificationMethod::missing_property("publicKeyMultibase"))?
286                .as_str()
287                .ok_or_else(|| {
288                    InvalidVerificationMethod::invalid_property(
289                        "publicKeyMultibase is not a string",
290                    )
291                })?
292                .parse()
293                .map_err(|e| {
294                    InvalidVerificationMethod::invalid_property(&format!(
295                        "publicKeyMultibase parsing failed because: {e}"
296                    ))
297                })?,
298        })
299    }
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
303#[serde(transparent)]
304pub struct PublicKey {
305    pub encoded: MultibaseBuf,
306
307    #[serde(skip)]
308    decoded: OnceLock<Result<DecodedMultikey, InvalidPublicKey>>,
309}
310
311impl PublicKey {
312    pub fn new(public_key: &impl MultiCodec) -> Self {
313        Self::from_multibase(MultibaseBuf::encode(
314            Base::Base58Btc,
315            MultiEncodedBuf::encode(public_key),
316        ))
317    }
318
319    pub fn from_multibase(encoded: MultibaseBuf) -> Self {
320        Self {
321            encoded,
322            decoded: OnceLock::new(),
323        }
324    }
325
326    pub fn decode(&self) -> Result<&DecodedMultikey, InvalidPublicKey> {
327        self.decoded
328            .get_or_init(|| {
329                let pk_multi_encoded = MultiEncodedBuf::new(self.encoded.decode()?.1)?;
330                pk_multi_encoded.decode().map_err(Into::into)
331            })
332            .as_ref()
333            .map_err(Clone::clone)
334    }
335}
336
337impl From<MultibaseBuf> for PublicKey {
338    fn from(value: MultibaseBuf) -> Self {
339        Self::from_multibase(value)
340    }
341}
342
343impl PartialEq for PublicKey {
344    fn eq(&self, other: &Self) -> bool {
345        self.encoded == other.encoded
346    }
347}
348
349impl Eq for PublicKey {}
350
351impl PartialOrd for PublicKey {
352    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
353        Some(self.cmp(other))
354    }
355}
356
357impl Ord for PublicKey {
358    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
359        self.encoded.cmp(&other.encoded)
360    }
361}
362
363impl Hash for PublicKey {
364    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
365        self.encoded.hash(state)
366    }
367}
368
369impl FromStr for PublicKey {
370    type Err = std::convert::Infallible;
371
372    fn from_str(s: &str) -> Result<Self, Self::Err> {
373        MultibaseBuf::from_str(s).map(Self::from_multibase)
374    }
375}
376
377impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataResource<I, V> for PublicKey
378where
379    V: IriVocabularyMut,
380{
381    fn interpretation(
382        &self,
383        vocabulary: &mut V,
384        interpretation: &mut I,
385    ) -> linked_data::ResourceInterpretation<I, V> {
386        self.encoded.interpretation(vocabulary, interpretation)
387    }
388}
389
390impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataPredicateObjects<I, V> for PublicKey
391where
392    V: IriVocabularyMut,
393{
394    fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
395    where
396        S: linked_data::PredicateObjectsVisitor<I, V>,
397    {
398        self.encoded.visit_objects(visitor)
399    }
400}
401
402impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataSubject<I, V> for PublicKey {
403    fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
404    where
405        S: linked_data::SubjectVisitor<I, V>,
406    {
407        self.encoded.visit_subject(visitor)
408    }
409}
410
411impl<V: Vocabulary, I> linked_data::LinkedDataDeserializeSubject<I, V> for PublicKey
412where
413    V: LiteralVocabulary,
414    I: ReverseIriInterpretation<Iri = V::Iri> + ReverseLiteralInterpretation<Literal = V::Literal>,
415{
416    fn deserialize_subject_in<D>(
417        vocabulary: &V,
418        interpretation: &I,
419        dataset: &D,
420        graph: Option<&I::Resource>,
421        resource: &<I as Interpretation>::Resource,
422        context: linked_data::Context<I>,
423    ) -> Result<Self, linked_data::FromLinkedDataError>
424    where
425        D: PatternMatchingDataset<Resource = I::Resource>,
426    {
427        Ok(Self::from_multibase(MultibaseBuf::deserialize_subject_in(
428            vocabulary,
429            interpretation,
430            dataset,
431            graph,
432            resource,
433            context,
434        )?))
435    }
436}
437
438#[derive(Debug, Clone)]
439#[non_exhaustive]
440pub enum DecodedMultikey {
441    #[cfg(feature = "ed25519")]
442    Ed25519(ed25519_dalek::VerifyingKey),
443
444    #[cfg(feature = "secp256k1")]
445    Secp256k1(k256::PublicKey),
446
447    #[cfg(feature = "secp256r1")]
448    P256(p256::PublicKey),
449
450    #[cfg(feature = "secp384r1")]
451    P384(p384::PublicKey),
452
453    #[cfg(feature = "bbs")]
454    Bls12_381(ssi_bbs::BBSplusPublicKey),
455}
456
457impl DecodedMultikey {
458    pub fn to_jwk(&self) -> Option<JWK> {
459        #[allow(unreachable_patterns)]
460        match self {
461            #[cfg(feature = "ed25519")]
462            Self::Ed25519(key) => Some((*key).into()),
463            #[cfg(feature = "secp256k1")]
464            Self::Secp256k1(key) => Some((*key).into()),
465            #[cfg(feature = "secp256r1")]
466            Self::P256(key) => Some((*key).into()),
467            #[cfg(feature = "secp384r1")]
468            Self::P384(key) => Some((*key).into()),
469            #[cfg(feature = "bbs")]
470            Self::Bls12_381(key) => Some(key.into()),
471            _ => None,
472        }
473    }
474}
475
476impl MultiCodec for DecodedMultikey {
477    #[allow(unused_variables)]
478    fn from_codec_and_bytes(codec: u64, bytes: &[u8]) -> Result<Self, ssi_multicodec::Error> {
479        match codec {
480            #[cfg(feature = "ed25519")]
481            ssi_multicodec::ED25519_PUB => {
482                ssi_multicodec::Codec::from_bytes(bytes).map(Self::Ed25519)
483            }
484            #[cfg(feature = "secp256k1")]
485            ssi_multicodec::SECP256K1_PUB => {
486                ssi_multicodec::Codec::from_bytes(bytes).map(Self::Secp256k1)
487            }
488            #[cfg(feature = "secp256r1")]
489            ssi_multicodec::P256_PUB => ssi_multicodec::Codec::from_bytes(bytes).map(Self::P256),
490            #[cfg(feature = "secp384r1")]
491            ssi_multicodec::P384_PUB => ssi_multicodec::Codec::from_bytes(bytes).map(Self::P384),
492            #[cfg(feature = "bbs")]
493            ssi_multicodec::BLS12_381_G2_PUB => {
494                ssi_multicodec::Codec::from_bytes(bytes).map(Self::Bls12_381)
495            }
496            _ => Err(ssi_multicodec::Error::UnexpectedCodec(codec)),
497        }
498    }
499
500    fn to_codec_and_bytes(&self) -> (u64, Cow<[u8]>) {
501        match self {
502            #[cfg(feature = "ed25519")]
503            Self::Ed25519(k) => k.to_codec_and_bytes(),
504            #[cfg(feature = "secp256k1")]
505            Self::Secp256k1(k) => k.to_codec_and_bytes(),
506            #[cfg(feature = "secp256r1")]
507            Self::P256(k) => k.to_codec_and_bytes(),
508            #[cfg(feature = "secp384r1")]
509            Self::P384(k) => k.to_codec_and_bytes(),
510            #[cfg(feature = "bbs")]
511            Self::Bls12_381(k) => k.to_codec_and_bytes(),
512            #[allow(unreachable_patterns)]
513            _ => unreachable!(), // references are always considered inhabited.
514        }
515    }
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
519pub struct MultikeyPair {
520    #[serde(rename = "publicKeyMultibase")]
521    pub public: MultibaseBuf,
522
523    #[serde(rename = "secretKeyMultibase")]
524    pub secret: MultibaseBuf,
525}
526
527impl MultikeyPair {
528    pub fn public_jwk(&self) -> Result<JWK, ToJWKError> {
529        let (_, decoded) = self.public.decode()?;
530        let multi_encoded = MultiEncodedBuf::new(decoded)?;
531        JWK::from_multicodec(&multi_encoded).map_err(Into::into)
532    }
533
534    pub fn secret_jwk(&self) -> Result<JWK, ToJWKError> {
535        let (_, decoded) = self.secret.decode()?;
536        let multi_encoded = MultiEncodedBuf::new(decoded)?;
537        JWK::from_multicodec(&multi_encoded).map_err(Into::into)
538    }
539}
540
541#[derive(Debug, thiserror::Error)]
542pub enum ToJWKError {
543    #[error(transparent)]
544    Multibase(#[from] multibase::Error),
545
546    #[error(transparent)]
547    MultiCodec(#[from] ssi_multicodec::Error),
548
549    #[error(transparent)]
550    JWK(#[from] ssi_jwk::FromMulticodecError),
551}