You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
4.1 KiB
113 lines
4.1 KiB
// ds.js —— 无需 fs-extra 的版本(CommonJS)
|
|
const fs = require('fs').promises; // 用内置 fs.promises
|
|
|
|
class DeepSeekHash {
|
|
constructor() {
|
|
this.wasmInstance = null;
|
|
this.offset = 0;
|
|
this.cachedUint8Memory = null;
|
|
this.cachedTextEncoder = new TextEncoder();
|
|
this._lastBufferRef = null; // 记录上次的 buffer,内存增长时刷新
|
|
}
|
|
|
|
_refreshIfNeeded() {
|
|
const buf = this.wasmInstance.memory.buffer;
|
|
if (this._lastBufferRef !== buf) {
|
|
this.cachedUint8Memory = new Uint8Array(buf);
|
|
this._lastBufferRef = buf;
|
|
}
|
|
}
|
|
|
|
getCachedUint8Memory() {
|
|
if (!this.wasmInstance || !this.wasmInstance.memory) {
|
|
throw new Error('WASM instance not initialized');
|
|
}
|
|
this._refreshIfNeeded();
|
|
return this.cachedUint8Memory;
|
|
}
|
|
|
|
encodeString(text, allocate, reallocate) {
|
|
if (!reallocate) {
|
|
const encoded = this.cachedTextEncoder.encode(text);
|
|
const ptr = allocate(encoded.length, 1) >>> 0;
|
|
const memory = this.getCachedUint8Memory();
|
|
memory.subarray(ptr, ptr + encoded.length).set(encoded);
|
|
this.offset = encoded.length;
|
|
return ptr;
|
|
}
|
|
const strLength = text.length;
|
|
let ptr = allocate(strLength, 1) >>> 0;
|
|
const memory = this.getCachedUint8Memory();
|
|
let asciiLength = 0;
|
|
for (; asciiLength < strLength; asciiLength++) {
|
|
const cc = text.charCodeAt(asciiLength);
|
|
if (cc > 127) break;
|
|
memory[ptr + asciiLength] = cc;
|
|
}
|
|
if (asciiLength !== strLength) {
|
|
if (asciiLength > 0) text = text.slice(asciiLength);
|
|
ptr = reallocate(ptr, strLength, asciiLength + text.length * 3, 1) >>> 0;
|
|
const view = this.getCachedUint8Memory().subarray(
|
|
ptr + asciiLength,
|
|
ptr + asciiLength + text.length * 3
|
|
);
|
|
const res = this.cachedTextEncoder.encodeInto(text, view);
|
|
asciiLength += res.written;
|
|
ptr = reallocate(ptr, asciiLength + text.length * 3, asciiLength, 1) >>> 0;
|
|
}
|
|
this.offset = asciiLength;
|
|
return ptr;
|
|
}
|
|
|
|
calculateHash(algorithm, challenge, salt, difficulty, expireAt) {
|
|
if (algorithm !== 'DeepSeekHashV1') {
|
|
throw new Error('Unsupported algorithm: ' + algorithm);
|
|
}
|
|
const prefix = `${salt}_${expireAt}_`;
|
|
let retptr;
|
|
try {
|
|
retptr = this.wasmInstance.__wbindgen_add_to_stack_pointer(-16);
|
|
|
|
const ptr0 = this.encodeString(
|
|
challenge,
|
|
this.wasmInstance.__wbindgen_export_0,
|
|
this.wasmInstance.__wbindgen_export_1
|
|
);
|
|
const len0 = this.offset;
|
|
|
|
const ptr1 = this.encodeString(
|
|
prefix,
|
|
this.wasmInstance.__wbindgen_export_0,
|
|
this.wasmInstance.__wbindgen_export_1
|
|
);
|
|
const len1 = this.offset;
|
|
|
|
this.wasmInstance.wasm_solve(retptr, ptr0, len0, ptr1, len1, difficulty);
|
|
|
|
// 读取返回(注意内存可能增长,先刷新)
|
|
this._refreshIfNeeded();
|
|
const dv = new DataView(this.wasmInstance.memory.buffer);
|
|
const status = dv.getInt32(retptr + 0, true);
|
|
const value = dv.getFloat64(retptr + 8, true);
|
|
|
|
if (status === 0) return undefined;
|
|
return value;
|
|
} finally {
|
|
if (retptr !== undefined) {
|
|
this.wasmInstance.__wbindgen_add_to_stack_pointer(16);
|
|
}
|
|
}
|
|
}
|
|
|
|
async init(wasmPath) {
|
|
const imports = { wbg: {} }; // 若报缺少导入,需改用对应的 glue JS
|
|
const wasmBuffer = await fs.readFile(wasmPath);
|
|
const { instance } = await WebAssembly.instantiate(wasmBuffer, imports);
|
|
this.wasmInstance = instance.exports;
|
|
this._lastBufferRef = this.wasmInstance.memory.buffer;
|
|
this.cachedUint8Memory = new Uint8Array(this._lastBufferRef);
|
|
return this.wasmInstance;
|
|
}
|
|
}
|
|
|
|
module.exports = DeepSeekHash;
|