Skip to main content

ssi_data_integrity_core/signing/
multibase.rs

1use std::marker::PhantomData;
2
3use multibase::Base;
4use ssi_claims_core::{ProofValidationError, ProofValidity, SignatureError};
5use ssi_crypto::algorithm::SignatureAlgorithmInstance;
6use ssi_verification_methods::{MessageSigner, VerifyBytes};
7
8use crate::{
9    suite::standard::{
10        SignatureAlgorithm, SignatureAndVerificationAlgorithm, VerificationAlgorithm,
11    },
12    CryptographicSuite, ProofConfigurationRef, ProofRef,
13};
14
15use super::AlgorithmSelection;
16
17/// Common signature format where the proof value is multibase-encoded.
18#[derive(
19    Debug,
20    Clone,
21    serde::Serialize,
22    serde::Deserialize,
23    linked_data::Serialize,
24    linked_data::Deserialize,
25)]
26#[ld(prefix("sec" = "https://w3id.org/security#"))]
27pub struct MultibaseSignature {
28    /// Multibase encoded signature.
29    #[serde(rename = "proofValue")]
30    #[ld("sec:proofValue")]
31    pub proof_value: String,
32}
33
34impl MultibaseSignature {
35    pub fn new(signature: Vec<u8>, base: Base) -> Self {
36        Self {
37            proof_value: multibase::encode(base, signature),
38        }
39    }
40
41    pub fn new_base58btc(signature: Vec<u8>) -> Self {
42        Self {
43            proof_value: multibase::encode(Base::Base58Btc, signature),
44        }
45    }
46
47    pub fn decode(&self) -> Result<(Base, Vec<u8>), ProofValidationError> {
48        multibase::decode(&self.proof_value).map_err(|_| ProofValidationError::InvalidSignature)
49    }
50}
51
52impl AsRef<str> for MultibaseSignature {
53    fn as_ref(&self) -> &str {
54        &self.proof_value
55    }
56}
57
58impl super::AlterSignature for MultibaseSignature {
59    fn alter(&mut self) {
60        self.proof_value.push_str("ff")
61    }
62}
63
64pub trait StaticBase {
65    const BASE: Base;
66}
67
68pub struct Base58Btc;
69
70impl StaticBase for Base58Btc {
71    const BASE: Base = Base::Base58Btc;
72}
73
74pub struct MultibaseSigning<A, B>(PhantomData<(A, B)>);
75
76impl<A, B> SignatureAndVerificationAlgorithm for MultibaseSigning<A, B> {
77    type Signature = MultibaseSignature;
78}
79
80impl<A, B, S, T> SignatureAlgorithm<S, T> for MultibaseSigning<A, B>
81where
82    S: CryptographicSuite,
83    S::PreparedClaims: AsRef<[u8]>,
84    A: AlgorithmSelection<S::VerificationMethod, S::ProofOptions>,
85    B: StaticBase,
86    T: MessageSigner<A>,
87{
88    async fn sign(
89        verification_method: &S::VerificationMethod,
90        signer: T,
91        prepared_claims: S::PreparedClaims,
92        proof_configuration: ProofConfigurationRef<'_, S>,
93    ) -> Result<Self::Signature, SignatureError> {
94        let algorithm = A::select_algorithm(verification_method, proof_configuration.options)?;
95
96        Ok(MultibaseSignature::new(
97            signer.sign(algorithm, prepared_claims.as_ref()).await?,
98            B::BASE,
99        ))
100    }
101}
102
103impl<A, B, S> VerificationAlgorithm<S> for MultibaseSigning<A, B>
104where
105    S: CryptographicSuite<Signature = MultibaseSignature>,
106    S::PreparedClaims: AsRef<[u8]>,
107    S::VerificationMethod: VerifyBytes<A>,
108    A: AlgorithmSelection<S::VerificationMethod, S::ProofOptions>,
109    B: StaticBase,
110{
111    fn verify(
112        verification_method: &S::VerificationMethod,
113        prepared_claims: S::PreparedClaims,
114        proof: ProofRef<S>,
115    ) -> Result<ProofValidity, ProofValidationError> {
116        let algorithm_instance = A::select_algorithm(verification_method, proof.options)?;
117
118        let (_, signature_bytes) = proof.signature.decode()?; // Should we check the base?
119        verification_method.verify_bytes(
120            algorithm_instance.algorithm(),
121            prepared_claims.as_ref(),
122            &signature_bytes,
123        )
124    }
125}