ssi_verification_methods/methods/w3c/
ecdsa_secp_256k1_verification_key_2019.rs1use 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#[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 #[ld(id)]
56 pub id: IriBuf,
57
58 #[ld("sec:controller")]
60 pub controller: UriBuf,
61
62 #[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 ssi_jws::sign_bytes(algorithm, signing_bytes, secret_key)
92 .map_err(|_| MessageSignatureError::InvalidSecretKey)
93 }
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 fn id(&self) -> &Iri {
118 self.id.as_iri()
119 }
120
121 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 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}