mina_signer/
seckey.rs

1//! Secret key structures and helpers
2
3extern crate alloc;
4use crate::ScalarField;
5use alloc::{string::String, vec, vec::Vec};
6use ark_ff::UniformRand;
7use o1_utils::FieldHelpers;
8use rand::{self, CryptoRng, RngCore};
9use sha2::{Digest, Sha256};
10use thiserror::Error;
11
12/// Keypair error
13#[derive(Error, Debug, Clone, PartialEq, Eq)]
14pub enum SecKeyError {
15    /// Invalid secret key hex
16    #[error("invalid secret key hex")]
17    SecretKeyHex,
18    /// Invalid secret key bytes
19    #[error("Invalid secret key bytes")]
20    SecretKeyBytes,
21    /// Invalid secrey key length
22    #[error("Invalid secret key length")]
23    SecretKeyLength,
24    /// Invalid base58 secret key
25    #[error("Invalid secret key base58")]
26    SecretKeyBase58,
27    /// Invalid secret key checksum
28    #[error("Invalid secret key checksum")]
29    SecretKeyChecksum,
30    /// Invalid secret key version
31    #[error("Invalid secret key version")]
32    SecretKeyVersion,
33}
34/// Keypair result
35pub type Result<T> = core::result::Result<T, SecKeyError>;
36
37/// Secret key length
38pub const MINA_SEC_KEY_LEN: usize = 52;
39
40/// Secret key
41#[derive(Clone, Debug, PartialEq, Eq)] // No Debug nor Display
42pub struct SecKey(ScalarField);
43
44impl SecKey {
45    /// Generate a random secret key
46    pub fn rand(rng: &mut (impl RngCore + CryptoRng)) -> Self {
47        let secret: ScalarField = ScalarField::rand(rng);
48
49        Self(secret)
50    }
51
52    /// Create secret key from scalar field element
53    pub fn new(scalar: ScalarField) -> Self {
54        Self(scalar)
55    }
56
57    /// Deserialize secret key from bytes
58    ///
59    /// # Errors
60    ///
61    /// Will give error if `bytes` do not match certain requirements.
62    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
63        if bytes.len() != ScalarField::size_in_bytes() {
64            return Err(SecKeyError::SecretKeyBytes);
65        }
66        let mut sec_bytes = vec![0u8; ScalarField::size_in_bytes()];
67        sec_bytes.clone_from_slice(bytes);
68        sec_bytes.reverse(); // mina scalars hex format is in big-endian order
69        let secret =
70            ScalarField::from_bytes(&sec_bytes).map_err(|_| SecKeyError::SecretKeyBytes)?;
71        Ok(SecKey(secret))
72    }
73
74    /// Deserialize secret key from hex
75    ///
76    /// # Errors
77    ///
78    /// Will give error if `hex` string does not match certain requirements.
79    pub fn from_hex(secret_hex: &str) -> Result<Self> {
80        let bytes: Vec<u8> = hex::decode(secret_hex).map_err(|_| SecKeyError::SecretKeyHex)?;
81        SecKey::from_bytes(&bytes)
82    }
83
84    /// Deserialize base58 encoded secret key
85    ///
86    /// # Errors
87    ///
88    /// Will give error if `base58` string does not match certain requirements.
89    pub fn from_base58(base58: &str) -> Result<Self> {
90        if base58.len() != MINA_SEC_KEY_LEN {
91            return Err(SecKeyError::SecretKeyLength);
92        }
93
94        let bytes = bs58::decode(base58)
95            .into_vec()
96            .map_err(|_| SecKeyError::SecretKeyBase58)?;
97
98        let (raw, checksum) = (&bytes[..bytes.len() - 4], &bytes[bytes.len() - 4..]);
99
100        let hash = Sha256::digest(&Sha256::digest(raw)[..]);
101
102        if checksum != &hash[..4] {
103            return Err(SecKeyError::SecretKeyChecksum);
104        }
105
106        let (version, scalar_bytes) = (&raw[..2], &raw[2..raw.len()]);
107
108        if version != [0x5a, 0x01] {
109            return Err(SecKeyError::SecretKeyVersion);
110        }
111
112        let mut scalar_bytes = scalar_bytes.to_vec();
113
114        scalar_bytes.reverse();
115
116        Self::from_bytes(&scalar_bytes)
117    }
118
119    /// Borrows secret key as scalar field element
120    pub fn scalar(&self) -> &ScalarField {
121        &self.0
122    }
123
124    /// Convert secret key into scalar field element
125    pub fn into_scalar(self) -> ScalarField {
126        self.0
127    }
128
129    /// Deserialize secret key into bytes
130    pub fn to_bytes(&self) -> Vec<u8> {
131        let mut bytes = self.0.to_bytes();
132        bytes.reverse(); // mina scalars hex format is in big-endian order
133        bytes
134    }
135
136    /// Deserialize secret key into hex
137    pub fn to_hex(&self) -> String {
138        hex::encode(self.to_bytes())
139    }
140
141    /// Deserialize secret key into base58
142    pub fn to_base58(&self) -> String {
143        let mut raw: Vec<u8> = vec![0x5a, 0x01];
144
145        let mut scalar_bytes = self.to_bytes();
146        scalar_bytes.reverse();
147
148        raw.extend(scalar_bytes);
149
150        let checksum = Sha256::digest(&Sha256::digest(&raw[..])[..]);
151        raw.extend(&checksum[..4]);
152
153        bs58::encode(raw).into_string()
154    }
155}