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}