Use naive, slow implementation
This commit is contained in:
+178
-18
@@ -1,21 +1,159 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>PoW Shield</title>
|
<title>PoW Shield</title>
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
|
function getCookie(name) {
|
||||||
|
const cookies = document.cookie.split("; ");
|
||||||
|
|
||||||
|
for (const c of cookies) {
|
||||||
|
if (c.startsWith(name + "=")) {
|
||||||
|
return decodeURIComponent(c.substring(name.length + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function b64ToBytes(b64) {
|
||||||
|
const bin = atob(b64);
|
||||||
|
const out = new Uint8Array(bin.length);
|
||||||
|
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytesToB64(bytes) {
|
||||||
|
let s = "";
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
s += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
return btoa(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDifficulty(hash, bits) {
|
||||||
|
const full = bits >> 3;
|
||||||
|
const rem = bits & 7;
|
||||||
|
|
||||||
|
for (let i = 0; i < full; i++) {
|
||||||
|
if (hash[i] !== 0) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rem) {
|
||||||
|
const mask = 0xff << (8 - rem);
|
||||||
|
if ((hash[full] & mask) !== 0) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sha256(buf) {
|
||||||
|
const h = await crypto.subtle.digest("SHA-256", buf);
|
||||||
|
return new Uint8Array(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function minePow(cookieB64, {
|
||||||
|
timeoutMs = 5000,
|
||||||
|
startNonce = 0,
|
||||||
|
littleEndian = true
|
||||||
|
} = {}) {
|
||||||
|
|
||||||
|
const start = performance.now();
|
||||||
|
|
||||||
|
// decode challenge once
|
||||||
|
const challenge = b64ToBytes(cookieB64);
|
||||||
|
const challengeLen = challenge.length;
|
||||||
|
|
||||||
|
// layout:
|
||||||
|
// [ challenge | nonce | hash ]
|
||||||
|
const NONCE_OFFSET = challengeLen;
|
||||||
|
const HASH_OFFSET = challengeLen + 4;
|
||||||
|
const TOTAL_SIZE = challengeLen + 4 + 32;
|
||||||
|
|
||||||
|
// single working buffer (NO reallocation in loop)
|
||||||
|
const work = new Uint8Array(TOTAL_SIZE);
|
||||||
|
work.set(challenge, 0);
|
||||||
|
|
||||||
|
const view = new DataView(work.buffer);
|
||||||
|
|
||||||
|
// extract difficulty once
|
||||||
|
const difficulty = view.getUint32(12, littleEndian);
|
||||||
|
|
||||||
|
for (nonce = startNonce; ; nonce++) {
|
||||||
|
|
||||||
|
// timeout throttle (cheap check)
|
||||||
|
if ((nonce & 2047) === 0) {
|
||||||
|
if (performance.now() - start > timeoutMs) {
|
||||||
|
throw new Error("PoW timeout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set nonce (this still copies the nonce)
|
||||||
|
view.setUint32(NONCE_OFFSET, nonce, littleEndian);
|
||||||
|
|
||||||
|
// Calculate sha256
|
||||||
|
const input = work.subarray(0, challengeLen + 4);
|
||||||
|
const hash = new Uint8Array(
|
||||||
|
await crypto.subtle.digest("SHA-256", input)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set hash (this still copies the hash)
|
||||||
|
work.set(hash, HASH_OFFSET);
|
||||||
|
|
||||||
|
if (checkDifficulty(hash, difficulty)) {
|
||||||
|
return {
|
||||||
|
nonce,
|
||||||
|
hash,
|
||||||
|
resultBytes: work,
|
||||||
|
resultB64: bytesToB64(work)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const powChallengeCookie = getCookie('pow-challenge');
|
||||||
|
console.log(powChallengeCookie);
|
||||||
|
|
||||||
|
minePow(powChallengeCookie)
|
||||||
|
.then(pow => {
|
||||||
|
console.log(pow);
|
||||||
|
document.cookie = `pow = ${pow.resultB64}`
|
||||||
|
})
|
||||||
|
.catch(e => console.log(e));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- script>
|
||||||
const SHA256_MD_LENGTH = 64;
|
const SHA256_MD_LENGTH = 64;
|
||||||
const POW_RANDOM_LENGTH = 64;
|
const POW_RANDOM_LENGTH = 64;
|
||||||
|
|
||||||
|
class PowChallenge {
|
||||||
|
constructor(cookie) {
|
||||||
|
const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
|
||||||
|
const view = new DataView(powChallengeBytes.buffer);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
this.version = view.getUint32(offset, true); offset += 4;
|
||||||
|
this.created = view.getUint32(offset, true); offset += 4;
|
||||||
|
this.ttl = view.getUint32(offset, true); offset += 4;
|
||||||
|
this.difficulty = view.getUint32(offset, true); offset += 4;
|
||||||
|
this.random = view.buffer.slice(offset, offset + POW_RANDOM_LENGTH); offset += POW_RANDOM_LENGTH;
|
||||||
|
this.digest = view.buffer.slice(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
getBytes() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function base64ToBytes(b64) {
|
function base64ToBytes(b64) {
|
||||||
return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
|
return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
function deserializePowChallenge(b64) {
|
function deserializePowChallenge(powChallengeBytes) {
|
||||||
const bytes = base64ToBytes(b64);
|
const view = new DataView(powChallengeBytes.buffer);
|
||||||
const view = new DataView(bytes.buffer);
|
|
||||||
|
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
@@ -53,10 +191,10 @@
|
|||||||
return new Uint8Array(hashBuffer);
|
return new Uint8Array(hashBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasLeadingBytes(buf, numBits) {
|
function hasLeadingBits(buf, numBits) {
|
||||||
const zeroBytes = numBits / 8;
|
const zeroBytes = numBits / 8;
|
||||||
const remainingBits = numBits % 8;
|
const remainingBits = numBits % 8;
|
||||||
const lut = Uint8Array([
|
const lut = new Uint8Array([
|
||||||
0b11111111, 0b01111111, 0b00111111, 0b00011111,
|
0b11111111, 0b01111111, 0b00111111, 0b00011111,
|
||||||
0b00001111, 0b00000111, 0b00000011, 0b00000001
|
0b00001111, 0b00000111, 0b00000011, 0b00000001
|
||||||
]);
|
]);
|
||||||
@@ -67,29 +205,51 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf[zeroBytes + 1] ^ lut[remainingBytes]) {
|
if (buf[zeroBytes + 1] ^ lut[remainingBits]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pow(challenge) {
|
function powSolve(powChallengeBytes, difficulty) {
|
||||||
const difficulty = deserializePowChallenge(challenge).difficulty
|
const powBytes = new Uint8Array(powChallengeBytes.length
|
||||||
const pow = Uint32
|
+ 4 // Nonce length
|
||||||
|
+ SHA256_MD_LENGTH);
|
||||||
|
powBytes.set(powChallengeBytes, 0);
|
||||||
|
|
||||||
let digest;
|
for (
|
||||||
let nonce = 0;
|
nonce = 0 >>> 0; // Force nonce to be uint32
|
||||||
|
(!hasLeadingBits(powBytes.slice(powChallengeBytes.length), difficulty)
|
||||||
|
&& nonce < 100)
|
||||||
|
|| nonce != 0;
|
||||||
|
nonce++
|
||||||
|
) {
|
||||||
|
powBytes[powChallengeBytes.length + 0] = nonce & 0xFF;
|
||||||
|
powBytes[powChallengeBytes.length + 1] = (nonce >>> 8) & 0xFF;
|
||||||
|
powBytes[powChallengeBytes.length + 2] = (nonce >>> 16) & 0xFF;
|
||||||
|
powBytes[powChallengeBytes.length + 3] = (nonce >>> 24) & 0xFF;
|
||||||
|
|
||||||
do {
|
sha256(powBytes.slice(0, powChallengeBytes.length + 4))
|
||||||
sha256(challenge).then(d => digest = d);
|
.then(s => powBytes.set(s, powChallengeBytes + 4))
|
||||||
} while (hasLeadingBytes(digest, difficulty))
|
.catch(e => console.log(e));
|
||||||
|
}
|
||||||
|
|
||||||
console.log(digest)
|
return powBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const powChallengeCookie = getCookie("pow-challenge");
|
const powChallengeCookie = getCookie("pow-challenge");
|
||||||
const powChallenge = deserializePowChallenge(powChallengeCookie);
|
console.log(powChallengeCookie);
|
||||||
console.log(powChallenge, powChallenge.length)
|
|
||||||
</script>
|
const powChallengeBytes = base64ToBytes(powChallengeCookie);
|
||||||
|
console.log(powChallengeBytes);
|
||||||
|
|
||||||
|
const powChallenge = deserializePowChallenge(powChallengeBytes);
|
||||||
|
console.log(powChallenge);
|
||||||
|
|
||||||
|
const pow = powSolve(powChallengeBytes, powChallenge.difficulty);
|
||||||
|
console.log(pow);
|
||||||
|
|
||||||
|
</script -->
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user