use crate::ScalarField;
use ark_ff::UniformRand;
use o1_utils::FieldHelpers;
use rand::{self, CryptoRng, RngCore};
use sha2::{Digest, Sha256};
use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum SecKeyError {
#[error("invalid secret key hex")]
SecretKeyHex,
#[error("Invalid secret key bytes")]
SecretKeyBytes,
#[error("Invalid secret key length")]
SecretKeyLength,
#[error("Invalid secret key base58")]
SecretKeyBase58,
#[error("Invalid secret key checksum")]
SecretKeyChecksum,
#[error("Invalid secret key version")]
SecretKeyVersion,
}
pub type Result<T> = std::result::Result<T, SecKeyError>;
pub const MINA_SEC_KEY_LEN: usize = 52;
#[derive(Clone, Debug, PartialEq, Eq)] pub struct SecKey(ScalarField);
impl SecKey {
pub fn rand(rng: &mut (impl RngCore + CryptoRng)) -> Self {
let secret: ScalarField = ScalarField::rand(rng);
Self(secret)
}
pub fn new(scalar: ScalarField) -> Self {
Self(scalar)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != ScalarField::size_in_bytes() {
return Err(SecKeyError::SecretKeyBytes);
}
let mut sec_bytes = vec![0u8; ScalarField::size_in_bytes()];
sec_bytes.clone_from_slice(bytes);
sec_bytes.reverse(); let secret =
ScalarField::from_bytes(&sec_bytes).map_err(|_| SecKeyError::SecretKeyBytes)?;
Ok(SecKey(secret))
}
pub fn from_hex(secret_hex: &str) -> Result<Self> {
let bytes: Vec<u8> = hex::decode(secret_hex).map_err(|_| SecKeyError::SecretKeyHex)?;
SecKey::from_bytes(&bytes)
}
pub fn from_base58(base58: &str) -> Result<Self> {
if base58.len() != MINA_SEC_KEY_LEN {
return Err(SecKeyError::SecretKeyLength);
}
let bytes = bs58::decode(base58)
.into_vec()
.map_err(|_| SecKeyError::SecretKeyBase58)?;
let (raw, checksum) = (&bytes[..bytes.len() - 4], &bytes[bytes.len() - 4..]);
let hash = Sha256::digest(&Sha256::digest(raw)[..]);
if checksum != &hash[..4] {
return Err(SecKeyError::SecretKeyChecksum);
}
let (version, scalar_bytes) = (&raw[..2], &raw[2..raw.len()]);
if version != [0x5a, 0x01] {
return Err(SecKeyError::SecretKeyVersion);
}
let mut scalar_bytes = scalar_bytes.to_vec();
scalar_bytes.reverse();
Self::from_bytes(&scalar_bytes)
}
pub fn scalar(&self) -> &ScalarField {
&self.0
}
pub fn into_scalar(self) -> ScalarField {
self.0
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.0.to_bytes();
bytes.reverse(); bytes
}
pub fn to_hex(&self) -> String {
hex::encode(self.to_bytes())
}
pub fn to_base58(&self) -> String {
let mut raw: Vec<u8> = vec![0x5a, 0x01];
let mut scalar_bytes = self.to_bytes();
scalar_bytes.reverse();
raw.extend(scalar_bytes);
let checksum = Sha256::digest(&Sha256::digest(&raw[..])[..]);
raw.extend(&checksum[..4]);
bs58::encode(raw).into_string()
}
}