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, 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 {
115        self.clone()
116    }
117}
118
119/// Converts a fixed-size byte array to an `ECUncompressedPublicKey`.
120impl From<[u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE]>
121    for ECUncompressedPublicKey
122{
123    /// Converts a 65-byte array into an EC uncompressed public key.
124    fn from(value: [u8; ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE]) -> Self {
125        Self::from_data(value)
126    }
127}
128
129/// Provides a reference to the key data as a byte slice.
130impl AsRef<[u8]> for ECUncompressedPublicKey {
131    /// Returns a reference to the key as a byte slice.
132    fn as_ref(&self) -> &[u8] { self.data() }
133}
134
135/// Defines CBOR tags for EC keys.
136impl CBORTagged for ECUncompressedPublicKey {
137    /// Returns the CBOR tags for EC keys.
138    fn cbor_tags() -> Vec<Tag> {
139        tags_for_values(&[tags::TAG_EC_KEY, tags::TAG_EC_KEY_V1])
140    }
141}
142
143/// Converts an `ECUncompressedPublicKey` to CBOR.
144impl From<ECUncompressedPublicKey> for CBOR {
145    /// Converts to tagged CBOR.
146    fn from(value: ECUncompressedPublicKey) -> Self { value.tagged_cbor() }
147}
148
149/// Implements CBOR encoding for EC uncompressed public keys.
150impl CBORTaggedEncodable for ECUncompressedPublicKey {
151    /// Creates the untagged CBOR representation.
152    ///
153    /// The format is a map with:
154    /// - Key 3: byte string of the key data
155    fn untagged_cbor(&self) -> CBOR {
156        let mut m = Map::new();
157        m.insert(3, CBOR::to_byte_string(self.0));
158        m.into()
159    }
160}
161
162impl ReferenceProvider for ECUncompressedPublicKey {
163    fn reference(&self) -> Reference {
164        Reference::from_digest(Digest::from_image(
165            self.tagged_cbor().to_cbor_data(),
166        ))
167    }
168}
169
170impl std::fmt::Display for ECUncompressedPublicKey {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        write!(f, "ECUncompressedPublicKey({})", self.ref_hex_short())
173    }
174}