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}