1/* CaptchaCheckbox / OSv2 â proof-of-work worker. 2 * 3 * ÐÐ°Ð¹Ð½Ð¸Ñ pow_nonce Ñакой, ÑÑо 4 * sha256("captcha-pow-v1|" || init_nonce_16 || pow_nonce_4LE) 5 * Ð¸Ð¼ÐµÐµÑ Ð½Ðµ менÑÑе `difficulty` ведÑÑÐ¸Ñ Ð½ÑлевÑÑ Ð±Ð¸Ñ. 6 * 7 * СообÑениÑ: 8 * in: { type: 'mine', challengeHex: '<32 hex>', difficulty: K } 9 * out: { type: 'progress', tried: N } â каждÑе ~64k попÑÑок 10 * { type: 'solved', nonceB64: '...' } â наÑли ÑеÑение 11 * { type: 'error', code: 'too_hard'|'bad_input' } 12 */ 13 14'use strict'; 15 16// SHA-256 (FIPS 180-4). РеализаÑÐ¸Ñ ÑаÑÑÑиÑана на одноблоÑнÑй Ð²Ñ Ð¾Ð´ 17// (msgLen ⤠55 байÑ): Ð¼Ñ Ð·Ð½Ð°ÐµÐ¼, ÑÑо Ð½Ð°Ñ Ð¿Ñепейл-нонÑ-payload â 35 байÑ. 18var K256 = new Uint32Array([ 19 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 20 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 21 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 22 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 23 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 24 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 25 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 26 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 27]); 28 29var H0 = new Uint32Array([
30 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 31 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 32]); 33 34function rotr(x, n) { return ((x >>> n) | (x << (32 - n))) >>> 0; } 35 36/** 37 * ХеÑиÑÑÐµÑ Ð¾Ð´Ð¸Ð½ 64-байÑнÑй блок (16 uint32 big-endian Ñлов). 38 * ÐозвÑаÑÐ°ÐµÑ Ð¿ÐµÑвÑе 4 байÑа ÑезÑлÑÑаÑа как uint32 â Ð´Ð»Ñ Ð¿ÑовеÑки leading zeros. 39 * ÐÐ»Ñ ÑазнÑÑ Ð·Ð°Ð´Ð°Ñ Ð¼Ð¾Ð¶Ð½Ð¾ веÑнÑÑÑ Ð¿Ð¾Ð»Ð½Ñй маÑÑив, но нам нÑÐ¶Ð½Ñ ÑолÑко пеÑвÑе биÑÑ. 40 */ 41function sha256FirstWord(W) { 42 // W: Uint32Array(64); пеÑвÑе 16 Ñлов = блок, оÑÑалÑнÑе пеÑеÑÑиÑÑваем здеÑÑ. 43 for (var i = 16; i < 64; i++) { 44 var x15 = W[i - 15]; 45 var s0 = (rotr(x15, 7) ^ rotr(x15, 18) ^ (x15 >>> 3)) >>> 0; 46 var x2 = W[i - 2]; 47 var s1 = (rotr(x2, 17) ^ rotr(x2, 19) ^ (x2 >>> 10)) >>> 0; 48 W[i] = (W[i - 16] + s0 + W[i - 7] + s1) | 0; 49 } 50 51 var a = H0[0], b = H0[1], c = H0[2], d = H0[3]; 52 var e = H0[4], f = H0[5], g = H0[6], h = H0[7]; 53 54 for (var i = 0; i < 64; i++) { 55 var S1 = (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) >>> 0; 56 var ch = ((e & f) ^ (~e & g)) >>> 0; 57 var temp1 = (h + S1 + ch + K256[i] + W[i]) | 0; 58 var S0 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) >>> 0; 59 var mj = ((a & b) ^ (a & c) ^ (b & c)) >>> 0; 60 var temp2 = (S0 + mj) | 0; 61 h = g; g = f; f = e; 62 e = (d + temp1) | 0; 63 d = c; c = b; b = a; 64 a = (temp1 + temp2) | 0; 65 } 66 // ÐозвÑаÑаем пеÑвое Ñлово иÑогового Ñ ÐµÑа (a + H0[0]). 67 return (a + H0[0]) >>> 0; 68} 69 70function leadingZeroBitsU32(w) { 71 if (w === 0) return 32; 72 var n = 0; 73 for (var mask = 0x80000000; mask > 0; mask = (mask >>> 1)) { 74 if ((w & mask) === 0) n++; 75 else break; 76 } 77 return n; 78} 79 80function hexToBytes(hex) { 81 if (hex.length % 2 !== 0) return null; 82 var out = new Uint8Array(hex.length / 2); 83 for (var i = 0; i < out.length; i++) { 84 var b = parseInt(hex.substr(i * 2, 2), 16); 85 if (isNaN(b)) return null; 86 out[i] = b; 87 } 88 return out; 89} 90 91function bytesToB64(bytes) { 92 var s = ''; 93 for (var i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]); 94 return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); 95} 96 97self.onmessage = function (ev) { 98 var msg = ev.data || {}; 99 if (msg.type !== 'mine') return; 100 101 var difficulty = msg.difficulty | 0; 102 var nonceBytes = hexToBytes(String(msg.challengeHex || '')); 103 if (!nonceBytes || nonceBytes.length !== 16 || difficulty <= 0 || difficulty > 32) { 104 self.postMessage({ type: 'error', code: 'bad_input' }); 105 return; 106 } 107 108 // ÐÑепейл: "captcha-pow-v1|" (15 байÑ) + nonce (16 байÑ) + pow_nonce (4 байÑа LE) = 35 байÑ. 109 // ÐÑо вмеÑаеÑÑÑ Ð² один блок sha256. ÐоÑовим блок-ÑловаÑÑ Ð¾Ð´Ð½Ð°Ð¶Ð´Ñ Ð¸ 110 // апдейÑим ÑолÑко Ñо, ÑÑо менÑеÑÑÑ Ð¿Ð¾ иÑеÑаÑиÑм. 111 var prefix = 'captcha-pow-v1|'; 112 var msgLen = prefix.length + 16 + 4; // 35 113 var bits = msgLen * 8; // 280 114 115 // 64-байÑнÑй блок = 16 uint32 big-endian. 116 // ÐаÑанее вÑÑиÑлÑем «поÑÑоÑннÑÑ ÑаÑÑÑ» блока (вÑÑ ÐºÑоме pow_nonce). 117 var msgBytes = new Uint8Array(64); 118 for (var i = 0; i < prefix.length; i++) msgBytes[i] = prefix.charCodeAt(i); 119 for (var i = 0; i < 16; i++) msgBytes[prefix.length + i] = nonceBytes[i]; 120 // bytes 31..34 â меÑÑо под pow_nonce, заполним в Ñикле. 121 msgBytes[35] = 0x80; 122 // bytes 36..55 â нÑли (Uint8Array Ñже занÑлÑн). 123 // bytes 56..63 â длина в биÑÐ°Ñ (uint64 BE). 124 msgBytes[56] = 0; msgBytes[57] = 0; msgBytes[58] = 0; msgBytes[59] = 0; 125 msgBytes[60] = (bits >>> 24) & 0xff; 126 msgBytes[61] = (bits >>> 16) & 0xff; 127 msgBytes[62] = (bits >>> 8) & 0xff; 128 msgBytes[63] = bits & 0xff;
129 130 var W = new Uint32Array(64); 131 function loadFixed() { 132 for (var i = 0; i < 16; i++) { 133 var b = i * 4; 134 W[i] = ((msgBytes[b] << 24) | 135 (msgBytes[b + 1] << 16) | 136 (msgBytes[b + 2] << 8) | 137 (msgBytes[b + 3] )) >>> 0; 138 } 139 } 140 loadFixed(); 141 142 var MAX_ITER = 0xFFFFFFFF; 143 var batch = 65536; 144 var tried = 0; 145 146 for (var n = 0; n <= MAX_ITER; n++) { 147 // pow_nonce_4LE â bytes 31..34. ТолÑко ÑÑи байÑÑ Ð¼ÐµÐ½ÑÑÑÑÑ; 148 // обновлÑем W[7] (low byte) и W[8] (high 3 bytes). 149 msgBytes[31] = n & 0xff; 150 msgBytes[32] = (n >>> 8) & 0xff; 151 msgBytes[33] = (n >>> 16) & 0xff; 152 msgBytes[34] = (n >>> 24) & 0xff; 153 // W[7] = bytes 28..31 â Ð±Ð°Ð¹Ñ 31 в low. 154 W[7] = ((msgBytes[28] << 24) | (msgBytes[29] << 16) | (msgBytes[30] << 8) | msgBytes[31]) >>> 0; 155 // W[8] = bytes 32..35 â байÑÑ 32,33,34 + 0x80. 156 W[8] = ((msgBytes[32] << 24) | (msgBytes[33] << 16) | (msgBytes[34] << 8) | 0x80) >>> 0; 157 158 var firstWord = sha256FirstWord(W); 159 if (leadingZeroBitsU32(firstWord) >= difficulty) { 160 var nonceLE = new Uint8Array(4); 161 nonceLE[0] = n & 0xff; 162 nonceLE[1] = (n >>> 8) & 0xff;
163 nonceLE[2] = (n >>> 16) & 0xff; 164 nonceLE[3] = (n >>> 24) & 0xff; 165 self.postMessage({ type: 'solved', nonceB64: bytesToB64(nonceLE), tried: n + 1 }); 166 return; 167 } 168 169 tried++; 170 if ((tried % batch) === 0) { 171 self.postMessage({ type: 'progress', tried: tried }); 172 } 173 } 174 self.postMessage({ type: 'error', code: 'too_hard' }); 175};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.