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}