use crate::error::{ImportError, Result};
use rustywallet_keys::prelude::PrivateKey;
use sha2::{Sha256, Digest};
pub fn import_mini_key(mini: &str) -> Result<PrivateKey> {
let mini = mini.trim();
if !mini.starts_with('S') {
return Err(ImportError::InvalidMiniKey(
"Mini key must start with 'S'".to_string()
));
}
if mini.len() != 22 && mini.len() != 30 {
return Err(ImportError::InvalidMiniKey(format!(
"Invalid length: expected 22 or 30 characters, got {}",
mini.len()
)));
}
for c in mini.chars() {
if !is_base58_char(c) {
return Err(ImportError::InvalidMiniKey(format!(
"Invalid character: '{}'",
c
)));
}
}
let check_input = format!("{}?", mini);
let check_hash = Sha256::digest(check_input.as_bytes());
if check_hash[0] != 0x00 {
return Err(ImportError::InvalidMiniKey(
"Invalid checksum (SHA256 check failed)".to_string()
));
}
let key_hash = Sha256::digest(mini.as_bytes());
let key_bytes: [u8; 32] = key_hash.into();
PrivateKey::from_bytes(key_bytes)
.map_err(|e| ImportError::InvalidMiniKey(format!("Invalid key: {}", e)))
}
fn is_base58_char(c: char) -> bool {
matches!(c,
'1'..='9' | 'A'..='H' | 'J'..='N' | 'P'..='Z' | 'a'..='k' | 'm'..='z'
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_mini_key() {
let mini = "S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy";
let result = import_mini_key(mini);
assert!(result.is_ok());
}
#[test]
fn test_invalid_start() {
let mini = "A6c56bnXQiBjk9mqSYE7yk";
let result = import_mini_key(mini);
assert!(matches!(result, Err(ImportError::InvalidMiniKey(_))));
}
#[test]
fn test_invalid_length() {
let mini = "S6c56bnXQiBjk9mq"; let result = import_mini_key(mini);
assert!(matches!(result, Err(ImportError::InvalidMiniKey(_))));
}
#[test]
fn test_invalid_checksum() {
let mini = "S6c56bnXQiBjk9mqSYE7yA";
let result = import_mini_key(mini);
assert!(matches!(result, Err(ImportError::InvalidMiniKey(_))));
}
#[test]
fn test_invalid_character() {
let mini = "S6c56bnXQiBjk9mqSYE70l"; let result = import_mini_key(mini);
assert!(matches!(result, Err(ImportError::InvalidMiniKey(_))));
}
}