bc_components/ec_key/
ec_uncompressed_public_key.rs

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