bc_components/ec_key/ec_private_key.rs
1use bc_rand::{RandomNumberGenerator, SecureRandomNumberGenerator};
2use bc_ur::prelude::*;
3
4use crate::{
5 Digest, ECKey, ECKeyBase, ECPublicKey, Error, Reference, ReferenceProvider,
6 Result, SchnorrPublicKey, tags,
7};
8
9/// The size of an ECDSA private key in bytes (32 bytes).
10pub const ECDSA_PRIVATE_KEY_SIZE: usize = bc_crypto::ECDSA_PRIVATE_KEY_SIZE;
11
12/// A private key for elliptic curve digital signature algorithms.
13///
14/// An `ECPrivateKey` is a 32-byte secret value that can be used to:
15///
16/// - Generate its corresponding public key
17/// - Sign messages using the ECDSA signature scheme
18/// - Sign messages using the Schnorr signature scheme (BIP-340)
19///
20/// These keys use the secp256k1 curve, which is the same curve used in Bitcoin
21/// and other cryptocurrencies. The secp256k1 curve is defined by the Standards
22/// for Efficient Cryptography Group (SECG).
23///
24/// # Security
25///
26/// Private keys should be kept secret and never exposed. They represent
27/// proof of ownership and control over any associated assets or identities.
28///
29/// # Examples
30///
31/// Creating a new random private key:
32///
33/// ```
34/// use bc_components::ECPrivateKey;
35///
36/// // Generate a random private key
37/// let private_key = ECPrivateKey::new();
38/// ```
39///
40/// Signing a message with ECDSA:
41///
42/// ```
43/// use bc_components::ECPrivateKey;
44///
45/// // Generate a random private key
46/// let private_key = ECPrivateKey::new();
47///
48/// // Sign a message
49/// let message = b"Hello, world!";
50/// let signature = private_key.ecdsa_sign(message);
51/// ```
52#[derive(Clone, PartialEq, Eq, Hash)]
53pub struct ECPrivateKey([u8; ECDSA_PRIVATE_KEY_SIZE]);
54
55impl ECPrivateKey {
56 /// Creates a new random ECDSA private key.
57 ///
58 /// Uses a secure random number generator to generate the key.
59 pub fn new() -> Self {
60 let mut rng = SecureRandomNumberGenerator;
61 Self::new_using(&mut rng)
62 }
63
64 /// Creates a new random ECDSA private key using the given random number
65 /// generator.
66 ///
67 /// This allows for deterministic key generation when using a seeded RNG.
68 pub fn new_using(rng: &mut impl RandomNumberGenerator) -> Self {
69 let mut key = [0u8; ECDSA_PRIVATE_KEY_SIZE];
70 rng.fill_random_data(&mut key);
71 Self::from_data(key)
72 }
73
74 /// Returns the ECDSA private key as an array of bytes.
75 pub fn data(&self) -> &[u8; ECDSA_PRIVATE_KEY_SIZE] { &self.0 }
76
77 /// Get the ECDSA private key as a byte slice.
78 pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
79
80 /// Restores an ECDSA private key from an array of bytes.
81 ///
82 /// This method performs no validation on the input data.
83 pub const fn from_data(data: [u8; ECDSA_PRIVATE_KEY_SIZE]) -> Self {
84 Self(data)
85 }
86
87 /// Restores an ECDSA private key from a reference to an array of bytes.
88 ///
89 /// Returns an error if the data is not exactly 32 bytes.
90 pub fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self> {
91 let data = data.as_ref();
92 if data.len() != ECDSA_PRIVATE_KEY_SIZE {
93 return Err(Error::invalid_size(
94 "EC private key",
95 ECDSA_PRIVATE_KEY_SIZE,
96 data.len(),
97 ));
98 }
99 let mut arr = [0u8; ECDSA_PRIVATE_KEY_SIZE];
100 arr.copy_from_slice(data);
101 Ok(Self::from_data(arr))
102 }
103
104 /// Derives a new private key from the given key material.
105 ///
106 /// This method uses the provided key material to deterministically
107 /// generate a valid private key for the secp256k1 curve.
108 pub fn derive_from_key_material(key_material: impl AsRef<[u8]>) -> Self {
109 Self::from_data(bc_crypto::derive_signing_private_key(key_material))
110 }
111}
112
113impl ECPrivateKey {
114 /// Derives the Schnorr public key from this ECDSA private key.
115 ///
116 /// Schnorr public keys are used with the BIP-340 Schnorr signature scheme.
117 /// Unlike ECDSA public keys, Schnorr public keys are 32 bytes ("x-only")
118 /// rather than 33 bytes.
119 pub fn schnorr_public_key(&self) -> SchnorrPublicKey {
120 bc_crypto::schnorr_public_key_from_private_key(self.into()).into()
121 }
122
123 /// Signs a message using the ECDSA signature scheme.
124 ///
125 /// Returns a 70-72 byte signature in DER format.
126 pub fn ecdsa_sign(
127 &self,
128 message: impl AsRef<[u8]>,
129 ) -> [u8; bc_crypto::ECDSA_SIGNATURE_SIZE] {
130 bc_crypto::ecdsa_sign(&self.0, message.as_ref())
131 }
132
133 /// Signs a message using the Schnorr signature scheme with a custom random
134 /// number generator.
135 ///
136 /// This method implements the BIP-340 Schnorr signature scheme, which
137 /// provides several advantages over ECDSA including linearity (allowing
138 /// for signature aggregation) and non-malleability.
139 ///
140 /// Returns a 64-byte signature.
141 pub fn schnorr_sign_using(
142 &self,
143 message: impl AsRef<[u8]>,
144 rng: &mut dyn RandomNumberGenerator,
145 ) -> [u8; bc_crypto::SCHNORR_SIGNATURE_SIZE] {
146 bc_crypto::schnorr_sign_using(&self.0, message, rng)
147 }
148
149 /// Signs a message using the Schnorr signature scheme.
150 ///
151 /// Uses a secure random number generator for nonce generation.
152 ///
153 /// Returns a 64-byte signature.
154 pub fn schnorr_sign(
155 &self,
156 message: impl AsRef<[u8]>,
157 ) -> [u8; bc_crypto::SCHNORR_SIGNATURE_SIZE] {
158 let mut rng = SecureRandomNumberGenerator;
159 self.schnorr_sign_using(message, &mut rng)
160 }
161}
162
163/// Converts a fixed-size byte array to an `ECPrivateKey`.
164impl From<[u8; ECDSA_PRIVATE_KEY_SIZE]> for ECPrivateKey {
165 /// Converts a 32-byte array into an EC private key.
166 fn from(data: [u8; ECDSA_PRIVATE_KEY_SIZE]) -> Self {
167 Self::from_data(data)
168 }
169}
170
171/// Provides a reference to the key data as a byte slice.
172impl AsRef<[u8]> for ECPrivateKey {
173 /// Returns a reference to the key as a byte slice.
174 fn as_ref(&self) -> &[u8] { self.0.as_ref() }
175}
176
177/// Formats the key for debugging, showing type name and hexadecimal value.
178impl std::fmt::Debug for ECPrivateKey {
179 /// Displays the key with type information and hexadecimal value.
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 write!(f, "ECPrivateKey({})", self.hex())
182 }
183}
184
185/// Implements the `Default` trait, creating a random key.
186impl Default for ECPrivateKey {
187 /// Creates a new random key as the default value.
188 fn default() -> Self { Self::new() }
189}
190
191/// Converts a reference to an `ECPrivateKey` to a reference to a fixed-size
192/// byte array.
193impl<'a> From<&'a ECPrivateKey> for &'a [u8; ECDSA_PRIVATE_KEY_SIZE] {
194 /// Returns a reference to the underlying byte array.
195 fn from(value: &'a ECPrivateKey) -> Self { &value.0 }
196}
197
198/// Converts a reference to an `ECPrivateKey` to a reference to a byte slice.
199impl<'a> From<&'a ECPrivateKey> for &'a [u8] {
200 /// Returns a reference to the key as a byte slice.
201 fn from(value: &'a ECPrivateKey) -> Self { value.as_ref() }
202}
203
204/// Implements the `ECKeyBase` trait methods.
205impl ECKeyBase for ECPrivateKey {
206 /// The size of an EC private key (32 bytes).
207 const KEY_SIZE: usize = bc_crypto::ECDSA_PRIVATE_KEY_SIZE;
208
209 /// Creates a key from a byte slice, with validation.
210 fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self>
211 where
212 Self: Sized,
213 {
214 let data = data.as_ref();
215 if data.len() != ECDSA_PRIVATE_KEY_SIZE {
216 return Err(Error::invalid_size(
217 "EC private key",
218 ECDSA_PRIVATE_KEY_SIZE,
219 data.len(),
220 ));
221 }
222 let mut key = [0u8; ECDSA_PRIVATE_KEY_SIZE];
223 key.copy_from_slice(data);
224 Ok(Self(key))
225 }
226
227 /// Returns the key as a byte slice.
228 fn data(&self) -> &[u8] { self.0.as_ref() }
229}
230
231/// Implements the `ECKey` trait for deriving public keys.
232impl ECKey for ECPrivateKey {
233 /// Derives the corresponding ECDSA compressed public key.
234 fn public_key(&self) -> ECPublicKey {
235 bc_crypto::ecdsa_public_key_from_private_key(&self.0).into()
236 }
237}
238
239/// Defines CBOR tags for EC keys.
240impl CBORTagged for ECPrivateKey {
241 /// Returns the CBOR tags for EC keys.
242 fn cbor_tags() -> Vec<Tag> {
243 tags_for_values(&[tags::TAG_EC_KEY, tags::TAG_EC_KEY_V1])
244 }
245}
246
247/// Converts an `ECPrivateKey` to CBOR.
248impl From<ECPrivateKey> for CBOR {
249 /// Converts to tagged CBOR.
250 fn from(value: ECPrivateKey) -> Self { value.tagged_cbor() }
251}
252
253/// Implements CBOR encoding for EC private keys.
254impl CBORTaggedEncodable for ECPrivateKey {
255 /// Creates the untagged CBOR representation.
256 ///
257 /// The format is a map with:
258 /// - Key 2: boolean true (indicates private key)
259 /// - Key 3: byte string of the key data
260 fn untagged_cbor(&self) -> CBOR {
261 let mut m = Map::new();
262 m.insert(2, true);
263 m.insert(3, CBOR::to_byte_string(self.0));
264 m.into()
265 }
266}
267
268impl ReferenceProvider for ECPrivateKey {
269 fn reference(&self) -> Reference {
270 Reference::from_digest(Digest::from_image(
271 self.tagged_cbor().to_cbor_data(),
272 ))
273 }
274}
275
276impl std::fmt::Display for ECPrivateKey {
277 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278 write!(f, "ECPrivateKey({})", self.ref_hex_short())
279 }
280}