bc_components/ec_key/ec_uncompressed_public_key.rs
1use bc_ur::prelude::*;
2
3use crate::{
4 Digest, ECKey, ECKeyBase, ECPublicKey, ECPublicKeyBase, Error, Reference,
5 ReferenceProvider, Result, tags,
6};
7
8/// The size of an ECDSA uncompressed public key in bytes (65 bytes).
9pub const ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE: usize =
10 bc_crypto::ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE;
11
12/// An uncompressed elliptic curve digital signature algorithm (ECDSA) public
13/// key.
14///
15/// An `ECUncompressedPublicKey` is a 65-byte representation of a public key on
16/// the secp256k1 curve. It consists of:
17///
18/// - 1 byte prefix (0x04)
19/// - 32 bytes for the x-coordinate
20/// - 32 bytes for the y-coordinate
21///
22/// This format explicitly includes both coordinates of the elliptic curve
23/// point, unlike the compressed format which only includes the x-coordinate and
24/// a single byte to indicate the parity of the y-coordinate.
25///
26/// This is considered a legacy key type and is not recommended for general use.
27/// The compressed format (`ECPublicKey`) is more space-efficient and provides
28/// the same cryptographic security. However, some legacy systems or protocols
29/// might require the uncompressed format.
30///
31/// # Examples
32///
33/// Converting between compressed and uncompressed formats:
34///
35/// ```
36/// use bc_components::{
37/// ECKey, ECPrivateKey, ECPublicKey, ECPublicKeyBase,
38/// ECUncompressedPublicKey,
39/// };
40///
41/// // Generate a keypair
42/// let private_key = ECPrivateKey::new();
43/// let compressed_key = private_key.public_key();
44///
45/// // Convert to uncompressed format
46/// let uncompressed_key = compressed_key.uncompressed_public_key();
47///
48/// // Convert back to compressed format
49/// let compressed_again = uncompressed_key.public_key();
50///
51/// // They should be equal
52/// assert_eq!(compressed_key, compressed_again);
53/// ```
54#[derive(Clone, Copy, PartialEq, Eq, Hash)]
55pub struct ECUncompressedPublicKey([u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE]);
56
57impl ECUncompressedPublicKey {
58 /// Restores an ECDSA uncompressed public key from an array of bytes.
59 ///
60 /// This method performs no validation on the input data.
61 pub const fn from_data(
62 data: [u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE],
63 ) -> Self {
64 Self(data)
65 }
66}
67
68/// Formats the key for debugging, showing type name and hexadecimal value.
69impl std::fmt::Debug for ECUncompressedPublicKey {
70 /// Displays the key with type information and hexadecimal value.
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "ECUncompressedPublicKey({})", self.hex())
73 }
74}
75
76/// Implements the `ECKeyBase` trait methods for `ECUncompressedPublicKey`.
77impl ECKeyBase for ECUncompressedPublicKey {
78 /// The size of an EC uncompressed public key (65 bytes).
79 const KEY_SIZE: usize = bc_crypto::ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE;
80
81 /// Creates a key from a byte slice, with validation.
82 fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self>
83 where
84 Self: Sized,
85 {
86 let data = data.as_ref();
87 if data.len() != ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE {
88 return Err(Error::invalid_size(
89 "ECDSA uncompressed public key",
90 ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE,
91 data.len(),
92 ));
93 }
94 let mut key = [0u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE];
95 key.copy_from_slice(data);
96 Ok(Self(key))
97 }
98
99 /// Returns the key as a byte slice.
100 fn data(&self) -> &[u8] { &self.0 }
101}
102
103/// Implements the `ECKey` trait for converting to compressed format.
104impl ECKey for ECUncompressedPublicKey {
105 /// Converts this uncompressed public key to its compressed form.
106 fn public_key(&self) -> ECPublicKey {
107 bc_crypto::ecdsa_compress_public_key(&self.0).into()
108 }
109}
110
111/// Implements the `ECPublicKeyBase` trait.
112impl ECPublicKeyBase for ECUncompressedPublicKey {
113 /// Returns this uncompressed public key (self).
114 fn uncompressed_public_key(&self) -> ECUncompressedPublicKey { *self }
115}
116
117/// Converts a fixed-size byte array to an `ECUncompressedPublicKey`.
118impl From<[u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE]>
119 for ECUncompressedPublicKey
120{
121 /// Converts a 65-byte array into an EC uncompressed public key.
122 fn from(value: [u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE]) -> Self {
123 Self::from_data(value)
124 }
125}
126
127/// Provides a reference to the key data as a byte slice.
128impl AsRef<[u8]> for ECUncompressedPublicKey {
129 /// Returns a reference to the key as a byte slice.
130 fn as_ref(&self) -> &[u8] { self.data() }
131}
132
133/// Defines CBOR tags for EC keys.
134impl CBORTagged for ECUncompressedPublicKey {
135 /// Returns the CBOR tags for EC keys.
136 fn cbor_tags() -> Vec<Tag> {
137 tags_for_values(&[tags::TAG_EC_KEY, tags::TAG_EC_KEY_V1])
138 }
139}
140
141/// Converts an `ECUncompressedPublicKey` to CBOR.
142impl From<ECUncompressedPublicKey> for CBOR {
143 /// Converts to tagged CBOR.
144 fn from(value: ECUncompressedPublicKey) -> Self { value.tagged_cbor() }
145}
146
147/// Implements CBOR encoding for EC uncompressed public keys.
148impl CBORTaggedEncodable for ECUncompressedPublicKey {
149 /// Creates the untagged CBOR representation.
150 ///
151 /// The format is a map with:
152 /// - Key 3: byte string of the key data
153 fn untagged_cbor(&self) -> CBOR {
154 let mut m = Map::new();
155 m.insert(3, CBOR::to_byte_string(self.0));
156 m.into()
157 }
158}
159
160impl ReferenceProvider for ECUncompressedPublicKey {
161 fn reference(&self) -> Reference {
162 Reference::from_digest(Digest::from_image(
163 self.tagged_cbor().to_cbor_data(),
164 ))
165 }
166}
167
168impl std::fmt::Display for ECUncompressedPublicKey {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 write!(f, "ECUncompressedPublicKey({})", self.ref_hex_short())
171 }
172}