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}