122 lines
2.9 KiB
JavaScript
122 lines
2.9 KiB
JavaScript
|
importScripts(
|
||
|
"https://cdn.jsdelivr.net/npm/hash-wasm@4.11.0/dist/argon2.umd.min.js"
|
||
|
);
|
||
|
|
||
|
let active = false;
|
||
|
let nonce = 0;
|
||
|
let signature = "";
|
||
|
let lastNotify = 0;
|
||
|
let hashesSinceLastNotify = 0;
|
||
|
let params = {
|
||
|
salt: null,
|
||
|
hashLength: 0,
|
||
|
iterations: 0,
|
||
|
memorySize: 0,
|
||
|
parallelism: 0,
|
||
|
targetValue: BigInt(0),
|
||
|
safariFix: false,
|
||
|
};
|
||
|
|
||
|
self.onmessage = async (event) => {
|
||
|
const { data } = event;
|
||
|
switch (data.type) {
|
||
|
case "stop":
|
||
|
active = false;
|
||
|
self.postMessage({ type: "paused", hashes: hashesSinceLastNotify });
|
||
|
return;
|
||
|
case "start":
|
||
|
active = true;
|
||
|
signature = data.signature;
|
||
|
nonce = data.nonce;
|
||
|
|
||
|
const c = data.challenge;
|
||
|
// decode salt to Uint8Array
|
||
|
const salt = new Uint8Array(c.s.length / 2);
|
||
|
for (let i = 0; i < c.s.length; i += 2) {
|
||
|
salt[i / 2] = parseInt(c.s.slice(i, i + 2), 16);
|
||
|
}
|
||
|
|
||
|
params = {
|
||
|
salt: salt,
|
||
|
hashLength: c.hl,
|
||
|
iterations: c.t,
|
||
|
memorySize: c.m,
|
||
|
parallelism: c.p,
|
||
|
targetValue: BigInt(c.d.slice(0, -1)),
|
||
|
safariFix: data.isMobileWebkit,
|
||
|
};
|
||
|
|
||
|
console.log("Started", params);
|
||
|
self.postMessage({ type: "started" });
|
||
|
setTimeout(solve, 0);
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const doHash = async (password) => {
|
||
|
const { salt, hashLength, iterations, memorySize, parallelism } = params;
|
||
|
return await self.hashwasm.argon2id({
|
||
|
password,
|
||
|
salt,
|
||
|
hashLength,
|
||
|
iterations,
|
||
|
memorySize,
|
||
|
parallelism,
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const checkHash = (hash) => {
|
||
|
const { targetValue } = params;
|
||
|
const hashValue = BigInt(`0x${hash}`);
|
||
|
return hashValue <= targetValue;
|
||
|
};
|
||
|
|
||
|
const solve = async () => {
|
||
|
if (!active) {
|
||
|
console.log("Stopped solver", nonce);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Safari WASM doesn't like multiple calls in one worker
|
||
|
const batchSize = 1;
|
||
|
const batch = [];
|
||
|
for (let i = 0; i < batchSize; i++) {
|
||
|
batch.push(nonce++);
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
const results = await Promise.all(
|
||
|
batch.map(async (nonce) => {
|
||
|
const hash = await doHash(String(nonce));
|
||
|
return { hash, nonce };
|
||
|
})
|
||
|
);
|
||
|
hashesSinceLastNotify += batchSize;
|
||
|
|
||
|
const solution = results.find(({ hash }) => checkHash(hash));
|
||
|
if (solution) {
|
||
|
console.log("Solution found", solution, params.salt);
|
||
|
self.postMessage({ type: "solved", nonce: solution.nonce });
|
||
|
active = false;
|
||
|
} else {
|
||
|
if (Date.now() - lastNotify > 1000) {
|
||
|
console.log("Last nonce", nonce, "Hashes", hashesSinceLastNotify);
|
||
|
self.postMessage({ type: "progress", hashes: hashesSinceLastNotify });
|
||
|
lastNotify = Date.now();
|
||
|
hashesSinceLastNotify = 0;
|
||
|
}
|
||
|
setTimeout(solve, 10);
|
||
|
}
|
||
|
} catch (error) {
|
||
|
console.error("Error", error);
|
||
|
const stack = error.stack;
|
||
|
const debug = {
|
||
|
stack,
|
||
|
lastNonce: nonce,
|
||
|
targetValue: params.targetValue,
|
||
|
};
|
||
|
self.postMessage({ type: "error", error: error.message, debug });
|
||
|
active = false;
|
||
|
}
|
||
|
};
|