bc_components/ec_key/
ec_public_key.rs

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