Skip to main content

mina_signer/
keypair.rs

1//! Keypair structures and algorithms
2//!
3//! Definition of secret key, keypairs and related helpers
4
5extern crate alloc;
6
7use crate::{pubkey::PubKeyError, seckey::SecKeyError, CurvePoint, PubKey, ScalarField, SecKey};
8use alloc::{string::String, vec::Vec};
9use core::{convert::TryFrom, fmt};
10use rand::{self, CryptoRng, RngCore};
11use thiserror::Error;
12
13/// Keypair error
14#[derive(Error, Debug, Clone, PartialEq, Eq)]
15pub enum KeypairError {
16    /// Invalid secret key
17    #[error(transparent)]
18    SecretKey(#[from] SecKeyError),
19    /// Public key error
20    #[error(transparent)]
21    PublicKey(#[from] PubKeyError),
22    /// point not on curve
23    #[error("point not on curve")]
24    NonCurvePoint,
25}
26/// Keypair result
27pub type Result<T> = core::result::Result<T, KeypairError>;
28
29/// Keypair structure
30///
31/// The secret key is intentionally private to prevent accidental exposure
32/// through logging or serialization. Use [`secret_key()`](Self::secret_key)
33/// to access it when needed.
34#[derive(Clone, PartialEq, Eq)]
35pub struct Keypair {
36    /// Secret key (private to prevent accidental exposure)
37    secret: SecKey,
38    /// Public key
39    pub public: PubKey,
40}
41
42impl Keypair {
43    /// Create keypair from scalar field `secret` element and curve point `public`
44    /// Note: Does not check point `public` is on curve
45    #[must_use]
46    pub const fn from_parts_unsafe(secret: ScalarField, public: CurvePoint) -> Self {
47        Self {
48            secret: SecKey::new(secret),
49            public: PubKey::from_point_unsafe(public),
50        }
51    }
52
53    /// Returns a reference to the secret key.
54    ///
55    /// # Security
56    ///
57    /// Handle the returned secret key with care. Avoid logging, printing,
58    /// or transmitting it unless absolutely necessary for cryptographic
59    /// operations.
60    #[must_use]
61    pub const fn secret_key(&self) -> &SecKey {
62        &self.secret
63    }
64
65    /// Create keypair from secret key
66    ///
67    /// # Errors
68    ///
69    /// Returns [`KeypairError`] if the public key cannot be derived from
70    /// the secret key.
71    ///
72    /// # Deprecated
73    ///
74    /// Use [`Keypair::try_from`] instead for idiomatic Rust conversions.
75    /// This method will be removed in version 0.5.0.
76    #[deprecated(
77        since = "0.4.0",
78        note = "use `Keypair::try_from(secret_key)` instead; will be removed in 0.5.0"
79    )]
80    pub fn from_secret_key(secret_key: SecKey) -> Result<Self> {
81        Self::from_secret_key_impl(secret_key)
82    }
83
84    /// Internal implementation of keypair creation from secret key.
85    /// Used by both `TryFrom` impl and the deprecated `from_secret_key`.
86    fn from_secret_key_impl(secret_key: SecKey) -> Result<Self> {
87        let public = PubKey::from_secret_key(&secret_key)?;
88
89        // Safe now because PubKey::from_secret_key() checked point is on the curve
90        Ok(Self::from_parts_unsafe(
91            secret_key.into_scalar(),
92            public.into_point(),
93        ))
94    }
95
96    /// Generate random keypair
97    ///
98    /// # Errors
99    ///
100    /// Returns [`KeypairError`] if the generated secret key produces an
101    /// invalid public key.
102    pub fn rand(rng: &mut (impl RngCore + CryptoRng)) -> Result<Self> {
103        let sec_key: SecKey = SecKey::rand(rng);
104        Self::from_secret_key_impl(sec_key)
105    }
106
107    /// Deserialize keypair from secret key bytes
108    ///
109    /// # Errors
110    ///
111    /// Will give error if `bytes` do not match certain requirements.
112    pub fn from_bytes(secret_bytes: &[u8]) -> Result<Self> {
113        let secret = SecKey::from_bytes(secret_bytes)?;
114        Self::from_secret_key_impl(secret)
115    }
116
117    /// Deserialize keypair from secret key hex
118    ///
119    /// # Errors
120    ///
121    /// Will give error if `hex` string does not match certain requirements.
122    pub fn from_hex(secret_hex: &str) -> Result<Self> {
123        let secret = SecKey::from_hex(secret_hex)?;
124        Self::from_secret_key_impl(secret)
125    }
126
127    /// Obtain the Mina address corresponding to the keypair's public key
128    #[must_use]
129    pub fn get_address(self) -> String {
130        self.public.into_address()
131    }
132
133    /// Deserialize keypair into bytes
134    #[must_use]
135    pub fn to_bytes(&self) -> Vec<u8> {
136        self.secret.to_bytes()
137    }
138
139    /// Deserialize keypair into hex
140    #[must_use]
141    pub fn to_hex(&self) -> String {
142        hex::encode(self.to_bytes())
143    }
144}
145
146impl TryFrom<SecKey> for Keypair {
147    type Error = KeypairError;
148
149    /// Create a keypair from a secret key.
150    ///
151    /// This is the idiomatic way to convert a [`SecKey`] into a [`Keypair`].
152    /// It derives the corresponding public key from the secret key.
153    ///
154    /// # Errors
155    ///
156    /// Returns [`KeypairError::PublicKey`] if the secret key is zero or
157    /// the derived point is not on the curve.
158    ///
159    /// # Example
160    ///
161    /// ```
162    /// use std::convert::TryFrom;
163    /// use mina_signer::{Keypair, SecKey};
164    ///
165    /// let secret = SecKey::from_hex(
166    ///     "164244176fddb5d769b7de2027469d027ad428fadcc0c02396e6280142efb718"
167    /// ).unwrap();
168    /// let keypair = Keypair::try_from(secret).unwrap();
169    /// ```
170    fn try_from(secret_key: SecKey) -> Result<Self> {
171        Self::from_secret_key_impl(secret_key)
172    }
173}
174
175impl fmt::Debug for Keypair {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        // Omit the secret key for security
178        write!(f, "{:?}", self.public)
179    }
180}
181
182impl fmt::Display for Keypair {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        // Omit the secret key for security
185        write!(f, "{}", self.public)
186    }
187}