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
28pub const MULTIKEY_TYPE: &str = "Multikey";
30
31#[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 #[ld(id)]
51 pub id: IriBuf,
52
53 #[ld("sec:controller")]
55 pub controller: UriBuf,
56
57 #[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!(), }
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}