| | use crate::utils::Result; |
| | use base64::{Engine as _, engine::general_purpose}; |
| | use serde_json::Value; |
| | use std::time::{SystemTime, UNIX_EPOCH}; |
| |
|
| | |
| | pub struct Challenges; |
| |
|
| | impl Challenges { |
| | |
| | pub fn encode(config: &Value) -> Result<String> { |
| | let json_str = serde_json::to_string(config)?; |
| | let encoded = general_purpose::STANDARD.encode(json_str.as_bytes()); |
| | Ok(encoded) |
| | } |
| |
|
| | |
| | pub fn generate_token(mut config: Value) -> Result<String> { |
| | |
| | if let Some(config_array) = config.as_array_mut() { |
| | if config_array.len() > 3 { |
| | config_array[3] = Value::Number(serde_json::Number::from(1)); |
| | } |
| | if config_array.len() > 9 { |
| | config_array[9] = Value::Number( |
| | serde_json::Number::from_f64(0.0) |
| | .unwrap_or_else(|| serde_json::Number::from(0)), |
| | ); |
| | } |
| | } |
| |
|
| | let encoded = Self::encode(&config)?; |
| | Ok(format!("gAAAAAC{}", encoded)) |
| | } |
| |
|
| | |
| | pub fn hash_mod(input: &str) -> String { |
| | let mut hash: u32 = 2166136261; |
| |
|
| | for byte in input.bytes() { |
| | hash ^= byte as u32; |
| | hash = hash.wrapping_mul(16777619); |
| | } |
| |
|
| | hash ^= hash >> 16; |
| | hash = hash.wrapping_mul(2246822507); |
| | hash ^= hash >> 13; |
| | hash = hash.wrapping_mul(3266489909); |
| | hash ^= hash >> 16; |
| |
|
| | format!("{:08x}", hash) |
| | } |
| |
|
| | |
| | fn run_check( |
| | start_time: u128, |
| | seed: &str, |
| | difficulty: &str, |
| | nonce: i32, |
| | mut config: Value, |
| | ) -> Option<String> { |
| | let current_time = SystemTime::now() |
| | .duration_since(UNIX_EPOCH) |
| | .unwrap() |
| | .as_millis(); |
| |
|
| | |
| | if let Some(config_array) = config.as_array_mut() { |
| | if config_array.len() > 3 { |
| | config_array[3] = Value::Number(serde_json::Number::from(nonce)); |
| | } |
| | if config_array.len() > 9 { |
| | let elapsed = current_time - start_time; |
| | config_array[9] = Value::Number( |
| | serde_json::Number::from_f64(elapsed as f64) |
| | .unwrap_or(serde_json::Number::from(0)), |
| | ); |
| | } |
| | } |
| |
|
| | let encoded = Self::encode(&config).ok()?; |
| | let hash_input = format!("{}{}", seed, encoded); |
| | let hash_result = Self::hash_mod(&hash_input); |
| |
|
| | if hash_result.len() >= difficulty.len() && &hash_result[..difficulty.len()] <= difficulty { |
| | Some(format!("{}~S", encoded)) |
| | } else { |
| | None |
| | } |
| | } |
| |
|
| | |
| | pub fn solve_pow(seed: &str, difficulty: &str, config: Value) -> Result<String> { |
| | let start_time = SystemTime::now() |
| | .duration_since(UNIX_EPOCH) |
| | .unwrap() |
| | .as_millis(); |
| |
|
| | for nonce in 0..500_000 { |
| | if let Some(solution) = |
| | Self::run_check(start_time, seed, difficulty, nonce, config.clone()) |
| | { |
| | return Ok(format!("gAAAAAB{}", solution)); |
| | } |
| | } |
| |
|
| | Err(crate::utils::ChatGptError::challenge_solve( |
| | "Failed to solve proof-of-work within iteration limit", |
| | )) |
| | } |
| | } |
| |
|