Skip to content

Instantly share code, notes, and snippets.

@codler
Last active December 19, 2015 01:39
Show Gist options
  • Save codler/5877964 to your computer and use it in GitHub Desktop.
Save codler/5877964 to your computer and use it in GitHub Desktop.
http://pastie.org/2054699
/* jsMiner.js - A Javascript Bitcoin miner */
/* version 1.1 - 5/24/2011 */
/* */
/* Copyright 2011, see LICENSE for details */
/* https://github.com/jwhitehorn/jsMiner */
/*******************************************/
// Performance improved by TheSeven on 2011-06-11
//
// Optimized for Firefox 4
//
// If this script improves your earnings,
// please donate to 1BjRqyMdWRu6eihQqssaEuuRsRqW2URm8h
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;
// Replaced by TheSeven
// 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;
// End of original
// End of replacement
jsMiner.engine = function(options){
this.publisherId = "";
this.siteId = "";
this.delayBetweenNonce = 30;
// Replaced by TheSeven
// this.sha = new Sha256();
// End of original
// End of replacement
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("siteId"))
this.siteId = options.siteId;
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){
// Replaced by TheSeven
// var url = "/work?client_id=" + this.clientId;
// End of original
var url = "http://api.bitp.it/work?client_id=" + this.clientId;
// End of replacement
if(this.siteId != ""){
url = url + "&site_id=" + this.siteId;
}
if(this.hashRate > 0){
url = url + "&hash_rate=" + this.hashRate + "&hash_count=" + (this.hashRate * 1000 * this.workerTimeout);
}
var me = this;
var httpRequest;
if(window.XDomainRequest){ //IE8+
httpRequest = new XDomainRequest();
httpRequest.onload = function(response){
// Replaced by TheSeven
// me.handleGetWorkResponse(httpRequest.responseText);
// End of original
if (!result) me.handleGetWorkResponse(httpRequest.responseText);
// End of replacement
};
}else if (window.XMLHttpRequest) { // Everybody else
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function(response){
try{
if(httpRequest.readyState == 4){
if(httpRequest.status == 200){
// Replaced by TheSeven
// me.handleGetWorkResponse(httpRequest.responseText);
// End of original
if (!result) me.handleGetWorkResponse(httpRequest.responseText);
// End of replacement
}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(){
// Replaced by TheSeven
// 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++;
// }
// End of original
var last = Math.min(nonce + 1024, endNonce + 1);
var data_ = half.concat(data);
me.tryHash(midstate, data_, nonce, last, function(lastnonce)
{
nonce = lastnonce;
data[19] = nonce;
workerDone(data)
});
nonce = last - 1;
// End of replacement
if(nonce++ < endNonce && (new Date()).getTime() <= endTime)
setTimeout(worker, delay);
else
workerDone(null);
};
setTimeout(worker, delay);
};
// Replaced by TheSeven
// 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;
// };
// End of original
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 os0 = 0x6a09e667, os1 = 0xbb67ae85, os2 = 0x3c6ef372, os3 = 0xa54ff53a;
var os4 = 0x510e527f, os5 = 0x9b05688c, os6 = 0x1f83d9ab, os7 = 0x5be0cd19;
this.tryHash = function(is, iw, firstnonce, lastnonce, callback)
{
var w0 = 0, w1 = 0, w2 = 0, w3 = 0, w4 = 0, w5 = 0, w6 = 0, w7 = 0;
var w8 = 0, w9 = 0, w10 = 0, w11 = 0, w12 = 0, w13 = 0, w14 = 0, w15 = 0;
var s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0, s6 = 0, s7 = 0;
var is0 = is[0], is1 = is[1], is2 = is[2], is3 = is[3];
var is4 = is[4], is5 = is[5], is6 = is[6], is7 = is[7];
var iw0 = iw[16], iw1 = iw[17], iw2 = iw[18];
var i = 0, j = 0, t0 = 0, t1 = 0, e = 0;
for (var nonce = firstnonce; nonce < lastnonce; nonce++)
{
w0 = iw0;
w1 = iw1;
w2 = iw2;
w3 = nonce;
w4 = 0x80000000;
w5 = 0;
w6 = 0;
w7 = 0;
w8 = 0;
w9 = 0;
w10 = 0;
w11 = 0;
w12 = 0;
w13 = 0;
w14 = 0;
w15 = 0x280;
s0 = is0;
s1 = is1;
s2 = is2;
s3 = is3;
s4 = is4;
s5 = is5;
s6 = is6;
s7 = is7;
for (i = 0; i < 125; i++)
{
if (i == 64)
{
w0 = is0 + s0;
w1 = is1 + s1;
w2 = is2 + s2;
w3 = is3 + s3;
w4 = is4 + s4;
w5 = is5 + s5;
w6 = is6 + s6;
w7 = is7 + s7;
w8 = 0x80000000;
w9 = 0;
w10 = 0;
w11 = 0;
w12 = 0;
w13 = 0;
w14 = 0;
w15 = 0x100;
s0 = os0;
s1 = os1;
s2 = os2;
s3 = os3;
s4 = os4;
s5 = os5;
s6 = os6;
s7 = os7;
}
e = (((s0 << 30) | (s0 >>> 2))
^ ((s0 << 19) | (s0 >>> 13))
^ ((s0 << 10) | (s0 >>> 22)))
+ ((s0 & s1) | (s2 & (s0 | s1)));
t0 = (((((w1 << 25) ^ (w1 << 14))
& 0xe0000000)
| ((((w1 << 25) | (w1 >>> 7))
^ ((w1 << 14) | (w1 >>> 18))
^ (w1 >>> 3))
& 0x1fffffff))
+ ((((w14 << 15) ^ (w14 << 13))
& 0xffc00000)
| ((((w14 << 15) | (w14 >>> 17))
^ ((w14 << 13) | (w14 >>> 19))
^ (w14 >>> 10))
& 0x003fffff))
+ w0
+ w9)
& 0xffffffff;
t1 = K[i & 0x3f]
+ w0
+ s7
+ (((s4 << 26) | (s4 >>> 6))
^ ((s4 << 21) | (s4 >>> 11))
^ ((s4 << 7) | (s4 >>> 25)))
+ (s6 ^ (s4 & (s5 ^ s6)));
w0 = w1;
w1 = w2;
w2 = w3;
w3 = w4;
w4 = w5;
w5 = w6;
w6 = w7;
w7 = w8;
w8 = w9;
w9 = w10;
w10 = w11;
w11 = w12;
w12 = w13;
w13 = w14;
w14 = w15;
w15 = t0;
s7 = s6;
s6 = s5;
s5 = s4;
s4 = (s3 + t1) & 0xffffffff;
s3 = s2;
s2 = s1;
s1 = s0;
s0 = (e + t1) & 0xffffffff;
}
if (((os7 + s4) & 0xffffffff) == 0) callback(nonce);
}
return false;
};
// End of replacement
//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});
// Replaced by TheSeven
// 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});
// End of original
for(var nonce = event.data.startNonce; nonce <= event.data.endNonce; nonce += 65536){
var last = Math.min(nonce + 65536, event.data.endNonce + 1);
var data = event.data.half.concat(event.data.data);
engine.tryHash(event.data.midstate, data, nonce, last, function(lastnonce)
{
data[19] = lastnonce;
postMessage({data: data, lastNonce: lastnonce});
});
if((new Date()).getTime() >= endTime){
postMessage({data: null, lastNonce: last - 1});
// End of replacement
return;
}
}
postMessage({data: null, lastNonce: event.data.endNonce});
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment