mina_node_account/
secret_key.rs

1use super::AccountPublicKey;
2use mina_core::{
3    constants::GENESIS_PRODUCER_SK, EncryptedSecretKey, EncryptedSecretKeyFile, EncryptionError,
4};
5use mina_p2p_messages::{bigint::BigInt, v2::SignatureLibPrivateKeyStableV1};
6use mina_signer::{keypair::KeypairError, seckey::SecKeyError, CompressedPubKey, Keypair};
7use rand::{rngs::StdRng, CryptoRng, Rng, SeedableRng};
8use serde::{Deserialize, Serialize};
9use std::{fmt, fs, io, path::Path, str::FromStr};
10
11#[derive(Clone)]
12pub struct AccountSecretKey(Keypair);
13
14impl std::fmt::Debug for AccountSecretKey {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        f.debug_tuple("AccountSecretKey").field(&"***").finish()
17    }
18}
19
20lazy_static::lazy_static! {
21    // TODO(binier): better way.
22    static ref GENERATED_DETERMINISTIC: Vec<AccountSecretKey> = {
23        let mut rng = StdRng::seed_from_u64(0);
24        (0..10000)
25            .map(|_| AccountSecretKey::rand_with(&mut rng))
26            .collect()
27    };
28}
29
30impl AccountSecretKey {
31    const BASE58_CHECK_VERSION: u8 = 90;
32
33    pub fn genesis_producer() -> Self {
34        Self::from_str(GENESIS_PRODUCER_SK).unwrap()
35    }
36
37    pub fn deterministic(i: u64) -> Self {
38        GENERATED_DETERMINISTIC[i as usize].clone()
39    }
40
41    pub fn deterministic_iter() -> impl Iterator<Item = &'static AccountSecretKey> {
42        GENERATED_DETERMINISTIC.iter()
43    }
44
45    pub fn max_deterministic_count() -> usize {
46        GENERATED_DETERMINISTIC.len()
47    }
48
49    pub fn rand() -> Self {
50        Self::rand_with(rand::thread_rng())
51    }
52
53    pub fn rand_with(mut rng: impl Rng + CryptoRng) -> Self {
54        Self(Keypair::rand(&mut rng).unwrap())
55    }
56
57    pub fn from_bytes(bytes: &[u8]) -> Result<Self, KeypairError> {
58        let mut bytes: [u8; 32] = match bytes.try_into() {
59            Ok(bytes) => bytes,
60            Err(_) => return Err(KeypairError::SecretKey(SecKeyError::SecretKeyLength)),
61        };
62
63        // For some reason, `mina_signer::SecKey::from_bytes` reverse the bytes
64        bytes.reverse();
65
66        Ok(Self(Keypair::from_bytes(&bytes[..])?))
67    }
68
69    pub fn to_bytes(&self) -> [u8; 32] {
70        // TODO(binier): refactor
71        let mut bytes = hex::decode(self.0.to_hex()).unwrap();
72        bytes.reverse();
73        bytes.try_into().unwrap()
74    }
75
76    pub fn public_key(&self) -> AccountPublicKey {
77        self.0.public.clone().into()
78    }
79
80    pub fn public_key_compressed(&self) -> CompressedPubKey {
81        self.0.public.clone().into_compressed()
82    }
83
84    pub fn from_encrypted_file(
85        path: impl AsRef<Path>,
86        password: &str,
87    ) -> Result<Self, EncryptionError> {
88        Self::from_encrypted_reader(fs::File::open(path)?, password)
89    }
90
91    pub fn from_encrypted_reader(
92        reader: impl io::Read,
93        password: &str,
94    ) -> Result<Self, EncryptionError> {
95        let encrypted: EncryptedSecretKeyFile = serde_json::from_reader(reader)?;
96        Self::from_encrypted(&encrypted, password)
97    }
98
99    pub fn from_encrypted(
100        encrypted: &EncryptedSecretKeyFile,
101        password: &str,
102    ) -> Result<Self, EncryptionError> {
103        let decrypted: Vec<u8> = Self::try_decrypt(encrypted, password)?;
104        AccountSecretKey::from_bytes(&decrypted[1..])
105            .map_err(|err| EncryptionError::Other(err.to_string()))
106    }
107
108    pub fn to_encrypted_file(
109        &self,
110        path: impl AsRef<Path>,
111        password: &str,
112    ) -> Result<(), EncryptionError> {
113        if path.as_ref().exists() {
114            panic!("File {} already exists", path.as_ref().display())
115        }
116
117        let f = fs::File::create(path)?;
118        let encrypted = Self::try_encrypt(&self.to_bytes(), password)?;
119
120        serde_json::to_writer(f, &encrypted)?;
121        Ok(())
122    }
123}
124
125impl EncryptedSecretKey for AccountSecretKey {}
126
127impl From<AccountSecretKey> for Keypair {
128    fn from(value: AccountSecretKey) -> Self {
129        value.0
130    }
131}
132
133impl From<&AccountSecretKey> for SignatureLibPrivateKeyStableV1 {
134    fn from(value: &AccountSecretKey) -> Self {
135        Self(BigInt::from_bytes(value.to_bytes()))
136    }
137}
138
139impl From<AccountSecretKey> for SignatureLibPrivateKeyStableV1 {
140    fn from(value: AccountSecretKey) -> Self {
141        Self(BigInt::from_bytes(value.to_bytes()))
142    }
143}
144
145impl FromStr for AccountSecretKey {
146    type Err = anyhow::Error;
147
148    fn from_str(s: &str) -> Result<Self, Self::Err> {
149        let mut bytes = [0u8; 38];
150
151        let size = bs58::decode(s)
152            .with_check(Some(Self::BASE58_CHECK_VERSION))
153            .into(&mut bytes)?;
154        if size != 34 {
155            return Err(bs58::decode::Error::BufferTooSmall.into());
156        }
157
158        Ok(Self::from_bytes(&bytes[2..34])?)
159    }
160}
161
162impl fmt::Display for AccountSecretKey {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        // TODO: implement to_bytes for Keypair, and remove this ugly workaround
165        let hex = self.0.to_hex();
166        let mut bytes = hex::decode(hex).expect("to_hex should return hex string");
167        bytes.reverse();
168        bytes.insert(0, 1);
169        let s = bs58::encode(&bytes)
170            .with_check_version(Self::BASE58_CHECK_VERSION)
171            .into_string();
172        f.write_str(&s)
173    }
174}
175
176impl Serialize for AccountSecretKey {
177    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
178    where
179        S: serde::Serializer,
180    {
181        serializer.serialize_str(&self.to_string())
182    }
183}
184
185impl<'de> serde::Deserialize<'de> for AccountSecretKey {
186    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
187    where
188        D: serde::Deserializer<'de>,
189    {
190        let b58: String = Deserialize::deserialize(deserializer)?;
191        b58.parse().map_err(serde::de::Error::custom)
192    }
193}