Skip to main content

warg_crypto/signing/
public_key.rs

1use super::{Signature, SignatureAlgorithm, SignatureAlgorithmParseError};
2use base64::{engine::general_purpose::STANDARD, Engine};
3use core::fmt;
4use serde::{Deserialize, Serialize};
5use signature::{Error as SignatureError, Verifier};
6use std::str::FromStr;
7use thiserror::Error;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
10pub enum PublicKey {
11    EcdsaP256(p256::ecdsa::VerifyingKey),
12}
13
14impl PublicKey {
15    /// The signature algorithm used by this key
16    pub fn signature_algorithm(&self) -> SignatureAlgorithm {
17        match self {
18            PublicKey::EcdsaP256(_) => SignatureAlgorithm::EcdsaP256,
19        }
20    }
21
22    /// Get the encoded bytes of this key
23    pub fn bytes(&self) -> Vec<u8> {
24        match self {
25            PublicKey::EcdsaP256(key) => key.to_encoded_point(true).as_bytes().to_vec(),
26        }
27    }
28
29    /// Verify that a given message and signature were signed by the private key associated with this public key
30    pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), SignatureError> {
31        match (self, signature) {
32            (PublicKey::EcdsaP256(key), Signature::P256(signature)) => key.verify(msg, signature),
33        }
34    }
35
36    /// Compute the digest of this key
37    pub fn fingerprint(&self) -> KeyID {
38        let key_hash = self
39            .signature_algorithm()
40            .digest_algorithm()
41            .digest(format!("{}", self).as_bytes());
42
43        KeyID(format!("{}", key_hash))
44    }
45}
46
47impl fmt::Display for PublicKey {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(
50            f,
51            "{}:{}",
52            self.signature_algorithm(),
53            STANDARD.encode(self.bytes())
54        )
55    }
56}
57
58impl FromStr for PublicKey {
59    type Err = PublicKeyParseError;
60
61    fn from_str(s: &str) -> Result<Self, Self::Err> {
62        let parts: Vec<&str> = s.split(|c| c == ':').collect();
63        if parts.len() != 2 {
64            return Err(PublicKeyParseError::IncorrectStructure(parts.len()));
65        }
66        let algo = parts[0].parse::<SignatureAlgorithm>()?;
67        let bytes = STANDARD.decode(parts[1])?;
68
69        let key = match algo {
70            SignatureAlgorithm::EcdsaP256 => {
71                PublicKey::EcdsaP256(p256::ecdsa::VerifyingKey::from_sec1_bytes(&bytes)?)
72            }
73        };
74
75        Ok(key)
76    }
77}
78
79impl Serialize for PublicKey {
80    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81    where
82        S: serde::Serializer,
83    {
84        serializer.serialize_str(&format!("{}", self))
85    }
86}
87
88impl<'de> Deserialize<'de> for PublicKey {
89    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
90    where
91        D: serde::Deserializer<'de>,
92    {
93        Self::from_str(&String::deserialize(deserializer)?).map_err(serde::de::Error::custom)
94    }
95}
96
97#[derive(Error, Debug)]
98pub enum PublicKeyParseError {
99    #[error("expected 2 parts, found {0}")]
100    IncorrectStructure(usize),
101
102    #[error("unable to parse signature algorithm")]
103    SignatureAlgorithmParseError(#[from] SignatureAlgorithmParseError),
104
105    #[error("base64 decode failed")]
106    Base64DecodeError(#[from] base64::DecodeError),
107
108    #[error("public key could not be constructed from bytes")]
109    SignatureError(#[from] SignatureError),
110}
111
112impl From<p256::ecdsa::VerifyingKey> for PublicKey {
113    fn from(key: p256::ecdsa::VerifyingKey) -> Self {
114        PublicKey::EcdsaP256(key)
115    }
116}
117
118#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
119#[serde(transparent)]
120pub struct KeyID(String);
121
122impl fmt::Display for KeyID {
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        write!(f, "{}", self.0)
125    }
126}
127
128impl From<String> for KeyID {
129    fn from(s: String) -> Self {
130        KeyID(s)
131    }
132}
133
134impl From<KeyID> for String {
135    fn from(id: KeyID) -> Self {
136        id.0
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use pretty_assertions::assert_eq;
144
145    #[test]
146    fn test_roundtrip_alice() {
147        let key_str = "ecdsa-p256:A1OfZz5Y9Ny7VKPVwroCTQPAr9tmlI4U/UTYHZHA87AF";
148        let pub_key: PublicKey = key_str.parse().unwrap();
149        assert_eq!(key_str, &format!("{pub_key}"));
150    }
151
152    #[test]
153    fn test_roundtrip_bob() {
154        let key_str = "ecdsa-p256:A5qc6uBi070EBb4GihGzpx6Cm5+oZnv4dWpBhhuZVagu";
155        let pub_key: PublicKey = key_str.parse().unwrap();
156        assert_eq!(key_str, &format!("{pub_key}"));
157    }
158}