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}