fuel_crypto/secp256/
secret.rs

1use fuel_types::Bytes32;
2
3use core::{
4    fmt,
5    ops::Deref,
6    str,
7};
8
9use zeroize::Zeroize;
10
11use crate::{
12    secp256::PublicKey,
13    Error,
14};
15
16#[cfg(feature = "std")]
17use coins_bip32::path::DerivationPath;
18
19#[cfg(feature = "std")]
20use coins_bip39::{
21    English,
22    Mnemonic,
23};
24
25#[cfg(feature = "random")]
26use rand::{
27    CryptoRng,
28    RngCore,
29};
30
31/// Asymmetric secret key, guaranteed to be valid by construction
32#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroize)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[repr(transparent)]
35pub struct SecretKey(Bytes32);
36
37impl SecretKey {
38    /// Memory length of the type
39    pub const LEN: usize = Bytes32::LEN;
40}
41
42impl Deref for SecretKey {
43    type Target = [u8; SecretKey::LEN];
44
45    fn deref(&self) -> &[u8; SecretKey::LEN] {
46        self.0.deref()
47    }
48}
49
50impl AsRef<[u8]> for SecretKey {
51    fn as_ref(&self) -> &[u8] {
52        self.0.as_ref()
53    }
54}
55
56impl From<SecretKey> for [u8; SecretKey::LEN] {
57    fn from(salt: SecretKey) -> [u8; SecretKey::LEN] {
58        salt.0.into()
59    }
60}
61
62impl fmt::LowerHex for SecretKey {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        self.0.fmt(f)
65    }
66}
67
68impl fmt::UpperHex for SecretKey {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        self.0.fmt(f)
71    }
72}
73
74impl fmt::Debug for SecretKey {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        self.0.fmt(f)
77    }
78}
79
80impl fmt::Display for SecretKey {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        self.0.fmt(f)
83    }
84}
85
86impl From<::k256::SecretKey> for SecretKey {
87    fn from(s: ::k256::SecretKey) -> Self {
88        let mut raw_bytes = [0u8; Self::LEN];
89        raw_bytes.copy_from_slice(&s.to_bytes());
90        Self(Bytes32::from(raw_bytes))
91    }
92}
93
94#[cfg(feature = "std")]
95impl From<::secp256k1::SecretKey> for SecretKey {
96    fn from(s: ::secp256k1::SecretKey) -> Self {
97        let mut raw_bytes = [0u8; Self::LEN];
98        raw_bytes.copy_from_slice(s.as_ref());
99        Self(Bytes32::from(raw_bytes))
100    }
101}
102
103impl From<&SecretKey> for ::k256::SecretKey {
104    fn from(sk: &SecretKey) -> Self {
105        ::k256::SecretKey::from_bytes(&(*sk.0).into())
106            .expect("SecretKey is guaranteed to be valid")
107    }
108}
109
110#[cfg(feature = "std")]
111impl From<&SecretKey> for ::secp256k1::SecretKey {
112    fn from(sk: &SecretKey) -> Self {
113        ::secp256k1::SecretKey::from_slice(sk.as_ref())
114            .expect("SecretKey is guaranteed to be valid")
115    }
116}
117
118#[cfg(all(feature = "random", feature = "test-helpers"))]
119impl Default for SecretKey {
120    /// Creates a new random secret using rand::thread_rng()
121    fn default() -> Self {
122        let mut rng = rand::thread_rng();
123        SecretKey::random(&mut rng)
124    }
125}
126
127#[cfg(feature = "std")]
128pub type W = English;
129
130impl SecretKey {
131    /// Create a new random secret
132    #[cfg(feature = "random")]
133    pub fn random(rng: &mut (impl CryptoRng + RngCore)) -> Self {
134        super::backend::k1::random_secret(rng)
135    }
136
137    /// Generate a new secret key from a mnemonic phrase and its derivation path.
138    /// Both are passed as `&str`. If you want to manually create a `DerivationPath`
139    /// and `Mnemonic`, use [`SecretKey::new_from_mnemonic`].
140    /// The derivation path is a list of integers, each representing a child index.
141    #[cfg(feature = "std")]
142    pub fn new_from_mnemonic_phrase_with_path(
143        phrase: &str,
144        path: &str,
145    ) -> Result<Self, Error> {
146        use core::str::FromStr;
147
148        let mnemonic = Mnemonic::<W>::new_from_phrase(phrase)?;
149        let path = DerivationPath::from_str(path)?;
150        Self::new_from_mnemonic(path, mnemonic)
151    }
152
153    /// Generate a new secret key from a `DerivationPath` and `Mnemonic`.
154    /// If you want to pass strings instead, use
155    /// [`SecretKey::new_from_mnemonic_phrase_with_path`].
156    #[cfg(feature = "std")]
157    pub fn new_from_mnemonic(d: DerivationPath, m: Mnemonic<W>) -> Result<Self, Error> {
158        let derived_priv_key = m.derive_key(d, None)?;
159        let key: &coins_bip32::prelude::SigningKey = derived_priv_key.as_ref();
160        let bytes: [u8; Self::LEN] = key.to_bytes().into();
161        Ok(SecretKey(Bytes32::from(bytes)))
162    }
163
164    /// Return the curve representation of this secret.
165    pub fn public_key(&self) -> PublicKey {
166        crate::secp256::backend::k1::public_key(self)
167    }
168}
169
170impl TryFrom<Bytes32> for SecretKey {
171    type Error = Error;
172
173    fn try_from(b: Bytes32) -> Result<Self, Self::Error> {
174        match k256::SecretKey::from_bytes((&*b).into()) {
175            Ok(_) => Ok(Self(b)),
176            Err(_) => Err(Error::InvalidSecretKey),
177        }
178    }
179}
180
181impl TryFrom<&[u8]> for SecretKey {
182    type Error = Error;
183
184    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
185        Bytes32::try_from(slice)
186            .map_err(|_| Error::InvalidSecretKey)
187            .and_then(SecretKey::try_from)
188    }
189}
190
191impl str::FromStr for SecretKey {
192    type Err = Error;
193
194    fn from_str(s: &str) -> Result<Self, Self::Err> {
195        Bytes32::from_str(s)
196            .map_err(|_| Error::InvalidSecretKey)
197            .and_then(SecretKey::try_from)
198    }
199}
200
201#[cfg(test)]
202#[allow(non_snake_case)]
203mod tests {
204    #[cfg(feature = "random")]
205    #[test]
206    fn default__yields_valid_secret() {
207        use super::SecretKey;
208        let _ = SecretKey::default();
209    }
210}