1
0
Fork 0
mirror of https://github.com/TransparentLC/opencl_vanity_gpg.git synced 2025-10-20 15:24:08 +00:00
opencl_vanity_gpg/src/utils/pattern.rs
2025-01-09 03:26:48 +08:00

124 lines
4 KiB
Rust

use std::{collections::HashMap, str::FromStr};
use anyhow::bail;
#[derive(Debug, Clone)]
pub struct HashPattern {
pub pattern: String,
pub filter: String,
pub possibliity: f64,
}
impl HashPattern {
pub fn is_match(&self, hash: &[u8]) -> bool {
if hash.len() != 20 {
return false;
}
let hash_str = hex::encode_upper(hash);
for (i, c) in self.pattern.chars().enumerate() {
if c.is_ascii_hexdigit() && c != hash_str.chars().nth(i).unwrap() {
return false;
}
}
let mut map = HashMap::new();
for (pos, c) in self.pattern.chars().enumerate() {
if ('G'..='Z').contains(&c) {
let hash_char = hash_str.chars().nth(pos).unwrap();
let expect = map.entry(c).or_insert(hash_char);
if *expect != hash_char {
return false;
}
}
}
true
}
}
impl FromStr for HashPattern {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let pattern = match s.trim().replace(' ', "").to_ascii_uppercase() {
x if x.len() <= 40 => "*".repeat(40 - x.len()) + &x,
_ => bail!("Invalid pattern: {}", s),
};
let mut parts: Vec<String> = vec![];
// Handle fixed 0-9A-F
let mut fixed_pos_count: usize = 0;
for i in 0..=4 {
let mut mask = String::new();
let mut value = String::new();
let mut activated = false;
for j in 0..8 {
let char = *pattern.chars().nth(i * 8 + j).get_or_insert(' ');
if char.is_ascii_hexdigit() {
fixed_pos_count += 1;
mask += "F";
value += &String::from(char);
activated = true;
} else {
mask += "0";
value += "0";
}
}
if activated {
parts.push(format!("(h[{i}] & 0x{mask}) == 0x{value}"));
}
}
// Handle wildcard G-Z
let mut wildcard_pos_all: [Vec<usize>; (b'Z' - b'G' + 1) as usize] =
std::default::Default::default();
for (i, wildcard) in pattern.chars().enumerate() {
if ('G'..='Z').contains(&wildcard) {
wildcard_pos_all[((wildcard as u8) - b'G') as usize].push(i);
}
}
let mut wildcard_pos_count = 0;
for wildcard in 'G'..='Z' {
let wildcard_pos = &wildcard_pos_all[((wildcard as u8) - b'G') as usize];
if wildcard_pos.len() >= 2 {
for i in 1..wildcard_pos.len() {
let left_index = wildcard_pos[i - 1] / 8;
let right_index = wildcard_pos[i] / 8;
let left_digit = 7 - wildcard_pos[i - 1] % 8;
let right_digit = 7 - wildcard_pos[i] % 8;
parts.push(format!(
"(/* {}: h[{}][{}] == h[{}][{}] */ (h[{}] {} {}) & 0xF{}) == (h[{}] & 0xF{})",
wildcard,
left_index,
left_digit,
right_index,
right_digit,
left_index,
if right_digit > left_digit { "<<" } else { ">>" },
right_digit.abs_diff(left_digit) * 4,
"0".repeat(right_digit),
right_index,
"0".repeat(right_digit),
));
}
wildcard_pos_count += wildcard_pos.len() - 1;
}
}
let filter = if !parts.is_empty() {
parts.join(" && ")
} else {
String::from("true")
};
Ok(HashPattern {
pattern,
filter,
possibliity: (16f64).powi((fixed_pos_count + wildcard_pos_count) as i32),
})
}
}