bc_components/ec_key/
ec_public_key.rs

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