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}