Skip to main content

mina_signer/
seckey.rs

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