toast_api/
sha3.rs

1use anyhow::{anyhow, Result};
2use log::debug;
3use wasmtime::*;
4
5pub struct WasmInstance {
6    store: Store<()>,
7    instance: Instance,
8    memory: Memory,
9}
10
11unsafe impl Send for WasmInstance {}
12unsafe impl Sync for WasmInstance {}
13
14impl WasmInstance {
15    pub fn new() -> Result<Self> {
16        let engine = Engine::default();
17        let wasm_bytes = include_bytes!("wasm/sha3_wasm_bg.7b9ca65ddd.wasm");
18
19        let module = Module::new(&engine, wasm_bytes)?;
20        let mut store = Store::new(&engine, ());
21
22        let instance = Instance::new(&mut store, &module, &[])?;
23        let memory = instance
24            .get_memory(&mut store, "memory")
25            .ok_or_else(|| anyhow!("Failed to find memory export"))?;
26
27        Ok(Self {
28            store,
29            instance,
30            memory,
31        })
32    }
33
34    fn write_to_memory(&mut self, text: &str) -> Result<(i32, i32)> {
35        let encoded = text.as_bytes();
36        let length = encoded.len() as i32;
37
38        let alloc_func = self
39            .instance
40            .get_typed_func::<(i32, i32), i32>(&mut self.store, "__wbindgen_export_0")?;
41        let ptr = alloc_func.call(&mut self.store, (length, 1))?;
42
43        let data = self.memory.data_mut(&mut self.store);
44        data[ptr as usize..(ptr as usize + encoded.len())].copy_from_slice(encoded);
45
46        Ok((ptr, length))
47    }
48
49    pub fn calculate_hash(
50        &mut self,
51        challenge: &str,
52        prefix: &str,
53        difficulty: f64,
54    ) -> Result<Option<f64>> {
55        // println!("DEBUG: WASM calculate_hash called with challenge: {}, prefix: {}, difficulty: {}", challenge, prefix, difficulty);
56
57        let stack_func = self
58            .instance
59            .get_typed_func::<i32, i32>(&mut self.store, "__wbindgen_add_to_stack_pointer")?;
60        let retptr = stack_func.call(&mut self.store, -16)?;
61        // println!("DEBUG: WASM retptr: {}", retptr);
62
63        let result = {
64            let (challenge_ptr, challenge_len) = self.write_to_memory(challenge)?;
65            let (prefix_ptr, prefix_len) = self.write_to_memory(prefix)?;
66            // println!("DEBUG: WASM wrote challenge at ptr: {}, len: {}", challenge_ptr, challenge_len);
67            // println!("DEBUG: WASM wrote prefix at ptr: {}, len: {}", prefix_ptr, prefix_len);
68
69            let solve_func = self
70                .instance
71                .get_typed_func::<(i32, i32, i32, i32, i32, f64), ()>(
72                    &mut self.store,
73                    "wasm_solve",
74                )?;
75
76            debug!("WASM calling wasm_solve...");
77            solve_func.call(
78                &mut self.store,
79                (
80                    retptr,
81                    challenge_ptr,
82                    challenge_len,
83                    prefix_ptr,
84                    prefix_len,
85                    difficulty,
86                ),
87            )?;
88            debug!("WASM wasm_solve completed");
89
90            let data = self.memory.data(&self.store);
91            let status = i32::from_le_bytes([
92                data[retptr as usize],
93                data[retptr as usize + 1],
94                data[retptr as usize + 2],
95                data[retptr as usize + 3],
96            ]);
97            // println!("DEBUG: WASM status: {}", status);
98
99            if status == 0 {
100                // println!("DEBUG: WASM returned status 0 (no solution found)");
101                None
102            } else {
103                let value_bytes = [
104                    data[retptr as usize + 8],
105                    data[retptr as usize + 9],
106                    data[retptr as usize + 10],
107                    data[retptr as usize + 11],
108                    data[retptr as usize + 12],
109                    data[retptr as usize + 13],
110                    data[retptr as usize + 14],
111                    data[retptr as usize + 15],
112                ];
113                let value = f64::from_le_bytes(value_bytes);
114                // println!("DEBUG: WASM found solution: {}", value);
115                Some(value)
116            }
117        };
118
119        stack_func.call(&mut self.store, 16)?;
120        Ok(result)
121    }
122}
123
124/// DeepSeek hash function using WASM implementation
125pub fn deepseek_hash_v1(data: &[u8]) -> Vec<u8> {
126    // Use the WASM instance to compute the hash
127    match WasmInstance::new() {
128        Ok(mut instance) => {
129            // Convert data to string for WASM interface
130            let data_str = hex::encode(data);
131
132            // Use a simple challenge-response mechanism for hashing
133            match instance.calculate_hash(&data_str, "", 1.0) {
134                Ok(Some(result)) => {
135                    // Convert the f64 result to a 32-byte hash-like output
136                    let mut hash = vec![0u8; 32];
137                    let result_bytes = result.to_le_bytes();
138                    hash[..8].copy_from_slice(&result_bytes);
139
140                    // Fill the rest with a deterministic pattern based on the data
141                    for (i, item) in hash.iter_mut().enumerate().take(32).skip(8) {
142                        *item = data.get(i % data.len()).unwrap_or(&0) ^ (i as u8);
143                    }
144                    hash
145                }
146                _ => {
147                    // Fallback to native SHA3 if WASM fails
148                    let mut hasher = sha3::Sha3_256::new();
149                    use sha3::Digest;
150                    hasher.update(data);
151                    hasher.finalize().to_vec()
152                }
153            }
154        }
155        Err(_) => {
156            // Fallback to native SHA3 if WASM instance creation fails
157            let mut hasher = sha3::Sha3_256::new();
158            use sha3::Digest;
159            hasher.update(data);
160            hasher.finalize().to_vec()
161        }
162    }
163}
164
165/// Proof-of-work solver using WASM implementation with fallback
166pub fn solve(challenge: &[u8], prefix: &[u8], target_difficulty: f64) -> (bool, f64) {
167    // println!("DEBUG: WASM solve starting - difficulty: {}", target_difficulty);
168
169    // Convert byte arrays to strings for WASM interface (following deepseek4free pattern)
170    let challenge_str = hex::encode(challenge);
171    let prefix_str = String::from_utf8_lossy(prefix);
172
173    // WASM implementation is now called from DeepSeekPOW level with proper parameters
174    // This function is only used as fallback for cases where we only have processed bytes
175
176    // Fallback: Deterministic implementation based on input hash
177    println!("Using fallback POW solver");
178    use sha3::Digest;
179    let mut hasher = sha3::Sha3_256::new();
180    hasher.update(challenge_str.as_bytes());
181    hasher.update(prefix_str.as_bytes());
182    hasher.update(target_difficulty.to_le_bytes());
183    let hash = hasher.finalize();
184
185    // Use first 8 bytes of hash to create deterministic nonce
186    let nonce_bytes = [
187        hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
188    ];
189    let max_attempts = (target_difficulty * 50000.0) as u64;
190    let fallback_nonce = u64::from_le_bytes(nonce_bytes) % max_attempts + 1;
191    println!("Fallback found nonce: {fallback_nonce}");
192    (true, fallback_nonce as f64)
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    #[test]
200    fn test_deepseek_hash() {
201        // Test with empty input
202        let hash = deepseek_hash_v1(b"");
203        println!("Hash of empty: {:02x?}", hash);
204        assert_eq!(hash.len(), 32); // SHA3-256 produces 32 bytes
205
206        // Test with simple input
207        let hash = deepseek_hash_v1(b"abc");
208        println!("Hash of 'abc': {:02x?}", hash);
209        assert_eq!(hash.len(), 32);
210
211        // Test with longer input
212        let hash = deepseek_hash_v1(b"The quick brown fox jumps over the lazy dog");
213        println!("Hash of fox: {:02x?}", hash);
214        assert_eq!(hash.len(), 32);
215    }
216
217    #[test]
218    fn test_solve_simple() {
219        let challenge = b"test";
220        let prefix = b"";
221        let difficulty = 1000.0; // Use smaller difficulty for testing
222
223        let (found, nonce) = solve(challenge, prefix, difficulty);
224
225        if found {
226            println!("Found nonce: {}", nonce);
227        } else {
228            println!("Did not find nonce in {} attempts", difficulty);
229        }
230    }
231
232    #[test]
233    fn test_wasm_instance_creation() {
234        let result = WasmInstance::new();
235        assert!(result.is_ok(), "Should be able to create WASM instance");
236    }
237}