-
Notifications
You must be signed in to change notification settings - Fork 288
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
1,723 additions
and
64 deletions.
There are no files selected for viewing
Binary file not shown.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import fs from 'fs-extra'; | ||
|
||
export class DeepSeekHash { | ||
private wasmInstance: any; | ||
private offset: number = 0; | ||
private cachedUint8Memory: Uint8Array | null = null; | ||
private cachedTextEncoder: TextEncoder = new TextEncoder(); | ||
|
||
// 编码字符串到 WASM 内存 | ||
private encodeString( | ||
text: string, | ||
allocate: (size: number, align: number) => number, | ||
reallocate?: (ptr: number, oldSize: number, newSize: number, align: number) => number | ||
): number { | ||
// 简单情况:当没有 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; | ||
} | ||
|
||
// 复杂情况:分两步处理 ASCII 和非 ASCII 字符 | ||
const strLength = text.length; | ||
let ptr = allocate(strLength, 1) >>> 0; | ||
const memory = this.getCachedUint8Memory(); | ||
let asciiLength = 0; | ||
|
||
// 首先尝试 ASCII 编码 | ||
for (; asciiLength < strLength; asciiLength++) { | ||
const charCode = text.charCodeAt(asciiLength); | ||
if (charCode > 127) break; | ||
memory[ptr + asciiLength] = charCode; | ||
} | ||
|
||
// 如果存在非 ASCII 字符,需要重新分配空间并处理 | ||
if (asciiLength !== strLength) { | ||
if (asciiLength > 0) { | ||
text = text.slice(asciiLength); | ||
} | ||
|
||
// 为非 ASCII 字符重新分配空间(每个字符最多需要 3 字节) | ||
ptr = reallocate(ptr, strLength, asciiLength + text.length * 3, 1) >>> 0; | ||
|
||
// 使用 encodeInto 处理剩余的非 ASCII 字符 | ||
const result = this.cachedTextEncoder.encodeInto( | ||
text, | ||
this.getCachedUint8Memory().subarray(ptr + asciiLength, ptr + asciiLength + text.length * 3) | ||
); | ||
asciiLength += result.written; | ||
|
||
// 最终调整内存大小 | ||
ptr = reallocate(ptr, asciiLength + text.length * 3, asciiLength, 1) >>> 0; | ||
} | ||
|
||
this.offset = asciiLength; | ||
return ptr; | ||
} | ||
|
||
// 获取 WASM 内存视图 | ||
private getCachedUint8Memory(): Uint8Array { | ||
if (this.cachedUint8Memory === null || this.cachedUint8Memory.byteLength === 0) { | ||
this.cachedUint8Memory = new Uint8Array(this.wasmInstance.memory.buffer); | ||
} | ||
return this.cachedUint8Memory; | ||
} | ||
|
||
// DeepSeekHash 计算函数 | ||
public calculateHash( | ||
algorithm: string, | ||
challenge: string, | ||
salt: string, | ||
difficulty: number, | ||
expireAt: number | ||
): number | undefined { | ||
if (algorithm !== 'DeepSeekHashV1') { | ||
throw new Error('Unsupported algorithm: ' + algorithm); | ||
} | ||
|
||
// 拼接前缀 | ||
const prefix = `${salt}_${expireAt}_`; | ||
|
||
try { | ||
// 分配栈空间 | ||
const 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); | ||
|
||
// 获取返回结果 | ||
const dataView = new DataView(this.wasmInstance.memory.buffer); | ||
const status = dataView.getInt32(retptr + 0, true); | ||
const value = dataView.getFloat64(retptr + 8, true); | ||
|
||
// 如果求解失败,返回 undefined | ||
if (status === 0) | ||
return undefined; | ||
|
||
return value; | ||
|
||
} finally { | ||
// 释放栈空间 | ||
this.wasmInstance.__wbindgen_add_to_stack_pointer(16); | ||
} | ||
} | ||
|
||
// 初始化 WASM 模块 | ||
public async init(wasmPath: string): Promise<any> { | ||
const imports = { wbg: {} }; | ||
const wasmBuffer = await fs.readFile(wasmPath); | ||
const { instance } = await WebAssembly.instantiate(wasmBuffer, imports); | ||
this.wasmInstance = instance.exports; | ||
return this.wasmInstance; | ||
} | ||
} | ||
|
||
// 导出类 | ||
export default DeepSeekHash; |
Oops, something went wrong.