bc_components/ec_key/
ec_public_key.rs

1use anyhow::{Result, bail};
2use bc_crypto::ECDSA_SIGNATURE_SIZE;
3use bc_ur::prelude::*;
4
5use crate::{ECKey, ECKeyBase, ECPublicKeyBase, Signature, Verifier, tags};
6
7/// The size of an ECDSA compressed public key in bytes (33 bytes).
8pub const ECDSA_PUBLIC_KEY_SIZE: usize = bc_crypto::ECDSA_PUBLIC_KEY_SIZE;
9
10/// A compressed elliptic curve digital signature algorithm (ECDSA) public key.
11///
12/// An `ECPublicKey` is a 33-byte compressed representation of a public key on
13/// the secp256k1 curve. The first byte is a prefix (0x02 or 0x03) that
14/// indicates the parity of the y-coordinate, followed by the 32-byte
15/// x-coordinate.
16///
17/// These public keys are used to:
18/// - Verify ECDSA signatures
19/// - Identify the owner of a private key without revealing the private key
20/// - Derive shared secrets (when combined with another party's private key)
21///
22/// Unlike the larger 65-byte uncompressed format (`ECUncompressedPublicKey`),
23/// compressed public keys save space while providing the same cryptographic
24/// security.
25///
26/// # Examples
27///
28/// Verifying an ECDSA signature:
29///
30/// ```
31/// use bc_components::{ECKey, ECPrivateKey, ECPublicKey};
32///
33/// // Generate a keypair
34/// let private_key = ECPrivateKey::new();
35/// let public_key = private_key.public_key();
36///
37/// // Sign a message
38/// let message = b"Hello, world!";
39/// let signature = private_key.ecdsa_sign(message);
40///
41/// // Verify the signature
42/// assert!(public_key.verify(&signature, message));
43/// ```
44#[derive(Clone, PartialEq, Eq, Hash)]
45pub struct ECPublicKey([u8; ECDSA_PUBLIC_KEY_SIZE]);
46
47impl ECPublicKey {
48    /// Restores an ECDSA public key from an array of bytes.
49    ///
50    /// This method performs no validation on the input data.
51    pub const fn from_data(data: [u8; ECDSA_PUBLIC_KEY_SIZE]) -> Self {
52        Self(data)
53    }
54
55    /// Returns the ECDSA public key as an array of bytes.
56    pub fn data(&self) -> &[u8; ECDSA_PUBLIC_KEY_SIZE] { &self.0 }
57
58    /// Get the ECDSA public key as a byte slice.
59    pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
60}
61
62impl ECPublicKey {
63    /// Verifies an ECDSA signature for a message using this public key.
64    ///
65    /// Returns `true` if the signature is valid for the given message and this
66    /// public key, and `false` otherwise.
67    ///
68    /// # Parameters
69    /// - `signature`: A 70-72 byte DER-encoded ECDSA signature
70    /// - `message`: The message that was signed
71    pub fn verify(
72        &self,
73        signature: &[u8; ECDSA_SIGNATURE_SIZE],
74        message: impl AsRef<[u8]>,
75    ) -> bool {
76        bc_crypto::ecdsa_verify(&self.0, signature, message)
77    }
78}
79
80impl AsRef<[u8]> for ECPublicKey {
81    fn as_ref(&self) -> &[u8] { &self.0 }
82}
83
84/// Formats the key as a hexadecimal string.
85impl std::fmt::Display for ECPublicKey {
86    /// Displays the key as a hexadecimal string.
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        write!(f, "{}", self.hex())
89    }
90}
91
92/// Formats the key for debugging, showing type name and hexadecimal value.
93impl std::fmt::Debug for ECPublicKey {
94    /// Displays the key with type information and hexadecimal value.
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(f, "ECPublicKey({})", self.hex())
97    }
98}
99
100/// Implements the `ECKeyBase` trait methods for `ECPublicKey`.
101impl ECKeyBase for ECPublicKey {
102    /// The size of an EC compressed public key (33 bytes).
103    const KEY_SIZE: usize = bc_crypto::ECDSA_PUBLIC_KEY_SIZE;
104
105    /// Creates a key from a byte slice, with validation.
106    fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self>
107    where
108        Self: Sized,
109    {
110        let data = data.as_ref();
111        if data.len() != ECDSA_PUBLIC_KEY_SIZE {
112            bail!("Invalid ECDSA public key size");
113        }
114        let mut key = [0u8; ECDSA_PUBLIC_KEY_SIZE];
115        key.copy_from_slice(data);
116        Ok(Self(key))
117    }
118
119    /// Returns the key as a byte slice.
120    fn data(&self) -> &[u8] { self.into() }
121}
122
123/// Implements the `Verifier` trait for verifying signatures.
124impl Verifier for ECPublicKey {
125    /// Verifies a signature for a message using this public key.
126    ///
127    /// Only supports ECDSA signatures; returns `false` for other signature
128    /// types.
129    fn verify(&self, signature: &Signature, message: &dyn AsRef<[u8]>) -> bool {
130        match signature {
131            Signature::ECDSA(sig) => self.verify(sig, message),
132            _ => false,
133        }
134    }
135}
136
137/// Implements the `ECKey` trait for `ECPublicKey`.
138impl ECKey for ECPublicKey {
139    /// Returns the public key (self).
140    fn public_key(&self) -> ECPublicKey { self.clone() }
141}
142
143/// Implements the `ECPublicKeyBase` trait for converting to uncompressed
144/// format.
145impl ECPublicKeyBase for ECPublicKey {
146    /// Converts this compressed public key to its uncompressed form.
147    fn uncompressed_public_key(&self) -> crate::ECUncompressedPublicKey {
148        bc_crypto::ecdsa_decompress_public_key(&self.0).into()
149    }
150}
151
152/// Converts a reference to an `ECPublicKey` to a reference to a fixed-size byte
153/// array.
154impl<'a> From<&'a ECPublicKey> for &'a [u8; ECPublicKey::KEY_SIZE] {
155    /// Returns a reference to the underlying byte array.
156    fn from(value: &'a ECPublicKey) -> Self { &value.0 }
157}
158
159/// Converts a fixed-size byte array to an `ECPublicKey`.
160impl From<[u8; ECDSA_PUBLIC_KEY_SIZE]> for ECPublicKey {
161    /// Converts a 33-byte array into an EC public key.
162    fn from(value: [u8; ECDSA_PUBLIC_KEY_SIZE]) -> Self {
163        Self::from_data(value)
164    }
165}
166
167/// Converts a reference to an `ECPublicKey` to a reference to a byte slice.
168impl<'a> From<&'a ECPublicKey> for &'a [u8] {
169    /// Returns a reference to the key as a byte slice.
170    fn from(value: &'a ECPublicKey) -> Self { &value.0 }
171}
172
173/// Defines CBOR tags for EC keys.
174impl CBORTagged for ECPublicKey {
175    /// Returns the CBOR tags for EC keys.
176    fn cbor_tags() -> Vec<Tag> {
177        tags_for_values(&[tags::TAG_EC_KEY, tags::TAG_EC_KEY_V1])
178    }
179}
180
181/// Converts an `ECPublicKey` to CBOR.
182impl From<ECPublicKey> for CBOR {
183    /// Converts to tagged CBOR.
184    fn from(value: ECPublicKey) -> Self { value.tagged_cbor() }
185}
186
187/// Implements CBOR encoding for EC public keys.
188impl CBORTaggedEncodable for ECPublicKey {
189    /// Creates the untagged CBOR representation.
190    ///
191    /// The format is a map with:
192    /// - Key 3: byte string of the key data (Note the absence of key 2, which
193    ///   would indicate a private key)
194    fn untagged_cbor(&self) -> CBOR {
195        let mut m = Map::new();
196        m.insert(3, CBOR::to_byte_string(self.0));
197        m.into()
198    }
199}