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}