""" DeepSeek PoW - 直接调用 WASM 文件 依赖: pip install wasmtime 用法: python deepseek_wasm.py """ import struct import time import urllib.request from pathlib import Path import base64 from wasmtime import Engine, Instance, Module, Store import json import requests WASM_URL = "https://fe-static.deepseek.com/chat/static/sha3_wasm_bg.7b9ca65ddd.wasm" WASM_CACHE = Path(__file__).resolve().parent / "js_data" / "sha3_wasm_bg.wasm" # ── 下载 / 缓存 WASM ───────────────────────────────────────────────────────── def load_wasm(url: str = WASM_URL, cache: Path = WASM_CACHE) -> bytes: if cache.exists(): print(f"[+] 读取缓存 {cache}") return cache.read_bytes() print(f"[+] 下载 {url}") with urllib.request.urlopen(url) as r: data = r.read() cache.write_bytes(data) print(f"[+] 已缓存 ({len(data):,} bytes)") return data # ── WASM 运行时 ────────────────────────────────────────────────────────────── class DeepSeekWasm: """ 封装 sha3_wasm_bg.wasm,提供与 JS get_answer() 等价的接口。 WASM 导出 (wasm-bindgen 约定): memory WebAssembly.Memory __wbindgen_add_to_stack_pointer (i32) -> i32 __wbindgen_export_0 malloc(size: i32, align: i32) -> i32 __wbindgen_export_1 realloc(ptr, old, new, align: i32) -> i32 wasm_solve(ret_ptr, ch_ptr, ch_len, salt_ptr, salt_len, difficulty) -> void """ def __init__(self, wasm_bytes: bytes): self.engine = Engine() self.store = Store(self.engine) self.module = Module(self.engine, wasm_bytes) self.instance = Instance(self.store, self.module, []) exp = self.instance.exports(self.store) self._memory = exp["memory"] self._stack_ptr = exp["__wbindgen_add_to_stack_pointer"] self._malloc = exp["__wbindgen_export_0"] self._realloc = exp["__wbindgen_export_1"] self._wasm_solve = exp["wasm_solve"] # ── 内存读写 ────────────────────────────────────────────────────────────── def _mem_write(self, ptr: int, data: bytes): self._memory.write(self.store, data, ptr) def _mem_read(self, ptr: int, length: int) -> bytes: return bytes(self._memory.read(self.store, ptr, ptr + length)) # ── 字符串写入(对应 JS h() 函数)──────────────────────────────────────── def _write_str(self, s: str) -> tuple[int, int]: """将字符串 UTF-8 编码后写入 WASM 内存,返回 (ptr, length)""" encoded = s.encode("utf-8") length = len(encoded) ptr = self._malloc(self.store, length, 1) self._mem_write(ptr, encoded) return ptr, length # ── 核心接口 ────────────────────────────────────────────────────────────── def solve(self, challenge: str, salt: str, difficulty: int) -> float: """ 对应 JS: get_answer(challenge, salt, difficulty) -> float 参数: challenge challenge hex 字符串 salt 完整 salt,通常为 "{salt}_{timestamp_ms}_" difficulty 难度整数 返回: 满足难度的 nonce(float) """ # 分配 16 字节栈空间存放返回值 ret_ptr = self._stack_ptr(self.store, -16) try: c_ptr, c_len = self._write_str(challenge) s_ptr, s_len = self._write_str(salt) self._wasm_solve( self.store, ret_ptr, c_ptr, c_len, s_ptr, s_len, float(difficulty), # wasm_solve 的 difficulty 参数为 f64 ) # ret_ptr+0 : i32 状态码(忽略) # ret_ptr+8 : f64 nonce 结果 nonce_bytes = self._mem_read(ret_ptr + 8, 8) return int(struct.unpack(" float: """ 接收 /api/v0/chat/challenge 返回的 challenge 字典,自动拼接 salt 并求解。 示例 challenge_obj: { "challenge": "645f91f8...", "salt": "98fe06400b75ab5d4b0e", "difficulty": 144000, } """ ts_ms = int(time.time() * 1000) salt_full = f"{challenge_obj['salt']}_{ts_ms}_" print(f" challenge : {challenge_obj['challenge']}") print(f" salt+ts : {salt_full}") print(f" difficulty: {challenge_obj['difficulty']}") t0 = time.time() nonce = wasm.solve(challenge_obj["challenge"], salt_full, challenge_obj["difficulty"]) print(f" nonce : {nonce} ({time.time() - t0:.3f}s)") return nonce wasm_bytes = load_wasm() wasm = DeepSeekWasm(wasm_bytes) def get_biz_data(authorization, target_path): headers = { "accept": "*/*", "accept-language": "zh-CN,zh;q=0.9", "authorization": authorization, "cache-control": "no-cache", "content-type": "application/json", "origin": "https://chat.deepseek.com", "pragma": "no-cache", "priority": "u=1, i", "referer": "https://chat.deepseek.com/", "sec-ch-ua": "\"Chromium\";v=\"9\", \"Not?A_Brand\";v=\"8\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 SLBrowser/9.0.8.3131 SLBChan/10 SLBVPV/64-bit", "x-app-version": "2.0.0", "x-client-locale": "zh_CN", "x-client-platform": "web", "x-client-timezone-offset": "28800", "x-client-version": "2.0.0" } url = "https://chat.deepseek.com/api/v0/chat/create_pow_challenge" data = { "target_path": target_path } data = json.dumps(data, separators=(',', ':')) response = requests.post(url, headers=headers, data=data).json() # print(response) return response['data']['biz_data'] def get_ds_pow(authorization="Bearer GL6ePPNDwuPU9UCpOchZh06IhBE+2JprhF+zKZ20ApnZ/X+LdH3SQgeMfbEou1qe", target_path="/api/v0/chat/completion", biz_data=None): if not biz_data: biz_data = get_biz_data(authorization, target_path) challenge_data = biz_data["challenge"] challenge = challenge_data['challenge'] salt2 = challenge_data["salt"] difficulty = challenge_data["difficulty"] expire_at = challenge_data['expire_at'] signature = challenge_data['signature'] salt = f'{salt2}_{expire_at}_' answer = wasm.solve( challenge=challenge, salt=salt, difficulty=difficulty, ) sign_data = {"algorithm": "DeepSeekHashV1", "challenge": challenge, "salt": salt2, "answer": answer, "signature": signature, "target_path": target_path} # print(sign_data) res = base64.b64encode(json.dumps(sign_data, ensure_ascii=False, separators=(',', ':')).encode()).decode() # print(res) return res # ── 示例 ────────────────────────────────────────────────────────────────────── if __name__ == "__main__": # 1. 加载 WASM # get_ds_pow() authorization = "Bearer GL6ePPNDwuPU9UCpOchZh06IhBE+2JprhF+zKZ20ApnZ/X+LdH3SQgeMfbEou1qe" headers = { "accept": "*/*", "accept-language": "zh-CN,zh;q=0.9", "authorization": authorization, "cache-control": "no-cache", "content-type": "application/json", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 SLBrowser/9.0.8.3131 SLBChan/10 SLBVPV/64-bit", "x-app-version": "2.0.0", "x-client-locale": "zh_CN", "x-client-platform": "web", "x-client-timezone-offset": "28800", "x-client-version": "2.0.0", "x-ds-pow-response": get_ds_pow(authorization), } url = "https://chat.deepseek.com/api/v0/chat/completion" data = { "chat_session_id": "03f2255a-d58f-4010-b2bc-6ee58e99b6c0", "parent_message_id": None, "model_type": "default", "prompt": "今天星期几", "ref_file_ids": [], "thinking_enabled": False, "search_enabled": True, "preempt": False } data = json.dumps(data, separators=(',', ':')) response = requests.post(url, headers=headers, data=data, stream=True) for i in response.iter_lines(decode_unicode=True): print(i, end=' ') # {"algorithm":"DeepSeekHashV1","challenge":"a9c77bb053d25365f6d2e292a4eddfb6b969486a004d008fc6dffa229b25b142","salt":"fe903bc4cde529d3f67d","answer":30474,"signature":"41014e3c1324d7f85c4493c931c0e9c24b6afac1e9df36b98dce336cf5d16f7c","target_path":"/api/v0/chat/completion"} # {"algorithm":"DeepSeekHashV1","challenge":"e5c90381316ec79fb0160fc3f7b9d7e0380a876a35852e4f85346a67c50d60de","salt":"f84419c32756da175814","answer":68071,"signature":"f009b60446b4fc5931e533a5ea9c6fa14834586aaf5aa334ea9a6d2fa9b9cd4d","target_path":"/api/v0/chat/completion"}