Skip to main content

ssi_verification_methods/methods/w3c/
ecdsa_secp_256k1_verification_key_2019.rs

1use std::{borrow::Cow, hash::Hash, str::FromStr};
2
3use hex::FromHexError;
4use iref::{Iri, IriBuf, UriBuf};
5use rdf_types::{Interpretation, Vocabulary};
6use serde::{Deserialize, Serialize};
7use ssi_claims_core::{InvalidProof, MessageSignatureError, ProofValidationError, ProofValidity};
8use ssi_jwk::JWK;
9use ssi_verification_methods_core::{JwkVerificationMethod, VerificationMethodSet, VerifyBytes};
10use static_iref::iri;
11
12use crate::{
13    ExpectedType, GenericVerificationMethod, InvalidVerificationMethod, TypedVerificationMethod,
14    VerificationMethod,
15};
16
17pub const ECDSA_SECP_256K1_VERIFICATION_KEY_2019_TYPE: &str = "EcdsaSecp256k1VerificationKey2019";
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub enum DigestFunction {
21    Sha256,
22    Keccack,
23}
24
25impl DigestFunction {
26    pub fn into_crypto_algorithm(self) -> ssi_jwk::Algorithm {
27        match self {
28            Self::Sha256 => ssi_jwk::Algorithm::ES256K,
29            Self::Keccack => ssi_jwk::Algorithm::ESKeccakK,
30        }
31    }
32}
33
34/// Key for [Ecdsa Secp256k1 Signature 2019][1].
35///
36/// See: <https://w3c-ccg.github.io/lds-ecdsa-secp256k1-2019/#key-format>
37///
38/// [1]: <https://w3c-ccg.github.io/lds-ecdsa-secp256k1-2019/>
39#[derive(
40    Debug,
41    Clone,
42    PartialEq,
43    Eq,
44    Hash,
45    Serialize,
46    Deserialize,
47    linked_data::Serialize,
48    linked_data::Deserialize,
49)]
50#[serde(tag = "type", rename = "EcdsaSecp256k1VerificationKey2019")]
51#[ld(prefix("sec" = "https://w3id.org/security#"))]
52#[ld(type = "sec:EcdsaSecp256k1VerificationKey2019")]
53pub struct EcdsaSecp256k1VerificationKey2019 {
54    /// Key identifier.
55    #[ld(id)]
56    pub id: IriBuf,
57
58    /// Key controller.
59    #[ld("sec:controller")]
60    pub controller: UriBuf,
61
62    /// Public key.
63    #[serde(flatten)]
64    #[ld(flatten)]
65    pub public_key: PublicKey,
66}
67
68impl EcdsaSecp256k1VerificationKey2019 {
69    pub const NAME: &'static str = ECDSA_SECP_256K1_VERIFICATION_KEY_2019_TYPE;
70    pub const IRI: &'static Iri =
71        iri!("https://w3id.org/security#EcdsaSecp256k1VerificationKey2019");
72
73    pub fn public_key_jwk(&'_ self) -> Cow<'_, JWK> {
74        self.public_key.to_jwk()
75    }
76
77    pub fn sign_bytes(
78        &self,
79        secret_key: &JWK,
80        digest_function: DigestFunction,
81        signing_bytes: &[u8],
82    ) -> Result<Vec<u8>, MessageSignatureError> {
83        let algorithm = digest_function.into_crypto_algorithm();
84        let key_algorithm = secret_key.algorithm.unwrap_or(algorithm);
85        if !algorithm.is_compatible_with(key_algorithm) {
86            return Err(MessageSignatureError::InvalidSecretKey);
87        }
88
89        // let header = ssi_jws::Header::new_unencoded(algorithm, None);
90        // let signing_bytes = header.encode_signing_bytes(data);
91        ssi_jws::sign_bytes(algorithm, signing_bytes, secret_key)
92            .map_err(|_| MessageSignatureError::InvalidSecretKey)
93        // Ok(JwsBuf::from_signing_bytes_and_signature(signing_bytes, signature).unwrap())
94    }
95
96    pub fn verify_bytes(
97        &self,
98        data: &[u8],
99        signature: &[u8],
100        digest_function: DigestFunction,
101    ) -> Result<ProofValidity, ProofValidationError> {
102        let public_key = self.public_key.to_jwk();
103        let algorithm = digest_function.into_crypto_algorithm();
104        if !algorithm.is_compatible_with(public_key.algorithm.unwrap_or(algorithm)) {
105            return Err(ProofValidationError::InvalidKey);
106        }
107
108        Ok(
109            ssi_jws::verify_bytes(ssi_jwk::Algorithm::ES256K, data, &public_key, signature)
110                .map_err(|_| InvalidProof::Signature),
111        )
112    }
113}
114
115impl VerificationMethod for EcdsaSecp256k1VerificationKey2019 {
116    /// Returns the identifier of the key.
117    fn id(&self) -> &Iri {
118        self.id.as_iri()
119    }
120
121    /// Returns an URI to the key controller.
122    fn controller(&self) -> Option<&Iri> {
123        Some(self.controller.as_iri())
124    }
125}
126
127impl VerificationMethodSet for EcdsaSecp256k1VerificationKey2019 {
128    type TypeSet = &'static str;
129
130    fn type_set() -> Self::TypeSet {
131        Self::NAME
132    }
133}
134
135impl TypedVerificationMethod for EcdsaSecp256k1VerificationKey2019 {
136    fn expected_type() -> Option<ExpectedType> {
137        Some(
138            ECDSA_SECP_256K1_VERIFICATION_KEY_2019_TYPE
139                .to_string()
140                .into(),
141        )
142    }
143
144    fn type_match(ty: &str) -> bool {
145        ty == ECDSA_SECP_256K1_VERIFICATION_KEY_2019_TYPE
146    }
147
148    /// Returns the type of the key.
149    fn type_(&self) -> &str {
150        ECDSA_SECP_256K1_VERIFICATION_KEY_2019_TYPE
151    }
152}
153
154impl JwkVerificationMethod for EcdsaSecp256k1VerificationKey2019 {
155    fn to_jwk(&'_ self) -> Cow<'_, JWK> {
156        self.public_key_jwk()
157    }
158}
159
160impl VerifyBytes<ssi_crypto::algorithm::ES256K> for EcdsaSecp256k1VerificationKey2019 {
161    fn verify_bytes(
162        &self,
163        _: ssi_crypto::algorithm::ES256K,
164        signing_bytes: &[u8],
165        signature: &[u8],
166    ) -> Result<ProofValidity, ProofValidationError> {
167        self.verify_bytes(signing_bytes, signature, DigestFunction::Sha256)
168    }
169}
170
171impl TryFrom<GenericVerificationMethod> for EcdsaSecp256k1VerificationKey2019 {
172    type Error = InvalidVerificationMethod;
173
174    fn try_from(mut m: GenericVerificationMethod) -> Result<Self, Self::Error> {
175        let public_key = match (
176            m.properties.remove("publicKeyJwk"),
177            m.properties.get("publicKeyHex"),
178        ) {
179            (Some(k), None) => PublicKey::Jwk(
180                serde_json::from_value(k)
181                    .map_err(|_| InvalidVerificationMethod::invalid_property("publicKeyJwk"))?,
182            ),
183            (None, Some(k)) => PublicKey::Hex(Box::new(
184                k.as_str()
185                    .ok_or_else(|| InvalidVerificationMethod::invalid_property("publicKeyHex"))?
186                    .parse()
187                    .map_err(|_| InvalidVerificationMethod::invalid_property("publicKeyHex"))?,
188            )),
189            (Some(_), Some(_)) => return Err(InvalidVerificationMethod::AmbiguousPublicKey),
190            (None, None) => {
191                return Err(InvalidVerificationMethod::missing_property("publicKeyJwk"))
192            }
193        };
194
195        Ok(Self {
196            id: m.id,
197            controller: m.controller,
198            public_key,
199        })
200    }
201}
202
203#[derive(
204    Debug,
205    Clone,
206    PartialEq,
207    Eq,
208    Hash,
209    Serialize,
210    Deserialize,
211    linked_data::Serialize,
212    linked_data::Deserialize,
213)]
214#[ld(prefix("sec" = "https://w3id.org/security#"))]
215pub enum PublicKey {
216    #[serde(rename = "publicKeyJwk")]
217    #[ld("sec:publicKeyJwk")]
218    Jwk(Box<JWK>),
219
220    #[serde(rename = "publicKeyHex")]
221    #[ld("sec:publicKeyHex")]
222    Hex(Box<PublicKeyHex>),
223}
224
225impl PublicKey {
226    pub fn to_jwk(&'_ self) -> Cow<'_, JWK> {
227        match self {
228            Self::Jwk(jwk) => Cow::Borrowed(jwk),
229            Self::Hex(hex) => Cow::Owned(hex.to_jwk()),
230        }
231    }
232}
233
234#[derive(Debug, Clone)]
235pub struct PublicKeyHex {
236    encoded: String,
237    decoded: k256::PublicKey,
238}
239
240impl PublicKeyHex {
241    pub fn decode(encoded: String) -> Result<Self, InvalidPublicKey> {
242        let bytes = hex::decode(&encoded)?;
243        let decoded = k256::PublicKey::from_sec1_bytes(&bytes)?;
244
245        Ok(Self { encoded, decoded })
246    }
247
248    pub fn to_jwk(&self) -> JWK {
249        self.decoded.into()
250    }
251}
252
253impl PartialEq for PublicKeyHex {
254    fn eq(&self, other: &Self) -> bool {
255        self.decoded.eq(&other.decoded)
256    }
257}
258
259impl Eq for PublicKeyHex {}
260
261impl Hash for PublicKeyHex {
262    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
263        self.encoded.hash(state)
264    }
265}
266
267impl Serialize for PublicKeyHex {
268    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
269    where
270        S: serde::Serializer,
271    {
272        self.encoded.serialize(serializer)
273    }
274}
275
276impl<'a> Deserialize<'a> for PublicKeyHex {
277    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
278    where
279        D: serde::Deserializer<'a>,
280    {
281        use serde::de::Error;
282        let encoded = String::deserialize(deserializer)?;
283        Self::decode(encoded).map_err(D::Error::custom)
284    }
285}
286
287impl FromStr for PublicKeyHex {
288    type Err = InvalidPublicKey;
289
290    fn from_str(s: &str) -> Result<Self, Self::Err> {
291        Self::decode(s.to_owned())
292    }
293}
294
295impl<I: Interpretation, V: Vocabulary> linked_data::LinkedDataResource<I, V> for PublicKeyHex
296where
297    String: linked_data::LinkedDataResource<I, V>,
298{
299    fn interpretation(
300        &'_ self,
301        vocabulary: &mut V,
302        interpretation: &mut I,
303    ) -> linked_data::ResourceInterpretation<'_, I, V> {
304        self.encoded.interpretation(vocabulary, interpretation)
305    }
306}
307
308impl<I: Interpretation, V: Vocabulary> linked_data::LinkedDataSubject<I, V> for PublicKeyHex
309where
310    String: linked_data::LinkedDataSubject<I, V>,
311{
312    fn visit_subject<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
313    where
314        S: linked_data::SubjectVisitor<I, V>,
315    {
316        self.encoded.visit_subject(serializer)
317    }
318}
319
320impl<I: Interpretation, V: Vocabulary> linked_data::LinkedDataPredicateObjects<I, V>
321    for PublicKeyHex
322where
323    String: linked_data::LinkedDataPredicateObjects<I, V>,
324{
325    fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
326    where
327        S: linked_data::PredicateObjectsVisitor<I, V>,
328    {
329        self.encoded.visit_objects(visitor)
330    }
331}
332
333#[derive(Debug, thiserror::Error)]
334pub enum InvalidPublicKey {
335    #[error("invalid hex encoding: {0}")]
336    Hex(#[from] FromHexError),
337
338    #[error("invalid key bytes: {0}")]
339    K256(#[from] k256::elliptic_curve::Error),
340}
341
342impl From<InvalidPublicKey> for ProofValidationError {
343    fn from(_value: InvalidPublicKey) -> Self {
344        Self::InvalidKey
345    }
346}