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)]
15#[allow(clippy::module_name_repetitions)]
16pub enum SecKeyError {
17    /// Invalid secret key hex
18    #[error("invalid secret key hex")]
19    SecretKeyHex,
20    /// Invalid secret key bytes
21    #[error("Invalid secret key bytes")]
22    SecretKeyBytes,
23    /// Invalid secrey key length
24    #[error("Invalid secret key length")]
25    SecretKeyLength,
26    /// Invalid base58 secret key
27    #[error("Invalid secret key base58")]
28    SecretKeyBase58,
29    /// Invalid secret key checksum
30    #[error("Invalid secret key checksum")]
31    SecretKeyChecksum,
32    /// Invalid secret key version
33    #[error("Invalid secret key version")]
34    SecretKeyVersion,
35}
36/// Keypair result
37pub type Result<T> = core::result::Result<T, SecKeyError>;
38
39/// Secret key length
40pub const MINA_SEC_KEY_LEN: usize = 52;
41
42/// Secret key
43#[derive(Clone, Debug, PartialEq, Eq)] // No Debug nor Display
44pub struct SecKey(ScalarField);
45
46impl SecKey {
47    /// Generate a random secret key
48    pub fn rand(rng: &mut (impl RngCore + CryptoRng)) -> Self {
49        let secret: ScalarField = ScalarField::rand(rng);
50
51        Self(secret)
52    }
53
54    /// Create secret key from scalar field element
55    #[must_use]
56    pub const fn new(scalar: ScalarField) -> Self {
57        Self(scalar)
58    }
59
60    /// Deserialize secret key from bytes
61    ///
62    /// # Errors
63    ///
64    /// Will give error if `bytes` do not match certain requirements.
65    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(); // mina scalars hex format is in big-endian order
72        let secret =
73            ScalarField::from_bytes(&sec_bytes).map_err(|_| SecKeyError::SecretKeyBytes)?;
74        Ok(Self(secret))
75    }
76
77    /// Deserialize secret key from hex
78    ///
79    /// # Errors
80    ///
81    /// Will give error if `hex` string does not match certain requirements.
82    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    /// Deserialize base58 encoded secret key
88    ///
89    /// # Errors
90    ///
91    /// Will give error if `base58` string does not match certain requirements.
92    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    /// Borrows secret key as scalar field element
123    #[must_use]
124    pub const fn scalar(&self) -> &ScalarField {
125        &self.0
126    }
127
128    /// Convert secret key into scalar field element
129    #[must_use]
130    pub const fn into_scalar(self) -> ScalarField {
131        self.0
132    }
133
134    /// Deserialize secret key into bytes
135    #[must_use]
136    pub fn to_bytes(&self) -> Vec<u8> {
137        let mut bytes = self.0.to_bytes();
138        bytes.reverse(); // mina scalars hex format is in big-endian order
139        bytes
140    }
141
142    /// Deserialize secret key into hex
143    #[must_use]
144    pub fn to_hex(&self) -> String {
145        hex::encode(self.to_bytes())
146    }
147
148    /// Deserialize secret key into base58
149    #[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}