mod key_parser;
mod milksad;
mod direct;
mod heuristic;
mod output;
pub use key_parser::{parse_private_key, ParseError};
pub use milksad::MilksadAnalyzer;
pub use direct::DirectAnalyzer;
pub use heuristic::HeuristicAnalyzer;
pub use output::{format_results, format_results_json};
use indicatif::ProgressBar;
pub fn calculate_bit_length(key: &[u8; 32]) -> u16 {
match key.iter().position(|&b| b != 0) {
Some(idx) => 256 - (idx as u16) * 8 - key[idx].leading_zeros() as u16,
None => 0,
}
}
#[derive(Debug, Clone)]
pub struct AnalysisResult {
pub analyzer: &'static str,
pub status: AnalysisStatus,
pub details: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AnalysisStatus {
Confirmed,
Possible,
NotFound,
Unknown,
}
#[derive(Debug, Clone, Default)]
pub struct AnalysisConfig {
pub mask_bits: Option<u8>,
}
impl AnalysisStatus {
pub fn symbol(&self) -> &'static str {
match self {
AnalysisStatus::Confirmed => "✓",
AnalysisStatus::Possible => "?",
AnalysisStatus::NotFound => "✗",
AnalysisStatus::Unknown => "?",
}
}
pub fn as_str(&self) -> &'static str {
match self {
AnalysisStatus::Confirmed => "confirmed",
AnalysisStatus::Possible => "possible",
AnalysisStatus::NotFound => "not_found",
AnalysisStatus::Unknown => "unknown",
}
}
}
pub trait Analyzer: Send + Sync {
fn name(&self) -> &'static str;
fn analyze(&self, key: &[u8; 32], config: &AnalysisConfig, progress: Option<&ProgressBar>) -> AnalysisResult;
fn supports_mask(&self) -> bool {
false
}
fn is_brute_force(&self) -> bool {
false
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum AnalyzerType {
Milksad,
Direct,
Heuristic,
}
impl AnalyzerType {
pub fn create(self) -> Box<dyn Analyzer> {
match self {
AnalyzerType::Milksad => Box::new(MilksadAnalyzer),
AnalyzerType::Direct => Box::new(DirectAnalyzer),
AnalyzerType::Heuristic => Box::new(HeuristicAnalyzer),
}
}
pub fn all() -> Vec<AnalyzerType> {
vec![
AnalyzerType::Milksad,
AnalyzerType::Direct,
AnalyzerType::Heuristic,
]
}
pub fn fast() -> Vec<AnalyzerType> {
vec![
AnalyzerType::Direct,
AnalyzerType::Heuristic,
]
}
}
#[derive(Debug, Clone)]
pub struct KeyMetadata {
pub hex: String,
pub bit_length: u16,
pub hamming_weight: u16,
pub leading_zeros: u8,
}
impl KeyMetadata {
pub fn from_key(key: &[u8; 32]) -> Self {
let hex = hex::encode(key);
let bit_length = calculate_bit_length(key);
let hamming_weight: u16 = key.iter().map(|b| b.count_ones() as u16).sum();
let leading_zeros = hex.chars().take_while(|&c| c == '0').count() as u8;
Self {
hex,
bit_length,
hamming_weight,
leading_zeros,
}
}
}