Download src/pow.js from pigracing/sd: direct link, hf CLI and curl.
- Browser
- Download file 8.42 kB
-
https://huggingface.co/spaces/pigracing/sd/resolve/main/src/pow.js
- Command line
-
hf download hf://spaces/pigracing/sd/src/pow.js
-
curl -L -o pow.js https://huggingface.co/spaces/pigracing/sd/resolve/main/src/pow.js
8.42 kB
| import { pickToken } from './auth.js'; | |
| import { apiHeaders, proxiedFetch } from './headers.js'; | |
| import { readFileSync } from 'fs'; | |
| import { fileURLToPath } from 'url'; | |
| import { dirname, join } from 'path'; | |
| const BASE_URL = 'https://chat.deepseek.com'; | |
| // Load and instantiate WASM sha3 module (one-time init) | |
| let wasmInstance = null; | |
| async function getWasm() { | |
| if (wasmInstance) return wasmInstance; | |
| const wasmPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'sha3_wasm_bg.wasm'); | |
| const wasmBuf = readFileSync(wasmPath); | |
| const { instance } = await WebAssembly.instantiate(wasmBuf, { wbg: {} }); | |
| wasmInstance = instance; | |
| return instance; | |
| } | |
| const encoder = new TextEncoder(); | |
| function passStringToWasm(instance, str) { | |
| const { memory, __wbindgen_export_0 } = instance.exports; | |
| const encoded = encoder.encode(str); | |
| const ptr = __wbindgen_export_0(encoded.length, 1) >>> 0; | |
| new Uint8Array(memory.buffer).set(encoded, ptr); | |
| return [ptr, encoded.length]; | |
| } | |
| function wasmSolve(instance, challengeHex, prefix, difficulty) { | |
| const { memory, wasm_solve, __wbindgen_add_to_stack_pointer } = instance.exports; | |
| const [chPtr, chLen] = passStringToWasm(instance, challengeHex); | |
| const [pfPtr, pfLen] = passStringToWasm(instance, prefix); | |
| const st = __wbindgen_add_to_stack_pointer(-16); | |
| wasm_solve(st, chPtr, chLen, pfPtr, pfLen, difficulty); | |
| const v = new DataView(memory.buffer); | |
| const found = v.getInt32(st, true); | |
| const answer = v.getFloat64(st + 8, true); | |
| __wbindgen_add_to_stack_pointer(16); | |
| if (!found) throw new Error('PoW solve failed: no solution within difficulty'); | |
| return answer; | |
| } | |
| // BigInt fallback | |
| const RC = [ | |
| 0x0000000000000001n, 0x0000000000008082n, 0x800000000000808an, 0x8000000080008000n, | |
| 0x000000000000808bn, 0x0000000080000001n, 0x8000000080008081n, 0x8000000000008009n, | |
| 0x000000000000008an, 0x0000000000000088n, 0x0000000080008009n, 0x000000008000000an, | |
| 0x000000008000808bn, 0x800000000000008bn, 0x8000000000008089n, 0x8000000000008003n, | |
| 0x8000000000008002n, 0x8000000000000080n, 0x000000000000800an, 0x800000008000000an, | |
| 0x8000000080008081n, 0x8000000000008080n, 0x0000000080000001n, 0x8000000080008008n, | |
| ]; | |
| const MASK = 0xffffffffffffffffn; | |
| const RATE = 136; | |
| function rotl64(v, k) { return ((v << BigInt(k)) | (v >> BigInt(64 - k))) & MASK; } | |
| function keccakF23(s) { | |
| let a = s.slice(); | |
| for (let r = 1; r < 24; r++) { | |
| const c = [a[0]^a[5]^a[10]^a[15]^a[20], a[1]^a[6]^a[11]^a[16]^a[21], a[2]^a[7]^a[12]^a[17]^a[22], | |
| a[3]^a[8]^a[13]^a[18]^a[23], a[4]^a[9]^a[14]^a[19]^a[24]]; | |
| const d = [c[4]^rotl64(c[1],1), c[0]^rotl64(c[2],1), c[1]^rotl64(c[3],1), c[2]^rotl64(c[4],1), c[3]^rotl64(c[0],1)]; | |
| for (let i = 0; i < 25; i++) a[i] = (a[i] ^ d[i%5]) & MASK; | |
| const b = new Array(25); | |
| b[0]=a[0];b[10]=rotl64(a[1],1);b[20]=rotl64(a[2],62);b[5]=rotl64(a[3],28);b[15]=rotl64(a[4],27); | |
| b[16]=rotl64(a[5],36);b[1]=rotl64(a[6],44);b[11]=rotl64(a[7],6);b[21]=rotl64(a[8],55);b[6]=rotl64(a[9],20); | |
| b[7]=rotl64(a[10],3);b[17]=rotl64(a[11],10);b[2]=rotl64(a[12],43);b[12]=rotl64(a[13],25);b[22]=rotl64(a[14],39); | |
| b[23]=rotl64(a[15],41);b[8]=rotl64(a[16],45);b[18]=rotl64(a[17],15);b[3]=rotl64(a[18],21);b[13]=rotl64(a[19],8); | |
| b[14]=rotl64(a[20],18);b[24]=rotl64(a[21],2);b[9]=rotl64(a[22],61);b[19]=rotl64(a[23],56);b[4]=rotl64(a[24],14); | |
| for (let y = 0; y < 5; y++) { | |
| const t = [b[y*5], b[y*5+1], b[y*5+2], b[y*5+3], b[y*5+4]]; | |
| for (let x = 0; x < 5; x++) a[y*5+x] = (t[x] ^ ((t[(x+1)%5] ^ MASK) & t[(x+2)%5])) & MASK; | |
| } | |
| a[0] = (a[0] ^ RC[r]) & MASK; | |
| } | |
| for (let i = 0; i < 25; i++) s[i] = a[i]; | |
| } | |
| function readU64LE(buf, off) { | |
| let v = 0n; | |
| for (let i = 0; i < 8; i++) v |= BigInt(buf[off + i]) << BigInt(i * 8); | |
| return v & MASK; | |
| } | |
| function writeU64LE(val, buf, off) { | |
| const v = val & MASK; | |
| for (let i = 0; i < 8; i++) buf[off + i] = Number((v >> BigInt(i * 8)) & 0xffn); | |
| } | |
| function preAbsorbPrefix(prefix) { | |
| const s = new Array(25).fill(0n); | |
| const buf = Buffer.from(prefix); | |
| let off = 0; | |
| while (off + RATE <= buf.length) { | |
| for (let i = 0; i < RATE / 8; i++) s[i] = (s[i] ^ readU64LE(buf, off + i * 8)) & MASK; | |
| keccakF23(s); | |
| off += RATE; | |
| } | |
| const tailLen = buf.length - off; | |
| const tail = Buffer.alloc(RATE); | |
| buf.copy(tail, 0, off); | |
| return { s, tail, tailLen }; | |
| } | |
| function solvePowBigInt(challengeHex, salt, expireAt, difficulty) { | |
| if (challengeHex.length !== 64) throw new Error('pow: challenge must be 64 hex chars'); | |
| const target = Buffer.from(challengeHex, 'hex'); | |
| const t0 = readU64LE(target, 0); | |
| const t1 = readU64LE(target, 8); | |
| const t2 = readU64LE(target, 16); | |
| const t3 = readU64LE(target, 24); | |
| const prefix = `${salt}_${expireAt}_`; | |
| const { s: baseState, tail, tailLen } = preAbsorbPrefix(prefix); | |
| for (let n = 0; n < difficulty; n++) { | |
| const nonceStr = n.toString(); | |
| const nonceBuf = Buffer.from(nonceStr); | |
| const totalTail = tailLen + nonceBuf.length; | |
| const s = baseState.slice(); | |
| if (totalTail < RATE) { | |
| const buf = Buffer.alloc(RATE); | |
| tail.copy(buf, 0, 0, tailLen); | |
| nonceBuf.copy(buf, tailLen); | |
| buf[totalTail] = 0x06; | |
| buf[RATE - 1] |= 0x80; | |
| for (let i = 0; i < RATE / 8; i++) s[i] = (s[i] ^ readU64LE(buf, i * 8)) & MASK; | |
| keccakF23(s); | |
| } else { | |
| const buf1 = Buffer.alloc(RATE); | |
| tail.copy(buf1, 0, 0, tailLen); | |
| nonceBuf.copy(buf1, tailLen, 0, RATE - tailLen); | |
| for (let i = 0; i < RATE / 8; i++) s[i] = (s[i] ^ readU64LE(buf1, i * 8)) & MASK; | |
| keccakF23(s); | |
| const rem = totalTail - RATE; | |
| const buf2 = Buffer.alloc(RATE); | |
| nonceBuf.copy(buf2, 0, RATE - tailLen, RATE - tailLen + rem); | |
| buf2[rem] = 0x06; | |
| buf2[RATE - 1] |= 0x80; | |
| for (let i = 0; i < RATE / 8; i++) s[i] = (s[i] ^ readU64LE(buf2, i * 8)) & MASK; | |
| keccakF23(s); | |
| } | |
| if (s[0] === t0 && s[1] === t1 && s[2] === t2 && s[3] === t3) return n; | |
| } | |
| throw new Error('PoW solve failed: no solution within difficulty'); | |
| } | |
| let useWasm = true; | |
| async function solvePowInternal(token, targetPath = '/api/v0/chat/completion') { | |
| const res = await proxiedFetch(`${BASE_URL}/api/v0/chat/create_pow_challenge`, { | |
| method: 'POST', | |
| headers: await apiHeaders(token), | |
| body: JSON.stringify({ target_path: targetPath }), | |
| }); | |
| if (res.status === 202) { | |
| throw new Error('PoW challenge: WAF blocked (202)'); | |
| } | |
| const text = await res.text(); | |
| if (!text) throw new Error('PoW challenge: empty response'); | |
| const json = JSON.parse(text); | |
| const c = json.data?.biz_data?.challenge; | |
| if (!c) throw new Error('PoW challenge failed: no challenge returned'); | |
| if (c.algorithm !== 'DeepSeekHashV1') throw new Error(`Unsupported PoW algorithm: ${c.algorithm}`); | |
| const difficulty = c.difficulty || 144000; | |
| const prefix = `${c.salt}_${c.expire_at}_`; | |
| let answer; | |
| if (useWasm) { | |
| try { | |
| const instance = await getWasm(); | |
| answer = wasmSolve(instance, c.challenge, prefix, difficulty); | |
| } catch (e) { | |
| console.warn('WASM PoW failed, falling back to BigInt:', e.message); | |
| useWasm = false; | |
| // Re-enable WASM after 30 minutes in case the failure was transient | |
| setTimeout(() => { useWasm = true; }, 30 * 60 * 1000); | |
| answer = solvePowBigInt(c.challenge, c.salt, c.expire_at, difficulty); | |
| } | |
| } else { | |
| answer = solvePowBigInt(c.challenge, c.salt, c.expire_at, difficulty); | |
| } | |
| const powResponse = { | |
| algorithm: c.algorithm, | |
| challenge: c.challenge, | |
| salt: c.salt, | |
| answer, | |
| signature: c.signature, | |
| target_path: c.target_path, | |
| }; | |
| return Buffer.from(JSON.stringify(powResponse)).toString('base64'); | |
| } | |
| // For chat.js — takes explicit token (same token used for PoW and completion) | |
| export async function solvePowChallengeWithToken(token, targetPath = '/api/v0/chat/completion') { | |
| const powResponse = await solvePowInternal(token, targetPath); | |
| return { powResponse }; | |
| } | |
| // Legacy: picks a token automatically (used by upload.js) | |
| export async function solvePowChallenge(preferVision = false) { | |
| const token = pickToken(preferVision); | |
| const powResponse = await solvePowInternal(token, '/api/v0/chat/completion'); | |
| return { powResponse, token }; | |
| } | |
| // For upload.js — takes explicit token | |
| export async function solvePowChallengeForUpload(token) { | |
| return solvePowInternal(token, '/api/v0/file/upload_file'); | |
| } | |