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 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 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 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 if status == 0 {
100 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 Some(value)
116 }
117 };
118
119 stack_func.call(&mut self.store, 16)?;
120 Ok(result)
121 }
122}
123
124pub fn deepseek_hash_v1(data: &[u8]) -> Vec<u8> {
126 match WasmInstance::new() {
128 Ok(mut instance) => {
129 let data_str = hex::encode(data);
131
132 match instance.calculate_hash(&data_str, "", 1.0) {
134 Ok(Some(result)) => {
135 let mut hash = vec![0u8; 32];
137 let result_bytes = result.to_le_bytes();
138 hash[..8].copy_from_slice(&result_bytes);
139
140 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 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 let mut hasher = sha3::Sha3_256::new();
158 use sha3::Digest;
159 hasher.update(data);
160 hasher.finalize().to_vec()
161 }
162 }
163}
164
165pub fn solve(challenge: &[u8], prefix: &[u8], target_difficulty: f64) -> (bool, f64) {
167 let challenge_str = hex::encode(challenge);
171 let prefix_str = String::from_utf8_lossy(prefix);
172
173 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 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 let hash = deepseek_hash_v1(b"");
203 println!("Hash of empty: {:02x?}", hash);
204 assert_eq!(hash.len(), 32); let hash = deepseek_hash_v1(b"abc");
208 println!("Hash of 'abc': {:02x?}", hash);
209 assert_eq!(hash.len(), 32);
210
211 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; 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}