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