115 lines
4.1 KiB
Python
115 lines
4.1 KiB
Python
import time
|
||
import json
|
||
import base64
|
||
from typing import List
|
||
|
||
DEBUG = True
|
||
|
||
class ProofOfWorkSolver:
|
||
"""解决 OpenAI Sentinel 的 Proof of Work challenge"""
|
||
|
||
def __init__(self):
|
||
# FNV-1a 常量
|
||
self.FNV_OFFSET = 2166136261
|
||
self.FNV_PRIME = 16777619
|
||
|
||
def fnv1a_hash(self, data: str) -> str:
|
||
"""FNV-1a hash 算法"""
|
||
hash_value = self.FNV_OFFSET
|
||
|
||
for char in data:
|
||
hash_value ^= ord(char)
|
||
hash_value = (hash_value * self.FNV_PRIME) & 0xFFFFFFFF
|
||
|
||
# 额外的混合步骤(从 JS 代码复制)
|
||
hash_value ^= hash_value >> 16
|
||
hash_value = (hash_value * 2246822507) & 0xFFFFFFFF
|
||
hash_value ^= hash_value >> 13
|
||
hash_value = (hash_value * 3266489909) & 0xFFFFFFFF
|
||
hash_value ^= hash_value >> 16
|
||
|
||
# 转为 8 位十六进制字符串
|
||
return format(hash_value, '08x')
|
||
|
||
def serialize_array(self, arr: List) -> str:
|
||
"""模拟 JS 的 T() 函数:JSON.stringify + Base64"""
|
||
json_str = json.dumps(arr, separators=(',', ':'))
|
||
return base64.b64encode(json_str.encode()).decode()
|
||
|
||
def build_fingerprint_array(self, nonce: int, elapsed_ms: int) -> List:
|
||
"""构建指纹数组(简化版)"""
|
||
return [
|
||
0, # [0] screen dimensions
|
||
"", # [1] timestamp
|
||
0, # [2] memory
|
||
nonce, # [3] nonce ← 关键
|
||
"", # [4] user agent
|
||
"", # [5] random element
|
||
"", # [6] script src
|
||
"", # [7] language
|
||
"", # [8] languages
|
||
elapsed_ms, # [9] elapsed time ← 关键
|
||
"", # [10] random function
|
||
"", # [11] keys
|
||
"", # [12] window keys
|
||
0, # [13] performance.now()
|
||
"", # [14] uuid
|
||
"", # [15] URL params
|
||
0, # [16] hardware concurrency
|
||
0 # [17] timeOrigin
|
||
]
|
||
|
||
def solve(self, seed: str, difficulty: str, max_iterations: int = 10000000) -> str:
|
||
"""
|
||
解决 PoW challenge
|
||
|
||
Args:
|
||
seed: Challenge seed
|
||
difficulty: 目标难度(十六进制字符串)
|
||
max_iterations: 最大尝试次数
|
||
|
||
Returns:
|
||
序列化的答案(包含 nonce)
|
||
"""
|
||
if DEBUG:
|
||
print(f"[PoW] Solving challenge:")
|
||
print(f" Seed: {seed}")
|
||
print(f" Difficulty: {difficulty}")
|
||
|
||
start_time = time.time()
|
||
|
||
for nonce in range(max_iterations):
|
||
elapsed_ms = int((time.time() - start_time) * 1000)
|
||
|
||
# 构建指纹数组
|
||
fingerprint = self.build_fingerprint_array(nonce, elapsed_ms)
|
||
|
||
# 序列化
|
||
serialized = self.serialize_array(fingerprint)
|
||
|
||
# 计算 hash(seed + serialized)
|
||
hash_input = seed + serialized
|
||
hash_result = self.fnv1a_hash(hash_input)
|
||
|
||
# 检查是否满足难度要求
|
||
# 比较方式:hash 的前 N 位(作为整数)<= difficulty(作为整数)
|
||
difficulty_len = len(difficulty)
|
||
hash_prefix = hash_result[:difficulty_len]
|
||
|
||
if hash_prefix <= difficulty:
|
||
elapsed = time.time() - start_time
|
||
if DEBUG:
|
||
print(f"[PoW] ✓ Found solution in {elapsed:.2f}s")
|
||
print(f" Nonce: {nonce}")
|
||
print(f" Hash: {hash_result}")
|
||
print(f" Serialized: {serialized[:100]}...")
|
||
|
||
# 返回 serialized + "~S" (表示成功)
|
||
return serialized + "~S"
|
||
|
||
# 每 100k 次迭代打印进度
|
||
if DEBUG and nonce > 0 and nonce % 100000 == 0:
|
||
print(f"[PoW] Tried {nonce:,} iterations...")
|
||
|
||
raise Exception(f"Failed to solve PoW after {max_iterations:,} iterations")
|