File size: 3,558 Bytes
94c29e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::utils::Result;
use base64::{Engine as _, engine::general_purpose};
use serde_json::Value;
use std::time::{SystemTime, UNIX_EPOCH};

/// Challenge solver for proof-of-work and token generation
pub struct Challenges;

impl Challenges {
    /// Encode configuration to base64 JSON
    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)
    }

    /// Generate token from configuration
    pub fn generate_token(mut config: Value) -> Result<String> {
        // Update config values
        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))
    }

    /// Hash function similar to Python's mod function
    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)
    }

    /// Check if solution is valid
    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();

        // Update config
        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
        }
    }

    /// Solve proof-of-work challenge
    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",
        ))
    }
}