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}