1extern crate alloc;
4
5use crate::ScalarField;
6use alloc::{string::String, vec, vec::Vec};
7use ark_ff::UniformRand;
8use o1_utils::FieldHelpers;
9use rand::{self, CryptoRng, RngCore};
10use sha2::{Digest, Sha256};
11use thiserror::Error;
12
13#[derive(Error, Debug, Clone, PartialEq, Eq)]
15#[allow(clippy::module_name_repetitions)]
16pub enum SecKeyError {
17 #[error("invalid secret key hex")]
19 SecretKeyHex,
20 #[error("Invalid secret key bytes")]
22 SecretKeyBytes,
23 #[error("Invalid secret key length")]
25 SecretKeyLength,
26 #[error("Invalid secret key base58")]
28 SecretKeyBase58,
29 #[error("Invalid secret key checksum")]
31 SecretKeyChecksum,
32 #[error("Invalid secret key version")]
34 SecretKeyVersion,
35}
36pub type Result<T> = core::result::Result<T, SecKeyError>;
38
39pub const MINA_SEC_KEY_LEN: usize = 52;
41
42#[derive(Clone, Debug, PartialEq, Eq)] pub struct SecKey(ScalarField);
45
46impl SecKey {
47 pub fn rand(rng: &mut (impl RngCore + CryptoRng)) -> Self {
49 let secret: ScalarField = ScalarField::rand(rng);
50
51 Self(secret)
52 }
53
54 #[must_use]
56 pub const fn new(scalar: ScalarField) -> Self {
57 Self(scalar)
58 }
59
60 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
66 if bytes.len() != ScalarField::size_in_bytes() {
67 return Err(SecKeyError::SecretKeyBytes);
68 }
69 let mut sec_bytes = vec![0u8; ScalarField::size_in_bytes()];
70 sec_bytes.clone_from_slice(bytes);
71 sec_bytes.reverse(); let secret =
73 ScalarField::from_bytes(&sec_bytes).map_err(|_| SecKeyError::SecretKeyBytes)?;
74 Ok(Self(secret))
75 }
76
77 pub fn from_hex(secret_hex: &str) -> Result<Self> {
83 let bytes: Vec<u8> = hex::decode(secret_hex).map_err(|_| SecKeyError::SecretKeyHex)?;
84 Self::from_bytes(&bytes)
85 }
86
87 pub fn from_base58(base58: &str) -> Result<Self> {
93 if base58.len() != MINA_SEC_KEY_LEN {
94 return Err(SecKeyError::SecretKeyLength);
95 }
96
97 let bytes = bs58::decode(base58)
98 .into_vec()
99 .map_err(|_| SecKeyError::SecretKeyBase58)?;
100
101 let (raw, checksum) = (&bytes[..bytes.len() - 4], &bytes[bytes.len() - 4..]);
102
103 let hash = Sha256::digest(&Sha256::digest(raw)[..]);
104
105 if checksum != &hash[..4] {
106 return Err(SecKeyError::SecretKeyChecksum);
107 }
108
109 let (version, scalar_bytes) = (&raw[..2], &raw[2..raw.len()]);
110
111 if version != [0x5a, 0x01] {
112 return Err(SecKeyError::SecretKeyVersion);
113 }
114
115 let mut scalar_bytes = scalar_bytes.to_vec();
116
117 scalar_bytes.reverse();
118
119 Self::from_bytes(&scalar_bytes)
120 }
121
122 #[must_use]
124 pub const fn scalar(&self) -> &ScalarField {
125 &self.0
126 }
127
128 #[must_use]
130 pub const fn into_scalar(self) -> ScalarField {
131 self.0
132 }
133
134 #[must_use]
136 pub fn to_bytes(&self) -> Vec<u8> {
137 let mut bytes = self.0.to_bytes();
138 bytes.reverse(); bytes
140 }
141
142 #[must_use]
144 pub fn to_hex(&self) -> String {
145 hex::encode(self.to_bytes())
146 }
147
148 #[must_use]
150 pub fn to_base58(&self) -> String {
151 let mut raw: Vec<u8> = vec![0x5a, 0x01];
152
153 let mut scalar_bytes = self.to_bytes();
154 scalar_bytes.reverse();
155
156 raw.extend(scalar_bytes);
157
158 let checksum = Sha256::digest(&Sha256::digest(&raw[..])[..]);
159 raw.extend(&checksum[..4]);
160
161 bs58::encode(raw).into_string()
162 }
163}